initialized
13
.editorconfig
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
47
.gitignore
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
# Only exists if Bazel was run
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# profiling files
|
||||||
|
chrome-profiler-events*.json
|
||||||
|
speed-measure-plugin*.json
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
/.awcache
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
11
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"Angular.ng-template",
|
||||||
|
"msjsdiag.debugger-for-chrome",
|
||||||
|
"eamodio.gitlens",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||||
|
"VisualStudioExptTeam.vscodeintellicode",
|
||||||
|
"nkokhelox.svg-font-previewer"
|
||||||
|
]
|
||||||
|
}
|
7
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": []
|
||||||
|
}
|
14
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.formatOnPaste": true,
|
||||||
|
"editor.autoClosingBrackets": "languageDefined",
|
||||||
|
"editor.trimAutoWhitespace": true,
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"files.trimFinalNewlines": true,
|
||||||
|
"go.testFlags": ["-v"],
|
||||||
|
"go.testTimeout": "100s",
|
||||||
|
"prettier.singleQuote": true,
|
||||||
|
"debug.node.autoAttach": "on"
|
||||||
|
}
|
15
.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "build:main:dev",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1521
angular.json
Normal file
19
config/enviroment.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as Path from 'path';
|
||||||
|
|
||||||
|
const projectRoot = Path.dirname(__dirname);
|
||||||
|
const channel = process.env.NODE_ENV;
|
||||||
|
|
||||||
|
const s = JSON.stringify;
|
||||||
|
|
||||||
|
export function getEnviroments() {
|
||||||
|
return {
|
||||||
|
__DARWIN__: process.platform === 'darwin',
|
||||||
|
__WIN32__: process.platform === 'win32',
|
||||||
|
__LINUX__: process.platform === 'linux',
|
||||||
|
__DEV__: channel === 'development',
|
||||||
|
'process.platform': s(process.platform),
|
||||||
|
'process.env.NODE_ENV': s(process.env.NODE_ENV || 'development'),
|
||||||
|
'process.env.TEST_ENV': s(process.env.TEST_ENV)
|
||||||
|
};
|
||||||
|
}
|
111
config/main.webpack.config.ts
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
import * as path from 'path';
|
||||||
|
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
|
||||||
|
import * as CopyWebpackPlugin from 'copy-webpack-plugin';
|
||||||
|
import * as webpack from 'webpack';
|
||||||
|
import * as nodeExternals from 'webpack-node-externals';
|
||||||
|
import { getEnviroments } from './enviroment';
|
||||||
|
|
||||||
|
const enviroments = getEnviroments();
|
||||||
|
|
||||||
|
export const externals = [nodeExternals()];
|
||||||
|
// if (enviroments.__DEV__) {
|
||||||
|
// externals.push('devtron');
|
||||||
|
// }
|
||||||
|
|
||||||
|
const outputDir = 'dist/main';
|
||||||
|
|
||||||
|
const mainConfig: webpack.Configuration = {
|
||||||
|
entry: { main: path.resolve(__dirname, '..', 'main/src/index') },
|
||||||
|
target: 'electron-main',
|
||||||
|
mode: enviroments.__DEV__ ? 'development' : 'production',
|
||||||
|
devtool: 'source-map',
|
||||||
|
optimization: {
|
||||||
|
noEmitOnErrors: true
|
||||||
|
},
|
||||||
|
externals,
|
||||||
|
output: {
|
||||||
|
filename: '[name].js',
|
||||||
|
path: path.resolve(__dirname, '..', outputDir)
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
include: [
|
||||||
|
path.resolve(__dirname, '..', 'main/src'),
|
||||||
|
path.resolve(__dirname, '..', 'projects')
|
||||||
|
],
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'awesome-typescript-loader',
|
||||||
|
options: {
|
||||||
|
useCache: true,
|
||||||
|
configFileName: path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'main/tsconfig.main.json'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.node$/,
|
||||||
|
loader: 'awesome-node-loader',
|
||||||
|
options: {
|
||||||
|
name: '[name].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin({ verbose: false }),
|
||||||
|
// This saves us a bunch of bytes by pruning locales (which we don't use)
|
||||||
|
// from moment.
|
||||||
|
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||||
|
new webpack.DefinePlugin(
|
||||||
|
Object.assign({}, enviroments, {
|
||||||
|
__PROCESS_KIND__: JSON.stringify('main')
|
||||||
|
})
|
||||||
|
),
|
||||||
|
new CopyWebpackPlugin([
|
||||||
|
{
|
||||||
|
from: 'main/resources/**/*',
|
||||||
|
to: path.resolve(__dirname, '..', 'dist')
|
||||||
|
}
|
||||||
|
])
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.ts'],
|
||||||
|
alias: {
|
||||||
|
'@ucap-webmessenger/electron-core': path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'projects/ucap-webmessenger-electron-core/src/public-api'
|
||||||
|
),
|
||||||
|
'@ucap-webmessenger/electron-notification': path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'projects/ucap-webmessenger-electron-notification/src/public-api'
|
||||||
|
),
|
||||||
|
'@ucap-webmessenger/native': path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'projects/ucap-webmessenger-native/src/public-api'
|
||||||
|
),
|
||||||
|
'@ucap-webmessenger/native-electron': path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'projects/ucap-webmessenger-native-electron/src/public-api'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modules: [path.resolve(__dirname, '..', 'node_modules/')]
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
__dirname: false,
|
||||||
|
__filename: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default [mainConfig];
|
18
config/renderer.webpack.config.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = (config, options) => {
|
||||||
|
const PRODUCTION = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
|
config.target = 'electron-renderer';
|
||||||
|
|
||||||
|
config.resolve.alias = {
|
||||||
|
...config.resolve.alias,
|
||||||
|
'@ucap-webmessenger-scss/ui': path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'projects/ucap-webmessenger-ui/src/assets/scss'
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
return config;
|
||||||
|
};
|
6
config/tsconfig.webpack.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs"
|
||||||
|
}
|
||||||
|
}
|
40
electron-builder.json
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"productName": "WooriTalk",
|
||||||
|
"appId": "lgcns.ucap.messenger",
|
||||||
|
"asar": true,
|
||||||
|
"protocols": {
|
||||||
|
"name": "WooriTalk",
|
||||||
|
"schemes": ["WooriTalk"]
|
||||||
|
},
|
||||||
|
"publish": {
|
||||||
|
"provider": "generic",
|
||||||
|
"url": "http://localhost:8099/client-updates/"
|
||||||
|
},
|
||||||
|
"mac": {
|
||||||
|
"target": ["default"],
|
||||||
|
"icon": "./resources/installer/woori.icns"
|
||||||
|
},
|
||||||
|
"dmg": {
|
||||||
|
"title": "WooriTalk",
|
||||||
|
"icon": "./resources/installer/woori.icns"
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"target": ["zip", "nsis"],
|
||||||
|
"icon": "./resources/installer/woori_256x256.ico"
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"target": ["AppImage", "deb", "rpm", "zip", "tar.gz"],
|
||||||
|
"icon": "./resources/linuxicon"
|
||||||
|
},
|
||||||
|
"nsis": {
|
||||||
|
"oneClick": false,
|
||||||
|
"allowToChangeInstallationDirectory": true,
|
||||||
|
"perMachine": true,
|
||||||
|
"differentialPackage": true
|
||||||
|
},
|
||||||
|
"directories": {
|
||||||
|
"buildResources": "resources/installer/",
|
||||||
|
"output": "dist-electron/",
|
||||||
|
"app": "."
|
||||||
|
}
|
||||||
|
}
|
BIN
main/resources/image/128_128.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
main/resources/image/16_16.png
Normal file
After Width: | Height: | Size: 504 B |
BIN
main/resources/image/256_256.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
main/resources/image/32_32.png
Normal file
After Width: | Height: | Size: 897 B |
BIN
main/resources/image/48_48.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
main/resources/image/64_64.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
main/resources/image/ico_64_64.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
main/resources/image/ico_64x64.ico
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
main/resources/image/ico_64x64.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
main/resources/image/ico_64x64_r.ico
Normal file
After Width: | Height: | Size: 105 KiB |
BIN
main/resources/image/ico_64x64_r.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
main/resources/installer/woori.icns
Normal file
BIN
main/resources/installer/woori.ico
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
main/resources/installer/woori_256x256.ico
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
main/resources/installer/woori_256x256.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
main/resources/linuxicon/256x256.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
main/resources/notification/image/btn_call_message.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
main/resources/notification/image/btn_call_receive.png
Normal file
After Width: | Height: | Size: 842 B |
BIN
main/resources/notification/image/btn_call_refuse.png
Normal file
After Width: | Height: | Size: 643 B |
BIN
main/resources/notification/image/btn_call_transfer.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
main/resources/notification/image/btn_close.png
Normal file
After Width: | Height: | Size: 226 B |
BIN
main/resources/notification/image/btn_close_gray.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
main/resources/notification/image/btn_noti_call.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
main/resources/notification/image/img_nophoto_50.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
143
main/resources/notification/preload.js
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const electron = require('electron');
|
||||||
|
const ipc = electron.ipcRenderer;
|
||||||
|
const winId = electron.remote.getCurrentWindow().id;
|
||||||
|
|
||||||
|
function setStyle(config) {
|
||||||
|
// Style it
|
||||||
|
let notiDoc = global.window.document;
|
||||||
|
let container = notiDoc.getElementById('container');
|
||||||
|
let appIcon = notiDoc.getElementById('appIcon');
|
||||||
|
let image = notiDoc.getElementById('image');
|
||||||
|
let close = notiDoc.getElementById('close');
|
||||||
|
let message = notiDoc.getElementById('message');
|
||||||
|
// Default style
|
||||||
|
setStyleOnDomElement(config.defaultStyleContainer, container);
|
||||||
|
// Size and radius
|
||||||
|
let style = {
|
||||||
|
height:
|
||||||
|
config.height -
|
||||||
|
2 * config.borderRadius -
|
||||||
|
2 * config.defaultStyleContainer.padding,
|
||||||
|
width:
|
||||||
|
config.width -
|
||||||
|
2 * config.borderRadius -
|
||||||
|
2 * config.defaultStyleContainer.padding,
|
||||||
|
borderRadius: config.borderRadius + 'px'
|
||||||
|
};
|
||||||
|
setStyleOnDomElement(style, container);
|
||||||
|
// Style appIcon or hide
|
||||||
|
if (config.appIcon) {
|
||||||
|
setStyleOnDomElement(config.defaultStyleAppIcon, appIcon);
|
||||||
|
appIcon.src = config.appIcon;
|
||||||
|
} else {
|
||||||
|
setStyleOnDomElement(
|
||||||
|
{
|
||||||
|
display: 'none'
|
||||||
|
},
|
||||||
|
appIcon
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Style image
|
||||||
|
setStyleOnDomElement(config.defaultStyleImage, image);
|
||||||
|
// Style close button
|
||||||
|
setStyleOnDomElement(config.defaultStyleClose, close);
|
||||||
|
// Remove margin from text p
|
||||||
|
setStyleOnDomElement(config.defaultStyleText, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setContents(event, notificationObj) {
|
||||||
|
// sound
|
||||||
|
if (notificationObj.sound) {
|
||||||
|
// Check if file is accessible
|
||||||
|
try {
|
||||||
|
// If it's a local file, check it's existence
|
||||||
|
// Won't check remote files e.g. http://
|
||||||
|
if (
|
||||||
|
notificationObj.sound.match(/^file\:/) !== null ||
|
||||||
|
notificationObj.sound.match(/^\//) !== null
|
||||||
|
) {
|
||||||
|
let audio = new global.window.Audio(notificationObj.sound);
|
||||||
|
audio.play();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log(
|
||||||
|
'electron-notify: ERROR could not find sound file: ' +
|
||||||
|
notificationObj.sound.replace('file://', ''),
|
||||||
|
e,
|
||||||
|
e.stack
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let notiDoc = global.window.document;
|
||||||
|
// Title
|
||||||
|
let titleDoc = notiDoc.getElementById('title');
|
||||||
|
titleDoc.innerHTML = notificationObj.title || '';
|
||||||
|
// message
|
||||||
|
let messageDoc = notiDoc.getElementById('message');
|
||||||
|
messageDoc.innerHTML = notificationObj.text || '';
|
||||||
|
// Image
|
||||||
|
let imageDoc = notiDoc.getElementById('image');
|
||||||
|
if (notificationObj.image) {
|
||||||
|
imageDoc.src = notificationObj.image;
|
||||||
|
} else {
|
||||||
|
setStyleOnDomElement({ display: 'none' }, imageDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close button
|
||||||
|
let closeButton = notiDoc.getElementById('close');
|
||||||
|
closeButton.addEventListener('click', function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
ipc.send('UCAP::ElectronNotification::close', winId, notificationObj);
|
||||||
|
});
|
||||||
|
|
||||||
|
// URL
|
||||||
|
let container = notiDoc.getElementById('container');
|
||||||
|
container.addEventListener('click', function() {
|
||||||
|
ipc.send('UCAP::ElectronNotification::click', winId, notificationObj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStyleOnDomElement(styleObj, domElement) {
|
||||||
|
try {
|
||||||
|
for (let styleAttr in styleObj) {
|
||||||
|
domElement.style[styleAttr] = styleObj[styleAttr];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(
|
||||||
|
'electron-notify: Could not set style on domElement',
|
||||||
|
styleObj,
|
||||||
|
domElement
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadConfig(event, conf) {
|
||||||
|
setStyle(conf || {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
let notiDoc = global.window.document;
|
||||||
|
let container = notiDoc.getElementById('container');
|
||||||
|
let closeButton = notiDoc.getElementById('close');
|
||||||
|
|
||||||
|
// Remove event listener
|
||||||
|
let newContainer = container.cloneNode(true);
|
||||||
|
container.parentNode.replaceChild(newContainer, container);
|
||||||
|
let newCloseButton = closeButton.cloneNode(true);
|
||||||
|
closeButton.parentNode.replaceChild(newCloseButton, closeButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
ipc.on('UCAP::ElectronNotification::BrowserWindowSetContents', setContents);
|
||||||
|
ipc.on('UCAP::ElectronNotification::loadConfig', loadConfig);
|
||||||
|
ipc.on('UCAP::ElectronNotification::reset', reset);
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
console.log.apply(console, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete global.require;
|
||||||
|
delete global.exports;
|
||||||
|
delete global.module;
|
BIN
main/resources/notification/sound/messageAlarm.mp3
Normal file
130
main/resources/notification/styles/noti_messege.css
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
color: #333;
|
||||||
|
font-family: '나눔고딕', Malgun Gothic, '맑은고딕', Arial, Dotum, '돋움',
|
||||||
|
Gulim, '굴림';
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px !important;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body * {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
a:link,
|
||||||
|
a:visited,
|
||||||
|
a:hover,
|
||||||
|
a:active {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noti_messege {
|
||||||
|
width: 340px;
|
||||||
|
height: 100px;
|
||||||
|
border: 1px solid #666;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0px 0px 3px 0px #e7e7e7;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 16px 14px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.btn_close {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
right: 6px;
|
||||||
|
top: 6px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: url(../image/btn_close_gray.png) no-repeat 50% 50%;
|
||||||
|
}
|
||||||
|
.btn_close:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.photo {
|
||||||
|
position: relative;
|
||||||
|
top: 0px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: 4px 0;
|
||||||
|
width: 54px;
|
||||||
|
height: 54px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #5bc1ff url(../image/img_nophoto_50.png) no-repeat 50% 50%;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
}
|
||||||
|
.info .profile {
|
||||||
|
position: absolute;
|
||||||
|
width: 60px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.photo img {
|
||||||
|
overflow: hidden;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
.noti_messege .info .profile + div {
|
||||||
|
padding-left: 70px;
|
||||||
|
position: relative;
|
||||||
|
line-height: 180%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.sender {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
color: #333;
|
||||||
|
width: 94%;
|
||||||
|
}
|
||||||
|
.sender .name {
|
||||||
|
color: #2e7fb5;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.ellipsis {
|
||||||
|
display: block;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-wrap: normal;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.ellipsis_row2 {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
word-wrap: break-word;
|
||||||
|
line-height: 1.6em;
|
||||||
|
height: 3.2em;
|
||||||
|
}
|
50
main/resources/notification/template.html
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<title>[개발]M Messenger - 메시지 알림</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link
|
||||||
|
type="text/css"
|
||||||
|
rel="stylesheet"
|
||||||
|
href="styles/noti_messege.css"
|
||||||
|
/>
|
||||||
|
</HEAD>
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
overflow-y: hidden;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<BODY>
|
||||||
|
<div class="noti_messege" id="container">
|
||||||
|
<div class="info">
|
||||||
|
<a class="btn_close" id="close"></a>
|
||||||
|
<div class="profile">
|
||||||
|
<div class="photo">
|
||||||
|
<img src="" id="appIcon" />
|
||||||
|
<img
|
||||||
|
src=""
|
||||||
|
id="image"
|
||||||
|
onerror="this.src='image/img_nophoto_50.png';"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ul id="text">
|
||||||
|
<li class="sender ellipsis" id="title">
|
||||||
|
<span class="name">김 수안무 거북이와 두루미</span>님이 메시지를
|
||||||
|
보냈습니다.
|
||||||
|
</li>
|
||||||
|
<li class="message ellipsis_row2" id="message">
|
||||||
|
홍길동 대리(솔루션사업팀)홍길동 대리(솔루션사업팀)홍길동
|
||||||
|
대리(솔루션사업팀)홍길동 대리(솔루션사업팀)
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
229
main/src/app/AppWindow.ts
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as url from 'url';
|
||||||
|
|
||||||
|
import { app, BrowserWindow, screen, ipcMain, IpcMainEvent } from 'electron';
|
||||||
|
import windowStateKeeper from 'electron-window-state';
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
|
import { now } from '../util/now';
|
||||||
|
import { registerWindowStateChangedEvents } from '../lib/window-state';
|
||||||
|
import {
|
||||||
|
ElectronAppChannel,
|
||||||
|
ElectronBrowserWindowChannel,
|
||||||
|
ElectronWebContentsChannel
|
||||||
|
} from '@ucap-webmessenger/electron-core';
|
||||||
|
|
||||||
|
export class AppWindow {
|
||||||
|
private window: BrowserWindow | null = null;
|
||||||
|
|
||||||
|
private eventEmitter = new EventEmitter();
|
||||||
|
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
private _loadTime: number | null = null;
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
private _rendererReadyTime: number | null = null;
|
||||||
|
|
||||||
|
private minWidth = 960;
|
||||||
|
private minHeight = 660;
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
const savedWindowState = windowStateKeeper({
|
||||||
|
defaultWidth: this.minWidth,
|
||||||
|
defaultHeight: this.minHeight
|
||||||
|
});
|
||||||
|
|
||||||
|
const windowOptions: Electron.BrowserWindowConstructorOptions = {
|
||||||
|
x: savedWindowState.x,
|
||||||
|
y: savedWindowState.y,
|
||||||
|
width: savedWindowState.width,
|
||||||
|
height: savedWindowState.height,
|
||||||
|
minWidth: this.minWidth,
|
||||||
|
minHeight: this.minHeight,
|
||||||
|
center: true,
|
||||||
|
// This fixes subpixel aliasing on Windows
|
||||||
|
// See https://github.com/atom/atom/commit/683bef5b9d133cb194b476938c77cc07fd05b972
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
webPreferences: {
|
||||||
|
// Disable auxclick event
|
||||||
|
// See https://developers.google.com/web/updates/2016/10/auxclick
|
||||||
|
disableBlinkFeatures: 'Auxclick',
|
||||||
|
// Enable, among other things, the ResizeObserver
|
||||||
|
experimentalFeatures: true,
|
||||||
|
nodeIntegration: true
|
||||||
|
},
|
||||||
|
acceptFirstMouse: true,
|
||||||
|
icon: path.join(__dirname, 'resources/image', 'ico_64_64.png')
|
||||||
|
};
|
||||||
|
|
||||||
|
if (__DARWIN__) {
|
||||||
|
windowOptions.titleBarStyle = 'hidden';
|
||||||
|
} else if (__WIN32__) {
|
||||||
|
windowOptions.frame = false;
|
||||||
|
} else if (__LINUX__) {
|
||||||
|
windowOptions.icon = path.join(__dirname, 'static', 'icon-logo.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.window = new BrowserWindow(windowOptions);
|
||||||
|
savedWindowState.manage(this.window);
|
||||||
|
|
||||||
|
let quitting = false;
|
||||||
|
app.on(ElectronAppChannel.BeforeQuit, () => {
|
||||||
|
quitting = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(ElectronAppChannel.WillQuit, (event: IpcMainEvent) => {
|
||||||
|
quitting = true;
|
||||||
|
event.returnValue = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// on macOS, when the user closes the window we really just hide it. This
|
||||||
|
// lets us activate quickly and keep all our interesting logic in the
|
||||||
|
// renderer.
|
||||||
|
if (__DARWIN__) {
|
||||||
|
this.window.on(ElectronBrowserWindowChannel.Close, e => {
|
||||||
|
if (!quitting) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__WIN32__) {
|
||||||
|
// workaround for known issue with fullscreen-ing the app and restoring
|
||||||
|
// is that some Chromium API reports the incorrect bounds, so that it
|
||||||
|
// will leave a small space at the top of the screen on every other
|
||||||
|
// maximize
|
||||||
|
//
|
||||||
|
// adapted from https://github.com/electron/electron/issues/12971#issuecomment-403956396
|
||||||
|
//
|
||||||
|
// can be tidied up once https://github.com/electron/electron/issues/12971
|
||||||
|
// has been confirmed as resolved
|
||||||
|
this.window.once(ElectronBrowserWindowChannel.ReadyToShow, () => {
|
||||||
|
this.window.on(ElectronBrowserWindowChannel.Unmaximize, () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const bounds = this.window.getBounds();
|
||||||
|
bounds.width += 1;
|
||||||
|
this.window.setBounds(bounds);
|
||||||
|
bounds.width -= 1;
|
||||||
|
this.window.setBounds(bounds);
|
||||||
|
}, 5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public load(): void {
|
||||||
|
let startLoad = 0;
|
||||||
|
|
||||||
|
this.window.webContents.once(
|
||||||
|
ElectronWebContentsChannel.DidStartLoading,
|
||||||
|
() => {
|
||||||
|
this._rendererReadyTime = null;
|
||||||
|
this._loadTime = null;
|
||||||
|
|
||||||
|
startLoad = now();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.window.webContents.once(
|
||||||
|
ElectronWebContentsChannel.DidFinishLoad,
|
||||||
|
() => {
|
||||||
|
this.window.webContents.setVisualZoomLevelLimits(1, 1);
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
this.window.webContents.openDevTools();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._loadTime = now() - startLoad;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.window.webContents.on(ElectronWebContentsChannel.DidFailLoad, () => {
|
||||||
|
this.window.webContents.openDevTools();
|
||||||
|
this.window.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
registerWindowStateChangedEvents(this.window);
|
||||||
|
|
||||||
|
if (__DEV__) {
|
||||||
|
this.window.loadURL('http://localhost:4200');
|
||||||
|
} else {
|
||||||
|
this.window.loadURL(
|
||||||
|
url.format({
|
||||||
|
pathname: path.join(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
'ucap-webmessenger-app/index.html'
|
||||||
|
),
|
||||||
|
protocol: 'file:',
|
||||||
|
slashes: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Is the page loaded and has the renderer signalled it's ready? */
|
||||||
|
private get rendererLoaded(): boolean {
|
||||||
|
return !!this.loadTime && !!this.rendererReadyTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onClose(fn: () => void) {
|
||||||
|
this.window.on(ElectronBrowserWindowChannel.Closed, fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a function to call when the window is done loading. At that point
|
||||||
|
* the page has loaded and the renderer has signalled that it is ready.
|
||||||
|
*/
|
||||||
|
public onDidLoad(fn: () => void): EventEmitter {
|
||||||
|
return this.eventEmitter.on('did-load', fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isMinimized() {
|
||||||
|
return this.window.isMinimized();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Is the window currently visible? */
|
||||||
|
public isVisible() {
|
||||||
|
return this.window.isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
public restore() {
|
||||||
|
this.window.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
public focus() {
|
||||||
|
this.window.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Show the window. */
|
||||||
|
public show() {
|
||||||
|
this.window.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the time (in milliseconds) spent loading the page.
|
||||||
|
*
|
||||||
|
* This will be `null` until `onDidLoad` is called.
|
||||||
|
*/
|
||||||
|
public get loadTime(): number | null {
|
||||||
|
return this._loadTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the time (in milliseconds) elapsed from the renderer being loaded to it
|
||||||
|
* signaling it was ready.
|
||||||
|
*
|
||||||
|
* This will be `null` until `onDidLoad` is called.
|
||||||
|
*/
|
||||||
|
public get rendererReadyTime(): number | null {
|
||||||
|
return this._rendererReadyTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.window.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get browserWindow(): BrowserWindow | null {
|
||||||
|
return this.window;
|
||||||
|
}
|
||||||
|
}
|
0
main/src/crash/CrashWindow.ts
Normal file
1
main/src/crash/show-uncaught-exception.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export function showUncaughtException(isLaunchError: boolean, error: Error) {}
|
18
main/src/global.d.ts
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/* eslint-disable @typescript-eslint/interface-name-prefix */
|
||||||
|
/** Is the app running in dev mode? */
|
||||||
|
declare const __DEV__: boolean;
|
||||||
|
|
||||||
|
/** Is the app being built to run on Darwin? */
|
||||||
|
declare const __DARWIN__: boolean;
|
||||||
|
|
||||||
|
/** Is the app being built to run on Win32? */
|
||||||
|
declare const __WIN32__: boolean;
|
||||||
|
|
||||||
|
/** Is the app being built to run on Linux? */
|
||||||
|
declare const __LINUX__: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently executing process kind, this is specific to desktop
|
||||||
|
* and identifies the processes that we have.
|
||||||
|
*/
|
||||||
|
declare const __PROCESS_KIND__: 'main' | 'ui';
|
306
main/src/index.ts
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
import { app, ipcMain, IpcMainEvent, remote } from 'electron';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as url from 'url';
|
||||||
|
import * as fse from 'fs-extra';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
import { AppWindow } from './app/AppWindow';
|
||||||
|
import { now } from './util/now';
|
||||||
|
import { showUncaughtException } from './crash/show-uncaught-exception';
|
||||||
|
|
||||||
|
import {
|
||||||
|
UpdaterChannel,
|
||||||
|
FileChannel,
|
||||||
|
IdleStateChannel,
|
||||||
|
NotificationChannel
|
||||||
|
} from '@ucap-webmessenger/native-electron';
|
||||||
|
import { ElectronNotificationService } from '@ucap-webmessenger/electron-notification';
|
||||||
|
|
||||||
|
import { root } from './util/root';
|
||||||
|
import { DefaultFolder } from './lib/default-folder';
|
||||||
|
import { FileUtil } from './lib/file-util';
|
||||||
|
|
||||||
|
import { IdleChecker } from './lib/idle-checker';
|
||||||
|
import { NotificationRequest } from '@ucap-webmessenger/native';
|
||||||
|
import { ElectronAppChannel } from '@ucap-webmessenger/electron-core';
|
||||||
|
|
||||||
|
let appWindow: AppWindow | null = null;
|
||||||
|
|
||||||
|
const launchTime = now();
|
||||||
|
let readyTime: number | null = null;
|
||||||
|
|
||||||
|
type OnDidLoadFn = (window: AppWindow) => void;
|
||||||
|
let onDidLoadFns: Array<OnDidLoadFn> | null = [];
|
||||||
|
|
||||||
|
let preventQuit = false;
|
||||||
|
|
||||||
|
let notificationService: ElectronNotificationService | null;
|
||||||
|
|
||||||
|
function handleUncaughtException(error: Error) {
|
||||||
|
preventQuit = true;
|
||||||
|
|
||||||
|
// If we haven't got a window we'll assume it's because
|
||||||
|
// we've just launched and haven't created it yet.
|
||||||
|
// It could also be because we're encountering an unhandled
|
||||||
|
// exception on shutdown but that's less likely and since
|
||||||
|
// this only affects the presentation of the crash dialog
|
||||||
|
// it's a safe assumption to make.
|
||||||
|
const isLaunchError = appWindow === null;
|
||||||
|
|
||||||
|
if (appWindow) {
|
||||||
|
appWindow.destroy();
|
||||||
|
appWindow = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
showUncaughtException(isLaunchError, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUptimeInSeconds() {
|
||||||
|
return (now() - launchTime) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('uncaughtException', (error: Error) => {
|
||||||
|
// error = withSourceMappedStack(error);
|
||||||
|
// reportError(error, getExtraErrorContext());
|
||||||
|
handleUncaughtException(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
let isDuplicateInstance = false;
|
||||||
|
const gotSingleInstanceLock = app.requestSingleInstanceLock();
|
||||||
|
isDuplicateInstance = !gotSingleInstanceLock;
|
||||||
|
let idle: IdleChecker | null;
|
||||||
|
|
||||||
|
app.on(ElectronAppChannel.SecondInstance, (event, args, workingDirectory) => {
|
||||||
|
// Someone tried to run a second instance, we should focus our window.
|
||||||
|
if (appWindow) {
|
||||||
|
if (appWindow.isMinimized()) {
|
||||||
|
appWindow.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!appWindow.isVisible()) {
|
||||||
|
appWindow.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
appWindow.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDuplicateInstance) {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
const window = new AppWindow();
|
||||||
|
|
||||||
|
if (__DEV__) {
|
||||||
|
// const {
|
||||||
|
// default: installExtension,
|
||||||
|
// REDUX_DEVTOOLS
|
||||||
|
// } = require('electron-devtools-installer');
|
||||||
|
|
||||||
|
import('electron-debug').then(ed => {
|
||||||
|
ed.default({ showDevTools: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
import('electron-devtools-installer').then(edi => {
|
||||||
|
const ChromeLens = {
|
||||||
|
id: 'idikgljglpfilbhaboonnpnnincjhjkd',
|
||||||
|
electron: '>=1.2.1'
|
||||||
|
};
|
||||||
|
|
||||||
|
const extensions = [edi.REDUX_DEVTOOLS, ChromeLens];
|
||||||
|
|
||||||
|
for (const extension of extensions) {
|
||||||
|
try {
|
||||||
|
edi.default(extension);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onClose(() => {
|
||||||
|
appWindow = null;
|
||||||
|
if (!__DARWIN__ && !preventQuit) {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.onDidLoad(() => {
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
const fns = onDidLoadFns;
|
||||||
|
onDidLoadFns = null;
|
||||||
|
for (const fn of fns) {
|
||||||
|
fn(window);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.load();
|
||||||
|
|
||||||
|
appWindow = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method will be called when Electron has finished
|
||||||
|
// initialization and is ready to create browser windows.
|
||||||
|
// Some APIs can only be used after this event occurs.
|
||||||
|
app.on(ElectronAppChannel.Ready, () => {
|
||||||
|
if (isDuplicateInstance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
readyTime = now() - launchTime;
|
||||||
|
|
||||||
|
createWindow();
|
||||||
|
|
||||||
|
notificationService = new ElectronNotificationService({
|
||||||
|
width: 340,
|
||||||
|
height: 100,
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 0,
|
||||||
|
// appIcon: iconPath,
|
||||||
|
displayTime: 5000,
|
||||||
|
defaultStyleContainer: {},
|
||||||
|
defaultStyleAppIcon: { display: 'none' },
|
||||||
|
defaultStyleImage: {},
|
||||||
|
defaultStyleClose: {},
|
||||||
|
defaultStyleText: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
notificationService.options.defaultWindow.webPreferences.preload = path.join(
|
||||||
|
__dirname,
|
||||||
|
'resources/notification/preload.js'
|
||||||
|
);
|
||||||
|
|
||||||
|
notificationService.templatePath = path.join(
|
||||||
|
__dirname,
|
||||||
|
'resources/notification/template.html'
|
||||||
|
);
|
||||||
|
|
||||||
|
ipcMain.on('uncaught-exception', (event: IpcMainEvent, error: Error) => {
|
||||||
|
handleUncaughtException(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(
|
||||||
|
'send-error-report',
|
||||||
|
(
|
||||||
|
event: IpcMainEvent,
|
||||||
|
{ error, extra }: { error: Error; extra: { [key: string]: string } }
|
||||||
|
) => {}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Quit when all windows are closed.
|
||||||
|
app.on(ElectronAppChannel.WindowAllClosed, () => {
|
||||||
|
// On OS X it is common for applications and their menu bar
|
||||||
|
// to stay active until the user quits explicitly with Cmd + Q
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on(ElectronAppChannel.Activate, () => {
|
||||||
|
onDidLoad(window => {
|
||||||
|
window.show();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function onDidLoad(fn: OnDidLoadFn) {
|
||||||
|
if (onDidLoadFns) {
|
||||||
|
onDidLoadFns.push(fn);
|
||||||
|
} else {
|
||||||
|
if (appWindow) {
|
||||||
|
fn(appWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcMain.on(UpdaterChannel.Check, (event: IpcMainEvent, ...args: any[]) => {
|
||||||
|
event.returnValue = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(FileChannel.ReadFile, (event: IpcMainEvent, ...args: any[]) => {
|
||||||
|
try {
|
||||||
|
fse.readFile(root(args[0]), (err, data) => {
|
||||||
|
if (!!err) {
|
||||||
|
event.returnValue = null;
|
||||||
|
} else {
|
||||||
|
event.returnValue = new Blob([data]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
event.returnValue = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(
|
||||||
|
FileChannel.SaveFile,
|
||||||
|
async (event: IpcMainEvent, ...args: any[]) => {
|
||||||
|
try {
|
||||||
|
const buffer: Buffer = args[0];
|
||||||
|
const fileName: string = args[1];
|
||||||
|
let savePath: string = path.join(
|
||||||
|
!!args[2] ? args[2] : DefaultFolder.downloads(),
|
||||||
|
fileName
|
||||||
|
);
|
||||||
|
savePath = await FileUtil.uniqueFileName(savePath);
|
||||||
|
|
||||||
|
fse.writeFile(savePath, buffer, err => {
|
||||||
|
if (!err) {
|
||||||
|
event.returnValue = savePath;
|
||||||
|
} else {
|
||||||
|
event.returnValue = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
event.returnValue = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
ipcMain.on(
|
||||||
|
IdleStateChannel.StartCheck,
|
||||||
|
(event: IpcMainEvent, ...args: any[]) => {
|
||||||
|
if (!!idle) {
|
||||||
|
idle.destoryChecker();
|
||||||
|
idle = null;
|
||||||
|
}
|
||||||
|
idle = new IdleChecker(appWindow.browserWindow); // default 10min
|
||||||
|
idle.startChecker();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
ipcMain.on(
|
||||||
|
NotificationChannel.Notify,
|
||||||
|
(event: IpcMainEvent, ...args: any[]) => {
|
||||||
|
const noti: NotificationRequest = args[0];
|
||||||
|
|
||||||
|
notificationService.notify({
|
||||||
|
title: noti.title,
|
||||||
|
text: noti.contents,
|
||||||
|
image:
|
||||||
|
noti.image ||
|
||||||
|
path.join(__dirname, 'resources/notification/image/img_nophoto_50.png'),
|
||||||
|
sound: noti.useSound
|
||||||
|
? path.join(
|
||||||
|
'file://',
|
||||||
|
__dirname,
|
||||||
|
'resources/notification/sound/messageAlarm.mp3'
|
||||||
|
)
|
||||||
|
: '',
|
||||||
|
onClick: () => {
|
||||||
|
console.log('onClick');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Channel.notify', noti);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
ipcMain.on(
|
||||||
|
NotificationChannel.CloseAllNotify,
|
||||||
|
(event: IpcMainEvent, ...args: any[]) => {
|
||||||
|
console.log('Channel.closeAllNotify', args);
|
||||||
|
}
|
||||||
|
);
|
37
main/src/lib/default-folder.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import * as os from 'os';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import * as fse from 'fs-extra';
|
||||||
|
|
||||||
|
export class DefaultFolder {
|
||||||
|
static downloads(): string {
|
||||||
|
switch (os.platform()) {
|
||||||
|
case 'win32':
|
||||||
|
return `${process.env.USERPROFILE}/Downloads`;
|
||||||
|
case 'darwin':
|
||||||
|
return `${process.env.HOME}/Downloads`;
|
||||||
|
case 'linux': {
|
||||||
|
let dir: Buffer;
|
||||||
|
try {
|
||||||
|
dir = execSync('xdg-user-dir DOWNLOAD', { stdio: [0, 3, 3] });
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
if (dir) {
|
||||||
|
return dir.toString('utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
let stat: fse.Stats;
|
||||||
|
const homeDownloads = `${process.env.HOME}/Downloads`;
|
||||||
|
try {
|
||||||
|
stat = fse.statSync(homeDownloads);
|
||||||
|
} catch (_) {}
|
||||||
|
if (stat) {
|
||||||
|
return homeDownloads;
|
||||||
|
}
|
||||||
|
return '/tmp/';
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
222
main/src/lib/file-util.ts
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as fse from 'fs-extra';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* separator
|
||||||
|
* If the specified filename exists, the separator will be added before the incremental value such as: file{separator}2.jpg
|
||||||
|
* The default value is '-'.
|
||||||
|
*
|
||||||
|
* mode
|
||||||
|
* The mode allows you to specify which characters to use to generate the incremental value (the string after the separator)
|
||||||
|
* The default value is 'numeric'.
|
||||||
|
* 'numeric' Using the following characters: 1234567890
|
||||||
|
* 'alpha' Using the following characters: abcdefghijklmnopqrstuvwxyz
|
||||||
|
* 'ALPHA' Using the following characters: ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||||
|
* 'alphanumeric' Using the following characters: 0123456789abcdefghijklmnopqrstuvwxyz
|
||||||
|
* 'ALPHANUMERIC' Using the following characters: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||||
|
* 'charset' You must specify the characters you wish to use in the charset option
|
||||||
|
*
|
||||||
|
* paddingCharacter && paddingSize
|
||||||
|
* If you wish to left-pad the incremental values with a character, use this option. Here's an example :
|
||||||
|
* var uniquefilename = require('uniquefilename');
|
||||||
|
* options = {mode: 'alpha', paddingCharacter: '0', paddingSize: 3};
|
||||||
|
* uniquefilename.get('/path/to/dir/file.jpg', options, function(filename) {
|
||||||
|
* // filename might be "/path/to/dir/file.jpg",
|
||||||
|
* // "/path/to/dir/file-002.jpg", "/path/to/dir/file-045.jpg", etc...
|
||||||
|
* // depending on the files that exist on your filesystem
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* alwaysAppend
|
||||||
|
* If alwaysAppend is true filenames will include the separator and attachment from the first request.
|
||||||
|
* So instead of file.jpg, file-2.jpg you'd get file-1.jpg, file-2.jpg.
|
||||||
|
*/
|
||||||
|
export interface UniqueFileNameOption {
|
||||||
|
separator?: string;
|
||||||
|
mode?:
|
||||||
|
| 'numeric'
|
||||||
|
| 'alpha'
|
||||||
|
| 'ALPHA'
|
||||||
|
| 'alphanumeric'
|
||||||
|
| 'ALPHANUMERIC'
|
||||||
|
| 'charset';
|
||||||
|
paddingCharacter?: string;
|
||||||
|
paddingSize?: number;
|
||||||
|
alwaysAppend?: boolean;
|
||||||
|
charset?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const charsets = {
|
||||||
|
alpha: 'abcdefghijklmnopqrstuvwxyz',
|
||||||
|
alphanumeric: '0123456789abcdefghijklmnopqrstuvwxyz',
|
||||||
|
ALPHA: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||||
|
ALPHANUMERIC: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||||
|
};
|
||||||
|
|
||||||
|
interface UniqueFile {
|
||||||
|
dir?: string;
|
||||||
|
ext?: string;
|
||||||
|
base?: string;
|
||||||
|
increment?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FileUtil {
|
||||||
|
static blobToBuffer(blob: Blob): Promise<Buffer> {
|
||||||
|
if (typeof Blob === 'undefined' || !(blob instanceof Blob)) {
|
||||||
|
throw new Error('first argument must be a Blob');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise<Buffer>((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onloadend = () => {
|
||||||
|
resolve(Buffer.from(reader.result as ArrayBuffer));
|
||||||
|
};
|
||||||
|
reader.onerror = () => {
|
||||||
|
reader.abort();
|
||||||
|
reject(reader.error);
|
||||||
|
};
|
||||||
|
reader.readAsArrayBuffer(blob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static uniqueFileName(
|
||||||
|
filePath: string,
|
||||||
|
options?: UniqueFileNameOption
|
||||||
|
): Promise<string> {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
const dir = path.dirname(filePath);
|
||||||
|
const ext = path.extname(filePath);
|
||||||
|
const base = path.basename(filePath, ext);
|
||||||
|
|
||||||
|
const uniqueFile: UniqueFile = {
|
||||||
|
dir,
|
||||||
|
ext,
|
||||||
|
base
|
||||||
|
};
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
options.separator = options.separator || '-';
|
||||||
|
options.mode = options.mode || 'numeric';
|
||||||
|
|
||||||
|
if ('numeric' !== options.mode) {
|
||||||
|
if (charsets[options.mode]) {
|
||||||
|
options.charset = charsets[options.mode];
|
||||||
|
options.mode = 'charset';
|
||||||
|
} else if (
|
||||||
|
'charset' !== options.mode ||
|
||||||
|
('charset' === options.mode && !options.charset)
|
||||||
|
) {
|
||||||
|
options.mode = 'numeric';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.paddingSize && !options.paddingCharacter) {
|
||||||
|
options.paddingCharacter = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtil.uniqueFileNameProcess(
|
||||||
|
uniqueFile,
|
||||||
|
options,
|
||||||
|
(fileName: string) => {
|
||||||
|
resolve(fileName);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uniqueFileNameProcess(
|
||||||
|
uniqueFile: UniqueFile,
|
||||||
|
options: UniqueFileNameOption,
|
||||||
|
callback: (fileName: string) => void
|
||||||
|
) {
|
||||||
|
let fileName: string;
|
||||||
|
let append = '';
|
||||||
|
|
||||||
|
if (options.alwaysAppend && !uniqueFile.increment) {
|
||||||
|
uniqueFile.increment = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uniqueFile.increment) {
|
||||||
|
if ('numeric' === options.mode) {
|
||||||
|
append = '' + uniqueFile.increment;
|
||||||
|
} else {
|
||||||
|
append = FileUtil.numberToString(uniqueFile.increment, options.charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.paddingSize) {
|
||||||
|
while (append.length < options.paddingSize) {
|
||||||
|
append = options.paddingCharacter + append;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
append = options.separator + append;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName = path.join(
|
||||||
|
uniqueFile.dir,
|
||||||
|
uniqueFile.base + append + uniqueFile.ext
|
||||||
|
);
|
||||||
|
if (fse.existsSync(fileName)) {
|
||||||
|
if (uniqueFile.increment) {
|
||||||
|
uniqueFile.increment += 1;
|
||||||
|
} else {
|
||||||
|
uniqueFile.increment = 'numeric' === options.mode ? 2 : 1;
|
||||||
|
}
|
||||||
|
return FileUtil.uniqueFileNameProcess(uniqueFile, options, callback);
|
||||||
|
} else {
|
||||||
|
return callback(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static numberToString(nbr: number, charset: string) {
|
||||||
|
const charsetLen = charset.length;
|
||||||
|
let strLen = 0;
|
||||||
|
let strThisLen = 0;
|
||||||
|
let tmp: number;
|
||||||
|
|
||||||
|
for (let maxpower = 20; maxpower >= 0; maxpower--) {
|
||||||
|
const maxvalue = FileUtil.sumOfPowerFromOne(charsetLen, maxpower);
|
||||||
|
|
||||||
|
if (maxvalue < nbr) {
|
||||||
|
strLen = maxpower + 1;
|
||||||
|
strThisLen = maxvalue + Math.pow(charsetLen, maxpower + 1) - maxvalue;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 === strLen) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let str = '';
|
||||||
|
while (--strLen >= 0) {
|
||||||
|
if (strLen === 0) {
|
||||||
|
str += charset.charAt(nbr - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strThisLen = Math.pow(charsetLen, strLen);
|
||||||
|
const initial = FileUtil.sumOfPowerFromOne(charsetLen, strLen - 1);
|
||||||
|
|
||||||
|
for (tmp = charsetLen; tmp >= 1; tmp--) {
|
||||||
|
if (initial + tmp * strThisLen < nbr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nbr -= tmp * strThisLen;
|
||||||
|
str += charset.charAt(tmp - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static sumOfPowerFromOne(base: number, maxpower: number) {
|
||||||
|
let value = 0;
|
||||||
|
for (let tmp = maxpower; tmp >= 1; tmp--) {
|
||||||
|
value += Math.pow(base, tmp);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
72
main/src/lib/idle-checker.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { powerMonitor, BrowserWindow } from 'electron';
|
||||||
|
import { IdleStateChannel } from '@ucap-webmessenger/native-electron';
|
||||||
|
import { setInterval } from 'timers';
|
||||||
|
|
||||||
|
export enum IdleType {
|
||||||
|
ACTIVE = 'ACT',
|
||||||
|
IDLE = 'IDLE'
|
||||||
|
}
|
||||||
|
|
||||||
|
export class IdleChecker {
|
||||||
|
private limitSec: number;
|
||||||
|
private intervalObject: any;
|
||||||
|
private status: IdleType;
|
||||||
|
private window: BrowserWindow | null;
|
||||||
|
|
||||||
|
public constructor(window: BrowserWindow, limitedMin?: number) {
|
||||||
|
limitedMin = limitedMin || 10;
|
||||||
|
|
||||||
|
this.limitSec = limitedMin * 60;
|
||||||
|
this.intervalObject = null;
|
||||||
|
this.status = IdleType.ACTIVE;
|
||||||
|
this.window = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
private doCheckIdle(): void {
|
||||||
|
const idle: number = powerMonitor.getSystemIdleTime();
|
||||||
|
if (idle > this.limitSec) {
|
||||||
|
if (this.status === IdleType.ACTIVE) {
|
||||||
|
this.status = IdleType.IDLE;
|
||||||
|
// TODO :: USER_STATUS change away
|
||||||
|
this.window.webContents.send(IdleStateChannel.Changed, this.status);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.status === IdleType.IDLE) {
|
||||||
|
this.status = IdleType.ACTIVE;
|
||||||
|
// TODO :: USER_STATUS chage online
|
||||||
|
this.window.webContents.send(IdleStateChannel.Changed, this.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public resetIdleTime(limitedMin: number): void {
|
||||||
|
limitedMin = limitedMin || 10;
|
||||||
|
|
||||||
|
if (!!this.intervalObject) {
|
||||||
|
clearInterval(this.intervalObject);
|
||||||
|
}
|
||||||
|
this.limitSec = limitedMin * 60;
|
||||||
|
|
||||||
|
// storage.setIdleTimeLimit(limitedMin);
|
||||||
|
// global.opt_idleTimeLimit = limitedMin;
|
||||||
|
|
||||||
|
this.startChecker();
|
||||||
|
console.log('RESET IDLE TIMER in ' + limitedMin + 'm');
|
||||||
|
}
|
||||||
|
|
||||||
|
public startChecker() {
|
||||||
|
console.log('Idle Checker Start');
|
||||||
|
if (!this.intervalObject) {
|
||||||
|
this.intervalObject = setInterval(() => {
|
||||||
|
this.doCheckIdle();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public destoryChecker() {
|
||||||
|
console.log('Idle Checker Destory');
|
||||||
|
if (!!this.intervalObject) {
|
||||||
|
clearInterval(this.intervalObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
99
main/src/lib/storage.ts
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
import Store from 'electron-store';
|
||||||
|
|
||||||
|
const STORE_KEY_AUTORUN = 'options.autoRun';
|
||||||
|
const STORE_KEY_AUTOLOGIN = 'options.autoLogin';
|
||||||
|
const STORE_KEY_STARTUPHIDEWINDOW = 'options.startupHideWindow';
|
||||||
|
const STORE_KEY_LOGINCOMPANY = 'login.loginCompany';
|
||||||
|
const STORE_KEY_LOGINID = 'login.loginId';
|
||||||
|
const STORE_KEY_LOGINPW = 'login.loginPw';
|
||||||
|
|
||||||
|
export class Storage extends Store<any> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
schema: {
|
||||||
|
options: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
autoRun: {
|
||||||
|
type: 'boolean'
|
||||||
|
},
|
||||||
|
autoLogin: {
|
||||||
|
type: 'boolean'
|
||||||
|
},
|
||||||
|
startupHideWindow: {
|
||||||
|
type: 'boolean'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
autoRun: false,
|
||||||
|
autoLogin: false,
|
||||||
|
startupHideWindow: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
login: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
loginCompany: {
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
loginId: {
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
loginPw: {
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
loginCompany: '',
|
||||||
|
loginId: '',
|
||||||
|
loginPw: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
encryptionKey: 'ucap',
|
||||||
|
fileExtension: 'dat'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get autoRun(): boolean {
|
||||||
|
return this.get(STORE_KEY_AUTORUN, false);
|
||||||
|
}
|
||||||
|
set autoRun(autoRun: boolean) {
|
||||||
|
this.set(STORE_KEY_AUTORUN, autoRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
get autoLogin(): boolean {
|
||||||
|
return this.get(STORE_KEY_AUTOLOGIN, false);
|
||||||
|
}
|
||||||
|
set autoLogin(autoLogin: boolean) {
|
||||||
|
this.set(STORE_KEY_AUTOLOGIN, autoLogin);
|
||||||
|
}
|
||||||
|
|
||||||
|
get startupHideWindow(): boolean {
|
||||||
|
return this.get(STORE_KEY_STARTUPHIDEWINDOW, false);
|
||||||
|
}
|
||||||
|
set startupHideWindow(startupHideWindow: boolean) {
|
||||||
|
this.set(STORE_KEY_STARTUPHIDEWINDOW, startupHideWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
get loginCompany(): string {
|
||||||
|
return this.get(STORE_KEY_LOGINCOMPANY, false);
|
||||||
|
}
|
||||||
|
set loginCompany(loginCompany: string) {
|
||||||
|
this.set(STORE_KEY_LOGINCOMPANY, loginCompany);
|
||||||
|
}
|
||||||
|
|
||||||
|
get loginId(): string {
|
||||||
|
return this.get(STORE_KEY_LOGINID, false);
|
||||||
|
}
|
||||||
|
set loginId(loginId: string) {
|
||||||
|
this.set(STORE_KEY_LOGINID, loginId);
|
||||||
|
}
|
||||||
|
|
||||||
|
get loginPw(): string {
|
||||||
|
return this.get(STORE_KEY_LOGINPW, false);
|
||||||
|
}
|
||||||
|
set loginPw(loginPw: string) {
|
||||||
|
this.set(STORE_KEY_LOGINPW, loginPw);
|
||||||
|
}
|
||||||
|
}
|
54
main/src/lib/window-state.ts
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import { BrowserWindow } from 'electron';
|
||||||
|
import { WindowState } from '@ucap-webmessenger/native';
|
||||||
|
import { WindowStateChannel } from '@ucap-webmessenger/native-electron';
|
||||||
|
import { ElectronBrowserWindowChannel } from '@ucap-webmessenger/electron-core';
|
||||||
|
|
||||||
|
export function getWindowState(window: Electron.BrowserWindow): WindowState {
|
||||||
|
if (window.isFullScreen()) {
|
||||||
|
return WindowState.FullScreen;
|
||||||
|
} else if (window.isMaximized()) {
|
||||||
|
return WindowState.Maximized;
|
||||||
|
} else if (window.isMinimized()) {
|
||||||
|
return WindowState.Minimized;
|
||||||
|
} else if (!window.isVisible()) {
|
||||||
|
return WindowState.Hidden;
|
||||||
|
} else {
|
||||||
|
return WindowState.Normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerWindowStateChangedEvents(window: BrowserWindow) {
|
||||||
|
window.on(ElectronBrowserWindowChannel.EnterFullScreen, () =>
|
||||||
|
sendWindowStateEvent(window, WindowState.FullScreen)
|
||||||
|
);
|
||||||
|
|
||||||
|
window.on(ElectronBrowserWindowChannel.LeaveFullScreen, () =>
|
||||||
|
sendWindowStateEvent(window, WindowState.Normal)
|
||||||
|
);
|
||||||
|
|
||||||
|
window.on(ElectronBrowserWindowChannel.Maximize, () =>
|
||||||
|
sendWindowStateEvent(window, WindowState.Maximized)
|
||||||
|
);
|
||||||
|
window.on(ElectronBrowserWindowChannel.Minimize, () =>
|
||||||
|
sendWindowStateEvent(window, WindowState.Minimized)
|
||||||
|
);
|
||||||
|
window.on(ElectronBrowserWindowChannel.Unmaximize, () =>
|
||||||
|
sendWindowStateEvent(window, WindowState.Normal)
|
||||||
|
);
|
||||||
|
window.on(ElectronBrowserWindowChannel.Restore, () =>
|
||||||
|
sendWindowStateEvent(window, WindowState.Normal)
|
||||||
|
);
|
||||||
|
window.on(ElectronBrowserWindowChannel.Hide, () =>
|
||||||
|
sendWindowStateEvent(window, WindowState.Hidden)
|
||||||
|
);
|
||||||
|
window.on(ElectronBrowserWindowChannel.Show, () => {
|
||||||
|
// because the app can be maximized before being closed - which will restore it
|
||||||
|
// maximized on the next launch - this function should inspect the current state
|
||||||
|
// rather than always assume it is a 'normal' launch
|
||||||
|
sendWindowStateEvent(window, getWindowState(window));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendWindowStateEvent(window: BrowserWindow, windowState: WindowState) {
|
||||||
|
window.webContents.send(WindowStateChannel.Changed, windowState);
|
||||||
|
}
|
4
main/src/util/now.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export function now(): number {
|
||||||
|
const time = process.hrtime();
|
||||||
|
return time[0] * 1000 + time[1] / 1000000;
|
||||||
|
}
|
11
main/src/util/root.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
const _root = __DEV__
|
||||||
|
? path.resolve(__dirname, '..', '..')
|
||||||
|
: path.resolve(__dirname);
|
||||||
|
|
||||||
|
export function root(...paths: string[]) {
|
||||||
|
const args = Array.prototype.slice.call(paths, 0);
|
||||||
|
return path.join.apply(path, [_root].concat(args));
|
||||||
|
}
|
32
main/tsconfig.main.json
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"outDir": "../dist/main",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"target": "es5",
|
||||||
|
"types": ["node"],
|
||||||
|
"lib": ["es2017", "es2016", "es2015", "dom"],
|
||||||
|
"paths": {
|
||||||
|
"@ucap-webmessenger/electron-core": [
|
||||||
|
"../projects/ucap-webmessenger-electron-core/src/public-api"
|
||||||
|
],
|
||||||
|
"@ucap-webmessenger/electron-notification": [
|
||||||
|
"../projects/ucap-webmessenger-electron-notification/src/public-api"
|
||||||
|
],
|
||||||
|
"@ucap-webmessenger/native": [
|
||||||
|
"../projects/ucap-webmessenger-native/src/public-api"
|
||||||
|
],
|
||||||
|
"@ucap-webmessenger/native-electron": [
|
||||||
|
"../projects/ucap-webmessenger-native-electron/src/public-api"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"exclude": ["../node_modules", "**/*.spec.ts"]
|
||||||
|
}
|
16640
package-lock.json
generated
Normal file
116
package.json
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
{
|
||||||
|
"name": "ucap-webmessenger",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "npm-run-all -p start:renderer start:main",
|
||||||
|
"start:main": "wait-on http-get://localhost:4200/ && npm run build:main:dev && electron --nolazy --inspect-brk=9229 .",
|
||||||
|
"start:renderer": "ng serve",
|
||||||
|
"start:web": "cross-env UCAP_ENV=WEB ng serve",
|
||||||
|
"start:production": "npm run build:renderer && npm run build:main:prod && electron --nolazy --inspect-brk=9229 .",
|
||||||
|
"build:renderer": "cross-env NODE_ENV=production ng build --base-href ./",
|
||||||
|
"build:main:dev": "cross-env NODE_ENV=development TS_NODE_PROJECT='./config/tsconfig.webpack.json' parallel-webpack --config=config/main.webpack.config.ts",
|
||||||
|
"build:main:prod": "cross-env NODE_ENV=production TS_NODE_PROJECT='./config/tsconfig.webpack.json' NODE_OPTIONS='--max_old_space_size=4096' parallel-webpack --config=config/main.webpack.config.ts",
|
||||||
|
"test": "ng test",
|
||||||
|
"lint": "ng lint",
|
||||||
|
"e2e": "ng e2e"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-builders/custom-webpack": "^8.2.0",
|
||||||
|
"@angular-devkit/build-angular": "~0.803.14",
|
||||||
|
"@angular-devkit/build-ng-packagr": "~0.803.14",
|
||||||
|
"@angular/animations": "^8.2.12",
|
||||||
|
"@angular/cdk": "^8.2.3",
|
||||||
|
"@angular/cli": "~8.3.14",
|
||||||
|
"@angular/common": "~8.2.12",
|
||||||
|
"@angular/compiler": "~8.2.12",
|
||||||
|
"@angular/compiler-cli": "~8.2.12",
|
||||||
|
"@angular/core": "~8.2.12",
|
||||||
|
"@angular/flex-layout": "^8.0.0-beta.27",
|
||||||
|
"@angular/forms": "~8.2.12",
|
||||||
|
"@angular/language-service": "~8.2.12",
|
||||||
|
"@angular/material": "^8.2.3",
|
||||||
|
"@angular/material-moment-adapter": "^8.2.3",
|
||||||
|
"@angular/platform-browser": "~8.2.12",
|
||||||
|
"@angular/platform-browser-dynamic": "~8.2.12",
|
||||||
|
"@angular/router": "~8.2.12",
|
||||||
|
"@ngrx/effects": "^8.4.0",
|
||||||
|
"@ngrx/entity": "^8.4.0",
|
||||||
|
"@ngrx/router-store": "^8.4.0",
|
||||||
|
"@ngrx/store": "^8.4.0",
|
||||||
|
"@ngrx/store-devtools": "^8.4.0",
|
||||||
|
"@ngx-translate/core": "^11.0.1",
|
||||||
|
"@types/copy-webpack-plugin": "^5.0.0",
|
||||||
|
"@types/crypto-js": "^3.1.43",
|
||||||
|
"@types/detect-browser": "^4.0.0",
|
||||||
|
"@types/electron-debug": "^2.1.0",
|
||||||
|
"@types/electron-devtools-installer": "^2.2.0",
|
||||||
|
"@types/extract-text-webpack-plugin": "^3.0.4",
|
||||||
|
"@types/fs-extra": "^8.0.0",
|
||||||
|
"@types/file-saver": "^2.0.1",
|
||||||
|
"@types/filesize": "^4.1.0",
|
||||||
|
"@types/jasmine": "~3.3.8",
|
||||||
|
"@types/jasminewd2": "~2.0.3",
|
||||||
|
"@types/node": "^10.14.22",
|
||||||
|
"@types/semver": "^6.0.2",
|
||||||
|
"@types/webpack": "^4.39.5",
|
||||||
|
"@types/webpack-merge": "^4.1.5",
|
||||||
|
"@types/webpack-node-externals": "^1.6.3",
|
||||||
|
"awesome-node-loader": "^1.1.1",
|
||||||
|
"awesome-typescript-loader": "^5.2.1",
|
||||||
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
|
"copy-webpack-plugin": "^5.0.4",
|
||||||
|
"codelyzer": "^5.0.0",
|
||||||
|
"concurrently": "^4.1.2",
|
||||||
|
"crypto-js": "^3.1.9-1",
|
||||||
|
"cross-env": "^5.2.1",
|
||||||
|
"detect-browser": "^4.6.0",
|
||||||
|
"devtron": "^1.4.0",
|
||||||
|
"electron": "^6.1.2",
|
||||||
|
"electron-builder": "^21.2.0",
|
||||||
|
"electron-debug": "^3.0.1",
|
||||||
|
"electron-devtools-installer": "^2.2.4",
|
||||||
|
"electron-log": "^3.0.8",
|
||||||
|
"electron-reload": "^1.5.0",
|
||||||
|
"electron-store": "^4.0.0",
|
||||||
|
"electron-updater": "^4.1.2",
|
||||||
|
"electron-window-state": "^5.0.3",
|
||||||
|
"file-saver": "^2.0.2",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
|
"filesize": "^4.1.2",
|
||||||
|
"hammerjs": "^2.0.8",
|
||||||
|
"jasmine-core": "~3.4.0",
|
||||||
|
"jasmine-spec-reporter": "~4.2.1",
|
||||||
|
"karma": "~4.1.0",
|
||||||
|
"karma-chrome-launcher": "~2.2.0",
|
||||||
|
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||||
|
"karma-jasmine": "~2.0.1",
|
||||||
|
"karma-jasmine-html-reporter": "^1.4.0",
|
||||||
|
"moment": "^2.24.0",
|
||||||
|
"ng-packagr": "^5.4.0",
|
||||||
|
"ngrx-store-freeze": "^0.2.4",
|
||||||
|
"ngx-logger": "^4.0.5",
|
||||||
|
"ngx-perfect-scrollbar": "^8.0.0",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"parallel-webpack": "^2.4.0",
|
||||||
|
"protractor": "~5.4.0",
|
||||||
|
"queueing-subject": "^0.3.4",
|
||||||
|
"rxjs": "^6.5.2",
|
||||||
|
"semver": "^6.3.0",
|
||||||
|
"ts-node": "~7.0.0",
|
||||||
|
"tsickle": "^0.37.0",
|
||||||
|
"tslib": "^1.10.0",
|
||||||
|
"tslint": "~5.15.0",
|
||||||
|
"typescript": "~3.5.3",
|
||||||
|
"wait-on": "^3.3.0",
|
||||||
|
"webpack": "4.39.2",
|
||||||
|
"webpack-cli": "^3.3.7",
|
||||||
|
"webpack-node-externals": "^1.7.2",
|
||||||
|
"zone.js": "~0.9.1"
|
||||||
|
},
|
||||||
|
"main": "./dist/main/main.js"
|
||||||
|
}
|
24
projects/ucap-webmessenger-api-common/README.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# UcapWebmessengerApiCommon
|
||||||
|
|
||||||
|
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.4.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name --project ucap-webmessenger-api-common` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ucap-webmessenger-api-common`.
|
||||||
|
> Note: Don't forget to add `--project ucap-webmessenger-api-common` or else it will be added to the default project in your `angular.json` file.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build ucap-webmessenger-api-common` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||||
|
|
||||||
|
## Publishing
|
||||||
|
|
||||||
|
After building your library with `ng build ucap-webmessenger-api-common`, go to the dist folder `cd dist/ucap-webmessenger-api-common` and run `npm publish`.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test ucap-webmessenger-api-common` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
32
projects/ucap-webmessenger-api-common/karma.conf.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage-istanbul-reporter'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
dir: require('path').join(__dirname, '../../coverage/ucap-webmessenger-api-common'),
|
||||||
|
reports: ['html', 'lcovonly', 'text-summary'],
|
||||||
|
fixWebpackSourcePaths: true
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false,
|
||||||
|
restartOnFileChange: true
|
||||||
|
});
|
||||||
|
};
|
7
projects/ucap-webmessenger-api-common/ng-package.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||||
|
"dest": "../../dist/ucap-webmessenger-api-common",
|
||||||
|
"lib": {
|
||||||
|
"entryFile": "src/public-api.ts"
|
||||||
|
}
|
||||||
|
}
|
8
projects/ucap-webmessenger-api-common/package.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"name": "@ucap-webmessenger/api-common",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": "^8.2.4",
|
||||||
|
"@angular/core": "^8.2.4"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface FileProfileSaveRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
file?: File;
|
||||||
|
intro?: string;
|
||||||
|
initProfileImage?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileProfileSaveResponse extends APIResponse {
|
||||||
|
ProfileURL?: string;
|
||||||
|
ProfileSubDir?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileProfileEncodeMap = {};
|
||||||
|
|
||||||
|
export const encodeFileProfileSave: APIEncoder<FileProfileSaveRequest> = (
|
||||||
|
req: FileProfileSaveRequest
|
||||||
|
) => {
|
||||||
|
return ParameterUtil.encode(fileProfileEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeFileProfileSave: APIDecoder<FileProfileSaveResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
return {} as FileProfileSaveResponse;
|
||||||
|
};
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIEncoder,
|
||||||
|
ParameterUtil,
|
||||||
|
APIFormDataEncoder
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
import { FileDownloadItem } from '../models/file-download-item';
|
||||||
|
|
||||||
|
export interface FileTalkDownloadRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
attachmentsSeq?: number;
|
||||||
|
fileDownloadItem?: FileDownloadItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileTalkDownloadEncodeMap = {
|
||||||
|
userSeq: 'p_user_seq',
|
||||||
|
deviceType: 'p_device_type',
|
||||||
|
token: 'p_token',
|
||||||
|
attachmentsSeq: 'p_att_seq'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeFileTalkDownload: APIEncoder<FileTalkDownloadRequest> = (
|
||||||
|
req: FileTalkDownloadRequest
|
||||||
|
) => {
|
||||||
|
const extraParams: any = {};
|
||||||
|
|
||||||
|
extraParams.userSeq = String(req.userSeq);
|
||||||
|
extraParams.attachmentsSeq = String(req.attachmentsSeq);
|
||||||
|
|
||||||
|
return ParameterUtil.encode(fileTalkDownloadEncodeMap, req, extraParams);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeFormDataFileTalkDownload: APIFormDataEncoder<
|
||||||
|
FileTalkDownloadRequest
|
||||||
|
> = (req: FileTalkDownloadRequest) => {
|
||||||
|
const extraParams: any = {};
|
||||||
|
|
||||||
|
extraParams.userSeq = String(req.userSeq);
|
||||||
|
extraParams.attachmentsSeq = String(req.attachmentsSeq);
|
||||||
|
|
||||||
|
return ParameterUtil.encodeFormData(
|
||||||
|
fileTalkDownloadEncodeMap,
|
||||||
|
req,
|
||||||
|
extraParams
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,99 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil,
|
||||||
|
StatusCode,
|
||||||
|
JsonAnalization,
|
||||||
|
APIFormDataEncoder
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
import { FileUploadItem } from '../models/file-upload-item';
|
||||||
|
|
||||||
|
export interface FileTalkSaveRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
file: File;
|
||||||
|
fileName?: string;
|
||||||
|
fileUploadItem: FileUploadItem;
|
||||||
|
thumb?: File;
|
||||||
|
voice?: boolean;
|
||||||
|
voiceTime?: string;
|
||||||
|
roomSeq?: string;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileTalkSaveResponse extends APIResponse {
|
||||||
|
roomSeq?: string;
|
||||||
|
fileName?: string;
|
||||||
|
fileExt?: string;
|
||||||
|
fileType?: string;
|
||||||
|
thumbnailUrl?: string;
|
||||||
|
attachmentSeq?: string;
|
||||||
|
attachmentSize?: string;
|
||||||
|
attachmentRegDate?: string;
|
||||||
|
imageWidth?: string;
|
||||||
|
imageHeight?: string;
|
||||||
|
companyCode?: string;
|
||||||
|
voiceTime?: string;
|
||||||
|
synapKey?: string;
|
||||||
|
returnJson?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileTalkSaveEncodeMap = {
|
||||||
|
userSeq: 'p_user_seq',
|
||||||
|
deviceType: 'p_device_type',
|
||||||
|
token: 'p_token',
|
||||||
|
file: 'file',
|
||||||
|
fileName: 'p_file_name',
|
||||||
|
thumb: 'thumb',
|
||||||
|
voice: 'p_voice',
|
||||||
|
voiceTime: 'p_voice_time',
|
||||||
|
roomSeq: 'p_room_id',
|
||||||
|
type: 'p_type'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeFileTalkSave: APIFormDataEncoder<FileTalkSaveRequest> = (
|
||||||
|
req: FileTalkSaveRequest
|
||||||
|
) => {
|
||||||
|
const extraParams: any = {};
|
||||||
|
|
||||||
|
extraParams.userSeq = String(req.userSeq);
|
||||||
|
if (!!req.voice) {
|
||||||
|
extraParams.voice = req.voice ? 'Y' : 'N';
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParameterUtil.encodeFormData(fileTalkSaveEncodeMap, req, extraParams);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeFileTalkSave: APIDecoder<FileTalkSaveResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const json = JsonAnalization.receiveAnalization(res);
|
||||||
|
return {
|
||||||
|
statusCode: json.StatusCode,
|
||||||
|
roomSeq: json.RoomID,
|
||||||
|
fileName: json.FileName,
|
||||||
|
fileExt: json.FileExt,
|
||||||
|
fileType: json.FileType,
|
||||||
|
thumbnailUrl: json.ThumbURL,
|
||||||
|
attachmentSeq: json.AttSEQ,
|
||||||
|
attachmentSize: json.AttSize,
|
||||||
|
attachmentRegDate: json.AttRegDate,
|
||||||
|
imageWidth: json.ImageWidth,
|
||||||
|
imageHeight: json.ImageHeight,
|
||||||
|
companyCode: json.CompanyCode,
|
||||||
|
voiceTime: json.VoiceTime,
|
||||||
|
synapKey: json.SynapKey,
|
||||||
|
returnJson: res
|
||||||
|
} as FileTalkSaveResponse;
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
statusCode: StatusCode.Fail,
|
||||||
|
errorMessage: e
|
||||||
|
} as FileTalkSaveResponse;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil,
|
||||||
|
JsonAnalization,
|
||||||
|
StatusCode
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface FileTalkShareRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
attachmentsSeq?: string;
|
||||||
|
roomSeq?: string;
|
||||||
|
synapKey?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileTalkShareResponse extends APIResponse {
|
||||||
|
roomSeq?: string;
|
||||||
|
fileName?: string;
|
||||||
|
fileExt?: string;
|
||||||
|
fileType?: string;
|
||||||
|
thumbnailUrl?: string;
|
||||||
|
attachmentSeq?: string;
|
||||||
|
attachmentSize?: string;
|
||||||
|
attachmentRegDate?: string;
|
||||||
|
companyCode?: string;
|
||||||
|
synapKey?: string;
|
||||||
|
returnJson?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileTalkShareEncodeMap = {
|
||||||
|
userSeq: 'p_user_seq',
|
||||||
|
deviceType: 'p_device_type',
|
||||||
|
token: 'p_token',
|
||||||
|
attachmentsSeq: 'p_att_seq',
|
||||||
|
roomSeq: 'p_room_id',
|
||||||
|
synapKey: 'p_synap_key'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeFileTalkShare: APIEncoder<FileTalkShareRequest> = (
|
||||||
|
req: FileTalkShareRequest
|
||||||
|
) => {
|
||||||
|
return ParameterUtil.encode(fileTalkShareEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeFileTalkShare: APIDecoder<FileTalkShareResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const json = JsonAnalization.receiveAnalization(res);
|
||||||
|
return {
|
||||||
|
statusCode: json.StatusCode,
|
||||||
|
roomSeq: json.RoomID,
|
||||||
|
fileName: json.FileName,
|
||||||
|
fileExt: json.FileExt,
|
||||||
|
fileType: json.FileType,
|
||||||
|
thumbnailUrl: json.ThumbURL,
|
||||||
|
attachmentSeq: json.AttSEQ,
|
||||||
|
attachmentSize: json.AttSize,
|
||||||
|
attachmentRegDate: json.AttRegDate,
|
||||||
|
companyCode: json.CompanyCode,
|
||||||
|
synapKey: json.SynapKey,
|
||||||
|
returnJson: res
|
||||||
|
} as FileTalkShareResponse;
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
statusCode: StatusCode.Fail,
|
||||||
|
errorMessage: e
|
||||||
|
} as FileTalkShareResponse;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil,
|
||||||
|
JsonAnalization,
|
||||||
|
StatusCode
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface MassTalkDownloadRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
eventMassSeq?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MassTalkDownloadResponse extends APIResponse {
|
||||||
|
content?: string;
|
||||||
|
userName?: string;
|
||||||
|
regDate?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const massTalkDownloadEncodeMap = {
|
||||||
|
userSeq: 'p_user_seq',
|
||||||
|
deviceType: 'p_device_type',
|
||||||
|
token: 'p_token',
|
||||||
|
eventMassSeq: 'p_event_mass_seq'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeMassTalkDownload: APIEncoder<MassTalkDownloadRequest> = (
|
||||||
|
req: MassTalkDownloadRequest
|
||||||
|
) => {
|
||||||
|
return ParameterUtil.encode(massTalkDownloadEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeMassTalkDownload: APIDecoder<MassTalkDownloadResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const json = JsonAnalization.receiveAnalization(res);
|
||||||
|
return {
|
||||||
|
statusCode: json.StatusCode,
|
||||||
|
errorMessage: json.ErrorMessage,
|
||||||
|
content: json.Content,
|
||||||
|
userName: json.UserName,
|
||||||
|
regDate: json.RegDate
|
||||||
|
} as MassTalkDownloadResponse;
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
statusCode: StatusCode.Fail,
|
||||||
|
errorMessage: e
|
||||||
|
} as MassTalkDownloadResponse;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil,
|
||||||
|
StatusCode,
|
||||||
|
JsonAnalization
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface MassTalkSaveRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
content?: string;
|
||||||
|
roomSeq?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MassTalkSaveResponse extends APIResponse {
|
||||||
|
eventMassSeq?: string;
|
||||||
|
roomSeq?: string;
|
||||||
|
regDate?: string;
|
||||||
|
content?: string;
|
||||||
|
returnJson?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const massTalkSaveEncodeMap = {
|
||||||
|
userSeq: 'p_user_seq',
|
||||||
|
deviceType: 'p_device_type',
|
||||||
|
token: 'p_token',
|
||||||
|
content: 'p_content',
|
||||||
|
roomSeq: 'p_room_id'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeMassTalkSave: APIEncoder<MassTalkSaveRequest> = (
|
||||||
|
req: MassTalkSaveRequest
|
||||||
|
) => {
|
||||||
|
return ParameterUtil.encode(massTalkSaveEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeMassTalkSave: APIDecoder<MassTalkSaveResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const json = JsonAnalization.receiveAnalization(res);
|
||||||
|
return {
|
||||||
|
statusCode: json.StatusCode,
|
||||||
|
errorMessage: json.ErrorMessage,
|
||||||
|
content: json.Content,
|
||||||
|
eventMassSeq: json.EventMassSeq,
|
||||||
|
regDate: json.RegDate,
|
||||||
|
roomSeq: json.RoomID,
|
||||||
|
returnJson: res
|
||||||
|
} as MassTalkSaveResponse;
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
statusCode: StatusCode.Fail,
|
||||||
|
errorMessage: e
|
||||||
|
} as MassTalkSaveResponse;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface TransMassTalkDownloadRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
eventTransSeq?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransMassTalkDownloadResponse extends APIResponse {
|
||||||
|
Original?: string;
|
||||||
|
Translation?: string;
|
||||||
|
Locale?: string;
|
||||||
|
UserName?: string;
|
||||||
|
RegDate?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transMassTalkDownloadEncodeMap = {};
|
||||||
|
|
||||||
|
export const encodeTransMassTalkDownload: APIEncoder<
|
||||||
|
TransMassTalkDownloadRequest
|
||||||
|
> = (req: TransMassTalkDownloadRequest) => {
|
||||||
|
return ParameterUtil.encode(transMassTalkDownloadEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeTransMassTalkDownload: APIDecoder<
|
||||||
|
TransMassTalkDownloadResponse
|
||||||
|
> = (res: any) => {
|
||||||
|
return {} as TransMassTalkDownloadResponse;
|
||||||
|
};
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil,
|
||||||
|
JsonAnalization,
|
||||||
|
StatusCode
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface TransMassTalkSaveRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
original?: string;
|
||||||
|
translation?: string;
|
||||||
|
roomSeq?: string;
|
||||||
|
locale: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransMassTalkSaveResponse extends APIResponse {
|
||||||
|
roomSeq?: string;
|
||||||
|
registrationDate?: string;
|
||||||
|
translationSeq?: string;
|
||||||
|
locale?: string;
|
||||||
|
original?: string;
|
||||||
|
translation?: string;
|
||||||
|
returnJson?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transMassTalkSaveEncodeMap = {
|
||||||
|
userSeq: 'p_user_seq',
|
||||||
|
deviceType: 'p_device_type',
|
||||||
|
token: 'p_token',
|
||||||
|
original: 'p_original',
|
||||||
|
translation: 'p_translation',
|
||||||
|
roomSeq: 'p_room_id',
|
||||||
|
locale: 'p_locale'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeTransMassTalkSave: APIEncoder<TransMassTalkSaveRequest> = (
|
||||||
|
req: TransMassTalkSaveRequest
|
||||||
|
) => {
|
||||||
|
return ParameterUtil.encode(transMassTalkSaveEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeTransMassTalkSave: APIDecoder<TransMassTalkSaveResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const json = JsonAnalization.receiveAnalization(res);
|
||||||
|
return {
|
||||||
|
statusCode: json.StatusCode,
|
||||||
|
translationSeq: json.EventTransSEQ,
|
||||||
|
roomSeq: json.RoomID,
|
||||||
|
registrationDate: json.RegDate,
|
||||||
|
locale: json.Locale,
|
||||||
|
original: json.Original,
|
||||||
|
translation: json.Translation,
|
||||||
|
returnJson: res
|
||||||
|
} as TransMassTalkSaveResponse;
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
statusCode: StatusCode.Fail,
|
||||||
|
errorMessage: e
|
||||||
|
} as TransMassTalkSaveResponse;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface TranslationReqRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
original: string;
|
||||||
|
srcLocale: string;
|
||||||
|
destLocale: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TranslationReqResponse extends APIResponse {
|
||||||
|
SrcLocale?: string;
|
||||||
|
DestLocale?: string;
|
||||||
|
Original?: string;
|
||||||
|
Translation?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const translationReqEncodeMap = {};
|
||||||
|
|
||||||
|
export const encodeTranslationReq: APIEncoder<TranslationReqRequest> = (
|
||||||
|
req: TranslationReqRequest
|
||||||
|
) => {
|
||||||
|
return ParameterUtil.encode(translationReqEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeTranslationReq: APIDecoder<TranslationReqResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
return {} as TranslationReqResponse;
|
||||||
|
};
|
|
@ -0,0 +1,71 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil,
|
||||||
|
JsonAnalization,
|
||||||
|
StatusCode
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface TranslationSaveRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
roomSeq?: string;
|
||||||
|
original?: string;
|
||||||
|
srcLocale: string;
|
||||||
|
destLocale: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TranslationSaveResponse extends APIResponse {
|
||||||
|
translationSeq?: string;
|
||||||
|
roomSeq?: string;
|
||||||
|
registrationDate?: string;
|
||||||
|
srcLocale?: string;
|
||||||
|
destLocale?: string;
|
||||||
|
original?: string;
|
||||||
|
translation?: string;
|
||||||
|
returnJson?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const translationSaveEncodeMap = {
|
||||||
|
userSeq: 'p_user_seq',
|
||||||
|
deviceType: 'p_device_type',
|
||||||
|
token: 'p_token',
|
||||||
|
roomSeq: 'p_room_id',
|
||||||
|
original: 'p_original',
|
||||||
|
srcLocale: 'p_src_locale',
|
||||||
|
destLocale: 'p_dest_locale'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeTranslationSave: APIEncoder<TranslationSaveRequest> = (
|
||||||
|
req: TranslationSaveRequest
|
||||||
|
) => {
|
||||||
|
return ParameterUtil.encode(translationSaveEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeTranslationSave: APIDecoder<TranslationSaveResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const json = JsonAnalization.receiveAnalization(res);
|
||||||
|
return {
|
||||||
|
statusCode: json.StatusCode,
|
||||||
|
translationSeq: json.EventTransSEQ,
|
||||||
|
roomSeq: json.RoomID,
|
||||||
|
registrationDate: json.RegDate,
|
||||||
|
srcLocale: json.SrcLocale,
|
||||||
|
destLocale: json.DestLocale,
|
||||||
|
original: json.Original,
|
||||||
|
translation: json.Translation,
|
||||||
|
returnJson: res
|
||||||
|
} as TranslationSaveResponse;
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
statusCode: StatusCode.Fail,
|
||||||
|
errorMessage: e
|
||||||
|
} as TranslationSaveResponse;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Observable, Subject } from 'rxjs';
|
||||||
|
import { share } from 'rxjs/operators';
|
||||||
|
|
||||||
|
export class FileDownloadItem {
|
||||||
|
downloadTime: number;
|
||||||
|
downloadingProgress$: Observable<number>;
|
||||||
|
|
||||||
|
private downloadingProgress: Subject<number>;
|
||||||
|
private downloadStartTime: number;
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
downloadStart(): Subject<number> {
|
||||||
|
this.downloadStartTime = new Date().getTime();
|
||||||
|
this.downloadingProgress = new Subject<number>();
|
||||||
|
this.downloadingProgress$ = this.downloadingProgress
|
||||||
|
.asObservable()
|
||||||
|
.pipe(share());
|
||||||
|
return this.downloadingProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadComplete() {
|
||||||
|
const endTime = new Date().getTime();
|
||||||
|
this.downloadTime = endTime - this.downloadStartTime;
|
||||||
|
this.downloadingProgress.complete();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { Observable, Subject } from 'rxjs';
|
||||||
|
import { share } from 'rxjs/operators';
|
||||||
|
|
||||||
|
export class FileUploadItem {
|
||||||
|
file: File;
|
||||||
|
uploadTime: number;
|
||||||
|
uploadingProgress$: Observable<number>;
|
||||||
|
|
||||||
|
private uploadingProgress: Subject<number>;
|
||||||
|
private uploadStartTime: number;
|
||||||
|
|
||||||
|
private constructor(file: File) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromFiles(files: FileList): FileUploadItem[] {
|
||||||
|
const fileItems: FileUploadItem[] = [];
|
||||||
|
|
||||||
|
// tslint:disable-next-line: prefer-for-of
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
fileItems.push(new FileUploadItem(files[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadStart(): Subject<number> {
|
||||||
|
this.uploadStartTime = new Date().getTime();
|
||||||
|
this.uploadingProgress = new Subject<number>();
|
||||||
|
this.uploadingProgress$ = this.uploadingProgress
|
||||||
|
.asObservable()
|
||||||
|
.pipe(share());
|
||||||
|
return this.uploadingProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadComplete() {
|
||||||
|
const endTime = new Date().getTime();
|
||||||
|
this.uploadTime = endTime - this.uploadStartTime;
|
||||||
|
this.uploadingProgress.complete();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CommonApiService } from './common-api.service';
|
||||||
|
|
||||||
|
describe('CommonApiService', () => {
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({}));
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const service: CommonApiService = TestBed.get(CommonApiService);
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,295 @@
|
||||||
|
import { Injectable, Inject } from '@angular/core';
|
||||||
|
import {
|
||||||
|
HttpClient,
|
||||||
|
HttpEventType,
|
||||||
|
HttpResponse,
|
||||||
|
HttpRequest
|
||||||
|
} from '@angular/common/http';
|
||||||
|
|
||||||
|
import { Observable, Subject } from 'rxjs';
|
||||||
|
import { map, filter } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { _MODULE_CONFIG } from '../types/token';
|
||||||
|
import { ModuleConfig } from '../types/module-config';
|
||||||
|
import {
|
||||||
|
FileProfileSaveRequest,
|
||||||
|
FileProfileSaveResponse,
|
||||||
|
encodeFileProfileSave,
|
||||||
|
decodeFileProfileSave
|
||||||
|
} from '../apis/file-profile-save';
|
||||||
|
import {
|
||||||
|
FileTalkDownloadRequest,
|
||||||
|
encodeFileTalkDownload,
|
||||||
|
encodeFormDataFileTalkDownload
|
||||||
|
} from '../apis/file-talk-download';
|
||||||
|
import {
|
||||||
|
FileTalkSaveRequest,
|
||||||
|
FileTalkSaveResponse,
|
||||||
|
encodeFileTalkSave,
|
||||||
|
decodeFileTalkSave
|
||||||
|
} from '../apis/file-talk-save';
|
||||||
|
import {
|
||||||
|
FileTalkShareRequest,
|
||||||
|
FileTalkShareResponse,
|
||||||
|
encodeFileTalkShare,
|
||||||
|
decodeFileTalkShare
|
||||||
|
} from '../apis/file-talk-share';
|
||||||
|
import {
|
||||||
|
MassTalkDownloadRequest,
|
||||||
|
MassTalkDownloadResponse,
|
||||||
|
encodeMassTalkDownload,
|
||||||
|
decodeMassTalkDownload
|
||||||
|
} from '../apis/mass-talk-download';
|
||||||
|
import {
|
||||||
|
MassTalkSaveRequest,
|
||||||
|
MassTalkSaveResponse,
|
||||||
|
encodeMassTalkSave,
|
||||||
|
decodeMassTalkSave
|
||||||
|
} from '../apis/mass-talk-save';
|
||||||
|
import {
|
||||||
|
TransMassTalkDownloadRequest,
|
||||||
|
TransMassTalkDownloadResponse,
|
||||||
|
encodeTransMassTalkDownload,
|
||||||
|
decodeTransMassTalkDownload
|
||||||
|
} from '../apis/trans-mass-talk-download';
|
||||||
|
import {
|
||||||
|
TransMassTalkSaveRequest,
|
||||||
|
TransMassTalkSaveResponse,
|
||||||
|
encodeTransMassTalkSave,
|
||||||
|
decodeTransMassTalkSave
|
||||||
|
} from '../apis/trans-mass-talk-save';
|
||||||
|
import {
|
||||||
|
TranslationReqRequest,
|
||||||
|
TranslationReqResponse,
|
||||||
|
encodeTranslationReq,
|
||||||
|
decodeTranslationReq
|
||||||
|
} from '../apis/translation-req';
|
||||||
|
import {
|
||||||
|
TranslationSaveRequest,
|
||||||
|
TranslationSaveResponse,
|
||||||
|
encodeTranslationSave,
|
||||||
|
decodeTranslationSave
|
||||||
|
} from '../apis/translation-save';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CommonApiService {
|
||||||
|
constructor(
|
||||||
|
@Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig,
|
||||||
|
private httpClient: HttpClient
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public fileProfileSave(
|
||||||
|
req: FileProfileSaveRequest,
|
||||||
|
fileProfileSaveUrl?: string
|
||||||
|
): Observable<FileProfileSaveResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
!!fileProfileSaveUrl
|
||||||
|
? fileProfileSaveUrl
|
||||||
|
: this.moduleConfig.urls.fileProfileSave,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeFileProfileSave(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeFileProfileSave(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public urlForFileTalkDownload(
|
||||||
|
req: FileTalkDownloadRequest,
|
||||||
|
fileTalkDownloadUrl?: string
|
||||||
|
): string {
|
||||||
|
const httpReq = new HttpRequest(
|
||||||
|
'GET',
|
||||||
|
!!fileTalkDownloadUrl
|
||||||
|
? fileTalkDownloadUrl
|
||||||
|
: this.moduleConfig.urls.fileTalkDownload,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeFileTalkDownload(req)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return httpReq.urlWithParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public fileTalkDownload(
|
||||||
|
req: FileTalkDownloadRequest,
|
||||||
|
fileTalkDownloadUrl?: string
|
||||||
|
): Observable<Blob> {
|
||||||
|
const httpReq = new HttpRequest(
|
||||||
|
'POST',
|
||||||
|
!!fileTalkDownloadUrl
|
||||||
|
? fileTalkDownloadUrl
|
||||||
|
: this.moduleConfig.urls.fileTalkDownload,
|
||||||
|
encodeFormDataFileTalkDownload(req),
|
||||||
|
{ reportProgress: true, responseType: 'blob' }
|
||||||
|
);
|
||||||
|
|
||||||
|
let progress: Subject<number>;
|
||||||
|
if (!!req.fileDownloadItem) {
|
||||||
|
progress = req.fileDownloadItem.downloadStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.httpClient.request(httpReq).pipe(
|
||||||
|
filter(event => {
|
||||||
|
if (event instanceof HttpResponse) {
|
||||||
|
return true;
|
||||||
|
} else if (HttpEventType.DownloadProgress === event.type) {
|
||||||
|
if (!!progress) {
|
||||||
|
progress.next(Math.round((100 * event.loaded) / event.total));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}),
|
||||||
|
map((event: HttpResponse<any>) => {
|
||||||
|
if (!!progress) {
|
||||||
|
req.fileDownloadItem.downloadComplete();
|
||||||
|
}
|
||||||
|
return event.body;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public fileTalkSave(
|
||||||
|
req: FileTalkSaveRequest,
|
||||||
|
fileTalkSaveUrl?: string
|
||||||
|
): Observable<FileTalkSaveResponse> {
|
||||||
|
const httpReq = new HttpRequest(
|
||||||
|
'POST',
|
||||||
|
!!fileTalkSaveUrl ? fileTalkSaveUrl : this.moduleConfig.urls.fileTalkSave,
|
||||||
|
encodeFileTalkSave(req),
|
||||||
|
{ reportProgress: true, responseType: 'text' as 'json' }
|
||||||
|
);
|
||||||
|
|
||||||
|
const progress = req.fileUploadItem.uploadStart();
|
||||||
|
|
||||||
|
return this.httpClient.request(httpReq).pipe(
|
||||||
|
filter(event => {
|
||||||
|
if (event instanceof HttpResponse) {
|
||||||
|
return true;
|
||||||
|
} else if (HttpEventType.UploadProgress === event.type) {
|
||||||
|
progress.next(Math.round((100 * event.loaded) / event.total));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}),
|
||||||
|
map((event: HttpResponse<any>) => {
|
||||||
|
req.fileUploadItem.uploadComplete();
|
||||||
|
return decodeFileTalkSave(event.body);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public acceptableExtensionForFileTalk(extensions: string[]): boolean {
|
||||||
|
for (const extension of extensions) {
|
||||||
|
if (
|
||||||
|
-1 === this.moduleConfig.acceptableFileExtensions.indexOf(extension.toLowerCase())
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public fileTalkShare(
|
||||||
|
req: FileTalkShareRequest
|
||||||
|
): Observable<FileTalkShareResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.fileTalkShare,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeFileTalkShare(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeFileTalkShare(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public massTalkDownload(
|
||||||
|
req: MassTalkDownloadRequest
|
||||||
|
): Observable<MassTalkDownloadResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.massTalkDownload,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeMassTalkDownload(req),
|
||||||
|
responseType: 'text' as 'json'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeMassTalkDownload(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public massTalkSave(
|
||||||
|
req: MassTalkSaveRequest
|
||||||
|
): Observable<MassTalkSaveResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.massTalkSave,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeMassTalkSave(req),
|
||||||
|
responseType: 'text' as 'json'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeMassTalkSave(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public transMassTalkDownload(
|
||||||
|
req: TransMassTalkDownloadRequest
|
||||||
|
): Observable<TransMassTalkDownloadResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.transMassTalkDownload,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeTransMassTalkDownload(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeTransMassTalkDownload(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public transMassTalkSave(
|
||||||
|
req: TransMassTalkSaveRequest
|
||||||
|
): Observable<TransMassTalkSaveResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.transMassTalkSave,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeTransMassTalkSave(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeTransMassTalkSave(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public translationReq(
|
||||||
|
req: TranslationReqRequest
|
||||||
|
): Observable<TranslationReqResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.translationReq,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeTranslationReq(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeTranslationReq(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public translationSave(
|
||||||
|
req: TranslationSaveRequest
|
||||||
|
): Observable<TranslationSaveResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.translationSave,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeTranslationSave(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeTranslationSave(res)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
export interface ModuleConfig {
|
||||||
|
urls: {
|
||||||
|
fileProfileSave: string;
|
||||||
|
fileTalkDownload: string;
|
||||||
|
fileTalkSave: string;
|
||||||
|
fileTalkShare: string;
|
||||||
|
massTalkDownload: string;
|
||||||
|
massTalkSave: string;
|
||||||
|
transMassTalkDownload: string;
|
||||||
|
transMassTalkSave: string;
|
||||||
|
translationReq: string;
|
||||||
|
translationSave: string;
|
||||||
|
};
|
||||||
|
acceptableFileExtensions: string[];
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { InjectionToken } from '@angular/core';
|
||||||
|
|
||||||
|
export const _MODULE_CONFIG = new InjectionToken(
|
||||||
|
'@ucap-webmessenger/api-common config of module'
|
||||||
|
);
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||||
|
import { _MODULE_CONFIG } from './types/token';
|
||||||
|
|
||||||
|
import { CommonApiService } from './services/common-api.service';
|
||||||
|
import { ModuleConfig } from './types/module-config';
|
||||||
|
|
||||||
|
const SERVICES = [CommonApiService];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [],
|
||||||
|
exports: []
|
||||||
|
})
|
||||||
|
export class UCapCommonApiModule {
|
||||||
|
public static forRoot(
|
||||||
|
config: ModuleConfig
|
||||||
|
): ModuleWithProviders<UCapCommonApiModule> {
|
||||||
|
return {
|
||||||
|
ngModule: UCapCommonApiModule,
|
||||||
|
providers: [{ provide: _MODULE_CONFIG, useValue: config }, ...SERVICES]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
23
projects/ucap-webmessenger-api-common/src/public-api.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Public API Surface of ucap-webmessenger-api-common
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib/types/module-config';
|
||||||
|
|
||||||
|
export * from './lib/apis/file-profile-save';
|
||||||
|
export * from './lib/apis/file-talk-download';
|
||||||
|
export * from './lib/apis/file-talk-save';
|
||||||
|
export * from './lib/apis/file-talk-share';
|
||||||
|
export * from './lib/apis/mass-talk-download';
|
||||||
|
export * from './lib/apis/mass-talk-save';
|
||||||
|
export * from './lib/apis/trans-mass-talk-download';
|
||||||
|
export * from './lib/apis/trans-mass-talk-save';
|
||||||
|
export * from './lib/apis/translation-req';
|
||||||
|
export * from './lib/apis/translation-save';
|
||||||
|
|
||||||
|
export * from './lib/models/file-download-item';
|
||||||
|
export * from './lib/models/file-upload-item';
|
||||||
|
|
||||||
|
export * from './lib/services/common-api.service';
|
||||||
|
|
||||||
|
export * from './lib/ucap-common-api.module';
|
21
projects/ucap-webmessenger-api-common/src/test.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||||
|
|
||||||
|
import 'zone.js/dist/zone';
|
||||||
|
import 'zone.js/dist/zone-testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
declare const require: any;
|
||||||
|
|
||||||
|
// First, initialize the Angular testing environment.
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting()
|
||||||
|
);
|
||||||
|
// Then we find all the tests.
|
||||||
|
const context = require.context('./', true, /\.spec\.ts$/);
|
||||||
|
// And load the modules.
|
||||||
|
context.keys().map(context);
|
26
projects/ucap-webmessenger-api-common/tsconfig.lib.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/lib",
|
||||||
|
"target": "es2015",
|
||||||
|
"declaration": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"types": [],
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"es2018"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"annotateForClosureCompiler": true,
|
||||||
|
"skipTemplateCodegen": true,
|
||||||
|
"strictMetadataEmit": true,
|
||||||
|
"fullTemplateTypeCheck": true,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"enableResourceInlining": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"src/test.ts",
|
||||||
|
"**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
17
projects/ucap-webmessenger-api-common/tsconfig.spec.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/test.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
17
projects/ucap-webmessenger-api-common/tslint.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tslint.json",
|
||||||
|
"rules": {
|
||||||
|
"directive-selector": [
|
||||||
|
true,
|
||||||
|
"attribute",
|
||||||
|
"ucapApiCommon",
|
||||||
|
"camelCase"
|
||||||
|
],
|
||||||
|
"component-selector": [
|
||||||
|
true,
|
||||||
|
"element",
|
||||||
|
"ucap-api-common",
|
||||||
|
"kebab-case"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
24
projects/ucap-webmessenger-api-external/README.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# UcapWebmessengerApiExternal
|
||||||
|
|
||||||
|
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.4.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name --project ucap-webmessenger-api-external` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ucap-webmessenger-api-external`.
|
||||||
|
> Note: Don't forget to add `--project ucap-webmessenger-api-external` or else it will be added to the default project in your `angular.json` file.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build ucap-webmessenger-api-external` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||||
|
|
||||||
|
## Publishing
|
||||||
|
|
||||||
|
After building your library with `ng build ucap-webmessenger-api-external`, go to the dist folder `cd dist/ucap-webmessenger-api-external` and run `npm publish`.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test ucap-webmessenger-api-external` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
32
projects/ucap-webmessenger-api-external/karma.conf.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage-istanbul-reporter'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
dir: require('path').join(__dirname, '../../coverage/ucap-webmessenger-api-external'),
|
||||||
|
reports: ['html', 'lcovonly', 'text-summary'],
|
||||||
|
fixWebpackSourcePaths: true
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false,
|
||||||
|
restartOnFileChange: true
|
||||||
|
});
|
||||||
|
};
|
7
projects/ucap-webmessenger-api-external/ng-package.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||||
|
"dest": "../../dist/ucap-webmessenger-api-external",
|
||||||
|
"lib": {
|
||||||
|
"entryFile": "src/public-api.ts"
|
||||||
|
}
|
||||||
|
}
|
8
projects/ucap-webmessenger-api-external/package.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"name": "@ucap-webmessenger/api-external",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": "^8.2.4",
|
||||||
|
"@angular/core": "^8.2.4"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface CheckUserInfoExRequest extends APIRequest {
|
||||||
|
userId: string;
|
||||||
|
companyCode: string;
|
||||||
|
userSession: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CheckUserInfoExResponse extends APIResponse {
|
||||||
|
userId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkUserInfoExEncodeMap = {
|
||||||
|
userId: 'p_user_id',
|
||||||
|
companyCode: 'p_comp_code',
|
||||||
|
userSession: 'p_user_session'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeCheckUserInfoEx: APIEncoder<CheckUserInfoExRequest> = (
|
||||||
|
req: CheckUserInfoExRequest
|
||||||
|
) => {
|
||||||
|
return ParameterUtil.encode(checkUserInfoExEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeCheckUserInfoEx: APIDecoder<CheckUserInfoExResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
statusCode: res.StatusCode,
|
||||||
|
errorMessage: res.ErrorMessage,
|
||||||
|
userId: res.UserID
|
||||||
|
} as CheckUserInfoExResponse;
|
||||||
|
};
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { AppType, DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
import { Company } from '../models/company';
|
||||||
|
|
||||||
|
export interface CompanyListRequest extends APIRequest {
|
||||||
|
userSeq?: number;
|
||||||
|
appType?: AppType;
|
||||||
|
deviceType?: DeviceType;
|
||||||
|
token?: string;
|
||||||
|
companyGroupCode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompanyListResponse extends APIResponse {
|
||||||
|
companyList?: Company[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const companyListEncodeMap = {
|
||||||
|
userSeq: 'p_user_seq',
|
||||||
|
appType: 'p_app_type',
|
||||||
|
deviceType: 'p_device_type',
|
||||||
|
token: 'p_token',
|
||||||
|
companyGroupCode: 'p_comp_group_code'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeCompanyList: APIEncoder<CompanyListRequest> = (
|
||||||
|
req: CompanyListRequest
|
||||||
|
) => {
|
||||||
|
const extraParams: any = {};
|
||||||
|
|
||||||
|
extraParams.userSeq = String(req.userSeq);
|
||||||
|
|
||||||
|
return ParameterUtil.encode(companyListEncodeMap, req, extraParams);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeCompanyList: APIDecoder<CompanyListResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
let companyList: Company[] | undefined;
|
||||||
|
if (!!res.CompanyList) {
|
||||||
|
companyList = [];
|
||||||
|
for (const company of res.CompanyList) {
|
||||||
|
companyList.push({
|
||||||
|
companyCode: company.COMPANY_CODE,
|
||||||
|
companyName: company.COMPANY_NAME,
|
||||||
|
companyDomain: company.COMPANY_DOMAIN,
|
||||||
|
companyConfAuthYn: company.COMPANY_CONF_AUTH,
|
||||||
|
ucapUseYn: company.UCAP_USE_YN,
|
||||||
|
companyTimerChatAuthYn: company.COMPANY_TIMER_CHAT_AUTH
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: res.StatusCode,
|
||||||
|
errorMessage: res.ErrorMessage,
|
||||||
|
companyList
|
||||||
|
} as CompanyListResponse;
|
||||||
|
};
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { DeviceType, PushType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface TokenUpdateRequest extends APIRequest {
|
||||||
|
userSeq: number;
|
||||||
|
deviceType: DeviceType;
|
||||||
|
token: string;
|
||||||
|
mobilePid?: string;
|
||||||
|
pushType?: PushType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line: no-empty-interface
|
||||||
|
export interface TokenUpdateResponse extends APIResponse {}
|
||||||
|
|
||||||
|
const tokenUpdateEncodeMap = {
|
||||||
|
userSeq: 'p_user_seq',
|
||||||
|
deviceType: 'p_device_type',
|
||||||
|
token: 'p_token',
|
||||||
|
mobilePid: 'p_mobile_pid',
|
||||||
|
pushType: 'p_push_type'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeTokenUpdate: APIEncoder<TokenUpdateRequest> = (
|
||||||
|
req: TokenUpdateRequest
|
||||||
|
) => {
|
||||||
|
const extraParams: any = {};
|
||||||
|
|
||||||
|
extraParams.userSeq = String(req.userSeq);
|
||||||
|
|
||||||
|
return ParameterUtil.encode(tokenUpdateEncodeMap, req, extraParams);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeTokenUpdate: APIDecoder<TokenUpdateResponse> = (
|
||||||
|
res: any
|
||||||
|
) => {
|
||||||
|
return {} as TokenUpdateResponse;
|
||||||
|
};
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { DeviceType } from '@ucap-webmessenger/core';
|
||||||
|
import {
|
||||||
|
APIRequest,
|
||||||
|
APIResponse,
|
||||||
|
APIEncoder,
|
||||||
|
APIDecoder,
|
||||||
|
ParameterUtil
|
||||||
|
} from '@ucap-webmessenger/api';
|
||||||
|
|
||||||
|
export interface UrlInfoRequest extends APIRequest {
|
||||||
|
deviceType: DeviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UrlInfoResponse extends APIResponse {
|
||||||
|
portCheckUrl?: string;
|
||||||
|
messageUrl?: string;
|
||||||
|
messageUrl2?: string;
|
||||||
|
passwordUrl?: string;
|
||||||
|
planUrl?: string;
|
||||||
|
planUrl2?: string;
|
||||||
|
vocUrl?: string;
|
||||||
|
confUrl?: string;
|
||||||
|
uprApiUrl?: string;
|
||||||
|
uprSvcUrl?: string;
|
||||||
|
uprDownloadUrl?: string;
|
||||||
|
synapViewUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlInfoEncodeMap = {
|
||||||
|
deviceType: 'p_device_type'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const encodeUrlInfo: APIEncoder<UrlInfoRequest> = (
|
||||||
|
req: UrlInfoRequest
|
||||||
|
) => {
|
||||||
|
return ParameterUtil.encode(urlInfoEncodeMap, req);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeUrlInfo: APIDecoder<UrlInfoResponse> = (res: any) => {
|
||||||
|
return {
|
||||||
|
statusCode: res.StatusCode,
|
||||||
|
errorMessage: res.ErrorMessage,
|
||||||
|
portCheckUrl: res.PortCheckURL,
|
||||||
|
messageUrl: res.MsgURL,
|
||||||
|
messageUrl2: res.MsgURL2,
|
||||||
|
passwordUrl: res.PasswordURL,
|
||||||
|
planUrl: res.PlanURL,
|
||||||
|
planUrl2: res.PlanURL2,
|
||||||
|
vocUrl: res.VocURL,
|
||||||
|
confUrl: res.ConfURL,
|
||||||
|
uprApiUrl: res.UprApiURL,
|
||||||
|
uprSvcUrl: res.UprSvcURL,
|
||||||
|
uprDownloadUrl: res.UprDownloadURL,
|
||||||
|
synapViewUrl: res.SynapViewURL
|
||||||
|
} as UrlInfoResponse;
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
export interface Company {
|
||||||
|
companyCode?: string;
|
||||||
|
companyName?: string;
|
||||||
|
companyDomain?: string;
|
||||||
|
companyConfAuthYn?: string;
|
||||||
|
ucapUseYn?: string;
|
||||||
|
companyTimerChatAuthYn?: string;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ExternalApiService } from './external-api.service';
|
||||||
|
|
||||||
|
describe('ExternalApiService', () => {
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({}));
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const service: ExternalApiService = TestBed.get(ExternalApiService);
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,92 @@
|
||||||
|
import { Injectable, Inject } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { _MODULE_CONFIG } from '../types/token';
|
||||||
|
import { ModuleConfig } from '../types/module-config';
|
||||||
|
import {
|
||||||
|
CheckUserInfoExRequest,
|
||||||
|
CheckUserInfoExResponse,
|
||||||
|
encodeCheckUserInfoEx,
|
||||||
|
decodeCheckUserInfoEx
|
||||||
|
} from '../apis/check-user-info-ex';
|
||||||
|
import {
|
||||||
|
CompanyListRequest,
|
||||||
|
CompanyListResponse,
|
||||||
|
encodeCompanyList,
|
||||||
|
decodeCompanyList
|
||||||
|
} from '../apis/company-list';
|
||||||
|
import {
|
||||||
|
TokenUpdateRequest,
|
||||||
|
TokenUpdateResponse,
|
||||||
|
encodeTokenUpdate,
|
||||||
|
decodeTokenUpdate
|
||||||
|
} from '../apis/token-update';
|
||||||
|
import {
|
||||||
|
UrlInfoResponse,
|
||||||
|
UrlInfoRequest,
|
||||||
|
encodeUrlInfo,
|
||||||
|
decodeUrlInfo
|
||||||
|
} from '../apis/url-info';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ExternalApiService {
|
||||||
|
constructor(
|
||||||
|
@Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig,
|
||||||
|
private httpClient: HttpClient
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public checkUserInfoEx(
|
||||||
|
req: CheckUserInfoExRequest
|
||||||
|
): Observable<CheckUserInfoExResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.checkUserInfoEx,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeCheckUserInfoEx(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeCheckUserInfoEx(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public companyList(req: CompanyListRequest): Observable<CompanyListResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.companyList,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeCompanyList(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeCompanyList(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public tokenUpdate(req: TokenUpdateRequest): Observable<TokenUpdateResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.tokenUpdate,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeTokenUpdate(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeTokenUpdate(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public urlInfo(req: UrlInfoRequest): Observable<UrlInfoResponse> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<any>(
|
||||||
|
this.moduleConfig.urls.urlInfo,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
params: encodeUrlInfo(req)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.pipe(map(res => decodeUrlInfo(res)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
export interface ModuleConfig {
|
||||||
|
urls: {
|
||||||
|
checkUserInfoEx: string;
|
||||||
|
companyList: string;
|
||||||
|
tokenUpdate: string;
|
||||||
|
urlInfo: string;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { InjectionToken } from '@angular/core';
|
||||||
|
|
||||||
|
export const _MODULE_CONFIG = new InjectionToken(
|
||||||
|
'@ucap-webmessenger/api-external config of module'
|
||||||
|
);
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||||
|
import { _MODULE_CONFIG } from './types/token';
|
||||||
|
|
||||||
|
import { ExternalApiService } from './services/external-api.service';
|
||||||
|
import { ModuleConfig } from './types/module-config';
|
||||||
|
|
||||||
|
const SERVICES = [ExternalApiService];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [],
|
||||||
|
exports: []
|
||||||
|
})
|
||||||
|
export class UCapExternalApiModule {
|
||||||
|
public static forRoot(
|
||||||
|
config: ModuleConfig
|
||||||
|
): ModuleWithProviders<UCapExternalApiModule> {
|
||||||
|
return {
|
||||||
|
ngModule: UCapExternalApiModule,
|
||||||
|
providers: [{ provide: _MODULE_CONFIG, useValue: config }, ...SERVICES]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
16
projects/ucap-webmessenger-api-external/src/public-api.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* Public API Surface of ucap-webmessenger-api-public
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib/types/module-config';
|
||||||
|
|
||||||
|
export * from './lib/models/company';
|
||||||
|
|
||||||
|
export * from './lib/apis/check-user-info-ex';
|
||||||
|
export * from './lib/apis/company-list';
|
||||||
|
export * from './lib/apis/token-update';
|
||||||
|
export * from './lib/apis/url-info';
|
||||||
|
|
||||||
|
export * from './lib/services/external-api.service';
|
||||||
|
|
||||||
|
export * from './lib/ucap-external-api.module';
|
21
projects/ucap-webmessenger-api-external/src/test.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||||
|
|
||||||
|
import 'zone.js/dist/zone';
|
||||||
|
import 'zone.js/dist/zone-testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
declare const require: any;
|
||||||
|
|
||||||
|
// First, initialize the Angular testing environment.
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting()
|
||||||
|
);
|
||||||
|
// Then we find all the tests.
|
||||||
|
const context = require.context('./', true, /\.spec\.ts$/);
|
||||||
|
// And load the modules.
|
||||||
|
context.keys().map(context);
|
26
projects/ucap-webmessenger-api-external/tsconfig.lib.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/lib",
|
||||||
|
"target": "es2015",
|
||||||
|
"declaration": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"types": [],
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"es2018"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"annotateForClosureCompiler": true,
|
||||||
|
"skipTemplateCodegen": true,
|
||||||
|
"strictMetadataEmit": true,
|
||||||
|
"fullTemplateTypeCheck": true,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"enableResourceInlining": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"src/test.ts",
|
||||||
|
"**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
17
projects/ucap-webmessenger-api-external/tsconfig.spec.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/test.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"**/*.spec.ts",
|
||||||
|
"**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|