v0.0.1
Разработка: - БД скрипт с начальными данными - вывод списка номеров телефонов по группам
|
@ -1 +1,20 @@
|
|||
/database/volumes-data
|
||||
.dub
|
||||
docs.json
|
||||
__dummy.html
|
||||
docs/
|
||||
/web
|
||||
web.so
|
||||
web.dylib
|
||||
web.dll
|
||||
web.a
|
||||
web.lib
|
||||
web-test-*
|
||||
*.exe
|
||||
*.o
|
||||
*.obj
|
||||
*.lst
|
||||
bin
|
||||
web.log
|
||||
settings.conf
|
||||
.vscode
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
WwU=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,51 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -9,9 +9,15 @@ services:
|
|||
POSTGRES_PASSWORD: asterisk
|
||||
PGTZ: Europe/Moscow
|
||||
TZ: Europe/Moscow
|
||||
networks:
|
||||
- db_net
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- ./volumes-data:/var/lib/postgresql/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
networks:
|
||||
db_net:
|
||||
name: db_net
|
||||
|
|
|
@ -1,62 +1,62 @@
|
|||
create table if not exists "groups" (
|
||||
"name" varchar(20) not null,
|
||||
"comment" varchar(100) default null,
|
||||
constraint groups_pk primary key ("name")
|
||||
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)
|
||||
);
|
||||
|
||||
insert into "groups" ("name", "comment")
|
||||
insert into da_groups (da_name, da_comment)
|
||||
values
|
||||
('general', 'Общие контакты'),
|
||||
('work', 'Рабочие контакты'),
|
||||
('personal', 'Личные контакты');
|
||||
|
||||
create table if not exists lists (
|
||||
"name" varchar(20) not null,
|
||||
"comment" varchar(100) default null,
|
||||
constraint lists_pk primary key ("name")
|
||||
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)
|
||||
);
|
||||
|
||||
insert into lists ("name", "comment")
|
||||
insert into da_lists (da_name, da_comment)
|
||||
values
|
||||
('general', 'Общий список'),
|
||||
('whitelist', 'Белый список'),
|
||||
('blacklist', 'Черный список');
|
||||
('general', 'Общий'),
|
||||
('whitelist', 'Белый'),
|
||||
('blacklist', 'Черный');
|
||||
|
||||
create table if not exists numbers (
|
||||
"number" varchar(12) not null,
|
||||
"group" varchar(20) not null default 'general',
|
||||
list varchar(20) not null default 'general',
|
||||
all_cc int not null default 0,
|
||||
white_cc int not null default 0,
|
||||
black_cc int not null default 0,
|
||||
"comment" varchar(100) default null,
|
||||
constraint numbers_pk primary key ("number"),
|
||||
foreign key ("group") references "groups" ("name") on delete set null on update cascade,
|
||||
foreign key (list) references lists ("name") on delete set null on update cascade
|
||||
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
|
||||
);
|
||||
|
||||
create table if not exists sms (
|
||||
id bigserial not null,
|
||||
"date" timestamp not null default NOW(),
|
||||
"to" varchar(12) not null,
|
||||
"from" varchar(12) not null,
|
||||
"text" text not null,
|
||||
constraint sms_pk primary key (id)
|
||||
create table if not exists da_sms (
|
||||
da_id bigserial not null,
|
||||
da_date timestamp not null default NOW(),
|
||||
da_to varchar(12) not null,
|
||||
da_from varchar(12) not null,
|
||||
da_text text not null,
|
||||
constraint da_sms_pk primary key (da_id)
|
||||
);
|
||||
|
||||
create table if not exists ussd (
|
||||
id bigserial not null,
|
||||
"date" timestamp not null default NOW(),
|
||||
"to" varchar(12) not null,
|
||||
"type" smallint not null,
|
||||
"text" text not null,
|
||||
constraint ussd_pk primary key (id)
|
||||
create table if not exists da_ussd (
|
||||
da_id bigserial not null,
|
||||
da_date timestamp not null default NOW(),
|
||||
da_to varchar(12) not null,
|
||||
da_type smallint not null,
|
||||
da_text text not null,
|
||||
constraint da_ussd_pk primary key (da_id)
|
||||
);
|
||||
|
||||
create table if not exists "server" (
|
||||
address varchar(50) not null,
|
||||
transparent_mode bool not null default false,
|
||||
internal_number varchar(12) not null,
|
||||
external_number varchar(12) not null,
|
||||
constraint server_pk primary key (address)
|
||||
create table if not exists da_server (
|
||||
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,
|
||||
constraint da_server_pk primary key (da_address)
|
||||
);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"authors": [
|
||||
"Alexander Zhirov"
|
||||
],
|
||||
"copyright": "Copyright © 2023, Alexander Zhirov",
|
||||
"dependencies": {
|
||||
"vibe-d": "~>0.9",
|
||||
"ldap": "~>0.4",
|
||||
"singlog": "~>0.3.1",
|
||||
"arsd-official:postgres": "~>10.9.10",
|
||||
"readconf": "~>0.3.1"
|
||||
},
|
||||
"buildTypes": {
|
||||
"debug": {
|
||||
"buildOptions": [
|
||||
"debugMode",
|
||||
"debugInfo"
|
||||
]
|
||||
},
|
||||
"release": {
|
||||
"buildOptions": [
|
||||
"releaseMode",
|
||||
"inline",
|
||||
"optimize"
|
||||
]
|
||||
}
|
||||
},
|
||||
"description": "Dialplan Asterisk - веб-сервер для управления обработкой вызовов Asterisk",
|
||||
"license": "proprietary",
|
||||
"name": "daster",
|
||||
"targetPath": "bin",
|
||||
"targetType": "executable"
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"fileVersion": 1,
|
||||
"versions": {
|
||||
"arsd-official": "10.9.10",
|
||||
"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.3.1",
|
||||
"silly": "1.1.1",
|
||||
"singlog": "0.3.1",
|
||||
"stdx-allocator": "2.77.5",
|
||||
"taggedalgebraic": "0.11.22",
|
||||
"vibe-core": "2.2.0",
|
||||
"vibe-d": "0.9.6"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"defaultArchitecture": "x86_64",
|
||||
"defaultCompiler": "ldc2"
|
||||
}
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 6.4 KiB |
|
@ -0,0 +1,100 @@
|
|||
class Message {
|
||||
timer;
|
||||
|
||||
constructor() {
|
||||
this.div = $('<div id="div-message"></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 = $(`<div class="message">${message}</div>`);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
$(document).ready(function () {
|
||||
message = new Message;
|
||||
|
||||
// (new divNotFoundNumbers).push("Загрузка...");
|
||||
|
||||
$("button").button();
|
||||
$("#tabs").tabs();
|
||||
// $("#accordion-numbers").accordion();
|
||||
|
||||
// $(".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 = {}) {
|
||||
let response = await fetch('.', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...queryData,
|
||||
query: query
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok)
|
||||
throw new Error(`Произошла неизвестаня ошибка: ${response.status}`);
|
||||
|
||||
const data = await response[type]();
|
||||
return data;
|
||||
}
|
||||
|
||||
function isJSON(str) {
|
||||
try {
|
||||
return (JSON.parse(str) && !!str);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function loadData() {
|
||||
request('listsgroups', 'json').then(data => {
|
||||
data.error ? message.error(data.message) : generateListsGroups(data);
|
||||
}).catch(error => {
|
||||
message.error(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function generateListsGroups(data) {
|
||||
let numbers = $("#tabs-numbers");
|
||||
let group = $('<div id="accordion-numbers"></div>');
|
||||
$(data).each((i, j) => {
|
||||
group.append(`<h3>${j.comment}</h3><div class="group-content" data-group-name="${j.name}"></div>`);
|
||||
});
|
||||
numbers.append(group);
|
||||
$("#accordion-numbers").accordion({
|
||||
heightStyle: "content",
|
||||
create: function( event, ui ) {
|
||||
generateGroupNumbers(ui.panel);
|
||||
},
|
||||
beforeActivate: function( event, ui ) {
|
||||
generateGroupNumbers(ui.newPanel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function generateGroupNumbers(panel) {
|
||||
request('groupnumbers', 'text', { group: panel.data("group-name") }).then(data => {
|
||||
if (isJSON(data) && JSON.parse(data).error)
|
||||
message.error(JSON.parse(data).message);
|
||||
else {
|
||||
panel.html(data);
|
||||
}
|
||||
}).catch(error => {
|
||||
message.error(error.message);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
@font-face {
|
||||
font-family: Scada;
|
||||
src: url(Scada-Regular.ttf);
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
flex-direction: column;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
font-family: Scada;
|
||||
}
|
||||
|
||||
div.div-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 60%;
|
||||
justify-content: center;
|
||||
margin-top: 30px
|
||||
}
|
||||
|
||||
/* HEADER */
|
||||
|
||||
/* div.div-add {
|
||||
margin-right: 20px
|
||||
} */
|
||||
|
||||
div.div-search {
|
||||
display: flex;
|
||||
height: 100%
|
||||
}
|
||||
|
||||
div.div-user {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
input {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.input-focus {
|
||||
border: 1px solid#c5c5c5;
|
||||
}
|
||||
|
||||
.input-focus:hover {
|
||||
border: 1px solid #ccc
|
||||
}
|
||||
|
||||
.input-focus::placeholder {
|
||||
color: #333
|
||||
}
|
||||
|
||||
.input-focus:focus {
|
||||
outline: none;
|
||||
box-shadow: 1px 1px 10px 1px #007fff;
|
||||
border: 1px solid #003eff;
|
||||
}
|
||||
|
||||
/* BODY */
|
||||
|
||||
.content {
|
||||
width: 60%;
|
||||
margin-top: 20px
|
||||
}
|
||||
|
||||
.content table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
div.body-rows {
|
||||
max-height: 55vh;
|
||||
overflow-x: auto;
|
||||
border: 1px solid #c5c5c5;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
th {
|
||||
color: #333;
|
||||
height: 50px;
|
||||
background-color: #f6f6f6;
|
||||
border: 1px solid #c5c5c5;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.body-rows tbody tr:nth-child(even){
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
tr.row:hover, tr.row:nth-child(even):hover {
|
||||
background-color: #c5c5c5;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
[web-host]
|
||||
title => "Управление диалпланом"
|
||||
addresses => 127.0.0.1
|
||||
http => 8080
|
||||
https => 443
|
||||
cert => certs/test.local.crt
|
||||
key => certs/test.local.key
|
||||
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/jaster.log ; if log-output set with 4
|
||||
|
||||
[daster-db]
|
||||
host => 127.0.0.1
|
||||
port => 5432
|
||||
dbname => daster
|
||||
user => daster
|
||||
password => daster
|
|
@ -0,0 +1,405 @@
|
|||
module daster;
|
||||
|
||||
import vibe.vibe;
|
||||
import singlog;
|
||||
import readconf;
|
||||
|
||||
import core.stdc.stdlib : exit, EXIT_SUCCESS, EXIT_FAILURE;
|
||||
import std.stdio: writefln;
|
||||
import std.getopt;
|
||||
import std.file;
|
||||
import std.path;
|
||||
import std.algorithm;
|
||||
import std.array;
|
||||
|
||||
import verinfo;
|
||||
import pgdb;
|
||||
import structures;
|
||||
|
||||
import requests.listsgroups;
|
||||
import requests.groupnumbers;
|
||||
|
||||
static ServerInfo serverInfo;
|
||||
|
||||
private void showVersion() {
|
||||
writefln("daster версия %s, собрано %s", getDasterVersion(), __DATE__);
|
||||
}
|
||||
|
||||
int main(string[] args) {
|
||||
log.level(log.INFORMATION);
|
||||
log.output(log.SYSLOG);
|
||||
|
||||
bool flagVersion;
|
||||
string flagSettings;
|
||||
|
||||
try {
|
||||
auto opt = getopt(
|
||||
args,
|
||||
config.bundling,
|
||||
config.caseSensitive,
|
||||
"settings|s",
|
||||
"<файл> Путь к файлу конфигурации settings.conf",
|
||||
&flagSettings,
|
||||
"version|v",
|
||||
"Текущая версия программы",
|
||||
&flagVersion
|
||||
);
|
||||
if (opt.helpWanted) {
|
||||
showVersion();
|
||||
defaultGetoptPrinter(
|
||||
"Использование: daster [ОПЦИИ]...\n",
|
||||
opt.options
|
||||
);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (flagVersion) {
|
||||
showVersion();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
} catch (GetOptException e) {
|
||||
showVersion();
|
||||
log.c(e.msg);
|
||||
log.i("Попробуйте 'daster -h' для дополнительной информации");
|
||||
log.i("https://git.zhirov.kz/alexander/daster");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!flagSettings.length)
|
||||
flagSettings = "./settings.conf";
|
||||
|
||||
if (!flagSettings.exists) {
|
||||
log.c("Файл конфигурации не найден: " ~ flagSettings);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
auto router = new URLRouter;
|
||||
router.post("/", &postReq);
|
||||
router.get("/", &getReq);
|
||||
router.get("*", serveStaticFiles(buildPath(webHost.data, "public")));
|
||||
router.get("*", serveStaticFiles(buildPath(webHost.data, "images")));
|
||||
router.get("*", serveStaticFiles(buildPath(webHost.data, "js")));
|
||||
router.get("*", serveStaticFiles(buildPath(webHost.data, "jq")));
|
||||
|
||||
auto memorySessionStore = new MemorySessionStore;
|
||||
|
||||
auto settingsHTTP = new HTTPServerSettings;
|
||||
auto settingsHTTPS = new HTTPServerSettings;
|
||||
|
||||
if (webHost.http) {
|
||||
settingsHTTP.sessionStore = memorySessionStore;
|
||||
settingsHTTP.port = webHost.http;
|
||||
settingsHTTP.bindAddresses = ["::1"] ~ webHost.addresses;
|
||||
}
|
||||
|
||||
if (webHost.https) {
|
||||
settingsHTTPS.sessionStore = memorySessionStore;
|
||||
settingsHTTPS.port = webHost.https;
|
||||
settingsHTTPS.bindAddresses = ["::1"] ~ webHost.addresses;
|
||||
settingsHTTPS.tlsContext = createTLSContext(TLSContextKind.server);
|
||||
settingsHTTPS.tlsContext.useCertificateChainFile(webHost.cert);
|
||||
settingsHTTPS.tlsContext.usePrivateKeyFile(webHost.key);
|
||||
}
|
||||
|
||||
startWebServer(webHost, settingsHTTP, settingsHTTPS, router);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void startWebServer(WebHost wh, HTTPServerSettings http, HTTPServerSettings https, URLRouter router)
|
||||
{
|
||||
if (wh.http && wh.https) {
|
||||
auto listenerHTTP = listenHTTP(http, router);
|
||||
auto listenerHTTPS = listenHTTP(https, router);
|
||||
scope (exit) { listenerHTTP.stopListening(); }
|
||||
scope (exit) { listenerHTTPS.stopListening(); }
|
||||
runApplication();
|
||||
} else if (wh.http) {
|
||||
auto listenerHTTP = listenHTTP(http, router);
|
||||
scope (exit) { listenerHTTP.stopListening(); }
|
||||
runApplication();
|
||||
} else if (wh.https) {
|
||||
auto listenerHTTPS = listenHTTP(https, router);
|
||||
scope (exit) { listenerHTTPS.stopListening(); }
|
||||
runApplication();
|
||||
}
|
||||
}
|
||||
|
||||
void getReq(HTTPServerRequest req, HTTPServerResponse res) {
|
||||
// if (req.session) {
|
||||
// auto user = req.session.get!UserData("userData");
|
||||
// if (user.loggedIn) {
|
||||
// renderMainPage(req, res);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// render!("index.dt", serverInfo)(res);
|
||||
renderMainPage(req, res);
|
||||
}
|
||||
|
||||
void renderMainPage(HTTPServerRequest req, HTTPServerResponse res) {
|
||||
render!("index.dt", serverInfo)(res);
|
||||
}
|
||||
|
||||
void postReq(HTTPServerRequest req, HTTPServerResponse res) {
|
||||
if (req.method != HTTPMethod.POST) return;
|
||||
|
||||
auto jsr = req.json;
|
||||
string query = jsr["query"].get!string;
|
||||
|
||||
if (query.empty) return;
|
||||
|
||||
// if (query != "authorization" && !checkAuth(req)) {
|
||||
// res.send(
|
||||
// true,
|
||||
// "Сессия не существует. Перезагрузите страницу"
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
|
||||
switch (query) {
|
||||
case "listsgroups":
|
||||
listsgroups(req, res);
|
||||
break;
|
||||
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("/");
|
||||
}
|
||||
}
|
||||
|
||||
void rcAsteriskDB() {
|
||||
ConfigSection asteriskDB;
|
||||
|
||||
try {
|
||||
asteriskDB = rc[]["daster-db"];
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки daster-db");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (asteriskDB["host"].empty) {
|
||||
log.c("В конфигурационном файле не верны настройки daster-db.host");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (asteriskDB["port"].empty) {
|
||||
log.c("В конфигурационном файле не верны настройки daster-db.port");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (asteriskDB["dbname"].empty) {
|
||||
log.c("В конфигурационном файле не верны настройки daster-db.dbname");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (asteriskDB["user"].empty) {
|
||||
log.c("В конфигурационном файле не верны настройки daster-db.user");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
pgsql(
|
||||
"hostaddr=" ~ asteriskDB["host"] ~
|
||||
" port=" ~ asteriskDB["port"] ~
|
||||
" dbname=" ~ asteriskDB["dbname"] ~
|
||||
" user=" ~ asteriskDB["user"] ~
|
||||
" password=" ~ asteriskDB["password"]
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.c(e);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
WebHost rcWebHost() {
|
||||
WebHost wh;
|
||||
ConfigSection webHost;
|
||||
|
||||
try {
|
||||
webHost = rc[]["web-host"];
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (webHost["addresses"].empty) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.addresses");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
wh.addresses = webHost["addresses"].to!string.split(',').map!(a => a.strip).array;
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.addresses");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (webHost["http"].empty && webHost["https"].empty) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.[http|https]:
|
||||
должен быть указан хотя бы один протокол");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!webHost["http"].empty) {
|
||||
try {
|
||||
wh.http = webHost["http"].to!ushort;
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.http");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!webHost["https"].empty) {
|
||||
try {
|
||||
wh.https = webHost["https"].to!ushort;
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.https");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!webHost["https"].empty) {
|
||||
if (webHost["cert"].empty || webHost["key"].empty) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.[cert|key]:
|
||||
необходимо указать сертификат и ключ для использования https протокола"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
wh.cert = webHost["cert"];
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.cert");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
wh.key = webHost["key"];
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.key");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!webHost["data"].empty) {
|
||||
string data;
|
||||
|
||||
try {
|
||||
data = webHost["data"];
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.data");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (data.exists) {
|
||||
if (!buildPath(data, "public").exists) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: public");
|
||||
exit(1);
|
||||
}
|
||||
if (!buildPath(data, "js").exists) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: js");
|
||||
exit(1);
|
||||
}
|
||||
if (!buildPath(data, "images").exists) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: images");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.data - каталог не существует: " ~ data);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
wh.data = data;
|
||||
}
|
||||
|
||||
if (!webHost["title"].empty) {
|
||||
try {
|
||||
wh.title = webHost["title"];
|
||||
} catch (Exception e) {
|
||||
log.w("Заголовок не был установлен - web-host.title");
|
||||
}
|
||||
}
|
||||
|
||||
if (!webHost["loglevel"].empty) {
|
||||
try {
|
||||
wh.loglevel = webHost["loglevel"].to!int;
|
||||
if (wh.loglevel < 0 || wh.loglevel > 6)
|
||||
throw new Exception("несуществующий уровень");
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.loglevel: " ~ e.msg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!webHost["logoutput"].empty) {
|
||||
try {
|
||||
wh.logoutput = webHost["logoutput"]
|
||||
.to!string.split(',')
|
||||
.map!((a) {
|
||||
auto flag = a.strip.to!int;
|
||||
|
||||
if ([1, 2, 4].canFind(flag))
|
||||
return flag;
|
||||
|
||||
log.c("В конфигурационном файле не верны настройки web-host.logoutput");
|
||||
exit(1);
|
||||
})
|
||||
.fold!((a, b) => a | b);
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.logoutput");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (wh.logoutput & 4) {
|
||||
if (webHost["logfile"].empty) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.logfile");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
wh.logfile = webHost["logfile"];
|
||||
} catch (Exception e) {
|
||||
log.c("В конфигурационном файле не верны настройки web-host.logfile");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wh;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
module pgdb;
|
||||
|
||||
import arsd.postgres;
|
||||
import std.stdio;
|
||||
|
||||
alias pgsql = PG.getConnection;
|
||||
|
||||
class PG : PostgreSql {
|
||||
private:
|
||||
static PG _pgsql;
|
||||
this(string config) {
|
||||
super(config);
|
||||
}
|
||||
public:
|
||||
@property static PG getConnection(string config = null) {
|
||||
if (this._pgsql is null) {
|
||||
try {
|
||||
this._pgsql = new PG(config);
|
||||
} catch (Exception e) {
|
||||
throw new Exception(e.msg);
|
||||
}
|
||||
}
|
||||
|
||||
return this._pgsql;
|
||||
}
|
||||
|
||||
PostgresResult sql(T...)(string query, T t) {
|
||||
return cast(PostgresResult)this.query(query, t);
|
||||
}
|
||||
|
||||
void commit() {
|
||||
this.query("COMMIT");
|
||||
}
|
||||
|
||||
void rollback() {
|
||||
this.query("ROLLBACK");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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());
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
module response;
|
||||
|
||||
import vibe.vibe;
|
||||
|
||||
struct Res {
|
||||
bool error;
|
||||
string message;
|
||||
string data;
|
||||
}
|
||||
|
||||
void send(HTTPServerResponse res, bool error = false, string message = "", string data = "") {
|
||||
res.writeJsonBody(Res(
|
||||
error, message, data
|
||||
).serializeToJson());
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
module structures;
|
||||
|
||||
struct ServerInfo {
|
||||
string name;
|
||||
}
|
||||
|
||||
struct WebHost {
|
||||
string[] addresses;
|
||||
ushort http = 0;
|
||||
ushort https = 0;
|
||||
string cert;
|
||||
string key;
|
||||
string data;
|
||||
string title;
|
||||
int loglevel = -1;
|
||||
int logoutput = 0;
|
||||
string logfile;
|
||||
}
|
||||
|
||||
struct GroupDB {
|
||||
string name;
|
||||
string comment;
|
||||
}
|
||||
|
||||
struct NumberDB {
|
||||
string number;
|
||||
string group;
|
||||
string list;
|
||||
int all_cc;
|
||||
int white_cc;
|
||||
int black_cc;
|
||||
string comment;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
module verinfo;
|
||||
|
||||
import std.algorithm: startsWith;
|
||||
import version_;
|
||||
import std.array : split, join;
|
||||
|
||||
string getDasterVersion() {
|
||||
auto verstr = dasterVersion;
|
||||
if (verstr.startsWith("v"))
|
||||
verstr = verstr[1 .. $];
|
||||
auto parts = verstr.split("-");
|
||||
if (parts.length >= 3) {
|
||||
if (parts[$-1].length == 8 && parts[$-1][1 .. $].isHexNumber() && parts[$-2].isNumber())
|
||||
verstr = parts[0 .. $-2].join("-") ~ "+" ~ parts[$-2 .. $].join("-");
|
||||
}
|
||||
return verstr;
|
||||
}
|
||||
|
||||
private bool isHexNumber(string str) {
|
||||
foreach (ch; str)
|
||||
switch (ch) {
|
||||
case '0': .. case '9': break;
|
||||
case 'a': .. case 'f': break;
|
||||
case 'A': .. case 'F': break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool isNumber(string str) {
|
||||
foreach (ch; str)
|
||||
switch (ch) {
|
||||
case '0': .. case '9': break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module version_;
|
||||
|
||||
enum dasterVersion = "v0.0.1";
|
|
@ -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}
|
|
@ -0,0 +1,39 @@
|
|||
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='style.css')
|
||||
script(src='jquery-3.7.0.min.js')
|
||||
script(src='jquery-ui.min.js')
|
||||
script(src='message.js')
|
||||
script(src='script.js')
|
||||
body
|
||||
div.div-header
|
||||
// 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
|
||||
li
|
||||
a(href='#tabs-numbers') Номера телефонов
|
||||
li
|
||||
a(href='#tabs-sms') SMS
|
||||
li
|
||||
a(href='#tabs-ussd') USSD
|
||||
li
|
||||
a(href='#tabs-server') Сервер
|
||||
div#tabs-numbers
|
||||
div#tabs-sms
|
||||
p Список SMS сообщений
|
||||
div#tabs-ussd
|
||||
p Список результатов USSD запросов
|
||||
div#tabs-server
|
||||
p Информация о сервере
|