From eab59a060b178f7fde9ed6170a0c838c41519f9f Mon Sep 17 00:00:00 2001 From: Palkan Date: Tue, 14 Jun 2022 15:16:56 +0300 Subject: [PATCH] Weekly sync 2022-06-14 --- api/v2.php | 3 + core/fox/UUID.php | 115 ++++++++++++++++++++++++++++++++++++ core/fox/baseClass.php | 9 +-- core/fox/common.php | 6 +- core/fox/modules.php | 4 ++ core/fox/request.php | 21 +++++++ core/fox/user.php | 38 ++++++++++++ core/fox/userGroup.php | 49 +++++++++++---- static/js/core/coreGroup.js | 2 +- static/js/core/lang_ru.js | 1 + static/js/core/login.js | 3 + static/js/core/ui.js | 34 ++++++++++- static/theme/core/main.css | 11 ++++ 13 files changed, 274 insertions(+), 22 deletions(-) create mode 100644 core/fox/UUID.php diff --git a/api/v2.php b/api/v2.php index 3c28567..6d9a1ea 100644 --- a/api/v2.php +++ b/api/v2.php @@ -54,6 +54,8 @@ try { } ob_clean(); + header('Content-Type: application/json; charset=utf-8'); + $apiMethod=fox\common::clearInput($request->method,"A-Z"); $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"); @@ -78,6 +80,7 @@ try { } 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()]); diff --git a/core/fox/UUID.php b/core/fox/UUID.php new file mode 100644 index 0000000..0834b5a --- /dev/null +++ b/core/fox/UUID.php @@ -0,0 +1,115 @@ +__settings = $settings; if (empty($this::$baseSqlSelectTemplate) && ! empty($this::$sqlTable)) { - $this->__sqlSelectTemplate = "select * from `" . $this::$sqlTable . "` as `i`"; + $this->__sqlSelectTemplate = "select `i`.* from `" . $this::$sqlTable . "` as `i`"; } else { $this->__sqlSelectTemplate = $this::$baseSqlSelectTemplate; } @@ -589,10 +589,11 @@ class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportabl } $xRes=static::xSearch($where, $pattern, $options, $sql); - $where = $xRes["where"]; - $join=$xRes["join"]; + $where = array_key_exists("where",$xRes)?$xRes["where"]:""; + $join=array_key_exists("join",$xRes)?$xRes["join"]:""; + $groupBy=array_key_exists("group",$xRes)?$xRes["group"]:""; - $sqlQueryString=$ref->sqlSelectTemplate.(empty($join)?"":" ".$join).(empty($where)?"":" WHERE ".$where).(empty($limit)?"":" ".$limit); + $sqlQueryString=$ref->sqlSelectTemplate.(empty($join)?"":" ".$join).(empty($where)?"":" WHERE ".$where).(empty($groupBy)?"":" GROUP BY ".$groupBy).(empty($limit)?"":" ".$limit); $res=$sql->quickExec($sqlQueryString); $rv=new searchResult(); diff --git a/core/fox/common.php b/core/fox/common.php index 075a52c..baaec4a 100644 --- a/core/fox/common.php +++ b/core/fox/common.php @@ -90,11 +90,7 @@ class common static function getGUIDc() { - mt_srand((double) microtime() * 10000); // optional for php 4.2.0 and up. - $charid = strtoupper(md5(uniqid(rand(), true))); - $hyphen = chr(45); // "-" - return substr($charid, 0, 8) . $hyphen . substr($charid, 8, 4) . $hyphen . substr($charid, 12, 4) . $hyphen . substr($charid, 16, 4) . $hyphen . substr($charid, 20, 12); - + return strtoupper(UUID::v4()); } static function getGUID() diff --git a/core/fox/modules.php b/core/fox/modules.php index 60e7585..dfbeeb3 100644 --- a/core/fox/modules.php +++ b/core/fox/modules.php @@ -43,6 +43,10 @@ class modules implements externalCallable "adminAuthMethods"=>"Manage auth methods", "viewCompanies"=>"View companies", "adminCompanies"=>"Manage companies", + "viewAllGroups"=>"Search in all groups and lists", + "viewAllLists"=>"Search in all lists", + "viewAllUsers"=>"Search in all users", + "viewOwnListsUsers"=>"Search users only from own lists" ], "configKeys"=> [ "converterURL"=>"FoxConverter URL prefix", diff --git a/core/fox/request.php b/core/fox/request.php index 9d2c0f3..c9a1ed1 100644 --- a/core/fox/request.php +++ b/core/fox/request.php @@ -180,6 +180,27 @@ class request extends baseClass implements noSqlMigration throw new foxException("Forbidden", 403); } } + + public function checkAccess(string $rule, string $modInstance=null) { + if ($modInstance==null) { $modInstance=$this->instance; } + return $this->user->checkAccess($rule, $modInstance); + } + + public function getRequestBodyItem($key) { + if ($this->requestBody!=null && property_exists($this->requestBody, $key)) { + return $this->requestBody->{$key}; + } else { + return null; + } + } + + public function getParamItem($key) { + if ($this->parameters !=null && array_key_exists($key, $this->parameters)) { + return $this->parameters[$key]; + } else { + return null; + } + } } ?> \ No newline at end of file diff --git a/core/fox/user.php b/core/fox/user.php index 5a841c0..b54c6ef 100644 --- a/core/fox/user.php +++ b/core/fox/user.php @@ -284,6 +284,22 @@ class user extends baseClass implements externalCallable $rv["config"]=(object)$this->config; return $rv; } + /** + * @param array $options - ["groups" - array of userGroup, if set - search will performed only in it] + */ + protected static function xSearch($where, $pattern, ?array $options, sql $sql) { + $ruleJoin=null; + + if ($options["groups"]) { + $groups=""; + foreach ($options["groups"] as $group) { + $groups .= (empty($groups)?"":",")."\"".$group->id."\""; + } + $ruleJoin = " INNER JOIN `tblUserGroupLink` as `l` on `l`.`userId`=`i`.`id` AND `l`.`groupId` in ($groups)"; + } + + return ["where"=>$where, "join"=>$ruleJoin, "group"=>"`i`.`id`"]; + } ### REST API public static function API_GET_list(request $request) @@ -295,6 +311,28 @@ class user extends baseClass implements externalCallable } public static function API_POST_search(request $request) { + + $opts=[]; + if ($request->checkAccess("viewAllUsers") || $request->checkAccess("adminUsers")) { + $opts=[]; + } else if ($request->checkAccess("viewOwnListsUsers")) { + $opts = [ + "groups"=>userGroup::getForUser($request->user,true), + ]; + } else { + $rv=new searchResult(); + $rv->push($request->user); + return $rv; + + } + + return static::search( + $request->getRequestBodyItem("pattern"), + $request->getRequestBodyItem("pageSize"), + $request->getRequestBodyItem("page"), + $opts + ); + if (! $request->user->checkAccess("adminUsers", "core")) { throw new foxException("Forbidden", 403); } diff --git a/core/fox/userGroup.php b/core/fox/userGroup.php index ff9d3e1..c35bfc4 100644 --- a/core/fox/userGroup.php +++ b/core/fox/userGroup.php @@ -40,7 +40,8 @@ class userGroup extends baseClass implements externalCallable public static $sqlColumns = [ "name" => [ "type" => "VARCHAR(255)", - "index" => "INDEX" + "index" => "INDEX", + "search"=>"LIKE", ], "companyId" => [ "type" => "INT", @@ -87,22 +88,18 @@ class userGroup extends baseClass implements externalCallable * */ protected static function xSearch($where, $pattern, ?array $options, sql $sql) { - $accessRule=(empty($options["accessRule"])?null:$options["accessRule"]); $isList=(array_key_exists("isList", $options)?$options["isList"]:false); $ruleJoin=null; - $ruleWhere=null; - + if ($isList !== false) { - $ruleWhere .= " and `i`.`isList` = " . ($isList == true ? 1 : 0); + $where = (empty($where)?"":"( $where ) and ")."`i`.`isList` = " . ($isList == true ? 1 : 0); } - if (empty($ruleWhere)) { - $xWhere=$where; - } else { - $xWhere=(empty($where)?$ruleWhere:"(".$where.") AND ".$ruleWhere); + if ($options["user"]) { + $ruleJoin = " INNER JOIN `tblUserGroupLink` as `l` on `l`.`groupId`=`i`.`id` AND `l`.`userId`='".$options["user"]->id."'"; } - - return ["where"=>$xWhere, "join"=>$ruleJoin]; + + return ["where"=>$where, "join"=>$ruleJoin]; } public function join(user $user) @@ -167,6 +164,36 @@ class userGroup extends baseClass implements externalCallable } } + ### REST API + + public static function API_POST_search(request $request) { + + $opts=[]; + if ($request->checkAccess("viewAllGroups")) { + $opts=[ + "user"=>$request->getRequestBodyItem("own",true)?$request->user:null, + "isList"=>$request->getRequestBodyItem("type")=="list", + ]; + } else if ($request->checkAccess("viewAllLists")) { + $opts = [ + "user"=>$request->getRequestBodyItem("own",true)?$request->user:null, + "isList"=>true, + ]; + } else { + $opts = [ + "user"=>$request->user, + "isList"=>true, + ]; + + } + return static::search( + $request->getRequestBodyItem("pattern"), + $request->getRequestBodyItem("pageSize"), + $request->getRequestBodyItem("page"), + $opts + ); + } + public static function API_GET_list(request $request) { if (! $request->user->checkAccess("adminUserGroups", "core")) { diff --git a/static/js/core/coreGroup.js b/static/js/core/coreGroup.js index b84eb5c..17c2693 100644 --- a/static/js/core/coreGroup.js +++ b/static/js/core/coreGroup.js @@ -190,7 +190,7 @@ function btnUserpAdd_click() { data: {pattern: request.term, pageSize: 10}, onSuccess: function(json) { let rv=[]; - $.each(json.data,function(key,val) { + $.each(json.data.result,function(key,val) { rv.push({id: val.id, value: val.fullName}); }); response(rv); diff --git a/static/js/core/lang_ru.js b/static/js/core/lang_ru.js index 76c881b..ae856c8 100644 --- a/static/js/core/lang_ru.js +++ b/static/js/core/lang_ru.js @@ -29,6 +29,7 @@ export var langItem={ set: "Установить", edit: "Изменить", copy: "Копировать", + copyHash: "Копировать указатель", paste: "Вставить", updated: "Обновлен", reload: "Обновить", diff --git a/static/js/core/login.js b/static/js/core/login.js index 728a03e..f621e2c 100644 --- a/static/js/core/login.js +++ b/static/js/core/login.js @@ -83,6 +83,9 @@ export function load() { }) }).appendTo("body"); + $("
",{ class: "poweredByCFOX", text: "Powered by Chimera FOX"}) + .appendTo("body") + let oap=API.settings.get("oauthProfiles"); if (oap.length>0) { let oad=$("
",{ class: "widget", id: "divAuthWith" }); diff --git a/static/js/core/ui.js b/static/js/core/ui.js index 4ec9c0c..004bd76 100644 --- a/static/js/core/ui.js +++ b/static/js/core/ui.js @@ -170,6 +170,19 @@ export function createRightPanel(panels) { createTabsPanel(panels,ref); } +export function tabPanelRenameTab(tabId, text) { + $("#a-tab-"+tabId).text(text); +} +export function tabPanelHideTab(tabId) { + $( "#item_tabs").tabs("disable","#tab-"+tabId); +} +export function tabPanelShowTab(tabId) { + $( "#item_tabs").tabs("enable","#tab-"+tabId); +} +export function tabPanelActivateTab(tabId) { + $("#item_tabs").tabs({active: Number($("#a-tab-"+tabId).attr("idx"))}); +} + export function createTabsPanel(panels,ref) { if (ref===undefined) { ref=$(".t_main #mainframe"); @@ -200,7 +213,7 @@ export function createTabsPanel(panels,ref) { $.each(panels,function (index,panel) { if (panel.id==undefined) {panel.id=index;} - $("
  • ",{append: $("",{href: "#tab-"+panel.id, id: "a-tab-"+panel.id, text: panel.title})}) + $("
  • ",{append: $("",{href: "#tab-"+panel.id, id: "a-tab-"+panel.id, text: panel.title}).attr("idx",index)}) .appendTo("#item_tabs_ul_list"); $("
    ", { id: "tab-"+panel.id, @@ -702,6 +715,25 @@ export function copySelText(selText) { } } +export function getClipboard(onSuccess, onFail) { + console.log(typeof(onFail)); + console.log(typeof(onSuccess)); + + navigator.clipboard.readText().then(text => { + console.log('Clipboard content is: ', text); + if (typeof(onSuccess)=="function") { + onSuccess(text); + } + }) + .catch(err => { + console.error('Failed to read clipboard contents: ', err); + if (typeof(onFail)=="function") { + + onFail(err); + } + }) +} + export function getSelectionText() { var text = ""; if (window.getSelection) { diff --git a/static/theme/core/main.css b/static/theme/core/main.css index 23b7db0..c17168c 100644 --- a/static/theme/core/main.css +++ b/static/theme/core/main.css @@ -42,6 +42,17 @@ .ui-dialog { z-index: 1000 !important ;} +div.poweredByCFOX { + position: absolute; + display: block; + bottom: 32px; + text-align: center; + width: 100%; + font-family: 'Jura', sans-serif; + font-size: 16px; + color: #024c68; +} + ul.ui-menu.ui-widget.ui-widget-content.ui-autocomplete.ui-front { z-index: 1200 !important; }