v0.9.0
This commit is contained in:
parent
f0d3e74b0c
commit
a12a40c8b1
|
@ -0,0 +1,39 @@
|
||||||
|
## V.0.9.0 RC
|
||||||
|
### Back
|
||||||
|
1. The organization of a transparent REST API through the fox\externalCallable interface - allows you to organize access to the necessary entities with minimal costs, but with all the necessary checks.
|
||||||
|
2. Support for third-party modules with the ability to install multiple instances of the same module (if supported by the module).
|
||||||
|
3. User authentication — both using built-in tools and using external OAuth sources (currently Gitlab, Gitea, Yandex, VK support is implemented).
|
||||||
|
4. User authorization — with the help of the built-in access control system based on roles, flexible verification of the user's access rights is performed. The lists of user roles are checked both by the back when making REST API calls, and by the front — for this, after authentication, the list of access rights of the current user is transmitted.
|
||||||
|
5. The ability to make requests without authorization, if necessary. For example, to implement Webhooks.
|
||||||
|
6. Embedded database migrations based on the description of the class structure.
|
||||||
|
7. A base class for performing standard database functions (write, read, search, delete) on the basis of which you can quickly create entities.
|
||||||
|
8. memcached support for both embedded and custom objects for quick access to frequently used data
|
||||||
|
9. Configuration storage for each module in the database (with cache) so it is in the environment of the container.
|
||||||
|
10. Built-in functionality for registering users by invitation with the ability to automatically add to groups both for granting access and for organizing into logical groups ("lists").
|
||||||
|
11. Built-in functionality of action confirmation codes for both built-in functions (password recovery, mail confirmation, etc.) and for user modules.
|
||||||
|
12. Support for S3-compatible storage management (creating bouquets, deleting data, etc.).
|
||||||
|
13. The ability to add any other object storage based on a typical interface.
|
||||||
|
14. Storing files (email attachments, servicedesk attachments, templates and report results, etc.) in S3-compatible object storage
|
||||||
|
15. Built-in support for OpenDocument ODS and ODT formats for automated document generation (reports, invoices, acts, etc.)
|
||||||
|
16. Built-in Fox Converter support for exporting documents in any office format.
|
||||||
|
17. Built-in support at the base class level of data exchange in JSON format with the ability to control the visibility of individual properties and create virtual properties.
|
||||||
|
18. Built-in eMail client that supports simultaneous work both for receiving and sending emails, including attachments from multiple accounts using IMAP and SMTP protocols (with and without authorization).
|
||||||
|
19. Storing metadata of modules (for example, the last synchronization, etc.) in the built-in storage with caching.
|
||||||
|
20. Support for receiving and generating data in Prometheus format
|
||||||
|
21. Built-in REST API Client for communication with third-party systems.
|
||||||
|
22. Built-in stringExportable && stringImportable interfaces for automatic conversion of objects to a string and back (for example, time to unixTime or ISO).
|
||||||
|
23. Built-in encryption module for critical data (for example, passwords) as well as the formation of hashes based on an individual master password.
|
||||||
|
24. A system for generating unique identifiers in the format 1000-0000-00 with a checksum for the formation of a register of documents, inventory and other objects. For example, to organize a global search (in future releases) and barcodes.
|
||||||
|
25. Built-in cron, which allows you to run periodic processes of modules in parallel with a limit on the maximum execution time and with the possibility of blocking the restart until the last process is completed separately for each task.
|
||||||
|
26. Support for multiple languages, for example, for sending notifications to e-mail or messengers. The list of languages may vary for Chimera Core and additional modules.
|
||||||
|
27. Logging of all user actions.
|
||||||
|
|
||||||
|
### Front
|
||||||
|
1. Built-in methods of REST interaction with both your own backup and other services.
|
||||||
|
2. Formation of a visual basic user interface in several languages
|
||||||
|
3. Basic system administration functions
|
||||||
|
4. Authorization, user registration. Session monitoring
|
||||||
|
5. Built-in Fox UI library for creating menus, dialogs, buttons, forms including forms for automatic password generation and autofill.
|
||||||
|
6. Access rights verification library to control the display of interface elements.
|
||||||
|
7. The ability to customize the interface by creating your own color themes and images.
|
||||||
|
8. Using FontAwesome 5 to form interfaces, it is also possible to add your own fonts with icons.
|
|
@ -0,0 +1,39 @@
|
||||||
|
## V.0.9.0 RC
|
||||||
|
### Бэк
|
||||||
|
1. Огранизация прозрачного REST API через интерфейс fox\externalCallable - позволяет с минимальными затратами но при этом со всеми необходимыми проверками организовать доступ к нужным сущностям.
|
||||||
|
2. Поддержка сторонних модулей с возможностью установки нескольких инстансов одного модуля (если поддерживается модулем).
|
||||||
|
3. Аутентификация пользователей — как с помощью встроенных средств так и с помощью внешних источников oAuth (на данный момент реализована поддержка Gitlab, Gitea, Yandex, VK).
|
||||||
|
4. Авторизация пользователей — с помощью встроенной системы контроля доступа, основанной на ролях производится гибкая проверка наличия у пользователя прав доступа. Списки ролей пользователя проверяются как бэком при выполнении вызовов REST API, так и фронтом — для этого после аутентификации передается список прав доступа текущего пользователя.
|
||||||
|
5. Возможность выполнения запросов без авторизации, если такое необходимо. Например для реализации Вебхуки.
|
||||||
|
6. Встроенные миграции БД на основе описания структуры класса.
|
||||||
|
7. Базовый класс для выполнения стандартных функции работы с БД (запись, чтение, поиск, удаление) на основе которого можно быстро создавать сущности.
|
||||||
|
8. Поддержка memcached как для встроенных объектов так и для пользовательских для быстрого доступа к часто используемым данным
|
||||||
|
9. Хранилище конфигурации для каждого модуля в БД (с кэшем) так и глобальной в окружении контейнера.
|
||||||
|
10. Встроенный функционал регистрации пользователей по приглашениям с возможность автоматического добавления в группы как для предоставления доступа так и для организации в логические группы («списки»).
|
||||||
|
11. Встроенный функционал кодов подтверждения действий как для встроенных функций (восстановление пароля, подтверждение почты итд) так и для пользовательских модулей.
|
||||||
|
12. Поддержка управления S3-совместимым хранилищем (создание букетов, удаление данных итд).
|
||||||
|
13. Возможность добавления любых других объектных хранилищ на основе типового интерфейса.
|
||||||
|
14. Хранение файлов (вложений электронной почты, вложений в servicedesk, шаблонов и результатов отчетов итд) в S3-совместимом объектном хранилище
|
||||||
|
15. Встроенная поддержка форматов OpenDocument ODS и ODT для автоматизированного формирования документов (отчеты, счета, акты итд)
|
||||||
|
16. Встроенная поддержка Fox Converter для экспорта документов в любом офисном формате.
|
||||||
|
17. Встроенная поддержка на уровне базового класса обмена данными в формате JSON с возможность контроля видимости отдельных свойств и создания виртуальных свойств.
|
||||||
|
18. Встроенный eMail клиент, поддерживающий одновременную работу как на получение так и на отправку писем в том чисте с вложениями с нескольких учетных записей по протоколам IMAP и SMTP (с авторизацией и без).
|
||||||
|
19. Хранение метаданных модулей (например, последняя синхронизация итд) во встроенном хранилище с кешированием.
|
||||||
|
20. Поддержка получения и формирования данных в формате Prometheus
|
||||||
|
21. Встроенный REST API Client для связи со сторонними системами.
|
||||||
|
22. Встроенные интерфейсы stringExportable && stringImportable для автоматической конвертации объектов в строку и обратно (например время в unixTime или ISO).
|
||||||
|
23. Встроенный модуль шифрования критиченых данных (например, паролей) а так же формирования хэшей на основе индивидуального мастер-пароля.
|
||||||
|
24. Система формирования уникальных идентификаторов в формате 1000-0000-00 с контрольной суммой для формирования реестра документов, инвентаризации и других объектов. Например для организации глобального поиска (в будущих релизах) и штрих-кодов.
|
||||||
|
25. Встроенный cron, позволяющий запускать периодические процессы модулей параллельно с ограничением по максимальному времени выполнения и с возможностью блокировки повторного запуска, пока не завершится прошлый процесс отдельно для каждой задачи.
|
||||||
|
26. Поддержка нескольких языков, например для отправки уведомлений на электронную почту или мессенджеры. Список языков может различаться для Chimera Core и дополнительных модулей.
|
||||||
|
27. Логирование всех действий пользователей.
|
||||||
|
|
||||||
|
### Фронт
|
||||||
|
1. Встроенные методы взаимодействия по REST как с собственным бэком, так и с другими службами.
|
||||||
|
2. Формирование визуального базового интерфейса пользователя на нескольких языках
|
||||||
|
3. Базовые функции администрирования системы
|
||||||
|
4. Авторизациия, регистрации пользователей. Контроль сессий
|
||||||
|
5. Встроенная библиотека Fox UI для формирования меню, диалогов, кнопок, форм включая формы автоматической генерации паролей и автозаполнения.
|
||||||
|
6. Библиотека проверки прав доступа для контроля за отображением элементов интерфейса.
|
||||||
|
7. Возможность кастомизации интерфейса в помощью создания собственных цветовых тем и изображений.
|
||||||
|
8. Использование FontAwesome 5 для формирования интерфейсов, так же возможно добавление собственных шрифтов с иконками.
|
33
README.md
33
README.md
|
@ -1,9 +1,34 @@
|
||||||
# Chimera Fox Platform Mark2
|
# Chimera Fox Platform Mark2
|
||||||
|
Chimera Fox is a universal framework for quickly creating web applications. The back is written in PHP, and provides basic functions. Front on JS. Interaction via REST.
|
||||||
|
|
||||||
Полностью новая версия платформы Chimera Fox.
|
# How to run in docker
|
||||||
|
```
|
||||||
|
version: "2"
|
||||||
|
|
||||||
Предыдущие версии будут поддерживаться только в качестве обновлений безопасности.
|
networks:
|
||||||
|
interlink:
|
||||||
|
|
||||||
Обратная совместимость с предыдущими версиями отсутствует - это основная причина выхода новой платформы - совместимость со старыми версиями занимает слишком много ресурсов на поддержку, а фактически она уже не нужна.
|
services:
|
||||||
|
|
||||||
*Актуальные модули старой версии будут портированы на Mark2*
|
fox-web-mk2:
|
||||||
|
restart: always
|
||||||
|
image: mxfox/chimera-mk2-basic:lastest
|
||||||
|
container_name: fox-web-mk2
|
||||||
|
volumes:
|
||||||
|
- ./fox-log-web/logs:/var/log/apache2
|
||||||
|
- ./fox-log-cron/logs:/var/log/fox
|
||||||
|
|
||||||
|
networks:
|
||||||
|
- interlink
|
||||||
|
|
||||||
|
environment:
|
||||||
|
- "FOX_SQLSERVER=XXXXXX"
|
||||||
|
- "FOX_SQLUSER=XXXXX"
|
||||||
|
- "FOX_SQLPASSWD=XXXX"
|
||||||
|
- "FOX_SQLDB=XXXXX"
|
||||||
|
- "FOX_CACHEHOST=memcached"
|
||||||
|
- "FOX_TITLE=Mark2"
|
||||||
|
- "FOX_SITEPREFIX=https://mark2.fox.local"
|
||||||
|
- "FOX_MASTERSECRET=SuperSecretPassword"
|
||||||
|
- "FOX_INIT_PASSWORD=AnotherSuperSecretPassword"
|
||||||
|
```
|
||||||
|
|
|
@ -11,6 +11,7 @@ use fox\oAuthProfile;
|
||||||
use fox\config;
|
use fox\config;
|
||||||
use fox\userGroup;
|
use fox\userGroup;
|
||||||
use fox\authToken;
|
use fox\authToken;
|
||||||
|
use fox\logEntry;
|
||||||
|
|
||||||
class register implements externalCallable {
|
class register implements externalCallable {
|
||||||
|
|
||||||
|
@ -33,9 +34,6 @@ class register implements externalCallable {
|
||||||
$ic=null;
|
$ic=null;
|
||||||
if (!empty($regCode)) {
|
if (!empty($regCode)) {
|
||||||
$ic=userInvitation::getByCode($regCode);
|
$ic=userInvitation::getByCode($regCode);
|
||||||
if (!$ic || ($ic->expireStamp->stamp>time())) {
|
|
||||||
$ic=null;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$ic =userInvitation::getByEMail($eMail);
|
$ic =userInvitation::getByEMail($eMail);
|
||||||
}
|
}
|
||||||
|
@ -88,11 +86,9 @@ class register implements externalCallable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($ic) {
|
if ($ic) {
|
||||||
if ($ic && ($ic->expireStamp->stamp<=time())) {
|
foreach ($ic->joinGroupsId as $grid) {
|
||||||
foreach ($ic->joinGroupsId as $grid) {
|
$group = new userGroup($grid);
|
||||||
$group = new userGroup($grid);
|
$group->join($u);
|
||||||
$group->join($u);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!$ic->allowMultiUse) { $ic->delete(); }
|
if (!$ic->allowMultiUse) { $ic->delete(); }
|
||||||
}
|
}
|
||||||
|
@ -102,7 +98,7 @@ class register implements externalCallable {
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
trigger_error($e->getMessage());
|
trigger_error($e->getMessage());
|
||||||
}
|
}
|
||||||
|
logEntry::add($request->instance, static::class, __FUNCTION__, null, "User ".$u->login." registered ", "INFO", $u, "user", $u->id);
|
||||||
$t = authToken::issue($u, "WEB");
|
$t = authToken::issue($u, "WEB");
|
||||||
return [
|
return [
|
||||||
"token" => $t->token,
|
"token" => $t->token,
|
||||||
|
@ -148,6 +144,8 @@ class register implements externalCallable {
|
||||||
|
|
||||||
|
|
||||||
$t = authToken::issue($u, "WEB");
|
$t = authToken::issue($u, "WEB");
|
||||||
|
|
||||||
|
logEntry::add($request->instance, static::class, __FUNCTION__, null, "Password recovered for user ".$u->login, "INFO", $u, "user", $u->id);
|
||||||
return [
|
return [
|
||||||
"token" => $t->token,
|
"token" => $t->token,
|
||||||
"expire" => $t->expireStamp->isNull() ? "Never" : $t->expireStamp
|
"expire" => $t->expireStamp->isNull() ? "Never" : $t->expireStamp
|
||||||
|
|
|
@ -268,7 +268,12 @@ class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportabl
|
||||||
$stringRef = (is_bool($ref->{$key}) || ! (is_object($ref->{$key}) || is_array($ref->{$key})));
|
$stringRef = (is_bool($ref->{$key}) || ! (is_object($ref->{$key}) || is_array($ref->{$key})));
|
||||||
$stringVal = (is_bool($val) || ! (is_object($val) || is_array($val)));
|
$stringVal = (is_bool($val) || ! (is_object($val) || is_array($val)));
|
||||||
|
|
||||||
$this->changelog .= "key: " . $key . " changed from " . ($stringRef ? (is_bool($ref->{$key}) ? ($ref->{$key} ? "true" : "false") : $ref->{$key}) : "<" . gettype($ref->{$key}) . ">") . " to " . ($stringVal ? (is_bool($val) ? ($val ? "true" : "false") : $val) : "<" . gettype($val) . ">") . ";\n ";
|
if (preg_match("/^_/",$key)) {
|
||||||
|
$this->changelog .= "key: " . $key . " changed \n";
|
||||||
|
} else {
|
||||||
|
$this->changelog .= "key: " . $key . " changed from " . ($stringRef ? (is_bool($ref->{$key}) ? ($ref->{$key} ? "true" : "false") : $ref->{$key}) : "<" . gettype($ref->{$key}) . ">") . " to " . ($stringVal ? (is_bool($val) ? ($val ? "true" : "false") : $val) : "<" . gettype($val) . ">") . ";\n ";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,17 +289,18 @@ class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportabl
|
||||||
if (property_exists($this, static::$sqlIdx) && ($this->{static::$sqlIdx} == null)) {
|
if (property_exists($this, static::$sqlIdx) && ($this->{static::$sqlIdx} == null)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$this->validateDelete()) {
|
||||||
|
throw new \Exception("ValidateDelete failed");
|
||||||
|
}
|
||||||
|
|
||||||
if (static::$allowDeleteFromDB) {
|
if (static::$allowDeleteFromDB) {
|
||||||
if ($this->validateDelete()) {
|
$this->checkSql();
|
||||||
$this->checkSql();
|
$this->sql->quickExec("DELETE FROM `" . static::$sqlTable . "` where " . static::$sqlIdx . " = '" . $this->{static::$sqlIdx} . "'");
|
||||||
$this->sql->quickExec("DELETE FROM `" . static::$sqlTable . "` where " . static::$sqlIdx . " = '" . $this->{static::$sqlIdx} . "'");
|
if (! (empty(static::$deletedFieldName))) {
|
||||||
if (! (empty(static::$deletedFieldName))) {
|
$this->{static::$deletedFieldName} = true;
|
||||||
$this->{static::$deletedFieldName} = true;
|
|
||||||
}
|
|
||||||
$this->{static::$sqlIdx} = null;
|
|
||||||
} else {
|
|
||||||
throw new \Exception("ValidateDelete failed");
|
|
||||||
}
|
}
|
||||||
|
$this->{static::$sqlIdx} = null;
|
||||||
} elseif (! (empty(static::$deletedFieldName))) {
|
} elseif (! (empty(static::$deletedFieldName))) {
|
||||||
$this->checkSql();
|
$this->checkSql();
|
||||||
$this->sql->quickExec("UPDATE `" . static::$sqlTable . "` set `" . static::$deletedFieldName . "`='1' where " . $this::$sqlIdx . " = '" . $this->{static::$sqlIdx} . "'");
|
$this->sql->quickExec("UPDATE `" . static::$sqlTable . "` set `" . static::$deletedFieldName . "`='1' where " . $this::$sqlIdx . " = '" . $this->{static::$sqlIdx} . "'");
|
||||||
|
@ -583,4 +589,8 @@ class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportabl
|
||||||
}
|
}
|
||||||
return $rv;
|
return $rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function log(string $instance, $method, string $message, ?user $user=null, ?string $refType=null, ?string $refId=null, string $msgCode=null, ?string $severity="INFO", $payload=null) {
|
||||||
|
return logEntry::add($instance, static::class, $method, $msgCode, $message, $severity, $user, $refType, $refId, $payload);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -30,7 +30,7 @@ class ru {
|
||||||
Добрый день!<br/>
|
Добрый день!<br/>
|
||||||
|
|
||||||
Для подтверждения адреса электронной почты укажите код <span style='color: #ff6f0f'>\${confCodePrint}</span> в форме подтверждения по адресу <a style='color: #ff6f0f; text-decoration: underline;' href='
|
Для подтверждения адреса электронной почты укажите код <span style='color: #ff6f0f'>\${confCodePrint}</span> в форме подтверждения по адресу <a style='color: #ff6f0f; text-decoration: underline;' href='
|
||||||
\${sitePrefix}/auth/mailConfirm'>\${sitePrefix}/core/userEmailConfirm</a><br/>
|
\${sitePrefix}/core/userEmailConfirm'>\${sitePrefix}/core/userEmailConfirm</a><br/>
|
||||||
или перейдите по <a style='color: #ff6f0f; text-decoration: underline;' href='
|
или перейдите по <a style='color: #ff6f0f; text-decoration: underline;' href='
|
||||||
\${sitePrefix}/core/userEmailConfirm?code=\${confCodePrint}'>ссылке</a><br/>
|
\${sitePrefix}/core/userEmailConfirm?code=\${confCodePrint}'>ссылке</a><br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php namespace fox;
|
||||||
|
|
||||||
|
class logEntry extends baseClass implements externalCallable {
|
||||||
|
protected $id;
|
||||||
|
protected time $entryStamp;
|
||||||
|
public $severity;
|
||||||
|
public $module;
|
||||||
|
public $class;
|
||||||
|
public $method;
|
||||||
|
public $userId;
|
||||||
|
public $msgCode;
|
||||||
|
public $message;
|
||||||
|
public $refType;
|
||||||
|
public $refId;
|
||||||
|
public $payload=[];
|
||||||
|
|
||||||
|
public static $sqlTable="tblLog";
|
||||||
|
|
||||||
|
protected static $sqlColumns = [
|
||||||
|
"severity"=>["type"=>"CHAR(10)","index"=>"INDEX"],
|
||||||
|
"module"=>["type"=>"VARCHAR(255)","index"=>"INDEX"],
|
||||||
|
"class"=>["type"=>"VARCHAR(255)"],
|
||||||
|
"method"=>["type"=>"VARCHAR(255)"],
|
||||||
|
"userId"=>["type"=>"INT","index"=>"INDEX"],
|
||||||
|
"msgCode"=>["type"=>"CHAR(16)"],
|
||||||
|
"message"=>["type"=>"TEXT"],
|
||||||
|
"refType"=>["type"=>"VARCHAR(255)","index"=>"INDEX"],
|
||||||
|
"refId"=>["type"=>"VARCHAR(255)","index"=>"INDEX"],
|
||||||
|
];
|
||||||
|
|
||||||
|
const sevDebug="DEBUG";
|
||||||
|
const sevInfo="INFO";
|
||||||
|
const sevWarning="WARN";
|
||||||
|
const sevAlert="ALERT";
|
||||||
|
|
||||||
|
protected function __xConstruct() {
|
||||||
|
$this->entryStamp=new time();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function validateSave() {
|
||||||
|
if ($this->entryStamp->isNull()) { $this->entryStamp=time::current(); }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function add(string $instance, string $class, string $method, ?string $msgCode=null, string $message, ?string $severity="INFO", ?user $user=null, ?string $refType=null, ?string $refId=null, $payload=null) {
|
||||||
|
$l = new static();
|
||||||
|
$l->module = $instance;
|
||||||
|
$l->class=$class;
|
||||||
|
$l->method=$method;
|
||||||
|
$l->userId = empty($user)?null:$user->id;
|
||||||
|
$l->msgCode=$msgCode;
|
||||||
|
$l->message=$message;
|
||||||
|
$l->refType=$refType;
|
||||||
|
$l->refId=$refId;
|
||||||
|
$l->payload=empty($payload)?[]:$payload;
|
||||||
|
$l->severity=$severity;
|
||||||
|
$l->save();
|
||||||
|
return $l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
|
@ -22,10 +22,12 @@ namespace fox;
|
||||||
* @property mixed $rxPassword
|
* @property mixed $rxPassword
|
||||||
* @property mixed $rxLogin
|
* @property mixed $rxLogin
|
||||||
* @property mixed $rxPassword
|
* @property mixed $rxPassword
|
||||||
|
* @property mixed $rxURL
|
||||||
|
* @property mixed $txURL
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
|
|
||||||
class mailAccount extends baseClass {
|
class mailAccount extends baseClass implements externalCallable {
|
||||||
protected $id;
|
protected $id;
|
||||||
public $address;
|
public $address;
|
||||||
public $rxServer;
|
public $rxServer;
|
||||||
|
@ -45,6 +47,17 @@ class mailAccount extends baseClass {
|
||||||
public bool $default=false;
|
public bool $default=false;
|
||||||
public bool $deleted=false;
|
public bool $deleted=false;
|
||||||
|
|
||||||
|
const urlSchemas=[
|
||||||
|
"rx"=>[
|
||||||
|
"imap"=>["ssl"=>false,"port"=>143,"proto"=>"imap"],
|
||||||
|
"imaps"=>["ssl"=>true,"port"=>993,"proto"=>"imap"],
|
||||||
|
],
|
||||||
|
"tx"=>[
|
||||||
|
"smtp"=>["ssl"=>false,"port"=>587,"proto"=>"smtp"],
|
||||||
|
"smtps"=>["ssl"=>true,"port"=>465,"proto"=>"smtp"],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
public static $deletedFieldName = "deleted";
|
public static $deletedFieldName = "deleted";
|
||||||
|
|
||||||
public static $sqlTable = 'tblMailAccounts';
|
public static $sqlTable = 'tblMailAccounts';
|
||||||
|
@ -76,21 +89,63 @@ class mailAccount extends baseClass {
|
||||||
|
|
||||||
public function __set($key, $val) {
|
public function __set($key, $val) {
|
||||||
switch ($key) {
|
switch ($key) {
|
||||||
|
case "txURL":
|
||||||
|
$this->parceURL($val, "tx");
|
||||||
|
break;
|
||||||
|
case "rxURL":
|
||||||
|
$this->parceURL($val, "rx");
|
||||||
|
break;
|
||||||
case "password": $this->__password = xcrypt::encrypt($val); break;
|
case "password": $this->__password = xcrypt::encrypt($val); break;
|
||||||
default: parent::__set($key, $val);
|
default: parent::__set($key, $val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function parceURL($val, $dst) {
|
||||||
|
if (!array_key_exists($dst, static::urlSchemas)) {
|
||||||
|
foxException::throw("ERR","Invalid dst scheme",400,"UDSCH");
|
||||||
|
}
|
||||||
|
|
||||||
|
$schemaRef=static::urlSchemas[$dst];
|
||||||
|
$ref=parse_url($val);
|
||||||
|
if (!array_key_exists($ref["scheme"], $schemaRef)) {
|
||||||
|
foxException::throw("ERR","Invalid URL scheme",400,"UUSCH");
|
||||||
|
}
|
||||||
|
$this->{$dst."SSL"}=$schemaRef[$ref["scheme"]]["ssl"];
|
||||||
|
$this->{$dst."Port"}=empty($ref["port"])?$schemaRef[$ref["scheme"]]["port"]:$ref["port"];
|
||||||
|
$this->{$dst."Server"}=$ref["host"];
|
||||||
|
$this->{$dst."Proto"}=$schemaRef[$ref["scheme"]]["proto"];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function connect() {
|
public function connect() {
|
||||||
return new mailClient($this);
|
return new mailClient($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function validateSave() {
|
protected function validateSave() {
|
||||||
if (empty($this->login) || empty($this->__password) || empty($this->address)) { return false;}
|
if (empty($this->login) || empty($this->__password) || empty($this->address)) {
|
||||||
|
throw new foxException("Validation failed",406);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function validateDelete()
|
||||||
|
{
|
||||||
|
if ($this->default) {
|
||||||
|
foxException::throw("ERR","Default account deletion prohibited",406,"DDAX");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDefault() {
|
||||||
|
if ($this->default) { return;}
|
||||||
|
if ($this->deleted) { throw new foxException("Unacceptable",406); }
|
||||||
|
|
||||||
|
$this->checkSql();
|
||||||
|
$this->sql->quickExec("UPDATE `".static::$sqlTable."` set `default`=0");
|
||||||
|
$this->default=true;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
public static function getDefaultAccount(&$sql=null) {
|
public static function getDefaultAccount(&$sql=null) {
|
||||||
$ref = new static();
|
$ref = new static();
|
||||||
|
@ -101,4 +156,72 @@ class mailAccount extends baseClass {
|
||||||
} else {return null;}
|
} else {return null;}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function API_GET_list(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminMailAccounts", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::search();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function API_DELETE(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminMailAccounts", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static(common::clearInput($request->function,"0-9"));
|
||||||
|
$m->delete();
|
||||||
|
static::log($request->instance,__FUNCTION__, "Mail account ".$m->address." deleted",$request->user,"mailAccount",$m->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function API_GET(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminMailAccounts", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static(common::clearInput($request->function,"0-9"));
|
||||||
|
return $m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function APIX_GET_setDefault(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminMailAccounts", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static(common::clearInput($request->function,"0-9"));
|
||||||
|
$m->setDefault();
|
||||||
|
static::log($request->instance,__FUNCTION__, "Default mail account changed to ".$m->address,$request->user,"mailAccount",$m->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function API_PUT(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminMailAccounts", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static();
|
||||||
|
$m->address=common::clearInput($request->requestBody->address,"0-9A-Za-z._@-");
|
||||||
|
$m->rxURL=common::clearInput($request->requestBody->rxURL,"0-9A-Za-z._:/-");
|
||||||
|
$m->txURL=common::clearInput($request->requestBody->txURL,"0-9A-Za-z._:/-");
|
||||||
|
$m->login=common::clearInput($request->requestBody->login,"0-9A-Za-z._@-");
|
||||||
|
$m->password=$request->requestBody->password;
|
||||||
|
$m->rxFolder=common::clearInput($request->requestBody->rxFolder,"0-9A-Za-z._-");
|
||||||
|
$m->rxArchiveFolder=common::clearInput($request->requestBody->rxArchiveFolder,"0-9A-Za-z._-");$m->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "Mail account ".$m->address." created",$request->user,"mailAccount",$m->id,null,logEntry::sevInfo);
|
||||||
|
return $m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function API_PATCH(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminMailAccounts", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static(common::clearInput($request->function,"0-9"));
|
||||||
|
$m->address=common::clearInput($request->requestBody->address,"0-9A-Za-z._@-");
|
||||||
|
$m->rxURL=common::clearInput($request->requestBody->rxURL,"0-9A-Za-z._:/-");
|
||||||
|
trigger_error(common::clearInput($request->requestBody->rxURL,"0-9A-Za-z._:/-"));
|
||||||
|
$m->txURL=common::clearInput($request->requestBody->txURL,"0-9A-Za-z._:/-");
|
||||||
|
$m->login=common::clearInput($request->requestBody->login,"0-9A-Za-z._@-");
|
||||||
|
if (!empty($request->requestBody->password)) { $m->password=$request->requestBody->password; }
|
||||||
|
$m->rxFolder=common::clearInput($request->requestBody->rxFolder,"0-9A-Za-z._-");
|
||||||
|
$m->rxArchiveFolder=common::clearInput($request->requestBody->rxArchiveFolder,"0-9A-Za-z._-");
|
||||||
|
$m->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "Mail account ".$m->address." updated",$request->user,"mailAccount",$m->id,null,logEntry::sevInfo,["changelog"=>"$m->changelog"]);
|
||||||
|
return $m;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -57,6 +57,7 @@ class mailBlocklist extends baseClass implements externalCallable {
|
||||||
|
|
||||||
$bl=new static();
|
$bl=new static();
|
||||||
$bl->address=$eMail;
|
$bl->address=$eMail;
|
||||||
|
static::log($request->instance,__FUNCTION__, "Address ".$eMail." added to blockList",$request->user,"eMailAddress",$eMail,null,logEntry::sevInfo);
|
||||||
$bl->save();
|
$bl->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +74,7 @@ class mailBlocklist extends baseClass implements externalCallable {
|
||||||
|
|
||||||
if ($bl = static::getByAddress($eMail)) {
|
if ($bl = static::getByAddress($eMail)) {
|
||||||
$bl->delete();
|
$bl->delete();
|
||||||
|
static::log($request->instance,__FUNCTION__, "Address ".$eMail." removed from blockList",$request->user,"eMailAddress",$eMail,null,logEntry::sevInfo);
|
||||||
foxRequestResult::throw("200", "Deleted");
|
foxRequestResult::throw("200", "Deleted");
|
||||||
} else {
|
} else {
|
||||||
foxException::throw("WARN", "Not found", 404,"ANF");
|
foxException::throw("WARN", "Not found", 404,"ANF");
|
||||||
|
|
|
@ -314,6 +314,7 @@ class moduleInfo extends baseClass implements externalCallable
|
||||||
|
|
||||||
if (empty($request->parameters[0])) {
|
if (empty($request->parameters[0])) {
|
||||||
$mod->delete();
|
$mod->delete();
|
||||||
|
static::log($request->instance,__FUNCTION__, "Module ".$mod->name." deleted",$request->user);
|
||||||
foxRequestResult::throw(200, "Deleted");
|
foxRequestResult::throw(200, "Deleted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,12 +325,14 @@ class moduleInfo extends baseClass implements externalCallable
|
||||||
unset($mod->features[$idx]);
|
unset($mod->features[$idx]);
|
||||||
$mod->features=array_values($mod->features);
|
$mod->features=array_values($mod->features);
|
||||||
$mod->save();
|
$mod->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "feature ".common::clearInput($request->requestBody->feature)." deleted from module ".$mod->name,$request->user);
|
||||||
foxRequestResult::throw(200, "Deleted");
|
foxRequestResult::throw(200, "Deleted");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "config":
|
case "config":
|
||||||
config::del(common::clearInput($request->requestBody->key), $mod->name);
|
config::del(common::clearInput($request->requestBody->key), $mod->name);
|
||||||
|
static::log($request->instance,__FUNCTION__, "config key ".common::clearInput($request->requestBody->key)." deleted from module ".$mod->name,$request->user);
|
||||||
foxRequestResult::throw(200, "Deleted");
|
foxRequestResult::throw(200, "Deleted");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -359,6 +362,7 @@ class moduleInfo extends baseClass implements externalCallable
|
||||||
$mod->features[]=common::clearInput($request->requestBody->feature);
|
$mod->features[]=common::clearInput($request->requestBody->feature);
|
||||||
$mod->features=array_values($mod->features);
|
$mod->features=array_values($mod->features);
|
||||||
$mod->save();
|
$mod->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "feature ".common::clearInput($request->requestBody->feature)." set for module ".$mod->name,$request->user,"module",$user->id,null,logEntry::sevInfo);
|
||||||
foxRequestResult::throw(201, "Created");
|
foxRequestResult::throw(201, "Created");
|
||||||
}
|
}
|
||||||
foxRequestResult::throw(201, "Created");
|
foxRequestResult::throw(201, "Created");
|
||||||
|
@ -366,6 +370,7 @@ class moduleInfo extends baseClass implements externalCallable
|
||||||
|
|
||||||
case "config":
|
case "config":
|
||||||
config::set(common::clearInput($request->requestBody->key), $request->requestBody->value, $mod->name);
|
config::set(common::clearInput($request->requestBody->key), $request->requestBody->value, $mod->name);
|
||||||
|
static::log($request->instance,__FUNCTION__, "config key ".common::clearInput($request->requestBody->key)." set for module ".$mod->name,$request->user,"module",$user->id,null,logEntry::sevInfo);
|
||||||
foxRequestResult::throw(201, "Created");
|
foxRequestResult::throw(201, "Created");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -37,6 +37,8 @@ class modules implements externalCallable
|
||||||
"adminModulesInstall"=>"Install modules",
|
"adminModulesInstall"=>"Install modules",
|
||||||
"adminUsers"=>"Manage users",
|
"adminUsers"=>"Manage users",
|
||||||
"adminUserGroups"=>"Manage userGroups",
|
"adminUserGroups"=>"Manage userGroups",
|
||||||
|
"adminMailAccounts"=>"Manage system mail accounts",
|
||||||
|
"adminAuthMethods"=>"Manage auth methods",
|
||||||
],
|
],
|
||||||
"configKeys"=> [
|
"configKeys"=> [
|
||||||
"converterURL"=>"FoxConverter URL prefix",
|
"converterURL"=>"FoxConverter URL prefix",
|
||||||
|
@ -73,10 +75,26 @@ class modules implements externalCallable
|
||||||
"ru" => "Группы",
|
"ru" => "Группы",
|
||||||
"en" => "Groups"
|
"en" => "Groups"
|
||||||
],
|
],
|
||||||
"titleLangIdx" => "adminGroups",
|
|
||||||
"function" => "groups",
|
"function" => "groups",
|
||||||
"pageKey" => "adminGrous"
|
"pageKey" => "adminGrous"
|
||||||
]
|
],
|
||||||
|
[
|
||||||
|
"title" => [
|
||||||
|
"ru" => "Учетные записи почты",
|
||||||
|
"en" => "Mail accounts"
|
||||||
|
],
|
||||||
|
"function" => "mailAccounts",
|
||||||
|
"pageKey" => "mailAccounts",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"title" => [
|
||||||
|
"ru" => "Методы oAuth",
|
||||||
|
"en" => "oAuth methods"
|
||||||
|
],
|
||||||
|
"function" => "oauth",
|
||||||
|
"pageKey" => "oauth",
|
||||||
|
],
|
||||||
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -208,7 +226,7 @@ class modules implements externalCallable
|
||||||
$mod->modPriority=$modPriority;
|
$mod->modPriority=$modPriority;
|
||||||
}
|
}
|
||||||
$mod->save();
|
$mod->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "Module ".$mod->name." installed",$request->user,"module",$mod->id,null,logEntry::sevInfo);
|
||||||
foxRequestResult::throw(201, "Created", $mod);
|
foxRequestResult::throw(201, "Created", $mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
class oAuthProfile extends baseClass implements externalCallable {
|
class oAuthProfile extends baseClass implements externalCallable {
|
||||||
protected $id;
|
protected $id;
|
||||||
public $name;
|
public $name;
|
||||||
protected $hash;
|
public $hash;
|
||||||
public $url;
|
public $url;
|
||||||
public $clientId;
|
public $clientId;
|
||||||
protected $__clientKey;
|
protected $__clientKey;
|
||||||
|
@ -45,6 +45,17 @@ class oAuthProfile extends baseClass implements externalCallable {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __set($key, $val) {
|
||||||
|
switch ($key) {
|
||||||
|
case "clientKey":
|
||||||
|
$this->__clientKey=$val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parent::__set($key, $val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getClient($redirectUrl, $scope=null) : oAuthClient {
|
public function getClient($redirectUrl, $scope=null) : oAuthClient {
|
||||||
return new oAuthClient($this->url, $this->clientId, $this->__clientKey, $redirectUrl."/".$this->hash,$scope,$this->config);
|
return new oAuthClient($this->url, $this->clientId, $this->__clientKey, $redirectUrl."/".$this->hash,$scope,$this->config);
|
||||||
}
|
}
|
||||||
|
@ -59,5 +70,81 @@ class oAuthProfile extends baseClass implements externalCallable {
|
||||||
throw new foxException("Invalid hash");
|
throw new foxException("Invalid hash");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function API_GET_list(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminAuthMethods", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
return static::search();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function APIX_GET_disable(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminAuthMethods", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static(common::clearInput($request->function,"0-9"));
|
||||||
|
$m->enabled=false;
|
||||||
|
$m->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "OAuth profile ".$m->name." disabled.",$request->user,"oAuthProfile",$m->id,null,logEntry::sevInfo);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function APIX_GET_enable(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminAuthMethods", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static(common::clearInput($request->function,"0-9"));
|
||||||
|
$m->enabled=true;
|
||||||
|
$m->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "OAuth profile ".$m->name." enabled.",$request->user,"oAuthProfile",$m->id,null,logEntry::sevInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function API_GET(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminAuthMethods", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static(common::clearInput($request->function,"0-9"));
|
||||||
|
return $m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function API_DELETE(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminAuthMethods", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static(common::clearInput($request->function,"0-9"));
|
||||||
|
$m->delete();
|
||||||
|
static::log($request->instance,__FUNCTION__, "OAuth profile ".$m->name." deleted.",$request->user,"oAuthProfile",$m->id,null,logEntry::sevInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function API_PUT(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminAuthMethods", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static();
|
||||||
|
$m->name=common::clearInput($request->requestBody->name,"0-9A-Za-z._@-");
|
||||||
|
$m->url=common::clearInput($request->requestBody->url,"0-9A-Za-z._:/-");
|
||||||
|
$m->clientId=common::clearInput($request->requestBody->clientId,"0-9A-Za-z._:/-");
|
||||||
|
$m->clientKey=common::clearInput($request->requestBody->clientKey,"0-9A-Za-z._@-");
|
||||||
|
$m->config=$request->requestBody->config;
|
||||||
|
$m->hash=common::clearInput($request->requestBody->hash,"0-9A-Za-z._@-");
|
||||||
|
$m->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "OAuth profile ".$m->name." created.",$request->user,"oAuthProfile",$m->id,null,logEntry::sevInfo);
|
||||||
|
return $m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function API_PATCH(request $request) {
|
||||||
|
if (! $request->user->checkAccess("adminAuthMethods", "core")) {
|
||||||
|
throw new foxException("Forbidden", 403);
|
||||||
|
}
|
||||||
|
$m=new static(common::clearInput($request->function,"0-9"));
|
||||||
|
$m->name=common::clearInput($request->requestBody->name,"0-9A-Za-z._@-");
|
||||||
|
$m->url=common::clearInput($request->requestBody->url,"0-9A-Za-z._:/-");
|
||||||
|
if (!empty($request->requestBody->clientId)) { $m->clientId=common::clearInput($request->requestBody->clientId,"0-9A-Za-z._:/-"); }
|
||||||
|
if (!empty($request->requestBody->clientKey)) { $m->clientKey=common::clearInput($request->requestBody->clientKey,"0-9A-Za-z._@-"); }
|
||||||
|
$m->config=$request->requestBody->config;
|
||||||
|
$m->hash=common::clearInput($request->requestBody->hash,"0-9A-Za-z._@-");
|
||||||
|
$m->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "OAuth profile ".$m->name." updated.",$request->user,"oAuthProfile",$m->id,null,logEntry::sevInfo,["changelog"=>$m->changelog]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
|
@ -325,14 +325,17 @@ class user extends baseClass implements externalCallable
|
||||||
}
|
}
|
||||||
$user = new static(common::clearInput($request->function,"0-9"));
|
$user = new static(common::clearInput($request->function,"0-9"));
|
||||||
$user->sendEMailConfirmation();
|
$user->sendEMailConfirmation();
|
||||||
|
static::log($request->instance,__FUNCTION__, "mailConfirmation sent for user ".$user->login,$request->user,"user",$user->id,null,logEntry::sevInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function API_GET_sendEMailConfirmation(request $request) {
|
public static function API_GET_sendEMailConfirmation(request $request) {
|
||||||
$request->user->sendEMailConfirmation();
|
$request->user->sendEMailConfirmation();
|
||||||
|
static::log($request->instance,__FUNCTION__, "mailConfirmation sent for user ".$user->login,$request->user,"user",$user->id,null,logEntry::sevInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function API_POST_validateEMailCode(request $request) {
|
public static function API_POST_validateEMailCode(request $request) {
|
||||||
if ($request->user->validateEMailConfirmation(common::clearInput($request->requestBody->code,"0-9"))) {
|
if ($request->user->validateEMailConfirmation(common::clearInput($request->requestBody->code,"0-9"))) {
|
||||||
|
static::log($request->instance,__FUNCTION__, "Mail address confirmed for user ".$request->user->login,$request->user,"user",$request->user->id,null,logEntry::sevInfo);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
foxException::throw("ERR", "Validation failed", 400);
|
foxException::throw("ERR", "Validation failed", 400);
|
||||||
|
|
|
@ -182,7 +182,7 @@ class userGroup extends baseClass implements externalCallable
|
||||||
$group = new static(common::clearInput($request->requestBody->groupId,"0-9"));
|
$group = new static(common::clearInput($request->requestBody->groupId,"0-9"));
|
||||||
$group->dropAccessRule(common::clearInput($request->requestBody->rule), common::clearInput($request->requestBody->module));
|
$group->dropAccessRule(common::clearInput($request->requestBody->rule), common::clearInput($request->requestBody->module));
|
||||||
$group->save();
|
$group->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "Rule ".common::clearInput($request->requestBody->rule)."@".common::clearInput($request->requestBody->module)." removed from group ".$group->name,$request->user,"userGroup",$group->id,null,logEntry::sevInfo);
|
||||||
foxRequestResult::throw(200, "Deleted");
|
foxRequestResult::throw(200, "Deleted");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -194,6 +194,7 @@ class userGroup extends baseClass implements externalCallable
|
||||||
}
|
}
|
||||||
$group = new static(common::clearInput($request->requestBody->groupId,"0-9"));
|
$group = new static(common::clearInput($request->requestBody->groupId,"0-9"));
|
||||||
$group->addAccessRule(common::clearInput($request->requestBody->rule), ($request->requestBody->forAll=="1")?"<all>":common::clearInput($request->requestBody->module));
|
$group->addAccessRule(common::clearInput($request->requestBody->rule), ($request->requestBody->forAll=="1")?"<all>":common::clearInput($request->requestBody->module));
|
||||||
|
static::log($request->instance,__FUNCTION__, "Rule ".common::clearInput($request->requestBody->rule)."@".common::clearInput($request->requestBody->module)." added for group ".$group->name,$request->user,"userGroup",$group->id,null,logEntry::sevInfo);
|
||||||
$group->save();
|
$group->save();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -233,6 +234,7 @@ class userGroup extends baseClass implements externalCallable
|
||||||
$group->name=$grName;
|
$group->name=$grName;
|
||||||
$group->isList=$request->requestBody->isList==1;
|
$group->isList=$request->requestBody->isList==1;
|
||||||
$group->save();
|
$group->save();
|
||||||
|
static::log($request->instance,__FUNCTION__, "UserGroup ".$group->name." created.",$request->user,"userGroup",$group->id,null,logEntry::sevInfo);
|
||||||
foxRequestResult::throw(201, "Created",$group);
|
foxRequestResult::throw(201, "Created",$group);
|
||||||
break;
|
break;
|
||||||
case "DELETE":
|
case "DELETE":
|
||||||
|
@ -242,6 +244,8 @@ class userGroup extends baseClass implements externalCallable
|
||||||
}
|
}
|
||||||
|
|
||||||
$group->delete();
|
$group->delete();
|
||||||
|
static::log($request->instance,__FUNCTION__, "UserGroup ".$group->name." deleted.",$request->user,"userGroup",$group->id,null,logEntry::sevInfo);
|
||||||
|
|
||||||
throw new foxRequestResult("Deleted",200);
|
throw new foxRequestResult("Deleted",200);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -212,6 +212,7 @@ class userGroupMembership extends baseClass implements externalCallable
|
||||||
$userGroupMembership->groupId=$userGroup->id;
|
$userGroupMembership->groupId=$userGroup->id;
|
||||||
$userGroupMembership->save();
|
$userGroupMembership->save();
|
||||||
$user->flushACRCache();
|
$user->flushACRCache();
|
||||||
|
static::log($request->instance,__FUNCTION__, "User ".$user->login ." join group ".$userGroup->name,$request->user,"user",$user->id,null,logEntry::sevInfo);
|
||||||
foxRequestResult::throw("201", "Created");
|
foxRequestResult::throw("201", "Created");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -219,6 +220,8 @@ class userGroupMembership extends baseClass implements externalCallable
|
||||||
if ($userGroupMembership==null) {
|
if ($userGroupMembership==null) {
|
||||||
foxException::throw("ERR", "Not found", 404, "UGN");
|
foxException::throw("ERR", "Not found", 404, "UGN");
|
||||||
}
|
}
|
||||||
|
static::log($request->instance,__FUNCTION__, "User ".$userGroupMembership->user->login ." left group ".$userGroupMembership->group->name,$request->user,"user",$userGroupMembership->user->id,null,logEntry::sevInfo);
|
||||||
|
|
||||||
$userGroupMembership->delete();
|
$userGroupMembership->delete();
|
||||||
$user->flushACRCache();
|
$user->flushACRCache();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -112,7 +112,7 @@ class userInvitation extends baseClass implements externalCallable {
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
trigger_error($e->getMessage());
|
trigger_error($e->getMessage());
|
||||||
}
|
}
|
||||||
|
static::log($request->instance,__FUNCTION__, "User invitation ".$inv->regCode." created.",$request->user,"userInvitation",$inv->id,null,logEntry::sevInfo);
|
||||||
return $inv;
|
return $inv;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -127,6 +127,7 @@ class userInvitation extends baseClass implements externalCallable {
|
||||||
}
|
}
|
||||||
$inv=new static(common::clearInput($request->function));
|
$inv=new static(common::clearInput($request->function));
|
||||||
$inv->sendEmail();
|
$inv->sendEmail();
|
||||||
|
static::log($request->instance,__FUNCTION__, "User invitation ".$inv->regCode." email resent.",$request->user,"userInvitation",$inv->id,null,logEntry::sevInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function API_DELETE(request $request) {
|
public static function API_DELETE(request $request) {
|
||||||
|
@ -135,6 +136,7 @@ class userInvitation extends baseClass implements externalCallable {
|
||||||
}
|
}
|
||||||
$inv=new static(common::clearInput($request->function));
|
$inv=new static(common::clearInput($request->function));
|
||||||
$inv->delete();
|
$inv->delete();
|
||||||
|
static::log($request->instance,__FUNCTION__, "User invitation ".$inv->regCode." deleted.",$request->user,"userInvitation",$inv->id,null,logEntry::sevInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ function btnGroupAdd_click() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function btnGroupDel_click(ref) {
|
function btnGroupDel_click(ref) {
|
||||||
var gid=($(ref.currentTarget).attr("groupId"));
|
var gid=($(ref.target).closest("tr").attr("groupId"));
|
||||||
var buttons={};
|
var buttons={};
|
||||||
buttons[langPack.core.iface.dialodDelButton]=function() {
|
buttons[langPack.core.iface.dialodDelButton]=function() {
|
||||||
$("#dialogInfo").dialog("close");
|
$("#dialogInfo").dialog("close");
|
||||||
|
@ -115,5 +115,5 @@ function btnGroupDel_click(ref) {
|
||||||
|
|
||||||
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
||||||
|
|
||||||
UI.showInfoDialog(langPack.core.iface.groups.delButtonTitle+" #"+gid+" "+$(ref.currentTarget).attr("xname"),langPack.core.iface.groups.delButtonTitle,buttons);
|
UI.showInfoDialog(langPack.core.iface.groups.delButtonTitle+" #"+gid+" "+$(ref.target).closest("tr").attr("xname"),langPack.core.iface.groups.delButtonTitle,buttons);
|
||||||
}
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
export function load() {
|
||||||
|
UI.breadcrumbsUpdate(langPack.core.breadcrumbs.modTitle+" / "+langPack.core.breadcrumbs.mailAccounts);
|
||||||
|
|
||||||
|
UI.createTabsPanel({
|
||||||
|
accounts:{"title":langPack.core.iface.mailAccounts.allTitle, preLoad: reloadList,buttons: UI.addButton({id: "btn_acctadd",icon: "fas fa-plus",title: langPack.core.iface.mailAccounts.addButtonTitle, onClick: btnAccAdd_click})},
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function btnAccAdd_click(ref) {
|
||||||
|
var buttons={};
|
||||||
|
buttons[langPack.core.iface.add]=async function() {
|
||||||
|
let fdata=UI.collectForm("addgrp", true,false, false,true);
|
||||||
|
if (fdata.validateErrCount==0) {
|
||||||
|
API.exec({
|
||||||
|
errDict: langPack.core.iface.register.errors,
|
||||||
|
requestType: "PUT",
|
||||||
|
data: {
|
||||||
|
address: fdata.address.val,
|
||||||
|
rxURL: fdata.rxUrl.val,
|
||||||
|
txURL: fdata.txUrl.val,
|
||||||
|
login: fdata.login.val,
|
||||||
|
password: fdata.passwd.val,
|
||||||
|
rxFolder: fdata.rxInbox.val,
|
||||||
|
rxArchiveFolder: fdata.rxArchive.val,
|
||||||
|
},
|
||||||
|
method: "core/mailAccount",
|
||||||
|
onSuccess: function(json) {
|
||||||
|
UI.closeDialog('addgrp');
|
||||||
|
reloadList();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
buttons[langPack.core.iface.dialodCloseButton]=function() { UI.closeDialog('addgrp');}
|
||||||
|
|
||||||
|
|
||||||
|
UI.createDialog(
|
||||||
|
UI.addFieldGroup([
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.address, type: "input", item: "acc_address", reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.login, type: "input", item: "acc_login",reqx:false}),
|
||||||
|
UI.addField({title: langPack.core.iface.password, type: "passwordNew", item: "acc_passwd",reqx:false}),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.rxURL, type: "input", item: "acc_rxUrl",reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.txURL, type: "input", item: "acc_txUrl",reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.rxFolder, type: "input", item: "reg_rxInbox",reqx: true, val: "INBOX" }),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.archiveFolder, type: "input", item: "reg_rxArchive",reqx:true, val: "Archive"}),
|
||||||
|
|
||||||
|
]),
|
||||||
|
langPack.core.iface.add,
|
||||||
|
buttons,
|
||||||
|
515,1,'addgrp');
|
||||||
|
|
||||||
|
UI.openDialog('addgrp');
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadList() {
|
||||||
|
$("div.widget.accounts").empty();
|
||||||
|
API.exec("GET","core/mailAccount/list",{},function(json) {
|
||||||
|
let tx = $("<table>",{class: "datatable sel"});
|
||||||
|
$("<th>",{class: "idx", text: "#"}).appendTo(tx);
|
||||||
|
$("<th>",{class: "", text: langPack.core.iface.mailAccounts.address}).appendTo(tx);
|
||||||
|
$("<th>",{class: "", text: langPack.core.iface.mailAccounts.login}).appendTo(tx);
|
||||||
|
$("<th>",{class: "", text: langPack.core.iface.mailAccounts.module}).appendTo(tx);
|
||||||
|
$("<th>",{class: "", text: langPack.core.iface.mailAccounts.default}).appendTo(tx);
|
||||||
|
$("<th>",{class: "button", style: "text-align: center", append: $("<i>",{class: "fas fa-ellipsis-h"})}).appendTo(tx);
|
||||||
|
|
||||||
|
tx.appendTo("div.widget.accounts");
|
||||||
|
|
||||||
|
let i=0;
|
||||||
|
$.each(json.data, function(idx, acc) {
|
||||||
|
i++;
|
||||||
|
let row=$("<tr>",{}).bind('contextmenu', mliContextMenuOpen).addClass("contextMenu").attr("accId",acc.id).attr("accAddr",acc.address);
|
||||||
|
$("<td>",{class: "idx", text: i}).appendTo(row);
|
||||||
|
$("<td>",{class: "", text: acc.address}).appendTo(row);
|
||||||
|
$("<td>",{class: "", text: acc.login}).appendTo(row);
|
||||||
|
$("<td>",{class: "", text: acc.module}).appendTo(row);
|
||||||
|
$("<td>",{class: "", text: acc.default?langPack.core.iface.yes:langPack.core.iface.no}).appendTo(row);
|
||||||
|
$("<td>",{class: "button", style: "text-align: center", append: $("<i>",{class: "fas fa-ellipsis-h"})})
|
||||||
|
.click(mliContextMenuOpen)
|
||||||
|
.appendTo(row);
|
||||||
|
$("<tbody>",{append: row}).appendTo(tx);
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function mliContextMenuOpen(el) {
|
||||||
|
UI.contextMenuOpen(el,[
|
||||||
|
{title: langPack.core.iface.mailAccounts.setDefault, onClick: function() {
|
||||||
|
accDefault_Click(el);
|
||||||
|
}},
|
||||||
|
{title: langPack.core.iface.edit, onClick: function() {
|
||||||
|
accEdit_Click(el);
|
||||||
|
}},
|
||||||
|
|
||||||
|
{title: langPack.core.iface.delete, onClick: function() {
|
||||||
|
accDelete_Click(el);
|
||||||
|
}},
|
||||||
|
|
||||||
|
],$(el.target).closest("tr").attr("accaddr"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function accDelete_Click(ref) {
|
||||||
|
var acid=($(ref.target).closest("tr").attr("accid"));
|
||||||
|
var buttons={};
|
||||||
|
buttons[langPack.core.iface.dialodDelButton]=function() {
|
||||||
|
$("#dialogInfo").dialog("close");
|
||||||
|
API.exec({
|
||||||
|
requestType: "DELETE",
|
||||||
|
method: "core/mailAccount/"+acid,
|
||||||
|
onSuccess: function(json) {
|
||||||
|
reloadList();
|
||||||
|
},
|
||||||
|
errDict: langPack.core.iface.mailAccounts.errors,
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
||||||
|
|
||||||
|
UI.showInfoDialog(langPack.core.iface.mailAccounts.delDialogText+" #"+acid+" "+$(ref.target).closest("tr").attr("accAddr"),langPack.core.iface.delete,buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
function accDefault_Click(ref) {
|
||||||
|
var acid=($(ref.target).closest("tr").attr("accid"));
|
||||||
|
var buttons={};
|
||||||
|
buttons[langPack.core.iface.set]=function() {
|
||||||
|
$("#dialogInfo").dialog("close");
|
||||||
|
API.exec({
|
||||||
|
requestType: "GET",
|
||||||
|
method: "core/mailAccount/"+acid+"/setDefault",
|
||||||
|
onSuccess: function(json) {
|
||||||
|
reloadList();
|
||||||
|
},
|
||||||
|
errDict: langPack.core.iface.mailAccounts.errors,
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
||||||
|
|
||||||
|
UI.showInfoDialog(langPack.core.iface.mailAccounts.setDefaultDialogText+" #"+acid+" "+$(ref.target).closest("tr").attr("accAddr"),langPack.core.iface.set,buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
function accEdit_Click(ref) {
|
||||||
|
var buttons={};
|
||||||
|
var acid=($(ref.target).closest("tr").attr("accid"));
|
||||||
|
|
||||||
|
buttons[langPack.core.iface.add]=async function() {
|
||||||
|
let fdata=UI.collectForm("addgrp", true,false, false,true);
|
||||||
|
if (fdata.validateErrCount==0) {
|
||||||
|
API.exec({
|
||||||
|
errDict: langPack.core.iface.register.errors,
|
||||||
|
requestType: "PATCH",
|
||||||
|
data: {
|
||||||
|
address: fdata.address.val,
|
||||||
|
rxURL: fdata.rxUrl.val,
|
||||||
|
txURL: fdata.txUrl.val,
|
||||||
|
login: fdata.login.val,
|
||||||
|
password: fdata.passwd.val,
|
||||||
|
rxFolder: fdata.rxInbox.val,
|
||||||
|
rxArchiveFolder: fdata.rxArchive.val,
|
||||||
|
},
|
||||||
|
method: "core/mailAccount/"+acid,
|
||||||
|
onSuccess: function(json) {
|
||||||
|
UI.closeDialog('addgrp');
|
||||||
|
reloadList();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
buttons[langPack.core.iface.dialodCloseButton]=function() { UI.closeDialog('addgrp');}
|
||||||
|
|
||||||
|
|
||||||
|
UI.createDialog(
|
||||||
|
UI.addFieldGroup([
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.address, type: "input", item: "acc_address", reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.login, type: "input", item: "acc_login",reqx:false}),
|
||||||
|
UI.addField({title: langPack.core.iface.password, type: "passwordNew", item: "acc_passwd",reqx:false}),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.rxURL, type: "input", item: "acc_rxUrl",reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.txURL, type: "input", item: "acc_txUrl",reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.rxFolder, type: "input", item: "reg_rxInbox",reqx: true, val: "INBOX" }),
|
||||||
|
UI.addField({title: langPack.core.iface.mailAccounts.archiveFolder, type: "input", item: "reg_rxArchive",reqx:true, val: "Archive"}),
|
||||||
|
|
||||||
|
]),
|
||||||
|
langPack.core.iface.add,
|
||||||
|
buttons,
|
||||||
|
515,1,'addgrp');
|
||||||
|
|
||||||
|
API.exec({
|
||||||
|
errDict: langPack.core.iface.register.errors,
|
||||||
|
requestType: "GET",
|
||||||
|
method: "core/mailAccount/"+acid,
|
||||||
|
onSuccess: function(json) {
|
||||||
|
$("#acc_address").val(json.data.address);
|
||||||
|
$("#acc_login").val(json.data.login);
|
||||||
|
$("#acc_rxUrl").val(json.data.rxProto+(json.data.rxSSL?"s":"")+"://"+json.data.rxServer+":"+json.data.rxPort);
|
||||||
|
$("#acc_txUrl").val(json.data.txProto+(json.data.txSSL?"s":"")+"://"+json.data.txServer+":"+json.data.txPort);
|
||||||
|
$("#reg_rxInbox").val(json.data.rxFolder);
|
||||||
|
$("#reg_rxArchive").val(json.data.rxArchiveFolder);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
UI.openDialog('addgrp');
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ export var menuSelector={
|
||||||
"module":"adminModules",
|
"module":"adminModules",
|
||||||
"users":"adminUsers",
|
"users":"adminUsers",
|
||||||
"group":"adminGrous",
|
"group":"adminGrous",
|
||||||
|
mailAccounts:"mailAccounts",
|
||||||
|
oauth: "oauth",
|
||||||
};
|
};
|
||||||
|
|
||||||
export function load() {
|
export function load() {
|
||||||
|
@ -59,6 +61,16 @@ export function load() {
|
||||||
mod.load();
|
mod.load();
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
|
case "mailAccounts":
|
||||||
|
import("./coreMailAccounts.js").then(function(mod) {
|
||||||
|
mod.load();
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case "oauth":
|
||||||
|
import("./coreOAuthProfiles.js").then(function(mod) {
|
||||||
|
mod.load();
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
export function load() {
|
||||||
|
UI.breadcrumbsUpdate(langPack.core.breadcrumbs.modTitle+" / "+langPack.core.breadcrumbs.oauth);
|
||||||
|
|
||||||
|
UI.createTabsPanel({
|
||||||
|
methods:{"title":langPack.core.iface.oauth.allTitle, preLoad: reloadList,buttons: UI.addButton({id: "btn_acctadd",icon: "fas fa-plus",title: langPack.core.iface.oauth.addButtonTitle, onClick: btnAdd_click})},
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadList(ref) {
|
||||||
|
$("div.widget.methods").empty();
|
||||||
|
API.exec("GET","core/oAuthProfile/list",{},function(json) {
|
||||||
|
let tx = $("<table>",{class: "datatable sel"});
|
||||||
|
$("<th>",{class: "idx", text: "#"}).appendTo(tx);
|
||||||
|
$("<th>",{class: "", text: langPack.core.iface.title}).appendTo(tx);
|
||||||
|
$("<th>",{class: "", text: langPack.core.iface.url}).appendTo(tx);
|
||||||
|
$("<th>",{class: "", text: langPack.core.iface.active}).appendTo(tx);
|
||||||
|
$("<th>",{class: "button", style: "text-align: center", append: $("<i>",{class: "fas fa-ellipsis-h"})}).appendTo(tx);
|
||||||
|
|
||||||
|
tx.appendTo("div.widget.methods");
|
||||||
|
|
||||||
|
let i=0;
|
||||||
|
$.each(json.data, function(idx, acc) {
|
||||||
|
i++;
|
||||||
|
let row=$("<tr>",{}).bind('contextmenu', mliContextMenuOpen).addClass("contextMenu").attr("accActive",acc.enabled?1:0).attr("accHash",acc.hash).attr("accId",acc.id).attr("accName",acc.name);
|
||||||
|
$("<td>",{class: "idx", text: i}).appendTo(row);
|
||||||
|
$("<td>",{class: "", text: acc.name}).appendTo(row);
|
||||||
|
$("<td>",{class: "", text: acc.url}).appendTo(row);
|
||||||
|
$("<td>",{class: "", text: acc.enabled?langPack.core.iface.yes:langPack.core.iface.no}).appendTo(row);
|
||||||
|
$("<td>",{class: "button", style: "text-align: center", append: $("<i>",{class: "fas fa-ellipsis-h"})})
|
||||||
|
.click(mliContextMenuOpen)
|
||||||
|
.appendTo(row);
|
||||||
|
$("<tbody>",{append: row}).appendTo(tx);
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function mliContextMenuOpen(el) {
|
||||||
|
|
||||||
|
let menuItems=[];
|
||||||
|
let menuOnOff;
|
||||||
|
if ($(el.target).closest("tr").attr("accActive")==1) {
|
||||||
|
menuOnOff= {title: langPack.core.iface.disable, onClick: function() { profileDisable_Click(el) ; }};
|
||||||
|
} else {
|
||||||
|
menuOnOff= {title: langPack.core.iface.enable, onClick: function() { profileEnable_Click(el);}};
|
||||||
|
}
|
||||||
|
menuItems.push(
|
||||||
|
{title: "CopyURL", onClick: function() { UI.copySelText(getCallbackUrl($(el.target).closest("tr").attr("accHash")));}},
|
||||||
|
menuOnOff,
|
||||||
|
{title: langPack.core.iface.edit, onClick: function() { profileEdit_Click(el); }},
|
||||||
|
{title: langPack.core.iface.delete, onClick: function() { profileDelete_Click(el);}},
|
||||||
|
);
|
||||||
|
UI.contextMenuOpen(el,menuItems,$(el.target).closest("tr").attr("accName"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function profileDisable_Click(ref) {
|
||||||
|
var acid=($(ref.target).closest("tr").attr("accId"));
|
||||||
|
var buttons={};
|
||||||
|
buttons[langPack.core.iface.disable]=function() {
|
||||||
|
$("#dialogInfo").dialog("close");
|
||||||
|
API.exec({
|
||||||
|
requestType: "GET",
|
||||||
|
method: "core/oAuthProfile/"+acid+"/disable",
|
||||||
|
onSuccess: function(json) {
|
||||||
|
reloadList();
|
||||||
|
},
|
||||||
|
errDict: langPack.core.iface.oauth.errors,
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
||||||
|
|
||||||
|
UI.showInfoDialog(langPack.core.iface.disable+" #"+acid+" "+$(ref.target).closest("tr").attr("accName"),langPack.core.iface.disable,buttons);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function profileEnable_Click(ref) {
|
||||||
|
var acid=($(ref.target).closest("tr").attr("accid"));
|
||||||
|
var buttons={};
|
||||||
|
buttons[langPack.core.iface.enable]=function() {
|
||||||
|
$("#dialogInfo").dialog("close");
|
||||||
|
API.exec({
|
||||||
|
requestType: "GET",
|
||||||
|
method: "core/oAuthProfile/"+acid+"/enable",
|
||||||
|
onSuccess: function(json) {
|
||||||
|
reloadList();
|
||||||
|
},
|
||||||
|
errDict: langPack.core.iface.oauth.errors,
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
||||||
|
|
||||||
|
UI.showInfoDialog(langPack.core.iface.enable+" #"+acid+" "+$(ref.target).closest("tr").attr("accName"),langPack.core.iface.enable,buttons);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function profileDelete_Click(ref) {
|
||||||
|
var acid=($(ref.target).closest("tr").attr("accid"));
|
||||||
|
var buttons={};
|
||||||
|
buttons[langPack.core.iface.delete]=function() {
|
||||||
|
$("#dialogInfo").dialog("close");
|
||||||
|
API.exec({
|
||||||
|
requestType: "DELETE",
|
||||||
|
method: "core/oAuthProfile/"+acid,
|
||||||
|
onSuccess: function(json) {
|
||||||
|
reloadList();
|
||||||
|
},
|
||||||
|
errDict: langPack.core.iface.oauth.errors,
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
||||||
|
|
||||||
|
UI.showInfoDialog(langPack.core.iface.delete+" #"+acid+" "+$(ref.target).closest("tr").attr("accName"),langPack.core.iface.delete,buttons);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function btnAdd_click(ref) {
|
||||||
|
var buttons={};
|
||||||
|
var hash=UI.genPassword("0123456789abcdef", 64);
|
||||||
|
buttons[langPack.core.iface.add]=async function() {
|
||||||
|
let fdata=UI.collectForm("addgrp", true,false, false,true);
|
||||||
|
if (fdata.validateErrCount==0) {
|
||||||
|
API.exec({
|
||||||
|
errDict: langPack.core.iface.register.errors,
|
||||||
|
requestType: "PUT",
|
||||||
|
data: {
|
||||||
|
name: fdata.name.val,
|
||||||
|
url: fdata.url.val,
|
||||||
|
clientId: fdata.clientId.val,
|
||||||
|
clientKey: fdata.clientKey.val,
|
||||||
|
config: fdata.type.val,
|
||||||
|
hash: hash,
|
||||||
|
},
|
||||||
|
method: "core/oAuthProfile",
|
||||||
|
onSuccess: function(json) {
|
||||||
|
UI.closeDialog('addgrp');
|
||||||
|
reloadList();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
buttons[langPack.core.iface.dialodCloseButton]=function() { UI.closeDialog('addgrp');}
|
||||||
|
|
||||||
|
|
||||||
|
UI.createDialog(
|
||||||
|
UI.addFieldGroup([
|
||||||
|
UI.addField({title: langPack.core.iface.title, type: "input", item: "acc_name", reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.url, type: "input", item: "acc_url",reqx:false}),
|
||||||
|
UI.addField({title: langPack.core.iface.template, type: "select", item: "acc_type",reqx:true, args: {"":"--"+langPack.core.iface.oauth.selectPreset+"--","vk":"VK","yandex":"Yandex", "gitea":"Gitea", "gitlab":"Gitlab"}}),
|
||||||
|
UI.addField({title: langPack.core.iface.oauth.callback, type: "multiline", args: {rows: 4}, item: "acc_callbackurl", disabled: true, val: "callback"}),
|
||||||
|
UI.addField({title: langPack.core.iface.oauth.clientId, type: "input", item: "acc_clientId",reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.oauth.clientKey, type: "input", item: "acc_clientKey",reqx:true}),
|
||||||
|
]),
|
||||||
|
langPack.core.iface.add,
|
||||||
|
buttons,
|
||||||
|
515,1,'addgrp');
|
||||||
|
$("#acc_callbackurl").val(getCallbackUrl(hash));
|
||||||
|
UI.openDialog('addgrp');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCallbackUrl(hash) {
|
||||||
|
return API.settings.get("sitePrefix")+"/auth/oauth/"+hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
function profileEdit_Click(ref) {
|
||||||
|
var acid=($(ref.target).closest("tr").attr("accid"));
|
||||||
|
var buttons={};
|
||||||
|
buttons[langPack.core.iface.edit]=async function() {
|
||||||
|
let fdata=UI.collectForm("addgrp", true,false, false,true);
|
||||||
|
if (fdata.validateErrCount==0) {
|
||||||
|
API.exec({
|
||||||
|
errDict: langPack.core.iface.register.errors,
|
||||||
|
requestType: "PATCH",
|
||||||
|
data: {
|
||||||
|
name: fdata.name.val,
|
||||||
|
url: fdata.url.val,
|
||||||
|
clientId: fdata.clientId.val,
|
||||||
|
clientKey: fdata.clientKey.val,
|
||||||
|
config: fdata.type.val,
|
||||||
|
},
|
||||||
|
method: "core/oAuthProfile/"+acid,
|
||||||
|
onSuccess: function(json) {
|
||||||
|
UI.closeDialog('addgrp');
|
||||||
|
reloadList();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
buttons[langPack.core.iface.dialodCloseButton]=function() { UI.closeDialog('addgrp');}
|
||||||
|
|
||||||
|
|
||||||
|
UI.createDialog(
|
||||||
|
UI.addFieldGroup([
|
||||||
|
UI.addField({title: langPack.core.iface.title, type: "input", item: "acc_name", reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.url, type: "input", item: "acc_url",reqx:false}),
|
||||||
|
UI.addField({title: langPack.core.iface.template, type: "select", item: "acc_type",reqx:true, args: {"":"--"+langPack.core.iface.oauth.selectPreset+"--","vk":"VK","yandex":"Yandex", "gitea":"Gitea", "gitlab":"Gitlab"}}),
|
||||||
|
UI.addField({title: langPack.core.iface.oauth.clientId, type: "input", item: "acc_clientId",reqx:true}),
|
||||||
|
UI.addField({title: langPack.core.iface.oauth.clientKey, type: "input", item: "acc_clientKey",reqx:false}),
|
||||||
|
]),
|
||||||
|
langPack.core.iface.add,
|
||||||
|
buttons,
|
||||||
|
385,1,'addgrp');
|
||||||
|
API.exec({
|
||||||
|
errDict: langPack.core.iface.register.errors,
|
||||||
|
requestType: "GET",
|
||||||
|
method: "core/oAuthProfile/"+acid,
|
||||||
|
onSuccess: function(json) {
|
||||||
|
$("#acc_name").val(json.data.name);
|
||||||
|
$("#acc_url").val(json.data.url);
|
||||||
|
$("#acc_type").val(json.data.config);
|
||||||
|
$("#acc_clientId").val(json.data.clientId);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
UI.openDialog('addgrp');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ export var langItem={
|
||||||
ok0: "Операция завершена успешно",
|
ok0: "Операция завершена успешно",
|
||||||
dataEmpty: "Информация недоступна, скорее здесь ничего нет.",
|
dataEmpty: "Информация недоступна, скорее здесь ничего нет.",
|
||||||
emptyInvCode: "-нет-",
|
emptyInvCode: "-нет-",
|
||||||
|
enable: "Активировать",
|
||||||
|
disable: "Заблокировать",
|
||||||
dataLoading: "Информация загружается",
|
dataLoading: "Информация загружается",
|
||||||
loginFailedDialogTitle: "Ошибка авторизации",
|
loginFailedDialogTitle: "Ошибка авторизации",
|
||||||
loginFailed401text: "Неправильные имя пользователя или пароль\nУточните данные и попробуйте еще раз",
|
loginFailed401text: "Неправильные имя пользователя или пароль\nУточните данные и попробуйте еще раз",
|
||||||
|
@ -17,10 +19,12 @@ export var langItem={
|
||||||
active: "Активен",
|
active: "Активен",
|
||||||
version: "Версия",
|
version: "Версия",
|
||||||
title: "Наименование",
|
title: "Наименование",
|
||||||
|
url: "URL",
|
||||||
desc: "Описание",
|
desc: "Описание",
|
||||||
installed: "Установлен",
|
installed: "Установлен",
|
||||||
install: "Установить",
|
install: "Установить",
|
||||||
set: "Установить",
|
set: "Установить",
|
||||||
|
edit: "Изменить",
|
||||||
updated: "Обновлен",
|
updated: "Обновлен",
|
||||||
invCode: "invCode",
|
invCode: "invCode",
|
||||||
dialodCloseButton: "Закрыть",
|
dialodCloseButton: "Закрыть",
|
||||||
|
@ -132,6 +136,34 @@ export var langItem={
|
||||||
URNF: "Пользователь не найден либо восстановление пароля не предусмотрено спосбом авторизации",
|
URNF: "Пользователь не найден либо восстановление пароля не предусмотрено спосбом авторизации",
|
||||||
IVCC: "Некорректный код подтверждения. Проверьте правильность кода и повторите попытку.",
|
IVCC: "Некорректный код подтверждения. Проверьте правильность кода и повторите попытку.",
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
mailAccounts: {
|
||||||
|
allTitle: "Учетные записи электронной почты",
|
||||||
|
addButtonTitle: "Добавить УЗ",
|
||||||
|
address: "Адрес",
|
||||||
|
login: "Логин",
|
||||||
|
module: "Модуль",
|
||||||
|
rxURL: "RX URL",
|
||||||
|
txURL: "TX URL",
|
||||||
|
rxFolder: "Входящие",
|
||||||
|
archiveFolder: "Архив",
|
||||||
|
default: "Основной",
|
||||||
|
setDefault: "Сделать основным",
|
||||||
|
delDialogText: "Удалить аккаунт",
|
||||||
|
setDefaultDialogText: "Установить основным аккаунт",
|
||||||
|
errors: {
|
||||||
|
DDAX: "Нельзя удалить основной аккаунт",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
oauth: {
|
||||||
|
allTitle: "Методы oAuth",
|
||||||
|
addButtonTitle: "Добавить метод",
|
||||||
|
clientId: "ID Клиента",
|
||||||
|
clientKey: "Секретный ключ",
|
||||||
|
callback: "URL возврата",
|
||||||
|
selectPreset: "Выберите шаблон",
|
||||||
|
errors: {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -140,7 +172,9 @@ export var langItem={
|
||||||
modules: "Модули",
|
modules: "Модули",
|
||||||
users: "Пользователи",
|
users: "Пользователи",
|
||||||
groups: "Группы",
|
groups: "Группы",
|
||||||
myprofile: "Мой профиль"
|
myprofile: "Мой профиль",
|
||||||
|
mailAccounts: "Учетные записи ЭП",
|
||||||
|
oauth: "oAuth",
|
||||||
|
|
||||||
},
|
},
|
||||||
date: {
|
date: {
|
||||||
|
|
|
@ -3,7 +3,8 @@ import * as UI from './ui.js';
|
||||||
import { langPack, lpCacheDrop } from './langpack.js';
|
import { langPack, lpCacheDrop } from './langpack.js';
|
||||||
|
|
||||||
export function load() {
|
export function load() {
|
||||||
$("body").empty();
|
$("body").empty().addClass("login");
|
||||||
|
$("html").addClass("login");
|
||||||
|
|
||||||
if (UI.parceURL().module=='auth' && UI.parceURL().function=='oauth') {
|
if (UI.parceURL().module=='auth' && UI.parceURL().function=='oauth') {
|
||||||
let hash = UI.parceURL().id;
|
let hash = UI.parceURL().id;
|
||||||
|
|
|
@ -295,7 +295,7 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
||||||
let password=genPassword();
|
let password=genPassword();
|
||||||
$("#"+item_id).val(password);
|
$("#"+item_id).val(password);
|
||||||
$("#"+item_id).change();
|
$("#"+item_id).change();
|
||||||
if (typeof(ref.newPasswdGenCallback)) {
|
if (typeof(ref.newPasswdGenCallback)=="function") {
|
||||||
ref.newPasswdGenCallback(password);
|
ref.newPasswdGenCallback(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,8 +763,8 @@ export function setTitle(title, desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initBody() {
|
export function initBody() {
|
||||||
|
$("html").removeClass("login");
|
||||||
$("body").empty();
|
$("body").empty().removeClass("login");
|
||||||
$("<div>",{id: "contextMenu", class: "contextMenu"}).appendTo("body").hide();
|
$("<div>",{id: "contextMenu", class: "contextMenu"}).appendTo("body").hide();
|
||||||
$("<div>", { class: "t_global"})
|
$("<div>", { class: "t_global"})
|
||||||
.appendTo("body")
|
.appendTo("body")
|
||||||
|
|
|
@ -1518,6 +1518,10 @@ div.t_main
|
||||||
width: 1681px;
|
width: 1681px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.mainfame {
|
||||||
|
width: 1676px;
|
||||||
|
}
|
||||||
|
|
||||||
div.t_global
|
div.t_global
|
||||||
{
|
{
|
||||||
width: 1881px;
|
width: 1881px;
|
||||||
|
@ -1848,6 +1852,10 @@ div.t_main
|
||||||
width: 1360px;
|
width: 1360px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div#mainframe {
|
||||||
|
width: 1343px !important;
|
||||||
|
}
|
||||||
|
|
||||||
div.t_global
|
div.t_global
|
||||||
{
|
{
|
||||||
width: 1560px;
|
width: 1560px;
|
||||||
|
@ -1926,6 +1934,10 @@ div.t_main
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div#mainframe {
|
||||||
|
width: 1022px !important;
|
||||||
|
}
|
||||||
|
|
||||||
div.t_global
|
div.t_global
|
||||||
{
|
{
|
||||||
width: 1239px;
|
width: 1239px;
|
||||||
|
@ -2039,6 +2051,10 @@ div.t_main
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div#mainframe {
|
||||||
|
width: 1022px !important;
|
||||||
|
}
|
||||||
|
|
||||||
div.t_global
|
div.t_global
|
||||||
{
|
{
|
||||||
width: 1035px;
|
width: 1035px;
|
||||||
|
@ -2135,6 +2151,10 @@ div.t_main
|
||||||
width: 710px;
|
width: 710px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div#mainframe {
|
||||||
|
width: 699px !important;
|
||||||
|
}
|
||||||
|
|
||||||
div.t_global
|
div.t_global
|
||||||
{
|
{
|
||||||
width: 710px;
|
width: 710px;
|
||||||
|
|
Loading…
Reference in New Issue