Permission stuff
This commit is contained in:
		
							parent
							
								
									be6d48ac10
								
							
						
					
					
						commit
						e48ea51a5a
					
				| @ -37,8 +37,6 @@ namespace Api\Groups { | |||||||
|         'count' => new Parameter('count', Parameter::TYPE_INT, true, 20) |         'count' => new Parameter('count', Parameter::TYPE_INT, true, 20) | ||||||
|       )); |       )); | ||||||
| 
 | 
 | ||||||
|       $this->loginRequired = true; |  | ||||||
|       $this->requiredGroup = array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN); |  | ||||||
|       $this->groupCount = 0; |       $this->groupCount = 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -116,9 +114,6 @@ namespace Api\Groups { | |||||||
|         'name' => new StringType('name', 32), |         'name' => new StringType('name', 32), | ||||||
|         'color' => new StringType('color', 10), |         'color' => new StringType('color', 10), | ||||||
|       )); |       )); | ||||||
| 
 |  | ||||||
|       $this->loginRequired = true; |  | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function execute($values = array()) { |     public function execute($values = array()) { | ||||||
| @ -165,9 +160,6 @@ namespace Api\Groups { | |||||||
|       parent::__construct($user, $externalCall, array( |       parent::__construct($user, $externalCall, array( | ||||||
|         'uid' => new Parameter('uid', Parameter::TYPE_INT) |         'uid' => new Parameter('uid', Parameter::TYPE_INT) | ||||||
|       )); |       )); | ||||||
| 
 |  | ||||||
|       $this->loginRequired = true; |  | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function execute($values = array()) { |     public function execute($values = array()) { | ||||||
|  | |||||||
							
								
								
									
										120
									
								
								core/Api/MailAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										120
									
								
								core/Api/MailAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,120 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  |   class MailAPI extends Request { | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\Mail { | ||||||
|  | 
 | ||||||
|  |   use Api\MailAPI; | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use Api\Parameter\StringType; | ||||||
|  |   use External\PHPMailer\Exception; | ||||||
|  |   use External\PHPMailer\PHPMailer; | ||||||
|  |   use Objects\ConnectionData; | ||||||
|  |   use Objects\User; | ||||||
|  | 
 | ||||||
|  |   class Test extends MailAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         "receiver" => new Parameter("receiver", Parameter::TYPE_EMAIL) | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $receiver = $this->getParam("receiver"); | ||||||
|  |       $req = new \Api\Mail\Send($this->user); | ||||||
|  |       $this->success = $req->execute(array( | ||||||
|  |         "to" => $receiver, | ||||||
|  |         "subject" => "Test E-Mail", | ||||||
|  |         "body" => "Hey! If you receive this e-mail, your mail configuration seems to be working." | ||||||
|  |       )); | ||||||
|  | 
 | ||||||
|  |       $this->lastError = $req->getLastError(); | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Send extends MailAPI { | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'to' => new Parameter('to', Parameter::TYPE_EMAIL), | ||||||
|  |         'subject'  => new StringType('subject', -1), | ||||||
|  |         'body' => new StringType('body', -1), | ||||||
|  |       )); | ||||||
|  |       $this->isPublic = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function getMailConfig() : ?ConnectionData { | ||||||
|  |       $req = new \Api\Settings\Get($this->user); | ||||||
|  |       $this->success = $req->execute(array("key" => "^mail_")); | ||||||
|  |       $this->lastError = $req->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $settings = $req->getResult()["settings"]; | ||||||
|  | 
 | ||||||
|  |         if (!isset($settings["mail_enabled"]) || $settings["mail_enabled"] !== "1") { | ||||||
|  |           $this->createError("Mail is not configured yet."); | ||||||
|  |           return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $host = $settings["mail_host"] ?? "localhost"; | ||||||
|  |         $port = intval($settings["mail_port"] ?? "25"); | ||||||
|  |         $login = $settings["mail_username"] ?? ""; | ||||||
|  |         $password = $settings["mail_password"] ?? ""; | ||||||
|  |         $connectionData = new ConnectionData($host, $port, $login, $password); | ||||||
|  |         $connectionData->setProperty("from", $settings["mail_from"] ?? ""); | ||||||
|  |         return $connectionData; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $mailConfig = $this->getMailConfig(); | ||||||
|  |       if (!$this->success) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       try { | ||||||
|  |         $mail = new PHPMailer; | ||||||
|  |         $mail->IsSMTP(); | ||||||
|  |         $mail->setFrom($mailConfig->getProperty("from")); | ||||||
|  |         $mail->addAddress($this->getParam('to')); | ||||||
|  |         $mail->Subject = $this->getParam('subject'); | ||||||
|  |         $mail->SMTPDebug = 0; | ||||||
|  |         $mail->Host = $mailConfig->getHost(); | ||||||
|  |         $mail->Port = $mailConfig->getPort(); | ||||||
|  |         $mail->SMTPAuth = true; | ||||||
|  |         $mail->Username = $mailConfig->getLogin(); | ||||||
|  |         $mail->Password = $mailConfig->getPassword(); | ||||||
|  |         $mail->SMTPSecure = 'tls'; | ||||||
|  |         $mail->IsHTML(true); | ||||||
|  |         $mail->CharSet = 'UTF-8'; | ||||||
|  |         $mail->Body = $this->getParam('body'); | ||||||
|  | 
 | ||||||
|  |         $this->success = @$mail->Send(); | ||||||
|  |         if (!$this->success) { | ||||||
|  |           $this->lastError = "Error sending Mail: $mail->ErrorInfo"; | ||||||
|  |           error_log("sendMail() failed: $mail->ErrorInfo"); | ||||||
|  |         } | ||||||
|  |       } catch (Exception $e) { | ||||||
|  |         $this->success = false; | ||||||
|  |         $this->lastError = "Error sending Mail: $e"; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -26,7 +26,6 @@ namespace Api\Notifications { | |||||||
|         'message' =>  new StringType('message', 256), |         'message' =>  new StringType('message', 256), | ||||||
|       )); |       )); | ||||||
|       $this->isPublic = false; |       $this->isPublic = false; | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function checkUser($userId) { |     private function checkUser($userId) { | ||||||
|  | |||||||
| @ -18,7 +18,11 @@ namespace Api\Permission { | |||||||
|   use Api\Parameter\Parameter; |   use Api\Parameter\Parameter; | ||||||
|   use Api\Parameter\StringType; |   use Api\Parameter\StringType; | ||||||
|   use Api\PermissionAPI; |   use Api\PermissionAPI; | ||||||
|  |   use Driver\SQL\Column\Column; | ||||||
|   use Driver\SQL\Condition\Compare; |   use Driver\SQL\Condition\Compare; | ||||||
|  |   use Driver\SQL\Condition\CondIn; | ||||||
|  |   use Driver\SQL\Condition\CondNot; | ||||||
|  |   use Driver\SQL\Strategy\UpdateStrategy; | ||||||
|   use Objects\User; |   use Objects\User; | ||||||
| 
 | 
 | ||||||
|   class Check extends PermissionAPI { |   class Check extends PermissionAPI { | ||||||
| @ -57,6 +61,7 @@ namespace Api\Permission { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (!$this->user->isLoggedIn() || empty(array_intersect($groups, array_keys($this->user->getGroups())))) { |         if (!$this->user->isLoggedIn() || empty(array_intersect($groups, array_keys($this->user->getGroups())))) { | ||||||
|  |           header('HTTP 1.1 401 Unauthorized'); | ||||||
|           return $this->createError("Permission denied."); |           return $this->createError("Permission denied."); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @ -75,7 +80,7 @@ namespace Api\Permission { | |||||||
| 
 | 
 | ||||||
|     private function fetchGroups() { |     private function fetchGroups() { | ||||||
|       $sql = $this->user->getSQL(); |       $sql = $this->user->getSQL(); | ||||||
|       $res = $sql->select("uid", "name") |       $res = $sql->select("uid", "name", "color") | ||||||
|         ->from("Group") |         ->from("Group") | ||||||
|         ->orderBy("uid") |         ->orderBy("uid") | ||||||
|         ->ascending() |         ->ascending() | ||||||
| @ -89,7 +94,8 @@ namespace Api\Permission { | |||||||
|         foreach($res as $row) { |         foreach($res as $row) { | ||||||
|           $groupId = $row["uid"]; |           $groupId = $row["uid"]; | ||||||
|           $groupName = $row["name"]; |           $groupName = $row["name"]; | ||||||
|           $this->groups[$groupId] = $groupName; |           $groupColor = $row["color"]; | ||||||
|  |           $this->groups[$groupId] = array("name" => $groupName, "color" => $groupColor); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
| @ -110,7 +116,7 @@ namespace Api\Permission { | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       $sql = $this->user->getSQL(); |       $sql = $this->user->getSQL(); | ||||||
|       $res = $sql->select("method", "groups") |       $res = $sql->select("method", "groups", "description") | ||||||
|         ->from("ApiPermission") |         ->from("ApiPermission") | ||||||
|         ->execute(); |         ->execute(); | ||||||
| 
 | 
 | ||||||
| @ -121,8 +127,13 @@ namespace Api\Permission { | |||||||
|         $permissions = array(); |         $permissions = array(); | ||||||
|         foreach ($res as $row) { |         foreach ($res as $row) { | ||||||
|           $method = $row["method"]; |           $method = $row["method"]; | ||||||
|  |           $description = $row["description"]; | ||||||
|           $groups = json_decode($row["groups"]); |           $groups = json_decode($row["groups"]); | ||||||
|           $permissions[] = array("method" => $method, "groups" => $groups); |           $permissions[] = array( | ||||||
|  |             "method" => $method, | ||||||
|  |             "groups" => $groups, | ||||||
|  |             "description" => $description | ||||||
|  |           ); | ||||||
|         } |         } | ||||||
|         $this->result["permissions"] = $permissions; |         $this->result["permissions"] = $permissions; | ||||||
|         $this->result["groups"] = $this->groups; |         $this->result["groups"] = $this->groups; | ||||||
| @ -149,7 +160,52 @@ namespace Api\Permission { | |||||||
|         return false; |         return false; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  |       $permissions = $this->getParam("permissions"); | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $methodParam = new StringType('method', 32); | ||||||
|  |       $groupsParam = new Parameter('groups', Parameter::TYPE_ARRAY); | ||||||
| 
 | 
 | ||||||
|  |       $updateQuery = $sql->insert("ApiPermission", array("method", "groups")) | ||||||
|  |         ->onDuplicateKeyStrategy(new UpdateStrategy(array("method"), array( "groups" => new Column("groups") ))); | ||||||
|  | 
 | ||||||
|  |       $insertedMethods = array(); | ||||||
|  | 
 | ||||||
|  |       foreach($permissions as $permission) { | ||||||
|  |         if (!is_array($permission)) { | ||||||
|  |           return $this->createError("Invalid data type found in parameter: permissions, expected: object"); | ||||||
|  |         } else if(!isset($permission["method"]) || !array_key_exists("groups", $permission)) { | ||||||
|  |           return $this->createError("Invalid object found in parameter: permissions, expected keys 'method' and 'groups'"); | ||||||
|  |         } else if (!$methodParam->parseParam($permission["method"])) { | ||||||
|  |           $expectedType = $methodParam->getTypeName(); | ||||||
|  |           return $this->createError("Invalid data type found for attribute 'method', expected: $expectedType"); | ||||||
|  |         } else if(!$groupsParam->parseParam($permission["groups"])) { | ||||||
|  |           $expectedType = $groupsParam->getTypeName(); | ||||||
|  |           return $this->createError("Invalid data type found for attribute 'groups', expected: $expectedType"); | ||||||
|  |         } else if(empty(trim($methodParam->value))) { | ||||||
|  |           return $this->createError("Method cannot be empty."); | ||||||
|  |         } else { | ||||||
|  |           $method = $methodParam->value; | ||||||
|  |           $groups = $groupsParam->value; | ||||||
|  |           $updateQuery->addRow($method, $groups); | ||||||
|  |           $insertedMethods[] = $method; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!empty($permissions)) { | ||||||
|  |         $res = $updateQuery->execute(); | ||||||
|  |         $this->success = ($res !== FALSE); | ||||||
|  |         $this->lastError = $sql->getLastError(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $res = $sql->delete("ApiPermission") | ||||||
|  |           ->where(new Compare("description", "")) // only delete non default permissions
 | ||||||
|  |           ->where(new CondNot(new CondIn("method", $insertedMethods))) | ||||||
|  |           ->execute(); | ||||||
|  | 
 | ||||||
|  |         $this->success = ($res !== FALSE); | ||||||
|  |         $this->lastError = $sql->getLastError(); | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|       return $this->success; |       return $this->success; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -16,7 +16,6 @@ class Request { | |||||||
|   protected bool $variableParamCount; |   protected bool $variableParamCount; | ||||||
|   protected bool $isDisabled; |   protected bool $isDisabled; | ||||||
|   protected bool $apiKeyAllowed; |   protected bool $apiKeyAllowed; | ||||||
|   protected array $requiredGroup; |  | ||||||
|   protected bool $csrfTokenRequired; |   protected bool $csrfTokenRequired; | ||||||
| 
 | 
 | ||||||
|   private array $aDefaultParams; |   private array $aDefaultParams; | ||||||
| @ -36,7 +35,6 @@ class Request { | |||||||
|     $this->variableParamCount = false; |     $this->variableParamCount = false; | ||||||
|     $this->apiKeyAllowed = true; |     $this->apiKeyAllowed = true; | ||||||
|     $this->allowedMethods = array("GET", "POST"); |     $this->allowedMethods = array("GET", "POST"); | ||||||
|     $this->requiredGroup = array(); |  | ||||||
|     $this->lastError = ""; |     $this->lastError = ""; | ||||||
|     $this->csrfTokenRequired = true; |     $this->csrfTokenRequired = true; | ||||||
|   } |   } | ||||||
| @ -54,15 +52,13 @@ class Request { | |||||||
| 
 | 
 | ||||||
|       $isEmpty = (is_string($value) || is_array($value)) && empty($value); |       $isEmpty = (is_string($value) || is_array($value)) && empty($value); | ||||||
|       if(!$param->optional && (is_null($value) || $isEmpty)) { |       if(!$param->optional && (is_null($value) || $isEmpty)) { | ||||||
|         $this->lastError = 'Missing parameter: ' . $name; |         return $this->createError("Missing parameter: $name"); | ||||||
|         return false; |  | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       if(!is_null($value) && !$isEmpty) { |       if(!is_null($value) && !$isEmpty) { | ||||||
|         if(!$param->parseParam($value)) { |         if(!$param->parseParam($value)) { | ||||||
|           $value = print_r($value, true); |           $value = print_r($value, true); | ||||||
|           $this->lastError = "Invalid Type for parameter: $name '$value' (Required: " . $param->getTypeName() . ")"; |           return $this->createError("Invalid Type for parameter: $name '$value' (Required: " . $param->getTypeName() . ")"); | ||||||
|           return false; |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @ -135,26 +131,25 @@ class Request { | |||||||
|           header('HTTP 1.1 401 Unauthorized'); |           header('HTTP 1.1 401 Unauthorized'); | ||||||
|           return false; |           return false; | ||||||
|         } |         } | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|         // CSRF Token
 |       // CSRF Token
 | ||||||
|         if($this->csrfTokenRequired && !$apiKeyAuthorized) { |       if($this->csrfTokenRequired && $this->user->isLoggedIn()) { | ||||||
|           // csrf token required + external call
 |         // csrf token required + external call
 | ||||||
|           // if it's not a call with API_KEY, check for csrf_token
 |         // if it's not a call with API_KEY, check for csrf_token
 | ||||||
|           if (!isset($values["csrf_token"]) || strcmp($values["csrf_token"], $this->user->getSession()->getCsrfToken()) !== 0) { |         if (!isset($values["csrf_token"]) || strcmp($values["csrf_token"], $this->user->getSession()->getCsrfToken()) !== 0) { | ||||||
|             $this->lastError = "CSRF-Token mismatch"; |           $this->lastError = "CSRF-Token mismatch"; | ||||||
|             header('HTTP 1.1 403 Forbidden'); |           header('HTTP 1.1 403 Forbidden'); | ||||||
|             return false; |           return false; | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       // Check for permission
 |       // Check for permission
 | ||||||
|       if (!($this instanceof PermissionAPI)) { |       if (!($this instanceof \Api\Permission\Save)) { | ||||||
|         $req = new \Api\Permission\Check($this->user); |         $req = new \Api\Permission\Check($this->user); | ||||||
|         $this->success = $req->execute(array("method" => $this->getMethod())); |         $this->success = $req->execute(array("method" => $this->getMethod())); | ||||||
|         $this->lastError = $req->getLastError(); |         $this->lastError = $req->getLastError(); | ||||||
|         if (!$this->success) { |         if (!$this->success) { | ||||||
|           header('HTTP 1.1 401 Unauthorized'); |  | ||||||
|           return false; |           return false; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  | |||||||
| @ -32,8 +32,6 @@ namespace Api\Routes { | |||||||
| 
 | 
 | ||||||
|   public function __construct($user, $externalCall = false) { |   public function __construct($user, $externalCall = false) { | ||||||
|     parent::__construct($user, $externalCall, array()); |     parent::__construct($user, $externalCall, array()); | ||||||
|     $this->loginRequired = true; |  | ||||||
|     $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function execute($values = array()) { |   public function execute($values = array()) { | ||||||
| @ -133,9 +131,6 @@ namespace Api\Routes { | |||||||
|       parent::__construct($user, $externalCall, array( |       parent::__construct($user, $externalCall, array( | ||||||
|         'routes' => new Parameter('routes',Parameter::TYPE_ARRAY, false) |         'routes' => new Parameter('routes',Parameter::TYPE_ARRAY, false) | ||||||
|       )); |       )); | ||||||
| 
 |  | ||||||
|       $this->loginRequired = true; |  | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function execute($values = array()) { |     public function execute($values = array()) { | ||||||
|  | |||||||
| @ -1,85 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api; |  | ||||||
| use Api\Parameter\Parameter; |  | ||||||
| use Api\Parameter\StringType; |  | ||||||
| use External\PHPMailer\Exception; |  | ||||||
| use External\PHPMailer\PHPMailer; |  | ||||||
| use Objects\ConnectionData; |  | ||||||
| 
 |  | ||||||
| class SendMail extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externalCall = false) { |  | ||||||
|     parent::__construct($user, $externalCall, array( |  | ||||||
|       'to' => new Parameter('to', Parameter::TYPE_EMAIL), |  | ||||||
|       'subject'  => new StringType('subject', -1), |  | ||||||
|       'body' => new StringType('body', -1), |  | ||||||
|     )); |  | ||||||
|     $this->isPublic = false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function getMailConfig() : ?ConnectionData { |  | ||||||
|     $req = new \Api\Settings\Get($this->user); |  | ||||||
|     $this->success = $req->execute(array("key" => "^mail_")); |  | ||||||
|     $this->lastError = $req->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if ($this->success) { |  | ||||||
|       $settings = $req->getResult()["settings"]; |  | ||||||
| 
 |  | ||||||
|       if (!isset($settings["mail_enabled"]) || $settings["mail_enabled"] !== "1") { |  | ||||||
|         $this->createError("Mail is not configured yet."); |  | ||||||
|         return null; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       $host = $settings["mail_host"] ?? "localhost"; |  | ||||||
|       $port = intval($settings["mail_port"] ?? "25"); |  | ||||||
|       $login = $settings["mail_username"] ?? ""; |  | ||||||
|       $password = $settings["mail_password"] ?? ""; |  | ||||||
|       $connectionData = new ConnectionData($host, $port, $login, $password); |  | ||||||
|       $connectionData->setProperty("from", $settings["mail_from"] ?? ""); |  | ||||||
|       return $connectionData; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return null; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $mailConfig = $this->getMailConfig(); |  | ||||||
|     if (!$this->success) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     try { |  | ||||||
|       $mail = new PHPMailer; |  | ||||||
|       $mail->IsSMTP(); |  | ||||||
|       $mail->setFrom($mailConfig->getProperty("from")); |  | ||||||
|       $mail->addAddress($this->getParam('to')); |  | ||||||
|       $mail->Subject = $this->getParam('subject'); |  | ||||||
|       $mail->SMTPDebug = 0; |  | ||||||
|       $mail->Host = $mailConfig->getHost(); |  | ||||||
|       $mail->Port = $mailConfig->getPort(); |  | ||||||
|       $mail->SMTPAuth = true; |  | ||||||
|       $mail->Username = $mailConfig->getLogin(); |  | ||||||
|       $mail->Password = $mailConfig->getPassword(); |  | ||||||
|       $mail->SMTPSecure = 'tls'; |  | ||||||
|       $mail->IsHTML(true); |  | ||||||
|       $mail->CharSet = 'UTF-8'; |  | ||||||
|       $mail->Body = $this->getParam('body'); |  | ||||||
| 
 |  | ||||||
|       $this->success = @$mail->Send(); |  | ||||||
|       if (!$this->success) { |  | ||||||
|         $this->lastError = "Error sending Mail: $mail->ErrorInfo"; |  | ||||||
|         error_log("sendMail() failed: $mail->ErrorInfo"); |  | ||||||
|       } |  | ||||||
|      } catch (Exception $e) { |  | ||||||
|       $this->success = false; |  | ||||||
|       $this->lastError = "Error sending Mail: $e"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,35 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api; |  | ||||||
| 
 |  | ||||||
| use Api\Parameter\Parameter; |  | ||||||
| use Objects\User; |  | ||||||
| 
 |  | ||||||
| class SendTestMail extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct(User $user, bool $externalCall = false) { |  | ||||||
|     parent::__construct($user, $externalCall, array( |  | ||||||
|       "receiver" => new Parameter("receiver", Parameter::TYPE_EMAIL) |  | ||||||
|     )); |  | ||||||
| 
 |  | ||||||
|     $this->requiredGroup = array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if (!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $receiver = $this->getParam("receiver"); |  | ||||||
|     $req = new SendMail($this->user); |  | ||||||
|     $this->success = $req->execute(array( |  | ||||||
|       "to" => $receiver, |  | ||||||
|       "subject" => "Test E-Mail", |  | ||||||
|       "body" => "Hey! If you receive this e-mail, your mail configuration seems to be working." |  | ||||||
|     )); |  | ||||||
| 
 |  | ||||||
|     $this->lastError = $req->getLastError(); |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -25,11 +25,8 @@ namespace Api\Settings { | |||||||
| 
 | 
 | ||||||
|     public function __construct(User $user, bool $externalCall = false) { |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|       parent::__construct($user, $externalCall, array( |       parent::__construct($user, $externalCall, array( | ||||||
|         'key' => new StringType('key', 32, true, NULL) |         'key' => new StringType('key', -1, true, NULL) | ||||||
|       )); |       )); | ||||||
| 
 |  | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|       $this->loginRequired = true; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function execute($values = array()) { |     public function execute($values = array()) { | ||||||
| @ -73,9 +70,6 @@ namespace Api\Settings { | |||||||
|       parent::__construct($user, $externalCall, array( |       parent::__construct($user, $externalCall, array( | ||||||
|         'settings' => new Parameter('settings', Parameter::TYPE_ARRAY) |         'settings' => new Parameter('settings', Parameter::TYPE_ARRAY) | ||||||
|       )); |       )); | ||||||
| 
 |  | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|       $this->loginRequired = true; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function execute($values = array()) { |     public function execute($values = array()) { | ||||||
|  | |||||||
| @ -7,11 +7,11 @@ use Driver\SQL\Condition\CondBool; | |||||||
| 
 | 
 | ||||||
| class Stats extends Request { | class Stats extends Request { | ||||||
| 
 | 
 | ||||||
|  |   private bool $mailConfigured; | ||||||
|  |   private bool $recaptchaConfigured; | ||||||
|  | 
 | ||||||
|   public function __construct($user, $externalCall = false) { |   public function __construct($user, $externalCall = false) { | ||||||
|     parent::__construct($user, $externalCall, array()); |     parent::__construct($user, $externalCall, array()); | ||||||
| 
 |  | ||||||
|     $this->loginRequired = true; |  | ||||||
|     $this->requiredGroup = array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private function getUserCount() { |   private function getUserCount() { | ||||||
| @ -67,12 +67,15 @@ class Stats extends Request { | |||||||
|     return $visitors; |     return $visitors; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private function isMailConfigured() { |   private function checkSettings() { | ||||||
|     $req = new \Api\Settings\Get($this->user); |     $req = new \Api\Settings\Get($this->user); | ||||||
|     $this->success = $req->execute(array("key" => "^mail_enabled$")); |     $this->success = $req->execute(array("key" => "^(mail_enabled|recaptcha_enabled)$")); | ||||||
|  |     $this->lastError = $req->getLastError(); | ||||||
| 
 | 
 | ||||||
|     if ($this->success) { |     if ($this->success) { | ||||||
|       return ($req->getResult()["mail_enabled"] ?? "0") === "1"; |       $settings = $req->getResult()["settings"]; | ||||||
|  |       $this->mailConfigured = ($settings["mail_enabled"] ?? "0") === "1"; | ||||||
|  |       $this->recaptchaConfigured = ($settings["recaptcha_enabled"] ?? "0") === "1"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return $this->success; |     return $this->success; | ||||||
| @ -95,8 +98,7 @@ class Stats extends Request { | |||||||
|       $loadAvg = sys_getloadavg(); |       $loadAvg = sys_getloadavg(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     $mailConfigured = $this->isMailConfigured(); |     if (!$this->checkSettings()) { | ||||||
|     if (!$this->success) { |  | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -109,7 +111,8 @@ class Stats extends Request { | |||||||
|       "memory_usage" => memory_get_usage(), |       "memory_usage" => memory_get_usage(), | ||||||
|       "load_avg" => $loadAvg, |       "load_avg" => $loadAvg, | ||||||
|       "database" => $this->user->getSQL()->getStatus(), |       "database" => $this->user->getSQL()->getStatus(), | ||||||
|       "mail" => $mailConfigured |       "mail" => $this->mailConfigured, | ||||||
|  |       "reCaptcha" => $this->recaptchaConfigured | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     return $this->success; |     return $this->success; | ||||||
|  | |||||||
| @ -118,7 +118,6 @@ namespace Api\User { | |||||||
| 
 | 
 | ||||||
|   use Api\Parameter\Parameter; |   use Api\Parameter\Parameter; | ||||||
|   use Api\Parameter\StringType; |   use Api\Parameter\StringType; | ||||||
|   use Api\SendMail; |  | ||||||
|   use Api\UserAPI; |   use Api\UserAPI; | ||||||
|   use Api\VerifyCaptcha; |   use Api\VerifyCaptcha; | ||||||
|   use DateTime; |   use DateTime; | ||||||
| @ -137,7 +136,6 @@ namespace Api\User { | |||||||
|       )); |       )); | ||||||
| 
 | 
 | ||||||
|       $this->loginRequired = true; |       $this->loginRequired = true; | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function execute($values = array()) { |     public function execute($values = array()) { | ||||||
| @ -179,15 +177,10 @@ namespace Api\User { | |||||||
|     private int $userCount; |     private int $userCount; | ||||||
| 
 | 
 | ||||||
|     public function __construct($user, $externalCall = false) { |     public function __construct($user, $externalCall = false) { | ||||||
| 
 |  | ||||||
|       parent::__construct($user, $externalCall, array( |       parent::__construct($user, $externalCall, array( | ||||||
|         'page' => new Parameter('page', Parameter::TYPE_INT, true, 1), |         'page' => new Parameter('page', Parameter::TYPE_INT, true, 1), | ||||||
|         'count' => new Parameter('count', Parameter::TYPE_INT, true, 20) |         'count' => new Parameter('count', Parameter::TYPE_INT, true, 20) | ||||||
|       )); |       )); | ||||||
| 
 |  | ||||||
|       $this->loginRequired = true; |  | ||||||
|       $this->requiredGroup = array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN); |  | ||||||
|       $this->userCount = 0; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function getUserCount() { |     private function getUserCount() { | ||||||
| @ -297,13 +290,9 @@ namespace Api\User { | |||||||
|   class Get extends UserAPI { |   class Get extends UserAPI { | ||||||
| 
 | 
 | ||||||
|     public function __construct($user, $externalCall = false) { |     public function __construct($user, $externalCall = false) { | ||||||
| 
 |  | ||||||
|       parent::__construct($user, $externalCall, array( |       parent::__construct($user, $externalCall, array( | ||||||
|         'id' => new Parameter('id', Parameter::TYPE_INT) |         'id' => new Parameter('id', Parameter::TYPE_INT) | ||||||
|       )); |       )); | ||||||
| 
 |  | ||||||
|       $this->loginRequired = true; |  | ||||||
|       $this->requiredGroup = array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function execute($values = array()) { |     public function execute($values = array()) { | ||||||
| @ -373,7 +362,6 @@ namespace Api\User { | |||||||
|       )); |       )); | ||||||
| 
 | 
 | ||||||
|       $this->loginRequired = true; |       $this->loginRequired = true; | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function execute($values = array()) { |     public function execute($values = array()) { | ||||||
| @ -418,7 +406,7 @@ namespace Api\User { | |||||||
|             $body = str_replace("{{{$key}}}", $value, $body); |             $body = str_replace("{{{$key}}}", $value, $body); | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           $request = new SendMail($this->user); |           $request = new \Api\Mail\Send($this->user); | ||||||
|           $this->success = $request->execute(array( |           $this->success = $request->execute(array( | ||||||
|             "to" => $email, |             "to" => $email, | ||||||
|             "subject" => "[$siteName] Account Invitation", |             "subject" => "[$siteName] Account Invitation", | ||||||
| @ -560,18 +548,6 @@ namespace Api\User { | |||||||
|       return $this->success; |       return $this->success; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function checkSettings() { |  | ||||||
|       $req = new \Api\Settings\Get($this->user); |  | ||||||
|       $this->success = $req->execute(array("key" => "user_registration_enabled")); |  | ||||||
|       $this->lastError = $req->getLastError(); |  | ||||||
| 
 |  | ||||||
|       if ($this->success) { |  | ||||||
|         return ($req->getResult()["user_registration_enabled"] ?? "0") === "1"; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       return $this->success; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public function execute($values = array()) { |     public function execute($values = array()) { | ||||||
|       if (!parent::execute($values)) { |       if (!parent::execute($values)) { | ||||||
|         return false; |         return false; | ||||||
| @ -581,11 +557,7 @@ namespace Api\User { | |||||||
|         return $this->createError(L('You are already logged in')); |         return $this->createError(L('You are already logged in')); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       $registrationAllowed = $this->checkSettings(); |       $registrationAllowed = $this->user->getConfiguration()->getSettings()->isRegistrationAllowed(); | ||||||
|       if (!$this->success) { |  | ||||||
|         return false; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       if(!$registrationAllowed) { |       if(!$registrationAllowed) { | ||||||
|         return $this->createError("User Registration is not enabled."); |         return $this->createError("User Registration is not enabled."); | ||||||
|       } |       } | ||||||
| @ -640,7 +612,7 @@ namespace Api\User { | |||||||
|           $body = str_replace("{{{$key}}}", $value, $body); |           $body = str_replace("{{{$key}}}", $value, $body); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $request = new SendMail($this->user); |         $request = new \Api\Mail\Send($this->user); | ||||||
|         $this->success = $request->execute(array( |         $this->success = $request->execute(array( | ||||||
|             "to" => $email, |             "to" => $email, | ||||||
|             "subject" => "[$siteName] E-Mail Confirmation", |             "subject" => "[$siteName] E-Mail Confirmation", | ||||||
| @ -696,7 +668,6 @@ namespace Api\User { | |||||||
|         'groups' => new Parameter('groups', Parameter::TYPE_ARRAY, true, NULL), |         'groups' => new Parameter('groups', Parameter::TYPE_ARRAY, true, NULL), | ||||||
|       )); |       )); | ||||||
| 
 | 
 | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|       $this->loginRequired = true; |       $this->loginRequired = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -786,7 +757,6 @@ namespace Api\User { | |||||||
|         'id' => new Parameter('id', Parameter::TYPE_INT) |         'id' => new Parameter('id', Parameter::TYPE_INT) | ||||||
|       )); |       )); | ||||||
| 
 | 
 | ||||||
|       $this->requiredGroup = array(USER_GROUP_ADMIN); |  | ||||||
|       $this->loginRequired = true; |       $this->loginRequired = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -174,39 +174,30 @@ class CreateDatabase { | |||||||
|     $queries[] = $sql->createTable("ApiPermission") |     $queries[] = $sql->createTable("ApiPermission") | ||||||
|       ->addString("method", 32) |       ->addString("method", 32) | ||||||
|       ->addJson("groups", true, '[]') |       ->addJson("groups", true, '[]') | ||||||
|  |       ->addString("description", 128, false, "") | ||||||
|       ->primaryKey("method"); |       ->primaryKey("method"); | ||||||
| 
 | 
 | ||||||
|     $queries[] = $sql->insert("ApiPermission", array("method", "groups")) |     $queries[] = $sql->insert("ApiPermission", array("method", "groups", "description")) | ||||||
|       ->addRow("ApiKey/create", array()) |       ->addRow("ApiKey/create", array(), "Allows users to create API-Keys for themselves") | ||||||
|       ->addRow("ApiKey/fetch", array()) |       ->addRow("ApiKey/fetch", array(), "Allows users to list their API-Keys") | ||||||
|       ->addRow("ApiKey/refresh", array()) |       ->addRow("ApiKey/refresh", array(), "Allows users to refresh their API-Keys") | ||||||
|       ->addRow("ApiKey/revoke", array()) |       ->addRow("ApiKey/revoke", array(), "Allows users to revoke their API-Keys") | ||||||
|       ->addRow("Contact/request", array()) |       ->addRow("Groups/fetch", array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN), "Allows users to list all available groups") | ||||||
|       ->addRow("Groups/fetch", array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN)) |       ->addRow("Groups/create", array(USER_GROUP_ADMIN), "Allows users to create a new groups") | ||||||
|       ->addRow("Groups/create", array(USER_GROUP_ADMIN)) |       ->addRow("Groups/delete", array(USER_GROUP_ADMIN), "Allows users to delete a group") | ||||||
|       ->addRow("Groups/delete", array(USER_GROUP_ADMIN)) |       ->addRow("Routes/fetch", array(USER_GROUP_ADMIN), "Allows users to list all configured routes") | ||||||
|       ->addRow("Language/get", array()) |       ->addRow("Routes/save", array(USER_GROUP_ADMIN), "Allows users to create, delete and modify routes") | ||||||
|       ->addRow("Language/set", array()) |       ->addRow("Mail/test", array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN), "Allows users to send a test email to a given address") | ||||||
|       ->addRow("Notifications/create", array(USER_GROUP_ADMIN)) |       ->addRow("Settings/get", array(USER_GROUP_ADMIN), "Allows users to fetch server settings") | ||||||
|       ->addRow("Notifications/fetch", array()) |       ->addRow("Settings/set", array(USER_GROUP_ADMIN), "Allows users create, delete or modify server settings") | ||||||
|       ->addRow("Notifications/seen", array()) |       ->addRow("Stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to fetch server stats") | ||||||
|       ->addRow("Routes/fetch", array(USER_GROUP_ADMIN)) |       ->addRow("User/create", array(USER_GROUP_ADMIN), "Allows users to create a new user, email address does not need to be confirmed") | ||||||
|       ->addRow("Routes/save", array(USER_GROUP_ADMIN)) |       ->addRow("User/fetch", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to list all registered users") | ||||||
|       ->addRow("sendTestMail", array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN)) |       ->addRow("User/get", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to get information about a single user") | ||||||
|       ->addRow("Settings/get", array(USER_GROUP_ADMIN)) |       ->addRow("User/invite", array(USER_GROUP_ADMIN), "Allows users to create a new user and send them an invitation link") | ||||||
|       ->addRow("Settings/set", array(USER_GROUP_ADMIN)) |       ->addRow("User/edit", array(USER_GROUP_ADMIN), "Allows users to edit details and group memberships of any user") | ||||||
|       ->addRow("Stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT)) |       ->addRow("User/delete", array(USER_GROUP_ADMIN), "Allows users to delete any other user") | ||||||
|       ->addRow("User/create", array(USER_GROUP_ADMIN)) |       ->addRow("Permission/fetch", array(USER_GROUP_ADMIN), "Allows users to list all API permissions"); | ||||||
|       ->addRow("User/fetch", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT)) |  | ||||||
|       ->addRow("User/get", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT)) |  | ||||||
|       ->addRow("User/info", array()) |  | ||||||
|       ->addRow("User/invite", array(USER_GROUP_ADMIN)) |  | ||||||
|       ->addRow("User/login", array()) |  | ||||||
|       ->addRow("User/logout", array()) |  | ||||||
|       ->addRow("User/register", array()) |  | ||||||
|       ->addRow("User/checkToken", array()) |  | ||||||
|       ->addRow("User/edit", array(USER_GROUP_ADMIN)) |  | ||||||
|       ->addRow("User/delete", array(USER_GROUP_ADMIN)); |  | ||||||
| 
 | 
 | ||||||
|     return $queries; |     return $queries; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -81,23 +81,27 @@ class Settings { | |||||||
|       ->addRow("recaptcha_private_key", $this->recaptchaPrivateKey, true, false); |       ->addRow("recaptcha_private_key", $this->recaptchaPrivateKey, true, false); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getSiteName() { |   public function getSiteName() : string { | ||||||
|     return $this->siteName; |     return $this->siteName; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getBaseUrl() { |   public function getBaseUrl() : string { | ||||||
|     return $this->baseUrl; |     return $this->baseUrl; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function isRecaptchaEnabled() { |   public function isRecaptchaEnabled() : bool { | ||||||
|     return $this->recaptchaEnabled; |     return $this->recaptchaEnabled; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getRecaptchaSiteKey() { |   public function getRecaptchaSiteKey() : string { | ||||||
|     return $this->recaptchaPublicKey; |     return $this->recaptchaPublicKey; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getRecaptchaSecretKey() { |   public function getRecaptchaSecretKey() : string { | ||||||
|     return $this->recaptchaPrivateKey; |     return $this->recaptchaPrivateKey; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   public function isRegistrationAllowed() : bool { | ||||||
|  |     return $this->registrationAllowed; | ||||||
|  |   } | ||||||
| } | } | ||||||
| @ -7,7 +7,7 @@ class UpdateStrategy extends Strategy { | |||||||
|   private array $values; |   private array $values; | ||||||
|   private array $conflictingColumns; |   private array $conflictingColumns; | ||||||
| 
 | 
 | ||||||
|   public function __construct($conflictingColumns, $values) { |   public function __construct(array $conflictingColumns, array $values) { | ||||||
|     $this->conflictingColumns = $conflictingColumns; |     $this->conflictingColumns = $conflictingColumns; | ||||||
|     $this->values = $values; |     $this->values = $values; | ||||||
|   } |   } | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								js/admin.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										8
									
								
								js/admin.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -104,6 +104,14 @@ export default class API { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async sendTestMail(receiver) { |     async sendTestMail(receiver) { | ||||||
|         return this.apiCall("sendTestMail", { receiver: receiver }); |         return this.apiCall("mail/test", { receiver: receiver }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fetchPermissions() { | ||||||
|  |         return this.apiCall("permission/fetch"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async savePermissions(permissions) { | ||||||
|  |         return this.apiCall("permission/save", { permissions: permissions }); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| @ -209,8 +209,26 @@ export default class Overview extends React.Component { | |||||||
|                                         <li><b>Load Average</b>: { loadAvg }</li> |                                         <li><b>Load Average</b>: { loadAvg }</li> | ||||||
|                                         <li><b>Database</b>: { this.state.server["database"]  }</li> |                                         <li><b>Database</b>: { this.state.server["database"]  }</li> | ||||||
|                                         <li><b>Mail</b>: { this.state.server["mail"] === true |                                         <li><b>Mail</b>: { this.state.server["mail"] === true | ||||||
|                                             ?  <span>OK<Icon icon={""} className={"ml-2"}/></span> |                                             ? <span> | ||||||
|                                             :  <Link to={"/admin/settings"}>Not configured</Link>}</li> |                                                     OK | ||||||
|  |                                                     <Icon icon={"check-circle"} className={"ml-2 text-success"}/> | ||||||
|  |                                                </span> | ||||||
|  |                                             :  <span> | ||||||
|  |                                                     <Link to={"/admin/settings"}>Not configured</Link> | ||||||
|  |                                                     <Icon icon={"times-circle"} className={"ml-2 text-danger"}/> | ||||||
|  |                                                </span>} | ||||||
|  |                                         </li> | ||||||
|  |                                         <li> | ||||||
|  |                                             <b>Google reCaptcha</b>: { this.state.server["reCaptcha"] === true | ||||||
|  |                                             ? <span> | ||||||
|  |                                                     OK | ||||||
|  |                                                     <Icon icon={"check-circle"} className={"ml-2 text-success"}/> | ||||||
|  |                                                </span> | ||||||
|  |                                             :  <span> | ||||||
|  |                                                     <Link to={"/admin/settings"}>Not configured</Link> | ||||||
|  |                                                     <Icon icon={"times-circle"} className={"ml-2 text-danger"}/> | ||||||
|  |                                                </span>} | ||||||
|  |                                          </li> | ||||||
|                                     </ul> |                                     </ul> | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </Collapse> |                             </Collapse> | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| import * as React from "react"; | import * as React from "react"; | ||||||
| import {Link} from "react-router-dom"; | import {Link} from "react-router-dom"; | ||||||
| import Icon from "../elements/icon"; | import Icon from "../elements/icon"; | ||||||
|  | import Alert from "../elements/alert"; | ||||||
|  | import ReactTooltip from "react-tooltip"; | ||||||
| 
 | 
 | ||||||
| export default class PermissionSettings extends React.Component { | export default class PermissionSettings extends React.Component { | ||||||
| 
 | 
 | ||||||
| @ -10,11 +12,127 @@ export default class PermissionSettings extends React.Component { | |||||||
|         this.state = { |         this.state = { | ||||||
|             alerts: [], |             alerts: [], | ||||||
|             permissions: [], |             permissions: [], | ||||||
|             groups: {} |             groups: {}, | ||||||
|  |             isSaving: false, | ||||||
|  |             isResetting: false | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         this.parent = { | ||||||
|  |             api: props.api | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     componentDidMount() { | ||||||
|  |         this.fetchPermissions() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fetchPermissions() { | ||||||
|  |         this.parent.api.fetchPermissions().then((res) => { | ||||||
|  |             if (!res.success) { | ||||||
|  |                 let alerts = this.state.alerts.slice(); | ||||||
|  |                 alerts.push({ message: res.msg, title: "Error fetching permissions" }); | ||||||
|  |                 this.setState({...this.state, alerts: alerts, isResetting: false}); | ||||||
|  |             } else { | ||||||
|  |                 this.setState({...this.state, groups: res.groups, permissions: res.permissions, isResetting: false}); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     removeAlert(i) { | ||||||
|  |         if (i >= 0 && i < this.state.alerts.length) { | ||||||
|  |             let alerts = this.state.alerts.slice(); | ||||||
|  |             alerts.splice(i, 1); | ||||||
|  |             this.setState({...this.state, alerts: alerts}); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     onChangeMethod(e, index) { | ||||||
|  |         if (index < 0 || index >= this.state.permissions.length) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let value = e.target.value; | ||||||
|  |         let newPermissions = this.state.permissions.slice(); | ||||||
|  |         newPermissions[index].method = value; | ||||||
|  |         this.setState({ ...this.state, permissions: newPermissions }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     render() { |     render() { | ||||||
|  | 
 | ||||||
|  |         let alerts = []; | ||||||
|  |         for (let i = 0; i < this.state.alerts.length; i++) { | ||||||
|  |             alerts.push(<Alert key={"error-" + i} onClose={() => this.removeAlert(i)} {...this.state.alerts[i]}/>) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let th = []; | ||||||
|  |         th.push(<th key={"th-method"}>Method</th>); | ||||||
|  |         th.push(<th key={"th-everyone"} className={"text-center"}>Everyone</th>); | ||||||
|  | 
 | ||||||
|  |         for (let groupId in this.state.groups) { | ||||||
|  |             if (this.state.groups.hasOwnProperty(groupId)) { | ||||||
|  |                 let groupName = this.state.groups[groupId].name; | ||||||
|  |                 let groupColor = this.state.groups[groupId].color; | ||||||
|  |                 th.push( | ||||||
|  |                     <th key={"th-" + groupId} className={"text-center"}> | ||||||
|  |                         <span key={"group-" + groupId} className={"badge text-white"} style={{backgroundColor: groupColor}}> | ||||||
|  |                             {groupName} | ||||||
|  |                         </span> | ||||||
|  |                     </th> | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let tr = []; | ||||||
|  |         for (let i = 0; i < this.state.permissions.length; i++) { | ||||||
|  |             let permission = this.state.permissions[i]; | ||||||
|  |             let td = []; | ||||||
|  | 
 | ||||||
|  |             if (permission.description) { | ||||||
|  |                 td.push( | ||||||
|  |                     <td> | ||||||
|  |                         <ReactTooltip id={"tooltip-" + i} /> | ||||||
|  |                         { permission.method } | ||||||
|  |                         <Icon icon={"info-circle"} className={"text-info float-right"} | ||||||
|  |                               data-tip={permission.description} data-place={"right"} data-type={"info"} | ||||||
|  |                               data-effect={"solid"} data-for={"tooltip-" + i} /> | ||||||
|  |                     </td> | ||||||
|  |                 ); | ||||||
|  |             } else { | ||||||
|  |                 td.push( | ||||||
|  |                     <td> | ||||||
|  |                         <ReactTooltip id={"tooltip-" + i} /> | ||||||
|  |                         <input type={"text"} maxLength={32} value={this.state.permissions[i].method} | ||||||
|  |                             onChange={(e) => this.onChangeMethod(e, i)} /> | ||||||
|  |                         <Icon icon={"trash"} className={"text-danger float-right"} | ||||||
|  |                               data-tip={"Delete"} data-place={"right"} data-type={"error"} | ||||||
|  |                               data-effect={"solid"} data-for={"tooltip-" + i} | ||||||
|  |                               onClick={() => this.onDeletePermission(i)} style={{cursor: "pointer"}} /> | ||||||
|  |                     </td> | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             td.push( | ||||||
|  |                 <td key={"td-everyone"} className={"text-center"}> | ||||||
|  |                     <input type={"checkbox"} checked={this.state.permissions[i].groups.length === 0} | ||||||
|  |                            onChange={(e) => this.onChangePermission(e, i)}/> | ||||||
|  |                 </td> | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             for (let groupId in this.state.groups) { | ||||||
|  |                 if (this.state.groups.hasOwnProperty(groupId)) { | ||||||
|  |                     groupId = parseInt(groupId); | ||||||
|  |                     td.push( | ||||||
|  |                         <td key={"td-" + groupId} className={"text-center"}> | ||||||
|  |                             <input type={"checkbox"} checked={this.state.permissions[i].groups.includes(groupId)} | ||||||
|  |                                 onChange={(e) => this.onChangePermission(e, i, groupId)}/> | ||||||
|  |                         </td> | ||||||
|  |                     ); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             tr.push(<tr key={"permission-" + i}>{td}</tr>); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         return <> |         return <> | ||||||
|             <div className="content-header"> |             <div className="content-header"> | ||||||
|                 <div className="container-fluid"> |                 <div className="container-fluid"> | ||||||
| @ -35,15 +153,110 @@ export default class PermissionSettings extends React.Component { | |||||||
|             <div className={"content"}> |             <div className={"content"}> | ||||||
|                 <div className={"row"}> |                 <div className={"row"}> | ||||||
|                     <div className={"col-lg-6 pl-5 pr-5"}> |                     <div className={"col-lg-6 pl-5 pr-5"}> | ||||||
|                         <form> |                         {alerts} | ||||||
|                             <Link to={"/admin/users"} className={"btn btn-info mt-2 mr-2"}> |                         <form onSubmit={(e) => e.preventDefault()}> | ||||||
|                                 <Icon icon={"arrow-left"}/> |                             <table className={"table table-bordered table-hover dataTable dtr-inline"}> | ||||||
|                                  Back |                                 <thead> | ||||||
|                             </Link> |                                     <tr role={"row"}> | ||||||
|  |                                         {th} | ||||||
|  |                                     </tr> | ||||||
|  |                                 </thead> | ||||||
|  |                                 <tbody> | ||||||
|  |                                     {tr} | ||||||
|  |                                 </tbody> | ||||||
|  |                             </table> | ||||||
|  | 
 | ||||||
|  |                             <div className={"mt-2"}> | ||||||
|  |                                 <Link to={"/admin/users"} className={"btn btn-primary"}> | ||||||
|  |                                     <Icon icon={"arrow-left"}/> | ||||||
|  |                                      Back | ||||||
|  |                                 </Link> | ||||||
|  |                                 <button className={"btn btn-info ml-2"} onClick={() => this.onAddPermission()} disabled={this.state.isResetting || this.state.isSaving}> | ||||||
|  |                                     <Icon icon={"plus"}/> Add new Permission | ||||||
|  |                                 </button> | ||||||
|  |                                 <button className={"btn btn-secondary ml-2"} onClick={() => this.onResetPermissions()} disabled={this.state.isResetting || this.state.isSaving}> | ||||||
|  |                                     { this.state.isResetting ? <span>Resetting <Icon icon={"circle-notch"}/></span> : "Reset" } | ||||||
|  |                                 </button> | ||||||
|  |                                 <button className={"btn btn-success ml-2"} onClick={() => this.onSavePermissions()} disabled={this.state.isResetting || this.state.isSaving}> | ||||||
|  |                                     { this.state.isSaving ? <span>Saving <Icon icon={"circle-notch"}/></span> : "Save" } | ||||||
|  |                                 </button> | ||||||
|  |                             </div> | ||||||
|                         </form> |                         </form> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|         </>; |         </>; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     onAddPermission() { | ||||||
|  |         let newPermissions = this.state.permissions.slice(); | ||||||
|  |         newPermissions.push({ method: "", groups: [], description: null }); | ||||||
|  |         this.setState({ ...this.state, permissions: newPermissions }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     onResetPermissions() { | ||||||
|  |         this.setState({ ...this.state, isResetting: true }); | ||||||
|  |         this.fetchPermissions(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     onSavePermissions() { | ||||||
|  |         this.setState({ ...this.state, isSaving: true }); | ||||||
|  | 
 | ||||||
|  |         let permissions = []; | ||||||
|  |         for (let i = 0; i < this.state.permissions.length; i++) { | ||||||
|  |             let permission = this.state.permissions[i]; | ||||||
|  |             permissions.push({ method: permission.method, groups: permission.groups }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.parent.api.savePermissions(permissions).then((res) => { | ||||||
|  |             if (!res.success) { | ||||||
|  |                 let alerts = this.state.alerts.slice(); | ||||||
|  |                 alerts.push({ message: res.msg, title: "Error saving permissions" }); | ||||||
|  |                 this.setState({...this.state, alerts: alerts, isSaving: false}); | ||||||
|  |             } else { | ||||||
|  |                 this.setState({...this.state, isSaving: false}); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     onDeletePermission(index) { | ||||||
|  |         if (index < 0 || index >= this.state.permissions.length) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let newPermissions = this.state.permissions.slice(); | ||||||
|  |         newPermissions.splice(index, 1); | ||||||
|  |         this.setState({ ...this.state, permissions: newPermissions }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     onChangePermission(event, index, group = null) { | ||||||
|  |         if (index < 0 || index >= this.state.permissions.length) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let isChecked = event.target.checked; | ||||||
|  |         let newPermissions = this.state.permissions.slice(); | ||||||
|  |         if (group === null) { | ||||||
|  |             if (isChecked) { | ||||||
|  |                 newPermissions[index].groups = []; | ||||||
|  |             } else { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if (isChecked && !newPermissions[index].groups.includes(group)) { | ||||||
|  |                 newPermissions[index].groups.push(group); | ||||||
|  |             } else if(!isChecked) { | ||||||
|  |                 let indexOf = newPermissions[index].groups.indexOf(group); | ||||||
|  |                 if (indexOf !== -1) { | ||||||
|  |                     newPermissions[index].groups.splice(indexOf, 1); | ||||||
|  |                 } else { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.setState({ ...this.state, permissions: newPermissions }) | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| @ -78,6 +78,7 @@ export default class Settings extends React.Component { | |||||||
|         return this.state.general.keys.includes(key) |         return this.state.general.keys.includes(key) | ||||||
|             || this.state.mail.keys.includes(key) |             || this.state.mail.keys.includes(key) | ||||||
|             || this.state.messages.keys.includes(key) |             || this.state.messages.keys.includes(key) | ||||||
|  |             || this.state.recaptcha.keys.includes(key) | ||||||
|             || this.hiddenKeys.includes(key); |             || this.hiddenKeys.includes(key); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user