before delete 3software
This commit is contained in:
@@ -4,38 +4,15 @@ const sqlite3 = require('better-sqlite3')
|
||||
|
||||
const db = sqlite3(`./data/db.sqlite`)
|
||||
db.pragma('journal_mode = WAL')
|
||||
db.pragma('foreign_keys = on')
|
||||
|
||||
db.exec(fs.readFileSync('./data/init.sql', 'utf8'))
|
||||
|
||||
/*
|
||||
db.exec(`attach database './data/backup.sqlite' as backup`)
|
||||
|
||||
db.function('backup', (tblname, ...values) => {
|
||||
db
|
||||
.prepare(`insert into backup.${tblname} select ` + values.map(e => '?').join(', '))
|
||||
.run(values)
|
||||
})
|
||||
|
||||
const backupQuery = db
|
||||
.prepare(`
|
||||
select group_concat(tbl || char(13) || trg, char(13) || char(13)) from (
|
||||
select 'create table if not exists backup.' || t.name || ' (' || group_concat(c.name || ' ' || c.type, ', ') || ', time integer);' tbl,
|
||||
'create trigger if not exists trg_' || t.name || '_delete after delete on ' || t.name || ' for each row begin ' ||
|
||||
' select backup (' || t.name || ',' || group_concat('OLD.' || c.name, ', ') || ', strftime(''%s'', ''now'')); end;' trg
|
||||
from sqlite_master t left join pragma_table_xinfo c on t.tbl_name = c.arg and c.schema = 'main'
|
||||
where t.sql is not null and t.type = 'table' and t.name <> 'sqlite_sequence'
|
||||
group by t.type, t.name order by t.type, t.name)
|
||||
`)
|
||||
.pluck(true)
|
||||
.get()
|
||||
db.exec(backupQuery)
|
||||
*/
|
||||
|
||||
db.function('generate_key', (id, time) => {
|
||||
return [
|
||||
'KEY',
|
||||
Buffer.from(time + '').toString('base64'),
|
||||
crypto.createHash('md5').update(`sa${time}-${id}lt`).digest('hex')
|
||||
crypto.createHash('md5').update(`sa${time}-${id}lty`).digest('hex')
|
||||
].join('-')
|
||||
})
|
||||
|
||||
@@ -54,4 +31,16 @@ db.prepareUpdate = function (table, columns, data, where) {
|
||||
` where ` + where.map(col => `"${col}" = :${col}`).join(' and '))
|
||||
}
|
||||
|
||||
db.prepareUpsert = function (table, columns, data, where) {
|
||||
const dataColumns = columns.filter(col => col in data)
|
||||
if (dataColumns.length == 0)
|
||||
throw Error('SQLite Error: No data to update')
|
||||
|
||||
return db.prepare(
|
||||
`insert into "${table}" (` + [...dataColumns, ...where].join(', ') + `) values (:` + [...dataColumns, ...where].join(', :') +
|
||||
`) on conflict (` + where.join(',') + `) do update ` +
|
||||
`set ` + dataColumns.map(col => `"${col}" = :${col}`).join(', ') +
|
||||
` where ` + where.map(col => `"${col}" = :${col}`).join(' and '))
|
||||
}
|
||||
|
||||
module.exports = db
|
||||
5
backend/include/eventbus.js
Normal file
5
backend/include/eventbus.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const EventEmitter = require('events')
|
||||
class EventBus extends EventEmitter {}
|
||||
const eventBus = new EventBus()
|
||||
|
||||
module.exports = eventBus
|
||||
58
backend/include/i18n.js
Normal file
58
backend/include/i18n.js
Normal file
@@ -0,0 +1,58 @@
|
||||
const i18n = {
|
||||
en: {
|
||||
ON_PROJECT_ARCHIVE: 'The project was moved to an rachive. Message tracking has been discontinued.',
|
||||
ON_PROJECT_RESTORE: 'The project has been recovered from the archives.',
|
||||
ON_CHAT_REMOVE: 'The chat was removed from a project.',
|
||||
CHAT_IN_USE: 'Chat is already in use',
|
||||
EXPIRED_KEY: 'The key validity time for binding has expired',
|
||||
OPEN_PROJECT: 'Open project',
|
||||
WELCOME: 'Welcome, strange',
|
||||
TASK_MESSAGE: ':clipboard: New task ${PRIORITY}\n${NAME}\n[${CREATOR}](tg://user?id=${CREATOR_ID}) > [${ASSIGNEE}](tg://user?id=${ASSIGNEE_ID})\nPlan date: ${PLAN_DATE}\n[Open a task page](${URL})',
|
||||
TASK_PRIORITY_0: '',
|
||||
TASK_PRIORITY_1: '',
|
||||
TASK_PRIORITY_2: '(Important)',
|
||||
TASK_PRIORITY_3: '(Critical)',
|
||||
MEETING_MESSAGE: 'Meeting ${name}',
|
||||
ADMIN_APP: 'Administrator Access',
|
||||
USER_APP: 'User Access'
|
||||
},
|
||||
ru: {
|
||||
ON_PROJECT_ARCHIVE: 'Проект помещен в архив. Отслеживание сообщений прекращено.',
|
||||
ON_PROJECT_RESTORE: 'Проект восстановлен из архива.',
|
||||
ON_CHAT_REMOVE: 'Чат удален из проекта.',
|
||||
CHAT_IN_USE: 'Чат уже используется',
|
||||
EXPIRED_KEY: 'Время действия ключа для привязки истекло',
|
||||
OPEN_PROJECT: 'Открыть проект',
|
||||
WELCOME: 'Добро пожаловать',
|
||||
TASK_MESSAGE: '📋 Новая задача ${PRIORITY}\n${NAME}\n<a href="tg://user?id=${CREATOR_ID}">${CREATOR}</a> > <a href="tg://user?id=${ASSIGNEE_ID}">${ASSIGNEE}</a>\nСрок: ${PLAN_DATE}\n<a href="${URL}">Перейти на страницу задачи</a>',
|
||||
TASK_PRIORITY_0: '',
|
||||
TASK_PRIORITY_1: '',
|
||||
TASK_PRIORITY_2: '(Важно)',
|
||||
TASK_PRIORITY_3: '(Критично)',
|
||||
MEETING_MESSAGE: 'Встреча ${name}',
|
||||
ADMIN_APP: 'Режим администратора',
|
||||
USER_APP: 'Режим пользователя'
|
||||
}
|
||||
}
|
||||
|
||||
const hasLocale = (locale) => !!i18n[locale]
|
||||
function getString (locale, code, args = {}) {
|
||||
const params = {}
|
||||
Object.keys(args instanceof Object ? args : {}).forEach(key => {
|
||||
const value = args[key]
|
||||
params[key] = value[0] == '$' ? getString(locale, value.substring(1)) : value
|
||||
})
|
||||
|
||||
let res = i18n[locale] ? i18n[locale][code] : undefined
|
||||
if (res === undefined)
|
||||
res = i18n.en[code]
|
||||
if (res === undefined)
|
||||
res = code
|
||||
if (res === undefined)
|
||||
res = 'ERROR'
|
||||
|
||||
res = res.replace(/\${(\w+)}/g, (match, key) => params.hasOwnProperty(key) ? params[key] : match)
|
||||
return res
|
||||
}
|
||||
|
||||
module.exports = { hasLocale, getString }
|
||||
90
backend/include/log.js
Normal file
90
backend/include/log.js
Normal file
@@ -0,0 +1,90 @@
|
||||
const sqlite3 = require('better-sqlite3')
|
||||
|
||||
const db = sqlite3(`./data/log.sqlite`)
|
||||
db.pragma('journal_mode = DELETE')
|
||||
db.pragma('synchronous = 0')
|
||||
|
||||
db.exec(`
|
||||
create table if not exists http (time integer default (strftime('%s','now')), method text, url text, headers text, body text, status text, duration integer);
|
||||
create table if not exists mtproto (time integer default (strftime('%s','now')), message text);
|
||||
create table if not exists error (time integer default (strftime('%s','now')), message text, stack text);
|
||||
`)
|
||||
|
||||
function http (req, res, duration) {
|
||||
const data = {
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
status: res.statusCode,
|
||||
duration
|
||||
};
|
||||
|
||||
['headers', 'body'].forEach(key => {
|
||||
const value = req.body[key]
|
||||
try {
|
||||
data[key] = value instanceof Array && value.length < 1_000_000 || value instanceof Object ? JSON.stringify(value) : value?.toString() || null
|
||||
} catch (err) {
|
||||
error(err)
|
||||
data[key] = value?.toString() || null
|
||||
}
|
||||
})
|
||||
|
||||
db
|
||||
.prepare(`insert into http (method, url, headers, body, status, duration) values (:method, :url, :headers, :body, :status, :duration)`)
|
||||
.run(data)
|
||||
}
|
||||
|
||||
function safeStringify(obj, indent = 2) {
|
||||
const cache = new Set()
|
||||
|
||||
return JSON.stringify(obj, (key, value) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (cache.has(value))
|
||||
return '[Circular]'
|
||||
|
||||
cache.add(value)
|
||||
}
|
||||
|
||||
return value
|
||||
}, indent)
|
||||
}
|
||||
|
||||
function mtproto (update) {
|
||||
const message = update
|
||||
message.self = message
|
||||
|
||||
db
|
||||
.prepare(`insert into mtproto (message) values (:message)`)
|
||||
.run({
|
||||
message: safeStringify(message)
|
||||
})
|
||||
}
|
||||
|
||||
function error (...args) {
|
||||
const stacks = []
|
||||
const message = args.map(arg => {
|
||||
if (arg instanceof Error) {
|
||||
stacks.push(arg.stack)
|
||||
return 'Error: ' + arg.message
|
||||
} else if (arg instanceof Object) {
|
||||
try {
|
||||
return JSON.stringify(arg)
|
||||
} catch (err) { }
|
||||
}
|
||||
|
||||
return String(arg)
|
||||
}).join('\n')
|
||||
|
||||
if (stacks.length == 0)
|
||||
stacks.push(new Error().stack)
|
||||
|
||||
console.error(message)
|
||||
|
||||
db
|
||||
.prepare(`insert into error (message, stack) values (:message, :stack)`)
|
||||
.run({
|
||||
message,
|
||||
stack: stacks.join('\n\n')
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { http, mtproto, error }
|
||||
Reference in New Issue
Block a user