S3 files, unAuth methods in API, bugifx
s3 files download, packages version fix, oauth fix, time intervals,
This commit is contained in:
parent
872da83978
commit
f59fdf61ca
|
@ -0,0 +1,111 @@
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: SonarQube check
|
||||||
|
|
||||||
|
image_pull_secrets:
|
||||||
|
- dockerconfig
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- develop
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- custom
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: SonarQube check
|
||||||
|
image: sonarsource/sonar-scanner-cli
|
||||||
|
environment:
|
||||||
|
SONAR_PROJECT:
|
||||||
|
from_secret: sonarProjectId
|
||||||
|
SONAR_TOKEN:
|
||||||
|
from_secret: sonarToken
|
||||||
|
SONAR_HOST:
|
||||||
|
from_secret: sonarHost
|
||||||
|
TEST: test
|
||||||
|
|
||||||
|
commands:
|
||||||
|
- sonar-scanner -Dsonar.projectKey=$${SONAR_PROJECT} -Dsonar.sources=. -Dsonar.host.url=$${SONAR_HOST} -Dsonar.login=$${SONAR_TOKEN}
|
||||||
|
depends_on:
|
||||||
|
- clone
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: Build image
|
||||||
|
|
||||||
|
image_pull_secrets:
|
||||||
|
- dockerconfig
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/heads/testing
|
||||||
|
- refs/heads/master
|
||||||
|
- refs/tags/*
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Prepare image
|
||||||
|
image: mxfox.ru/mxfox/fox-web-basic:latest
|
||||||
|
commands:
|
||||||
|
- |
|
||||||
|
apt-get update -y
|
||||||
|
apt-get install curl -y
|
||||||
|
cd /tmp
|
||||||
|
curl -sS https://getcomposer.org/installer -o composer-setup.php
|
||||||
|
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
|
||||||
|
DEBIAN_FRONTEND=noninteractive TZ=Europe/Moscow apt-get -y install tzdata
|
||||||
|
cd -
|
||||||
|
- composer install
|
||||||
|
- |
|
||||||
|
find . -name "*~" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name "*.bak" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name "*.old" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name ".git" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name ".settings" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name ".buildpath" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name ".project" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name "README.*" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name "*.md" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name "composer.*" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name ".travis*" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name "installed.json" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -name "*.sample" -prune -exec rm -rf '{}' \;
|
||||||
|
find . -type d ! -path './.git/**' ! -path './static/**' ! -path "./static" ! -path ./*/modules/*/static* -exec bash -c 'test -f {}/.htaccess && echo -n "[ SKIP ] " || (cp ./docker-build/.htaccess {} && echo -n "[ ADD ] ") && echo {}/.htaccess' \;
|
||||||
|
cp docker-build/Dockerfile Dockerfile
|
||||||
|
rm -f composer.*
|
||||||
|
|
||||||
|
- name: Build docker image
|
||||||
|
image: mxfox.ru/mxfox/docker-dind.buildx:latest
|
||||||
|
privileged: true
|
||||||
|
environment:
|
||||||
|
DOCKER_AUTH:
|
||||||
|
from_secret: dockerconfig
|
||||||
|
IMAGE_PREFIX: mxfox.ru/mxfox/chimera-mk2-core
|
||||||
|
|
||||||
|
commands:
|
||||||
|
- buildx-bgstart.sh
|
||||||
|
- echo $${DOCKER_AUTH} > ~/.docker/config.json
|
||||||
|
- echo "CB ${CI_COMMIT_BRANCH}"
|
||||||
|
- echo "DT ${DRONE_TAG}"
|
||||||
|
- |
|
||||||
|
if [ -n "${DRONE_TAG}" ]
|
||||||
|
then
|
||||||
|
export xBuildSuffix=" -t $${IMAGE_PREFIX}:${DRONE_TAG} -t $${IMAGE_PREFIX}:latest --push"
|
||||||
|
else
|
||||||
|
export xBuildSuffix=" -t $${IMAGE_PREFIX}:${CI_COMMIT_BRANCH}-${CI_BUILD_NUMBER}-${DRONE_COMMIT_SHA:0:10} -t $${IMAGE_PREFIX}:${CI_COMMIT_BRANCH} --push"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- docker buildx build --platform linux/amd64,linux/arm64 . $${xBuildSuffix}
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: Export code
|
||||||
|
image_pull_secrets:
|
||||||
|
- dockerconfig
|
||||||
|
trigger:
|
||||||
|
ref:
|
||||||
|
- refs/tags/*
|
||||||
|
steps:
|
||||||
|
- name: Export code
|
||||||
|
image: mxfox.ru/mxfox/fox-web-basic:latest
|
||||||
|
commands:
|
||||||
|
- echo "Not implemented yet"
|
|
@ -5,4 +5,5 @@
|
||||||
/temp-test
|
/temp-test
|
||||||
/composer.lock
|
/composer.lock
|
||||||
/vendor
|
/vendor
|
||||||
.scannerwork
|
.scannerwork
|
||||||
|
.vscode
|
||||||
|
|
|
@ -1,3 +1,63 @@
|
||||||
|
## V.1.0.0
|
||||||
|
1. Add disabled flag for createLeftPanel and crealeTabsPanel
|
||||||
|
2. Remove context menu title if empty title
|
||||||
|
3. onEnter for fieldGroup
|
||||||
|
4. Поиск по группам пользователей
|
||||||
|
5. Поиск по пользователям
|
||||||
|
6. onContextMenu для поля UI.fieldAdd(type=label)
|
||||||
|
7. Кликабельность поля типа "label" для UI.fieldAdd
|
||||||
|
8. Исправлена ошибка загрузки модуля в Firefox
|
||||||
|
9. Исправлена ошибка /users/x
|
||||||
|
10. Исправлена Ошибка создания форм с полем passwordNew
|
||||||
|
11. Исправлено Изменение хэша при изменение URL oAuth
|
||||||
|
12. Установка модулей и fox-start.d
|
||||||
|
13. Скрывать меню при обновлении
|
||||||
|
14. Добавить подпись Powered by chimera fox как было на mark1
|
||||||
|
15. Добавить заглушку на случай если браузер не поддерживается
|
||||||
|
17. Установщик пакетов с модулями
|
||||||
|
18. Экранирование параметра id в baseClass::__construct() @type=string|int
|
||||||
|
19. added searchResult class, updated system to use it in search
|
||||||
|
20. Implemented fox\modules::getByFeature and fox\moduleInfo::getByFeature
|
||||||
|
21. added UI.collectForm().getVals() method
|
||||||
|
22. Updated session/modules logic
|
||||||
|
23. Added chars and length props for passwordNew field, added string ref type for smartClick
|
||||||
|
24. Added Filrebase/jwt into composer.json, added id for tabs-anchor
|
||||||
|
25. Added API.session.checkAccess(rule, module)
|
||||||
|
26. added qGetSql() and qGetSqlSelectTemplate()
|
||||||
|
27. Updated UI panels
|
||||||
|
28. Implemented usage of user session config if exists
|
||||||
|
29. Added public function isMember(user $user)
|
||||||
|
30. Added href (smartClick) type into UI.addField()
|
||||||
|
31. Added click-protection for foxClick: click blocked if selection not empty
|
||||||
|
32. table.datatable td(th).icon - icon size reduced
|
||||||
|
33. Updated Breadcrumbs for use objects
|
||||||
|
34. Added attrs.disabled translation into item for UI.fieldAdd
|
||||||
|
35. Implemented companies management
|
||||||
|
36. Added onClick and onContextMenu for fieldBlock, added .onEnter ext.
|
||||||
|
37. Added async key into api.exec and disabled flag into LR-tabs
|
||||||
|
38. API.session.checkAccess fix
|
||||||
|
39. Added tabs manipulation methods
|
||||||
|
40. Switched common::getGUIDc to UUID:v4
|
||||||
|
41. Added UI.getClipboard(callback) function
|
||||||
|
42. Added onFail callback into UI.getClipboard
|
||||||
|
43. Iplemented ref.onContextMenu for adField with type label and href
|
||||||
|
44. Added API.loadModule method
|
||||||
|
45. Blanker z-index changed
|
||||||
|
46. added baseClass->search page and pagesize type conversion
|
||||||
|
47. Added marker into s3client->listobjects method, added listAllObjects and added forced garbage collection
|
||||||
|
48. Added $__foxRequestInstance
|
||||||
|
49. Added count into default search, fixed foxpager
|
||||||
|
50. added UI.stamp2isodateq and UI.stamp2isodatens funcitons
|
||||||
|
51. Added attrs into accordion panel
|
||||||
|
52. Updated xSearch to extend orderBy
|
||||||
|
53. Webhook implemented
|
||||||
|
54. fox\request @property-read $rawRequestBody
|
||||||
|
55. multipart cache
|
||||||
|
(Last commit processed #6b3a7f420d)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## V.0.9.0 RC
|
## V.0.9.0 RC
|
||||||
### Бэк
|
### Бэк
|
||||||
1. Огранизация прозрачного REST API через интерфейс fox\externalCallable - позволяет с минимальными затратами но при этом со всеми необходимыми проверками организовать доступ к нужным сущностям.
|
1. Огранизация прозрачного REST API через интерфейс fox\externalCallable - позволяет с минимальными затратами но при этом со всеми необходимыми проверками организовать доступ к нужным сущностям.
|
||||||
|
|
60
api/v2.php
60
api/v2.php
|
@ -30,7 +30,8 @@ try {
|
||||||
}
|
}
|
||||||
$request->shift();
|
$request->shift();
|
||||||
$modules=moduleInfo::getAll();
|
$modules=moduleInfo::getAll();
|
||||||
if (!array_key_exists(request::get()->module, $modules)) {
|
$reqModule=request::get()->module;
|
||||||
|
if (!array_key_exists($reqModule, $modules)) {
|
||||||
if (request::get()->authOK) {
|
if (request::get()->authOK) {
|
||||||
throw new foxException("Invalid module",404);
|
throw new foxException("Invalid module",404);
|
||||||
} else {
|
} else {
|
||||||
|
@ -38,11 +39,8 @@ try {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($modules[request::get()->module]->authRequired && !request::get()->authOK) {
|
|
||||||
throw new foxException("Unauthorized",401);
|
|
||||||
}
|
|
||||||
|
|
||||||
$modNS=$modules[request::get()->module]->namespace;
|
$modNS=$modules[$reqModule]->namespace;
|
||||||
request::get()->shift();
|
request::get()->shift();
|
||||||
$className=$modNS."\\".request::get()->module;
|
$className=$modNS."\\".request::get()->module;
|
||||||
if (!class_exists($className)) {
|
if (!class_exists($className)) {
|
||||||
|
@ -60,24 +58,46 @@ try {
|
||||||
$apiFunction=fox\common::clearInput($request->function,"a-zA-Z0-9");
|
$apiFunction=fox\common::clearInput($request->function,"a-zA-Z0-9");
|
||||||
$apiXFunction=empty($request->parameters[0])?NULL:fox\common::clearInput($request->parameters[0],"a-zA-Z0-9");
|
$apiXFunction=empty($request->parameters[0])?NULL:fox\common::clearInput($request->parameters[0],"a-zA-Z0-9");
|
||||||
|
|
||||||
$apiCallMethod="API_".$apiMethod."_".$apiFunction;
|
|
||||||
$apiXCallMethod="APIX_".$apiMethod."_".$apiXFunction;
|
if ($modules[$reqModule]->authRequired && !request::get()->authOK) {
|
||||||
$apiZCallMethod="API_".$apiMethod;
|
|
||||||
|
$apiPCallMethod="API_UnAuth_".$apiMethod."_".$apiFunction;
|
||||||
if (method_exists($className, $apiCallMethod)) {
|
$apiPXCallMethod="APIX_UnAuth_".$apiMethod."_".$apiXFunction;
|
||||||
$rv=$className::$apiCallMethod($request);
|
$apiPZCallMethod="API_UnAuth_".$apiMethod;
|
||||||
} else if (($apiXFunction!==null) && method_exists($className, $apiXCallMethod)) {
|
|
||||||
$rv=$className::$apiXCallMethod($request);
|
if (method_exists($className, $apiPCallMethod)) {
|
||||||
} else if (method_exists($className, $apiZCallMethod)) {
|
$rv=$className::$apiPCallMethod($request);
|
||||||
$rv=$className::$apiZCallMethod($request);
|
} else if (($apiXFunction!==null) && method_exists($className, $apiPXCallMethod)) {
|
||||||
} else if (method_exists($className, "APICall")) {
|
$rv=$className::$apiPXCallMethod($request);
|
||||||
$rv=$className::apiCall(request::get());
|
} else if (method_exists($className, $apiPZCallMethod)) {
|
||||||
|
$rv=$className::$apiPZCallMethod($request);
|
||||||
|
} else {
|
||||||
|
throw new foxException("Unauthorized",401);
|
||||||
|
}
|
||||||
|
|
||||||
|
foxRequestResult::throw("200", "OK", $rv);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new foxException("Method not allowed", 405);
|
|
||||||
|
$apiCallMethod="API_".$apiMethod."_".$apiFunction;
|
||||||
|
$apiXCallMethod="APIX_".$apiMethod."_".$apiXFunction;
|
||||||
|
$apiZCallMethod="API_".$apiMethod;
|
||||||
|
|
||||||
|
if (method_exists($className, $apiCallMethod)) {
|
||||||
|
$rv=$className::$apiCallMethod($request);
|
||||||
|
} else if (($apiXFunction!==null) && method_exists($className, $apiXCallMethod)) {
|
||||||
|
$rv=$className::$apiXCallMethod($request);
|
||||||
|
} else if (method_exists($className, $apiZCallMethod)) {
|
||||||
|
$rv=$className::$apiZCallMethod($request);
|
||||||
|
} else if (method_exists($className, "APICall")) {
|
||||||
|
$rv=$className::apiCall(request::get());
|
||||||
|
} else {
|
||||||
|
throw new foxException("Method not allowed", 405);
|
||||||
|
}
|
||||||
|
|
||||||
|
foxRequestResult::throw("200", "OK", $rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
foxRequestResult::throw("200", "OK", $rv);
|
|
||||||
|
|
||||||
} catch (fox\foxRequestResult $e) {
|
} catch (fox\foxRequestResult $e) {
|
||||||
ob_clean();
|
ob_clean();
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use fox\modules;
|
use fox\modules;
|
||||||
use fox\config;
|
use fox\config;
|
||||||
|
use fox\moduleInfo;
|
||||||
|
|
||||||
include(__DIR__."/../Autoloader.php");
|
include(__DIR__."/../Autoloader.php");
|
||||||
|
|
||||||
|
@ -49,6 +50,18 @@ foreach (scandir(modules::packagesDir) as $file) {
|
||||||
if (file_exists(modules::modulesDir."/".$newModInfo->name."/fox-start.d")) {
|
if (file_exists(modules::modulesDir."/".$newModInfo->name."/fox-start.d")) {
|
||||||
system("chmod a+x \"".modules::modulesDir."/".$newModInfo->name."/fox-start.d/\"*");
|
system("chmod a+x \"".modules::modulesDir."/".$newModInfo->name."/fox-start.d/\"*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$mods = moduleInfo::getAll();
|
||||||
|
|
||||||
|
foreach($mods as $mod) {
|
||||||
|
if ($newModInfo->name==$mod->instanceOf) {
|
||||||
|
$mod->modVersion=$newModInfo->version;
|
||||||
|
$mod->modBuild=$newModInfo->build;
|
||||||
|
$mod->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
print "OK\n";
|
print "OK\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ namespace fox;
|
||||||
class cache
|
class cache
|
||||||
{
|
{
|
||||||
|
|
||||||
|
protected const chunkSize=1024000;
|
||||||
|
|
||||||
public ?\Memcached $mcd = null;
|
public ?\Memcached $mcd = null;
|
||||||
|
|
||||||
protected $prefix = null;
|
protected $prefix = null;
|
||||||
|
@ -84,9 +86,26 @@ class cache
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($encrypt) {
|
if ($encrypt) {
|
||||||
$this->mcd->set($this->prefix . "." . $key, xcrypt::encrypt(json_encode($val)), $TTL);
|
$str=xcrypt::encrypt(json_encode($val));
|
||||||
} else {
|
} else {
|
||||||
$this->mcd->set($this->prefix . "." . $key, json_encode($val), $TTL);
|
$str=json_encode($val);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->del($key);
|
||||||
|
|
||||||
|
$len=strlen($str);
|
||||||
|
if ($len <= static::chunkSize) {
|
||||||
|
$this->mcd->set($this->prefix . "." . $key, $str, $TTL);
|
||||||
|
} else {
|
||||||
|
# multipart
|
||||||
|
$md5=md5($str);
|
||||||
|
$chunks=ceil($len/static::chunkSize);
|
||||||
|
|
||||||
|
$this->mcd->set($this->prefix . "." . $key.".MPX00", json_encode(["len"=>$len, "md5"=>$md5,"chunks"=>$chunks]), $TTL);
|
||||||
|
for ($i = 0; $i<$chunks; $i++) {
|
||||||
|
$xzval=substr($str,$i*static::chunkSize,static::chunkSize);
|
||||||
|
$this->mcd->set($this->prefix . "." . $key.".MPX0".($i+1), $xzval, $TTL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,10 +120,31 @@ class cache
|
||||||
|
|
||||||
|
|
||||||
$xval=$this->mcd->get($this->prefix . "." . $key);
|
$xval=$this->mcd->get($this->prefix . "." . $key);
|
||||||
|
if ($xval==null) {
|
||||||
|
$idx=$this->mcd->get($this->prefix . "." . $key.".MPX00");
|
||||||
|
if ($idx) {
|
||||||
|
$idx=json_decode($idx);
|
||||||
|
if ($idx) {
|
||||||
|
$xval="";
|
||||||
|
for ($i=1; $i <=$idx->chunks; $i++) {
|
||||||
|
$xzval=$this->mcd->get($this->prefix . "." . $key.".MPX0".$i);
|
||||||
|
$xval .= $xzval;
|
||||||
|
}
|
||||||
|
$xlen=strlen($xval);
|
||||||
|
$xmd5=md5($xval);
|
||||||
|
|
||||||
|
if ($xlen!=$idx->len || $xmd5!=$idx->md5) {
|
||||||
|
$this->del($key);
|
||||||
|
$xval=null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if ($xval==null || $xval=="null") { return null; }
|
if ($xval==null || $xval=="null") { return null; }
|
||||||
$rv= json_decode($this->mcd->get($this->prefix . "." . $key), $array);
|
|
||||||
|
$rv= json_decode($xval, $array);
|
||||||
if ($rv !== null) { return $rv; }
|
if ($rv !== null) { return $rv; }
|
||||||
return json_decode(xcrypt::decrypt($this->mcd->get($this->prefix . "." . $key)), $array);
|
return json_decode(xcrypt::decrypt($xval), $array);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function del($key) {
|
public function del($key) {
|
||||||
|
@ -116,6 +156,17 @@ class cache
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->mcd->delete($this->prefix . "." . $key);
|
$this->mcd->delete($this->prefix . "." . $key);
|
||||||
|
|
||||||
|
$idx=$this->mcd->get($this->prefix . "." . $key.".MPX00");
|
||||||
|
if ($idx) {
|
||||||
|
$idx=json_decode($idx);
|
||||||
|
if ($idx) {
|
||||||
|
$this->mcd->delete($this->prefix . "." . $key.".MPX00");
|
||||||
|
for ($i=1; $i <=$idx->chunks; $i++) {
|
||||||
|
$this->mcd->delete($this->prefix . "." . $key.".MPX0".$i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ namespace fox;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Class fox\common
|
* Class fox\common
|
||||||
*
|
* Common methods ex. generation GUID
|
||||||
|
*
|
||||||
* @copyright MX STAR LLC 2021
|
* @copyright MX STAR LLC 2021
|
||||||
* @version 4.0.0
|
* @version 4.0.0
|
||||||
* @author Pavel Dmitriev
|
* @author Pavel Dmitriev
|
||||||
|
@ -88,14 +89,34 @@ class common
|
||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate uuid withous curly braces in lowercase
|
||||||
|
* xxx....xxx
|
||||||
|
**/
|
||||||
|
|
||||||
|
static function getUUID()
|
||||||
|
{
|
||||||
|
return strtolower(UUID::v4());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate GUID withous curly braces
|
||||||
|
* XXX.....XXX
|
||||||
|
**/
|
||||||
|
|
||||||
static function getGUIDc()
|
static function getGUIDc()
|
||||||
{
|
{
|
||||||
return strtoupper(UUID::v4());
|
return strtoupper(UUID::v4());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate GUID with curly braces
|
||||||
|
* { XXX.....XXX }
|
||||||
|
**/
|
||||||
|
|
||||||
static function getGUID()
|
static function getGUID()
|
||||||
{
|
{
|
||||||
return chr(123) . getGUIDc() . chr(125);
|
return chr(123) . static::getGUIDc() . chr(125);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function fullname2qname($first, $mid, $last)
|
static function fullname2qname($first, $mid, $last)
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
<?php namespace fox;
|
<?php namespace fox;
|
||||||
|
|
||||||
|
use fox\meta\settings;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Class fox\file
|
* Class fox\file
|
||||||
|
@ -11,23 +14,37 @@
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
|
|
||||||
class file extends baseClass {
|
class file extends baseClass implements externalCallable {
|
||||||
protected $id;
|
protected $id;
|
||||||
|
public $uuid;
|
||||||
public $fileName;
|
public $fileName;
|
||||||
public $module;
|
public $module;
|
||||||
public $class;
|
public $class;
|
||||||
|
public $refId;
|
||||||
public $public=false;
|
public $public=false;
|
||||||
public $private=false;
|
public $private=false;
|
||||||
public $ownerId=null;
|
public $ownerId=null;
|
||||||
|
public time $uploadStamp;
|
||||||
public time $expireStamp;
|
public time $expireStamp;
|
||||||
|
|
||||||
|
protected $__data;
|
||||||
|
|
||||||
public static $sqlTable="tblFiles";
|
public static $sqlTable="tblFiles";
|
||||||
|
|
||||||
|
# file access token expires in 30 seconds
|
||||||
|
const fileTokenTTL=30;
|
||||||
|
const defaultBucket="files";
|
||||||
|
|
||||||
protected function __xConstruct() {
|
protected function __xConstruct() {
|
||||||
$this->expireStamp=new time();
|
$this->expireStamp=new time();
|
||||||
|
$this->uploadStamp=time::current();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static $sqlColumns = [
|
public static $sqlColumns = [
|
||||||
|
"uuid" => [
|
||||||
|
"type" => "CHAR(36)",
|
||||||
|
"index"=>"UNIQUE",
|
||||||
|
],
|
||||||
"fileName" => [
|
"fileName" => [
|
||||||
"type" => "VARCHAR(255)",
|
"type" => "VARCHAR(255)",
|
||||||
],
|
],
|
||||||
|
@ -39,6 +56,10 @@ class file extends baseClass {
|
||||||
"type" => "VARCHAR(255)",
|
"type" => "VARCHAR(255)",
|
||||||
"index" => "INDEX"
|
"index" => "INDEX"
|
||||||
],
|
],
|
||||||
|
"refId" => [
|
||||||
|
"type" => "VARCHAR(255)",
|
||||||
|
],
|
||||||
|
|
||||||
"ownerId" => [
|
"ownerId" => [
|
||||||
"type" => "INT",
|
"type" => "INT",
|
||||||
"index" => "INDEX",
|
"index" => "INDEX",
|
||||||
|
@ -49,9 +70,134 @@ class file extends baseClass {
|
||||||
"index" => "INDEX",
|
"index" => "INDEX",
|
||||||
"nullable"=>true
|
"nullable"=>true
|
||||||
],
|
],
|
||||||
|
"uploadStamp" => [
|
||||||
|
"type" => "DATETIME",
|
||||||
|
"index" => "INDEX",
|
||||||
|
"nullable"=>true,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
protected function validateSave()
|
||||||
|
{
|
||||||
|
if (empty($this->uuid)) { $this->uuid = common::getUUID(); }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function xSearch($where, $pattern, ?array $options, sql $sql) {
|
||||||
|
|
||||||
|
$xWhere="";
|
||||||
|
if (!empty($options["uuid"])) {
|
||||||
|
$xWhere .= ($xWhere?" AND ":"")." `uuid` = '".common::clearInput($options["uuid"],"0-9a-z-")."'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($options["instance"])) {
|
||||||
|
$xWhere .= ($xWhere?" AND ":"")." `module` = '".common::clearInput($options["instance"])."'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($options["class"])) {
|
||||||
|
$xWhere .= ($xWhere?" AND ":"")." `class` = '".common::clearInput($options["class"],'0-9A-Za-z_\.\-\\\/')."'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($options["refId"])) {
|
||||||
|
$xWhere .= ($xWhere?" AND ":"")." `refId` = '".common::clearInput($options["refId"])."'";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($xWhere) {
|
||||||
|
if ($where) {
|
||||||
|
$where = "(".$where.") AND (".$xWhere.")";
|
||||||
|
} else {
|
||||||
|
$where = $xWhere;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ["where"=>$where, "join"=>null];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function prepareFileUpload($data, $fileName, object $ref, string $instance=null, user $owner=null, $ttl=null) {
|
||||||
|
$f=new static();
|
||||||
|
$f->fileName=$fileName;
|
||||||
|
$f->module=$instance;
|
||||||
|
if ($owner) { $f->ownerId=$owner->id; }
|
||||||
|
if ($ttl) { $f->expireStamp=time::current()->addSec($ttl); }
|
||||||
|
$f->class = $ref::class;
|
||||||
|
$f->uuid=common::getUUID();
|
||||||
|
return $f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function directUpload($data, $fileName, object $ref, string $instance=null, user $owner=null, $ttl=null) {
|
||||||
|
$f=static::prepareFileUpload($data, $fileName, $ref, $instance, $owner, $ttl);
|
||||||
|
$s3=new s3client();
|
||||||
|
if (!$s3->headBucket(static::defaultBucket)) {
|
||||||
|
$s3->createBucket(static::defaultBucket);
|
||||||
|
}
|
||||||
|
$s3->putObject(static::defaultBucket,$f->uuid, $data);
|
||||||
|
$f->save();
|
||||||
|
return $f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getByUUID(string $uuid) : file {
|
||||||
|
$files = file::search(options: ["uuid"=>$uuid]);
|
||||||
|
if ($files->result) {
|
||||||
|
return array_shift($files->result);
|
||||||
|
} else {
|
||||||
|
throw new foxException("File not found", 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent() {
|
||||||
|
if ($this->uuid) {
|
||||||
|
$s3=new s3client();
|
||||||
|
return $s3->getObject(static::defaultBucket, $this->uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDownloadToken() {
|
||||||
|
if (empty($this->id)) {
|
||||||
|
throw new foxException("Empty fileId not allowed here");
|
||||||
|
};
|
||||||
|
$token=common::genPasswd(32);
|
||||||
|
|
||||||
|
$c=new cache();
|
||||||
|
$c->set('fileDnldToken-'.$token,$this,static::fileTokenTTL);
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getByToken($token) {
|
||||||
|
$c=new cache();
|
||||||
|
$ftile=$c->get('fileDnldToken-'.$token,true);
|
||||||
|
if ($ftile) {
|
||||||
|
$file = new static($ftile);
|
||||||
|
$c->del('fileDnldToken-'.$token);
|
||||||
|
return $file;
|
||||||
|
} else {
|
||||||
|
throw new foxException("Invalid token",404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getUploadToken($data, $fileName, object $ref, string $instance=null, user $owner=null) {
|
||||||
|
$f=static::prepareFileUpload($data, $fileName, $ref, $instance, $owner);
|
||||||
|
$token=common::genPasswd(32);
|
||||||
|
$c=new cache();
|
||||||
|
$c->set('fileUpldToken-'.$token,$f,static::fileTokenTTL);
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
#### REST API
|
||||||
|
|
||||||
|
public static function API_UnAuth_GET(request $request) {
|
||||||
|
if (!empty($request->parameters)) throw new foxException("Invalid request", 400);
|
||||||
|
$file2=file::getByToken($request->function);
|
||||||
|
header_remove('Content-Type');
|
||||||
|
header('Content-Description: File Transfer');
|
||||||
|
header('Content-Type: application/octet-stream');
|
||||||
|
header('Content-Disposition: attachment; filename='.$file2->fileName);
|
||||||
|
print($file2->getContent());
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
?>
|
?>
|
|
@ -33,6 +33,8 @@ class moduleInfo extends baseClass implements externalCallable
|
||||||
|
|
||||||
public string $modVersion = "1.0.0";
|
public string $modVersion = "1.0.0";
|
||||||
|
|
||||||
|
public ?string $modBuild=null;
|
||||||
|
|
||||||
public string $modPriority = "9999";
|
public string $modPriority = "9999";
|
||||||
|
|
||||||
public time $installDate;
|
public time $installDate;
|
||||||
|
@ -67,6 +69,9 @@ class moduleInfo extends baseClass implements externalCallable
|
||||||
"type" => "INT",
|
"type" => "INT",
|
||||||
"index" => "INDEX"
|
"index" => "INDEX"
|
||||||
],
|
],
|
||||||
|
"modBuild"=> [
|
||||||
|
"type"=>"VARCHAR(255)",
|
||||||
|
],
|
||||||
"singleInstanceOnly" => [
|
"singleInstanceOnly" => [
|
||||||
"type" => "SKIP"
|
"type" => "SKIP"
|
||||||
],
|
],
|
||||||
|
|
|
@ -162,6 +162,7 @@ class modules implements externalCallable
|
||||||
if ($modDesc->name != $modInfo->name) { throw new foxException("Module name mismatch for ".$modInfo->name); }
|
if ($modDesc->name != $modInfo->name) { throw new foxException("Module name mismatch for ".$modInfo->name); }
|
||||||
$modInfo->title=$modDesc->title;
|
$modInfo->title=$modDesc->title;
|
||||||
$modInfo->modVersion=$modDesc->version;
|
$modInfo->modVersion=$modDesc->version;
|
||||||
|
@$modInfo->modBuild=$modDesc->build;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
trigger_error($e->getMessage());
|
trigger_error($e->getMessage());
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -40,6 +40,7 @@ class oAuthProfile extends baseClass implements externalCallable {
|
||||||
protected function validateSave()
|
protected function validateSave()
|
||||||
{
|
{
|
||||||
if (empty($this->hash)) {
|
if (empty($this->hash)) {
|
||||||
|
trigger_error($this->hash);
|
||||||
$this->hash=xcrypt::hash(json_encode($this));
|
$this->hash=xcrypt::hash(json_encode($this));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -142,7 +143,7 @@ class oAuthProfile extends baseClass implements externalCallable {
|
||||||
if (!empty($request->requestBody->clientId)) { $m->clientId=common::clearInput($request->requestBody->clientId,"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._@-"); }
|
if (!empty($request->requestBody->clientKey)) { $m->clientKey=common::clearInput($request->requestBody->clientKey,"0-9A-Za-z._@-"); }
|
||||||
$m->config=$request->requestBody->config;
|
$m->config=$request->requestBody->config;
|
||||||
$m->hash=common::clearInput($request->requestBody->hash,"0-9A-Za-z._@-");
|
if (property_exists($request->requestBody,"hash")) { $m->hash=common::clearInput($request->requestBody->hash,"0-9A-Za-z._@-"); }
|
||||||
$m->save();
|
$m->save();
|
||||||
static::log($request->instance,__FUNCTION__, "OAuth profile ".$m->name." updated.",$request->user,"oAuthProfile",$m->id,null,logEntry::sevInfo,["changelog"=>$m->changelog]);
|
static::log($request->instance,__FUNCTION__, "OAuth profile ".$m->name." updated.",$request->user,"oAuthProfile",$m->id,null,logEntry::sevInfo,["changelog"=>$m->changelog]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,5 +28,9 @@ interface objectStorageClient
|
||||||
public function createBucket($bucket);
|
public function createBucket($bucket);
|
||||||
|
|
||||||
public function deleteBucket($bucket);
|
public function deleteBucket($bucket);
|
||||||
|
|
||||||
|
public function headBucket($bucket);
|
||||||
|
|
||||||
|
public function headObject($bucket, $key);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
|
@ -12,6 +12,7 @@ namespace fox;
|
||||||
*
|
*
|
||||||
* @property-read user $user
|
* @property-read user $user
|
||||||
* @property-read $userId
|
* @property-read $userId
|
||||||
|
* @property-read $rawRequestBody
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class request extends baseClass implements noSqlMigration
|
class request extends baseClass implements noSqlMigration
|
||||||
|
@ -164,6 +165,8 @@ class request extends baseClass implements noSqlMigration
|
||||||
throw new foxException('Unauthorized', 401);
|
throw new foxException('Unauthorized', 401);
|
||||||
}
|
}
|
||||||
return $this->token->user;
|
return $this->token->user;
|
||||||
|
case "rawRequestBody":
|
||||||
|
return file_get_contents("php://input");
|
||||||
default:
|
default:
|
||||||
return parent::__get($key);
|
return parent::__get($key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace fox;
|
namespace fox;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Class fox\s3client
|
* Class fox\s3client
|
||||||
|
@ -139,6 +141,22 @@ class s3client implements objectStorageClient
|
||||||
public function __destruct() {
|
public function __destruct() {
|
||||||
$this->s3=null;
|
$this->s3=null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function headBucket($bucket) {
|
||||||
|
try {
|
||||||
|
if ($this->s3->headBucket(["Bucket" => $this->prefix . $bucket])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function headObject($bucket, $key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
|
@ -100,6 +100,18 @@ class time implements stringExportable, stringImportable, \JsonSerializable
|
||||||
return $this->stamp;
|
return $this->stamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function formatInterval($val) {
|
||||||
|
$durWeeks=floor($val/604800);
|
||||||
|
$durXWeeks=$val % 604800;
|
||||||
|
$durDays=floor($durXWeeks/86400);
|
||||||
|
$durXDays=$durXWeeks % 86400;
|
||||||
|
$durHrs=floor($durXDays/3600);
|
||||||
|
$durXHrs=$durXDays % 3600;
|
||||||
|
$durMins=floor($durXHrs/60);
|
||||||
|
$durSecs=floor($durXHrs % 60);
|
||||||
|
|
||||||
|
return ($durWeeks>0?$durWeeks."W ":"").($durDays>0?$durDays."D ":"").str_pad($durHrs,2, "0", STR_PAD_LEFT).":".str_pad($durMins,2, "0", STR_PAD_LEFT).":".str_pad($durSecs,2, "0", STR_PAD_LEFT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
namespace fox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Interface fox\externalCallable
|
||||||
|
*
|
||||||
|
* @copyright MX STAR LLC 2021
|
||||||
|
* @version 4.0.0
|
||||||
|
* @author Pavel Dmitriev
|
||||||
|
* @license GPLv3
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface webhookCallable
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* public static function HOOK_<method>_<function>(request $request);
|
||||||
|
* Example:
|
||||||
|
* public static function HOOK_POST_members(request $request);
|
||||||
|
* public static function HOOKCall(request $request);
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
|
@ -31,8 +31,6 @@ class xcrypt
|
||||||
|
|
||||||
static function decrypt($val, $key = null)
|
static function decrypt($val, $key = null)
|
||||||
{
|
{
|
||||||
$ENC_KEY = substr(md5(config::get("masterSecret")), 0, 24);
|
|
||||||
|
|
||||||
if (isset($key)) {
|
if (isset($key)) {
|
||||||
$ENC_KEY = substr(md5($key), 0, 24);
|
$ENC_KEY = substr(md5($key), 0, 24);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteRule . index.php [END]
|
||||||
|
RewriteRule . - [END,R=404]
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0000404
|
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
require_once(__DIR__.'/../Autoloader.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Script hook\index.php
|
||||||
|
*
|
||||||
|
* @copyright MX STAR LLC 2022
|
||||||
|
* @version 4.0.0
|
||||||
|
* @author Pavel Dmitriev
|
||||||
|
* @license GPLv3
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
use fox\request;
|
||||||
|
use fox\moduleInfo;
|
||||||
|
use fox\foxException;
|
||||||
|
use fox\foxRequestResult;
|
||||||
|
$request = request::get();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($request->module !== 'hook') {
|
||||||
|
throw new foxException("Invalid request",400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->shift();
|
||||||
|
|
||||||
|
$modules=moduleInfo::getAll();
|
||||||
|
|
||||||
|
if (!array_key_exists(request::get()->module, $modules)) {
|
||||||
|
throw new foxException("Invalid module",404);
|
||||||
|
}
|
||||||
|
$request->shift();
|
||||||
|
|
||||||
|
$modNS=$modules[request::get()->instance]->namespace;
|
||||||
|
$className=$modNS."\\".request::get()->module;
|
||||||
|
|
||||||
|
if (!class_exists($className)) {
|
||||||
|
throw new foxException("Not found",404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_a($className, fox\webhookCallable::class,true)) {
|
||||||
|
throw new foxException("Not found",404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$hookMethod=fox\common::clearInput($request->method,"A-Z");
|
||||||
|
$hookFunction=fox\common::clearInput($request->function,"a-zA-Z0-9");
|
||||||
|
$hookXFunction=empty($request->parameters[0])?NULL:fox\common::clearInput($request->parameters[0],"a-zA-Z0-9");
|
||||||
|
|
||||||
|
$hookCallMethod="HOOK_".$hookMethod."_".$hookFunction;
|
||||||
|
$hookXCallMethod="HOOKX_".$hookMethod."_".$hookXFunction;
|
||||||
|
$hookZCallMethod="HOOK_".$hookMethod;
|
||||||
|
|
||||||
|
if (method_exists($className, $hookCallMethod)) {
|
||||||
|
$rv=$className::$hookCallMethod($request);
|
||||||
|
} else if (($hookXFunction!==null) && method_exists($className, $hookXCallMethod)) {
|
||||||
|
$rv=$className::$hookXCallMethod($request);
|
||||||
|
} else if (method_exists($className, $hookZCallMethod)) {
|
||||||
|
$rv=$className::$hookZCallMethod($request);
|
||||||
|
} else if (method_exists($className, "HOOKCall")) {
|
||||||
|
$rv=$className::hookCall(request::get());
|
||||||
|
} else {
|
||||||
|
throw new foxException("Method not allowed", 405);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rv!==false) {
|
||||||
|
ob_clean();
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
foxRequestResult::throw("200", "OK", $rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (fox\foxRequestResult $e) {
|
||||||
|
ob_clean();
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
header('HTTP/1.0 '.$e->getCode().' '.$e->getMessage(), true, $e->getCode());
|
||||||
|
if ($e->retVal===null) {
|
||||||
|
print json_encode(["status"=>$e->getMessage()]);
|
||||||
|
} else {
|
||||||
|
print json_encode($e->retVal);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
} catch (fox\foxException $e) {
|
||||||
|
if (($e->getCode()>=400 && $e->getCode()<500) || ($e->getCode() == 501) || ($e->getCode() >= 600 && $e->getCode()<900)) {
|
||||||
|
trigger_error($e->getStatus().": ".$e->getCode().": ".$e->getMessage()." in ".$e->getFile()." at line ".$e->getLine(), E_USER_WARNING);
|
||||||
|
print(json_encode(["error"=>["code"=>$e->getCode(),"message"=>$e->getMessage(), "xCode"=>$e->getXCode()]]));
|
||||||
|
if ($e->getCode()>=400 && $e->getCode()<502) {
|
||||||
|
header('HTTP/1.0 '.$e->getCode().' '.$e->getMessage(), true, $e->getCode());
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.0 501 '.$e->getMessage(), true, $e->getCode());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trigger_error($e->getStatus().": ".$e->getCode().": ".$e->getMessage()." in ".$e->getFile()." at line ".$e->getLine(), E_USER_WARNING);
|
||||||
|
print(json_encode(["error"=>["errCode"=>500,"message"=>"Internal server error","xCode"=>$e->getXCode()]]));
|
||||||
|
header('HTTP/1.0 500 Internal server error', true, 500);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
trigger_error($e->getCode().": ".$e->getMessage()." in ".$e->getFile()." at line ".$e->getLine(), E_USER_WARNING);
|
||||||
|
print(json_encode(["error"=>["errCode"=>500,"message"=>"Internal server error", "xCode"=>"ERR"]]));
|
||||||
|
header('HTTP/1.0 500 Internal server error', true, 500);
|
||||||
|
throw($e);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
|
||||||
|
?>
|
|
@ -105,6 +105,20 @@ export function exec(requestType, method , data, onSuccess,noblank,onError,versi
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getFileByToken(token, fileName) {
|
||||||
|
let url='/api/v2/core/file/'+token;
|
||||||
|
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.href = url
|
||||||
|
if (fileName != undefined) {
|
||||||
|
a.download=fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.appendChild(a)
|
||||||
|
a.click()
|
||||||
|
document.body.removeChild(a);
|
||||||
|
}
|
||||||
|
|
||||||
export class settings {
|
export class settings {
|
||||||
static async load() {
|
static async load() {
|
||||||
if (sessionStorage.getItem("baseSettings")==undefined) {
|
if (sessionStorage.getItem("baseSettings")==undefined) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ function reloadInstalled() {
|
||||||
$("<td>",{class: "", text: mod.name}).appendTo(row);
|
$("<td>",{class: "", text: mod.name}).appendTo(row);
|
||||||
$("<td>",{class: "", text: mod.enabled}).appendTo(row);
|
$("<td>",{class: "", text: mod.enabled}).appendTo(row);
|
||||||
$("<td>",{class: "", text: mod.instanceOf}).appendTo(row);
|
$("<td>",{class: "", text: mod.instanceOf}).appendTo(row);
|
||||||
$("<td>",{class: "", text: mod.modVersion}).appendTo(row);
|
$("<td>",{class: "", text: mod.modVersion+"."+mod.modBuild}).appendTo(row);
|
||||||
$("<td>",{class: "", text: mod.title}).appendTo(row);
|
$("<td>",{class: "", text: mod.title}).appendTo(row);
|
||||||
$("<td>",{class: "", text: UI.stamp2date(mod.installDate,true)}).appendTo(row);
|
$("<td>",{class: "", text: UI.stamp2date(mod.installDate,true)}).appendTo(row);
|
||||||
$("<td>",{class: "", text: UI.stamp2date(mod.updateDate,true)}).appendTo(row);
|
$("<td>",{class: "", text: UI.stamp2date(mod.updateDate,true)}).appendTo(row);
|
||||||
|
@ -157,7 +157,7 @@ function reloadAvail() {
|
||||||
let row=$("<tr>",{}).bind('contextmenu', mlaContextMenuOpen).addClass("contextMenu").attr("modName",mod.name).attr("modTitle",mod.title);
|
let row=$("<tr>",{}).bind('contextmenu', mlaContextMenuOpen).addClass("contextMenu").attr("modName",mod.name).attr("modTitle",mod.title);
|
||||||
$("<td>",{class: "idx", text: i}).appendTo(row);
|
$("<td>",{class: "idx", text: i}).appendTo(row);
|
||||||
$("<td>",{class: "", text: mod.name}).appendTo(row);
|
$("<td>",{class: "", text: mod.name}).appendTo(row);
|
||||||
$("<td>",{class: "", text: mod.modVersion}).appendTo(row);
|
$("<td>",{class: "", text: mod.modVersion+"."+mod.modBuild}).appendTo(row);
|
||||||
$("<td>",{class: "", text: mod.title}).appendTo(row);
|
$("<td>",{class: "", text: mod.title}).appendTo(row);
|
||||||
$("<td>",{class: "", html: mod.singleInstanceOnly?'<i class="far fa-check-square"></i>':""}).appendTo(row);
|
$("<td>",{class: "", html: mod.singleInstanceOnly?'<i class="far fa-check-square"></i>':""}).appendTo(row);
|
||||||
$("<td>",{class: "", text: mod.instancesCount}).appendTo(row);
|
$("<td>",{class: "", text: mod.instancesCount}).appendTo(row);
|
||||||
|
|
|
@ -42,6 +42,7 @@ export var langItem={
|
||||||
open: "Открыть",
|
open: "Открыть",
|
||||||
dialodAddButton: "Добавить",
|
dialodAddButton: "Добавить",
|
||||||
dialodCreateButton: "Создать",
|
dialodCreateButton: "Создать",
|
||||||
|
dialodSaveButton: "Записать",
|
||||||
dialodInfoTitle: "Информация",
|
dialodInfoTitle: "Информация",
|
||||||
dialogRegisterButton: "Регистрация",
|
dialogRegisterButton: "Регистрация",
|
||||||
dialogRecoveryButton: "Восстановить",
|
dialogRecoveryButton: "Восстановить",
|
||||||
|
@ -69,6 +70,7 @@ export var langItem={
|
||||||
confCodeFmtErr: "Неверный формат кода подтверждения",
|
confCodeFmtErr: "Неверный формат кода подтверждения",
|
||||||
recoverFormEmtyX: "Должно быть заполнено одно из полей",
|
recoverFormEmtyX: "Должно быть заполнено одно из полей",
|
||||||
oauthLoginFailedUNR: "Пользователь не зарегистрирован в системе. Для продолжения работы нужно зарегистрироваться на начальной странице.",
|
oauthLoginFailedUNR: "Пользователь не зарегистрирован в системе. Для продолжения работы нужно зарегистрироваться на начальной странице.",
|
||||||
|
oauthLoginFailed500: "Сервер авторизации вернул неверные данные либо недоступен. Повторите попытку через некоторое время",
|
||||||
type: "Тип",
|
type: "Тип",
|
||||||
types: "Типы",
|
types: "Типы",
|
||||||
company: "Компания",
|
company: "Компания",
|
||||||
|
|
|
@ -39,16 +39,16 @@ export function load() {
|
||||||
} else {
|
} else {
|
||||||
// auth
|
// auth
|
||||||
API.exec("POST", "auth/oauth",{hash: hash, code: code},loginSuccessCallback,false,function onFail(json) {
|
API.exec("POST", "auth/oauth",{hash: hash, code: code},loginSuccessCallback,false,function onFail(json) {
|
||||||
console.log(json);
|
let buttons={};
|
||||||
|
buttons["OK"]=function() {
|
||||||
|
UI.closeDialog("dialogInfo");
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
if (json.status.code==401 && json.data.error.xCode=="UNR") {
|
if (json.status.code==401 && json.data.error.xCode=="UNR") {
|
||||||
let buttons={};
|
|
||||||
buttons["OK"]=function() {
|
|
||||||
UI.closeDialog("dialogInfo");
|
|
||||||
load();
|
|
||||||
}
|
|
||||||
UI.showInfoDialog(langPack.core.iface.oauthLoginFailedUNR,langPack.core.iface.loginFailedDialogTitle,buttons);
|
UI.showInfoDialog(langPack.core.iface.oauthLoginFailedUNR,langPack.core.iface.loginFailedDialogTitle,buttons);
|
||||||
} else {
|
} else {
|
||||||
console.log("Error:",json);
|
UI.showInfoDialog(langPack.core.iface.oauthLoginFailed500,langPack.core.iface.loginFailedDialogTitle,buttons);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
--mxs-switch-off: rgba(00,64,128,0.2);
|
--mxs-switch-off: rgba(00,64,128,0.2);
|
||||||
--mxs-switch-disabled: rgba(50,50,50,1);
|
--mxs-switch-disabled: rgba(50,50,50,1);
|
||||||
--mxs-switch-blocked: rgba(255,111,0,0.8);
|
--mxs-switch-blocked: rgba(255,111,0,0.8);
|
||||||
|
--mxs-switch-warn: var(--mxs-switch-blocked);
|
||||||
--mxs-switch-alert: rgba(255,35,0,0.8);
|
--mxs-switch-alert: rgba(255,35,0,0.8);
|
||||||
|
|
||||||
--mxs-title-font: 'Jura', sans-serif;
|
--mxs-title-font: 'Jura', sans-serif;
|
||||||
|
|
Loading…
Reference in New Issue