Compare commits
13 Commits
c8b8199e93
...
v9.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c6342a989 | |||
| b47debeef2 | |||
| 2886ab6522 | |||
| 994cc72e1d | |||
| a02ce50cf3 | |||
| c16c07ea42 | |||
| 535cf6ea05 | |||
| 766ed86999 | |||
| 76a2bf0e88 | |||
| fe8fcdf45b | |||
| 7a99b1ab55 | |||
| 41f6e640e1 | |||
| 26f1902996 |
+23
-3
@@ -1,4 +1,24 @@
|
|||||||
node_modules
|
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode/*
|
||||||
dist
|
|
||||||
|
client/node_modules
|
||||||
|
client/dist
|
||||||
|
|
||||||
|
.vs/
|
||||||
|
.user
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|||||||
+753
-788
File diff suppressed because it is too large
Load Diff
@@ -5,17 +5,15 @@ module.exports = {
|
|||||||
namespace: 'http://cp-solutions.at',
|
namespace: 'http://cp-solutions.at',
|
||||||
version: pkg.version,
|
version: pkg.version,
|
||||||
author: pkg.author,
|
author: pkg.author,
|
||||||
copyright: 'Copyright 2021 CP Solutions GmbH',
|
copyright: 'Copyright CP Solutions GmbH',
|
||||||
source: pkg.repository.url,
|
source: pkg.repository.url,
|
||||||
downloadURL: 'https://source.cp-austria.at/git/CPATRD/3cx_tapi/raw/branch/master/3CX_TAPI.user.js',
|
downloadURL: `${pkg.repository.url}/raw/branch/master/3CX_TAPI.user.js`,
|
||||||
match: [
|
match: [
|
||||||
'https://192.168.0.154:5001/*',
|
'https://192.168.0.154:5001/*',
|
||||||
'https://cpsolution.my3cx.at:5001/*'
|
'https://cpsolution.my3cx.at:5001/*'
|
||||||
],
|
],
|
||||||
require: [
|
require: [
|
||||||
'https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.2/waitForKeyElements.js',
|
'https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.2/waitForKeyElements.js',
|
||||||
`https://cdn.jsdelivr.net/npm/axios@${pkg.dependencies.axios}/dist/axios.min.js`,
|
|
||||||
`https://cdn.jsdelivr.net/npm/axios-userscript-adapter@${pkg.dependencies['axios-userscript-adapter']}/dist/axiosGmxhrAdapter.min.js`
|
|
||||||
],
|
],
|
||||||
grant: [
|
grant: [
|
||||||
'GM.xmlHttpRequest',
|
'GM.xmlHttpRequest',
|
||||||
@@ -24,7 +22,7 @@ module.exports = {
|
|||||||
'GM.setValue'
|
'GM.setValue'
|
||||||
],
|
],
|
||||||
connect: [
|
connect: [
|
||||||
'cpatapi.cpsrvweb2016.cp-austria.at'
|
'3cxtapi.cp-austria.at'
|
||||||
],
|
],
|
||||||
'run-at': 'document-end'
|
'run-at': 'document-end'
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,10 @@ const webpackConfig = {
|
|||||||
'style-loader',
|
'style-loader',
|
||||||
'css-loader',
|
'css-loader',
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.svg$/,
|
||||||
|
loader: 'svg-inline-loader'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
+2184
-1990
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "3cx-tapi",
|
"name": "3cx-tapi",
|
||||||
"description": "3CX CP Tapi and Projectmanager integration",
|
"description": "3CX CP Tapi and Projectmanager integration",
|
||||||
"version": "9.2.2",
|
"version": "9.3.1",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Daniel Triendl",
|
"name": "Daniel Triendl",
|
||||||
"email": "d.triendl@cp-solutions.at"
|
"email": "d.triendl@cp-solutions.at"
|
||||||
@@ -20,35 +20,36 @@
|
|||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://source.cp-austria.at/git/CPATRD/3cx_tapi.git"
|
"url": "https://source.cp-austria.at/CPATRD/3cx_tapi.git"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chrono-node": "^2.7.7",
|
"@trim21/gm-fetch": "^0.3.0",
|
||||||
"@trim21/gm-fetch": "^0.1.16"
|
"chrono-node": "^2.9.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.29.0",
|
||||||
|
"@babel/preset-env": "^7.29.2",
|
||||||
"@types/greasemonkey": "^4.0.7",
|
"@types/greasemonkey": "^4.0.7",
|
||||||
"@babel/core": "^7.25.8",
|
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
||||||
"@babel/preset-env": "^7.25.8",
|
"@typescript-eslint/parser": "^8.57.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.8.1",
|
"babel-loader": "^10.1.1",
|
||||||
"@typescript-eslint/parser": "^8.8.1",
|
|
||||||
"babel-loader": "^9.2.1",
|
|
||||||
"browserslist": "^4.21.9",
|
"browserslist": "^4.21.9",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.4",
|
||||||
"eslint": "^9.12.0",
|
"eslint": "^9.39.4",
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-node": "11.1.0",
|
"eslint-plugin-node": "11.1.0",
|
||||||
"eslint-plugin-promise": "^7.1.0S",
|
"eslint-plugin-promise": "^7.2.1",
|
||||||
"less": "4.2.0",
|
"less": "^4.6.4",
|
||||||
"less-loader": "^12.2.0",
|
"less-loader": "^12.3.2",
|
||||||
"style-loader": "^4.0.0",
|
"style-loader": "^4.0.0",
|
||||||
"ts-loader": "^9.5.1",
|
"svg-inline-loader": "^0.8.2",
|
||||||
"typescript": "^5.6.3",
|
"ts-loader": "^9.5.4",
|
||||||
"userscript-metadata-webpack-plugin": "^0.4.0",
|
"typescript": "^5.9.3",
|
||||||
"webpack": "^5.95.0",
|
"userscript-metadata-webpack-plugin": "^0.4.2",
|
||||||
"webpack-bundle-analyzer": "^4.10.2",
|
"webpack": "^5.105.4",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-bundle-analyzer": "^5.2.0",
|
||||||
|
"webpack-cli": "^7.0.2",
|
||||||
"webpack-livereload-plugin": "3.0.2",
|
"webpack-livereload-plugin": "3.0.2",
|
||||||
"webpack-merge": "^6.0.1"
|
"webpack-merge": "^6.0.1"
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ npm run build
|
|||||||
## distribution
|
## distribution
|
||||||
|
|
||||||
```
|
```
|
||||||
cp "dist/3CX TAPI.prod.user.js" 3CX_TAPI.user.js
|
cp "dist/3CX TAPI.prod.user.js" ../3CX_TAPI.user.js
|
||||||
```
|
```
|
||||||
|
|
||||||
And commit 3CX_TAPI.user.js
|
And commit 3CX_TAPI.user.js
|
||||||
@@ -2,6 +2,8 @@ import * as chrono from 'chrono-node'
|
|||||||
import { TapiContact } from './tapi-contact'
|
import { TapiContact } from './tapi-contact'
|
||||||
import { extractNumber } from './utils'
|
import { extractNumber } from './utils'
|
||||||
import GM_fetch from '@trim21/gm-fetch'
|
import GM_fetch from '@trim21/gm-fetch'
|
||||||
|
import { Config } from './config'
|
||||||
|
const telephoneIcon = require('./telephone.svg');
|
||||||
|
|
||||||
export class CallHistory {
|
export class CallHistory {
|
||||||
private callerIds: { [number: string]: TapiContact } = {}
|
private callerIds: { [number: string]: TapiContact } = {}
|
||||||
@@ -57,18 +59,7 @@ export class CallHistory {
|
|||||||
a.onclick = () => {
|
a.onclick = () => {
|
||||||
window.open(href)
|
window.open(href)
|
||||||
}
|
}
|
||||||
a.innerHTML = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 559.98 559.98">' +
|
a.innerHTML = telephoneIcon;
|
||||||
'<g>' +
|
|
||||||
' <g>' +
|
|
||||||
' <path d="M279.99,0C125.601,0,0,125.601,0,279.99c0,154.39,125.601,279.99,279.99,279.99c154.39,0,279.99-125.601,279.99-279.99' +
|
|
||||||
' C559.98,125.601,434.38,0,279.99,0z M279.99,498.78c-120.644,0-218.79-98.146-218.79-218.79' +
|
|
||||||
' c0-120.638,98.146-218.79,218.79-218.79s218.79,98.152,218.79,218.79C498.78,400.634,400.634,498.78,279.99,498.78z"/>' +
|
|
||||||
' <path d="M304.226,280.326V162.976c0-13.103-10.618-23.721-23.716-23.721c-13.102,0-23.721,10.618-23.721,23.721v124.928' +
|
|
||||||
' c0,0.373,0.092,0.723,0.11,1.096c-0.312,6.45,1.91,12.999,6.836,17.926l88.343,88.336c9.266,9.266,24.284,9.266,33.543,0' +
|
|
||||||
' c9.26-9.266,9.266-24.284,0-33.544L304.226,280.326z"/>' +
|
|
||||||
' </g>' +
|
|
||||||
'</g>' +
|
|
||||||
'</svg>'
|
|
||||||
|
|
||||||
a.classList.add('btn');
|
a.classList.add('btn');
|
||||||
a.classList.add('btn-plain');
|
a.classList.add('btn-plain');
|
||||||
@@ -86,7 +77,7 @@ export class CallHistory {
|
|||||||
if (this.callerIds[number] !== undefined) {
|
if (this.callerIds[number] !== undefined) {
|
||||||
this.updateCallHistoryEntry(element, this.callerIds[number])
|
this.updateCallHistoryEntry(element, this.callerIds[number])
|
||||||
} else {
|
} else {
|
||||||
var response = await GM_fetch('http://cpatapi.cpsrvweb2016.cp-austria.at/callerid/' + encodeURIComponent(number))
|
var response = await GM_fetch(Config.tapi_server_url + '/callerid/' + encodeURIComponent(number))
|
||||||
var callerId: TapiContact = { tD_NAME: '' }
|
var callerId: TapiContact = { tD_NAME: '' }
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
callerId = await response.json() as TapiContact
|
callerId = await response.json() as TapiContact
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import GM_fetch from '@trim21/gm-fetch'
|
import GM_fetch from '@trim21/gm-fetch'
|
||||||
import { TapiContact } from './tapi-contact'
|
import { TapiContact } from './tapi-contact'
|
||||||
import { extractNumber } from './utils'
|
import { extractNumber } from './utils'
|
||||||
|
import { Config } from './config'
|
||||||
|
|
||||||
export class CallNotification {
|
export class CallNotification {
|
||||||
public async showCallNotification (element: HTMLElement) {
|
public async showCallNotification (element: HTMLElement) {
|
||||||
@@ -14,7 +15,7 @@ export class CallNotification {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('TAPI searching callerid for', number)
|
console.log('TAPI searching callerid for', number)
|
||||||
var response = await GM_fetch('http://cpatapi.cpsrvweb2016.cp-austria.at/callerid/' + encodeURIComponent(number))
|
var response = await GM_fetch(Config.tapi_server_url + '/callerid/' + encodeURIComponent(number))
|
||||||
console.log('TAPI callerid response', response)
|
console.log('TAPI callerid response', response)
|
||||||
var notification = {
|
var notification = {
|
||||||
text: number
|
text: number
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class _Config {
|
||||||
|
public tapi_server_url: string = 'https://3cxtapi.cp-austria.at'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Config = new _Config()
|
||||||
@@ -17,8 +17,10 @@ waitForKeyElements('call-view', (element) => { callNotification.showCallNotifica
|
|||||||
|
|
||||||
const callHistory = new CallHistory()
|
const callHistory = new CallHistory()
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
waitForKeyElements('.call-history-list call', (element) => { callHistory.showCallHistory(element) }, false)
|
waitForKeyElements('call', (element) => { callHistory.showCallHistory(element) }, false)
|
||||||
|
|
||||||
const status = new Status()
|
const status = new Status()
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
waitForKeyElements('wc-account-menu', (element) => { status.showStatus(element) }, false)
|
waitForKeyElements('wc-account-menu', (element) => { status.showStatus(element) }, false)
|
||||||
|
|
||||||
|
waitForKeyElements('wc-account-menu i.status-indicator', (element) => { status.watchStatus(element) }, false)
|
||||||
@@ -3,6 +3,7 @@ import { TapiContact } from './tapi-contact'
|
|||||||
import { debounce } from './debounce'
|
import { debounce } from './debounce'
|
||||||
import { fireChangeEvents } from './utils'
|
import { fireChangeEvents } from './utils'
|
||||||
import GM_fetch from '@trim21/gm-fetch'
|
import GM_fetch from '@trim21/gm-fetch'
|
||||||
|
import { Config } from './config'
|
||||||
|
|
||||||
export class Search {
|
export class Search {
|
||||||
private currentSearchText = ''
|
private currentSearchText = ''
|
||||||
@@ -103,7 +104,7 @@ export class Search {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log('Searching TAPI')
|
console.log('Searching TAPI')
|
||||||
var response = await GM_fetch('http://cpatapi.cpsrvweb2016.cp-austria.at/search?query=' + encodeURIComponent(searchText))
|
var response = await GM_fetch(Config.tapi_server_url + '/search?query=' + encodeURIComponent(searchText))
|
||||||
console.log('TAPI Search response', response)
|
console.log('TAPI Search response', response)
|
||||||
var contacts = await response.json() as TapiContact[]
|
var contacts = await response.json() as TapiContact[]
|
||||||
console.log('TAPI Contacts', contacts)
|
console.log('TAPI Contacts', contacts)
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { Config } from './config';
|
||||||
import './status.css';
|
import './status.css';
|
||||||
import { ZcStatus } from './zc-status';
|
import { ZcStatus } from './zc-status';
|
||||||
import GM_fetch from "@trim21/gm-fetch";
|
import GM_fetch from "@trim21/gm-fetch";
|
||||||
|
const zcIcon = require('./stopwatch-regular-full.svg');
|
||||||
|
|
||||||
declare function waitForKeyElements(selectorOrFunction: any, callback: any, waitOnce: boolean): any;
|
declare function waitForKeyElements(selectorOrFunction: any, callback: any, waitOnce: boolean): any;
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ export class Status {
|
|||||||
private async checkStatus() {
|
private async checkStatus() {
|
||||||
if (this._enabled) {
|
if (this._enabled) {
|
||||||
try {
|
try {
|
||||||
var response = await GM_fetch('http://cpatapi.cpsrvweb2016.cp-austria.at/availability/' + encodeURIComponent(this._user));
|
var response = await GM_fetch(Config.tapi_server_url + '/availability/' + encodeURIComponent(this._user));
|
||||||
if (response.status == 200) {
|
if (response.status == 200) {
|
||||||
var status = await response.json() as ZcStatus;
|
var status = await response.json() as ZcStatus;
|
||||||
if (this._currentStatus !== status.loggedIn) {
|
if (this._currentStatus !== status.loggedIn) {
|
||||||
@@ -56,57 +58,69 @@ export class Status {
|
|||||||
element.appendChild(divider);
|
element.appendChild(divider);
|
||||||
|
|
||||||
var menu = document.createElement('li');
|
var menu = document.createElement('li');
|
||||||
|
menu.role = 'menuitem';
|
||||||
element.appendChild(menu);
|
element.appendChild(menu);
|
||||||
|
|
||||||
var link = document.createElement('a');
|
var link = document.createElement('a');
|
||||||
link.id = 'tapi-zc-button';
|
link.id = 'tapi-zc-button';
|
||||||
link.innerText = 'ZeitConsens';
|
//link.innerText = 'ZeitConsens';
|
||||||
link.classList.add('dropdown-item');
|
link.classList.add('dropdown-item');
|
||||||
link.classList.add('d-flex');
|
link.classList.add('d-flex');
|
||||||
|
link.classList.add('align-items-center');
|
||||||
|
link.classList.add('gap-2');
|
||||||
link.onclick = () => {
|
link.onclick = () => {
|
||||||
document.getElementById('zc-modal').classList.toggle('show');
|
document.getElementById('zc-modal').classList.toggle('show');
|
||||||
}
|
}
|
||||||
menu.appendChild(link);
|
menu.appendChild(link);
|
||||||
|
|
||||||
|
var icon = document.createElement('span');
|
||||||
|
icon.classList.add('icon');
|
||||||
|
icon.classList.add('svg-xs');
|
||||||
|
icon.innerHTML = zcIcon;
|
||||||
|
link.appendChild(icon);
|
||||||
|
var text = document.createElement('span');
|
||||||
|
text.innerText = 'ZeitConsens';
|
||||||
|
link.appendChild(text);
|
||||||
|
|
||||||
var html =
|
var html =
|
||||||
'<div role="document" class="modal-dialog">' +
|
'<div role="document" class="modal-dialog">' +
|
||||||
' <div class="modal-content">' +
|
' <div class="modal-content">' +
|
||||||
' <div class="modal-header">' +
|
' <div class="modal-header">' +
|
||||||
' <h4 class="modal-title">ZeitConsens Status</h4><button id="zc-btnClose" type="button" aria-label="Close" class="btn-close" data-qa="modal-cross"></button>' +
|
' <h4 class="modal-title">ZeitConsens Status</h4><button id="zc-btnClose" type="button" aria-label="Close" class="btn-close" data-qa="modal-cross"></button>' +
|
||||||
' </div>' +
|
' </div>' +
|
||||||
' <div class="modal-body">' +
|
' <div class="modal-body">' +
|
||||||
' <div class="form-group">' +
|
' <div class="form-group">' +
|
||||||
' <label for="tapi-zc-user">Username</label>' +
|
' <label for="tapi-zc-user">Username</label>' +
|
||||||
' <input type="text" class="form-control" name="tapi-zc-user" id="tapi-zc-user">' +
|
' <input type="text" class="form-control" name="tapi-zc-user" id="tapi-zc-user">' +
|
||||||
' </div>' +
|
' </div>' +
|
||||||
' <div class="form-group">' +
|
' <div class="form-group">' +
|
||||||
' <label for="tapi-zc-on">Signed in</label>' +
|
' <label for="tapi-zc-on">Signed in</label>' +
|
||||||
' <select id="tapi-zc-on" class="form-control">' +
|
' <select id="tapi-zc-on" class="form-control">' +
|
||||||
' <option value="menuAvailable">Available</option>' +
|
' <option value="menuAvailable">Available</option>' +
|
||||||
' <option value="menuOutofoffice">Do Not Disturb</option>' +
|
' <option value="menuOutofoffice">Do Not Disturb</option>' +
|
||||||
' <option value="menuCustom1">Verfügbar DW</option>' +
|
' <option value="menuCustom1">Verfügbar DW</option>' +
|
||||||
' </select>' +
|
' </select>' +
|
||||||
' </div>' +
|
' </div>' +
|
||||||
' <div class="form-group">' +
|
' <div class="form-group">' +
|
||||||
' <label for="tapi-zc-off">Signed out</label>' +
|
' <label for="tapi-zc-off">Signed out</label>' +
|
||||||
' <select id="tapi-zc-off" class="form-control">' +
|
' <select id="tapi-zc-off" class="form-control">' +
|
||||||
' <option value="menuAway">Away</option>' +
|
' <option value="menuAway">Away</option>' +
|
||||||
' <option value="menuOutofoffice">Do Not Disturb</option>' +
|
' <option value="menuOutofoffice">Do Not Disturb</option>' +
|
||||||
' </select>' +
|
' </select>' +
|
||||||
' </div>' +
|
' </div>' +
|
||||||
' <div class="checkbox">' +
|
' <div class="checkbox">' +
|
||||||
' <label class="i-checks" for="tapi-zc-enabled">' +
|
' <label class="i-checks" for="tapi-zc-enabled">' +
|
||||||
' <input type="checkbox" id="tapi-zc-enabled">' +
|
' <input type="checkbox" id="tapi-zc-enabled">' +
|
||||||
' <i></i><span>Enabled</span>' +
|
' <i></i><span>Enabled</span>' +
|
||||||
' </label>' +
|
' </label>' +
|
||||||
' </div>' +
|
' </div>' +
|
||||||
' </div>' +
|
' </div>' +
|
||||||
//' <div class="modal-footer">' +
|
//' <div class="modal-footer">' +
|
||||||
//' <button id="zc-btnOk" type="button" class="btn btn-primary" data-qa="modal-ok">OK </button>' +
|
//' <button id="zc-btnOk" type="button" class="btn btn-primary" data-qa="modal-ok">OK </button>' +
|
||||||
//' <button id="zc-btnCancel" type="button" class="btn btn-border" data-qa="modal-close">Cancel </button>' +
|
//' <button id="zc-btnCancel" type="button" class="btn btn-border" data-qa="modal-close">Cancel </button>' +
|
||||||
//' </div>' +
|
//' </div>' +
|
||||||
' </div>' +
|
' </div>' +
|
||||||
'</div>';
|
'</div>';
|
||||||
var modal = document.createElement('modal-container');
|
var modal = document.createElement('modal-container');
|
||||||
modal.id = 'zc-modal';
|
modal.id = 'zc-modal';
|
||||||
modal.classList.add('modal');
|
modal.classList.add('modal');
|
||||||
@@ -156,4 +170,34 @@ export class Status {
|
|||||||
this._currentStatus = undefined;
|
this._currentStatus = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public watchStatus(element: HTMLElement) {
|
||||||
|
console.log('updateFavicon watching', element);
|
||||||
|
const attrObserver = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach((mutation) => {
|
||||||
|
if (mutation.attributeName === 'class') {
|
||||||
|
this.updateStatus(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
attrObserver.observe(element, { attributes: true });
|
||||||
|
this.updateStatus(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateStatus(element: HTMLElement) {
|
||||||
|
console.log('Status changed', element.classList);
|
||||||
|
var color = window.getComputedStyle(element).getPropertyValue("background-color");
|
||||||
|
console.log('Background color:', color);
|
||||||
|
this.setFaviconColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setFaviconColor(color: string) {
|
||||||
|
var link = document.querySelector("link[rel~='icon']") as HTMLLinkElement;
|
||||||
|
if (!link) {
|
||||||
|
link = document.createElement('link');
|
||||||
|
link.rel = 'icon';
|
||||||
|
document.head.appendChild(link);
|
||||||
|
}
|
||||||
|
link.href = "data:image/svg+xml,%3Csvg width='32px' height='32px' xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cpolyline points='9,0 20,0 32,16 20,32 9,32, 20,16' fill='" + encodeURIComponent(color) + "' id='MyLine' /%3E%3C/svg%3E";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Pro 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2026 Fonticons, Inc.--><path d="M240 88C240 74.7 250.7 64 264 64L376 64C389.3 64 400 74.7 400 88C400 101.3 389.3 112 376 112L344 112L344 137.3C393.6 142.8 438.1 165 471.8 198.3L495 175C504.4 165.6 519.6 165.6 528.9 175C538.2 184.4 538.3 199.6 528.9 208.9L502.1 235.7C523.5 269.2 536 309.1 536 351.9C536 471.2 439.3 567.9 320 567.9C200.7 567.9 104 471.3 104 352C104 240.8 188 149.3 296 137.3L296 112L264 112C250.7 112 240 101.3 240 88zM320 184C227.2 184 152 259.2 152 352C152 444.8 227.2 520 320 520C412.8 520 488 444.8 488 352C488 259.2 412.8 184 320 184zM344 248L344 352C344 365.3 333.3 376 320 376C306.7 376 296 365.3 296 352L296 248C296 234.7 306.7 224 320 224C333.3 224 344 234.7 344 248z"/></svg>
|
||||||
|
After Width: | Height: | Size: 906 B |
@@ -0,0 +1,12 @@
|
|||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 559.98 559.98">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M279.99,0C125.601,0,0,125.601,0,279.99c0,154.39,125.601,279.99,279.99,279.99c154.39,0,279.99-125.601,279.99-279.99
|
||||||
|
C559.98,125.601,434.38,0,279.99,0z M279.99,498.78c-120.644,0-218.79-98.146-218.79-218.79
|
||||||
|
c0-120.638,98.146-218.79,218.79-218.79s218.79,98.152,218.79,218.79C498.78,400.634,400.634,498.78,279.99,498.78z"/>
|
||||||
|
<path d="M304.226,280.326V162.976c0-13.103-10.618-23.721-23.716-23.721c-13.102,0-23.721,10.618-23.721,23.721v124.928
|
||||||
|
c0,0.373,0.092,0.723,0.11,1.096c-0.312,6.45,1.91,12.999,6.836,17.926l88.343,88.336c9.266,9.266,24.284,9.266,33.543,0
|
||||||
|
c9.26-9.266,9.266-24.284,0-33.544L304.226,280.326z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 821 B |
@@ -0,0 +1,30 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
|
!**/.gitignore
|
||||||
|
!.git/HEAD
|
||||||
|
!.git/config
|
||||||
|
!.git/packed-refs
|
||||||
|
!.git/refs/heads/**
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 18
|
||||||
|
VisualStudioVersion = 18.5.11612.153 insiders
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CPATapi.Server", "src\CPATapi.Server\CPATapi.Server.csproj", "{7879A024-A074-FE67-0546-8668213BFA99}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{7879A024-A074-FE67-0546-8668213BFA99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7879A024-A074-FE67-0546-8668213BFA99}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7879A024-A074-FE67-0546-8668213BFA99}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7879A024-A074-FE67-0546-8668213BFA99}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {E2CF5765-9038-4ED6-AC5C-1A3E569ABC6C}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UserSecretsId>a7b40068-a2f6-4c63-bbd9-0fd346908fb0</UserSecretsId>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<DockerfileContext>..\..</DockerfileContext>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Dapper" Version="2.1.72" />
|
||||||
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.9.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using CPATapi.Server.Interfaces;
|
||||||
|
using CPATapi.Server.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Dapper;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Controllers;
|
||||||
|
|
||||||
|
[Route("[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class AvailabilityController(IZeitConsensRepository zeitConsens) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
[Route("users")]
|
||||||
|
[ProducesResponseType<IEnumerable<string>>(StatusCodes.Status200OK)]
|
||||||
|
public async Task<IActionResult> GetUsers()
|
||||||
|
{
|
||||||
|
return Ok(await zeitConsens.GetUsersAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("{user}")]
|
||||||
|
[ProducesResponseType<Availability>(StatusCodes.Status200OK)]
|
||||||
|
public async Task<IActionResult> GetAvailability(string user)
|
||||||
|
{
|
||||||
|
var stampCount = (await zeitConsens.GetStampsAsync(user, DateTime.Now.Date, DateTime.Now.AddDays(1).Date)).Count();
|
||||||
|
return Ok(new Availability { User = user, LoggedIn = stampCount % 2 != 0 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using CPATapi.Server.Interfaces;
|
||||||
|
using CPATapi.Server.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Controllers;
|
||||||
|
|
||||||
|
[Route("[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class CallerIdController(ITapiDirectoryRepository tapiDirectory) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
[Route("{number}")]
|
||||||
|
[ProducesResponseType<TapiContact>(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<IActionResult> CallerIdAsync([FromRoute] string number)
|
||||||
|
{
|
||||||
|
if (number.Length >= 5)
|
||||||
|
{
|
||||||
|
var minMatch = number[^5..];
|
||||||
|
number = "%" + minMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await tapiDirectory.SearchByNumberAsync(number);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using CPATapi.Server.Interfaces;
|
||||||
|
using CPATapi.Server.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]")]
|
||||||
|
public class ContactController(ILogger<ContactController> logger, ITapiDirectoryRepository tapiDirectory) : ControllerBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly ILogger<ContactController> _logger = logger;
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Produces("application/json")]
|
||||||
|
[ProducesResponseType<IEnumerable<TapiContact>>(StatusCodes.Status200OK)]
|
||||||
|
public async Task<IActionResult> GetAsync()
|
||||||
|
{
|
||||||
|
return Ok(await tapiDirectory.GetAllAsync());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using CPATapi.Server.Interfaces;
|
||||||
|
using CPATapi.Server.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Controllers;
|
||||||
|
|
||||||
|
[Route("[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class SearchController(ITapiDirectoryRepository tapiDirectory) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
[ProducesResponseType<IEnumerable<TapiContact>>(StatusCodes.Status200OK)]
|
||||||
|
public async Task<IActionResult> SearchAsync([FromQuery] string query)
|
||||||
|
{
|
||||||
|
if (query == null)
|
||||||
|
{
|
||||||
|
return Ok(new List<TapiContact>());
|
||||||
|
}
|
||||||
|
|
||||||
|
var args = Regex.Split(query, "\\s").Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).ToArray();
|
||||||
|
|
||||||
|
return Ok(await tapiDirectory.SearchAsync(args));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||||
|
|
||||||
|
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||||
|
USER $APP_UID
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# This stage is used to build the service project
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["CPATapi.Server/CPATapi.Server.csproj", "CPATapi.Server/"]
|
||||||
|
RUN dotnet restore "CPATapi.Server/CPATapi.Server.csproj"
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/CPATapi.Server"
|
||||||
|
RUN dotnet build "./CPATapi.Server.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||||
|
|
||||||
|
# This stage is used to publish the service project to be copied to the final stage
|
||||||
|
FROM build AS publish
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
RUN dotnet publish "./CPATapi.Server.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "CPATapi.Server.dll"]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
namespace CPATapi.Server.Interfaces;
|
||||||
|
|
||||||
|
public interface IRepository
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using CPATapi.Server.Models;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Interfaces;
|
||||||
|
|
||||||
|
public interface ITapiDirectoryRepository : IRepository
|
||||||
|
{
|
||||||
|
Task<IEnumerable<TapiContact>> SearchAsync(string[] args);
|
||||||
|
Task<TapiContact?> SearchByNumberAsync(string number);
|
||||||
|
Task<IEnumerable<TapiContact>> GetAllAsync();
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using CPATapi.Server.Models;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Interfaces;
|
||||||
|
|
||||||
|
public interface IZeitConsensRepository : IRepository
|
||||||
|
{
|
||||||
|
Task<IEnumerable<string>> GetUsersAsync();
|
||||||
|
Task<IEnumerable<Stamp>> GetStampsAsync(string user, DateTime from, DateTime to);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Models;
|
||||||
|
|
||||||
|
public class Availability
|
||||||
|
{
|
||||||
|
[JsonPropertyName("user")]
|
||||||
|
public string User { get; set; }
|
||||||
|
[JsonPropertyName("loggedIn")]
|
||||||
|
public bool LoggedIn { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace CPATapi.Server.Models;
|
||||||
|
|
||||||
|
public class Stamp
|
||||||
|
{
|
||||||
|
public int MA_NR { get; set; }
|
||||||
|
public DateTime BU_BU { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace CPATapi.Server.Models;
|
||||||
|
|
||||||
|
public class TapiContact
|
||||||
|
{
|
||||||
|
public string TD_ID { get; set; }
|
||||||
|
public string TD_NAME { get; set; }
|
||||||
|
public string TD_NUMBER { get; set; }
|
||||||
|
public string TD_NUMBER_TAPI { get; set; }
|
||||||
|
public string TD_MEDIUM { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using CPATapi.Server.Interfaces;
|
||||||
|
using CPATapi.Server.Repository;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Services.AddSerilog(config =>
|
||||||
|
{
|
||||||
|
config
|
||||||
|
.ReadFrom.Configuration(builder.Configuration)
|
||||||
|
.Enrich.WithClientIp()
|
||||||
|
.Enrich.WithCorrelationId()
|
||||||
|
.Enrich.WithRequestHeader("User-Agent")
|
||||||
|
.WriteTo.Console();
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddTransient<ITapiDirectoryRepository, TapiDirectoryRepository>();
|
||||||
|
builder.Services.AddTransient<IZeitConsensRepository, ZeitConsensRepository>();
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
app.UseSerilogRequestLogging();
|
||||||
|
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
await app.RunAsync();
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "contact",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CPATapiServer": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "availability/users",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "https://3cxtapi.cp-austria.at:5001;https://localhost:5001;http://localhost:5000"
|
||||||
|
},
|
||||||
|
"Container (Dockerfile)": {
|
||||||
|
"commandName": "Docker",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/contact",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_HTTP_PORTS": "8080"
|
||||||
|
},
|
||||||
|
"publishAllPorts": true,
|
||||||
|
"useSSL": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:62406",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Data.Common;
|
||||||
|
using CPATapi.Server.Interfaces;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Repository;
|
||||||
|
|
||||||
|
public class Repository: IRepository
|
||||||
|
{
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
|
||||||
|
protected Repository(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
protected async Task<DbConnection> OpenAsync(string name)
|
||||||
|
{
|
||||||
|
var db = new SqlConnection(_config.GetConnectionString(name));
|
||||||
|
await db.OpenAsync();
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using System.Text;
|
||||||
|
using CPATapi.Server.Interfaces;
|
||||||
|
using CPATapi.Server.Models;
|
||||||
|
using Dapper;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Repository;
|
||||||
|
|
||||||
|
internal class TapiDirectoryRepository(IConfiguration config) : Repository(config), ITapiDirectoryRepository
|
||||||
|
{
|
||||||
|
public async Task<IEnumerable<TapiContact>> SearchAsync(string[] args)
|
||||||
|
{
|
||||||
|
await using var con = await OpenAsync("Tapi");
|
||||||
|
var sql = new StringBuilder("""
|
||||||
|
SELECT TOP 10
|
||||||
|
TD_ID,
|
||||||
|
TD_NAME,
|
||||||
|
TD_NUMBER,
|
||||||
|
TD_NUMBER_TAPI,
|
||||||
|
TD_MEDIUM
|
||||||
|
FROM dbo.CP_TAPI_DIRECTORY
|
||||||
|
WHERE
|
||||||
|
""");
|
||||||
|
var first = true;
|
||||||
|
var dp = new DynamicParameters();
|
||||||
|
for (var i = 1; i <= args.Length; i++)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
sql.AppendLine("AND");
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
sql.AppendLine($"(TD_NAME LIKE @s{i} OR");
|
||||||
|
sql.AppendLine($" TD_NUMBER_TAPI LIKE @s{i})");
|
||||||
|
dp.Add($"s{i}", $"%{args[i-1]}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await con.QueryAsync<TapiContact>(sql.ToString(), dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TapiContact?> SearchByNumberAsync(string number)
|
||||||
|
{
|
||||||
|
await using var con = await OpenAsync("Tapi");
|
||||||
|
|
||||||
|
var result = await con.QueryFirstOrDefaultAsync<TapiContact>("""
|
||||||
|
SELECT
|
||||||
|
TD_ID
|
||||||
|
,TD_NAME
|
||||||
|
,TD_NUMBER
|
||||||
|
,TD_NUMBER_TAPI
|
||||||
|
,TD_MEDIUM
|
||||||
|
FROM dbo.CP_TAPI_DIRECTORY
|
||||||
|
WHERE TD_NUMBER_TAPI LIKE @number
|
||||||
|
""", new {number});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TapiContact>> GetAllAsync()
|
||||||
|
{
|
||||||
|
await using var con = await OpenAsync("Tapi");
|
||||||
|
|
||||||
|
return await con.QueryAsync<TapiContact>("""
|
||||||
|
SELECT
|
||||||
|
TD_ID
|
||||||
|
,TD_NAME
|
||||||
|
,TD_NUMBER
|
||||||
|
,TD_NUMBER_TAPI
|
||||||
|
,TD_MEDIUM
|
||||||
|
FROM dbo.CP_TAPI_DIRECTORY
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using CPATapi.Server.Interfaces;
|
||||||
|
using CPATapi.Server.Models;
|
||||||
|
using Dapper;
|
||||||
|
|
||||||
|
namespace CPATapi.Server.Repository;
|
||||||
|
|
||||||
|
internal class ZeitConsensRepository(IConfiguration config) : Repository(config), IZeitConsensRepository
|
||||||
|
{
|
||||||
|
public async Task<IEnumerable<string>> GetUsersAsync()
|
||||||
|
{
|
||||||
|
await using var con = await OpenAsync("ZeitConsens");
|
||||||
|
return await con.QueryAsync<string>("""
|
||||||
|
SELECT DISTINCT MA_USER_NAME
|
||||||
|
FROM dbo.MA_DATEN
|
||||||
|
WHERE MA_USER_NAME IS NOT NULL AND MA_USER_AKTIV = 1
|
||||||
|
ORDER BY MA_USER_NAME
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Stamp>> GetStampsAsync(string user, DateTime from, DateTime to)
|
||||||
|
{
|
||||||
|
await using var con = await OpenAsync("ZeitConsens");
|
||||||
|
return await con.QueryAsync<Stamp>("""
|
||||||
|
SELECT
|
||||||
|
MA_NR
|
||||||
|
,BU_BU
|
||||||
|
FROM dbo.BU
|
||||||
|
INNER JOIN dbo.MA_DATEN on MA_NR = BU_MA_NR
|
||||||
|
WHERE
|
||||||
|
MA_USER_NAME = @user AND
|
||||||
|
BU_BU >= @from AND BU_BU < @to
|
||||||
|
""", new { user, from, to });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"Tapi": "",
|
||||||
|
"ZeitConsens": ""
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
cd /d %~dp0
|
||||||
|
|
||||||
|
docker build -t source.cp-austria.at/cpatrd/3cx_tapi:latest -f Dockerfile ..
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo.
|
||||||
|
echo ERROR: Docker build failed!
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
SET /P AREYOUSURE=Publish to source.cp-austria.at? (Y/[N])
|
||||||
|
IF /I "%AREYOUSURE%" NEQ "Y" GOTO END
|
||||||
|
|
||||||
|
docker push source.cp-austria.at/cpatrd/3cx_tapi:latest
|
||||||
|
|
||||||
|
:END
|
||||||
|
endlocal
|
||||||
Reference in New Issue
Block a user