V1.0 RC2
This commit is contained in:
parent
f59fdf61ca
commit
0aaddfbaec
111
.drone.yml
111
.drone.yml
|
@ -1,111 +0,0 @@
|
|||
---
|
||||
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"
|
|
@ -17,6 +17,7 @@ use fox\foxException;
|
|||
use fox\request;
|
||||
use fox\modules;
|
||||
use fox\foxRequestResult;
|
||||
use fox\moduleInfo;
|
||||
|
||||
class session implements externalCallable
|
||||
{
|
||||
|
@ -35,6 +36,7 @@ class session implements externalCallable
|
|||
if ($request->authOK) {
|
||||
$modules=[];
|
||||
$i = 0;
|
||||
|
||||
foreach (modules::listInstalled() as $mod) {
|
||||
if ($request->user->checkAccess($mod->globalAccessKey, $mod->name)) {
|
||||
$i ++;
|
||||
|
@ -48,11 +50,12 @@ class session implements externalCallable
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return [
|
||||
"updated" => time(),
|
||||
"user" => $request->token->user,
|
||||
"acls" => $request->user->getAccessRules(),
|
||||
"modules" => $modules
|
||||
"modules" => $modules,
|
||||
];
|
||||
}
|
||||
throw new foxException("Unauthorized", 401);
|
||||
|
|
|
@ -77,6 +77,8 @@ class baseModule
|
|||
|
||||
public static $crontab=[];
|
||||
|
||||
public static $themes=[];
|
||||
|
||||
public static function getModInfo(): moduleInfo
|
||||
{
|
||||
$mi = new moduleInfo();
|
||||
|
@ -90,6 +92,7 @@ class baseModule
|
|||
$mi->globalAccessKey = static::$globalAccessKey;
|
||||
$mi->languages = static::$languages;
|
||||
$mi->configKeys=static::$configKeys;
|
||||
$mi->themes=static::$themes;
|
||||
|
||||
return $mi;
|
||||
}
|
||||
|
|
|
@ -84,6 +84,11 @@ class confirmCode extends baseClass {
|
|||
|
||||
return !$this->fillByHash();
|
||||
}
|
||||
|
||||
public static function flushExpired() {
|
||||
$sql=static::qGetSql();
|
||||
$sql->quickExec("DELETE FROM `".static::$sqlTable."` where `expireStamp` < '".time::current()."'");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -30,9 +30,10 @@ class file extends baseClass implements externalCallable {
|
|||
protected $__data;
|
||||
|
||||
public static $sqlTable="tblFiles";
|
||||
public static $allowDeleteFromDB = true;
|
||||
|
||||
# file access token expires in 30 seconds
|
||||
const fileTokenTTL=30;
|
||||
# file access token expires in 120 seconds
|
||||
const fileTokenTTL=120;
|
||||
const defaultBucket="files";
|
||||
|
||||
protected function __xConstruct() {
|
||||
|
@ -78,6 +79,16 @@ class file extends baseClass implements externalCallable {
|
|||
];
|
||||
|
||||
|
||||
protected function validateDelete()
|
||||
{
|
||||
if (empty($this->id)) { throw new foxException("Unable to delete empty file"); }
|
||||
if ($this->uuid) {
|
||||
$s3=new s3client();
|
||||
$s3->deleteObject(static::defaultBucket, $this->uuid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function validateSave()
|
||||
{
|
||||
if (empty($this->uuid)) { $this->uuid = common::getUUID(); }
|
||||
|
@ -103,6 +114,10 @@ class file extends baseClass implements externalCallable {
|
|||
$xWhere .= ($xWhere?" AND ":"")." `refId` = '".common::clearInput($options["refId"])."'";
|
||||
}
|
||||
|
||||
if (!empty($options["expired"])) {
|
||||
$xWhere .= ($xWhere?" AND ":"")." `expireStamp` <= '".time::current()."'";
|
||||
}
|
||||
|
||||
|
||||
if ($xWhere) {
|
||||
if ($where) {
|
||||
|
@ -114,7 +129,7 @@ class file extends baseClass implements externalCallable {
|
|||
return ["where"=>$where, "join"=>null];
|
||||
}
|
||||
|
||||
protected static function prepareFileUpload($data, $fileName, object $ref, string $instance=null, user $owner=null, $ttl=null) {
|
||||
protected static function prepareFileUpload($fileName, object $ref, string $instance=null, user $owner=null, $ttl=null) {
|
||||
$f=new static();
|
||||
$f->fileName=$fileName;
|
||||
$f->module=$instance;
|
||||
|
@ -125,14 +140,26 @@ class file extends baseClass implements externalCallable {
|
|||
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);
|
||||
public function upload($data) {
|
||||
if (!empty($this->id)) {
|
||||
throw new foxException("Not allowed for existing files");
|
||||
}
|
||||
|
||||
if (empty($this->uuid)) {
|
||||
throw new foxException("Empty UUID not allowed here");
|
||||
}
|
||||
|
||||
$s3=new s3client();
|
||||
if (!$s3->headBucket(static::defaultBucket)) {
|
||||
$s3->createBucket(static::defaultBucket);
|
||||
}
|
||||
$s3->putObject(static::defaultBucket,$f->uuid, $data);
|
||||
$f->save();
|
||||
$s3->putObject(static::defaultBucket,$this->uuid, $data);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public static function directUpload($data, $fileName, object $ref, string $instance=null, user $owner=null, $ttl=null) {
|
||||
$f=static::prepareFileUpload($fileName, $ref, $instance, $owner, $ttl);
|
||||
$f->upload($data);
|
||||
return $f;
|
||||
}
|
||||
|
||||
|
@ -163,20 +190,21 @@ class file extends baseClass implements externalCallable {
|
|||
return $token;
|
||||
}
|
||||
|
||||
public static function getByToken($token) {
|
||||
public static function getByToken($token, $upload=false) {
|
||||
$c=new cache();
|
||||
$ftile=$c->get('fileDnldToken-'.$token,true);
|
||||
$prefix=$upload?"fileUpldToken":"fileDnldToken";
|
||||
$ftile=$c->get($prefix.'-'.$token,true);
|
||||
if ($ftile) {
|
||||
$file = new static($ftile);
|
||||
$c->del('fileDnldToken-'.$token);
|
||||
$c->del($prefix.'-'.$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);
|
||||
public static function getUploadToken($fileName, object $ref, string $instance=null, user $owner=null) {
|
||||
$f=static::prepareFileUpload($fileName, $ref, $instance, $owner);
|
||||
$token=common::genPasswd(32);
|
||||
$c=new cache();
|
||||
$c->set('fileUpldToken-'.$token,$f,static::fileTokenTTL);
|
||||
|
@ -196,6 +224,44 @@ class file extends baseClass implements externalCallable {
|
|||
exit;
|
||||
}
|
||||
|
||||
public static function API_UnAuth_POST(request $request) {
|
||||
if (!empty($request->parameters)) throw new foxException("Invalid request", 400);
|
||||
|
||||
$err=false;
|
||||
$rv=[];
|
||||
foreach ($_FILES as $sFile) {
|
||||
$sOK=$sFile["error"]==0;
|
||||
if (!$sOK) {
|
||||
throw new foxException("File upload error");
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($_FILES as $token=>$sFile) {
|
||||
$sOK=$sFile["error"]==0;
|
||||
if ($sOK) {
|
||||
$file = file::getByToken(common::clearInput($token),true);
|
||||
$tmpPath=$sFile["tmp_name"];
|
||||
$data=file_get_contents($tmpPath);
|
||||
$file->upload($data);
|
||||
$rv[$token]=[
|
||||
"fileName"=>$sFile["name"],
|
||||
"fileSize"=>$sFile["size"],
|
||||
"status"=>"OK",
|
||||
];
|
||||
} else {
|
||||
$err=true;
|
||||
$rv[$token]=[
|
||||
"fileName"=>$sFile["name"],
|
||||
"status"=>"Fail",
|
||||
];
|
||||
}
|
||||
}
|
||||
return [
|
||||
"status"=>$err?"ERR":"OK",
|
||||
"details"=>$rv,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,9 +12,11 @@ namespace fox\meta;
|
|||
*
|
||||
**/
|
||||
|
||||
use fox\cache;
|
||||
use fox\externalCallable;
|
||||
use fox\request;
|
||||
use fox\config;
|
||||
use fox\moduleInfo;
|
||||
use fox\time;
|
||||
use fox\modules;
|
||||
use fox\oAuthProfile;
|
||||
|
@ -23,18 +25,44 @@ class settings implements externalCallable
|
|||
{
|
||||
public static function APICall(request $request)
|
||||
{
|
||||
$profiles = oAuthProfile::search()->result;
|
||||
$oauth=[];
|
||||
foreach ($profiles as $p) {
|
||||
if ($p->enabled) {
|
||||
$oauth[] = [
|
||||
"name"=>$p->name,
|
||||
"id"=>$p->id,
|
||||
"icon"=>$p->getClient(null)->getAuthIcon(),
|
||||
];
|
||||
$c=new cache();
|
||||
|
||||
$oauth=$c->get("coreSettingsOauthProfiles");
|
||||
if ($oauth==null) {
|
||||
$profiles = oAuthProfile::search()->result;
|
||||
$oauth=[];
|
||||
foreach ($profiles as $p) {
|
||||
if ($p->enabled) {
|
||||
$oauth[] = [
|
||||
"name"=>$p->name,
|
||||
"id"=>$p->id,
|
||||
"icon"=>$p->getClient(null)->getAuthIcon(),
|
||||
];
|
||||
}
|
||||
}
|
||||
$c->set("coreSettingsOauthProfiles", $oauth);
|
||||
}
|
||||
|
||||
|
||||
$themes=$c->get("coreSettingsThemes");
|
||||
if ($themes==null) {
|
||||
$themes=[];
|
||||
foreach (moduleInfo::getByFeature("theme") as $mod) {
|
||||
if ($mod->themes) {
|
||||
$themes=array_merge($themes, $mod->themes);
|
||||
} else {
|
||||
$themes[$mod->name]=$mod->title;
|
||||
}
|
||||
}
|
||||
$c->set("coreSettingsThemes",$themes);
|
||||
}
|
||||
|
||||
$coreLangs=$c->get("coreSettingsLanguages");
|
||||
if ($coreLangs==null) {
|
||||
$coreLangs=modules::list()["core"]->languages;
|
||||
$c->set("coreSettingsLanguages",$coreLangs);
|
||||
}
|
||||
|
||||
return [
|
||||
"title" => config::get("TITLE"),
|
||||
"sitePrefix" => config::get("SITEPREFIX"),
|
||||
|
@ -45,8 +73,9 @@ class settings implements externalCallable
|
|||
"language" => config::get("DEFAULT_LANGUAGE") === null ? "ru" : config::get("DEFAULT_LANGUAGE"),
|
||||
"defaultModule" => config::get("DEFAULT_MODULE") === null ? "core" : config::get("DEFAULT_MODULE"),
|
||||
"sessionRenewInterval" => config::get("SESSION_RENEW_SEC") === null ? "3600" : config::get("SESSION_RENEW_SEC"),
|
||||
"coreLanguages" => modules::list()["core"]->languages,
|
||||
"coreLanguages" => $coreLangs,
|
||||
"oauthProfiles"=>$oauth,
|
||||
"themes"=>$themes,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ class moduleInfo extends baseClass implements externalCallable
|
|||
|
||||
public array $features = [];
|
||||
|
||||
public array $themes=[];
|
||||
|
||||
public bool $enabled = true;
|
||||
|
||||
public string $modVersion = "1.0.0";
|
||||
|
@ -104,6 +106,9 @@ class moduleInfo extends baseClass implements externalCallable
|
|||
],
|
||||
"configKeys" => [
|
||||
"type" => "SKIP"
|
||||
],
|
||||
"themes" => [
|
||||
"type" => "SKIP"
|
||||
]
|
||||
];
|
||||
|
||||
|
@ -123,6 +128,7 @@ class moduleInfo extends baseClass implements externalCallable
|
|||
$this->namespace = $this->template->namespace;
|
||||
$this->languages = $this->template->languages;
|
||||
$this->configKeys= $this->template->configKeys;
|
||||
$this->themes=$this->template->themes;
|
||||
}
|
||||
return $rv;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ class modules implements externalCallable
|
|||
"namespace" => "fox",
|
||||
"features" => [
|
||||
"page",
|
||||
"menu"
|
||||
"menu",
|
||||
"theme"
|
||||
],
|
||||
"isTemplate" => true,
|
||||
"singleInstanceOnly" => true,
|
||||
|
@ -33,6 +34,10 @@ class modules implements externalCallable
|
|||
"languages" => [
|
||||
"ru"
|
||||
],
|
||||
"themes"=>[
|
||||
"chimera"=>"Chimera Theme",
|
||||
"polarfox"=>"PolarFox Theme",
|
||||
],
|
||||
"ACLRules" => [
|
||||
"isRoot" => "Superadmin user",
|
||||
"adminViewModules"=>"Manage modules",
|
||||
|
|
|
@ -184,7 +184,7 @@ class user extends baseClass implements externalCallable
|
|||
public static function getByEmail($eMail) {
|
||||
$ref=new static();
|
||||
$sql = $ref->getSql();
|
||||
$res = $sql->quickExec1Line($ref->sqlSelectTemplate. " where `eMail`='".common::clearInput($eMail,"@0-9A-Za-z._-")."'");
|
||||
$res = $sql->quickExec1Line($ref->sqlSelectTemplate. " where `eMail`='".common::clearInput($eMail,"@0-9A-Za-z._-")."' and `deleted` != 1");
|
||||
if ($res) {
|
||||
return new static($res);
|
||||
} else {
|
||||
|
@ -354,9 +354,74 @@ class user extends baseClass implements externalCallable
|
|||
static::log($request->instance,__FUNCTION__, "Mail address confirmed for user ".$request->user->login,$request->user,"user",$request->user->id,null,logEntry::sevInfo);
|
||||
return;
|
||||
} else {
|
||||
foxException::throw("ERR", "Validation failed", 400);
|
||||
foxException::throw("ERR", "Validation failed", 400,"IVCC");
|
||||
}
|
||||
}
|
||||
|
||||
public static function API_PATCH(request $request) {
|
||||
if (!empty($request->parameters)) { throw new foxException("Invalid request", 400); }
|
||||
if ($request->user->id == $request->function) {
|
||||
$u=$request->user;
|
||||
} else {
|
||||
$request->blockIfNoAccess("adminUsers", "core");
|
||||
$u=new static(common::clearInput($request->function));
|
||||
}
|
||||
|
||||
$resendEMailConfirmation=false;
|
||||
if (property_exists($request->requestBody, "fullName")) { $u->fullName=$request->requestBody->fullName; }
|
||||
if (property_exists($request->requestBody, "enabled")) { $u->active=$request->requestBody->enabled==1; }
|
||||
if (property_exists($request->requestBody, "eMail") && $request->requestBody->eMail != $u->eMail) {
|
||||
if ($request->requestBody->eMail && !common::validateEMail($request->requestBody->eMail)) {
|
||||
foxException::throw(foxException::STATUS_ERR, "Invalid email format", 400, "WREML");
|
||||
}
|
||||
|
||||
if ($request->requestBody->eMail) {
|
||||
if ($rx=static::getByEmail($request->requestBody->eMail)) {
|
||||
trigger_error(json_encode($rx));
|
||||
foxException::throw(foxException::STATUS_ERR, "EMail already in-use", 400, "UAX");
|
||||
}
|
||||
$u->eMail=$request->requestBody->eMail;
|
||||
$u->eMailConfirmed=false;
|
||||
$resendEMailConfirmation=true;
|
||||
} else {
|
||||
$u->eMail=null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($request->requestBody->password)) {
|
||||
if (strlen($request->requestBody->password) < 6) {
|
||||
throw new foxException("Password too short");
|
||||
}
|
||||
|
||||
$u->setPassword($request->requestBody->password);
|
||||
}
|
||||
$u->save();
|
||||
if ($resendEMailConfirmation) {
|
||||
$u->sendEMailConfirmation();
|
||||
}
|
||||
return $u;
|
||||
}
|
||||
|
||||
public static function APIX_PATCH_settings(request $request) {
|
||||
if ($request->user->id == $request->function) {
|
||||
$u=$request->user;
|
||||
} else {
|
||||
$request->blockIfNoAccess("adminUsers", "core");
|
||||
$u=new static(common::clearInput($request->function));
|
||||
}
|
||||
|
||||
foreach ($request->requestBody as $key=>$val) {
|
||||
$u->config[common::clearInput($key)]=$val;
|
||||
}
|
||||
$u->save();
|
||||
return $u->config;
|
||||
}
|
||||
|
||||
public static function API_DELETE(request $request) {
|
||||
$request->blockIfNoAccess("adminUsers", "core");
|
||||
$u=new static(common::clearInput($request->function));
|
||||
$u->delete();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -7,4 +7,6 @@
|
|||
# | | | | |
|
||||
# * * * * * user-name command to be executed
|
||||
* * * * * www-data bash -c '/var/www/html/fox-cron.d/cron.php &>> /var/log/fox/fox-cron.log'
|
||||
* * * * * www-data bash -c '/var/www/html/fox-cron.d/expungeFiles.php &>> /var/log/fox/fox-cron.log'
|
||||
* * * * * www-data bash -c '/var/www/html/fox-cron.d/flushExpiredConfirmationCodes.php &>> /var/log/fox/fox-cron.log'
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Script expungeFiles.php
|
||||
*
|
||||
* @copyright MX STAR LLC 2018-2022
|
||||
* @version 4.0.0
|
||||
* @author Pavel Dmitriev
|
||||
* @license GPLv3
|
||||
*
|
||||
**/
|
||||
|
||||
use fox\file;
|
||||
|
||||
if (php_sapi_name() != 'cli') {
|
||||
throw new Exception("This script can be run via CLI only");
|
||||
}
|
||||
|
||||
require_once(getenv("FOX_WEBROOT")."/Autoloader.php");
|
||||
|
||||
$list = file::search(options: ["expired"=>1]);
|
||||
foreach ($list->result as $file) {
|
||||
$file->delete();
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* Script flushExpiredConfirmationCodes.php
|
||||
*
|
||||
* @copyright MX STAR LLC 2018-2022
|
||||
* @version 4.0.0
|
||||
* @author Pavel Dmitriev
|
||||
* @license GPLv3
|
||||
*
|
||||
**/
|
||||
|
||||
use fox\confirmCode;
|
||||
|
||||
if (php_sapi_name() != 'cli') {
|
||||
throw new Exception("This script can be run via CLI only");
|
||||
}
|
||||
|
||||
require_once(getenv("FOX_WEBROOT")."/Autoloader.php");
|
||||
|
||||
confirmCode::flushExpired();
|
|
@ -119,6 +119,38 @@ export function getFileByToken(token, fileName) {
|
|||
document.body.removeChild(a);
|
||||
}
|
||||
|
||||
function uploadFileToken(file, token){
|
||||
let formData = new FormData();
|
||||
formData.append(token, file);
|
||||
fetch('/api/v2/core/file', {
|
||||
method: "POST", body: formData
|
||||
});
|
||||
}
|
||||
|
||||
export function uploadFiles(method, filesFieldId, extraFields) {
|
||||
let data={};
|
||||
if (typeof(extraFields)=='object') {
|
||||
let data=extraFields;
|
||||
}
|
||||
|
||||
let files = document.getElementById(filesFieldId).files;
|
||||
$.each(files, function(_key, file) {
|
||||
data.fileName=file.name;
|
||||
data.fileSize=file.size;
|
||||
|
||||
API.exec({
|
||||
requestType: "POST",
|
||||
method: method,
|
||||
data: data,
|
||||
onSuccess: function(json) {
|
||||
uploadFileToken(file, json.data.Token);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
export class settings {
|
||||
static async load() {
|
||||
if (sessionStorage.getItem("baseSettings")==undefined) {
|
||||
|
@ -273,6 +305,11 @@ export class session {
|
|||
sessionStorage.setItem("session",JSON.stringify(xsession));
|
||||
}
|
||||
|
||||
static async reload(callback) {
|
||||
sessionStorage.removeItem("session");
|
||||
this.load(callback);
|
||||
}
|
||||
|
||||
static async load(callback) {
|
||||
let token=localStorage.getItem("token");
|
||||
if (token===null) {
|
||||
|
|
|
@ -2,7 +2,262 @@ import * as API from './api.js';
|
|||
import * as UI from './ui.js';
|
||||
import { langPack } from './langpack.js';
|
||||
|
||||
const userSettings={
|
||||
language: {
|
||||
type: "select",
|
||||
source: function() {
|
||||
let rv={};
|
||||
$.each(API.settings.get("coreLanguages"), function() {
|
||||
rv[this]=(langPack.core.languages && langPack.core.languages[this])?langPack.core.languages[this]:this;
|
||||
})
|
||||
return rv;
|
||||
},
|
||||
reqx: true,
|
||||
},
|
||||
pageSize: {
|
||||
type: "input",
|
||||
regx: "^[0-9]{2}$",
|
||||
reqx: true,
|
||||
},
|
||||
theme: {
|
||||
type: "select",
|
||||
source: API.settings.get("themes"),
|
||||
reqx: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function load() {
|
||||
UI.breadcrumbsUpdate(langPack.core.breadcrumbs.modTitle+" / "+langPack.core.breadcrumbs.myprofile);
|
||||
UI.createLeftPanel([
|
||||
{id: "gendesc", title: langPack.core.iface.genDescTitle,disabled: false, buttons: [
|
||||
UI.addButton({
|
||||
id: "btnGdEdit",
|
||||
icon: "fas fa-edit",
|
||||
onClick: btnGdEdit_click,
|
||||
}),
|
||||
]},
|
||||
{id: "config", title: langPack.core.iface.configTitle,disabled: false, buttons: [
|
||||
UI.addButton({
|
||||
id: "btnStEdit",
|
||||
icon: "fas fa-edit",
|
||||
onClick: btnStEdit_click,
|
||||
}),
|
||||
]},
|
||||
]);
|
||||
|
||||
UI.createRightPanel([
|
||||
|
||||
{id: "mail", title: langPack.core.iface.messagesTitle,disabled: false},
|
||||
{id: "agreements", title: langPack.core.iface.agreementsTitle,disabled: true},
|
||||
{id: "messengers", title: langPack.core.iface.messengersTitle,disabled: true},
|
||||
{id: "log", title: langPack.core.iface.logTitle,disabled: true},
|
||||
|
||||
])
|
||||
API.session.reload(reloadGenDesc);
|
||||
}
|
||||
|
||||
function btnStEdit_click(_ref) {
|
||||
UI.blankerShow();
|
||||
API.session.reload(function() {
|
||||
UI.blankerHide();
|
||||
let buttons={};
|
||||
let dx;
|
||||
buttons[langPack.core.iface.dialodSaveButton]=function() {
|
||||
dialogStEdit_Save_Click(dx);
|
||||
}
|
||||
buttons[langPack.core.iface.dialodCloseButton]=function() {
|
||||
UI.closeDialog(dx);
|
||||
}
|
||||
|
||||
let dxflds=[];
|
||||
|
||||
$.each(userSettings, function(key) {
|
||||
let fld={
|
||||
type: this.type,
|
||||
item: key,
|
||||
title: langPack.core.userSettings[key]?langPack.core.userSettings[key]:key,
|
||||
reqx: this.reqx,
|
||||
regx: this.regx,
|
||||
};
|
||||
|
||||
if (this.source) {
|
||||
if (typeof(this.source)=="function") {
|
||||
fld.args=this.source();
|
||||
} else {
|
||||
fld.args=this.source;
|
||||
}
|
||||
}
|
||||
|
||||
fld.val=API.session.getConfigItem(key);
|
||||
|
||||
dxflds.push(UI.addField(fld));
|
||||
});
|
||||
|
||||
dx=UI.createDialog(
|
||||
UI.addFieldGroup(dxflds),
|
||||
langPack.core.iface.edit+": "+langPack.core.iface.configTitle,
|
||||
buttons);
|
||||
UI.openDialog(dx);
|
||||
});
|
||||
}
|
||||
|
||||
function btnGdEdit_click(_ref) {
|
||||
UI.blankerShow();
|
||||
API.session.reload(function() {
|
||||
UI.blankerHide();
|
||||
let buttons={};
|
||||
let dx;
|
||||
buttons[langPack.core.iface.dialodSaveButton]=function() {
|
||||
dialogGdEdit_Save_Click(dx);
|
||||
}
|
||||
buttons[langPack.core.iface.dialodCloseButton]=function() {
|
||||
UI.closeDialog(dx);
|
||||
}
|
||||
dx=UI.createDialog(
|
||||
UI.addFieldGroup([
|
||||
UI.addField({
|
||||
title: langPack.core.iface.uid,
|
||||
val: UI.formatInvCode(API.session.get("user").invCode),
|
||||
}),
|
||||
UI.addField({
|
||||
title: langPack.core.iface.users.login,
|
||||
val: API.session.get("user").login,
|
||||
}),
|
||||
UI.addField({
|
||||
item: "dx_fullName",
|
||||
type: "input",
|
||||
title: langPack.core.iface.users.fullName,
|
||||
val: API.session.get("user").fullName,
|
||||
reqx: true,
|
||||
|
||||
}),
|
||||
UI.addField({
|
||||
item: "dx_eMail",
|
||||
type: "input",
|
||||
title: langPack.core.iface.users.email,
|
||||
val: API.session.get("user").eMail,
|
||||
regx: "(^$)|(^[0-9a-zA-Z._-]+\@[0-9a-zA-Z._-]+\.[a-zA_Z]+$)",
|
||||
regxTitle: langPack.core.iface.users.errors.WREML,
|
||||
}),
|
||||
UI.addField({
|
||||
title: langPack.core.iface.password,
|
||||
type: "passwordNew",
|
||||
item: "dx_password",
|
||||
reqx:false,
|
||||
regx: "(^$)|(.{6,})",
|
||||
disabled: false,
|
||||
newPasswdGenCallback: function(passwd) {
|
||||
$("#dx_password2").val(passwd).addClass("changed").prop("type","input");
|
||||
}
|
||||
}),
|
||||
UI.addField({
|
||||
title: langPack.core.iface.passConfirm,
|
||||
type: "password",
|
||||
item: "dx_password2",
|
||||
reqx:false,
|
||||
disabled: false
|
||||
}),
|
||||
]),
|
||||
langPack.core.iface.edit+": "+langPack.core.iface.genDescTitle,
|
||||
buttons);
|
||||
|
||||
}
|
||||
UI.openDialog(dx);
|
||||
});
|
||||
}
|
||||
|
||||
function dialogGdEdit_Save_Click(dx) {
|
||||
let data = UI.collectForm(UI.getId(dx),true,true,false,true);
|
||||
if(data.validateErrCount) { return };
|
||||
|
||||
if (data.password.changed && data.password.val != data.password2.val) {
|
||||
$("#dx_password").addClass("alert");
|
||||
$("#dx_password2").addClass("alert");
|
||||
return;
|
||||
}
|
||||
|
||||
API.exec({
|
||||
requestType: "PATCH",
|
||||
method: "core/user/"+API.session.get("user").id,
|
||||
data: data.getVals(),
|
||||
onSuccess: function(json) {
|
||||
UI.closeDialog(dx);
|
||||
API.session.reload(reloadGenDesc);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function dialogStEdit_Save_Click(dx) {
|
||||
let data = UI.collectForm(UI.getId(dx),true,true,false,true);
|
||||
if(data.validateErrCount) { return };
|
||||
|
||||
API.exec({
|
||||
requestType: "PATCH",
|
||||
method: "core/user/"+API.session.get("user").id+"/settings",
|
||||
data: data.getVals(),
|
||||
onSuccess: function(json) {
|
||||
UI.closeDialog(dx);
|
||||
API.session.reload(reloadGenDesc);
|
||||
if (data.theme.changed) {
|
||||
console.log("Theme changed");
|
||||
window.location.reload(true);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function reloadGenDesc() {
|
||||
let gdg=UI.addFieldGroup().appendTo($("#gendesc").empty());
|
||||
|
||||
UI.addField({title: langPack.core.iface.uid, val: UI.formatInvCode(API.session.get("user").invCode)}).appendTo(gdg);
|
||||
UI.addField({title: langPack.core.iface.users.login, val: API.session.get("user").login}).appendTo(gdg);
|
||||
UI.addField({title: langPack.core.iface.users.fullName, val: API.session.get("user").fullName}).appendTo(gdg);
|
||||
UI.addField({title: langPack.core.iface.users.email, val: API.session.get("user").eMail}).appendTo(gdg);
|
||||
let emailConfirmationOnContextMenu;
|
||||
if (!API.session.get("user").eMailConfirmed && API.session.get("user").eMail) {
|
||||
emailConfirmationOnContextMenu= function(el) {
|
||||
UI.contextMenuOpen(el,[
|
||||
{
|
||||
title: langPack.core.iface.users.resendConfirmationCode,
|
||||
onClick: function() {
|
||||
API.exec({
|
||||
requestType: "GET",
|
||||
method: "core/user/sendEMailConfirmation",
|
||||
})
|
||||
}
|
||||
}
|
||||
]);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
UI.addField({
|
||||
title: "eMail Confirmed",
|
||||
val: API.session.get("user").eMailConfirmed?langPack.core.iface.yes:langPack.core.iface.no,
|
||||
onContextMenu: emailConfirmationOnContextMenu,
|
||||
}).appendTo(gdg);
|
||||
|
||||
let cfg=UI.addFieldGroup().appendTo($("#config").empty());
|
||||
$.each(userSettings, function(key) {
|
||||
let val=API.session.getConfigItem(key);
|
||||
|
||||
if (userSettings[key] && userSettings[key].type=="select" && userSettings[key].source) {
|
||||
let opts={};
|
||||
if (typeof(userSettings[key].source)=="function") {
|
||||
opts=userSettings[key].source();
|
||||
} else {
|
||||
opts=userSettings[key].source;
|
||||
}
|
||||
|
||||
if (opts[val]) {
|
||||
val=opts[val];
|
||||
}
|
||||
}
|
||||
|
||||
UI.addField({
|
||||
title: langPack.core.userSettings[key],
|
||||
val: val
|
||||
}).appendTo(cfg);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -23,20 +23,24 @@ function reloadUsers() {
|
|||
$("<th>",{class: "", text: langPack.core.iface.users.fullName}).appendTo(tx);
|
||||
$("<th>",{class: "", text: langPack.core.iface.users.eMainConfirmedQTitle}).appendTo(tx);
|
||||
$("<th>",{class: "", text: langPack.core.iface.users.active}).appendTo(tx);
|
||||
$("<th>",{class: "button", style: "text-align: center", append: $("<i>",{class: "fas fa-ellipsis-h"})}).appendTo(tx);
|
||||
tx.appendTo("div.widget.users");
|
||||
|
||||
let i=0;
|
||||
$.each(json.data, function(idx, user) {
|
||||
i++;
|
||||
let row=$("<tr>",{});
|
||||
let row=$("<tr>",{}).bind('contextmenu', usmContextMenuOpen).addClass("contextMenu").attr("userId",user.id).attr("xenabled",user.active?1:0).attr("xemconf",user.eMailConfirmed?1:0);
|
||||
$("<td>",{class: "idx", text: i}).appendTo(row);
|
||||
$("<td>",{class: "", text: UI.formatInvCode(user.invCode)}).appendTo(row);
|
||||
$("<td>",{class: "xInvCode", text: UI.formatInvCode(user.invCode)}).appendTo(row);
|
||||
$("<td>",{class: "", text: user.login}).appendTo(row);
|
||||
$("<td>",{class: "", text: user.eMail}).appendTo(row);
|
||||
$("<td>",{class: "", text: user.fullName}).appendTo(row);
|
||||
$("<td>",{class: "xFullName", text: user.fullName}).appendTo(row);
|
||||
$("<td>",{class: "", text: user.eMailConfirmed}).appendTo(row);
|
||||
$("<td>",{class: "", text: user.active}).appendTo(row);
|
||||
|
||||
$("<td>",{class: "button", style: "text-align: center", append: $("<i>",{class: "fas fa-ellipsis-h"})})
|
||||
.click(usmContextMenuOpen)
|
||||
.appendTo(row);
|
||||
//row.foxClick("/"+UI.parceURL().module+"/user/"+user.id);
|
||||
|
||||
$("<tbody>",{append: row}).appendTo(tx);
|
||||
});
|
||||
|
@ -44,6 +48,84 @@ function reloadUsers() {
|
|||
})
|
||||
}
|
||||
|
||||
function usmContextMenuOpen(el) {
|
||||
let userUID=$(el.target).closest("tr").find("td.xInvCode").text();
|
||||
let userName=$(el.target).closest("tr").find("td.xFullName").text();
|
||||
let userEnabled=$(el.target).closest("tr").attr("xenabled")==1;
|
||||
let xemconf=$(el.target).closest("tr").attr("xemconf")==1;
|
||||
let userId=$(el.target).closest("tr").attr("userId");
|
||||
|
||||
let menuitems=[];
|
||||
if (userEnabled) {
|
||||
menuitems.push({title: langPack.core.iface.disable, onClick: function() {
|
||||
toggleUserEnabled(userId,false, el)
|
||||
}})
|
||||
} else {
|
||||
menuitems.push({title: langPack.core.iface.enable, onClick: function() {
|
||||
toggleUserEnabled(userId,true, el);
|
||||
}})
|
||||
}
|
||||
|
||||
menuitems.push({title: langPack.core.iface.delete, onClick: function() {
|
||||
deleteUser(userId, el);
|
||||
}});
|
||||
|
||||
if (!xemconf && userEnabled) {
|
||||
menuitems.push({title: langPack.core.iface.users.resendConfirmationCode, onClick: function() {
|
||||
API.exec({
|
||||
requestType: "GET",
|
||||
method: "core/user/"+userId+"/sendEMailConfirmation",
|
||||
})
|
||||
}});
|
||||
}
|
||||
|
||||
UI.contextMenuOpen(el,menuitems,userUID+" "+userName);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function toggleUserEnabled(userId, state, ref) {
|
||||
|
||||
var buttons={};
|
||||
buttons[langPack.core.iface.dialodSaveButton]=function() {
|
||||
$("#dialogInfo").dialog("close");
|
||||
API.exec({
|
||||
requestType: "PATCH",
|
||||
method: "core/user/"+userId,
|
||||
data: {"enabled": state==true?1:0 },
|
||||
onSuccess: reloadUsers,
|
||||
errDict: langPack.core.iface.groups.errors,
|
||||
});
|
||||
};
|
||||
|
||||
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
||||
|
||||
UI.showInfoDialog(langPack.core.iface[state?"enable":"disable"]+" #"+userId+" "+$(ref.target).closest("tr").find("td.xFullName").text()+"?",langPack.core.iface[state?"enable":"disable"],buttons);
|
||||
|
||||
|
||||
}
|
||||
|
||||
function deleteUser(userId, ref) {
|
||||
|
||||
var buttons={};
|
||||
buttons[langPack.core.iface.dialodDelButton]=function() {
|
||||
$("#dialogInfo").dialog("close");
|
||||
API.exec({
|
||||
requestType: "DELETE",
|
||||
method: "core/user/"+userId,
|
||||
onSuccess: reloadUsers,
|
||||
errDict: langPack.core.iface.groups.errors,
|
||||
});
|
||||
};
|
||||
|
||||
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
||||
|
||||
UI.showInfoDialog(langPack.core.iface.delete+" #"+userId+" "+$(ref.target).closest("tr").find("td.xFullName").text()+"?",langPack.core.iface.delete,buttons);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function reloadInvites() {
|
||||
$("div.widget.invites").empty();
|
||||
API.exec("GET","core/userInvitation/list",{},function(json) {
|
||||
|
|
|
@ -42,13 +42,18 @@ export var langItem={
|
|||
open: "Открыть",
|
||||
dialodAddButton: "Добавить",
|
||||
dialodCreateButton: "Создать",
|
||||
dialodSaveButton: "Записать",
|
||||
dialodSaveButton: "Сохранить",
|
||||
dialodInfoTitle: "Информация",
|
||||
dialogRegisterButton: "Регистрация",
|
||||
dialogRecoveryButton: "Восстановить",
|
||||
dialogRegisterTitle: "Регистрация",
|
||||
dialogReсoveryTitle: "Восстановление доступа",
|
||||
genDescTitle: "Информация",
|
||||
configTitle: "Настройки",
|
||||
messagesTitle: "Сообщения",
|
||||
agreementsTitle: "Документы для ознакомления",
|
||||
logTitle: "История",
|
||||
messengersTitle: "Мессенджеры",
|
||||
contextMenuCopySelected: "Копировать выделение",
|
||||
contextMenu: "Открыть действия",
|
||||
actions: "Действия",
|
||||
|
@ -76,6 +81,10 @@ export var langItem={
|
|||
company: "Компания",
|
||||
companies: "Компании",
|
||||
uid: "UID",
|
||||
filesClickForSelect: "Нажмите для выбора файла",
|
||||
filesSelected: "Выбрано",
|
||||
filesFile: "файл",
|
||||
filesFiles: "файлов",
|
||||
comps: {
|
||||
qName: "Алиас",
|
||||
company: "Компания",
|
||||
|
@ -137,6 +146,7 @@ export var langItem={
|
|||
invitationExpire: "Срок действия",
|
||||
inviteToGroupTitleQ: "Группы",
|
||||
delInvDialogTitle: "Удалить приглашение",
|
||||
resendConfirmationCode: "Отправить код подтверждения",
|
||||
recoveryFormText: "Укажите адрес электронной почты, на который был зарегистрирован аккаунт и код подтверждения (если есть), полученный по eMail для завершения восстановления",
|
||||
recoverSentSucces: "Код подтверждения отправлен на указанный адрес. Введите его в поле \"код\" для продолжения процедуры.",
|
||||
enterNewPasswordText: "Введите новый пароль",
|
||||
|
@ -154,7 +164,7 @@ export var langItem={
|
|||
RNE: "Регистрация запрещена. Обратитесь к администратору для получения приглашения",
|
||||
ILF: "Некорректный формат логина - логин не может начинаться с цифры, может содержать цифры и буквы, а так же должен быть не мельше 5 символов.",
|
||||
IPF: "Некорректный формат пароля. Пароль должен быть не меньше 6 символов и содержать в своем составе цифры, буквы и спец. символы",
|
||||
URNF: "Пользователь не найден либо восстановление пароля не предусмотрено спосбом авторизации",
|
||||
URNF: "Пользователь не найден либо восстановление пароля не предусмотрено способом авторизации",
|
||||
IVCC: "Некорректный код подтверждения. Проверьте правильность кода и повторите попытку.",
|
||||
}
|
||||
},
|
||||
|
@ -188,6 +198,15 @@ export var langItem={
|
|||
}
|
||||
|
||||
},
|
||||
languages: {
|
||||
ru: "Русский",
|
||||
en: "Английский",
|
||||
},
|
||||
userSettings: {
|
||||
language: "Язык интерфейса",
|
||||
pageSize: "Элементов на странице",
|
||||
theme: "Тема оформления",
|
||||
},
|
||||
breadcrumbs: {
|
||||
modTitle: "Система",
|
||||
modules: "Модули",
|
||||
|
|
|
@ -347,7 +347,7 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
|||
}
|
||||
}
|
||||
|
||||
item = $("<input>", {class: "i", id: ref.item, name: name, width: 'calc(100% - 44px)'})
|
||||
item = $("<input>", {type: "password", class: "i", id: ref.item, name: name, width: 'calc(100% - 44px)'})
|
||||
.add($("<div>",{
|
||||
class: "button short",
|
||||
style: "width: 25px; margin-right: 0; margin-left: 2; padding: 0; padding-top: 1; font-size: 13px;",
|
||||
|
@ -359,6 +359,8 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
|||
}
|
||||
let password=genPassword(args.chars, args.length);
|
||||
$("#"+item_id).val(password);
|
||||
$("#"+item_id).prop("type","input");
|
||||
|
||||
$("#"+item_id).change();
|
||||
if (typeof(ref.newPasswdGenCallback)=="function") {
|
||||
ref.newPasswdGenCallback(password);
|
||||
|
@ -372,9 +374,9 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
|||
if (ref.args !== undefined) {
|
||||
$.each(ref.args, function(arg,val) {
|
||||
if (typeof(val)=='array' || typeof(val)=='object') {
|
||||
item.append($("<option>",{value: val.val, text: val.title}));
|
||||
item.append($("<option>",{value: val.val, text: val.title, selected: val.val==ref.val}));
|
||||
} else {
|
||||
item.append($("<option>",{value: arg, text: val}));
|
||||
item.append($("<option>",{value: arg, text: val, selected: arg==ref.val}));
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -394,6 +396,36 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
|||
|
||||
break;
|
||||
|
||||
case "file":
|
||||
item = $("<input>",{
|
||||
type: "file",
|
||||
id: ref.item,
|
||||
class: "ifile",
|
||||
multiple: ref.multiple==true,
|
||||
change: function(ref) {
|
||||
let files=ref.currentTarget.files;
|
||||
let label=$("#"+ref.currentTarget.id+"__labelTitle");
|
||||
|
||||
$("#"+ref.currentTarget.id+"__label").addClass("changed");
|
||||
if (files.length==0) {
|
||||
label.text(langPack.core.iface.filesClickForSelect);
|
||||
} else if (files.length==1) {
|
||||
label.text(langPack.core.iface.filesSelected+": 1 "+langPack.core.iface.filesFile);
|
||||
} else {
|
||||
label.text(langPack.core.iface.filesSelected+": "+files.length+" "+langPack.core.iface.filesFiles);
|
||||
}
|
||||
},
|
||||
})
|
||||
.add($("<label>", {
|
||||
id: ref.item+"__label",
|
||||
for: ref.item,
|
||||
append: $("<i>",{ class: "far fa-save", title: langPack.core.iface.filesClickForSelect})
|
||||
.add($("<span>",{style: "margin-left: 10px;", id: ref.item+"__labelTitle",text: langPack.core.iface.filesClickForSelect}))
|
||||
,
|
||||
}))
|
||||
|
||||
break;
|
||||
|
||||
case "label":
|
||||
item = $("<span>", {id: ref.item, class: "i", html: ref.val});
|
||||
break;
|
||||
|
@ -501,7 +533,7 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
|||
if (typeof(ref.onContextMenu)=="function") {
|
||||
rv.bind('contextmenu', ref.onContextMenu);
|
||||
rv.addClass("withContextMenu");
|
||||
rvv.append($("<i>",{style: "padding: 0 10px 0 10px; float: right;", class: "fas fa-ellipsis-v"}).bind('contextmenu click', ref.onContextMenu))
|
||||
rvv.append($("<i>",{style: "width: 50px; text-align: right; padding-right: 10px;", class: "fas fa-ellipsis-v"}).bind('contextmenu click', ref.onContextMenu))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,6 +646,15 @@ export function genPassword(chars, passwordLength) {
|
|||
return password;
|
||||
}
|
||||
|
||||
export function getId(ref) {
|
||||
if (ref.id) {
|
||||
return ref.id;
|
||||
} else if (ref[0] && ref[0].id) {
|
||||
return ref[0].id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function collectForm(formid, getall, withIDS, withREF, validate)
|
||||
{
|
||||
if (typeof(formid)=='object') {
|
||||
|
@ -633,9 +674,10 @@ export function collectForm(formid, getall, withIDS, withREF, validate)
|
|||
var cctr=0;
|
||||
var cerr=0;
|
||||
var key;
|
||||
|
||||
$('#'+formid+' .i'+((getall==true)?"":'.changed')).each(function() {
|
||||
if (isset(this.name)) {key = this.name} else {key = this.id}
|
||||
|
||||
if(!isset(key)) { return; }
|
||||
if (getall) {
|
||||
|
||||
var reqx="false";
|
||||
|
@ -723,11 +765,13 @@ export function createDialog(body, title, buttons, height, columns, id) {
|
|||
if (id==undefined) {id = 'dialogForm'; }
|
||||
if (columns=='undefined') { columns=1; }
|
||||
|
||||
$("<div>",{
|
||||
let dx=$("<div>",{
|
||||
id: id,
|
||||
title: title,
|
||||
style: "overflow: hidden;"
|
||||
}).appendTo("body")
|
||||
})
|
||||
.prop("dxColumns",columns)
|
||||
.appendTo("body")
|
||||
.dialog({
|
||||
autoOpen: false,
|
||||
height: height,
|
||||
|
@ -740,18 +784,54 @@ export function createDialog(body, title, buttons, height, columns, id) {
|
|||
buttons: buttons
|
||||
})
|
||||
.append(body);
|
||||
|
||||
return dx;
|
||||
|
||||
}
|
||||
|
||||
export function openDialog(id) {
|
||||
if (id==undefined) {id = 'dialogForm'; }
|
||||
let dx;
|
||||
if (typeof(id)=="object") {
|
||||
dx=$(id);
|
||||
id=dx.id;
|
||||
} else {
|
||||
dx=$("#"+id);
|
||||
}
|
||||
|
||||
$("#"+id+' .i').on("change",function() {on_valChanged($(this)); });
|
||||
$("#"+id).dialog("open");
|
||||
dx.dialog("open");
|
||||
|
||||
let height=$("#"+id).dialog("option","height");
|
||||
|
||||
if (!height) {
|
||||
|
||||
let summHeight=0;
|
||||
let maxHeight=0;
|
||||
let columns = dx.prop("dxColumns");
|
||||
|
||||
$.each(dx.find(".crm_entity_block_group"), function(_key,val) {
|
||||
summHeight +=val.clientHeight;
|
||||
if (val.clientHeight>maxHeight) { maxHeight=val.clientHeight; }
|
||||
})
|
||||
|
||||
let halfHeight=Math.ceil(summHeight/columns);
|
||||
let xHeight=(maxHeight>halfHeight)?maxHeight:halfHeight;
|
||||
|
||||
dx.dialog("option","height", xHeight+180);
|
||||
}
|
||||
}
|
||||
|
||||
export function closeDialog(id) {
|
||||
if (id==undefined) {id = 'dialogForm'; }
|
||||
$("#"+id).dialog("close");
|
||||
$("#"+id).remove();
|
||||
let dx;
|
||||
if (typeof(id)=="object") {
|
||||
dx=$(id);
|
||||
} else {
|
||||
dx=$("#"+id);
|
||||
}
|
||||
dx.dialog("close");
|
||||
dx.remove();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ function doValidation(code) {
|
|||
};
|
||||
|
||||
UI.showInfoDialog(langPack.core.iface.ok0,langPack.core.iface.dialodInfoTitle,buttons);
|
||||
API.session.reload();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -957,6 +957,12 @@ div.crm_entity_field_block.withContextMenu a {
|
|||
cursor: context-menu;
|
||||
}
|
||||
|
||||
div.crm_entity_field_block.withContextMenu span,
|
||||
div.crm_entity_field_block.withContextMenu title,
|
||||
div.crm_entity_field_block.withContextMenu a {
|
||||
margin-right: -60px;
|
||||
}
|
||||
|
||||
|
||||
table.datatable.sel tr:hover td
|
||||
|
||||
|
@ -1246,7 +1252,12 @@ div.crm_entity_field_block input, div.crm_entity_field_block select
|
|||
{
|
||||
height: 26px;
|
||||
}
|
||||
div.crm_entity_field_block input, div.crm_entity_field_block select, div.crm_entity_field_block textarea
|
||||
div.crm_entity_field_block input,
|
||||
div.crm_entity_field_block select,
|
||||
div.crm_entity_field_block textarea,
|
||||
div.crm_entity_field_block label,
|
||||
div.crm_entity_field_block span.i,
|
||||
div.crm_entity_field_block a.i
|
||||
{
|
||||
|
||||
border: none;
|
||||
|
@ -1256,6 +1267,23 @@ div.crm_entity_field_block input, div.crm_entity_field_block select, div.crm_ent
|
|||
outline: none;
|
||||
background: none;
|
||||
}
|
||||
div.crm_entity_field_block label {
|
||||
display: inline-block;
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
div.crm_entity_field_block span.i,
|
||||
div.crm_entity_field_block a.i
|
||||
{
|
||||
border-bottom-color: rgba(100,100,100,0.1);
|
||||
}
|
||||
div.crm_entity_field_block label,
|
||||
div.crm_entity_field_block span.i,
|
||||
div.crm_entity_field_block a.i
|
||||
{
|
||||
display: inline-block;
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
/* panel_full_normal */
|
||||
div.crm_entity_field_value,
|
||||
|
@ -1271,7 +1299,10 @@ div.crm_entity_block_group
|
|||
|
||||
div.crm_entity_field_block input,
|
||||
div.crm_entity_field_block select,
|
||||
div.crm_entity_field_block textarea
|
||||
div.crm_entity_field_block textarea,
|
||||
div.crm_entity_field_block label,
|
||||
div.crm_entity_field_block span.i,
|
||||
div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 300px;
|
||||
padding: 0 0 0 10px;
|
||||
|
@ -1293,7 +1324,10 @@ div.crm_entity_field_block textarea
|
|||
}
|
||||
.full-width-input div.crm_entity_field_block input,
|
||||
.full-width-input div.crm_entity_field_block select,
|
||||
.full-width-input div.crm_entity_field_block textarea
|
||||
.full-width-input div.crm_entity_field_block textarea,
|
||||
.full-width-input div.crm_entity_field_block label,
|
||||
.full-width-input div.crm_entity_field_block span.i,
|
||||
.full-width-input div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 1633px;
|
||||
}
|
||||
|
@ -1312,7 +1346,10 @@ div.widget_panel_left div.crm_entity_block_group
|
|||
|
||||
div.widget_panel_left div.crm_entity_field_block input,
|
||||
div.widget_panel_left div.crm_entity_field_block select,
|
||||
div.widget_panel_left div.crm_entity_field_block textarea
|
||||
div.widget_panel_left div.crm_entity_field_block textarea,
|
||||
div.widget_panel_left div.crm_entity_field_block label,
|
||||
div.widget_panel_left div.crm_entity_field_block span.i,
|
||||
div.widget_panel_left div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 280px;
|
||||
}
|
||||
|
@ -1320,6 +1357,9 @@ div.widget_panel_left div.crm_entity_field_block textarea
|
|||
div.widget_panel_left div.crm_entity_field_block input.half,
|
||||
div.widget_panel_left div.crm_entity_field_block select.half,
|
||||
div.widget_panel_left div.crm_entity_field_block textarea.half
|
||||
div.widget_panel_left div.crm_entity_field_block label.half,
|
||||
div.widget_panel_left div.crm_entity_field_block span.i.half,
|
||||
div.widget_panel_left div.crm_entity_field_block a.i.half
|
||||
{
|
||||
width: 132px;
|
||||
}
|
||||
|
@ -1338,7 +1378,10 @@ div.widget_panel_right div.crm_entity_block_group
|
|||
|
||||
div.widget_panel_right div.crm_entity_field_block input,
|
||||
div.widget_panel_right div.crm_entity_field_block select,
|
||||
div.widget_panel_right div.crm_entity_field_block textarea
|
||||
div.widget_panel_right div.crm_entity_field_block textarea,
|
||||
div.widget_panel_right div.crm_entity_field_block label,
|
||||
div.widget_panel_right div.crm_entity_field_block span.i,
|
||||
div.widget_panel_right div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 300px;
|
||||
}
|
||||
|
@ -1355,7 +1398,10 @@ div.ui-dialog-content div.crm_entity_block_group
|
|||
}
|
||||
|
||||
div.ui-dialog-content div.crm_entity_field_block input,
|
||||
div.ui-dialog-content div.crm_entity_field_block textarea
|
||||
div.ui-dialog-content div.crm_entity_field_block textarea,
|
||||
div.ui-dialog-content div.crm_entity_field_block label,
|
||||
div.ui-dialog-content div.crm_entity_field_block span.i,
|
||||
div.ui-dialog-content div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 290px;
|
||||
}
|
||||
|
@ -1379,13 +1425,21 @@ div.widget_panel_right table.t_icon div.crm_entity_block_group
|
|||
|
||||
div.widget_panel_right table.t_icon div.crm_entity_field_block input,
|
||||
div.widget_panel_right table.t_icon div.crm_entity_field_block select,
|
||||
div.widget_panel_right table.t_icon div.crm_entity_field_block textarea
|
||||
div.widget_panel_right table.t_icon,
|
||||
div.widget_panel_right table.t_icon div.crm_entity_field_block label,
|
||||
div.widget_panel_right table.t_icon div.crm_entity_field_block span.i,
|
||||
div.widget_panel_right table.t_icon div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 290px;
|
||||
}
|
||||
|
||||
|
||||
div.crm_entity_field_block input.half, div.crm_entity_field_block select.half, div.crm_entity_field_block textarea.half
|
||||
div.crm_entity_field_block input.half,
|
||||
div.crm_entity_field_block select.half,
|
||||
div.crm_entity_field_block textarea.half,
|
||||
div.crm_entity_field_block label.half,
|
||||
div.crm_entity_field_block span.i.half,
|
||||
div.crm_entity_field_block a.i.half
|
||||
{
|
||||
width: 130px;
|
||||
}
|
||||
|
@ -1393,9 +1447,15 @@ div.crm_entity_field_block input.half, div.crm_entity_field_block select.half, d
|
|||
div.crm_entity_field_block input:focus,
|
||||
div.crm_entity_field_block select:focus,
|
||||
div.crm_entity_field_block textarea:focus,
|
||||
div.crm_entity_field_block label:focus,
|
||||
div.crm_entity_field_block span.i:focus,
|
||||
div.crm_entity_field_block a.i:focus,
|
||||
div.crm_entity_field_block input:focus.changed,
|
||||
div.crm_entity_field_block select:focus.changed,
|
||||
div.crm_entity_field_block textarea:focus.changed
|
||||
div.crm_entity_field_block label:focus.changed,
|
||||
div.crm_entity_field_block span.i:focus.changed,
|
||||
div.crm_entity_field_block a.i:focus.changed
|
||||
{
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--mxs-green);
|
||||
|
@ -1406,7 +1466,12 @@ div.widget_panel_left div.crm_entity_block_group
|
|||
margin-right: 0px;
|
||||
}
|
||||
|
||||
div.crm_entity_field_block input:disabled,div.crm_entity_field_block select:disabled,div.crm_entity_field_block textarea:disabled
|
||||
div.crm_entity_field_block input:disabled,
|
||||
div.crm_entity_field_block select:disabled,
|
||||
div.crm_entity_field_block textarea:disabled,
|
||||
div.crm_entity_field_block label:disabled,
|
||||
div.crm_entity_field_block span.i:disabled,
|
||||
div.crm_entity_field_block a.i:disabled
|
||||
{
|
||||
border: none;
|
||||
border-bottom: 1px double var(--mxs-gray);
|
||||
|
@ -1644,21 +1709,30 @@ table.t_icon
|
|||
|
||||
div.crm_entity_field_block input.changed,
|
||||
div.crm_entity_field_block select.changed,
|
||||
div.crm_entity_field_block textarea.changed
|
||||
div.crm_entity_field_block textarea.changed,
|
||||
div.crm_entity_field_block label.changed,
|
||||
div.crm_entity_field_block span.i.changed,
|
||||
div.crm_entity_field_block a.i.changed
|
||||
{
|
||||
border-bottom-color: rgba(255,111,16,0.6);
|
||||
}
|
||||
|
||||
div.crm_entity_field_block input.saved,
|
||||
div.crm_entity_field_block select.saved,
|
||||
div.crm_entity_field_block textarea.saved
|
||||
div.crm_entity_field_block textarea.saved,
|
||||
div.crm_entity_field_block label.saved,
|
||||
div.crm_entity_field_block span.i.saved,
|
||||
div.crm_entity_field_block a.i.saved
|
||||
{
|
||||
border-bottom-color: var(--mxs-green);
|
||||
}
|
||||
|
||||
div.crm_entity_field_block input.alert,
|
||||
div.crm_entity_field_block select.alert,
|
||||
div.crm_entity_field_block textarea.alert
|
||||
div.crm_entity_field_block textarea.alert,
|
||||
div.crm_entity_field_block label.alert,
|
||||
div.crm_entity_field_block span.i.alert,
|
||||
div.crm_entity_field_block a.i.alert
|
||||
{
|
||||
border-bottom-color: var(--mxs-red);
|
||||
background-color: var(--mxs-inputalertbg);
|
||||
|
@ -1904,7 +1978,10 @@ div.crm_entity_block_group
|
|||
|
||||
div.crm_entity_field_block input,
|
||||
div.crm_entity_field_block select,
|
||||
div.crm_entity_field_block textarea
|
||||
div.crm_entity_field_block textarea,
|
||||
div.crm_entity_field_block label,
|
||||
div.crm_entity_field_block span.i,
|
||||
div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 304px;
|
||||
}
|
||||
|
@ -1923,7 +2000,10 @@ div.crm_entity_field_block textarea
|
|||
|
||||
.full-width-input div.crm_entity_field_block input,
|
||||
.full-width-input div.crm_entity_field_block select,
|
||||
.full-width-input div.crm_entity_field_block textarea
|
||||
.full-width-input div.crm_entity_field_block textarea,
|
||||
.full-width-input div.crm_entity_field_block label,
|
||||
.full-width-input div.crm_entity_field_block span.i,
|
||||
.full-width-input div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 1310px;
|
||||
}
|
||||
|
@ -1984,7 +2064,10 @@ div.crm_entity_block_group
|
|||
|
||||
div.crm_entity_field_block input,
|
||||
div.crm_entity_field_block select,
|
||||
div.crm_entity_field_block textarea
|
||||
div.crm_entity_field_block textarea,
|
||||
div.crm_entity_field_block label,
|
||||
div.crm_entity_field_block span.i,
|
||||
div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 307px;
|
||||
}
|
||||
|
@ -2003,7 +2086,10 @@ div.crm_entity_field_block textarea
|
|||
|
||||
.full-width-input div.crm_entity_field_block input,
|
||||
.full-width-input div.crm_entity_field_block select,
|
||||
.full-width-input div.crm_entity_field_block textarea
|
||||
.full-width-input div.crm_entity_field_block textarea,
|
||||
.full-width-input div.crm_entity_field_block label,
|
||||
.full-width-input div.crm_entity_field_block span.i,
|
||||
.full-width-input div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 993px;
|
||||
}
|
||||
|
@ -2115,7 +2201,10 @@ div.header
|
|||
|
||||
.full-width-input div.crm_entity_field_block input,
|
||||
.full-width-input div.crm_entity_field_block select,
|
||||
.full-width-input div.crm_entity_field_block textarea
|
||||
.full-width-input div.crm_entity_field_block textarea,
|
||||
.full-width-input div.crm_entity_field_block label,
|
||||
.full-width-input div.crm_entity_field_block span.i,
|
||||
.full-width-input div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 993px;
|
||||
}
|
||||
|
@ -2233,14 +2322,20 @@ div.widget_panel_left div.crm_entity_field_input
|
|||
|
||||
div.widget_panel_left div.crm_entity_field_block input,
|
||||
div.widget_panel_left div.crm_entity_field_block select,
|
||||
div.widget_panel_left div.crm_entity_field_block textarea
|
||||
div.widget_panel_left div.crm_entity_field_block textarea,
|
||||
div.widget_panel_left div.crm_entity_field_block label,
|
||||
div.widget_panel_left div.crm_entity_field_block span.i,
|
||||
div.widget_panel_left div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 322px;
|
||||
}
|
||||
|
||||
div.widget_panel_left div.crm_entity_field_block input.half,
|
||||
div.widget_panel_left div.crm_entity_field_block select.half,
|
||||
div.widget_panel_left div.crm_entity_field_block textarea.half
|
||||
div.widget_panel_left div.crm_entity_field_block textarea.half,
|
||||
div.widget_panel_left div.crm_entity_field_block label.half,
|
||||
div.widget_panel_left div.crm_entity_field_block span.i.half,
|
||||
div.widget_panel_left div.crm_entity_field_block a.i.half
|
||||
{
|
||||
width: 153px;
|
||||
}
|
||||
|
@ -2259,14 +2354,20 @@ div.crm_entity_block_group
|
|||
|
||||
div.crm_entity_field_block input,
|
||||
div.crm_entity_field_block select,
|
||||
div.crm_entity_field_block textarea
|
||||
div.crm_entity_field_block textarea,
|
||||
div.crm_entity_field_block label,
|
||||
div.crm_entity_field_block span.i,
|
||||
div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 315px;
|
||||
}
|
||||
|
||||
div.crm_entity_field_block input.half,
|
||||
div.crm_entity_field_block select.half,
|
||||
div.crm_entity_field_block textarea.half
|
||||
div.crm_entity_field_block textarea.half,
|
||||
div.crm_entity_field_block label.half,
|
||||
div.crm_entity_field_block span.i.half,
|
||||
div.crm_entity_field_block a.i.half
|
||||
{
|
||||
width: 150px;
|
||||
}
|
||||
|
@ -2290,7 +2391,10 @@ div.login
|
|||
|
||||
.full-width-input div.crm_entity_field_block input,
|
||||
.full-width-input div.crm_entity_field_block select,
|
||||
.full-width-input div.crm_entity_field_block textarea
|
||||
.full-width-input div.crm_entity_field_block textarea,
|
||||
.full-width-input div.crm_entity_field_block label,
|
||||
.full-width-input div.crm_entity_field_block span.i,
|
||||
.full-width-input div.crm_entity_field_block a.i
|
||||
{
|
||||
width: 670px;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue