diff --git a/README.md b/README.md index 4d897e2..0f1fc2b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ # daster -Dialplan Asterisk - управление диалпланом - -![mainpage](images/mainpage.png) +Управление диалпланом diff --git a/database/script.sql b/database/script.sql index beecc0f..4789ce4 100644 --- a/database/script.sql +++ b/database/script.sql @@ -1,38 +1,38 @@ create table if not exists da_groups ( - da_name varchar(20) not null, - da_comment varchar(100) default null, - constraint da_groups_pk primary key (da_name) + da_name varchar(20) not null, + da_comment varchar(100) default null, + constraint da_groups_pk primary key (da_name) ); insert into da_groups (da_name, da_comment) - values - ('general', 'Общие контакты'), - ('work', 'Рабочие контакты'), - ('personal', 'Личные контакты'); + values + ('general', 'Общие контакты'), + ('work', 'Рабочие контакты'), + ('personal', 'Личные контакты'); create table if not exists da_lists ( - da_name varchar(20) not null, - da_comment varchar(100) default null, - constraint da_lists_pk primary key (da_name) + da_name varchar(20) not null, + da_comment varchar(100) default null, + constraint da_lists_pk primary key (da_name) ); insert into da_lists (da_name, da_comment) - values - ('general', 'Общий'), - ('whitelist', 'Белый'), - ('blacklist', 'Черный'); + values + ('general', 'Общий'), + ('whitelist', 'Белый'), + ('blacklist', 'Черный'); create table if not exists da_numbers ( - da_number varchar(12) not null, - da_group varchar(20) not null default 'general', - da_list varchar(20) not null default 'general', - da_all_cc int not null default 0, - da_white_cc int not null default 0, - da_black_cc int not null default 0, - da_comment varchar(100) default null, - constraint da_numbers_pk primary key (da_number), - foreign key (da_group) references da_groups (da_name) on delete set null on update cascade, - foreign key (da_list) references da_lists (da_name) on delete set null on update cascade + da_number varchar(12) not null, + da_group varchar(20) not null default 'general', + da_list varchar(20) not null default 'general', + da_all_cc int not null default 0, + da_white_cc int not null default 0, + da_black_cc int not null default 0, + da_comment varchar(100) default null, + constraint da_numbers_pk primary key (da_number), + foreign key (da_group) references da_groups (da_name) on delete set null on update cascade, + foreign key (da_list) references da_lists (da_name) on delete set null on update cascade ); create table if not exists da_sms ( @@ -44,21 +44,6 @@ create table if not exists da_sms ( constraint da_sms_pk primary key (da_id) ); -create table if not exists da_ussd_type ( - da_id bigserial not null, - da_comment varchar(100) not null, - constraint da_ussd_type_pk primary key (da_id) -); - -insert into da_ussd_type (da_id, da_comment) - values - ('0', 'Уведомление'), - ('1', 'Запрос'), - ('2', 'Прервано сетью'), - ('3', 'Ответ другого локального клиента'), - ('4', 'Операция не поддерживается'), - ('5', 'Тайм-аут сети'); - create table if not exists da_ussd ( da_id bigserial not null, da_date timestamp not null default NOW(), @@ -69,10 +54,9 @@ create table if not exists da_ussd ( ); create table if not exists da_server ( - da_id int not null default 1, + da_address varchar(50) not null, da_transparent_mode bool not null default false, da_internal_number varchar(12) not null, da_external_number varchar(12) not null, - da_external_number_on bool not null default true, - constraint da_server_pk primary key (da_id) + constraint da_server_pk primary key (da_address) ); diff --git a/dub.json b/dub.json index d1e1943..5814e7b 100644 --- a/dub.json +++ b/dub.json @@ -5,9 +5,10 @@ "copyright": "Copyright © 2023, Alexander Zhirov", "dependencies": { "vibe-d": "~>0.9", - "singlog": "~>0.4.0", + "ldap": "~>0.4", + "singlog": "~>0.3.1", "arsd-official:postgres": "~>10.9.10", - "readconf": "~>0.4.0" + "readconf": "~>0.3.1" }, "buildTypes": { "debug": { @@ -25,7 +26,7 @@ } }, "description": "Dialplan Asterisk - веб-сервер для управления обработкой вызовов Asterisk", - "license": "GPL-2.0", + "license": "proprietary", "name": "daster", "targetPath": "bin", "targetType": "executable" diff --git a/dub.selections.json b/dub.selections.json index 08bea5a..f10278b 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -5,14 +5,15 @@ "datefmt": "1.0.4", "diet-ng": "1.8.1", "eventcore": "0.9.25", + "ldap": "0.4.0", "libasync": "0.8.6", "memutils": "1.0.9", "mir-linux-kernel": "1.0.1", "openssl": "3.3.0", "openssl-static": "1.0.2+3.0.8", - "readconf": "0.4.0", - "silly": "1.2.0-dev.2", - "singlog": "0.4.0", + "readconf": "0.3.1", + "silly": "1.1.1", + "singlog": "0.3.1", "stdx-allocator": "2.77.5", "taggedalgebraic": "0.11.22", "vibe-core": "2.2.0", diff --git a/images/404.png b/images/404.png deleted file mode 100644 index 116c3e7..0000000 Binary files a/images/404.png and /dev/null differ diff --git a/images/favicon.png b/images/favicon.png index e220943..f78f532 100644 Binary files a/images/favicon.png and b/images/favicon.png differ diff --git a/images/mainpage.png b/images/mainpage.png deleted file mode 100644 index d5cf9bf..0000000 Binary files a/images/mainpage.png and /dev/null differ diff --git a/js/authorization.js b/js/authorization.js deleted file mode 100644 index 4edab3f..0000000 --- a/js/authorization.js +++ /dev/null @@ -1,48 +0,0 @@ -$(document).ready(function () { - noticer = new Noticer; - - $("#authorization").button({ icon: "ui-icon-home" }); - - $("#login, #password").on('keypress',function(e) { - if(e.which == 13) { - authorization() - } - }); - - $("#authorization").click(() => { - authorization() - }); - - $("body").fadeTo(500, 1); -}); - -function authorization() { - request().then((data) => { - data.error ? noticer.error(data.message) : (window.location.href = "."); - }).catch((e) => { - noticer.error(e.message); - }); -} - -async function request() { - let login = $("#login").val(); - let password = $("#password").val(); - - let response = await fetch('.', { - method: 'POST', - headers: { - 'Content-Type': 'application/json;charset=utf-8' - }, - body: JSON.stringify({ - login: login, - password: password, - query: "login" - }) - }); - - if (!response.ok) - throw new Error(`Произошла неизвестаня ошибка: ${response.status}`); - - const data = await response.json(); - return data; -} diff --git a/js/message.js b/js/message.js new file mode 100644 index 0000000..e064ac5 --- /dev/null +++ b/js/message.js @@ -0,0 +1,100 @@ +class Message { + timer; + + constructor() { + this.div = $('
'); + this.div.css({ + "position": "absolute", + "top": "10px", + "right": "20px", + "z-index": "1000" + }); + + $('body').append(this.div); + } + + success(message, delay = 6000) { + this.print(message, delay, '#52b818', '#bffdc0'); + } + + warning(message, delay = 6000) { + this.print(message, delay, '#b8ae18', '#f8fdbf'); + } + + error(message, delay = 6000) { + this.print(message, delay, '#b96161', '#fddede'); + } + + print = function(message, delay, border, background) { + if (delay < 6000) delay = 6000; + let Timer = function(callback, delay) { + let timerId, start, remaining = delay; + + this.pause = function() { + clearTimeout(timerId); + remaining -= new Date() - start; + }; + + this.resume = function() { + start = new Date(); + clearTimeout(timerId); + timerId = setTimeout(callback, remaining); + }; + + this.dead = function() { + clearTimeout(timerId); + }; + + this.resume(); + } + + let newMessage = $(`
${message}
`); + + newMessage.css({ + "border": `1px solid ${border}`, + "background-color": `${background}`, + "color": "#333", + "padding": "10px 30px", + "text-align": "center", + "display": "none", + "margin": "10px 0 0 0", + "width": "350px", + "opacity": "1", + "cursor": "pointer" + }); + + newMessage.hover(function(){ + $(this).css({ + "opacity": "1" + }); + }, function(){ + $(this).css({ + "opacity": "0.3" + }); + }); + + this.div.append(newMessage); + + let opacityTimeout = setTimeout(function() { + newMessage.fadeTo(1000, 0.3); + }, 2500); + + newMessage.fadeIn(500).mouseenter(() => { + clearTimeout(opacityTimeout); + this.timer.pause(); + }).mouseleave(() => { + this.timer.resume(); + }).click(() => { + this.timer.dead(); + newMessage.fadeOut(0, function(){ + this.remove(); + }); + }); + + this.timer = new Timer(() => { + newMessage.fadeOut(500, function(){ + this.remove(); + }); + }, delay); + } +} diff --git a/js/noticer.min.js b/js/noticer.min.js deleted file mode 100644 index e7604a1..0000000 --- a/js/noticer.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! noticer - v0.1.1 - 2023-06-02 -* https://git.zhirov.kz/alexander/noticer -* Copyright Alexander Zhirov; Licensed GPL-2.0 */ -class Noticer{constructor(){this.div=$('
'),this.div.css({position:"absolute",top:"10px",right:"20px","z-index":"1000"}),$("body").append(this.div)}success(e,t=6e3){this.print(e,t,"#52b818","#bffdc0")}warning(e,t=6e3){this.print(e,t,"#b8ae18","#f8fdbf")}error(e,t=6e3){this.print(e,t,"#b96161","#fddede")}print=function(e,t,n,s){t<6e3&&(t=6e3);let a=function(e,t){let n,s,o=t;this.pause=function(){clearTimeout(n),o-=new Date-s},this.resume=function(){s=new Date,clearTimeout(n),n=setTimeout(e,o)},this.dead=function(){clearTimeout(n)},this.resume()},o=$(`
${e}
`);o.css({border:`1px solid ${n}`,"background-color":`${s}`,color:"#333",padding:"10px 30px","text-align":"center",display:"none",margin:"10px 0 0 0",width:"350px",opacity:"1",cursor:"pointer"}),o.hover(function(){$(this).css({opacity:"1"})},function(){$(this).css({opacity:"0.3"})}),this.div.append(o);let r=setTimeout(function(){o.fadeTo(1e3,.3)},2500);o.fadeIn(500).mouseenter(()=>{clearTimeout(r),i.pause()}).mouseleave(()=>{i.resume()}).click(()=>{i.dead(),o.fadeOut(0,function(){this.remove()})});let i=new a(()=>{o.fadeOut(500,function(){this.remove()})},t)}} diff --git a/js/script.js b/js/script.js index 7a00ef9..2dc6f90 100644 --- a/js/script.js +++ b/js/script.js @@ -1,77 +1,27 @@ -var numbers = []; -var sms = []; -var ussd = []; - $(document).ready(function () { - noticer = new Noticer; + message = new Message; - let tabs = { - 0: () => { loadNumbers() }, - 1: () => { loadSMS() }, - 2: () => { loadUSSD() }, - 3: () => { loadServerInfo() } - }; - - let lists = { - 0: () => { showListNumbers($("#accordion-numbers .ui-accordion-content-active")) }, - 1: () => { showListSMS($("#accordion-sms .ui-accordion-content-active")) }, - 2: () => { showListUSSD($("#accordion-ussd .ui-accordion-content-active")) }, - 3: () => {} - }; - - let groups = { - 0: () => { generateListGroupNumbers($("#accordion-numbers .ui-accordion-content-active")) }, - 1: () => { generateListGroupSMS($("#accordion-sms .ui-accordion-content-active")) }, - 2: () => { generateListGroupUSSD($("#accordion-ussd .ui-accordion-content-active")) }, - 3: () => {} - }; + // (new divNotFoundNumbers).push("Загрузка..."); $("button").button(); - $("#update-tab").button("option", "icon", "ui-icon-refresh"); - $("#update-group").button("option", "icon", "ui-icon-arrowrefresh-1-s"); - $("#add-number").button("option", "icon", "ui-icon-plusthick"); - $("#logout").button("option", "icon", "ui-icon-power"); + $("#tabs").tabs(); + // $("#accordion-numbers").accordion(); - $("#tabs").tabs({ - activate: function( event, ui ) { - lists[$(this).tabs( "option", "active" )](); - $("#add-number").button( "option", "disabled", $(this).tabs( "option", "active" ) > 0 ); - $("#update-group").button( "option", "disabled", $(this).tabs( "option", "active" ) > 2 ); - } - }); - - $("#update-tab").click(() => { - tabs[$("#tabs").tabs( "option", "active" )]() - }); - - $("#update-group").click(() => { - groups[$("#tabs").tabs( "option", "active" )]() - }); - - $("#add-number").click(() => { - addNumber($("#accordion-numbers .ui-accordion-content-active")) - }); - - $("#search").on("input", function () { - lists[$("#tabs").tabs( "option", "active" )]() - }).keydown(function (e) { - e.key == "Escape" && ($(this).val(""), lists[$("#tabs").tabs( "option", "active" )]()) - }); - - $("#logout").click(() => { - request('logout', 'json').then(data => { - data.error ? noticer.error(data.message) : (window.location.href = "."); - }).catch(error => { - noticer.error(error.message); - }); - }); - - loadNumbers(); - loadSMS(); - loadUSSD(); - loadServerInfo(); + // $(".addNumber").click(() => { + // numberAdd() + // }); $("body").fadeTo(500, 1); + + // getData("Список номеров успешно загружен"); + + $(".search").on("input", function () { + // showNumbers(numbers.filter(e => e.id.includes($(this).val()))) + }).keydown(function (e) { + // e.key == "Escape" && ($(this).val(""), showNumbers()) + }); + + loadData(); }) async function request(query, type, queryData = {}) { @@ -101,591 +51,40 @@ function isJSON(str) { } } -function isNumeric(value) { - return /^-?\d+$/.test(value); -} - -function divNotFoundNumbers(text = '') { - let notFound = $('.notFoundNumbers'); - let divTable = $('.body-rows'); - let divNotFound = $(`
${text}
`); - - divNotFound.css({ - "color": "#333", - "text-align": "center", - "padding": "20px 0 20px 0" - }); - - this.push = function() { - divTable.append(divNotFound); - } - - this.remove = function() { - notFound.remove(); - } -} - -function pEmpty(text) { - return $(`

${text}

`).css('text-align', 'center'); -} - -/************************************************************************************ - - Обработка таблицы с номерами телефонов - -************************************************************************************/ - -function loadNumbers() { - request('listnumbergroups', 'text').then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); - else - generateListNumberGroups(data); +function loadData() { + request('listsgroups', 'json').then(data => { + data.error ? message.error(data.message) : generateListsGroups(data); }).catch(error => { - noticer.error(error.message); + message.error(error.message); }); } -function generateListNumberGroups(data) { - if (!$(data).children().length) { - $("#tabs-numbers").html(pEmpty('Номера телефонов отсутствуют')); - return; - } - - $("#tabs-numbers").html(data); +function generateListsGroups(data) { + let numbers = $("#tabs-numbers"); + let group = $('
'); + $(data).each((i, j) => { + group.append(`

${j.comment}

`); + }); + numbers.append(group); $("#accordion-numbers").accordion({ heightStyle: "content", create: function( event, ui ) { - generateListGroupNumbers(ui.panel); + generateGroupNumbers(ui.panel); }, beforeActivate: function( event, ui ) { - generateListGroupNumbers(ui.newPanel); + generateGroupNumbers(ui.newPanel); } }); } -function generateListGroupNumbers(panel) { - if (!$("#accordion-numbers").children().length) { - noticer.warning("Номера телефонов отсутствуют"); - $("#tabs-numbers").html(pEmpty('Номера телефонов отсутствуют')); - return; - } - - request('listgroupnumbers', 'json', { group: panel.data("group-name") }).then(data => { - if (data.error) - noticer.error(data.message); - else { - numbers = data; - showListNumbers(panel); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -function showListNumbers(panel, data = numbers.filter(e => e.number.includes($("#search").val()))) { - (new divNotFoundNumbers).remove(); - let body = panel.find('.body').html(''); - $(data).each((i, j) => { - let row = $(``); - row.append(`${j.number}`); - row.append(`${j.list}`); - row.append(`${j.all_cc}`); - row.append(`${j.white_cc}`); - row.append(`${j.black_cc}`); - row.append(`${j.comment}`); - body.append(row); - - row.click(function() { - viewNumber(panel, $(this).data('number')); - }); - }); - - if (!body.children().length) - (new divNotFoundNumbers('Нет номеров')).push(); -} - -function viewNumber(panel, number) { - request('viewnumber', 'text', {number: number}).then(data => { +async function generateGroupNumbers(panel) { + request('groupnumbers', 'text', { group: panel.data("group-name") }).then(data => { if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); + message.error(JSON.parse(data).message); else { - showViewNumber(data, [ - { - id: "btn-save", - text: "Сохранить", - icon: "ui-icon-check", - click: function() { - actionNumber(panel, $(this), 'updatenumber'); - } - }, - { - id: "btn-delete", - text: "Удалить", - icon: "ui-icon-trash", - click: function() { - delNumber(panel, $(this)); - } - } - ], `Редактирование номера ${number}`); + panel.html(data); } }).catch(error => { - noticer.error(error.message); - }); -} - -function showViewNumber(data, actionButton, title) { - let form = $(data); - - form.appendTo('body').dialog({ - title: title, - height: 'auto', - width: 'auto', - resizable: false, - modal: true, - show: { effect: "fade", duration: 500 }, - close: function(event, ui) { - $(this).dialog('destroy').remove() - }, - buttons: [ - ...actionButton, - { - text: "Отмена", - icon: "ui-icon-cancel", - click: function() { - $(this).dialog("close"); - } - } - ] - }); - - $('#number-group, #number-list').selectmenu({ - width: 200 - }); -} - -function actionNumber(panel, currentWindow, query) { - let pattern_number = /^\+7\d{10}$/g; - - let number = $('#number-number').val(); - let group = $('#number-group').val(); - let list = $('#number-list').val(); - let all_cc = $('#number-all-cc').val(); - let white_cc = $('#number-white-cc').val(); - let black_cc = $('#number-black-cc').val(); - let comment = $('#number-comment').val(); - - let error = false; - - if (number.match(pattern_number) === null) { noticer.warning("Номер не соответствует формату +7XXXXXXXXXX"); error = true; } - if (!isNumeric(all_cc)) { noticer.warning("Общее количество звонков должно быть числом"); error = true; } - if (all_cc < 0) { noticer.warning("Общее количество звонков не может быть отрицательным"); error = true; } - if (!isNumeric(white_cc)) { noticer.warning("Белое количество звонков должно быть числом"); error = true; } - if (white_cc < 0) { noticer.warning("Белое количество звонков не может быть отрицательным"); error = true; } - if (!isNumeric(black_cc)) { noticer.warning("Черное количество звонков должно быть числом"); error = true; } - if (black_cc < 0) { noticer.warning("Черное количество звонков не может быть отрицательным"); error = true; } - - if (error) return; - - request(query, 'json', { - number: number, - group: group, - list: list, - all_cc: parseInt(all_cc), - white_cc: parseInt(white_cc), - black_cc: parseInt(black_cc), - comment: comment - }).then(data => { - if (data.error) - noticer.error(data.message); - else - { - query == 'write' ? noticer.success(`Номер ${number} был добавлен`) : noticer.success(`Номер ${number} был обновлен`); - generateListGroupNumbers(panel); - currentWindow.dialog("close"); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -function addNumber(panel) { - request('addnumber', 'text', { group: panel.data("group-name") }).then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); - else { - showViewNumber(data, [{ - id: "btnSave", - text: "Добавить", - icon: "ui-icon-check", - click: function() { - actionNumber(panel, $(this), 'writenumber'); - } - }], "Добавление нового номера"); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -function delNumber(panel, currentWindow) { - let number = $('#number-number').val(); - - let error = false; - if (!number.length) { noticer.warning('Номер не может быть пуст'); error = true; } - if (error) return; - - request('delnumber', 'json', { - number: number - }).then(data => { - if (data.error) - noticer.error(data.message); - else { - noticer.success(`Номер ${number} был удален`); - generateListGroupNumbers(panel); - currentWindow.dialog("close"); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -/************************************************************************************ - - Обработка таблицы с SMS - -************************************************************************************/ - -function loadSMS() { - request('listsmsgroups', 'text').then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); - else - generateListSMSGroups(data); - }).catch(error => { - noticer.error(error.message); - }); -} - -function generateListSMSGroups(data) { - if (!$(data).children().length) { - $("#tabs-sms").html(pEmpty('SMS отсутствуют')); - return; - } - - $("#tabs-sms").html(data); - $("#accordion-sms").accordion({ - heightStyle: "content", - create: function( event, ui ) { - generateListGroupSMS(ui.panel); - }, - beforeActivate: function( event, ui ) { - generateListGroupSMS(ui.newPanel); - } - }) -} - -function generateListGroupSMS(panel) { - if (!$("#accordion-sms").children().length) { - noticer.warning("SMS отсутствуют"); - $("#tabs-sms").html(pEmpty('SMS отсутствуют')); - return; - } - - request('listgroupsms', 'json', { to: panel.data("to") }).then(data => { - if (data.error) - noticer.error(data.message); - else { - sms = data; - showListSMS(panel); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -function showListSMS(panel, data = sms.filter(e => e.from.includes($("#search").val()))) { - (new divNotFoundNumbers).remove(); - let body = panel.find('.body').html(''); - $(data).each((i, j) => { - let row = $(``); - row.append(`${j.date}`); - row.append(`${j.from}`); - row.append(`${j.text}`); - body.append(row); - - row.click(function() { - viewSMS(panel, $(this).data('sms-id'), j.from); - }); - }); - - if (!body.children().length) - (new divNotFoundNumbers('Нет SMS')).push(); -} - -function viewSMS(panel, id, number) { - request('viewsms', 'text', {id: id}).then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); - else { - showViewSMS(data, [ - { - id: "btn-delete", - text: "Удалить", - icon: "ui-icon-trash", - click: function() { - delSMS(panel, $(this)); - } - } - ], `SMS от ${number}`); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -function showViewSMS(data, actionButton, title) { - let form = $(data); - - form.appendTo('body').dialog({ - title: title, - height: 'auto', - width: 'auto', - resizable: false, - modal: true, - show: { effect: "fade", duration: 500 }, - close: function(event, ui) { - $(this).dialog('destroy').remove() - }, - buttons: [ - ...actionButton, - { - text: "Отмена", - icon: "ui-icon-cancel", - click: function() { - $(this).dialog("close"); - } - } - ] - }); -} - -function delSMS(panel, currentWindow) { - let id = $('#sms-content').data('id'); - let from = $('#sms-content').data('from'); - - request('delsms', 'json', { - id: id - }).then(data => { - if (data.error) - noticer.error(data.message); - else { - noticer.success(`SMS от ${from} было удалено`); - generateListGroupSMS(panel); - currentWindow.dialog("close"); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -/************************************************************************************ - - Обработка таблицы с USSD - -************************************************************************************/ - -function loadUSSD() { - request('listussdgroups', 'text').then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); - else - generateListUSSDGroups(data); - }).catch(error => { - noticer.error(error.message); - }); -} - -function generateListUSSDGroups(data) { - if (!$(data).children().length) { - $("#tabs-ussd").html(pEmpty('USSD отсутствуют')); - return; - } - - $("#tabs-ussd").html(data); - $("#accordion-ussd").accordion({ - heightStyle: "content", - create: function( event, ui ) { - generateListGroupUSSD(ui.panel); - }, - beforeActivate: function( event, ui ) { - generateListGroupUSSD(ui.newPanel); - } - }) -} - -function generateListGroupUSSD(panel) { - if (!$("#accordion-ussd").children().length) { - noticer.warning("USSD отсутствуют"); - $("#tabs-ussd").html(pEmpty('USSD отсутствуют')); - return; - } - - request('listgroupussd', 'json', { to: panel.data("to") }).then(data => { - if (data.error) - noticer.error(data.message); - else { - ussd = data; - showListUSSD(panel); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -function showListUSSD(panel, data = ussd) { - (new divNotFoundNumbers).remove(); - let body = panel.find('.body').html(''); - $(data).each((i, j) => { - let row = $(``); - row.append(`${j.date}`); - row.append(`${j.type_comment}`); - row.append(`${j.text}`); - body.append(row); - - row.click(function() { - viewUSSD(panel, $(this).data('ussd-id'), j.type_comment); - }); - }); - - if (!body.children().length) - (new divNotFoundNumbers('Нет USSD')).push(); -} - -function viewUSSD(panel, id, type) { - request('viewussd', 'text', {id: id}).then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); - else { - showViewUSSD(data, [ - { - id: "btn-delete", - text: "Удалить", - icon: "ui-icon-trash", - click: function() { - delUSSD(panel, $(this)); - } - } - ], `USSD: ${type}`); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -function showViewUSSD(data, actionButton, title) { - let form = $(data); - - form.appendTo('body').dialog({ - title: title, - height: 'auto', - width: 'auto', - resizable: false, - modal: true, - show: { effect: "fade", duration: 500 }, - close: function(event, ui) { - $(this).dialog('destroy').remove() - }, - buttons: [ - ...actionButton, - { - text: "Отмена", - icon: "ui-icon-cancel", - click: function() { - $(this).dialog("close"); - } - } - ] - }); -} - -function delUSSD(panel, currentWindow) { - let id = $('#ussd-content').data('id'); - - request('delussd', 'json', { - id: id - }).then(data => { - if (data.error) - noticer.error(data.message); - else { - noticer.success(`USSD было удалено`); - generateListGroupUSSD(panel); - currentWindow.dialog("close"); - } - }).catch(error => { - noticer.error(error.message); - }); -} - -/************************************************************************************ - - Обработка таблицы информации о сервере - -************************************************************************************/ - -function loadServerInfo() { - request('serverinfo', 'text').then(data => { - if (isJSON(data) && JSON.parse(data).error) - noticer.error(JSON.parse(data).message); - else - showServerInfo(data); - }).catch(error => { - noticer.error(error.message); - }); -} - -function showServerInfo(data) { - $("#tabs-server").html(data); - $("#server-external-number-on").checkboxradio(); - $("#server-transparent-mode").checkboxradio(); - $("#server-button").button({ icon: "ui-icon-disk", disabled: true }); - - $(".server-input").on("change paste cut keydown", () => { - if ($("#server-button").button( "option", "disabled")) { - noticer.warning('Некоторые параметры сервера были изменены'); - $("#server-button").button( "option", "disabled", false); - } - }); - - $("#server-button").click(() => { - writeServerInfo(); - }); -} - -function writeServerInfo() { - let pattern_number = /^\+7\d{10}$/g; - - let internal_number = $("#server-internal-number").val(); - let external_number = $("#server-external-number").val(); - let external_number_on = $("#server-external-number-on").is(":checked"); - let transparent_mode = $("#server-transparent-mode").is(":checked"); - - let error = false; - - if (external_number.match(pattern_number) === null) { noticer.warning("Внешний номер не соответствует формату +7XXXXXXXXXX"); error = true; } - - if (error) return; - - request('writeserverinfo', 'json', { - internal_number: internal_number, - external_number: external_number, - external_number_on: external_number_on, - transparent_mode: transparent_mode - }).then(data => { - data.error ? - noticer.error(data.message) : - $("#server-button").button( "option", "disabled", true) && noticer.success("Параметры сервера были сохранены") - }).catch(error => { - noticer.error(error.message); + message.error(error.message); }); } diff --git a/public/404.css b/public/404.css deleted file mode 100644 index 74f4081..0000000 --- a/public/404.css +++ /dev/null @@ -1,18 +0,0 @@ -body { - display: flex; - align-items: center; - justify-content: center; - height: 100vh; -} - -div.page { - display: flex; - align-items: center; -} - -.pic { - background-image: url("404.png"); - min-width: 512px; - min-height: 512px; - background-size: contain; -} diff --git a/public/authorization.css b/public/authorization.css deleted file mode 100644 index 8137a7a..0000000 --- a/public/authorization.css +++ /dev/null @@ -1,62 +0,0 @@ -@font-face { - font-family: Scada; - src: url(Scada-Regular.ttf); -} - -body { - display: flex; - align-items: center; - justify-content: center; - height: 100vh; - margin-top: -5%; - color: #333; - opacity: 0; - font-family: Scada; -} - -div.form { - display: flex; - flex-direction: column; - align-items: center; -} - -.div-button { - display: flex; - justify-content: center; - margin-top: 10px; -} - -input { - text-align: center; - color: #333; - border: 1px solid#c5c5c5; - height: 30px; -} - -input:hover { - border: 1px solid #999; - box-shadow: 1px 1px 10px 1px #ccc; -} - -.input-focus:focus { - outline: none; - box-shadow: 1px 1px 10px 1px #666; - border: 1px solid #555; -} - -.logo { - background-image: url("favicon.png"); - min-width: 128px; - min-height: 128px; - background-size: contain; - margin-bottom: 20px; -} - -.title { - margin: 30px; -} - -.label { - text-align: right; - padding-right: 10px; -} diff --git a/public/style.css b/public/style.css index 8cd066b..3f86680 100644 --- a/public/style.css +++ b/public/style.css @@ -18,16 +18,16 @@ body { div.div-header { display: flex; align-items: center; - width: 70%; + width: 60%; justify-content: center; margin-top: 30px } /* HEADER */ -div.main-button { +/* div.div-add { margin-right: 20px -} +} */ div.div-search { display: flex; @@ -49,41 +49,36 @@ input { border: 1px solid#c5c5c5; } -.input-focus:hover:not([disabled]) { - border: 1px solid #999; - box-shadow: 1px 1px 10px 1px #ccc; +.input-focus:hover { + border: 1px solid #ccc } .input-focus::placeholder { color: #333 } -.input-focus:focus:not([disabled]) { +.input-focus:focus { outline: none; - box-shadow: 1px 1px 10px 1px #666; - border: 1px solid #555; + box-shadow: 1px 1px 10px 1px #007fff; + border: 1px solid #003eff; } /* BODY */ .content { - width: 70%; + width: 60%; margin-top: 20px } -.table-content { +.content table { width: 100%; border-collapse: collapse; border-spacing: 0; table-layout: fixed; } -div.group-content { - height: 55vh; -} - div.body-rows { - height: calc(100% - 55px); + max-height: 55vh; overflow-x: auto; border: 1px solid #c5c5c5; border-top: 0; @@ -101,112 +96,12 @@ td { text-align: center; } -.body-rows td { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - .body-rows tbody tr:nth-child(even){ background: #fff; } -tr.row { - border-top: 1px solid #fff; -} - tr.row:hover, tr.row:nth-child(even):hover { - background-color: #f6f6f6; - color: #003eff; + background-color: #c5c5c5; + color: #fff; cursor: pointer; - border-bottom: 1px solid #c5c5c5; - border-top: 1px solid #c5c5c5; -} - -/* EDIT NUMBER */ - -.number-label, .sms-label, .ussd-label, .server-label { - color: #333; - text-align: right; -} - -.number-value, .server-value { - height: 30px; -} - -.server-value { - text-align: left; - padding: 2px 0 2px 10px; -} - -.server-input { - height: 100%; -} - -.server-button { - margin-top: 30px; -} - -.sms-label-text, .ussd-label-text { - vertical-align:top -} - -.sms-value, .ussd-value { - width: 300px; - text-align: left; -} - -.number-input-main { - height: 25px; - width: 194px; - margin: 0 10px 0 10px; -} - -.number-input-cc { - height: 25px; - width: 50px; - margin: 0 10px 0 10px; -} - -.div-advanced { - display: flex; - flex-direction: column; -} - -.comment { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -.comment-name { - padding: 15px 0 5px 0; -} - -.comment-content, .sms-content, .ussd-content { - width: 100%; - height: 100%; -} - -#number-comment, #sms-content, #ussd-content { - width: calc(100% - 6px); - resize: none; -} - -#sms-content, #ussd-content { - height: 150px; - outline: none; - border: 1px solid#c5c5c5; - color: #333; - width: 400px; - padding: 5px 10px 5px 10px; -} - -th.sms-content-width, td.sms-content-width, th.ussd-content-width, td.ussd-content-width { - width: 155px; -} - -th.ussd-content-width-type, td.ussd-content-width-type { - width: 240px; } diff --git a/settings.conf.sample b/settings.conf.sample index 538d199..8a98fe3 100644 --- a/settings.conf.sample +++ b/settings.conf.sample @@ -1,18 +1,14 @@ [web-host] title => "Управление диалпланом" addresses => 127.0.0.1 -http => 80 +http => 8080 https => 443 cert => certs/test.local.crt key => certs/test.local.key -data => ./ ; Путь к каталогу, в котором расположены каталоги public, jq, js, images +data => ./ ; Путь к каталогу, в котором расположены каталоги public, js, images loglevel => 0 ; 0 - debug, 1 - crit, 2 - err, 3 - warn, 4 - notice, 5 - info, 6 - alert logoutput => 1, 4 ; 1 - syslog, 2 - stout, 4 - file => example: 1,2 or 1,2,4 -logfile => /var/log/daster.log ; if log-output set with 4 - -[auth] -login => -password => +logfile => /var/log/jaster.log ; if log-output set with 4 [daster-db] host => 127.0.0.1 diff --git a/source/daster.d b/source/daster.d index 0f4876c..7c2c52a 100644 --- a/source/daster.d +++ b/source/daster.d @@ -15,29 +15,19 @@ import std.array; import verinfo; import pgdb; import structures; -import response; -import requests.numbers; -import requests.sms; -import requests.ussd; -import requests.server; -import requests.authorization; +import requests.listsgroups; +import requests.groupnumbers; static ServerInfo serverInfo; -static AuthData serverAuthData; private void showVersion() { writefln("daster версия %s, собрано %s", getDasterVersion(), __DATE__); } -void page404(HTTPServerRequest req, HTTPServerResponse res, HTTPServerErrorInfo error) { - res.render!("404.dt", req, error); -} - int main(string[] args) { - log.level(log.INFORMATION) - .output(log.SYSLOG) - .color(true); + log.level(log.INFORMATION); + log.output(log.SYSLOG); bool flagVersion; string flagSettings; @@ -83,17 +73,15 @@ int main(string[] args) { } rc.read(flagSettings); - + rcAsteriskDB(); auto webHost = rcWebHost(); + serverInfo = ServerInfo(webHost.title); if (webHost.loglevel != -1) log.level(webHost.loglevel); if (webHost.logoutput) log.output(webHost.logoutput); if (webHost.logfile.length) log.file(webHost.logfile); - rcAsteriskDB(); - rcAuth(); - auto router = new URLRouter; router.post("/", &postReq); router.get("/", &getReq); @@ -108,14 +96,12 @@ int main(string[] args) { auto settingsHTTPS = new HTTPServerSettings; if (webHost.http) { - settingsHTTP.errorPageHandler = toDelegate(&page404); settingsHTTP.sessionStore = memorySessionStore; settingsHTTP.port = webHost.http; settingsHTTP.bindAddresses = ["::1"] ~ webHost.addresses; } if (webHost.https) { - settingsHTTPS.errorPageHandler = toDelegate(&page404); settingsHTTPS.sessionStore = memorySessionStore; settingsHTTPS.port = webHost.https; settingsHTTPS.bindAddresses = ["::1"] ~ webHost.addresses; @@ -149,15 +135,16 @@ void startWebServer(WebHost wh, HTTPServerSettings http, HTTPServerSettings http } void getReq(HTTPServerRequest req, HTTPServerResponse res) { - if (req.session) { - auto user = req.session.get!UserData("user"); - if (user.login) { - renderMainPage(req, res); - return; - } - } + // if (req.session) { + // auto user = req.session.get!UserData("userData"); + // if (user.loggedIn) { + // renderMainPage(req, res); + // return; + // } + // } - render!("authorization.dt", serverInfo)(res); + // render!("index.dt", serverInfo)(res); + renderMainPage(req, res); } void renderMainPage(HTTPServerRequest req, HTTPServerResponse res) { @@ -172,74 +159,45 @@ void postReq(HTTPServerRequest req, HTTPServerResponse res) { if (query.empty) return; - if (query != "login" && !checkAuth(req)) { - res.send( - true, - "Сессия не существует. Перезагрузите страницу" - ); - return; - } - - log.d("%s: json request %s".format(req.clientAddress.toAddressString(), jsr.to!string)); + // if (query != "authorization" && !checkAuth(req)) { + // res.send( + // true, + // "Сессия не существует. Перезагрузите страницу" + // ); + // return; + // } switch (query) { - case "login": - login(req, res, serverAuthData); + case "listsgroups": + listsgroups(req, res); break; - case "logout": - logout(req, res); - break; - case "listnumbergroups": - getListNumberGroups(req, res); - break; - case "listgroupnumbers": - getListGroupNumbers(req, res); - break; - case "viewnumber": - getViewNumber(req, res); - break; - case "addnumber": - getAddNumber(req, res); - break; - case "writenumber": - sendWriteNumber(req, res); - break; - case "updatenumber": - sendUpdateNumber(req, res); - break; - case "delnumber": - sendDelNumber(req, res); - break; - case "listsmsgroups": - getListSMSGroups(req, res); - break; - case "listgroupsms": - getListGroupSMS(req, res); - break; - case "viewsms": - getViewSMS(req, res); - break; - case "delsms": - sendDelSMS(req, res); - break; - case "listussdgroups": - getListUSSDGroups(req, res); - break; - case "listgroupussd": - getListGroupUSSD(req, res); - break; - case "viewussd": - getViewUSSD(req, res); - break; - case "delussd": - sendDelUSSD(req, res); - break; - case "serverinfo": - getServerInfo(req, res); - break; - case "writeserverinfo": - sendWriteServerInfo(req, res); + case "groupnumbers": + groupnumbers(req, res); break; + // case "authorization": + // authorization(req, res); + // break; + // case "logout": + // logout(req, res); + // break; + // case "numbers": + // numbers(req, res); + // break; + // case "add": + // addNumber(req, res); + // break; + // case "write": + // writeNumber(req, res); + // break; + // case "edit": + // editNumber(req, res); + // break; + // case "update": + // updateNumber(req, res); + // break; + // case "remove": + // removeNumber(req, res); + // break; default: res.redirect("/"); } @@ -284,7 +242,7 @@ void rcAsteriskDB() { " password=" ~ asteriskDB["password"] ); } catch (Exception e) { - log.c(e.msg); + log.c(e); exit(1); } } @@ -445,24 +403,3 @@ WebHost rcWebHost() { return wh; } - -void rcAuth() { - ConfigSection auth; - - try { - auth = rc[]["auth"]; - } catch (Exception e) { - log.c("В конфигурационном файле не верны настройки auth"); - exit(1); - } - - if (auth["login"].empty) - log.w("Логин не был установлен - auth.login"); - else - serverAuthData.login = auth["login"]; - - if (auth["password"].empty) - log.w("Пароль не был установлен - auth.password"); - else - serverAuthData.password = auth["password"]; -} diff --git a/source/data.d b/source/data.d new file mode 100644 index 0000000..b333388 --- /dev/null +++ b/source/data.d @@ -0,0 +1,67 @@ +module data; + +import pgdb; +import singlog; +import structures; + +import std.conv; + +GroupDB[] getListGroups() { + GroupDB[] groups; + try { + auto queryResult = pgsql.sql( + "select distinct + n.da_group, + g.da_comment + from da_numbers n + left join da_groups g ON g.da_name = n.da_group" + ); + foreach (row; queryResult) { + GroupDB data; + + data.name = row["da_group"]; + data.comment = row["da_comment"]; + + groups ~= data; + } + } catch (Exception e) { + log.e("Не удалось выполнить запрос к БД. " ~ e.msg); + } + + return groups; +} + +NumberDB[] getListNumbers(string group) { + NumberDB[] numbers; + try { + auto queryResult = pgsql.sql( + "select + dan.da_number, + dal.da_comment da_list, + dan.da_all_cc, + dan.da_white_cc, + dan.da_black_cc, + dan.da_comment + from da_numbers dan + left join da_lists dal on dal.da_name = dan.da_list + where da_group = ?", + group + ); + foreach (row; queryResult) { + NumberDB data; + + data.number = row["da_number"]; + data.list = row["da_list"]; + data.all_cc = row["da_all_cc"].to!int; + data.white_cc = row["da_white_cc"].to!int; + data.black_cc = row["da_black_cc"].to!int; + data.comment = row["da_comment"]; + + numbers ~= data; + } + } catch (Exception e) { + log.e("Не удалось выполнить запрос к БД. " ~ e.msg); + } + + return numbers; +} diff --git a/source/requests/authorization.d b/source/requests/authorization.d deleted file mode 100644 index 5456424..0000000 --- a/source/requests/authorization.d +++ /dev/null @@ -1,47 +0,0 @@ -module requests.authorization; - -import vibe.vibe; -import response; -import structures; -import singlog; - -void login(HTTPServerRequest req, HTTPServerResponse res, AuthData serverAuthData) { - auto userAuthData = deserializeJson!AuthData(req.json); - - if (!(serverAuthData.login == userAuthData.login && - serverAuthData.password == userAuthData.password)) { - log.i(req.clientAddress.toAddressString() ~ ": Данные авторизации не верны"); - res.send( - true, - "Данные авторизации не верны" - ); - return; - } - - auto user = UserData(true); - - req.session = res.startSession(); - req.session.set!UserData("user", user); - - log.i(req.clientAddress.toAddressString() ~ ": Вход в систему"); - - res.send(); -} - -void logout(HTTPServerRequest req, HTTPServerResponse res) { - req.session.set!UserData("user", UserData.init); - res.terminateSession(); - - log.i(req.clientAddress.toAddressString() ~ ": Выход из системы"); - - res.send(); -} - -bool checkAuth(HTTPServerRequest req) { - if (req.session) - return req.session.get!UserData("user").login; - - log.d(req.clientAddress.toAddressString() ~ ": Отсутствует авторизация"); - - return false; -} diff --git a/source/requests/groupnumbers.d b/source/requests/groupnumbers.d new file mode 100644 index 0000000..4634a38 --- /dev/null +++ b/source/requests/groupnumbers.d @@ -0,0 +1,12 @@ +module requests.groupnumbers; + +import vibe.vibe; +import response; +import data; +import singlog; + +void groupnumbers(HTTPServerRequest req, HTTPServerResponse res) { + auto jsr = req.json; + auto listNumbers = getListNumbers(jsr["group"].get!string); + render!("group-numbers-list.dt", listNumbers)(res); +} diff --git a/source/requests/listsgroups.d b/source/requests/listsgroups.d new file mode 100644 index 0000000..be1504c --- /dev/null +++ b/source/requests/listsgroups.d @@ -0,0 +1,11 @@ +module requests.listsgroups; + +import vibe.vibe; +import response; +import data; + +void listsgroups(HTTPServerRequest req, HTTPServerResponse res) { + // auto jsr = req.json; + + res.writeJsonBody(getListGroups().serializeToJson()); +} diff --git a/source/requests/numbers.d b/source/requests/numbers.d deleted file mode 100644 index 24fa4d7..0000000 --- a/source/requests/numbers.d +++ /dev/null @@ -1,113 +0,0 @@ -module requests.numbers; - -import vibe.vibe; -import response; -import structures; -import sql; -import singlog; - -import std.regex; - -// Получить список всех групп номеров -void getListNumberGroups(HTTPServerRequest req, HTTPServerResponse res) { - auto listGroups = sqlGetListGroups(); - render!("list_number_groups.dt", listGroups)(res); -} - -// Получить список номеров конкретной группы -void getListGroupNumbers(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - res.writeJsonBody(sqlGetListNumbers(jsr["group"].get!string).serializeToJson()); -} - -// Добавление номера телефона -void getAddNumber(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - bool edit = false; - NumberDB dataNumber; - dataNumber.group = jsr["group"].get!string; - auto groups = sqlGetGroups(); - auto lists = sqlGetLists(); - render!("number.dt", edit, dataNumber, groups, lists)(res); -} - -// Просмотр номера телефона -void getViewNumber(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - bool edit = true; - auto dataNumber = sqlGetDataNumber(jsr["number"].get!string); - auto groups = sqlGetGroups(); - auto lists = sqlGetLists(); - render!("number.dt", edit, dataNumber, groups, lists)(res); -} - -// Обновить номер телефона -void sendUpdateNumber(HTTPServerRequest req, HTTPServerResponse res) { - NumberDB number = deserializeJson!NumberDB(req.json); - - if (!checkNumber(number, res)) - return; - - if (!sqlUpdateNumber(number)) { - res.send(true, "Не удалось обновить номер"); - return; - } - res.send(); -} - -// Записать номер телефона -void sendWriteNumber(HTTPServerRequest req, HTTPServerResponse res) { - NumberDB number = deserializeJson!NumberDB(req.json); - - if (!checkNumber(number, res)) - return; - - if (!sqlInsertNumber(number)) { - res.send(true, "Не удалось записать номер"); - return; - } - res.send(); -} - -// Удалить номера телефона -void sendDelNumber(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - string number = jsr["number"].get!string; - - if (!number.length) { - res.send(true, "Номер не может быть пуст"); - return; - } - - if (!sqlDeleteNumber(number)) { - res.send(true, "Не удалось удалить номер"); - return; - } - - res.send(); -} - -// Проверка номера перед изменением -bool checkNumber(NumberDB number, HTTPServerResponse res) { - if (!number.number.matchFirst(regex(r"^\+7\d{10}$", "g"))) { - res.send(true, "Номер не соответствует формату +7XXXXXXXXXX"); - return false; - } - - if (number.all_cc < 0) { - res.send(true, "Общее количество звонков не может быть отрицательным"); - return false; - } - - if (number.white_cc < 0) { - res.send(true, "Белое количество звонков не может быть отрицательным"); - return false; - } - - if (number.black_cc < 0) { - res.send(true, "Черное количество звонков не может быть отрицательным"); - return false; - } - - return true; -} diff --git a/source/requests/server.d b/source/requests/server.d deleted file mode 100644 index 7b66583..0000000 --- a/source/requests/server.d +++ /dev/null @@ -1,30 +0,0 @@ -module requests.server; - -import vibe.vibe; -import response; -import structures; -import sql; -import singlog; - -import std.regex; - -// Получить информацию о сервере -void getServerInfo(HTTPServerRequest req, HTTPServerResponse res) { - auto dataServer = sqlGetServerInfo(); - render!("server.dt", dataServer)(res); -} - -void sendWriteServerInfo(HTTPServerRequest req, HTTPServerResponse res) { - ServerDB server = deserializeJson!ServerDB(req.json); - - if (!server.external_number.matchFirst(regex(r"^\+7\d{10}$", "g"))) { - res.send(true, "Внешний номер не соответствует формату +7XXXXXXXXXX"); - return; - } - - if (!sqlUpdateServerInfo(server)) { - res.send(true, "Не удалось записать параметры сервера"); - return; - } - res.send(); -} diff --git a/source/requests/sms.d b/source/requests/sms.d deleted file mode 100644 index 254793b..0000000 --- a/source/requests/sms.d +++ /dev/null @@ -1,39 +0,0 @@ -module requests.sms; - -import vibe.vibe; -import response; -import structures; -import sql; -import singlog; - -// Получить список всех групп SMS -void getListSMSGroups(HTTPServerRequest req, HTTPServerResponse res) { - auto numbers = sqlGetSMSNumbers(); - render!("list_sms_groups.dt", numbers)(res); -} - -// Получить список SMS конкретной группы -void getListGroupSMS(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - res.writeJsonBody(sqlGetListSMS(jsr["to"].get!string).serializeToJson()); -} - -// Просмотр SMS -void getViewSMS(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - auto dataSMS = sqlGetSMS(jsr["id"].to!int); - render!("sms.dt", dataSMS)(res); -} - -// Удалить SMS -void sendDelSMS(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - int idsms = jsr["id"].get!int; - - if (!sqlDeleteSMS(idsms)) { - res.send(true, "Не удалось удалить SMS"); - return; - } - - res.send(); -} diff --git a/source/requests/ussd.d b/source/requests/ussd.d deleted file mode 100644 index c39a46e..0000000 --- a/source/requests/ussd.d +++ /dev/null @@ -1,39 +0,0 @@ -module requests.ussd; - -import vibe.vibe; -import response; -import structures; -import sql; -import singlog; - -// Получить список всех групп USSD -void getListUSSDGroups(HTTPServerRequest req, HTTPServerResponse res) { - auto numbers = sqlGetUSSDNumbers(); - render!("list_ussd_groups.dt", numbers)(res); -} - -// Получить список USSD конкретной группы -void getListGroupUSSD(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - res.writeJsonBody(sqlGetListUSSD(jsr["to"].get!string).serializeToJson()); -} - -// Просмотр USSD -void getViewUSSD(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - auto dataUSSD = sqlGetUSSD(jsr["id"].to!int); - render!("ussd.dt", dataUSSD)(res); -} - -// Удалить USSD -void sendDelUSSD(HTTPServerRequest req, HTTPServerResponse res) { - auto jsr = req.json; - int idussd = jsr["id"].get!int; - - if (!sqlDeleteUSSD(idussd)) { - res.send(true, "Не удалось удалить USSD"); - return; - } - - res.send(); -} diff --git a/source/sql.d b/source/sql.d deleted file mode 100644 index a488407..0000000 --- a/source/sql.d +++ /dev/null @@ -1,454 +0,0 @@ -module sql; - -import pgdb; -import singlog; -import structures; - -import std.conv; - -/*********************************************************** - Запросы для таблицы номеров телефонов -***********************************************************/ - -GroupDB[] sqlGetListGroups() { - GroupDB[] groups; - try { - auto queryResult = pgsql.sql( - "select distinct - dan.da_group, - dag.da_comment - from da_numbers dan - left join da_groups dag ON dag.da_name = dan.da_group" - ); - foreach (row; queryResult) { - GroupDB data; - - data.name = row["da_group"]; - data.comment = row["da_comment"]; - - groups ~= data; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return groups; -} - -NumberDB[] sqlGetListNumbers(string group) { - NumberDB[] numbers; - try { - auto queryResult = pgsql.sql( - "select - dan.da_number, - dal.da_comment da_list, - dan.da_all_cc, - dan.da_white_cc, - dan.da_black_cc, - dan.da_comment - from da_numbers dan - left join da_lists dal on dal.da_name = dan.da_list - where dan.da_group = ? - order by dan.da_number", - group - ); - foreach (row; queryResult) { - NumberDB data; - - data.number = row["da_number"]; - data.list = row["da_list"]; - data.all_cc = row["da_all_cc"].to!int; - data.white_cc = row["da_white_cc"].to!int; - data.black_cc = row["da_black_cc"].to!int; - data.comment = row["da_comment"]; - - numbers ~= data; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return numbers; -} - -NumberDB sqlGetDataNumber(string number) { - NumberDB data; - try { - auto queryResult = pgsql.sql( - "select - da_number, - da_group, - da_list, - da_all_cc, - da_white_cc, - da_black_cc, - da_comment - from da_numbers - where da_number = ?", - number - ); - foreach (row; queryResult) { - data.number = row["da_number"]; - data.group = row["da_group"]; - data.list = row["da_list"]; - data.all_cc = row["da_all_cc"].to!int; - data.white_cc = row["da_white_cc"].to!int; - data.black_cc = row["da_black_cc"].to!int; - data.comment = row["da_comment"]; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return data; -} - -GroupDB[] sqlGetGroups() { - GroupDB[] groups; - try { - auto queryResult = pgsql.sql( - "select da_name, da_comment from da_groups" - ); - foreach (row; queryResult) { - GroupDB data; - - data.name = row["da_name"]; - data.comment = row["da_comment"]; - - groups ~= data; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return groups; -} - -ListDB[] sqlGetLists() { - ListDB[] lists; - try { - auto queryResult = pgsql.sql( - "select da_name, da_comment from da_lists" - ); - foreach (row; queryResult) { - ListDB data; - - data.name = row["da_name"]; - data.comment = row["da_comment"]; - - lists ~= data; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return lists; -} - -bool sqlUpdateNumber(NumberDB number) { - try { - pgsql.sql( - "update da_numbers set - da_group = ?, - da_list = ?, - da_all_cc = ?, - da_white_cc = ?, - da_black_cc = ?, - da_comment = ? - where da_number = ?", - number.group, - number.list, - number.all_cc, - number.white_cc, - number.black_cc, - number.comment, - number.number - ); - } catch (Exception e) { - log.e("Ошибка обновления номера в БД. " ~ e.msg); - return false; - } - return true; -} - -bool sqlDeleteNumber(string number) { - try { - pgsql.sql( - "delete from da_numbers where da_number = ?", number - ); - } catch (Exception e) { - log.e("Ошибка удаления номера в БД. " ~ e.msg); - return false; - } - return true; -} - -bool sqlInsertNumber(NumberDB number) { - try { - pgsql.sql( - "insert into da_numbers - (da_number, da_group, da_list, da_all_cc, da_white_cc, da_black_cc, da_comment) - values - (?, ?, ?, ?, ?, ?, ?)", - number.number, - number.group, - number.list, - number.all_cc, - number.white_cc, - number.black_cc, - number.comment - ); - } catch (Exception e) { - log.error("Ошибка добавления номера телефона в БД. " ~ e.msg); - return false; - } - return true; -} - -/*********************************************************** - Запросы для таблицы SMS -***********************************************************/ - -SMSDB[] sqlGetSMSNumbers() { - SMSDB[] numbers; - try { - auto queryResult = pgsql.sql( - "select distinct da_to from da_sms" - ); - foreach (row; queryResult) { - SMSDB data; - - data.to = row["da_to"]; - - numbers ~= data; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return numbers; -} - -SMSDB[] sqlGetListSMS(string to) { - SMSDB[] sms; - try { - auto queryResult = pgsql.sql( - "select - da_id, - to_char(da_date, 'YYYY.MM.DD HH24:MI:SS') da_date, - da_to, - da_from, - da_text - from da_sms - where da_to = ? - order by da_date desc", - to - ); - foreach (row; queryResult) { - SMSDB data; - - data.id = row["da_id"].to!int; - data.date = row["da_date"]; - data.to = row["da_to"]; - data.from = row["da_from"]; - data.text = row["da_text"]; - - sms ~= data; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return sms; -} - -SMSDB sqlGetSMS(int idsms) { - SMSDB data; - try { - auto queryResult = pgsql.sql( - "select - da_id, - to_char(da_date, 'YYYY.MM.DD HH24:MI:SS') da_date, - da_to, - da_from, - da_text - from da_sms - where da_id = ?", - idsms - ); - foreach (row; queryResult) { - data.id = row["da_id"].to!int; - data.date = row["da_date"]; - data.to = row["da_to"]; - data.from = row["da_from"]; - data.text = row["da_text"]; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return data; -} - -bool sqlDeleteSMS(int idsms) { - try { - pgsql.sql( - "delete from da_sms where da_id = ?", idsms - ); - } catch (Exception e) { - log.e("Ошибка удаления SMS в БД. " ~ e.msg); - return false; - } - return true; -} - -/*********************************************************** - Запросы для таблицы USSD -***********************************************************/ - -USSDDB[] sqlGetUSSDNumbers() { - USSDDB[] numbers; - try { - auto queryResult = pgsql.sql( - "select distinct da_to from da_ussd" - ); - foreach (row; queryResult) { - USSDDB data; - - data.to = row["da_to"]; - - numbers ~= data; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return numbers; -} - -USSDDB[] sqlGetListUSSD(string to) { - USSDDB[] ussd; - try { - auto queryResult = pgsql.sql( - "select - dau.da_id, - to_char(dau.da_date, 'YYYY.MM.DD HH24:MI:SS') da_date, - dau.da_to, - dau.da_type, - daut.da_comment da_type_comment, - dau.da_text - from da_ussd dau - inner join da_ussd_type daut - on dau.da_type = daut.da_id - where dau.da_to = ? - order by dau.da_date desc", - to - ); - foreach (row; queryResult) { - USSDDB data; - - data.id = row["da_id"].to!int; - data.date = row["da_date"]; - data.to = row["da_to"]; - data.type = row["da_type"].to!int; - data.type_comment = row["da_type_comment"]; - data.text = row["da_text"]; - - ussd ~= data; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return ussd; -} - -USSDDB sqlGetUSSD(int idussd) { - USSDDB data; - try { - auto queryResult = pgsql.sql( - "select - da_id, - to_char(da_date, 'YYYY.MM.DD HH24:MI:SS') da_date, - da_to, - da_type, - da_text - from da_ussd - where da_id = ?", - idussd - ); - foreach (row; queryResult) { - data.id = row["da_id"].to!int; - data.date = row["da_date"]; - data.to = row["da_to"]; - data.type = row["da_type"].to!int; - data.text = row["da_text"]; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return data; -} - -bool sqlDeleteUSSD(int idussd) { - try { - pgsql.sql( - "delete from da_ussd where da_id = ?", idussd - ); - } catch (Exception e) { - log.e("Ошибка удаления USSD в БД. " ~ e.msg); - return false; - } - return true; -} - -/*********************************************************** - Запросы для таблицы информации о сервере -***********************************************************/ - -ServerDB sqlGetServerInfo() { - ServerDB server; - try { - auto queryResult = pgsql.sql( - "select - case when da_transparent_mode then 1 else 0 end da_transparent_mode, - da_internal_number, - da_external_number, - case when da_external_number_on then 1 else 0 end da_external_number_on - from da_server - where da_id = 1" - ); - foreach (row; queryResult) { - server.transparent_mode = row["da_transparent_mode"].to!int.to!bool; - server.internal_number = row["da_internal_number"]; - server.external_number = row["da_external_number"]; - server.external_number_on = row["da_external_number_on"].to!int.to!bool; - } - } catch (Exception e) { - log.e("Не удалось выполнить запрос к БД. " ~ e.msg); - } - - return server; -} - -bool sqlUpdateServerInfo(ServerDB server) { - try { - pgsql.sql( - "update da_server set - da_transparent_mode = ?, - da_internal_number = ?, - da_external_number = ?, - da_external_number_on = ? - where da_id = 1", - server.transparent_mode, - server.internal_number, - server.external_number, - server.external_number_on - ); - } catch (Exception e) { - log.e("Ошибка обновления параметров сервера в БД. " ~ e.msg); - return false; - } - return true; -} diff --git a/source/structures.d b/source/structures.d index b38058d..1f04a77 100644 --- a/source/structures.d +++ b/source/structures.d @@ -4,15 +4,6 @@ struct ServerInfo { string name; } -struct AuthData { - string login; - string password; -} - -struct UserData { - bool login = false; -} - struct WebHost { string[] addresses; ushort http = 0; @@ -31,11 +22,6 @@ struct GroupDB { string comment; } -struct ListDB { - string name; - string comment; -} - struct NumberDB { string number; string group; @@ -45,27 +31,3 @@ struct NumberDB { int black_cc; string comment; } - -struct SMSDB { - int id; - string date; - string to; - string from; - string text; -} - -struct USSDDB { - int id; - string date; - string to; - int type; - string type_comment; - string text; -} - -struct ServerDB { - bool transparent_mode; - string internal_number; - string external_number; - bool external_number_on; -} diff --git a/source/version_.d b/source/version_.d index fa80cc9..ea9a3a6 100644 --- a/source/version_.d +++ b/source/version_.d @@ -1,3 +1,3 @@ module version_; -enum dasterVersion = "v0.1.0-beta.1"; +enum dasterVersion = "v0.0.1"; diff --git a/views/404.dt b/views/404.dt deleted file mode 100644 index 0d4d34b..0000000 --- a/views/404.dt +++ /dev/null @@ -1,8 +0,0 @@ -doctype html -head - title Страница не найдена - link(rel='icon', type='image/png', sizes='128x128', href='favicon.png') - link(rel='stylesheet', type='text/css', href='404.css') -body - div.page - div.pic diff --git a/views/authorization.dt b/views/authorization.dt deleted file mode 100644 index 6eb8540..0000000 --- a/views/authorization.dt +++ /dev/null @@ -1,26 +0,0 @@ -doctype html -head - title #{serverInfo.name}: авторизация - link(rel='icon', type='image/png', sizes='128x128', href='favicon.png') - link(rel='stylesheet', type='text/css', href='jquery-ui.min.css') - link(rel='stylesheet', type='text/css', href='authorization.css') - script(src='jquery-3.7.0.min.js') - script(src='jquery-ui.min.js') - script(src='noticer.min.js') - script(src='authorization.js') -body - div.form - div.logo - div.title #{serverInfo.name} - table - tbody - tr - td.label Логин: - td - input.input-focus#login(type='text') - tr - td.label Пароль: - td - input.input-focus#password(type='password') - div.div-button - button#authorization Войти diff --git a/views/group-numbers-list.dt b/views/group-numbers-list.dt new file mode 100644 index 0000000..46d56eb --- /dev/null +++ b/views/group-numbers-list.dt @@ -0,0 +1,22 @@ +- import structures; + +table + thead.head + tr + th Номер + th Список + th Общие звонки + th Белые звонки + th Черные звонки + th Комментарий +div.body-rows + table + tbody.body + - foreach (number; listNumbers) + tr.row + td #{number.number} + td #{number.list} + td #{number.all_cc} + td #{number.white_cc} + td #{number.black_cc} + td #{number.comment} diff --git a/views/index.dt b/views/index.dt index 60cf645..69887bd 100644 --- a/views/index.dt +++ b/views/index.dt @@ -6,21 +6,19 @@ head link(rel='stylesheet', type='text/css', href='style.css') script(src='jquery-3.7.0.min.js') script(src='jquery-ui.min.js') - script(src='noticer.min.js') + script(src='message.js') script(src='script.js') body div.div-header - div.div-add.main-button - button#add-number Добавить номер - div.div-search.main-button - input.input-focus#search(name='search', type='text', value='', placeholder='Найти номер') - div.div-update-tab.main-button - button#update-tab Перезагрузить - div.div-update-tab.main-button - button#update-group Обновить - div.div-user - div.div-logout - button#logout Выход + // div.div-add + // button.addNumber Добавить номер + div.div-search + input.input-focus.search(name='search', type='text', value='', placeholder='Найти номер') + // div.div-user Вы вошли как #{user.name} + div.div-user Вы вошли как Александр + div.div-button + button Выход + // button(onclick='logout()') Выход div.content div#tabs ul @@ -34,5 +32,8 @@ body a(href='#tabs-server') Сервер div#tabs-numbers div#tabs-sms + p Список SMS сообщений div#tabs-ussd + p Список результатов USSD запросов div#tabs-server + p Информация о сервере diff --git a/views/list_number_groups.dt b/views/list_number_groups.dt deleted file mode 100644 index 9a907a8..0000000 --- a/views/list_number_groups.dt +++ /dev/null @@ -1,16 +0,0 @@ -div#accordion-numbers - - foreach (group; listGroups) - h3 #{group.comment} - div.group-content(data-group-name='#{group.name}') - table.table-content - thead.head - tr - th Номер - th Список - th Общие звонки - th Белые звонки - th Черные звонки - th Комментарий - div.body-rows - table.table-content - tbody.body diff --git a/views/list_sms_groups.dt b/views/list_sms_groups.dt deleted file mode 100644 index c4f7270..0000000 --- a/views/list_sms_groups.dt +++ /dev/null @@ -1,13 +0,0 @@ -div#accordion-sms - - foreach (number; numbers) - h3 На номер #{number.to} - div.group-content(data-to='#{number.to}') - table.table-content - thead.head - tr - th.sms-content-width Дата - th.sms-content-width От кого - th Текст сообщения - div.body-rows - table.table-content - tbody.body diff --git a/views/list_ussd_groups.dt b/views/list_ussd_groups.dt deleted file mode 100644 index 4cd5b44..0000000 --- a/views/list_ussd_groups.dt +++ /dev/null @@ -1,13 +0,0 @@ -div#accordion-ussd - - foreach (number; numbers) - h3 На номер #{number.to} - div.group-content(data-to='#{number.to}') - table.table-content - thead.head - tr - th.ussd-content-width Дата - th.ussd-content-width-type Тип - th Текст сообщения - div.body-rows - table.table-content - tbody.body diff --git a/views/number.dt b/views/number.dt deleted file mode 100644 index 36efe5e..0000000 --- a/views/number.dt +++ /dev/null @@ -1,42 +0,0 @@ -div#number-data - table - tbody - tr - td.number-label Номер: - td.number-value - - if (edit) - input.number-input-main.input-focus#number-number(type='text', value='#{dataNumber.number}', disabled) - - else - input.number-input-main.input-focus#number-number(type='text', value='#{dataNumber.number}') - td.number-label Общие звонки: - td.number-value - input.number-input-cc.input-focus#number-all-cc(type='text', value='#{dataNumber.all_cc}') - tr - td.number-label Группа: - td.number-value - select#number-group - - foreach (group; groups) - - if (dataNumber.group == group.name) - option(selected, value='#{group.name}') #{group.comment} - - else - option(value='#{group.name}') #{group.comment} - td.number-label Белые звонки: - td.number-value - input.number-input-cc.input-focus#number-white-cc(type='text', value='#{dataNumber.white_cc}') - tr - td.number-label Список: - td.number-value - select#number-list - - foreach (list; lists) - - if (dataNumber.list == list.name) - option(selected, value='#{list.name}') #{list.comment} - - else - option(value='#{list.name}') #{list.comment} - td.number-label Черные звонки: - td.number-value - input.number-input-cc.input-focus#number-black-cc(type='text', value='#{dataNumber.black_cc}') - div.div-advanced - div.comment - div.comment-name Комментарий - div.comment-content - textarea.input-focus#number-comment #{dataNumber.comment} diff --git a/views/server.dt b/views/server.dt deleted file mode 100644 index f17ecaf..0000000 --- a/views/server.dt +++ /dev/null @@ -1,23 +0,0 @@ -div#server-data - table - tbody - tr - td.server-label Внутренний номер: - td.server-value - input.input-focus.server-input#server-internal-number(type="text", value="#{dataServer.internal_number}") - td.server-value - tr - td.server-label Внешний номер: - td.server-value - input.input-focus.server-input#server-external-number(type="text", value="#{dataServer.external_number}") - td.server-value - label(for="server-external-number-on") Использовать - input.server-input#server-external-number-on(name="server-external-number-on", type="checkbox", checked="#{dataServer.external_number_on}") - tr - td.server-label Прозрачный режим: - td.server-value - label(for="server-transparent-mode") Включен - input.server-input#server-transparent-mode(name="server-transparent-mode", type="checkbox", checked="#{dataServer.transparent_mode}") - td.server-value -div.server-button - button#server-button Сохранить изменения diff --git a/views/sms.dt b/views/sms.dt deleted file mode 100644 index bc57579..0000000 --- a/views/sms.dt +++ /dev/null @@ -1,11 +0,0 @@ -div#sms-data - table - tbody - tr - td.sms-label Дата: - td.sms-value #{dataSMS.date} - tr - td.sms-label.sms-label-text Текст: - td.sms-value - div.sms-content - textarea#sms-content(readonly, data-id="#{dataSMS.id}", data-from="#{dataSMS.from}") #{dataSMS.text} diff --git a/views/ussd.dt b/views/ussd.dt deleted file mode 100644 index 8e80a4b..0000000 --- a/views/ussd.dt +++ /dev/null @@ -1,11 +0,0 @@ -div#ussd-data - table - tbody - tr - td.ussd-label Дата: - td.ussd-value #{dataUSSD.date} - tr - td.ussd-label.ussd-label-text Текст: - td.ussd-value - div.ussd-content - textarea#ussd-content(readonly, data-id="#{dataUSSD.id}") #{dataUSSD.text}