Merge branch 'reactjs'
This commit is contained in:
		
						commit
						fd738c46e8
					
				
							
								
								
									
										11
									
								
								.htaccess
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										11
									
								
								.htaccess
									
									
									
									
									
								
							| @ -1,8 +1,13 @@ | |||||||
| php_flag display_errors on | php_flag display_errors on | ||||||
| Options -Indexes | Options -Indexes | ||||||
| 
 | 
 | ||||||
| RedirectMatch 404 /\.git | DirectorySlash Off | ||||||
| 
 | 
 | ||||||
| RewriteEngine On | RewriteEngine On | ||||||
| RewriteRule ^api/(.*)?$ index.php?api=$1&$2 [L,QSA] | RewriteRule ^api(/.*)?$ /index.php?api=$1 [L,QSA] | ||||||
| RewriteRule ^((?!((js|css|img|fonts|api)($|\/)))(.*)?)$ index.php?site=$1&$2 [L,QSA] | 
 | ||||||
|  | RewriteEngine On | ||||||
|  | RewriteOptions AllowNoSlash | ||||||
|  | RewriteRule ^((\.idea|\.git|src|test|core)(/.*)?)$ /index.php?site=$1 [L,QSA] | ||||||
|  | 
 | ||||||
|  | FallbackResource /index.php | ||||||
							
								
								
									
										2
									
								
								.idea/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								.idea/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | # Default ignored files | ||||||
|  | /workspace.xml | ||||||
							
								
								
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | <component name="ProjectCodeStyleConfiguration"> | ||||||
|  |   <state> | ||||||
|  |     <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" /> | ||||||
|  |   </state> | ||||||
|  | </component> | ||||||
							
								
								
									
										8
									
								
								.idea/dictionaries/webbase.xml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										8
									
								
								.idea/dictionaries/webbase.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | <component name="ProjectDictionaryState"> | ||||||
|  |   <dictionary name="webbase"> | ||||||
|  |     <words> | ||||||
|  |       <w>adminlte</w> | ||||||
|  |       <w>navbar</w> | ||||||
|  |     </words> | ||||||
|  |   </dictionary> | ||||||
|  | </component> | ||||||
							
								
								
									
										6
									
								
								.idea/misc.xml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										6
									
								
								.idea/misc.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project version="4"> | ||||||
|  |   <component name="JavaScriptSettings"> | ||||||
|  |     <option name="languageLevel" value="JSX" /> | ||||||
|  |   </component> | ||||||
|  | </project> | ||||||
							
								
								
									
										8
									
								
								.idea/modules.xml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										8
									
								
								.idea/modules.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project version="4"> | ||||||
|  |   <component name="ProjectModuleManager"> | ||||||
|  |     <modules> | ||||||
|  |       <module fileurl="file://$PROJECT_DIR$/.idea/web-base.iml" filepath="$PROJECT_DIR$/.idea/web-base.iml" /> | ||||||
|  |     </modules> | ||||||
|  |   </component> | ||||||
|  | </project> | ||||||
							
								
								
									
										4
									
								
								.idea/php.xml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										4
									
								
								.idea/php.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project version="4"> | ||||||
|  |   <component name="PhpProjectSharedConfiguration" php_language_level="7.4" /> | ||||||
|  | </project> | ||||||
							
								
								
									
										6
									
								
								.idea/vcs.xml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										6
									
								
								.idea/vcs.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project version="4"> | ||||||
|  |   <component name="VcsDirectoryMappings"> | ||||||
|  |     <mapping directory="$PROJECT_DIR$" vcs="Git" /> | ||||||
|  |   </component> | ||||||
|  | </project> | ||||||
							
								
								
									
										8
									
								
								.idea/web-base.iml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										8
									
								
								.idea/web-base.iml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <module type="WEB_MODULE" version="4"> | ||||||
|  |   <component name="NewModuleRootManager"> | ||||||
|  |     <content url="file://$MODULE_DIR$" /> | ||||||
|  |     <orderEntry type="inheritedJdk" /> | ||||||
|  |     <orderEntry type="sourceFolder" forTests="false" /> | ||||||
|  |   </component> | ||||||
|  | </module> | ||||||
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										13
									
								
								README.md
									
									
									
									
									
								
							| @ -1,12 +1,19 @@ | |||||||
| # Web-Base | # Web-Base | ||||||
| 
 | 
 | ||||||
| Web-Base is a php framework which provides basic web functionalities. | Web-Base is a php framework which provides basic web functionalities and a modern ReactJS Admin Dashboard. | ||||||
|  | 
 | ||||||
|  | ### Requirements | ||||||
|  | - PHP >= 7.4 | ||||||
|  | - One of these php extensions: mysqli, postgres | ||||||
| 
 | 
 | ||||||
| ### Current Functionalities: | ### Current Functionalities: | ||||||
| - Installation Guide with automatic database setup | - Installation Guide with automatic database setup | ||||||
| - REST API | - REST API | ||||||
| - Account managment | - Account management | ||||||
| - New: Now supporting MySQL + PostgreSQL | - Supporting MySQL + PostgreSQL | ||||||
|  | - New: Page Routing | ||||||
|  | - New: Admin Dashboard | ||||||
|  | - New: Account & User functions | ||||||
| 
 | 
 | ||||||
| ### Upcoming: | ### Upcoming: | ||||||
| I actually don't know what i want to implement here. There are quite to many CMS out there with alot of vulnerabilities. There also exist some frameworks already. This project is meant to provide a stable project base to implement what ever a developer wants to: Dynamic Homepages, Webshops, .. | I actually don't know what i want to implement here. There are quite to many CMS out there with alot of vulnerabilities. There also exist some frameworks already. This project is meant to provide a stable project base to implement what ever a developer wants to: Dynamic Homepages, Webshops, .. | ||||||
|  | |||||||
| @ -1,44 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api\ApiKey; |  | ||||||
| 
 |  | ||||||
| use \Api\Request; |  | ||||||
| class Create extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array()); |  | ||||||
|     $this->apiKeyAllowed = false; |  | ||||||
|     $this->loginRequired = true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
| 
 |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $apiKey = generateRandomString(64); |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $validUntil = (new \DateTime())->modify("+30 DAY"); |  | ||||||
| 
 |  | ||||||
|     $this->success = $sql->insert("ApiKey", array("user_id", "api_key", "valid_until")) |  | ||||||
|       ->addRow($this->user->getId(), $apiKey, $validUntil) |  | ||||||
|       ->returning("uid") |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if ($this->success) { |  | ||||||
|       $this->result["api_key"] = array( |  | ||||||
|         "api_key" => $apiKey, |  | ||||||
|         "valid_until" => $validUntil->getTimestamp(), |  | ||||||
|         "uid" => $sql->getLastInsertId(), |  | ||||||
|       ); |  | ||||||
|     } else { |  | ||||||
|       $this->result["api_key"] = null; |  | ||||||
|     } |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -1,46 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api\ApiKey; |  | ||||||
| 
 |  | ||||||
| use \Api\Request; |  | ||||||
| use \Driver\SQL\Condition\Compare; |  | ||||||
| 
 |  | ||||||
| class Fetch extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array()); |  | ||||||
|     $this->loginRequired = true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->select("uid", "api_key", "valid_until") |  | ||||||
|       ->from("ApiKey") |  | ||||||
|       ->where(new Compare("user_id", $this->user->getId())) |  | ||||||
|       ->where(new Compare("valid_until", $sql->currentTimestamp(), ">")) |  | ||||||
|       ->where(new Compare("active", true)) |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if($this->success) { |  | ||||||
|       $this->result["api_keys"] = array(); |  | ||||||
|       foreach($res as $row) { |  | ||||||
|         $this->result["api_keys"][] = array( |  | ||||||
|           "uid" => $row["uid"], |  | ||||||
|           "api_key" => $row["api_key"], |  | ||||||
|           "valid_until" => (new \DateTime($row["valid_until"]))->getTimestamp(), |  | ||||||
|         ); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -1,67 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api\ApiKey; |  | ||||||
| 
 |  | ||||||
| use \Api\Request; |  | ||||||
| use \Api\Parameter\Parameter; |  | ||||||
| use \Driver\SQL\Condition\Compare; |  | ||||||
| 
 |  | ||||||
| class Refresh extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array( |  | ||||||
|       "id" => new Parameter("id", Parameter::TYPE_INT), |  | ||||||
|     )); |  | ||||||
|     $this->loginRequired = true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function apiKeyExists() { |  | ||||||
|     $id = $this->getParam("id"); |  | ||||||
| 
 |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->select($sql->count()) |  | ||||||
|       ->from("ApiKey") |  | ||||||
|       ->where(new Compare("uid", $id)) |  | ||||||
|       ->where(new Compare("user_id", $this->user->getId())) |  | ||||||
|       ->where(new Compare("valid_until", $sql->currentTimestamp(), ">")) |  | ||||||
|       ->where(new Compare("active", 1)) |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if($this->success && $res[0]["count"] === 0) { |  | ||||||
|       $this->success = false; |  | ||||||
|       $this->lastError = "This API-Key does not exist."; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $id = $this->getParam("id"); |  | ||||||
|     if(!$this->apiKeyExists()) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     $validUntil = (new \DateTime)->modify("+30 DAY"); |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $this->success = $sql->update("ApiKey") |  | ||||||
|       ->set("valid_until", $validUntil) |  | ||||||
|       ->where(new Compare("uid", $id)) |  | ||||||
|       ->where(new Compare("user_id", $this->user->getId())) |  | ||||||
|       ->execute(); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if ($this->success) { |  | ||||||
|       $this->result["valid_until"] = $validUntil->getTimestamp(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -1,62 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api\ApiKey; |  | ||||||
| 
 |  | ||||||
| use \Api\Request; |  | ||||||
| use \Api\Parameter\Parameter; |  | ||||||
| use \Driver\SQL\Condition\Compare; |  | ||||||
| 
 |  | ||||||
| class Revoke extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array( |  | ||||||
|       "id" => new Parameter("id", Parameter::TYPE_INT), |  | ||||||
|     )); |  | ||||||
|     $this->loginRequired = true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function apiKeyExists() { |  | ||||||
|     $id = $this->getParam("id"); |  | ||||||
| 
 |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->select($sql->count()) |  | ||||||
|       ->from("ApiKey") |  | ||||||
|       ->where(new Compare("uid", $id)) |  | ||||||
|       ->where(new Compare("user_id", $this->user->getId())) |  | ||||||
|       ->where(new Compare("valid_until", $sql->currentTimestamp(), ">")) |  | ||||||
|       ->where(new Compare("active", 1)) |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if($this->success && $res[0]["count"] === 0) { |  | ||||||
|       $this->success = false; |  | ||||||
|       $this->lastError = "This API-Key does not exist."; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($aValues = array()) { |  | ||||||
|     if(!parent::execute($aValues)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $id = $this->getParam("id"); |  | ||||||
|     if(!$this->apiKeyExists()) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $this->success = $sql->update("ApiKey") |  | ||||||
|       ->set("active", false) |  | ||||||
|       ->where(new Compare("uid", $id)) |  | ||||||
|       ->where(new Compare("user_id", $this->user->getId())) |  | ||||||
|       ->execute(); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
							
								
								
									
										187
									
								
								core/Api/ApiKeyAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										187
									
								
								core/Api/ApiKeyAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,187 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  | 
 | ||||||
|  |   use Driver\SQL\Condition\Compare; | ||||||
|  | 
 | ||||||
|  |   abstract class ApiKeyAPI extends Request { | ||||||
|  | 
 | ||||||
|  |     protected function apiKeyExists($id) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select($sql->count()) | ||||||
|  |         ->from("ApiKey") | ||||||
|  |         ->where(new Compare("uid", $id)) | ||||||
|  |         ->where(new Compare("user_id", $this->user->getId())) | ||||||
|  |         ->where(new Compare("valid_until", $sql->currentTimestamp(), ">")) | ||||||
|  |         ->where(new Compare("active", 1)) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if($this->success && $res[0]["count"] === 0) { | ||||||
|  |         return $this->createError("This API-Key does not exist."); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\ApiKey { | ||||||
|  | 
 | ||||||
|  |   use Api\ApiKeyAPI; | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use DateTime; | ||||||
|  |   use Driver\SQL\Condition\Compare; | ||||||
|  |   use Exception; | ||||||
|  | 
 | ||||||
|  |   class Create extends ApiKeyAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array()); | ||||||
|  |       $this->apiKeyAllowed = false; | ||||||
|  |       $this->loginRequired = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  | 
 | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $apiKey = generateRandomString(64); | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $validUntil = (new \DateTime())->modify("+30 DAY"); | ||||||
|  | 
 | ||||||
|  |       $this->success = $sql->insert("ApiKey", array("user_id", "api_key", "valid_until")) | ||||||
|  |         ->addRow($this->user->getId(), $apiKey, $validUntil) | ||||||
|  |         ->returning("uid") | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $this->result["api_key"] = array( | ||||||
|  |           "api_key" => $apiKey, | ||||||
|  |           "valid_until" => $validUntil->getTimestamp(), | ||||||
|  |           "uid" => $sql->getLastInsertId(), | ||||||
|  |         ); | ||||||
|  |       } else { | ||||||
|  |         $this->result["api_key"] = null; | ||||||
|  |       } | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Fetch extends ApiKeyAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array()); | ||||||
|  |       $this->loginRequired = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select("uid", "api_key", "valid_until") | ||||||
|  |         ->from("ApiKey") | ||||||
|  |         ->where(new Compare("user_id", $this->user->getId())) | ||||||
|  |         ->where(new Compare("valid_until", $sql->currentTimestamp(), ">")) | ||||||
|  |         ->where(new Compare("active", true)) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if($this->success) { | ||||||
|  |         $this->result["api_keys"] = array(); | ||||||
|  |         foreach($res as $row) { | ||||||
|  |           try { | ||||||
|  |             $validUntil = (new DateTime($row["valid_until"]))->getTimestamp(); | ||||||
|  |           } catch (Exception $e) { | ||||||
|  |             $validUntil = $row["valid_until"]; | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|  |           $this->result["api_keys"][] = array( | ||||||
|  |             "uid" => intval($row["uid"]), | ||||||
|  |             "api_key" => $row["api_key"], | ||||||
|  |             "valid_until" => $validUntil, | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Refresh extends ApiKeyAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         "id" => new Parameter("id", Parameter::TYPE_INT), | ||||||
|  |       )); | ||||||
|  |       $this->loginRequired = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $id = $this->getParam("id"); | ||||||
|  |       if(!$this->apiKeyExists($id)) | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |       $validUntil = (new \DateTime)->modify("+30 DAY"); | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $this->success = $sql->update("ApiKey") | ||||||
|  |         ->set("valid_until", $validUntil) | ||||||
|  |         ->where(new Compare("uid", $id)) | ||||||
|  |         ->where(new Compare("user_id", $this->user->getId())) | ||||||
|  |         ->execute(); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $this->result["valid_until"] = $validUntil->getTimestamp(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Revoke extends ApiKeyAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         "id" => new Parameter("id", Parameter::TYPE_INT), | ||||||
|  |       )); | ||||||
|  |       $this->loginRequired = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($aValues = array()) { | ||||||
|  |       if(!parent::execute($aValues)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $id = $this->getParam("id"); | ||||||
|  |       if(!$this->apiKeyExists($id)) | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $this->success = $sql->update("ApiKey") | ||||||
|  |         ->set("active", false) | ||||||
|  |         ->where(new Compare("uid", $id)) | ||||||
|  |         ->where(new Compare("user_id", $this->user->getId())) | ||||||
|  |         ->execute(); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										115
									
								
								core/Api/ContactAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										115
									
								
								core/Api/ContactAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,115 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  |   abstract class ContactAPI extends Request { | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\Contact { | ||||||
|  | 
 | ||||||
|  |   use Api\ContactAPI; | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use Api\Parameter\StringType; | ||||||
|  |   use Api\VerifyCaptcha; | ||||||
|  |   use Objects\User; | ||||||
|  | 
 | ||||||
|  |   class Request extends ContactAPI { | ||||||
|  | 
 | ||||||
|  |     private int $notificationId; | ||||||
|  |     private int $contactRequestId; | ||||||
|  | 
 | ||||||
|  |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |       $parameters = array( | ||||||
|  |         'fromName' => new StringType('fromName', 32), | ||||||
|  |         'fromEmail' => new Parameter('fromEmail', Parameter::TYPE_EMAIL), | ||||||
|  |         'message' => new StringType('message', 512), | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |       $settings = $user->getConfiguration()->getSettings(); | ||||||
|  |       if ($settings->isRecaptchaEnabled()) { | ||||||
|  |         $parameters["captcha"] = new StringType("captcha"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       parent::__construct($user, $externalCall, $parameters); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $settings = $this->user->getConfiguration()->getSettings(); | ||||||
|  |       if ($settings->isRecaptchaEnabled()) { | ||||||
|  |         $captcha = $this->getParam("captcha"); | ||||||
|  |         $req = new VerifyCaptcha($this->user); | ||||||
|  |         if (!$req->execute(array("captcha" => $captcha, "action" => "contact"))) { | ||||||
|  |           return $this->createError($req->getLastError()); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!$this->insertContactRequest()) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $this->createNotification(); | ||||||
|  | 
 | ||||||
|  |       if (!$this->success) { | ||||||
|  |         return $this->createError("The contact request was saved, but the server was unable to create a notification."); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function insertContactRequest() { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $name = $this->getParam("fromName"); | ||||||
|  |       $email = $this->getParam("fromEmail"); | ||||||
|  |       $message = $this->getParam("message"); | ||||||
|  | 
 | ||||||
|  |       $res = $sql->insert("ContactRequest", array("from_name", "from_email", "message")) | ||||||
|  |         ->addRow($name, $email, $message) | ||||||
|  |         ->returning("uid") | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $this->contactRequestId = $sql->getLastInsertId(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function createNotification() { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $name = $this->getParam("fromName"); | ||||||
|  |       $email = $this->getParam("fromEmail"); | ||||||
|  |       $message = $this->getParam("message"); | ||||||
|  | 
 | ||||||
|  |       $res = $sql->insert("Notification", array("title", "message", "type")) | ||||||
|  |         ->addRow("New Contact Request from: $name", "$name ($email) wrote:\n$message", "message") | ||||||
|  |         ->returning("uid") | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $this->notificationId = $sql->getLastInsertId(); | ||||||
|  | 
 | ||||||
|  |         $res = $sql->insert("GroupNotification", array("group_id", "notification_id")) | ||||||
|  |           ->addRow(USER_GROUP_ADMIN, $this->notificationId) | ||||||
|  |           ->addRow(USER_GROUP_SUPPORT, $this->notificationId) | ||||||
|  |           ->execute(); | ||||||
|  | 
 | ||||||
|  |         $this->success = ($res !== FALSE); | ||||||
|  |         $this->lastError = $sql->getLastError(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -1,39 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api; |  | ||||||
| 
 |  | ||||||
| class GetLanguages extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->select("uid", "code", "name") |  | ||||||
|       ->from("Language") |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if($this->success) { |  | ||||||
|       $this->result['languages'] = array(); |  | ||||||
|       if(empty($res) === 0) { |  | ||||||
|         $this->lastError = L("No languages found"); |  | ||||||
|       } else { |  | ||||||
|         foreach($res as $row) { |  | ||||||
|           $this->result['languages'][$row['uid']] = $row; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
							
								
								
									
										194
									
								
								core/Api/GroupsAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										194
									
								
								core/Api/GroupsAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,194 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  | 
 | ||||||
|  |   use Driver\SQL\Condition\Compare; | ||||||
|  | 
 | ||||||
|  |   abstract class GroupsAPI extends Request { | ||||||
|  | 
 | ||||||
|  |     protected function groupExists($name) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select($sql->count()) | ||||||
|  |         ->from("Group") | ||||||
|  |         ->where(new Compare("name", $name)) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  |       return $this->success && $res[0]["count"] > 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\Groups { | ||||||
|  | 
 | ||||||
|  |   use Api\GroupsAPI; | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use Api\Parameter\StringType; | ||||||
|  |   use Driver\SQL\Condition\Compare; | ||||||
|  | 
 | ||||||
|  |   class Fetch extends GroupsAPI { | ||||||
|  | 
 | ||||||
|  |     private int $groupCount; | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'page' => new Parameter('page', Parameter::TYPE_INT, true, 1), | ||||||
|  |         'count' => new Parameter('count', Parameter::TYPE_INT, true, 20) | ||||||
|  |       )); | ||||||
|  | 
 | ||||||
|  |       $this->groupCount = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function getGroupCount() { | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select($sql->count())->from("Group")->execute(); | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $this->groupCount = $res[0]["count"]; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $page = $this->getParam("page"); | ||||||
|  |       if($page < 1) { | ||||||
|  |         return $this->createError("Invalid page count"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $count = $this->getParam("count"); | ||||||
|  |       if($count < 1 || $count > 50) { | ||||||
|  |         return $this->createError("Invalid fetch count"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!$this->getGroupCount()) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select("Group.uid as groupId", "Group.name as groupName", "Group.color as groupColor", $sql->count("UserGroup.user_id")) | ||||||
|  |         ->from("Group") | ||||||
|  |         ->leftJoin("UserGroup", "UserGroup.group_id", "Group.uid") | ||||||
|  |         ->groupBy("Group.uid") | ||||||
|  |         ->orderBy("Group.uid") | ||||||
|  |         ->ascending() | ||||||
|  |         ->limit($count) | ||||||
|  |         ->offset(($page - 1) * $count) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if($this->success) { | ||||||
|  |         $this->result["groups"] = array(); | ||||||
|  |         foreach($res as $row) { | ||||||
|  |           $groupId = intval($row["groupId"]); | ||||||
|  |           $groupName = $row["groupName"]; | ||||||
|  |           $groupColor = $row["groupColor"]; | ||||||
|  |           $memberCount = $row["usergroup_user_id_count"]; | ||||||
|  |           $this->result["groups"][$groupId] = array( | ||||||
|  |             "name" => $groupName, | ||||||
|  |             "memberCount" => $memberCount, | ||||||
|  |             "color" => $groupColor, | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |         $this->result["pageCount"] = intval(ceil($this->groupCount / $count)); | ||||||
|  |         $this->result["totalCount"] = $this->groupCount; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Create extends GroupsAPI { | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'name' => new StringType('name', 32), | ||||||
|  |         'color' => new StringType('color', 10), | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $name = $this->getParam("name"); | ||||||
|  |       if (preg_match("/^[a-zA-Z][a-zA-Z0-9_-]*$/", $name) !== 1) { | ||||||
|  |         return $this->createError("Invalid name"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $color = $this->getParam("color"); | ||||||
|  |       if (preg_match("/^#[a-fA-F0-9]{3,6}$/", $color) !== 1) { | ||||||
|  |         return $this->createError("Invalid color"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $exists = $this->groupExists($name); | ||||||
|  |       if (!$this->success) { | ||||||
|  |         return false; | ||||||
|  |       } else if ($exists) { | ||||||
|  |         return $this->createError("A group with this name already exists"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->insert("Group", array("name", "color")) | ||||||
|  |         ->addRow($name, $color) | ||||||
|  |         ->returning("uid") | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $this->result["uid"] = $sql->getLastInsertId(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Delete extends GroupsAPI { | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'uid' => new Parameter('uid', Parameter::TYPE_INT) | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $id = $this->getParam("uid"); | ||||||
|  |       if (in_array($id, DEFAULT_GROUPS)) { | ||||||
|  |         return $this->createError("You cannot delete a default group."); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select($sql->count()) | ||||||
|  |         ->from("Group") | ||||||
|  |         ->where(new Compare("uid", $id)) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success && $res[0]["count"] === 0) { | ||||||
|  |         return $this->createError("This group does not exist."); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $res = $sql->delete("Group")->where(new Compare("uid", $id))->execute(); | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										128
									
								
								core/Api/LanguageAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										128
									
								
								core/Api/LanguageAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  | 
 | ||||||
|  |   abstract class LanguageAPI extends Request { | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\Language { | ||||||
|  | 
 | ||||||
|  |   use Api\LanguageAPI; | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use Api\Parameter\StringType; | ||||||
|  |   use Driver\SQL\Condition\Compare; | ||||||
|  |   use Driver\SQL\Condition\CondOr; | ||||||
|  |   use Objects\Language; | ||||||
|  | 
 | ||||||
|  |   class Get extends LanguageAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select("uid", "code", "name") | ||||||
|  |         ->from("Language") | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if($this->success) { | ||||||
|  |         $this->result['languages'] = array(); | ||||||
|  |         if(empty($res) === 0) { | ||||||
|  |           $this->lastError = L("No languages found"); | ||||||
|  |         } else { | ||||||
|  |           foreach($res as $row) { | ||||||
|  |             $this->result['languages'][$row['uid']] = $row; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Set extends LanguageAPI { | ||||||
|  | 
 | ||||||
|  |     private Language $language; | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'langId' => new Parameter('langId', Parameter::TYPE_INT, true, NULL), | ||||||
|  |         'langCode' => new StringType('langCode', 5, true, NULL), | ||||||
|  |       )); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function checkLanguage() { | ||||||
|  |       $langId = $this->getParam("langId"); | ||||||
|  |       $langCode = $this->getParam("langCode"); | ||||||
|  | 
 | ||||||
|  |       if(is_null($langId) && is_null($langCode)) { | ||||||
|  |         return $this->createError(L("Either langId or langCode must be given")); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $res = $this->user->getSQL() | ||||||
|  |         ->select("uid", "code", "name") | ||||||
|  |         ->from("Language") | ||||||
|  |         ->where(new CondOr(new Compare("uid", $langId), new Compare("code", $langCode))) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $this->user->getSQL()->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         if(count($res) == 0) { | ||||||
|  |           return $this->createError(L("This Language does not exist")); | ||||||
|  |         } else { | ||||||
|  |           $row = $res[0]; | ||||||
|  |           $this->language = Language::newInstance($row['uid'], $row['code'], $row['name']); | ||||||
|  |           if(!$this->language) { | ||||||
|  |             return $this->createError(L("Error while loading language")); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function updateLanguage() { | ||||||
|  |       $languageId = $this->language->getId(); | ||||||
|  |       $userId = $this->user->getId(); | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  | 
 | ||||||
|  |       $this->success = $sql->update("User") | ||||||
|  |         ->set("language_id", $languageId) | ||||||
|  |         ->where(new Compare("uid", $userId)) | ||||||
|  |         ->execute(); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if(!$this->checkLanguage()) | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |       if($this->user->isLoggedIn()) { | ||||||
|  |         $this->updateLanguage(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $this->user->setLanguage($this->language); | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										120
									
								
								core/Api/MailAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										120
									
								
								core/Api/MailAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,120 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  |   abstract 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; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,135 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api\Notifications; |  | ||||||
| 
 |  | ||||||
| use \Api\Request; |  | ||||||
| use \Api\Parameter\Parameter; |  | ||||||
| use \Api\Parameter\StringType; |  | ||||||
| use \Driver\SQL\Condition\Compare; |  | ||||||
| 
 |  | ||||||
| class Create extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array( |  | ||||||
|       'groupId' => new Parameter('groupId', Parameter::TYPE_INT, true), |  | ||||||
|       'userId' => new Parameter('userId', Parameter::TYPE_INT, true), |  | ||||||
|       'title' =>  new StringType('title', 32), |  | ||||||
|       'message' =>  new StringType('message', 256), |  | ||||||
|     )); |  | ||||||
|     $this->isPublic = false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function checkUser($userId) { |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->select($sql->count()) |  | ||||||
|       ->from("User") |  | ||||||
|       ->where(new Compare("uid", $userId)) |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|       $this->success = ($res !== FALSE); |  | ||||||
|       $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if ($this->success) { |  | ||||||
|       if ($res[0]["count"] == 0) { |  | ||||||
|         $this->success = false; |  | ||||||
|         $this->lastError = "User not found"; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function insertUserNotification($userId, $notificationId) { |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->insert("UserNotification", array("user_id", "notification_id")) |  | ||||||
|       ->addRow($userId, $notificationId) |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function checkGroup($groupId) { |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->select($sql->count()) |  | ||||||
|       ->from("Group") |  | ||||||
|       ->where(new Compare("uid", $groupId)) |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if ($this->success) { |  | ||||||
|       if ($res[0]["count"] == 0) { |  | ||||||
|         $this->success = false; |  | ||||||
|         $this->lastError = "Group not found"; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function insertGroupNotification($groupId, $notificationId) { |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->insert("GroupNotification", array("group_id", "notification_id")) |  | ||||||
|       ->addRow($groupId, $notificationId) |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function createNotification($title, $message) { |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->insert("Notification", array("title", "message")) |  | ||||||
|       ->addRow($title, $message) |  | ||||||
|       ->returning("uid") |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if ($this->success) { |  | ||||||
|       return $sql->getLastInsertId(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $userId = $this->getParam("userId"); |  | ||||||
|     $groupId = $this->getParam("groupId"); |  | ||||||
|     $title = $this->getParam("title"); |  | ||||||
|     $message = $this->getParam("message"); |  | ||||||
| 
 |  | ||||||
|     if (is_null($userId) && is_null($groupId)) { |  | ||||||
|       return $this->createError("Either userId or groupId must be specified."); |  | ||||||
|     } else if(!is_null($userId) && !is_null($groupId)) { |  | ||||||
|       return $this->createError("Only one of userId and groupId must be specified."); |  | ||||||
|     } else if(!is_null($userId)) { |  | ||||||
|       if ($this->checkUser($userId)) { |  | ||||||
|         $id = $this->createNotification($title, $message); |  | ||||||
|         if ($this->success) { |  | ||||||
|           return $this->insertUserNotification($userId, $id); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } else if(!is_null($groupId)) { |  | ||||||
|       if ($this->checkGroup($groupId)) { |  | ||||||
|         $id = $this->createNotification($title, $message); |  | ||||||
|         if ($this->success) { |  | ||||||
|           return $this->insertGroupNotification($groupId, $id); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -1,94 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api\Notifications; |  | ||||||
| 
 |  | ||||||
| use \Api\Request; |  | ||||||
| use \Driver\SQL\Condition\Compare; |  | ||||||
| 
 |  | ||||||
| class Fetch extends Request { |  | ||||||
| 
 |  | ||||||
|   private $notifications; |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array()); |  | ||||||
|     $this->loginRequired = true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function fetchUserNotifications() { |  | ||||||
|     $userId = $this->user->getId(); |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message") |  | ||||||
|       ->from("Notification") |  | ||||||
|       ->innerJoin("UserNotification", "UserNotification.notification_id", "Notification.uid") |  | ||||||
|       ->where(new Compare("UserNotification.user_id", $userId)) |  | ||||||
|       ->where(new Compare("UserNotification.seen", false)) |  | ||||||
|       ->orderBy("created_at")->descending() |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if ($this->success) { |  | ||||||
|       foreach($res as $row) { |  | ||||||
|         $id = $row["uid"]; |  | ||||||
|         if (!isset($this->notifications[$id])) { |  | ||||||
|           $this->notifications[$id] = array( |  | ||||||
|             "uid" => $id, |  | ||||||
|             "title" => $row["title"], |  | ||||||
|             "message" => $row["message"], |  | ||||||
|             "created_at" => $row["created_at"], |  | ||||||
|           ); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function fetchGroupNotifications() { |  | ||||||
|     $userId = $this->user->getId(); |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message") |  | ||||||
|       ->from("Notification") |  | ||||||
|       ->innerJoin("GroupNotification", "GroupNotification.notification_id", "Notification.uid") |  | ||||||
|       ->innerJoin("UserGroup", "GroupNotification.group_id", "UserGroup.group_id") |  | ||||||
|       ->where(new Compare("UserGroup.user_id", $userId)) |  | ||||||
|       ->where(new Compare("GroupNotification.seen", false)) |  | ||||||
|       ->orderBy("created_at")->descending() |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if ($this->success) { |  | ||||||
|       foreach($res as $row) { |  | ||||||
|         $id = $row["uid"]; |  | ||||||
|         if (!isset($this->notifications[$id])) { |  | ||||||
|           $this->notifications[$id] = array( |  | ||||||
|             "uid" => $id, |  | ||||||
|             "title" => $row["title"], |  | ||||||
|             "message" => $row["message"], |  | ||||||
|             "created_at" => $row["created_at"], |  | ||||||
|           ); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $this->notifications = array(); |  | ||||||
|     if ($this->fetchUserNotifications() && $this->fetchGroupNotifications()) { |  | ||||||
|       $this->result["notifications"] = $this->notifications; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
							
								
								
									
										268
									
								
								core/Api/NotificationsAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										268
									
								
								core/Api/NotificationsAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,268 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  |   abstract class NotificationsAPI extends Request { | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\Notifications { | ||||||
|  | 
 | ||||||
|  |   use Api\NotificationsAPI; | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use Api\Parameter\StringType; | ||||||
|  |   use Driver\SQL\Condition\Compare; | ||||||
|  |   use Driver\SQL\Condition\CondIn; | ||||||
|  |   use Driver\SQL\Query\Select; | ||||||
|  |   use Objects\User; | ||||||
|  | 
 | ||||||
|  |   class Create extends NotificationsAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'groupId' => new Parameter('groupId', Parameter::TYPE_INT, true), | ||||||
|  |         'userId' => new Parameter('userId', Parameter::TYPE_INT, true), | ||||||
|  |         'title' =>  new StringType('title', 32), | ||||||
|  |         'message' =>  new StringType('message', 256), | ||||||
|  |       )); | ||||||
|  |       $this->isPublic = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function checkUser($userId) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select($sql->count()) | ||||||
|  |         ->from("User") | ||||||
|  |         ->where(new Compare("uid", $userId)) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         if ($res[0]["count"] == 0) { | ||||||
|  |           $this->success = false; | ||||||
|  |           $this->lastError = "User not found"; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function insertUserNotification($userId, $notificationId) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->insert("UserNotification", array("user_id", "notification_id")) | ||||||
|  |         ->addRow($userId, $notificationId) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function checkGroup($groupId) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select($sql->count()) | ||||||
|  |         ->from("Group") | ||||||
|  |         ->where(new Compare("uid", $groupId)) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         if ($res[0]["count"] == 0) { | ||||||
|  |           $this->success = false; | ||||||
|  |           $this->lastError = "Group not found"; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function insertGroupNotification($groupId, $notificationId) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->insert("GroupNotification", array("group_id", "notification_id")) | ||||||
|  |         ->addRow($groupId, $notificationId) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function createNotification($title, $message) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->insert("Notification", array("title", "message")) | ||||||
|  |         ->addRow($title, $message) | ||||||
|  |         ->returning("uid") | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         return $sql->getLastInsertId(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $userId = $this->getParam("userId"); | ||||||
|  |       $groupId = $this->getParam("groupId"); | ||||||
|  |       $title = $this->getParam("title"); | ||||||
|  |       $message = $this->getParam("message"); | ||||||
|  | 
 | ||||||
|  |       if (is_null($userId) && is_null($groupId)) { | ||||||
|  |         return $this->createError("Either userId or groupId must be specified."); | ||||||
|  |       } else if(!is_null($userId) && !is_null($groupId)) { | ||||||
|  |         return $this->createError("Only one of userId and groupId must be specified."); | ||||||
|  |       } else if(!is_null($userId)) { | ||||||
|  |         if ($this->checkUser($userId)) { | ||||||
|  |           $id = $this->createNotification($title, $message); | ||||||
|  |           if ($this->success) { | ||||||
|  |             return $this->insertUserNotification($userId, $id); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } else if(!is_null($groupId)) { | ||||||
|  |         if ($this->checkGroup($groupId)) { | ||||||
|  |           $id = $this->createNotification($title, $message); | ||||||
|  |           if ($this->success) { | ||||||
|  |             return $this->insertGroupNotification($groupId, $id); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Fetch extends NotificationsAPI { | ||||||
|  | 
 | ||||||
|  |     private array $notifications; | ||||||
|  |     private array $notificationids; | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'new' => new Parameter('new', Parameter::TYPE_BOOLEAN, true, true) | ||||||
|  |       )); | ||||||
|  |       $this->loginRequired = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function fetchUserNotifications() { | ||||||
|  |       $onlyNew = $this->getParam('new'); | ||||||
|  |       $userId = $this->user->getId(); | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $query = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message", "type") | ||||||
|  |         ->from("Notification") | ||||||
|  |         ->innerJoin("UserNotification", "UserNotification.notification_id", "Notification.uid") | ||||||
|  |         ->where(new Compare("UserNotification.user_id", $userId)) | ||||||
|  |         ->orderBy("created_at")->descending(); | ||||||
|  | 
 | ||||||
|  |       if ($onlyNew) { | ||||||
|  |         $query->where(new Compare("UserNotification.seen", false)); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->fetchNotifications($query); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function fetchGroupNotifications() { | ||||||
|  |       $onlyNew = $this->getParam('new'); | ||||||
|  |       $userId = $this->user->getId(); | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $query = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message", "type") | ||||||
|  |         ->from("Notification") | ||||||
|  |         ->innerJoin("GroupNotification", "GroupNotification.notification_id", "Notification.uid") | ||||||
|  |         ->innerJoin("UserGroup", "GroupNotification.group_id", "UserGroup.group_id") | ||||||
|  |         ->where(new Compare("UserGroup.user_id", $userId)) | ||||||
|  |         ->orderBy("created_at")->descending(); | ||||||
|  | 
 | ||||||
|  |       if ($onlyNew) { | ||||||
|  |         $query->where(new Compare("GroupNotification.seen", false)); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->fetchNotifications($query); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function fetchNotifications(Select $query) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $query->execute(); | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         foreach($res as $row) { | ||||||
|  |           $id = $row["uid"]; | ||||||
|  |           if (!in_array($id, $this->notificationids)) { | ||||||
|  |             $this->notificationids[] = $id; | ||||||
|  |             $this->notifications[] = array( | ||||||
|  |               "uid" => $id, | ||||||
|  |               "title" => $row["title"], | ||||||
|  |               "message" => $row["message"], | ||||||
|  |               "created_at" => $row["created_at"], | ||||||
|  |               "type" => $row["type"] | ||||||
|  |             ); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $this->notifications = array(); | ||||||
|  |       $this->notificationids = array(); | ||||||
|  |       if ($this->fetchUserNotifications() && $this->fetchGroupNotifications()) { | ||||||
|  |         $this->result["notifications"] = $this->notifications; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Seen extends NotificationsAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array()); | ||||||
|  |       $this->loginRequired = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->update("UserNotification") | ||||||
|  |         ->set("seen", true) | ||||||
|  |         ->where(new Compare("user_id", $this->user->getId())) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $res = $sql->update("GroupNotification") | ||||||
|  |           ->set("seen", true) | ||||||
|  |           ->where(new CondIn("group_id", | ||||||
|  |             $sql->select("group_id") | ||||||
|  |               ->from("UserGroup") | ||||||
|  |               ->where(new Compare("user_id", $this->user->getId())))) | ||||||
|  |           ->execute(); | ||||||
|  | 
 | ||||||
|  |         $this->success = ($res !== FALSE); | ||||||
|  |         $this->lastError = $sql->getLastError(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -2,6 +2,8 @@ | |||||||
| 
 | 
 | ||||||
| namespace Api\Parameter; | namespace Api\Parameter; | ||||||
| 
 | 
 | ||||||
|  | use DateTime; | ||||||
|  | 
 | ||||||
| class Parameter { | class Parameter { | ||||||
|   const TYPE_INT       = 0; |   const TYPE_INT       = 0; | ||||||
|   const TYPE_FLOAT     = 1; |   const TYPE_FLOAT     = 1; | ||||||
| @ -14,15 +16,17 @@ class Parameter { | |||||||
| 
 | 
 | ||||||
|   // only internal access
 |   // only internal access
 | ||||||
|   const TYPE_RAW       = 8; |   const TYPE_RAW       = 8; | ||||||
|  | 
 | ||||||
|  |   // only json will work here i guess
 | ||||||
|   const TYPE_ARRAY     = 9; |   const TYPE_ARRAY     = 9; | ||||||
| 
 | 
 | ||||||
|   const names = array('Integer', 'Float', 'Boolean', 'String', 'Date', 'Time', 'DateTime', 'E-Mail', 'Raw', 'Array'); |   const names = array('Integer', 'Float', 'Boolean', 'String', 'Date', 'Time', 'DateTime', 'E-Mail', 'Raw', 'Array'); | ||||||
| 
 | 
 | ||||||
|   public $name; |   public string $name; | ||||||
|   public $value; |   public $value; | ||||||
|   public $optional; |   public $optional; | ||||||
|   public $type; |   public int $type; | ||||||
|   public $typeName; |   public string $typeName; | ||||||
| 
 | 
 | ||||||
|   public function __construct($name, $type, $optional = FALSE, $defaultValue = NULL) { |   public function __construct($name, $type, $optional = FALSE, $defaultValue = NULL) { | ||||||
|     $this->name = $name; |     $this->name = $name; | ||||||
| @ -59,11 +63,11 @@ class Parameter { | |||||||
|       return Parameter::TYPE_BOOLEAN; |       return Parameter::TYPE_BOOLEAN; | ||||||
|     else if(is_a($value, 'DateTime')) |     else if(is_a($value, 'DateTime')) | ||||||
|       return Parameter::TYPE_DATE_TIME; |       return Parameter::TYPE_DATE_TIME; | ||||||
|     else if(($d = \DateTime::createFromFormat('Y-m-d', $value)) && $d->format('Y-m-d') === $value) |     else if(($d = DateTime::createFromFormat('Y-m-d', $value)) && $d->format('Y-m-d') === $value) | ||||||
|       return Parameter::TYPE_DATE; |       return Parameter::TYPE_DATE; | ||||||
|     else if(($d = \DateTime::createFromFormat('H:i:s', $value)) && $d->format('H:i:s') === $value) |     else if(($d = DateTime::createFromFormat('H:i:s', $value)) && $d->format('H:i:s') === $value) | ||||||
|       return Parameter::TYPE_TIME; |       return Parameter::TYPE_TIME; | ||||||
|     else if(($d = \DateTime::createFromFormat('Y-m-d H:i:s', $value)) && $d->format('Y-m-d H:i:s') === $value) |     else if(($d = DateTime::createFromFormat('Y-m-d H:i:s', $value)) && $d->format('Y-m-d H:i:s') === $value) | ||||||
|       return Parameter::TYPE_DATE_TIME; |       return Parameter::TYPE_DATE_TIME; | ||||||
|     else if (filter_var($value, FILTER_VALIDATE_EMAIL)) |     else if (filter_var($value, FILTER_VALIDATE_EMAIL)) | ||||||
|       return Parameter::TYPE_EMAIL; |       return Parameter::TYPE_EMAIL; | ||||||
| @ -157,5 +161,3 @@ class Parameter { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,10 +4,10 @@ namespace Api\Parameter; | |||||||
| 
 | 
 | ||||||
| class StringType extends Parameter { | class StringType extends Parameter { | ||||||
| 
 | 
 | ||||||
|   public $maxLength; |   public int $maxLength; | ||||||
|   public function __construct($name, $maxLength = -1, $optional = FALSE, $defaultValue = NULL) { |   public function __construct($name, $maxLength = -1, $optional = FALSE, $defaultValue = NULL) { | ||||||
|     parent::__construct($name, Parameter::TYPE_STRING, $optional, $defaultValue); |  | ||||||
|     $this->maxLength = $maxLength; |     $this->maxLength = $maxLength; | ||||||
|  |     parent::__construct($name, Parameter::TYPE_STRING, $optional, $defaultValue); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function parseParam($value) { |   public function parseParam($value) { | ||||||
| @ -39,5 +39,3 @@ class StringType extends Parameter { | |||||||
|     return $str; |     return $str; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
							
								
								
									
										213
									
								
								core/Api/PermissionAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										213
									
								
								core/Api/PermissionAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,213 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  | 
 | ||||||
|  |   abstract class PermissionAPI extends Request { | ||||||
|  |     protected function checkStaticPermission() { | ||||||
|  |       if (!$this->user->isLoggedIn() || !$this->user->hasGroup(USER_GROUP_ADMIN)) { | ||||||
|  |         return $this->createError("Permission denied."); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\Permission { | ||||||
|  | 
 | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use Api\Parameter\StringType; | ||||||
|  |   use Api\PermissionAPI; | ||||||
|  |   use Driver\SQL\Column\Column; | ||||||
|  |   use Driver\SQL\Condition\Compare; | ||||||
|  |   use Driver\SQL\Condition\CondIn; | ||||||
|  |   use Driver\SQL\Condition\CondNot; | ||||||
|  |   use Driver\SQL\Strategy\UpdateStrategy; | ||||||
|  |   use Objects\User; | ||||||
|  | 
 | ||||||
|  |   class Check extends PermissionAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'method' => new StringType('method', 323) | ||||||
|  |       )); | ||||||
|  | 
 | ||||||
|  |       $this->isPublic = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $method = $this->getParam("method"); | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select("groups") | ||||||
|  |         ->from("ApiPermission") | ||||||
|  |         ->where(new Compare("method", $method)) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         if (empty($res)) { | ||||||
|  |           return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $groups = json_decode($res[0]["groups"]); | ||||||
|  |         if (empty($groups)) { | ||||||
|  |           return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Fetch extends PermissionAPI { | ||||||
|  | 
 | ||||||
|  |     private array $groups; | ||||||
|  | 
 | ||||||
|  |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function fetchGroups() { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select("uid", "name", "color") | ||||||
|  |         ->from("Group") | ||||||
|  |         ->orderBy("uid") | ||||||
|  |         ->ascending() | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $this->groups = array(); | ||||||
|  |         foreach($res as $row) { | ||||||
|  |           $groupId = $row["uid"]; | ||||||
|  |           $groupName = $row["name"]; | ||||||
|  |           $groupColor = $row["color"]; | ||||||
|  |           $this->groups[$groupId] = array("name" => $groupName, "color" => $groupColor); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!$this->checkStaticPermission()) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!$this->fetchGroups()) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select("method", "groups", "description") | ||||||
|  |         ->from("ApiPermission") | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $permissions = array(); | ||||||
|  |         foreach ($res as $row) { | ||||||
|  |           $method = $row["method"]; | ||||||
|  |           $description = $row["description"]; | ||||||
|  |           $groups = json_decode($row["groups"]); | ||||||
|  |           $permissions[] = array( | ||||||
|  |             "method" => $method, | ||||||
|  |             "groups" => $groups, | ||||||
|  |             "description" => $description | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |         $this->result["permissions"] = $permissions; | ||||||
|  |         $this->result["groups"] = $this->groups; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Save extends PermissionAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'permissions' => new Parameter('permissions', Parameter::TYPE_ARRAY) | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!$this->checkStaticPermission()) { | ||||||
|  |         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; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -2,36 +2,41 @@ | |||||||
| 
 | 
 | ||||||
| namespace Api; | namespace Api; | ||||||
| 
 | 
 | ||||||
|  | use Objects\User; | ||||||
|  | 
 | ||||||
| class Request { | class Request { | ||||||
| 
 | 
 | ||||||
|   protected $user; |   protected User $user; | ||||||
|   protected $params; |   protected array $params; | ||||||
|   protected $lastError; |   protected string $lastError; | ||||||
|   protected $result; |   protected array $result; | ||||||
|   protected $success; |   protected bool $success; | ||||||
|   protected $isPublic; |   protected bool $isPublic; | ||||||
|   protected $loginRequired; |   protected bool $loginRequired; | ||||||
|   protected $variableParamCount; |   protected bool $variableParamCount; | ||||||
|   protected $isDisabled; |   protected bool $isDisabled; | ||||||
|   protected $apiKeyAllowed; |   protected bool $apiKeyAllowed; | ||||||
|  |   protected bool $csrfTokenRequired; | ||||||
| 
 | 
 | ||||||
|   private $aDefaultParams; |   private array $aDefaultParams; | ||||||
|   private $allowedMethods; |   private array $allowedMethods; | ||||||
|   private $externCall; |   private bool $externalCall; | ||||||
| 
 | 
 | ||||||
|   public function __construct($user, $externCall = false, $params = array()) { |   public function __construct(User $user, bool $externalCall = false, array $params = array()) { | ||||||
|     $this->user = $user; |     $this->user = $user; | ||||||
|     $this->aDefaultParams = $params; |     $this->aDefaultParams = $params; | ||||||
|     $this->lastError = ''; | 
 | ||||||
|     $this->success = false; |     $this->success = false; | ||||||
|     $this->result = array(); |     $this->result = array(); | ||||||
|     $this->externCall = $externCall; |     $this->externalCall = $externalCall; | ||||||
|     $this->isPublic = true; |     $this->isPublic = true; | ||||||
|     $this->isDisabled = false; |     $this->isDisabled = false; | ||||||
|     $this->loginRequired = false; |     $this->loginRequired = false; | ||||||
|     $this->variableParamCount = false; |     $this->variableParamCount = false; | ||||||
|     $this->apiKeyAllowed = true; |     $this->apiKeyAllowed = true; | ||||||
|     $this->allowedMethods = array("GET", "POST"); |     $this->allowedMethods = array("GET", "POST"); | ||||||
|  |     $this->lastError = ""; | ||||||
|  |     $this->csrfTokenRequired = true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected function forbidMethod($method) { |   protected function forbidMethod($method) { | ||||||
| @ -40,33 +45,20 @@ class Request { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getParamsString() { |  | ||||||
|     $str = ""; |  | ||||||
|     $count = count($this->params); |  | ||||||
|     $i = 0; |  | ||||||
|     foreach($this->params as $param) { |  | ||||||
|       $str .= $param->toString(); |  | ||||||
|       if($i < $count - 1) $str .= ", "; |  | ||||||
|       $i++; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return "($str)"; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function parseParams($values) { |   public function parseParams($values) { | ||||||
|     foreach($this->params as $name => $param) { |  | ||||||
|       $value = (isset($values[$name]) ? $values[$name] : NULL); |  | ||||||
| 
 | 
 | ||||||
|       if(!$param->optional && is_null($value)) { |     foreach($this->params as $name => $param) { | ||||||
|         $this->lastError = 'Missing parameter: ' . $name; |       $value = $values[$name] ?? NULL; | ||||||
|         return false; | 
 | ||||||
|  |       $isEmpty = (is_string($value) || is_array($value)) && empty($value); | ||||||
|  |       if(!$param->optional && (is_null($value) || $isEmpty)) { | ||||||
|  |         return $this->createError("Missing parameter: $name"); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       if(!is_null($value)) { |       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; |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @ -93,11 +85,17 @@ class Request { | |||||||
|       $this->result['logoutIn'] = $this->user->getSession()->getExpiresSeconds(); |       $this->result['logoutIn'] = $this->user->getSession()->getExpiresSeconds(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if($this->externCall) { |     if($this->externalCall) { | ||||||
|       $values = $_REQUEST; |       $values = $_REQUEST; | ||||||
|       if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SERVER["CONTENT_TYPE"]) && in_array("application/json", explode(";", $_SERVER["CONTENT_TYPE"]))) { |       if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SERVER["CONTENT_TYPE"]) && in_array("application/json", explode(";", $_SERVER["CONTENT_TYPE"]))) { | ||||||
|         $jsonData = json_decode(file_get_contents('php://input'), true); |         $jsonData = json_decode(file_get_contents('php://input'), true); | ||||||
|  |         if ($jsonData) { | ||||||
|           $values = array_merge($values, $jsonData); |           $values = array_merge($values, $jsonData); | ||||||
|  |         } else { | ||||||
|  |           $this->lastError = 'Invalid request body.'; | ||||||
|  |           header('HTTP 1.1 400 Bad Request'); | ||||||
|  |           return false; | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -106,7 +104,7 @@ class Request { | |||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if($this->externCall && !$this->isPublic) { |     if($this->externalCall && !$this->isPublic) { | ||||||
|       $this->lastError = 'This function is private.'; |       $this->lastError = 'This function is private.'; | ||||||
|       header('HTTP 1.1 403 Forbidden'); |       header('HTTP 1.1 403 Forbidden'); | ||||||
|       return false; |       return false; | ||||||
| @ -118,21 +116,45 @@ class Request { | |||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if($this->externalCall) { | ||||||
|  |       $apiKeyAuthorized = false; | ||||||
| 
 | 
 | ||||||
|  |       // Logged in or api key authorized?
 | ||||||
|       if ($this->loginRequired) { |       if ($this->loginRequired) { | ||||||
|       $authorized = false; |  | ||||||
|         if(isset($values['api_key']) && $this->apiKeyAllowed) { |         if(isset($values['api_key']) && $this->apiKeyAllowed) { | ||||||
|           $apiKey = $values['api_key']; |           $apiKey = $values['api_key']; | ||||||
|         $authorized = $this->user->authorize($apiKey); |           $apiKeyAuthorized = $this->user->authorize($apiKey); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|       if(!$this->user->isLoggedIn() && !$authorized) { |         if(!$this->user->isLoggedIn() && !$apiKeyAuthorized) { | ||||||
|           $this->lastError = 'You are not logged in.'; |           $this->lastError = 'You are not logged in.'; | ||||||
|           header('HTTP 1.1 401 Unauthorized'); |           header('HTTP 1.1 401 Unauthorized'); | ||||||
|           return false; |           return false; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  |       // CSRF Token
 | ||||||
|  |       if($this->csrfTokenRequired && $this->user->isLoggedIn()) { | ||||||
|  |         // csrf token required + external call
 | ||||||
|  |         // 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) { | ||||||
|  |           $this->lastError = "CSRF-Token mismatch"; | ||||||
|  |           header('HTTP 1.1 403 Forbidden'); | ||||||
|  |           return false; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // Check for permission
 | ||||||
|  |       if (!($this instanceof \Api\Permission\Save)) { | ||||||
|  |         $req = new \Api\Permission\Check($this->user); | ||||||
|  |         $this->success = $req->execute(array("method" => $this->getMethod())); | ||||||
|  |         $this->lastError = $req->getLastError(); | ||||||
|  |         if (!$this->success) { | ||||||
|  |           return false; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if(!$this->parseParams($values)) |     if(!$this->parseParams($values)) | ||||||
|       return false; |       return false; | ||||||
| 
 | 
 | ||||||
| @ -149,47 +171,32 @@ class Request { | |||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected function isValidString($str, $regex) { |  | ||||||
|     return preg_replace($regex, "", $str) === $str; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   protected function createError($err) { |   protected function createError($err) { | ||||||
|     $this->success = false; |     $this->success = false; | ||||||
|     $this->lastError = $err; |     $this->lastError = $err; | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|   //
 |  | ||||||
|   // public static function callDirectly($class, $db) {
 |  | ||||||
|   //   header('Content-Type: application/json');
 |  | ||||||
|   //   require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/api/objects/User.php';
 |  | ||||||
|   //   require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/sql.php';
 |  | ||||||
|   //   require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/conf/sql.php';
 |  | ||||||
|   //
 |  | ||||||
|   //   $sql = connectSQL(getSqlData($db));
 |  | ||||||
|   //   $user = new CUser($sql);
 |  | ||||||
|   //   $request = new $class($user, true);
 |  | ||||||
|   //   $request->execute();
 |  | ||||||
|   //   $sql->close();
 |  | ||||||
|   //   $user->sendCookies();
 |  | ||||||
|   //   return $request->getJsonResult();
 |  | ||||||
|   // }
 |  | ||||||
| 
 | 
 | ||||||
|   protected function getParam($name) { return isset($this->params[$name]) ? $this->params[$name]->value : NULL; } |   protected function getParam($name) { | ||||||
|  |     return isset($this->params[$name]) ? $this->params[$name]->value : NULL; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   public function isPublic() { return $this->isPublic; } |   public function isPublic() { return $this->isPublic; } | ||||||
|   public function getDescription() { return ''; } |  | ||||||
|   public function getSection() { return 'Default'; } |  | ||||||
|   public function getLastError() { return $this->lastError; } |   public function getLastError() { return $this->lastError; } | ||||||
|   public function getResult() { return $this->result; } |   public function getResult() { return $this->result; } | ||||||
|   public function success() { return $this->success; } |   public function success() { return $this->success; } | ||||||
|   public function loginRequired() { return $this->loginRequired; } |   public function loginRequired() { return $this->loginRequired; } | ||||||
|   public function isExternCall() { return $this->externCall; } |   public function isExternalCall() { return $this->externalCall; } | ||||||
|  | 
 | ||||||
|  |   private function getMethod() { | ||||||
|  |     $class = str_replace("\\", "/", get_class($this)); | ||||||
|  |     $class = substr($class, strlen("api/")); | ||||||
|  |     return $class; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   public function getJsonResult() { |   public function getJsonResult() { | ||||||
|     $this->result['success'] = $this->success; |     $this->result['success'] = $this->success; | ||||||
|     $this->result['msg'] = $this->lastError; |     $this->result['msg'] = $this->lastError; | ||||||
|     return json_encode($this->result); |     return json_encode($this->result); | ||||||
|   } |   } | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
							
								
								
									
										217
									
								
								core/Api/RoutesAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										217
									
								
								core/Api/RoutesAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,217 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  |   abstract class RoutesAPI extends Request { | ||||||
|  | 
 | ||||||
|  |     protected function formatRegex(string $input, bool $append) : string { | ||||||
|  |       $start = startsWith($input, "^"); | ||||||
|  |       $end = endsWith($input, "$"); | ||||||
|  |       if ($append) { | ||||||
|  |         if (!$start) $input = "^$input"; | ||||||
|  |         if (!$end) $input = "$input$"; | ||||||
|  |       } else { | ||||||
|  |         if ($start) $input = substr($input, 1); | ||||||
|  |         if ($end) $input = substr($input, 0, strlen($input)-1); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $input; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\Routes { | ||||||
|  | 
 | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use Api\Parameter\StringType; | ||||||
|  |   use Api\RoutesAPI; | ||||||
|  |   use Driver\SQL\Column\Column; | ||||||
|  |   use Driver\SQL\Condition\CondBool; | ||||||
|  |   use Driver\SQL\Condition\CondRegex; | ||||||
|  | 
 | ||||||
|  |   class Fetch extends RoutesAPI { | ||||||
|  | 
 | ||||||
|  |   public function __construct($user, $externalCall = false) { | ||||||
|  |     parent::__construct($user, $externalCall, array()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function execute($values = array()) { | ||||||
|  |     if(!parent::execute($values)) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     $sql = $this->user->getSQL(); | ||||||
|  | 
 | ||||||
|  |     $res = $sql | ||||||
|  |       ->select("uid", "request", "action", "target", "extra", "active") | ||||||
|  |       ->from("Route") | ||||||
|  |       ->orderBy("uid") | ||||||
|  |       ->ascending() | ||||||
|  |       ->execute(); | ||||||
|  | 
 | ||||||
|  |     $this->lastError = $sql->getLastError(); | ||||||
|  |     $this->success = ($res !== FALSE); | ||||||
|  | 
 | ||||||
|  |     if ($this->success) { | ||||||
|  |       $routes = array(); | ||||||
|  |       foreach($res as $row) { | ||||||
|  |         $routes[] = array( | ||||||
|  |           "uid"     => intval($row["uid"]), | ||||||
|  |           "request" => $this->formatRegex($row["request"], false), | ||||||
|  |           "action"  => $row["action"], | ||||||
|  |           "target"  => $row["target"], | ||||||
|  |           "extra"   => $row["extra"] ?? "", | ||||||
|  |           "active"  => intval($sql->parseBool($row["active"])), | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $this->result["routes"] = $routes; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return $this->success; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  |   class Find extends RoutesAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'request' => new StringType('request', 128, true, '/') | ||||||
|  |       )); | ||||||
|  | 
 | ||||||
|  |       $this->isPublic = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $request = $this->getParam('request'); | ||||||
|  |       if (!startsWith($request, '/')) { | ||||||
|  |         $request = "/$request"; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  | 
 | ||||||
|  |       $res = $sql | ||||||
|  |         ->select("uid", "request", "action", "target", "extra") | ||||||
|  |         ->from("Route") | ||||||
|  |         ->where(new CondBool("active")) | ||||||
|  |         ->where(new CondRegex($request, new Column("request"))) | ||||||
|  |         ->limit(1) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         if (!empty($res)) { | ||||||
|  |           $row = $res[0]; | ||||||
|  |           $this->result["route"] = array( | ||||||
|  |             "uid"     => intval($row["uid"]), | ||||||
|  |             "request" => $row["request"], | ||||||
|  |             "action"  => $row["action"], | ||||||
|  |             "target"  => $row["target"], | ||||||
|  |             "extra"   => $row["extra"] | ||||||
|  |           ); | ||||||
|  |         } else { | ||||||
|  |           $this->result["route"] = NULL; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Save extends RoutesAPI { | ||||||
|  | 
 | ||||||
|  |     private array $routes; | ||||||
|  | 
 | ||||||
|  |     public function __construct($user, $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'routes' => new Parameter('routes',Parameter::TYPE_ARRAY, false) | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if(!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!$this->validateRoutes()) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  | 
 | ||||||
|  |       // DELETE old rules
 | ||||||
|  |       $this->success = ($sql->truncate("Route")->execute() !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       // INSERT new routes
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $stmt = $sql->insert("Route", array("request", "action", "target", "extra", "active")); | ||||||
|  | 
 | ||||||
|  |         foreach($this->routes as $route) { | ||||||
|  |           $stmt->addRow($route["request"], $route["action"], $route["target"], $route["extra"], $route["active"]); | ||||||
|  |         } | ||||||
|  |         $this->success = ($stmt->execute() !== FALSE); | ||||||
|  |         $this->lastError = $sql->getLastError(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function validateRoutes() { | ||||||
|  | 
 | ||||||
|  |       $this->routes = array(); | ||||||
|  |       $keys = array( | ||||||
|  |         "request" => Parameter::TYPE_STRING, | ||||||
|  |         "action" => Parameter::TYPE_STRING, | ||||||
|  |         "target" => Parameter::TYPE_STRING, | ||||||
|  |         "extra"  => Parameter::TYPE_STRING, | ||||||
|  |         "active" => Parameter::TYPE_BOOLEAN | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |       $actions = array( | ||||||
|  |         "redirect_temporary", "redirect_permanently", "static", "dynamic" | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |       foreach($this->getParam("routes") as $index => $route) { | ||||||
|  |         foreach($keys as $key => $expectedType) { | ||||||
|  |           if (!array_key_exists($key, $route)) { | ||||||
|  |             return $this->createError("Route $index missing key: $key"); | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|  |           $value = $route[$key]; | ||||||
|  |           $type = Parameter::parseType($value); | ||||||
|  |           if ($type !== $expectedType) { | ||||||
|  |             $expectedTypeName = Parameter::names[$expectedType]; | ||||||
|  |             $gotTypeName = Parameter::names[$type]; | ||||||
|  |             return $this->createError("Route $index has invalid value for key: $key, expected: $expectedTypeName, got: $gotTypeName"); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $action = $route["action"]; | ||||||
|  |         if (!in_array($action, $actions)) { | ||||||
|  |           return $this->createError("Invalid action: $action"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(empty($route["request"])) { | ||||||
|  |           return $this->createError("Request cannot be empty."); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(empty($route["target"])) { | ||||||
|  |           return $this->createError("Target cannot be empty."); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // add start- and end pattern for database queries
 | ||||||
|  |         $route["request"] = $this->formatRegex($route["request"], true); | ||||||
|  |         $this->routes[] = $route; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @ -1,58 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api; |  | ||||||
| use Api\Parameter\Parameter; |  | ||||||
| use Api\Parameter\StringType; |  | ||||||
| 
 |  | ||||||
| class SendMail extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array( |  | ||||||
|       'from' => new Parameter('from', Parameter::TYPE_EMAIL), |  | ||||||
|       'to' => new Parameter('to', Parameter::TYPE_EMAIL), |  | ||||||
|       'subject'  => new StringType('subject', -1), |  | ||||||
|       'body' => new StringType('body', -1), |  | ||||||
|       'fromName' => new StringType('fromName', -1, true, ''), |  | ||||||
|       'replyTo' => new Parameter('to', Parameter::TYPE_EMAIL, true, ''), |  | ||||||
|     )); |  | ||||||
|     $this->isPublic = false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $mailConfig = $this->user->getConfiguration()->getMail(); |  | ||||||
|     $mail = new \External\PHPMailer\PHPMailer; |  | ||||||
|     $mail->IsSMTP(); |  | ||||||
|     $mail->setFrom($this->getParam('from'), $this->getParam('fromName')); |  | ||||||
|     $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'); |  | ||||||
| 
 |  | ||||||
|     $replyTo = $this->getParam('replyTo'); |  | ||||||
|     if(!is_null($replyTo) && !empty($replyTo)) { |  | ||||||
|       $mail->AddReplyTo($replyTo, $this->getParam('fromName')); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $this->success = @$mail->Send(); |  | ||||||
|     if (!$this->success) { |  | ||||||
|       $this->lastError = 'Error sending Mail: ' . $mail->ErrorInfo; |  | ||||||
|       error_log("sendMail() failed: " . $mail->ErrorInfo); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -1,83 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api; |  | ||||||
| 
 |  | ||||||
| use Api\Parameter\Parameter; |  | ||||||
| use Api\Parameter\StringType; |  | ||||||
| use Driver\SQL\Condition\CondOr; |  | ||||||
| use Driver\SQL\Condition\Compare; |  | ||||||
| 
 |  | ||||||
| class SetLanguage extends Request { |  | ||||||
| 
 |  | ||||||
|   private $language; |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array( |  | ||||||
|       'langId' => new Parameter('langId', Parameter::TYPE_INT, true, NULL), |  | ||||||
|       'langCode' => new StringType('langCode', 5, true, NULL), |  | ||||||
|     )); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function checkLanguage() { |  | ||||||
|     $langId = $this->getParam("langId"); |  | ||||||
|     $langCode = $this->getParam("langCode"); |  | ||||||
| 
 |  | ||||||
|     if(is_null($langId) && is_null($langCode)) { |  | ||||||
|       return $this->createError(L("Either langId or langCode must be given")); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $res = $this->user->getSQL() |  | ||||||
|       ->select("uid", "code", "name") |  | ||||||
|       ->from("Language") |  | ||||||
|       ->where(new CondOr(new Compare("uid", $langId), new Compare("code", $langCode))) |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $this->user->getSQL()->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if ($this->success) { |  | ||||||
|       if(count($res) == 0) { |  | ||||||
|         return $this->createError(L("This Language does not exist")); |  | ||||||
|       } else { |  | ||||||
|         $row = $res[0]; |  | ||||||
|         $this->language = \Objects\Language::newInstance($row['uid'], $row['code'], $row['name']); |  | ||||||
|         if(!$this->language) { |  | ||||||
|           return $this->createError(L("Error while loading language")); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function updateLanguage() { |  | ||||||
|     $languageId = $this->language->getId(); |  | ||||||
|     $userId = $this->user->getId(); |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
| 
 |  | ||||||
|     $this->success = $sql->update("User") |  | ||||||
|       ->set("language_id", $languageId) |  | ||||||
|       ->where(new Compare("uid", $userId)) |  | ||||||
|       ->execute(); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(!$this->checkLanguage()) |  | ||||||
|       return false; |  | ||||||
| 
 |  | ||||||
|     if($this->user->isLoggedIn()) { |  | ||||||
|       $this->updateLanguage(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $this->user->setLangauge($this->language); |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
							
								
								
									
										169
									
								
								core/Api/SettingsAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										169
									
								
								core/Api/SettingsAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,169 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  | 
 | ||||||
|  |   abstract class SettingsAPI extends Request { | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\Settings { | ||||||
|  | 
 | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use Api\Parameter\StringType; | ||||||
|  |   use Api\SettingsAPI; | ||||||
|  |   use Driver\SQL\Column\Column; | ||||||
|  |   use Driver\SQL\Condition\CondBool; | ||||||
|  |   use Driver\SQL\Condition\CondIn; | ||||||
|  |   use Driver\SQL\Condition\CondNot; | ||||||
|  |   use Driver\SQL\Condition\CondRegex; | ||||||
|  |   use Driver\SQL\Strategy\UpdateStrategy; | ||||||
|  |   use Objects\User; | ||||||
|  | 
 | ||||||
|  |   class Get extends SettingsAPI { | ||||||
|  | 
 | ||||||
|  |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'key' => new StringType('key', -1, true, NULL) | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |        if(!parent::execute($values)) { | ||||||
|  |          return false; | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |        $key = $this->getParam("key"); | ||||||
|  |        $sql = $this->user->getSQL(); | ||||||
|  | 
 | ||||||
|  |        $query = $sql->select("name", "value") ->from("Settings"); | ||||||
|  | 
 | ||||||
|  |        if (!is_null($key) && !empty($key)) { | ||||||
|  |          $query->where(new CondRegex(new Column("name"), $key)); | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |        // filter sensitive values, if called from outside
 | ||||||
|  |        if ($this->isExternalCall()) { | ||||||
|  |          $query->where(new CondNot("private")); | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |        $res = $query->execute(); | ||||||
|  | 
 | ||||||
|  |        $this->success = ($res !== FALSE); | ||||||
|  |        $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |        if ($this->success) { | ||||||
|  |          $settings = array(); | ||||||
|  |          foreach($res as $row) { | ||||||
|  |            $settings[$row["name"]] = $row["value"]; | ||||||
|  |          } | ||||||
|  |          $this->result["settings"] = $settings; | ||||||
|  |        } | ||||||
|  | 
 | ||||||
|  |        return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class Set extends SettingsAPI { | ||||||
|  |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'settings' => new Parameter('settings', Parameter::TYPE_ARRAY) | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $values = $this->getParam("settings"); | ||||||
|  |       if (empty($values)) { | ||||||
|  |         return $this->createError("No values given."); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $paramKey = new StringType('key', 32); | ||||||
|  |       $paramValue = new StringType('value', 1024, true, NULL); | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $query = $sql->insert("Settings", array("name", "value")); | ||||||
|  |       $keys = array(); | ||||||
|  |       $deleteKeys = array(); | ||||||
|  | 
 | ||||||
|  |       foreach($values as $key => $value) { | ||||||
|  |         if (!$paramKey->parseParam($key)) { | ||||||
|  |           $key = print_r($key, true); | ||||||
|  |           return $this->createError("Invalid Type for key in parameter settings: '$key' (Required: " . $paramKey->getTypeName() . ")"); | ||||||
|  |         } else if(!is_null($value) && !$paramValue->parseParam($value)) { | ||||||
|  |           $value = print_r($value, true); | ||||||
|  |           return $this->createError("Invalid Type for value in parameter settings: '$value' (Required: " . $paramValue->getTypeName() . ")"); | ||||||
|  |         } else if(preg_match("/^[a-zA-Z_][a-zA-Z_0-9-]*$/", $paramKey->value) !== 1) { | ||||||
|  |           return $this->createError("The property key should only contain alphanumeric characters, underscores and dashes"); | ||||||
|  |         } else { | ||||||
|  |           if (!is_null($paramValue->value)) { | ||||||
|  |             $query->addRow($paramKey->value, $paramValue->value); | ||||||
|  |           } else { | ||||||
|  |             $deleteKeys[] = $paramKey->value; | ||||||
|  |           } | ||||||
|  |           $keys[] = $paramKey->value; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if ($this->isExternalCall()) { | ||||||
|  |         $column = $this->checkReadonly($keys); | ||||||
|  |         if(!$this->success) { | ||||||
|  |           return false; | ||||||
|  |         } else if($column !== null) { | ||||||
|  |           return $this->createError("Column '$column' is readonly."); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!empty($deleteKeys) && !$this->deleteKeys($keys)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (count($deleteKeys) !== count($keys)) { | ||||||
|  |         $query->onDuplicateKeyStrategy(new UpdateStrategy( | ||||||
|  |           array("name"), | ||||||
|  |           array("value" => new Column("value"))) | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         $this->success = ($query->execute() !== FALSE); | ||||||
|  |         $this->lastError = $sql->getLastError(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function checkReadonly(array $keys) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->select("name") | ||||||
|  |         ->from("Settings") | ||||||
|  |         ->where(new CondBool("readonly")) | ||||||
|  |         ->where(new CondIn("name", $keys)) | ||||||
|  |         ->limit(1) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success && !empty($res)) { | ||||||
|  |         return $res[0]["name"]; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function deleteKeys(array $keys) { | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $res = $sql->delete("Settings") | ||||||
|  |         ->where(new CondIn("name", $keys)) | ||||||
|  |         ->execute(); | ||||||
|  | 
 | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										90
									
								
								core/Api/Stats.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										90
									
								
								core/Api/Stats.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api; | ||||||
|  | 
 | ||||||
|  | use Driver\SQL\Condition\CondBool; | ||||||
|  | 
 | ||||||
|  | class Stats extends Request { | ||||||
|  | 
 | ||||||
|  |   private bool $mailConfigured; | ||||||
|  |   private bool $recaptchaConfigured; | ||||||
|  | 
 | ||||||
|  |   public function __construct($user, $externalCall = false) { | ||||||
|  |     parent::__construct($user, $externalCall, array()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private function getUserCount() { | ||||||
|  |     $sql = $this->user->getSQL(); | ||||||
|  |     $res = $sql->select($sql->count())->from("User")->execute(); | ||||||
|  |     $this->success = $this->success && ($res !== FALSE); | ||||||
|  |     $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |     return ($this->success ? $res[0]["count"] : 0); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private function getPageCount() { | ||||||
|  |     $sql = $this->user->getSQL(); | ||||||
|  |     $res = $sql->select($sql->count())->from("Route") | ||||||
|  |       ->where(new CondBool("active")) | ||||||
|  |       ->execute(); | ||||||
|  |     $this->success = $this->success && ($res !== FALSE); | ||||||
|  |     $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |     return ($this->success ? $res[0]["count"] : 0); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private function checkSettings() { | ||||||
|  |     $req = new \Api\Settings\Get($this->user); | ||||||
|  |     $this->success = $req->execute(array("key" => "^(mail_enabled|recaptcha_enabled)$")); | ||||||
|  |     $this->lastError = $req->getLastError(); | ||||||
|  | 
 | ||||||
|  |     if ($this->success) { | ||||||
|  |       $settings = $req->getResult()["settings"]; | ||||||
|  |       $this->mailConfigured = ($settings["mail_enabled"] ?? "0") === "1"; | ||||||
|  |       $this->recaptchaConfigured = ($settings["recaptcha_enabled"] ?? "0") === "1"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return $this->success; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function execute($values = array()) { | ||||||
|  |     if(!parent::execute($values)) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     $userCount = $this->getUserCount(); | ||||||
|  |     $pageCount = $this->getPageCount(); | ||||||
|  |     $req = new \Api\Visitors\Stats($this->user); | ||||||
|  |     $this->success = $req->execute(array("type"=>"monthly")); | ||||||
|  |     $this->lastError = $req->getLastError(); | ||||||
|  |     if (!$this->success) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     $visitorStatistics = $req->getResult()["visitors"]; | ||||||
|  |     $loadAvg = "Unknown"; | ||||||
|  |     if (function_exists("sys_getloadavg")) { | ||||||
|  |       $loadAvg = sys_getloadavg(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!$this->checkSettings()) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     $this->result["userCount"] = $userCount; | ||||||
|  |     $this->result["pageCount"] = $pageCount; | ||||||
|  |     $this->result["visitors"] = $visitorStatistics; | ||||||
|  |     $this->result["server"] = array( | ||||||
|  |       "version" => WEBBASE_VERSION, | ||||||
|  |       "server" => $_SERVER["SERVER_SOFTWARE"] ?? "Unknown", | ||||||
|  |       "memory_usage" => memory_get_usage(), | ||||||
|  |       "load_avg" => $loadAvg, | ||||||
|  |       "database" => $this->user->getSQL()->getStatus(), | ||||||
|  |       "mail" => $this->mailConfigured, | ||||||
|  |       "reCaptcha" => $this->recaptchaConfigured | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     return $this->success; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -1,82 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api\User; |  | ||||||
| 
 |  | ||||||
| use \Api\Request; |  | ||||||
| use \Api\Parameter\Parameter; |  | ||||||
| use \Api\Parameter\StringType; |  | ||||||
| use \Driver\SQL\Condition\Compare; |  | ||||||
| 
 |  | ||||||
| class Login extends Request { |  | ||||||
| 
 |  | ||||||
|   private $startedAt; |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall, array( |  | ||||||
|       'username' => new StringType('username', 32), |  | ||||||
|       'password' => new StringType('password'), |  | ||||||
|       'stayLoggedIn' => new Parameter('stayLoggedIn', Parameter::TYPE_BOOLEAN, true, true) |  | ||||||
|     )); |  | ||||||
|     $this->forbidMethod("GET"); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private function wrongCredentials() { |  | ||||||
|     $runtime = microtime(true) - $this->startedAt; |  | ||||||
|     $sleepTime = round(3e6 - $runtime); |  | ||||||
|     if($sleepTime > 0) usleep($sleepTime); |  | ||||||
|     return $this->createError(L('Wrong username or password')); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if($this->user->isLoggedIn()) { |  | ||||||
|       $this->lastError = L('You are already logged in'); |  | ||||||
|       $this->success = true; |  | ||||||
|       return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $this->startedAt = microtime(true); |  | ||||||
|     $this->success = false; |  | ||||||
|     $username = $this->getParam('username'); |  | ||||||
|     $password = $this->getParam('password'); |  | ||||||
|     $stayLoggedIn = $this->getParam('stayLoggedIn'); |  | ||||||
| 
 |  | ||||||
|     $sql = $this->user->getSQL(); |  | ||||||
|     $res = $sql->select("User.uid", "User.password", "User.salt") |  | ||||||
|       ->from("User") |  | ||||||
|       ->where(new Compare("User.name", $username)) |  | ||||||
|       ->execute(); |  | ||||||
| 
 |  | ||||||
|     $this->success = ($res !== FALSE); |  | ||||||
|     $this->lastError = $sql->getLastError(); |  | ||||||
| 
 |  | ||||||
|     if($this->success) { |  | ||||||
|       if(count($res) === 0) { |  | ||||||
|         return $this->wrongCredentials(); |  | ||||||
|       } else { |  | ||||||
|         $row = $res[0]; |  | ||||||
|         $salt = $row['salt']; |  | ||||||
|         $uid = $row['uid']; |  | ||||||
|         $hash = hash('sha256', $password . $salt); |  | ||||||
|         if($hash === $row['password']) { |  | ||||||
|           if(!($this->success = $this->user->createSession($uid, $stayLoggedIn))) { |  | ||||||
|             return $this->createError("Error creating Session: " . $sql->getLastError()); |  | ||||||
|           } else { |  | ||||||
|             $this->result['logoutIn'] = $this->user->getSession()->getExpiresSeconds(); |  | ||||||
|             $this->success = true; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|           return $this->wrongCredentials(); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Api\User; |  | ||||||
| 
 |  | ||||||
| use \Api\Request; |  | ||||||
| 
 |  | ||||||
| class Logout extends Request { |  | ||||||
| 
 |  | ||||||
|   public function __construct($user, $externCall = false) { |  | ||||||
|     parent::__construct($user, $externCall); |  | ||||||
|     $this->loginRequired = true; |  | ||||||
|     $this->apiKeyAllowed = false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function execute($values = array()) { |  | ||||||
|     if(!parent::execute($values)) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $this->success = $this->user->logout(); |  | ||||||
|     $this->lastError = $this->user->getSQL()->getLastError(); |  | ||||||
|     return $this->success; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
							
								
								
									
										1140
									
								
								core/Api/UserAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1140
									
								
								core/Api/UserAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										67
									
								
								core/Api/VerifyCaptcha.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										67
									
								
								core/Api/VerifyCaptcha.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api; | ||||||
|  | 
 | ||||||
|  | use Api\Parameter\StringType; | ||||||
|  | use Objects\User; | ||||||
|  | 
 | ||||||
|  | class VerifyCaptcha extends Request { | ||||||
|  | 
 | ||||||
|  |   public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |     parent::__construct($user, $externalCall, array( | ||||||
|  |       "captcha" => new StringType("captcha"), | ||||||
|  |       "action" => new StringType("action"), | ||||||
|  |     )); | ||||||
|  | 
 | ||||||
|  |     $this->isPublic = false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function execute($values = array()) { | ||||||
|  |      if(!parent::execute($values)) { | ||||||
|  |        return false; | ||||||
|  |      } | ||||||
|  | 
 | ||||||
|  |      $settings = $this->user->getConfiguration()->getSettings(); | ||||||
|  |      if (!$settings->isRecaptchaEnabled()) { | ||||||
|  |        return $this->createError("Google reCaptcha is not enabled."); | ||||||
|  |      } | ||||||
|  | 
 | ||||||
|  |     $url = "https://www.google.com/recaptcha/api/siteverify"; | ||||||
|  |     $secret = $settings->getRecaptchaSecretKey(); | ||||||
|  |     $captcha = $this->getParam("captcha"); | ||||||
|  |     $action = $this->getParam("action"); | ||||||
|  | 
 | ||||||
|  |     $params = array( | ||||||
|  |       "secret" => $secret, | ||||||
|  |       "response" => $captcha | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     $ch = curl_init(); | ||||||
|  |     curl_setopt($ch, CURLOPT_URL,$url); | ||||||
|  |     curl_setopt($ch, CURLOPT_POST, 1); | ||||||
|  |     curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params)); | ||||||
|  |     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||||||
|  |     $response = @json_decode(curl_exec($ch), true); | ||||||
|  |     curl_close ($ch); | ||||||
|  | 
 | ||||||
|  |     $this->success = false; | ||||||
|  |     $this->lastError = "Could not verify captcha: No response from google received."; | ||||||
|  | 
 | ||||||
|  |     if($response) { | ||||||
|  |       $this->success = $response["success"]; | ||||||
|  |       if(!$this->success) { | ||||||
|  |         $this->lastError = "Could not verify captcha: " . implode(";", $response["error-codes"]); | ||||||
|  |       } else { | ||||||
|  |         $score = $response["score"]; | ||||||
|  |         if($action !== $response["action"]) { | ||||||
|  |           $this->createError("Could not verify captcha: Action does not match"); | ||||||
|  |         } | ||||||
|  |         else if($score < 0.7) { | ||||||
|  |           $this->createError("Could not verify captcha: Google ReCaptcha Score < 0.7 (Your score: $score), you are likely a bot"); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return $this->success; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								core/Api/VisitorsAPI.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										88
									
								
								core/Api/VisitorsAPI.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Api { | ||||||
|  | 
 | ||||||
|  |   abstract class VisitorsAPI extends Request { | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Api\Visitors { | ||||||
|  | 
 | ||||||
|  |   use Api\Parameter\Parameter; | ||||||
|  |   use Api\Parameter\StringType; | ||||||
|  |   use Api\VisitorsAPI; | ||||||
|  |   use DateTime; | ||||||
|  |   use Driver\SQL\Condition\Compare; | ||||||
|  |   use Driver\SQL\Query\Select; | ||||||
|  |   use Objects\User; | ||||||
|  | 
 | ||||||
|  |   class Stats extends VisitorsAPI { | ||||||
|  |     public function __construct(User $user, bool $externalCall = false) { | ||||||
|  |       parent::__construct($user, $externalCall, array( | ||||||
|  |         'type' => new StringType('type', 32), | ||||||
|  |         'date' => new Parameter('date', Parameter::TYPE_DATE, true, new DateTime()) | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function setConditions(string $type, DateTime $date, Select $query) { | ||||||
|  |       if ($type === "yearly") { | ||||||
|  |         $yearStart = $date->format("Y0000"); | ||||||
|  |         $yearEnd = $date->modify("+1 year")->format("Y0000"); | ||||||
|  |         $query->where(new Compare("day", $yearStart, ">=")); | ||||||
|  |         $query->where(new Compare("day", $yearEnd, "<")); | ||||||
|  |       } else if($type === "monthly") { | ||||||
|  |         $monthStart = $date->format("Ym00"); | ||||||
|  |         $monthEnd = $date->modify("+1 month")->format("Ym00"); | ||||||
|  |         $query->where(new Compare("day", $monthStart, ">=")); | ||||||
|  |         $query->where(new Compare("day", $monthEnd, "<")); | ||||||
|  |       } else if($type === "weekly") { | ||||||
|  |         $weekStart = ($date->modify("monday this week"))->format("Ymd"); | ||||||
|  |         $weekEnd = ($date->modify("sunday this week"))->format("Ymd"); | ||||||
|  |         $query->where(new Compare("day", $weekStart, ">=")); | ||||||
|  |         $query->where(new Compare("day", $weekEnd, "<=")); | ||||||
|  |       } else { | ||||||
|  |         $this->createError("Invalid scope: $type"); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute($values = array()) { | ||||||
|  |       if (!parent::execute($values)) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $date = $this->getParam("date"); | ||||||
|  |       $type = $this->getParam("type"); | ||||||
|  | 
 | ||||||
|  |       $sql = $this->user->getSQL(); | ||||||
|  |       $query = $sql->select($sql->count(), "day") | ||||||
|  |         ->from("Visitor") | ||||||
|  |         ->where(new Compare("count", 1, ">")) | ||||||
|  |         ->groupBy("day") | ||||||
|  |         ->orderBy("day") | ||||||
|  |         ->ascending(); | ||||||
|  | 
 | ||||||
|  |       $this->setConditions($type, $date, $query); | ||||||
|  |       if (!$this->success) { | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $res = $query->execute(); | ||||||
|  |       $this->success = ($res !== FALSE); | ||||||
|  |       $this->lastError = $sql->getLastError(); | ||||||
|  | 
 | ||||||
|  |       if ($this->success) { | ||||||
|  |         $this->result["type"] = $type; | ||||||
|  |         $this->result["visitors"] = array(); | ||||||
|  | 
 | ||||||
|  |         foreach($res as $row) { | ||||||
|  |           $day = DateTime::createFromFormat("Ymd", $row["day"])->format("Y/m/d"); | ||||||
|  |           $count = $row["count"]; | ||||||
|  |           $this->result["visitors"][$day] = $count; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->success; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								core/Configuration/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								core/Configuration/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1 @@ | |||||||
| Mail\.class\.php |  | ||||||
| JWT\.class\.php |  | ||||||
| Database\.class\.php | Database\.class\.php | ||||||
|  | |||||||
| @ -2,53 +2,36 @@ | |||||||
| 
 | 
 | ||||||
| namespace Configuration; | namespace Configuration; | ||||||
| 
 | 
 | ||||||
|  | use Objects\ConnectionData; | ||||||
|  | 
 | ||||||
| class Configuration { | class Configuration { | ||||||
| 
 | 
 | ||||||
|   private $database; |   private ?ConnectionData $database; | ||||||
|   private $mail; |   private Settings $settings; | ||||||
|   private $jwt; |  | ||||||
| 
 | 
 | ||||||
|   function __construct() { |   function __construct() { | ||||||
|   } |     $this->database = null; | ||||||
|  |     $this->settings = Settings::loadDefaults(); | ||||||
| 
 | 
 | ||||||
|   public function load() { |     $class = \Configuration\Database::class; | ||||||
|     try { |     $path = getClassPath($class, true); | ||||||
| 
 |     if(file_exists($path) && is_readable($path)) { | ||||||
|       $classes = array( |  | ||||||
|         \Configuration\Database::class => &$this->database, |  | ||||||
|         \Configuration\Mail::class => &$this->mail, |  | ||||||
|         \Configuration\JWT::class => &$this->jwt |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       $success = true; |  | ||||||
|       foreach($classes as $class => &$ref) { |  | ||||||
|         $path = getClassPath($class); |  | ||||||
|         if(!file_exists($path)) { |  | ||||||
|           $success = false; |  | ||||||
|         } else { |  | ||||||
|       include_once $path; |       include_once $path; | ||||||
|       if(class_exists($class)) { |       if(class_exists($class)) { | ||||||
|             $ref = new $class(); |         $this->database = new \Configuration\Database(); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|       return $success; |   public function getDatabase() : ?ConnectionData { | ||||||
|     } catch(\Error $e) { |     return $this->database; | ||||||
|       die($e); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getDatabase() { return $this->database; } |   public function getSettings() : Settings { | ||||||
|   public function getJWT() { return $this->jwt; } |     return $this->settings; | ||||||
|   public function getMail() { return $this->mail; } |  | ||||||
| 
 |  | ||||||
|   public function isFilePresent($className) { |  | ||||||
|     $path = getClassPath("\\Configuration\\$className"); |  | ||||||
|     return file_exists($path); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function create($className, $data) { |   public function create(string $className, $data) { | ||||||
|     $path = getClassPath("\\Configuration\\$className"); |     $path = getClassPath("\\Configuration\\$className"); | ||||||
| 
 | 
 | ||||||
|     if($data) { |     if($data) { | ||||||
| @ -59,22 +42,15 @@ class Configuration { | |||||||
| 
 | 
 | ||||||
|           namespace Configuration; |           namespace Configuration; | ||||||
| 
 | 
 | ||||||
|           class $className { |           class $className extends KeyData { | ||||||
| 
 |  | ||||||
|             private \$key; |  | ||||||
|            |            | ||||||
|             public function __construct() { |             public function __construct() { | ||||||
|               \$this->key = '$key'; |               parent::__construct('$key'); | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             public function getKey() { |           }", false
 | ||||||
|               return \$this->key; |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
| 
 |  | ||||||
|           ?>", false
 |  | ||||||
|         ); |         ); | ||||||
|       } else { |       } else if($data instanceof ConnectionData) { | ||||||
|         $superClass = get_class($data); |         $superClass = get_class($data); | ||||||
|         $host = addslashes($data->getHost()); |         $host = addslashes($data->getHost()); | ||||||
|         $port = intval($data->getPort()); |         $port = intval($data->getPort()); | ||||||
| @ -98,22 +74,19 @@ class Configuration { | |||||||
|             public function __construct() { |             public function __construct() { | ||||||
|               parent::__construct('$host', $port, '$login', '$password');$properties |               parent::__construct('$host', $port, '$login', '$password');$properties | ||||||
|             } |             } | ||||||
|           } |           }", false
 | ||||||
| 
 |  | ||||||
|           ?>", false
 |  | ||||||
|         ); |         ); | ||||||
|  |       } else { | ||||||
|  |         return false; | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       $code = intendCode( |       $code = "<?php"; | ||||||
|         "<?php
 |  | ||||||
| 
 |  | ||||||
|         ?>", false);
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return @file_put_contents($path, $code); |     return @file_put_contents($path, $code); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function delete($className) { |   public function delete(string $className) { | ||||||
|     $path = getClassPath("\\Configuration\\$className"); |     $path = getClassPath("\\Configuration\\$className"); | ||||||
|     if(file_exists($path)) { |     if(file_exists($path)) { | ||||||
|       return unlink($path); |       return unlink($path); | ||||||
| @ -121,6 +94,4 @@ class Configuration { | |||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -2,16 +2,16 @@ | |||||||
| 
 | 
 | ||||||
| namespace Configuration; | namespace Configuration; | ||||||
| 
 | 
 | ||||||
| use \Driver\SQL\Query\CreateTable; | use Driver\SQL\SQL; | ||||||
| use \Driver\SQL\Query\Insert; |  | ||||||
| use \Driver\SQL\Column\Column; |  | ||||||
| use \Driver\SQL\Strategy\UpdateStrategy; |  | ||||||
| use \Driver\SQL\Strategy\SetNullStrategy; | use \Driver\SQL\Strategy\SetNullStrategy; | ||||||
| use \Driver\SQL\Strategy\CascadeStrategy; | use \Driver\SQL\Strategy\CascadeStrategy; | ||||||
| 
 | 
 | ||||||
| class CreateDatabase { | class CreateDatabase { | ||||||
| 
 | 
 | ||||||
|   public static function createQueries($sql) { |   // NOTE:
 | ||||||
|  |   // explicit serial ids removed due to postgres' serial implementation
 | ||||||
|  | 
 | ||||||
|  |   public static function createQueries(SQL $sql) { | ||||||
|     $queries = array(); |     $queries = array(); | ||||||
| 
 | 
 | ||||||
|     // Language
 |     // Language
 | ||||||
| @ -23,17 +23,18 @@ class CreateDatabase { | |||||||
|       ->unique("code") |       ->unique("code") | ||||||
|       ->unique("name"); |       ->unique("name"); | ||||||
| 
 | 
 | ||||||
|     $queries[] = $sql->insert("Language", array("uid", "code", "name")) |     $queries[] = $sql->insert("Language", array("code", "name")) | ||||||
|       ->addRow(1, "en_US", 'American English') |       ->addRow( "en_US", 'American English') | ||||||
|       ->addRow(2, "de_DE", 'Deutsch Standard'); |       ->addRow( "de_DE", 'Deutsch Standard'); | ||||||
| 
 | 
 | ||||||
|     $queries[] = $sql->createTable("User") |     $queries[] = $sql->createTable("User") | ||||||
|       ->addSerial("uid") |       ->addSerial("uid") | ||||||
|       ->addString("email", 64, true) |       ->addString("email", 64, true) | ||||||
|       ->addString("name", 32) |       ->addString("name", 32) | ||||||
|       ->addString("salt", 16) |       ->addString("password", 128) | ||||||
|       ->addString("password", 64) |       ->addBool("confirmed", false) | ||||||
|       ->addInt("language_id", true, 1) |       ->addInt("language_id", true, 1) | ||||||
|  |       ->addDateTime("registered_at", false, $sql->currentTimestamp()) | ||||||
|       ->primaryKey("uid") |       ->primaryKey("uid") | ||||||
|       ->unique("email") |       ->unique("email") | ||||||
|       ->unique("name") |       ->unique("name") | ||||||
| @ -49,35 +50,39 @@ class CreateDatabase { | |||||||
|       ->addString("browser", 64) |       ->addString("browser", 64) | ||||||
|       ->addJson("data", false, '{}') |       ->addJson("data", false, '{}') | ||||||
|       ->addBool("stay_logged_in", true) |       ->addBool("stay_logged_in", true) | ||||||
|  |       ->addString("csrf_token", 16 ) | ||||||
|       ->primaryKey("uid", "user_id") |       ->primaryKey("uid", "user_id") | ||||||
|       ->foreignKey("user_id", "User", "uid", new CascadeStrategy()); |       ->foreignKey("user_id", "User", "uid", new CascadeStrategy()); | ||||||
| 
 | 
 | ||||||
|     $queries[] = $sql->createTable("UserToken") |     $queries[] = $sql->createTable("UserToken") | ||||||
|       ->addInt("user_id") |       ->addInt("user_id") | ||||||
|       ->addString("token", 36) |       ->addString("token", 36) | ||||||
|       ->addEnum("token_type", array("password_reset", "confirmation")) |       ->addEnum("token_type", array("password_reset", "email_confirm", "invite")) | ||||||
|       ->addDateTime("valid_until") |       ->addDateTime("valid_until") | ||||||
|  |       ->addBool("used", false) | ||||||
|       ->foreignKey("user_id", "User", "uid", new CascadeStrategy()); |       ->foreignKey("user_id", "User", "uid", new CascadeStrategy()); | ||||||
| 
 |  | ||||||
|     $queries[] = $sql->createTable("Group") |     $queries[] = $sql->createTable("Group") | ||||||
|       ->addSerial("uid") |       ->addSerial("uid") | ||||||
|       ->addString("name", 32) |       ->addString("name", 32) | ||||||
|  |       ->addString("color", 10) | ||||||
|       ->primaryKey("uid") |       ->primaryKey("uid") | ||||||
|       ->unique("name"); |       ->unique("name"); | ||||||
| 
 | 
 | ||||||
|     $queries[] = $sql->insert("Group", array("uid", "name")) |     $queries[] = $sql->insert("Group", array("name", "color")) | ||||||
|       ->addRow(USER_GROUP_DEFAULT, "Default") |       ->addRow(USER_GROUP_MODERATOR_NAME, "#007bff") | ||||||
|       ->addRow(USER_GROUP_ADMIN, "Administrator"); |       ->addRow(USER_GROUP_SUPPORT_NAME, "#28a745") | ||||||
|  |       ->addRow(USER_GROUP_ADMIN_NAME, "#dc3545"); | ||||||
| 
 | 
 | ||||||
|     $queries[] = $sql->createTable("UserGroup") |     $queries[] = $sql->createTable("UserGroup") | ||||||
|       ->addInt("user_id") |       ->addInt("user_id") | ||||||
|       ->addInt("group_id") |       ->addInt("group_id") | ||||||
|       ->unique("user_id", "group_id") |       ->unique("user_id", "group_id") | ||||||
|       ->foreignKey("user_id", "User", "uid") |       ->foreignKey("user_id", "User", "uid", new CascadeStrategy()) | ||||||
|       ->foreignKey("group_id", "Group", "uid"); |       ->foreignKey("group_id", "Group", "uid", new CascadeStrategy()); | ||||||
| 
 | 
 | ||||||
|     $queries[] = $sql->createTable("Notification") |     $queries[] = $sql->createTable("Notification") | ||||||
|       ->addSerial("uid") |       ->addSerial("uid") | ||||||
|  |       ->addEnum("type", array("default","message","warning"), false, "default") | ||||||
|       ->addDateTime("created_at", false, $sql->currentTimestamp()) |       ->addDateTime("created_at", false, $sql->currentTimestamp()) | ||||||
|       ->addString("title", 32) |       ->addString("title", 32) | ||||||
|       ->addString("message", 256) |       ->addString("message", 256) | ||||||
| @ -86,7 +91,7 @@ class CreateDatabase { | |||||||
|     $queries[] = $sql->createTable("UserNotification") |     $queries[] = $sql->createTable("UserNotification") | ||||||
|       ->addInt("user_id") |       ->addInt("user_id") | ||||||
|       ->addInt("notification_id") |       ->addInt("notification_id") | ||||||
|       ->addBool("seen") |       ->addBool("seen", false) | ||||||
|       ->foreignKey("user_id", "User", "uid") |       ->foreignKey("user_id", "User", "uid") | ||||||
|       ->foreignKey("notification_id", "Notification", "uid") |       ->foreignKey("notification_id", "Notification", "uid") | ||||||
|       ->unique("user_id", "notification_id"); |       ->unique("user_id", "notification_id"); | ||||||
| @ -94,7 +99,7 @@ class CreateDatabase { | |||||||
|     $queries[] = $sql->createTable("GroupNotification") |     $queries[] = $sql->createTable("GroupNotification") | ||||||
|       ->addInt("group_id") |       ->addInt("group_id") | ||||||
|       ->addInt("notification_id") |       ->addInt("notification_id") | ||||||
|       ->addBool("seen") |       ->addBool("seen", false) | ||||||
|       ->foreignKey("group_id", "Group", "uid") |       ->foreignKey("group_id", "Group", "uid") | ||||||
|       ->foreignKey("notification_id", "Notification", "uid") |       ->foreignKey("notification_id", "Notification", "uid") | ||||||
|       ->unique("group_id", "notification_id"); |       ->unique("group_id", "notification_id"); | ||||||
| @ -108,8 +113,116 @@ class CreateDatabase { | |||||||
|       ->primaryKey("uid") |       ->primaryKey("uid") | ||||||
|       ->foreignKey("user_id", "User", "uid"); |       ->foreignKey("user_id", "User", "uid"); | ||||||
| 
 | 
 | ||||||
|  |     $queries[] = $sql->createTable("Visitor") | ||||||
|  |       ->addInt("day") | ||||||
|  |       ->addInt("count", false, 1) | ||||||
|  |       ->addString("cookie", 26) | ||||||
|  |       ->unique("day", "cookie"); | ||||||
|  | 
 | ||||||
|  |     $queries[] = $sql->createTable("Route") | ||||||
|  |       ->addSerial("uid") | ||||||
|  |       ->addString("request", 128) | ||||||
|  |       ->addEnum("action", array("redirect_temporary", "redirect_permanently", "static", "dynamic")) | ||||||
|  |       ->addString("target", 128) | ||||||
|  |       ->addString("extra", 64, true) | ||||||
|  |       ->addBool("active", true) | ||||||
|  |       ->primaryKey("uid"); | ||||||
|  | 
 | ||||||
|  |     $queries[] = $sql->insert("Route", array("request", "action", "target", "extra")) | ||||||
|  |       ->addRow("^/admin(/.*)?$", "dynamic", "\\Documents\\Admin", NULL) | ||||||
|  |       ->addRow("^/register(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\Register") | ||||||
|  |       ->addRow("^/confirmEmail(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\ConfirmEmail") | ||||||
|  |       ->addRow("^/acceptInvite(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\AcceptInvite") | ||||||
|  |       ->addRow("^/resetPassword(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\ResetPassword") | ||||||
|  |       ->addRow("^/$", "static", "/static/welcome.html", NULL); | ||||||
|  | 
 | ||||||
|  |     $queries[] = $sql->createTable("Settings") | ||||||
|  |       ->addString("name", 32) | ||||||
|  |       ->addString("value", 1024, true) | ||||||
|  |       ->addBool("private", false) // these values are not returned from '/api/settings/get', but can be changed
 | ||||||
|  |       ->addBool("readonly", false) // these values are neither returned, nor can be changed from outside
 | ||||||
|  |       ->primaryKey("name"); | ||||||
|  | 
 | ||||||
|  |     $settingsQuery = $sql->insert("Settings", array("name", "value", "private", "readonly")) | ||||||
|  |       // ->addRow("mail_enabled", "0") # this key will be set during installation
 | ||||||
|  |       ->addRow("mail_host", "", false, false) | ||||||
|  |       ->addRow("mail_port", "", false, false) | ||||||
|  |       ->addRow("mail_username", "", false, false) | ||||||
|  |       ->addRow("mail_password", "", true, false) | ||||||
|  |       ->addRow("mail_from", "", false, false) | ||||||
|  |       ->addRow("message_confirm_email", self::MessageConfirmEmail(), false, false) | ||||||
|  |       ->addRow("message_accept_invite", self::MessageAcceptInvite(), false, false) | ||||||
|  |       ->addRow("message_reset_password", self::MessageResetPassword(), false, false); | ||||||
|  | 
 | ||||||
|  |     (Settings::loadDefaults())->addRows($settingsQuery); | ||||||
|  |     $queries[] = $settingsQuery; | ||||||
|  | 
 | ||||||
|  |     $queries[] = $sql->createTable("ContactRequest") | ||||||
|  |       ->addSerial("uid") | ||||||
|  |       ->addString("from_name", 32) | ||||||
|  |       ->addString("from_email", 64) | ||||||
|  |       ->addString("message", 512) | ||||||
|  |       ->addDateTime("created_at", false, $sql->currentTimestamp()) | ||||||
|  |       ->primaryKey("uid"); | ||||||
|  | 
 | ||||||
|  |     $queries[] = $sql->createTable("ApiPermission") | ||||||
|  |       ->addString("method", 32) | ||||||
|  |       ->addJson("groups", true, '[]') | ||||||
|  |       ->addString("description", 128, false, "") | ||||||
|  |       ->primaryKey("method"); | ||||||
|  | 
 | ||||||
|  |     $queries[] = $sql->insert("ApiPermission", array("method", "groups", "description")) | ||||||
|  |       ->addRow("ApiKey/create", array(), "Allows users to create API-Keys for themselves") | ||||||
|  |       ->addRow("ApiKey/fetch", array(), "Allows users to list their API-Keys") | ||||||
|  |       ->addRow("ApiKey/refresh", array(), "Allows users to refresh their API-Keys") | ||||||
|  |       ->addRow("ApiKey/revoke", array(), "Allows users to revoke their API-Keys") | ||||||
|  |       ->addRow("Groups/fetch", array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN), "Allows users to list all available groups") | ||||||
|  |       ->addRow("Groups/create", array(USER_GROUP_ADMIN), "Allows users to create a new groups") | ||||||
|  |       ->addRow("Groups/delete", array(USER_GROUP_ADMIN), "Allows users to delete a group") | ||||||
|  |       ->addRow("Routes/fetch", array(USER_GROUP_ADMIN), "Allows users to list all configured routes") | ||||||
|  |       ->addRow("Routes/save", array(USER_GROUP_ADMIN), "Allows users to create, delete and modify routes") | ||||||
|  |       ->addRow("Mail/test", array(USER_GROUP_SUPPORT, USER_GROUP_ADMIN), "Allows users to send a test email to a given address") | ||||||
|  |       ->addRow("Settings/get", array(USER_GROUP_ADMIN), "Allows users to fetch server settings") | ||||||
|  |       ->addRow("Settings/set", array(USER_GROUP_ADMIN), "Allows users create, delete or modify server settings") | ||||||
|  |       ->addRow("Stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to fetch server stats") | ||||||
|  |       ->addRow("User/create", array(USER_GROUP_ADMIN), "Allows users to create a new user, email address does not need to be confirmed") | ||||||
|  |       ->addRow("User/fetch", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to list all registered users") | ||||||
|  |       ->addRow("User/get", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to get information about a single user") | ||||||
|  |       ->addRow("User/invite", array(USER_GROUP_ADMIN), "Allows users to create a new user and send them an invitation link") | ||||||
|  |       ->addRow("User/edit", array(USER_GROUP_ADMIN), "Allows users to edit details and group memberships of any user") | ||||||
|  |       ->addRow("User/delete", array(USER_GROUP_ADMIN), "Allows users to delete any other user") | ||||||
|  |       ->addRow("Permission/fetch", array(USER_GROUP_ADMIN), "Allows users to list all API permissions") | ||||||
|  |       ->addRow("Visitors/stats", array(USER_GROUP_ADMIN, USER_GROUP_SUPPORT), "Allows users to see visitor statistics"); | ||||||
|  | 
 | ||||||
|     return $queries; |     return $queries; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   private static function MessageConfirmEmail() : string { | ||||||
|  |     return "Hello {{username}},<br>" . | ||||||
|  |       "You recently created an account on {{site_name}}. Please click on the following link to " . | ||||||
|  |       "confirm your email address and complete your registration. If you haven't registered an " . | ||||||
|  |       "account, you can simply ignore this email. The link is valid for the next 48 hours:<br><br> " . | ||||||
|  |       "<a href=\"{{link}}\">{{link}}</a><br><br> " . | ||||||
|  |       "Best Regards<br> " . | ||||||
|  |       "{{site_name}} Administration"; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| ?>
 |   private static function MessageAcceptInvite() : string { | ||||||
|  |     return "Hello {{username}},<br>" . | ||||||
|  |       "You were invited to create an account on {{site_name}}. Please click on the following link to " . | ||||||
|  |       "confirm your email address and complete your registration by choosing a new password. " . | ||||||
|  |       "If you want to decline the invitation, you can simply ignore this email. The link is valid for the next 7 days:<br><br>" . | ||||||
|  |       "<a href=\"{{link}}\">{{link}}</a><br><br>" . | ||||||
|  |       "Best Regards<br>" . | ||||||
|  |       "{{site_name}} Administration"; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private static function MessageResetPassword() : string { | ||||||
|  |     return "Hello {{username}},<br>" . | ||||||
|  |       "you requested a password reset on {{site_name}}. Please click on the following link to " . | ||||||
|  |       "choose a new password. If this request was not intended, you can simply ignore the email. The Link is valid for one hour:<br><br>" . | ||||||
|  |       "<a href=\"{{link}}\">{{link}}</a><br><br>" . | ||||||
|  |       "Best Regards<br>" . | ||||||
|  |       "{{site_name}} Administration"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										107
									
								
								core/Configuration/Settings.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										107
									
								
								core/Configuration/Settings.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Do not change settings here, they are dynamically loaded from database. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace Configuration; | ||||||
|  | 
 | ||||||
|  | use Driver\SQL\Query\Insert; | ||||||
|  | use Objects\User; | ||||||
|  | 
 | ||||||
|  | class Settings { | ||||||
|  | 
 | ||||||
|  |   private string $siteName; | ||||||
|  |   private string $baseUrl; | ||||||
|  |   private string $jwtSecret; | ||||||
|  |   private bool $installationComplete; | ||||||
|  |   private bool $registrationAllowed; | ||||||
|  |   private bool $recaptchaEnabled; | ||||||
|  |   private string $recaptchaPublicKey; | ||||||
|  |   private string $recaptchaPrivateKey; | ||||||
|  | 
 | ||||||
|  |   public function getJwtSecret(): string { | ||||||
|  |     return $this->jwtSecret; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function isInstalled() { | ||||||
|  |     return $this->installationComplete; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public static function loadDefaults() : Settings { | ||||||
|  |     $hostname = $_SERVER["SERVER_NAME"]; | ||||||
|  |     $protocol = getProtocol(); | ||||||
|  |     $jwt = generateRandomString(32); | ||||||
|  | 
 | ||||||
|  |     $settings = new Settings(); | ||||||
|  |     $settings->siteName = "WebBase"; | ||||||
|  |     $settings->baseUrl = "$protocol://$hostname"; | ||||||
|  |     $settings->jwtSecret = $jwt; | ||||||
|  |     $settings->installationComplete = false; | ||||||
|  |     $settings->registrationAllowed = false; | ||||||
|  |     $settings->recaptchaPublicKey = ""; | ||||||
|  |     $settings->recaptchaPrivateKey = ""; | ||||||
|  |     $settings->recaptchaEnabled = false; | ||||||
|  |     return $settings; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function loadFromDatabase(User $user) { | ||||||
|  |     $req = new \Api\Settings\Get($user); | ||||||
|  |     $success = $req->execute(); | ||||||
|  | 
 | ||||||
|  |     if ($success) { | ||||||
|  |       $result = $req->getResult()["settings"]; | ||||||
|  |       $this->siteName = $result["site_name"] ?? $this->siteName; | ||||||
|  |       $this->registrationAllowed = $result["user_registration_enabled"] ?? $this->registrationAllowed; | ||||||
|  |       $this->installationComplete = $result["installation_completed"] ?? $this->installationComplete; | ||||||
|  |       $this->jwtSecret = $result["jwt_secret"] ?? $this->jwtSecret; | ||||||
|  |       $this->recaptchaEnabled = $result["recaptcha_enabled"] ?? $this->recaptchaEnabled; | ||||||
|  |       $this->recaptchaPublicKey = $result["recaptcha_public_key"] ?? $this->recaptchaPublicKey; | ||||||
|  |       $this->recaptchaPrivateKey = $result["recaptcha_private_key"] ?? $this->recaptchaPrivateKey; | ||||||
|  | 
 | ||||||
|  |       if (!isset($result["jwt_secret"])) { | ||||||
|  |         $req = new \Api\Settings\Set($user); | ||||||
|  |         $req->execute(array("settings" => array( | ||||||
|  |           "jwt_secret" => $this->jwtSecret | ||||||
|  |         ))); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function addRows(Insert $query) { | ||||||
|  |     $query->addRow("site_name", $this->siteName, false, false) | ||||||
|  |       ->addRow("base_url", $this->baseUrl, false, false) | ||||||
|  |       ->addRow("user_registration_enabled", $this->registrationAllowed ? "1" : "0", false, false) | ||||||
|  |       ->addRow("installation_completed", $this->installationComplete ? "1" : "0", true, true) | ||||||
|  |       ->addRow("jwt_secret", $this->jwtSecret, true, true) | ||||||
|  |       ->addRow("recaptcha_enabled", $this->recaptchaEnabled ? "1" : "0", false, false) | ||||||
|  |       ->addRow("recaptcha_public_key", $this->recaptchaPublicKey, false, false) | ||||||
|  |       ->addRow("recaptcha_private_key", $this->recaptchaPrivateKey, true, false); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function getSiteName() : string { | ||||||
|  |     return $this->siteName; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function getBaseUrl() : string { | ||||||
|  |     return $this->baseUrl; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function isRecaptchaEnabled() : bool { | ||||||
|  |     return $this->recaptchaEnabled; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function getRecaptchaSiteKey() : string { | ||||||
|  |     return $this->recaptchaPublicKey; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function getRecaptchaSecretKey() : string { | ||||||
|  |     return $this->recaptchaPrivateKey; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function isRegistrationAllowed() : bool { | ||||||
|  |     return $this->registrationAllowed; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								core/Documents/Account.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										72
									
								
								core/Documents/Account.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Documents { | ||||||
|  | 
 | ||||||
|  |   use Documents\Account\AccountBody; | ||||||
|  |   use Documents\Account\AccountHead; | ||||||
|  |   use Elements\Document; | ||||||
|  |   use Objects\User; | ||||||
|  | 
 | ||||||
|  |   class Account extends Document { | ||||||
|  |     public function __construct(User $user, ?string $view) { | ||||||
|  |       parent::__construct($user, AccountHead::class, AccountBody::class, $view); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Documents\Account { | ||||||
|  | 
 | ||||||
|  |   use Elements\Head; | ||||||
|  |   use Elements\Script; | ||||||
|  |   use Elements\SimpleBody; | ||||||
|  | 
 | ||||||
|  |   class AccountHead extends Head { | ||||||
|  | 
 | ||||||
|  |     public function __construct($document) { | ||||||
|  |       parent::__construct($document); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected function initSources() { | ||||||
|  |       $this->loadJQuery(); | ||||||
|  |       $this->addJS(Script::CORE); | ||||||
|  |       $this->addJS(Script::ACCOUNT); | ||||||
|  |       $this->loadBootstrap(); | ||||||
|  |       $this->loadFontawesome(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected function initMetas() { | ||||||
|  |       return array( | ||||||
|  |         array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0'), | ||||||
|  |         array('name' => 'format-detection', 'content' => 'telephone=yes'), | ||||||
|  |         array('charset' => 'utf-8'), | ||||||
|  |         array("http-equiv" => 'expires', 'content' => '0'), | ||||||
|  |         array("name" => 'robots', 'content' => 'noarchive'), | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected function initRawFields() { | ||||||
|  |       return array(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected function initTitle() { | ||||||
|  |       return "Account"; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   class AccountBody extends SimpleBody { | ||||||
|  | 
 | ||||||
|  |     public function __construct($document) { | ||||||
|  |       parent::__construct($document); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected function getContent() { | ||||||
|  | 
 | ||||||
|  |       $view = $this->getDocument()->getView(); | ||||||
|  |       if ($view === null) { | ||||||
|  |         return "The page you does not exist or is no longer valid. <a href='/'>Return to start page</a>"; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $view->getCode(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,29 +1,35 @@ | |||||||
| <?php | <?php | ||||||
| 
 | 
 | ||||||
| namespace Documents { | namespace Documents { | ||||||
|   class Admin extends \Elements\Document { | 
 | ||||||
|     public function __construct($user) { |   use Documents\Admin\AdminHead; | ||||||
|       parent::__construct($user, Admin\Head::class, Admin\Body::class); |   use Elements\Document; | ||||||
|  |   use Objects\User; | ||||||
|  |   use Views\Admin\AdminDashboardBody; | ||||||
|  |   use Views\Admin\LoginBody; | ||||||
|  | 
 | ||||||
|  |   class Admin extends Document { | ||||||
|  |     public function __construct(User $user, ?string $view = NULL) { | ||||||
|  |       $body = $user->isLoggedIn() ? AdminDashboardBody::class : LoginBody::class; | ||||||
|  |       parent::__construct($user, AdminHead::class, $body, $view); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace Documents\Admin { | namespace Documents\Admin { | ||||||
| 
 | 
 | ||||||
|   class Head extends \Elements\Head { |   use Elements\Head; | ||||||
|  |   use Elements\Link; | ||||||
|  |   use Elements\Script; | ||||||
|  | 
 | ||||||
|  |   class AdminHead extends Head { | ||||||
| 
 | 
 | ||||||
|     public function __construct($document) { |     public function __construct($document) { | ||||||
|       parent::__construct($document); |       parent::__construct($document); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function initSources() { |     protected function initSources() { | ||||||
|       $this->loadJQuery(); |  | ||||||
|       $this->loadBootstrap(); |  | ||||||
|       $this->loadFontawesome(); |       $this->loadFontawesome(); | ||||||
|       $this->addJS(\Elements\Script::CORE); |  | ||||||
|       $this->addCSS(\Elements\Link::CORE); |  | ||||||
|       $this->addJS(\Elements\Script::ADMIN); |  | ||||||
|       $this->addCSS(\Elements\Link::ADMIN); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function initMetas() { |     protected function initMetas() { | ||||||
| @ -44,26 +50,4 @@ namespace Documents\Admin { | |||||||
|       return "WebBase - Administration"; |       return "WebBase - Administration"; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
|   class Body extends \Elements\Body { |  | ||||||
| 
 |  | ||||||
|     public function __construct($document) { |  | ||||||
|       parent::__construct($document); |  | ||||||
| } | } | ||||||
| 
 |  | ||||||
|     public function getCode() { |  | ||||||
|       $html = parent::getCode(); |  | ||||||
| 
 |  | ||||||
|       $document = $this->getDocument(); |  | ||||||
|       if(!$document->getUser()->isLoggedIn()) { |  | ||||||
|         $html .= new \Views\Login($document); |  | ||||||
|       } else { |  | ||||||
|         $html .= new \Views\Admin($document); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       return $html; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -1,27 +1,32 @@ | |||||||
| <?php | <?php | ||||||
| 
 | 
 | ||||||
| namespace Documents { | namespace Documents { | ||||||
|   class Document404 extends \Elements\Document { | 
 | ||||||
|     public function __construct($user) { |   use Documents\Document404\Body404; | ||||||
|       parent::__construct($user, Document404\Head404::class, Document404\Body404::class); |   use Documents\Document404\Head404; | ||||||
|  |   use Elements\Document; | ||||||
|  | 
 | ||||||
|  |   class Document404 extends Document { | ||||||
|  |     public function __construct($user, ?string $view = NULL) { | ||||||
|  |       parent::__construct($user, Head404::class, Body404::class, $view); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace Documents\Document404 { | namespace Documents\Document404 { | ||||||
| 
 | 
 | ||||||
|   class Head404 extends \Elements\Head { |   use Elements\Body; | ||||||
|  |   use Elements\Head; | ||||||
|  |   use Elements\SimpleBody; | ||||||
|  |   use Views\View404; | ||||||
|  | 
 | ||||||
|  |   class Head404 extends Head { | ||||||
| 
 | 
 | ||||||
|     public function __construct($document) { |     public function __construct($document) { | ||||||
|       parent::__construct($document); |       parent::__construct($document); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function initSources() { |     protected function initSources() { | ||||||
|       // $this->loadJQuery();
 |  | ||||||
|       // $this->loadBootstrap();
 |  | ||||||
|       // $this->loadFontawesome();
 |  | ||||||
|       // $this->addJS(\Elements\Script::CORE);
 |  | ||||||
|       // $this->addCSS(\Elements\Link::CORE);
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function initMetas() { |     protected function initMetas() { | ||||||
| @ -43,18 +48,18 @@ namespace Documents\Document404 { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   class Body404 extends \Elements\Body { |   class Body404 extends SimpleBody { | ||||||
| 
 | 
 | ||||||
|     public function __construct($document) { |     public function __construct($document) { | ||||||
|       parent::__construct($document); |       parent::__construct($document); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function getCode() { |     public function loadView() { | ||||||
|       $html = parent::getCode(); |       http_response_code(404); | ||||||
|       $html .= "<b>404 Not Found</b>"; |  | ||||||
|       return $html; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| ?>
 |     protected function getContent() { | ||||||
|  |       return $this->load(View404::class); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,9 +1,14 @@ | |||||||
| <?php | <?php | ||||||
| 
 | 
 | ||||||
| namespace Documents { | namespace Documents { | ||||||
|   class Install extends \Elements\Document { | 
 | ||||||
|  |   use Documents\Install\InstallBody; | ||||||
|  |   use Documents\Install\InstallHead; | ||||||
|  |   use Elements\Document; | ||||||
|  | 
 | ||||||
|  |   class Install extends Document { | ||||||
|     public function __construct($user) { |     public function __construct($user) { | ||||||
|       parent::__construct($user, Install\Head::class, Install\Body::class); |       parent::__construct($user, InstallHead::class, InstallBody::class); | ||||||
|       $this->databaseRequired = false; |       $this->databaseRequired = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -11,7 +16,17 @@ namespace Documents { | |||||||
| 
 | 
 | ||||||
| namespace Documents\Install { | namespace Documents\Install { | ||||||
| 
 | 
 | ||||||
|   class Head extends \Elements\Head { |   use Configuration\CreateDatabase; | ||||||
|  |   use Driver\SQL\SQL; | ||||||
|  |   use Elements\Body; | ||||||
|  |   use Elements\Head; | ||||||
|  |   use Elements\Link; | ||||||
|  |   use Elements\Script; | ||||||
|  |   use External\PHPMailer\Exception; | ||||||
|  |   use External\PHPMailer\PHPMailer; | ||||||
|  |   use Objects\ConnectionData; | ||||||
|  | 
 | ||||||
|  |   class InstallHead extends Head { | ||||||
| 
 | 
 | ||||||
|     public function __construct($document) { |     public function __construct($document) { | ||||||
|       parent::__construct($document); |       parent::__construct($document); | ||||||
| @ -21,9 +36,9 @@ namespace Documents\Install { | |||||||
|       $this->loadJQuery(); |       $this->loadJQuery(); | ||||||
|       $this->loadBootstrap(); |       $this->loadBootstrap(); | ||||||
|       $this->loadFontawesome(); |       $this->loadFontawesome(); | ||||||
|       $this->addJS(\Elements\Script::CORE); |       $this->addJS(Script::CORE); | ||||||
|       $this->addCSS(\Elements\Link::CORE); |       $this->addCSS(Link::CORE); | ||||||
|       $this->addJS(\Elements\Script::INSTALL); |       $this->addJS(Script::INSTALL); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function initMetas() { |     protected function initMetas() { | ||||||
| @ -46,27 +61,31 @@ namespace Documents\Install { | |||||||
| 
 | 
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   class Body extends \Elements\Body { |   class InstallBody extends Body { | ||||||
| 
 | 
 | ||||||
|     // Status enum
 |     // Status enum
 | ||||||
|     const NOT_STARTED = 0; |     const NOT_STARTED = 0; | ||||||
|     const PENDING = 1; |     const PENDING = 1; | ||||||
|     const SUCCESFULL = 2; |     const SUCCESSFUL = 2; | ||||||
|     const ERROR = 3; |     const ERROR = 3; | ||||||
| 
 | 
 | ||||||
|     // Step enum
 |     // Step enum
 | ||||||
|     const CHECKING_REQUIRMENTS = 1; |     const CHECKING_REQUIREMENTS = 1; | ||||||
|     const DATABASE_CONFIGURATION = 2; |     const DATABASE_CONFIGURATION = 2; | ||||||
|     const CREATE_USER = 3; |     const CREATE_USER = 3; | ||||||
|     const ADD_MAIL_SERVICE = 4; |     const ADD_MAIL_SERVICE = 4; | ||||||
|     const FINISH_INSTALLATION = 5; |     const FINISH_INSTALLATION = 5; | ||||||
| 
 | 
 | ||||||
|     //
 |     //
 | ||||||
|     private $errorString; |     private string $errorString; | ||||||
|  |     private int $currentStep; | ||||||
|  |     private array $steps; | ||||||
| 
 | 
 | ||||||
|     function __construct($document) { |     function __construct($document) { | ||||||
|       parent::__construct($document); |       parent::__construct($document); | ||||||
|       $this->errorString = ""; |       $this->errorString = ""; | ||||||
|  |       $this->currentStep = InstallBody::CHECKING_REQUIREMENTS; | ||||||
|  |       $this->steps = array(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function getParameter($name) { |     private function getParameter($name) { | ||||||
| @ -80,7 +99,7 @@ namespace Documents\Install { | |||||||
|     private function getCurrentStep() { |     private function getCurrentStep() { | ||||||
| 
 | 
 | ||||||
|       if(!$this->checkRequirements()["success"]) { |       if(!$this->checkRequirements()["success"]) { | ||||||
|         return self::CHECKING_REQUIRMENTS; |         return self::CHECKING_REQUIREMENTS; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       $user = $this->getDocument()->getUser(); |       $user = $this->getDocument()->getUser(); | ||||||
| @ -92,6 +111,10 @@ namespace Documents\Install { | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       $sql = $user->getSQL(); |       $sql = $user->getSQL(); | ||||||
|  |       if(!$sql || !$sql->isConnected()) { | ||||||
|  |         return self::DATABASE_CONFIGURATION; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       $countKeyword = $sql->count(); |       $countKeyword = $sql->count(); | ||||||
|       $res = $sql->select($countKeyword)->from("User")->execute(); |       $res = $sql->select($countKeyword)->from("User")->execute(); | ||||||
|       if ($res === FALSE) { |       if ($res === FALSE) { | ||||||
| @ -104,18 +127,27 @@ namespace Documents\Install { | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       if($step === self::ADD_MAIL_SERVICE && $config->isFilePresent("Mail")) { |       if ($step === self::ADD_MAIL_SERVICE) { | ||||||
|  |         $req = new \Api\Settings\Get($user); | ||||||
|  |         $success = $req->execute(array("key" => "^mail_enabled$")); | ||||||
|  |         if (!$success) { | ||||||
|  |           $this->errorString = $req->getLastError(); | ||||||
|  |           return self::DATABASE_CONFIGURATION; | ||||||
|  |         } else if (isset($req->getResult()["settings"]["mail_enabled"])) { | ||||||
|           $step = self::FINISH_INSTALLATION; |           $step = self::FINISH_INSTALLATION; | ||||||
|         if(!$config->isFilePresent("JWT") && !$config->create("JWT", generateRandomString(32))) { | 
 | ||||||
|           $this->errorString = "Unable to create jwt file"; |           $req = new \Api\Settings\Set($user); | ||||||
|  |           $success = $req->execute(array("settings" => array("installation_completed" => "1"))); | ||||||
|  |           if (!$success) { | ||||||
|  |             $this->errorString = $req->getLastError(); | ||||||
|           } else { |           } else { | ||||||
|             $req = new \Api\Notifications\Create($user); |             $req = new \Api\Notifications\Create($user); | ||||||
|           $success = $req->execute(array( |             $req->execute(array( | ||||||
|                 "title" => "Welcome", |                 "title" => "Welcome", | ||||||
|                 "message" => "Your Web-base was successfully installed. Check out the admin dashboard. Have fun!", |                 "message" => "Your Web-base was successfully installed. Check out the admin dashboard. Have fun!", | ||||||
|             "groupId" => USER_GROUP_ADMIN) |                 "groupId" => USER_GROUP_ADMIN | ||||||
|  |               ) | ||||||
|             ); |             ); | ||||||
|           if (!$success) { |  | ||||||
|             $this->errorString = $req->getLastError(); |             $this->errorString = $req->getLastError(); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
| @ -145,8 +177,8 @@ namespace Documents\Install { | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       if(version_compare(PHP_VERSION, '7.1', '<')) { |       if(version_compare(PHP_VERSION, '7.4', '<')) { | ||||||
|           $failedRequirements[] = "PHP Version <b>>= 7.1</b> is required. Got: <b>" . PHP_VERSION . "</b>"; |           $failedRequirements[] = "PHP Version <b>>= 7.4</b> is required. Got: <b>" . PHP_VERSION . "</b>"; | ||||||
|           $success = false; |           $success = false; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
| @ -213,16 +245,16 @@ namespace Documents\Install { | |||||||
|         $msg = "Unsupported database type. Must be one of: " . implode(", ", $supportedTypes); |         $msg = "Unsupported database type. Must be one of: " . implode(", ", $supportedTypes); | ||||||
|         $success = false; |         $success = false; | ||||||
|       } else { |       } else { | ||||||
|         $connectionData = new \Objects\ConnectionData($host, $port, $username, $password); |         $connectionData = new ConnectionData($host, $port, $username, $password); | ||||||
|         $connectionData->setProperty('database', $database); |         $connectionData->setProperty('database', $database); | ||||||
|         $connectionData->setProperty('encoding', $encoding); |         $connectionData->setProperty('encoding', $encoding); | ||||||
|         $connectionData->setProperty('type', $type); |         $connectionData->setProperty('type', $type); | ||||||
|         $sql = \Driver\SQL\SQL::createConnection($connectionData); |         $sql = SQL::createConnection($connectionData); | ||||||
|         $success = false; |         $success = false; | ||||||
|         if(!($sql instanceof \Driver\SQL\SQL)) { |         if(is_string($sql)) { | ||||||
|           $msg = "Error connecting to database: " . str($sql); |           $msg = "Error connecting to database: $sql"; | ||||||
|         } else if(!$sql->isConnected()) { |         } else if(!$sql->isConnected()) { | ||||||
|           if (!$sql->checkRequirements()["success"]) { |           if (!$sql->checkRequirements()) { | ||||||
|             $driverName = $sql->getDriverName(); |             $driverName = $sql->getDriverName(); | ||||||
|             $installLink = "https://www.php.net/manual/en/$driverName.setup.php"; |             $installLink = "https://www.php.net/manual/en/$driverName.setup.php"; | ||||||
|             $link = $this->createExternalLink($installLink); |             $link = $this->createExternalLink($installLink); | ||||||
| @ -234,7 +266,7 @@ namespace Documents\Install { | |||||||
| 
 | 
 | ||||||
|           $msg = ""; |           $msg = ""; | ||||||
|           $success = true; |           $success = true; | ||||||
|           $queries = \Configuration\CreateDatabase::createQueries($sql); |           $queries = CreateDatabase::createQueries($sql); | ||||||
|           foreach($queries as $query) { |           foreach($queries as $query) { | ||||||
|             if (!($res = $query->execute())) { |             if (!($res = $query->execute())) { | ||||||
|               $msg = "Error creating tables: " . $sql->getLastError(); |               $msg = "Error creating tables: " . $sql->getLastError(); | ||||||
| @ -243,7 +275,8 @@ namespace Documents\Install { | |||||||
|             } |             } | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           if($success && !$this->getDocument()->getUser()->getConfiguration()->create("Database", $connectionData)) { |           $config = $this->getDocument()->getUser()->getConfiguration(); | ||||||
|  |           if(!$config->create("Database", $connectionData)) { | ||||||
|             $success = false; |             $success = false; | ||||||
|             $msg = "Unable to write file"; |             $msg = "Unable to write file"; | ||||||
|           } |           } | ||||||
| @ -269,8 +302,8 @@ namespace Documents\Install { | |||||||
|       $username = $this->getParameter("username"); |       $username = $this->getParameter("username"); | ||||||
|       $password = $this->getParameter("password"); |       $password = $this->getParameter("password"); | ||||||
|       $confirmPassword = $this->getParameter("confirmPassword"); |       $confirmPassword = $this->getParameter("confirmPassword"); | ||||||
|  |       $email = $this->getParameter("email") ?? ""; | ||||||
| 
 | 
 | ||||||
|       $msg = $this->errorString; |  | ||||||
|       $success = true; |       $success = true; | ||||||
|       $missingInputs = array(); |       $missingInputs = array(); | ||||||
| 
 | 
 | ||||||
| @ -292,30 +325,24 @@ namespace Documents\Install { | |||||||
|       if(!$success) { |       if(!$success) { | ||||||
|         $msg = "Please fill out the following inputs:<br>" . |         $msg = "Please fill out the following inputs:<br>" . | ||||||
|           $this->createUnorderedList($missingInputs); |           $this->createUnorderedList($missingInputs); | ||||||
|       } else if(strlen($username) < 5 || strlen($username) > 32) { |  | ||||||
|         $msg = "The username should be between 5 and 32 characters long"; |  | ||||||
|         $success = false; |  | ||||||
|       } else if(strcmp($password, $confirmPassword) !== 0) { |  | ||||||
|         $msg = "The given passwords do not match"; |  | ||||||
|         $success = false; |  | ||||||
|       } else if(strlen($password) < 6) { |  | ||||||
|         $msg = "The password should be at least 6 characters long"; |  | ||||||
|         $success = false; |  | ||||||
|       } else { |       } else { | ||||||
|         $salt = generateRandomString(16); |  | ||||||
|         $hash = hash('sha256', $password . $salt); |  | ||||||
|         $sql = $user->getSQL(); |         $sql = $user->getSQL(); | ||||||
|  |         $req = new \Api\User\Create($user); | ||||||
|  |         $success = $req->execute(array( | ||||||
|  |           'username' => $username, | ||||||
|  |           'email' => $email, | ||||||
|  |           'password' => $password, | ||||||
|  |           'confirmPassword' => $confirmPassword, | ||||||
|  |         )); | ||||||
| 
 | 
 | ||||||
|         $success = $sql->insert("User", array("name", "salt", "password")) |         $msg = $req->getLastError(); | ||||||
|           ->addRow($username, $salt, $hash) |         if ($success) { | ||||||
|           ->returning("uid") |           $success = $sql->insert("UserGroup", array("group_id", "user_id")) | ||||||
|           ->execute() |             ->addRow(USER_GROUP_ADMIN, $req->getResult()["userId"]) | ||||||
|           && $sql->insert("UserGroup", array("group_id", "user_id")) |  | ||||||
|           ->addRow(USER_GROUP_ADMIN, $sql->getLastInsertId()) |  | ||||||
|             ->execute(); |             ->execute(); | ||||||
| 
 |  | ||||||
|           $msg = $sql->getLastError(); |           $msg = $sql->getLastError(); | ||||||
|         } |         } | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|       return array("msg" => $msg, "success" => $success); |       return array("msg" => $msg, "success" => $success); | ||||||
|     } |     } | ||||||
| @ -333,10 +360,9 @@ namespace Documents\Install { | |||||||
|       $success = true; |       $success = true; | ||||||
|       $msg = $this->errorString; |       $msg = $this->errorString; | ||||||
|       if($this->getParameter("skip") === "true") { |       if($this->getParameter("skip") === "true") { | ||||||
|         if(!$user->getConfiguration()->create("Mail", null)) { |         $req = new \Api\Settings\Set($user); | ||||||
|           $success = false; |         $success = $req->execute(array("settings" => array( "mail_enabled" => "0" ))); | ||||||
|           $msg = "Unable to create file"; |         $msg = $req->getLastError(); | ||||||
|         } |  | ||||||
|       } else { |       } else { | ||||||
| 
 | 
 | ||||||
|         $address = $this->getParameter("address"); |         $address = $this->getParameter("address"); | ||||||
| @ -375,7 +401,7 @@ namespace Documents\Install { | |||||||
|         } else { |         } else { | ||||||
|           $success = false; |           $success = false; | ||||||
| 
 | 
 | ||||||
|           $mail = new \External\PHPMailer\PHPMailer(true); |           $mail = new PHPMailer(true); | ||||||
|           $mail->IsSMTP(); |           $mail->IsSMTP(); | ||||||
|           $mail->SMTPAuth = true; |           $mail->SMTPAuth = true; | ||||||
|           $mail->Username = $username; |           $mail->Username = $username; | ||||||
| @ -395,16 +421,20 @@ namespace Documents\Install { | |||||||
|               $msg = ""; |               $msg = ""; | ||||||
|               $mail->smtpClose(); |               $mail->smtpClose(); | ||||||
|             } |             } | ||||||
|           } catch(\External\PHPMailer\Exception $error) { |           } catch(Exception $error) { | ||||||
|             $msg = "Could not connect to SMTP Server: " . $error->errorMessage(); |             $msg = "Could not connect to SMTP Server: " . $error->errorMessage(); | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           if($success) { |           if($success) { | ||||||
|             $connectionData = new \Objects\ConnectionData($address, $port, $username, $password); |             $req = new \Api\Settings\Set($user); | ||||||
|             if(!$user->getConfiguration()->create("Mail", $connectionData)) { |             $success = $req->execute(array("settings" => array( | ||||||
|               $success = false; |               "mail_enabled" => "1", | ||||||
|               $msg = "Unable to create file"; |               "mail_host" => "$address", | ||||||
|             } |               "mail_port" => "$port", | ||||||
|  |               "mail_username" => "$username", | ||||||
|  |               "mail_password" => "$password", | ||||||
|  |             ))); | ||||||
|  |             $msg = $req->getLastError(); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @ -416,7 +446,7 @@ namespace Documents\Install { | |||||||
| 
 | 
 | ||||||
|       switch($this->currentStep) { |       switch($this->currentStep) { | ||||||
| 
 | 
 | ||||||
|         case self::CHECKING_REQUIRMENTS: |         case self::CHECKING_REQUIREMENTS: | ||||||
|           return $this->checkRequirements(); |           return $this->checkRequirements(); | ||||||
| 
 | 
 | ||||||
|         case self::DATABASE_CONFIGURATION: |         case self::DATABASE_CONFIGURATION: | ||||||
| @ -446,26 +476,26 @@ namespace Documents\Install { | |||||||
| 
 | 
 | ||||||
|         switch($status) { |         switch($status) { | ||||||
|           case self::PENDING: |           case self::PENDING: | ||||||
|             $statusIcon  = '<i class="fas fa-spin fa-spinner"></i>'; |             $statusIcon  = $this->createIcon("spinner"); | ||||||
|             $statusText  = "Loading…"; |             $statusText  = "Loading…"; | ||||||
|             $statusColor = "muted"; |             $statusColor = "muted"; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|           case self::SUCCESFULL: |           case self::SUCCESSFUL: | ||||||
|             $statusIcon  = '<i class="fas fa-check-circle"></i>'; |             $statusIcon  = $this->createIcon("check-circle"); | ||||||
|             $statusText  = "Successfull"; |             $statusText  = "Successful"; | ||||||
|             $statusColor = "success"; |             $statusColor = "success"; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|           case self::ERROR: |           case self::ERROR: | ||||||
|             $statusIcon  = '<i class="fas fa-times-circle"></i>'; |             $statusIcon  = $this->createIcon("times-circle"); | ||||||
|             $statusText  = "Failed"; |             $statusText  = "Failed"; | ||||||
|             $statusColor = "danger"; |             $statusColor = "danger"; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|           case self::NOT_STARTED: |           case self::NOT_STARTED: | ||||||
|           default: |           default: | ||||||
|             $statusIcon = '<i class="far fa-circle"></i>'; |             $statusIcon = $this->createIcon("circle", "far"); | ||||||
|             $statusText = "Pending"; |             $statusText = "Pending"; | ||||||
|             $statusColor = "muted"; |             $statusColor = "muted"; | ||||||
|             break; |             break; | ||||||
| @ -552,7 +582,7 @@ namespace Documents\Install { | |||||||
|     private function createProgessMainview() { |     private function createProgessMainview() { | ||||||
| 
 | 
 | ||||||
|       $views = array( |       $views = array( | ||||||
|         self::CHECKING_REQUIRMENTS => array( |         self::CHECKING_REQUIREMENTS => array( | ||||||
|           "title" => "Application Requirements", |           "title" => "Application Requirements", | ||||||
|           "progressText" => "Checking requirements, please wait a moment…" |           "progressText" => "Checking requirements, please wait a moment…" | ||||||
|         ), |         ), | ||||||
| @ -585,6 +615,7 @@ namespace Documents\Install { | |||||||
|           "title" => "Create a User", |           "title" => "Create a User", | ||||||
|           "form" => array( |           "form" => array( | ||||||
|             array("title" => "Username", "name"  => "username", "type"  => "text", "required" => true), |             array("title" => "Username", "name"  => "username", "type"  => "text", "required" => true), | ||||||
|  |             array("title" => "Email", "name"  => "email", "type"  => "text"), | ||||||
|             array("title" => "Password", "name"  => "password", "type"  => "password", "required" => true), |             array("title" => "Password", "name"  => "password", "type"  => "password", "required" => true), | ||||||
|             array("title" => "Confirm Password", "name"  => "confirmPassword", "type"  => "password", "required" => true), |             array("title" => "Confirm Password", "name"  => "confirmPassword", "type"  => "password", "required" => true), | ||||||
|           ), |           ), | ||||||
| @ -661,7 +692,7 @@ namespace Documents\Install { | |||||||
|       ); |       ); | ||||||
| 
 | 
 | ||||||
|       if($this->currentStep != self::FINISH_INSTALLATION) { |       if($this->currentStep != self::FINISH_INSTALLATION) { | ||||||
|         if ($this->currentStep == self::CHECKING_REQUIRMENTS) { |         if ($this->currentStep == self::CHECKING_REQUIREMENTS) { | ||||||
|           $buttons[] = array("title" => "Retry", "type" => "success", "id" => "btnRetry", "float" => "right"); |           $buttons[] = array("title" => "Retry", "type" => "success", "id" => "btnRetry", "float" => "right"); | ||||||
|         } else { |         } else { | ||||||
|           $buttons[] = array("title" => "Submit", "type" => "success", "id" => "btnSubmit", "float" => "right"); |           $buttons[] = array("title" => "Submit", "type" => "success", "id" => "btnSubmit", "float" => "right"); | ||||||
| @ -683,7 +714,7 @@ namespace Documents\Install { | |||||||
|         $id = $button["id"]; |         $id = $button["id"]; | ||||||
|         $float = $button["float"]; |         $float = $button["float"]; | ||||||
|         $disabled = (isset($button["disabled"]) && $button["disabled"]) ? " disabled" : ""; |         $disabled = (isset($button["disabled"]) && $button["disabled"]) ? " disabled" : ""; | ||||||
|         $button = "<button type=\"button\" id=\"$id\" class=\"btn btn-$type margin-xs\"$disabled>$title</button>"; |         $button = "<button type=\"button\" id=\"$id\" class=\"btn btn-$type m-1\"$disabled>$title</button>"; | ||||||
| 
 | 
 | ||||||
|         if($float === "left") { |         if($float === "left") { | ||||||
|           $buttonsLeft .= $button; |           $buttonsLeft .= $button; | ||||||
| @ -701,12 +732,11 @@ namespace Documents\Install { | |||||||
|       return $html; |       return $html; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     function getCode() { |     function getCode() { | ||||||
|       $html = parent::getCode(); |       $html = parent::getCode(); | ||||||
| 
 | 
 | ||||||
|       $this->steps = array( |       $this->steps = array( | ||||||
|         self::CHECKING_REQUIRMENTS => array( |         self::CHECKING_REQUIREMENTS => array( | ||||||
|           "title" => "Checking requirements", |           "title" => "Checking requirements", | ||||||
|           "status" => self::ERROR |           "status" => self::ERROR | ||||||
|         ), |         ), | ||||||
| @ -731,12 +761,12 @@ namespace Documents\Install { | |||||||
|       $this->currentStep = $this->getCurrentStep(); |       $this->currentStep = $this->getCurrentStep(); | ||||||
| 
 | 
 | ||||||
|       // set status
 |       // set status
 | ||||||
|       for($step = self::CHECKING_REQUIRMENTS; $step < $this->currentStep; $step++) { |       for($step = self::CHECKING_REQUIREMENTS; $step < $this->currentStep; $step++) { | ||||||
|         $this->steps[$step]["status"] = self::SUCCESFULL; |         $this->steps[$step]["status"] = self::SUCCESSFUL; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       if($this->currentStep == self::FINISH_INSTALLATION) { |       if($this->currentStep == self::FINISH_INSTALLATION) { | ||||||
|         $this->steps[$this->currentStep]["status"] = self::SUCCESFULL; |         $this->steps[$this->currentStep]["status"] = self::SUCCESSFUL; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       // POST
 |       // POST
 | ||||||
| @ -748,6 +778,7 @@ namespace Documents\Install { | |||||||
| 
 | 
 | ||||||
|       $progressSidebar = $this->createProgressSidebar(); |       $progressSidebar = $this->createProgressSidebar(); | ||||||
|       $progressMainview = $this->createProgessMainview(); |       $progressMainview = $this->createProgessMainview(); | ||||||
|  | 
 | ||||||
|       $errorStyle = ($this->errorString ? '' : ' style="display:none"'); |       $errorStyle = ($this->errorString ? '' : ' style="display:none"'); | ||||||
|       $errorClass = ($this->errorString ? ' alert-danger' : ''); |       $errorClass = ($this->errorString ? ' alert-danger' : ''); | ||||||
| 
 | 
 | ||||||
| @ -773,7 +804,7 @@ namespace Documents\Install { | |||||||
|             </div> |             </div> | ||||||
|             <div class=\"col-md-8 order-md-1\">
 |             <div class=\"col-md-8 order-md-1\">
 | ||||||
|               $progressMainview |               $progressMainview | ||||||
|               <div class=\"alert$errorClass margin-top-m\" id=\"status\"$errorStyle>$this->errorString</div>
 |               <div class=\"alert$errorClass mt-4\" id=\"status\"$errorStyle>$this->errorString</div>
 | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
| @ -781,9 +812,5 @@ namespace Documents\Install { | |||||||
| 
 | 
 | ||||||
|       return $html; |       return $html; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -9,5 +9,3 @@ class BoolColumn extends Column { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,8 +4,8 @@ namespace Driver\SQL\Column; | |||||||
| 
 | 
 | ||||||
| class Column { | class Column { | ||||||
| 
 | 
 | ||||||
|   private $name; |   private string $name; | ||||||
|   private $nullable; |   private bool $nullable; | ||||||
|   private $defaultValue; |   private $defaultValue; | ||||||
| 
 | 
 | ||||||
|   public function __construct($name, $nullable = false, $defaultValue = NULL) { |   public function __construct($name, $nullable = false, $defaultValue = NULL) { | ||||||
| @ -19,5 +19,3 @@ class Column { | |||||||
|   public function getDefaultValue() { return $this->defaultValue; } |   public function getDefaultValue() { return $this->defaultValue; } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -8,5 +8,3 @@ class DateTimeColumn extends Column { | |||||||
|     parent::__construct($name, $nullable, $defaultValue); |     parent::__construct($name, $nullable, $defaultValue); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ namespace Driver\SQL\Column; | |||||||
| 
 | 
 | ||||||
| class EnumColumn extends Column { | class EnumColumn extends Column { | ||||||
| 
 | 
 | ||||||
|   private $values; |   private array $values; | ||||||
| 
 | 
 | ||||||
|   public function __construct($name, $values, $nullable=false, $defaultValue=NULL) { |   public function __construct($name, $values, $nullable=false, $defaultValue=NULL) { | ||||||
|     parent::__construct($name, $nullable, $defaultValue); |     parent::__construct($name, $nullable, $defaultValue); | ||||||
| @ -13,5 +13,3 @@ class EnumColumn extends Column { | |||||||
| 
 | 
 | ||||||
|   public function getValues() { return $this->values; } |   public function getValues() { return $this->values; } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -9,5 +9,3 @@ class IntColumn extends Column { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -9,5 +9,3 @@ class JsonColumn extends Column { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -9,5 +9,3 @@ class SerialColumn extends Column { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ namespace Driver\SQL\Column; | |||||||
| 
 | 
 | ||||||
| class StringColumn extends Column { | class StringColumn extends Column { | ||||||
| 
 | 
 | ||||||
|   private $maxSize; |   private ?int $maxSize; | ||||||
| 
 | 
 | ||||||
|   public function __construct($name, $maxSize=null, $nullable=false, $defaultValue=null) { |   public function __construct($name, $maxSize=null, $nullable=false, $defaultValue=null) { | ||||||
|     parent::__construct($name, $nullable, $defaultValue); |     parent::__construct($name, $nullable, $defaultValue); | ||||||
| @ -13,5 +13,3 @@ class StringColumn extends Column { | |||||||
| 
 | 
 | ||||||
|   public function getMaxSize() { return $this->maxSize; } |   public function getMaxSize() { return $this->maxSize; } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,6 +4,10 @@ namespace Driver\SQL\Condition; | |||||||
| 
 | 
 | ||||||
| class Compare extends Condition { | class Compare extends Condition { | ||||||
| 
 | 
 | ||||||
|  |   private string $operator; | ||||||
|  |   private string $column; | ||||||
|  |   private $value; | ||||||
|  | 
 | ||||||
|   public function __construct($col, $val, $operator='=') { |   public function __construct($col, $val, $operator='=') { | ||||||
|     $this->operator = $operator; |     $this->operator = $operator; | ||||||
|     $this->column = $col; |     $this->column = $col; | ||||||
| @ -15,5 +19,3 @@ class Compare extends Condition { | |||||||
|   public function getOperator() { return $this->operator; } |   public function getOperator() { return $this->operator; } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ namespace Driver\SQL\Condition; | |||||||
| 
 | 
 | ||||||
| class CondAnd extends Condition { | class CondAnd extends Condition { | ||||||
| 
 | 
 | ||||||
|   private $conditions; |   private array $conditions; | ||||||
| 
 | 
 | ||||||
|   public function __construct(...$conditions) { |   public function __construct(...$conditions) { | ||||||
|     $this->conditions = $conditions; |     $this->conditions = $conditions; | ||||||
| @ -12,5 +12,3 @@ class CondAnd extends Condition { | |||||||
| 
 | 
 | ||||||
|   public function getConditions() { return $this->conditions; } |   public function getConditions() { return $this->conditions; } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,6 +4,8 @@ namespace Driver\SQL\Condition; | |||||||
| 
 | 
 | ||||||
| class CondBool extends Condition { | class CondBool extends Condition { | ||||||
| 
 | 
 | ||||||
|  |   private $value; | ||||||
|  | 
 | ||||||
|   public function __construct($val) { |   public function __construct($val) { | ||||||
|     $this->value = $val; |     $this->value = $val; | ||||||
|   } |   } | ||||||
| @ -11,5 +13,3 @@ class CondBool extends Condition { | |||||||
|   public function getValue() { return $this->value; } |   public function getValue() { return $this->value; } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								core/Driver/SQL/Condition/CondIn.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										17
									
								
								core/Driver/SQL/Condition/CondIn.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Driver\SQL\Condition; | ||||||
|  | 
 | ||||||
|  | class CondIn extends Condition { | ||||||
|  | 
 | ||||||
|  |   private string $column; | ||||||
|  |   private $expression; | ||||||
|  | 
 | ||||||
|  |   public function __construct(string $column, $expression) { | ||||||
|  |     $this->column = $column; | ||||||
|  |     $this->expression = $expression; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function getColumn() { return $this->column; } | ||||||
|  |   public function getExpression() { return $this->expression; } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								core/Driver/SQL/Condition/CondKeyword.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										20
									
								
								core/Driver/SQL/Condition/CondKeyword.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Driver\SQL\Condition; | ||||||
|  | 
 | ||||||
|  | abstract class CondKeyword extends Condition { | ||||||
|  | 
 | ||||||
|  |   private $leftExpression; | ||||||
|  |   private $rightExpression; | ||||||
|  |   private string $keyword; | ||||||
|  | 
 | ||||||
|  |   public function __construct($keyword, $leftExpression, $rightExpression) { | ||||||
|  |     $this->leftExpression = $leftExpression; | ||||||
|  |     $this->rightExpression = $rightExpression; | ||||||
|  |     $this->keyword = $keyword; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function getLeftExp() { return $this->leftExpression; } | ||||||
|  |   public function getRightExp() { return $this->rightExpression; } | ||||||
|  |   public function getKeyword() { return $this->keyword; } | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								core/Driver/SQL/Condition/CondLike.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										10
									
								
								core/Driver/SQL/Condition/CondLike.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Driver\SQL\Condition; | ||||||
|  | 
 | ||||||
|  | class CondLike extends CondKeyword { | ||||||
|  | 
 | ||||||
|  |   public function __construct($leftExpression, $rightExpression) { | ||||||
|  |     parent::__construct("LIKE", $leftExpression, $rightExpression); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								core/Driver/SQL/Condition/CondNot.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								core/Driver/SQL/Condition/CondNot.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Driver\SQL\Condition; | ||||||
|  | 
 | ||||||
|  | class CondNot extends Condition { | ||||||
|  | 
 | ||||||
|  |   private $expression; // string or condition
 | ||||||
|  | 
 | ||||||
|  |   public function __construct($expression) { | ||||||
|  |     $this->expression = $expression; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function getExpression() { | ||||||
|  |     return $this->expression; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -4,13 +4,11 @@ namespace Driver\SQL\Condition; | |||||||
| 
 | 
 | ||||||
| class CondOr extends Condition { | class CondOr extends Condition { | ||||||
| 
 | 
 | ||||||
|   private $conditions; |   private array $conditions; | ||||||
| 
 | 
 | ||||||
|   public function __construct(...$conditions) { |   public function __construct(...$conditions) { | ||||||
|     $this->conditions = $conditions; |     $this->conditions = (!empty($conditions) && is_array($conditions[0])) ? $conditions[0] : $conditions; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getConditions() { return $this->conditions; } |   public function getConditions() { return $this->conditions; } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								core/Driver/SQL/Condition/CondRegex.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										11
									
								
								core/Driver/SQL/Condition/CondRegex.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Driver\SQL\Condition; | ||||||
|  | 
 | ||||||
|  | class CondRegex extends CondKeyword { | ||||||
|  | 
 | ||||||
|  |   public function __construct($leftExpression, $rightExpression) { | ||||||
|  |     parent::__construct("REGEXP", $leftExpression, $rightExpression); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -5,5 +5,3 @@ namespace Driver\SQL\Condition; | |||||||
| abstract class Condition { | abstract class Condition { | ||||||
|    |    | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,13 +4,11 @@ namespace Driver\SQL\Constraint; | |||||||
| 
 | 
 | ||||||
| abstract class Constraint { | abstract class Constraint { | ||||||
| 
 | 
 | ||||||
|   private $columnName; |   private array $columnNames; | ||||||
| 
 | 
 | ||||||
|   public function __construct($columnName) { |   public function __construct($columnNames) { | ||||||
|     $this->columnName = $columnName; |     $this->columnNames = (!is_array($columnNames) ? array($columnNames) : $columnNames); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getColumnName() { return $this->columnName; } |   public function getColumnNames() { return $this->columnNames; } | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -2,11 +2,13 @@ | |||||||
| 
 | 
 | ||||||
| namespace Driver\SQL\Constraint; | namespace Driver\SQL\Constraint; | ||||||
| 
 | 
 | ||||||
|  | use Driver\SQL\Strategy\Strategy; | ||||||
|  | 
 | ||||||
| class ForeignKey extends Constraint { | class ForeignKey extends Constraint { | ||||||
| 
 | 
 | ||||||
|   private $referencedTable; |   private string $referencedTable; | ||||||
|   private $referencedColumn; |   private string $referencedColumn; | ||||||
|   private $strategy; |   private ?Strategy $strategy; | ||||||
| 
 | 
 | ||||||
|   public function __construct($name, $refTable, $refColumn, $strategy = NULL) { |   public function __construct($name, $refTable, $refColumn, $strategy = NULL) { | ||||||
|     parent::__construct($name); |     parent::__construct($name); | ||||||
| @ -18,6 +20,4 @@ class ForeignKey extends Constraint { | |||||||
|   public function getReferencedTable() { return $this->referencedTable; } |   public function getReferencedTable() { return $this->referencedTable; } | ||||||
|   public function getReferencedColumn() { return $this->referencedColumn; } |   public function getReferencedColumn() { return $this->referencedColumn; } | ||||||
|   public function onDelete() { return $this->strategy; } |   public function onDelete() { return $this->strategy; } | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -8,6 +8,4 @@ class PrimaryKey extends Constraint { | |||||||
|     parent::__construct((!empty($names) && is_array($names[0])) ? $names[0] : $names); |     parent::__construct((!empty($names) && is_array($names[0])) ? $names[0] : $names); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -8,6 +8,4 @@ class Unique extends Constraint { | |||||||
|     parent::__construct((!empty($names) && is_array($names[0])) ? $names[0] : $names); |     parent::__construct((!empty($names) && is_array($names[0])) ? $names[0] : $names); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
							
								
								
									
										13
									
								
								core/Driver/SQL/Expression/Add.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										13
									
								
								core/Driver/SQL/Expression/Add.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Driver\SQL\Expression; | ||||||
|  | 
 | ||||||
|  | use Driver\SQL\Condition\Compare; | ||||||
|  | 
 | ||||||
|  | class Add extends Compare { | ||||||
|  | 
 | ||||||
|  |   public function __construct($col, $val) { | ||||||
|  |     parent::__construct($col, $val, "+"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -4,13 +4,13 @@ namespace Driver\SQL; | |||||||
| 
 | 
 | ||||||
| class Join { | class Join { | ||||||
| 
 | 
 | ||||||
|   private $type; |   private string $type; | ||||||
|   private $table; |   private string $table; | ||||||
|   private $columnA; |   private string $columnA; | ||||||
|   private $columnB; |   private string $columnB; | ||||||
| 
 | 
 | ||||||
|   public function __construct($type, $table, $columnA, $columnB) { |   public function __construct($type, $table, $columnA, $columnB) { | ||||||
|     $this->tpye = $type; |     $this->type = $type; | ||||||
|     $this->table = $table; |     $this->table = $table; | ||||||
|     $this->columnA = $columnA; |     $this->columnA = $columnA; | ||||||
|     $this->columnB = $columnB; |     $this->columnB = $columnB; | ||||||
| @ -22,5 +22,3 @@ class Join { | |||||||
|   public function getColumnB() { return $this->columnB; } |   public function getColumnB() { return $this->columnB; } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ namespace Driver\SQL; | |||||||
| 
 | 
 | ||||||
| class Keyword { | class Keyword { | ||||||
| 
 | 
 | ||||||
|   private $value; |   private string $value; | ||||||
| 
 | 
 | ||||||
|   public function __construct($value) { |   public function __construct($value) { | ||||||
|     $this->value = $value; |     $this->value = $value; | ||||||
| @ -13,5 +13,3 @@ class Keyword { | |||||||
|   public function getValue() { return $this->value; } |   public function getValue() { return $this->value; } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -13,9 +13,9 @@ use \Driver\SQL\Column\DateTimeColumn; | |||||||
| use Driver\SQL\Column\BoolColumn; | use Driver\SQL\Column\BoolColumn; | ||||||
| use Driver\SQL\Column\JsonColumn; | use Driver\SQL\Column\JsonColumn; | ||||||
| 
 | 
 | ||||||
| use \Driver\SQL\Strategy\CascadeStrategy; | use Driver\SQL\Condition\CondRegex; | ||||||
| use \Driver\SQL\Strategy\SetDefaultStrategy; | use Driver\SQL\Expression\Add; | ||||||
| use \Driver\SQL\Strategy\SetNullStrategy; | use Driver\SQL\Strategy\Strategy; | ||||||
| use \Driver\SQL\Strategy\UpdateStrategy; | use \Driver\SQL\Strategy\UpdateStrategy; | ||||||
| 
 | 
 | ||||||
| class MySQL extends SQL { | class MySQL extends SQL { | ||||||
| @ -32,7 +32,7 @@ class MySQL extends SQL { | |||||||
|     return 'mysqli'; |     return 'mysqli'; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Connection Managment
 |   // Connection Management
 | ||||||
|   public function connect() { |   public function connect() { | ||||||
| 
 | 
 | ||||||
|     if(!is_null($this->connection)) { |     if(!is_null($this->connection)) { | ||||||
| @ -47,7 +47,7 @@ class MySQL extends SQL { | |||||||
|       $this->connectionData->getPort() |       $this->connectionData->getPort() | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     if (mysqli_connect_errno($this->connection)) { |     if (mysqli_connect_errno()) { | ||||||
|       $this->lastError = "Failed to connect to MySQL: " . mysqli_connect_error(); |       $this->lastError = "Failed to connect to MySQL: " . mysqli_connect_error(); | ||||||
|       $this->connection = NULL; |       $this->connection = NULL; | ||||||
|       return false; |       return false; | ||||||
| @ -63,6 +63,7 @@ class MySQL extends SQL { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     mysqli_close($this->connection); |     mysqli_close($this->connection); | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getLastError() { |   public function getLastError() { | ||||||
| @ -81,6 +82,8 @@ class MySQL extends SQL { | |||||||
|       switch($paramType) { |       switch($paramType) { | ||||||
|         case Parameter::TYPE_BOOLEAN: |         case Parameter::TYPE_BOOLEAN: | ||||||
|           $value = $value ? 1 : 0; |           $value = $value ? 1 : 0; | ||||||
|  |           $sqlParams[0] .= 'i'; | ||||||
|  |           break; | ||||||
|         case Parameter::TYPE_INT: |         case Parameter::TYPE_INT: | ||||||
|           $sqlParams[0] .= 'i'; |           $sqlParams[0] .= 'i'; | ||||||
|           break; |           break; | ||||||
| @ -99,6 +102,10 @@ class MySQL extends SQL { | |||||||
|           $value = $value->format('Y-m-d H:i:s'); |           $value = $value->format('Y-m-d H:i:s'); | ||||||
|           $sqlParams[0] .= 's'; |           $sqlParams[0] .= 's'; | ||||||
|           break; |           break; | ||||||
|  |         case Parameter::TYPE_ARRAY: | ||||||
|  |           $value = json_encode($value); | ||||||
|  |           $sqlParams[0] .= 's'; | ||||||
|  |           break; | ||||||
|         case Parameter::TYPE_EMAIL: |         case Parameter::TYPE_EMAIL: | ||||||
|         default: |         default: | ||||||
|           $sqlParams[0] .= 's'; |           $sqlParams[0] .= 's'; | ||||||
| @ -161,64 +168,39 @@ class MySQL extends SQL { | |||||||
|     return ($success && $returnValues) ? $resultRows : $success; |     return ($success && $returnValues) ? $resultRows : $success; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function executeInsert($insert) { |   protected function getOnDuplicateStrategy(?Strategy $strategy, &$params) { | ||||||
|     $tableName = $this->tableName($insert->getTableName()); |     if (is_null($strategy)) { | ||||||
|     $columns = $insert->getColumns(); |       return ""; | ||||||
|     $rows = $insert->getRows(); |     } else if ($strategy instanceof UpdateStrategy) { | ||||||
|     $onDuplicateKey = $insert->onDuplicateKey() ?? ""; |  | ||||||
| 
 |  | ||||||
|     if (empty($rows)) { |  | ||||||
|       $this->lastError = "No rows to insert given."; |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (is_null($columns) || empty($columns)) { |  | ||||||
|       $columns = ""; |  | ||||||
|       $numColumns = count($rows[0]); |  | ||||||
|     } else { |  | ||||||
|       $numColumns = count($columns); |  | ||||||
|       $columns = " (" . $this->columnName($columns) . ")"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $numRows = count($rows); |  | ||||||
|     $parameters = array(); |  | ||||||
|     $values = implode(",", array_fill(0, $numRows, "(" . implode(",", array_fill(0, $numColumns, "?")) . ")")); |  | ||||||
| 
 |  | ||||||
|     foreach($rows as $row) { |  | ||||||
|       $parameters = array_merge($parameters, $row); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if ($onDuplicateKey) { |  | ||||||
|       if ($onDuplicateKey instanceof UpdateStrategy) { |  | ||||||
|       $updateValues = array(); |       $updateValues = array(); | ||||||
|         foreach($onDuplicateKey->getValues() as $key => $value) { |       foreach($strategy->getValues() as $key => $value) { | ||||||
|  |         $leftColumn = $this->columnName($key); | ||||||
|         if ($value instanceof Column) { |         if ($value instanceof Column) { | ||||||
|             $columnName = $value->getName(); |           $columnName = $this->columnName($value->getName()); | ||||||
|             $updateValues[] = "`$key`=`$columnName`"; |           $updateValues[] = "$leftColumn=VALUES($columnName)"; | ||||||
|  |         } else if($value instanceof Add) { | ||||||
|  |           $columnName = $this->columnName($value->getColumn()); | ||||||
|  |           $operator = $value->getOperator(); | ||||||
|  |           $value = $value->getValue(); | ||||||
|  |           $updateValues[] = "$leftColumn=$columnName$operator" . $this->addValue($value, $params); | ||||||
|         } else { |         } else { | ||||||
|             $updateValues[] = "`$key`=" . $this->addValue($value, $parameters); |           $updateValues[] = "$leftColumn=" . $this->addValue($value, $params); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|         $onDuplicateKey = " ON DUPLICATE KEY UPDATE " . implode(",", $updateValues); |       return " ON DUPLICATE KEY UPDATE " . implode(",", $updateValues); | ||||||
|     } else { |     } else { | ||||||
|         $strategy = get_class($onDuplicateKey); |       $strategyClass = get_class($strategy); | ||||||
|         $this->lastError = "ON DUPLICATE Strategy $strategy is not supported yet."; |       $this->lastError = "ON DUPLICATE Strategy $strategyClass is not supported yet."; | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|     $query = "INSERT INTO $tableName$columns VALUES$values$onDuplicateKey"; |   protected function fetchReturning($res, string $returningCol) { | ||||||
|     $success = $this->execute($query, $parameters); |  | ||||||
| 
 |  | ||||||
|     if($success) { |  | ||||||
|     $this->lastInsertId = mysqli_insert_id($this->connection); |     $this->lastInsertId = mysqli_insert_id($this->connection); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|     return $success; |   public function getColumnDefinition(Column $column) { | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function getColumnDefinition($column) { |  | ||||||
|     $columnName = $this->columnName($column->getName()); |     $columnName = $this->columnName($column->getName()); | ||||||
|     $defaultValue = $column->getDefaultValue(); |     $defaultValue = $column->getDefaultValue(); | ||||||
| 
 | 
 | ||||||
| @ -255,7 +237,7 @@ class MySQL extends SQL { | |||||||
| 
 | 
 | ||||||
|     $notNull = $column->notNull() ? " NOT NULL" : ""; |     $notNull = $column->notNull() ? " NOT NULL" : ""; | ||||||
|     if (!is_null($defaultValue) || !$column->notNull()) { |     if (!is_null($defaultValue) || !$column->notNull()) { | ||||||
|       $defaultValue = " DEFAULT " . $this->getValueDefinition($column->getDefaultValue()); |       $defaultValue = " DEFAULT " . $this->getValueDefinition($defaultValue); | ||||||
|     } else { |     } else { | ||||||
|       $defaultValue = ""; |       $defaultValue = ""; | ||||||
|     } |     } | ||||||
| @ -323,4 +305,7 @@ class MySQL extends SQL { | |||||||
|     return new Keyword("NOW()"); |     return new Keyword("NOW()"); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| }; |   public function getStatus() { | ||||||
|  |     return mysqli_stat($this->connection); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ namespace Driver\SQL; | |||||||
| 
 | 
 | ||||||
| use \Api\Parameter\Parameter; | use \Api\Parameter\Parameter; | ||||||
| 
 | 
 | ||||||
| use \Driver\SQL\Column\Column; | use Driver\SQL\Column\Column; | ||||||
| use \Driver\SQL\Column\IntColumn; | use \Driver\SQL\Column\IntColumn; | ||||||
| use \Driver\SQL\Column\SerialColumn; | use \Driver\SQL\Column\SerialColumn; | ||||||
| use \Driver\SQL\Column\StringColumn; | use \Driver\SQL\Column\StringColumn; | ||||||
| @ -13,10 +13,10 @@ use \Driver\SQL\Column\DateTimeColumn; | |||||||
| use Driver\SQL\Column\BoolColumn; | use Driver\SQL\Column\BoolColumn; | ||||||
| use Driver\SQL\Column\JsonColumn; | use Driver\SQL\Column\JsonColumn; | ||||||
| 
 | 
 | ||||||
| use \Driver\SQL\Strategy\CascadeStrategy; | use Driver\SQL\Condition\CondRegex; | ||||||
| use \Driver\SQL\Strategy\SetDefaultStrategy; | use Driver\SQL\Expression\Add; | ||||||
| use \Driver\SQL\Strategy\SetNullStrategy; | use Driver\SQL\Strategy\Strategy; | ||||||
| use \Driver\SQL\Strategy\UpdateStrategy; | use Driver\SQL\Strategy\UpdateStrategy; | ||||||
| 
 | 
 | ||||||
| class PostgreSQL extends SQL { | class PostgreSQL extends SQL { | ||||||
| 
 | 
 | ||||||
| @ -32,7 +32,7 @@ class PostgreSQL extends SQL { | |||||||
|     return 'pgsql'; |     return 'pgsql'; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Connection Managment
 |   // Connection Management
 | ||||||
|   public function connect() { |   public function connect() { | ||||||
|     if(!is_null($this->connection)) { |     if(!is_null($this->connection)) { | ||||||
|       return true; |       return true; | ||||||
| @ -68,13 +68,13 @@ class PostgreSQL extends SQL { | |||||||
|     if(is_null($this->connection)) |     if(is_null($this->connection)) | ||||||
|       return; |       return; | ||||||
| 
 | 
 | ||||||
|     pg_close($this->connection); |     @pg_close($this->connection); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getLastError() { |   public function getLastError() { | ||||||
|     $lastError = parent::getLastError(); |     $lastError = parent::getLastError(); | ||||||
|     if (empty($lastError)) { |     if (empty($lastError)) { | ||||||
|       $lastError = pg_last_error($this->connection) . " " . pg_last_error($this->connection); |       $lastError = trim(pg_last_error($this->connection) . " " . pg_last_error($this->connection)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return $lastError; |     return $lastError; | ||||||
| @ -99,6 +99,9 @@ class PostgreSQL extends SQL { | |||||||
|           case Parameter::TYPE_DATE_TIME: |           case Parameter::TYPE_DATE_TIME: | ||||||
|             $value = $value->format("Y-m-d H:i:s"); |             $value = $value->format("Y-m-d H:i:s"); | ||||||
|             break; |             break; | ||||||
|  |           case Parameter::TYPE_ARRAY: | ||||||
|  |             $value = json_encode($value); | ||||||
|  |             break; | ||||||
|           default: |           default: | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @ -131,76 +134,48 @@ class PostgreSQL extends SQL { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Querybuilder
 |   protected function getOnDuplicateStrategy(?Strategy $strategy, &$params) { | ||||||
|   public function executeInsert($insert) { |       if (!is_null($strategy)) { | ||||||
| 
 |         if ($strategy instanceof UpdateStrategy) { | ||||||
|     $tableName = $this->tableName($insert->getTableName()); |  | ||||||
|     $columns = $insert->getColumns(); |  | ||||||
|     $rows = $insert->getRows(); |  | ||||||
|     $onDuplicateKey = $insert->onDuplicateKey() ?? ""; |  | ||||||
| 
 |  | ||||||
|     if (empty($rows)) { |  | ||||||
|       $this->lastError = "No rows to insert given."; |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (is_null($columns) || empty($columns)) { |  | ||||||
|       $columnStr = ""; |  | ||||||
|     } else { |  | ||||||
|       $columnStr = " (" . $this->columnName($columns) . ")"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $numRows = count($rows); |  | ||||||
|     $parameters = array(); |  | ||||||
| 
 |  | ||||||
|     $values = array(); |  | ||||||
|     foreach($rows as $row) { |  | ||||||
|       $rowPlaceHolder = array(); |  | ||||||
|       foreach($row as $val) { |  | ||||||
|         $rowPlaceHolder[] = $this->addValue($val, $parameters); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       $values[] = "(" . implode(",", $rowPlaceHolder) . ")"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $values = implode(",", $values); |  | ||||||
| 
 |  | ||||||
|     if ($onDuplicateKey) { |  | ||||||
|       /*if ($onDuplicateKey instanceof UpdateStrategy) { |  | ||||||
|               $updateValues = array(); |               $updateValues = array(); | ||||||
|         foreach($onDuplicateKey->getValues() as $key => $value) { |               foreach($strategy->getValues() as $key => $value) { | ||||||
|  |                 $leftColumn = $this->columnName($key); | ||||||
|                 if ($value instanceof Column) { |                 if ($value instanceof Column) { | ||||||
|             $columnName = $value->getName(); |                   $columnName = $this->columnName($value->getName()); | ||||||
|             $updateValues[] = "\"$key\"=\"$columnName\"";
 |                   $updateValues[] = "$leftColumn=EXCLUDED.$columnName"; | ||||||
|  |                 } else if ($value instanceof Add) { | ||||||
|  |                   $columnName = $this->columnName($value->getColumn()); | ||||||
|  |                   $operator = $value->getOperator(); | ||||||
|  |                   $value = $value->getValue(); | ||||||
|  |                   $updateValues[] = "$leftColumn=$columnName$operator" . $this->addValue($value, $params); | ||||||
|                 } else { |                 } else { | ||||||
|             $updateValues[] = "\"$key\"=" . $this->addValue($value, $parameters);
 |                   $updateValues[] = "$leftColumn=" . $this->addValue($value, $parameters); | ||||||
|                 } |                 } | ||||||
|               } |               } | ||||||
| 
 | 
 | ||||||
|         $onDuplicateKey = " ON CONFLICT DO UPDATE SET " . implode(",", $updateValues); |               $conflictingColumns = $this->columnName($strategy->getConflictingColumns()); | ||||||
|       } else*/ { |               $updateValues = implode(",", $updateValues); | ||||||
|         $strategy = get_class($onDuplicateKey); |               return " ON CONFLICT ($conflictingColumns) DO UPDATE SET $updateValues"; | ||||||
|         $this->lastError = "ON DUPLICATE Strategy $strategy is not supported yet."; |           } else { | ||||||
|  |             $strategyClass = get_class($strategy); | ||||||
|  |             $this->lastError = "ON DUPLICATE Strategy $strategyClass is not supported yet."; | ||||||
|            return false; |            return false; | ||||||
|           } |           } | ||||||
|  |       } else { | ||||||
|  |         return ""; | ||||||
|  |       } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|     $returningCol = $insert->getReturning(); |   protected function getReturning(?string $columns) { | ||||||
|     $returning = $returningCol ? (" RETURNING " . $this->columnName($returningCol)) : ""; |     return $columns ? (" RETURNING " . $this->columnName($columns)) : ""; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     $query = "INSERT INTO $tableName$columnStr VALUES$values$onDuplicateKey$returning"; |   protected function fetchReturning($res, string $returningCol) { | ||||||
|     $res = $this->execute($query, $parameters, !empty($returning)); |  | ||||||
|     $success = ($res !== FALSE); |  | ||||||
| 
 |  | ||||||
|     if($success && !empty($returning)) { |  | ||||||
|     $this->lastInsertId = $res[0][$returningCol]; |     $this->lastInsertId = $res[0][$returningCol]; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|     return $success; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // UGLY but.. what should i do?
 |   // UGLY but.. what should i do?
 | ||||||
|   private function createEnum($enumColumn) { |   private function createEnum(EnumColumn $enumColumn) { | ||||||
|     $typeName = $enumColumn->getName(); |     $typeName = $enumColumn->getName(); | ||||||
|     if(!endsWith($typeName, "_type")) { |     if(!endsWith($typeName, "_type")) { | ||||||
|       $typeName = "${typeName}_type"; |       $typeName = "${typeName}_type"; | ||||||
| @ -319,5 +294,27 @@ class PostgreSQL extends SQL { | |||||||
|   public function currentTimestamp() { |   public function currentTimestamp() { | ||||||
|     return new Keyword("CURRENT_TIMESTAMP"); |     return new Keyword("CURRENT_TIMESTAMP"); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   public function getStatus() { | ||||||
|  |     $version = pg_version($this->connection)["client"] ?? "??"; | ||||||
|  |     $status = pg_connection_status($this->connection); | ||||||
|  |     static $statusTexts = array( | ||||||
|  |       PGSQL_CONNECTION_OK => "PGSQL_CONNECTION_OK", | ||||||
|  |       PGSQL_CONNECTION_BAD => "PGSQL_CONNECTION_BAD", | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     return ($statusTexts[$status] ?? "Unknown") . " (v$version)"; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function buildCondition($condition, &$params) { | ||||||
|  |     if($condition instanceof CondRegex) { | ||||||
|  |       $left = $condition->getLeftExp(); | ||||||
|  |       $right = $condition->getRightExp(); | ||||||
|  |       $left = ($left instanceof Column) ? $this->columnName($left->getName()) : $this->addValue($left, $params); | ||||||
|  |       $right = ($right instanceof Column) ? $this->columnName($right->getName()) : $this->addValue($right, $params); | ||||||
|  |       return $left . " ~ " . $right; | ||||||
|  |     } else { | ||||||
|  |       return parent::buildCondition($condition, $params); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -16,10 +16,10 @@ use Driver\SQL\Constraint\ForeignKey; | |||||||
| 
 | 
 | ||||||
| class CreateTable extends Query { | class CreateTable extends Query { | ||||||
| 
 | 
 | ||||||
|   private $tableName; |   private string $tableName; | ||||||
|   private $columns; |   private array $columns; | ||||||
|   private $constraints; |   private array $constraints; | ||||||
|   private $ifNotExists; |   private bool $ifNotExists; | ||||||
| 
 | 
 | ||||||
|   public function __construct($sql, $name) { |   public function __construct($sql, $name) { | ||||||
|     parent::__construct($sql); |     parent::__construct($sql); | ||||||
| @ -92,6 +92,4 @@ class CreateTable extends Query { | |||||||
|   public function getTableName() { return $this->tableName; } |   public function getTableName() { return $this->tableName; } | ||||||
|   public function getColumns() { return $this->columns; } |   public function getColumns() { return $this->columns; } | ||||||
|   public function getConstraints() { return $this->constraints; } |   public function getConstraints() { return $this->constraints; } | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -2,10 +2,12 @@ | |||||||
| 
 | 
 | ||||||
| namespace Driver\SQL\Query; | namespace Driver\SQL\Query; | ||||||
| 
 | 
 | ||||||
|  | use Driver\SQL\Condition\CondOr; | ||||||
|  | 
 | ||||||
| class Delete extends Query { | class Delete extends Query { | ||||||
| 
 | 
 | ||||||
|   private $table; |   private string $table; | ||||||
|   private $conditions; |   private array $conditions; | ||||||
| 
 | 
 | ||||||
|   public function __construct($sql, $table) { |   public function __construct($sql, $table) { | ||||||
|     parent::__construct($sql); |     parent::__construct($sql); | ||||||
| @ -14,7 +16,7 @@ class Delete extends Query { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function where(...$conditions) { |   public function where(...$conditions) { | ||||||
|     $this->conditions = array_merge($this->conditions, $conditions); |     $this->conditions[] = (count($conditions) === 1 ? $conditions : new CondOr($conditions)); | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -24,6 +26,4 @@ class Delete extends Query { | |||||||
| 
 | 
 | ||||||
|   public function getTable() { return $this->table; } |   public function getTable() { return $this->table; } | ||||||
|   public function getConditions() { return $this->conditions; } |   public function getConditions() { return $this->conditions; } | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -2,13 +2,15 @@ | |||||||
| 
 | 
 | ||||||
| namespace Driver\SQL\Query; | namespace Driver\SQL\Query; | ||||||
| 
 | 
 | ||||||
|  | use Driver\SQL\Strategy\Strategy; | ||||||
|  | 
 | ||||||
| class Insert extends Query { | class Insert extends Query { | ||||||
| 
 | 
 | ||||||
|   private $tableName; |   private string $tableName; | ||||||
|   private $columns; |   private array $columns; | ||||||
|   private $rows; |   private array $rows; | ||||||
|   private $onDuplicateKey; |   private ?Strategy $onDuplicateKey; | ||||||
|   private $returning; |   private ?string $returning; | ||||||
| 
 | 
 | ||||||
|   public function __construct($sql, $name, $columns=array()) { |   public function __construct($sql, $name, $columns=array()) { | ||||||
|     parent::__construct($sql); |     parent::__construct($sql); | ||||||
| @ -43,6 +45,4 @@ class Insert extends Query { | |||||||
|   public function getRows() { return $this->rows; } |   public function getRows() { return $this->rows; } | ||||||
|   public function onDuplicateKey() { return $this->onDuplicateKey; } |   public function onDuplicateKey() { return $this->onDuplicateKey; } | ||||||
|   public function getReturning() { return $this->returning; } |   public function getReturning() { return $this->returning; } | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -2,16 +2,23 @@ | |||||||
| 
 | 
 | ||||||
| namespace Driver\SQL\Query; | namespace Driver\SQL\Query; | ||||||
| 
 | 
 | ||||||
|  | use Driver\SQL\SQL; | ||||||
|  | 
 | ||||||
| abstract class Query { | abstract class Query { | ||||||
| 
 | 
 | ||||||
|   protected $sql; |   protected SQL $sql; | ||||||
|  |   public bool $dump; | ||||||
| 
 | 
 | ||||||
|   public function __construct($sql) { |   public function __construct($sql) { | ||||||
|     $this->sql = $sql; |     $this->sql = $sql; | ||||||
|  |     $this->dump = false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function dump() { | ||||||
|  |     $this->dump = true; | ||||||
|  |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public abstract function execute(); |   public abstract function execute(); | ||||||
| 
 | 
 | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -2,16 +2,20 @@ | |||||||
| 
 | 
 | ||||||
| namespace Driver\SQL\Query; | namespace Driver\SQL\Query; | ||||||
| 
 | 
 | ||||||
|  | use Driver\SQL\Condition\CondOr; | ||||||
|  | use Driver\SQL\Join; | ||||||
|  | 
 | ||||||
| class Select extends Query { | class Select extends Query { | ||||||
| 
 | 
 | ||||||
|   private $columns; |   private array $columns; | ||||||
|   private $tables; |   private array $tables; | ||||||
|   private $conditions; |   private array $conditions; | ||||||
|   private $joins; |   private array $joins; | ||||||
|   private $orderColumns; |   private array $orderColumns; | ||||||
|   private $sortAscending; |   private array $groupColumns; | ||||||
|   private $limit; |   private bool $sortAscending; | ||||||
|   private $offset; |   private int $limit; | ||||||
|  |   private int $offset; | ||||||
| 
 | 
 | ||||||
|   public function __construct($sql, ...$columns) { |   public function __construct($sql, ...$columns) { | ||||||
|     parent::__construct($sql); |     parent::__construct($sql); | ||||||
| @ -20,6 +24,7 @@ class Select extends Query { | |||||||
|     $this->conditions = array(); |     $this->conditions = array(); | ||||||
|     $this->joins = array(); |     $this->joins = array(); | ||||||
|     $this->orderColumns = array(); |     $this->orderColumns = array(); | ||||||
|  |     $this->groupColumns = array(); | ||||||
|     $this->limit = 0; |     $this->limit = 0; | ||||||
|     $this->offset = 0; |     $this->offset = 0; | ||||||
|     $this->sortAscending = true; |     $this->sortAscending = true; | ||||||
| @ -31,17 +36,22 @@ class Select extends Query { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function where(...$conditions) { |   public function where(...$conditions) { | ||||||
|     $this->conditions = array_merge($this->conditions, $conditions); |     $this->conditions[] = (count($conditions) === 1 ? $conditions : new CondOr($conditions)); | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function innerJoin($table, $columnA, $columnB) { |   public function innerJoin($table, $columnA, $columnB) { | ||||||
|     $this->joins[] = new \Driver\SQL\Join("INNER", $table, $columnA, $columnB); |     $this->joins[] = new Join("INNER", $table, $columnA, $columnB); | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function leftJoin($table, $columnA, $columnB) { |   public function leftJoin($table, $columnA, $columnB) { | ||||||
|     $this->joins[] = new \Driver\SQL\Join("LEFT", $table, $columnA, $columnB); |     $this->joins[] = new Join("LEFT", $table, $columnA, $columnB); | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function groupBy(...$columns) { | ||||||
|  |     $this->groupColumns = $columns; | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -51,12 +61,12 @@ class Select extends Query { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function ascending() { |   public function ascending() { | ||||||
|     $this->ascending = true; |     $this->sortAscending = true; | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function descending() { |   public function descending() { | ||||||
|     $this->ascending = false; |     $this->sortAscending = false; | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -78,11 +88,10 @@ class Select extends Query { | |||||||
|   public function getTables() { return $this->tables; } |   public function getTables() { return $this->tables; } | ||||||
|   public function getConditions() { return $this->conditions; } |   public function getConditions() { return $this->conditions; } | ||||||
|   public function getJoins() { return $this->joins; } |   public function getJoins() { return $this->joins; } | ||||||
|   public function isOrderedAscending() { return $this->ascending; } |   public function isOrderedAscending() { return $this->sortAscending; } | ||||||
|   public function getOrderBy() { return $this->orderColumns; } |   public function getOrderBy() { return $this->orderColumns; } | ||||||
|   public function getLimit() { return $this->limit; } |   public function getLimit() { return $this->limit; } | ||||||
|   public function getOffset() { return $this->offset; } |   public function getOffset() { return $this->offset; } | ||||||
|  |   public function getGroupBy() { return $this->groupColumns; } | ||||||
| 
 | 
 | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -4,7 +4,7 @@ namespace Driver\SQL\Query; | |||||||
| 
 | 
 | ||||||
| class Truncate extends Query { | class Truncate extends Query { | ||||||
| 
 | 
 | ||||||
|   private $tableName; |   private string $tableName; | ||||||
| 
 | 
 | ||||||
|   public function __construct($sql, $name) { |   public function __construct($sql, $name) { | ||||||
|     parent::__construct($sql); |     parent::__construct($sql); | ||||||
| @ -15,7 +15,5 @@ class Truncate extends Query { | |||||||
|     return $this->sql->executeTruncate($this); |     return $this->sql->executeTruncate($this); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getTableName() { return $this->tableName; } |   public function getTable() { return $this->tableName; } | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -2,11 +2,13 @@ | |||||||
| 
 | 
 | ||||||
| namespace Driver\SQL\Query; | namespace Driver\SQL\Query; | ||||||
| 
 | 
 | ||||||
|  | use Driver\SQL\Condition\CondOr; | ||||||
|  | 
 | ||||||
| class Update extends Query { | class Update extends Query { | ||||||
| 
 | 
 | ||||||
|   private $values; |   private array $values; | ||||||
|   private $table; |   private string $table; | ||||||
|   private $conditions; |   private array $conditions; | ||||||
| 
 | 
 | ||||||
|   public function __construct($sql, $table) { |   public function __construct($sql, $table) { | ||||||
|     parent::__construct($sql); |     parent::__construct($sql); | ||||||
| @ -16,7 +18,7 @@ class Update extends Query { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function where(...$conditions) { |   public function where(...$conditions) { | ||||||
|     $this->conditions = array_merge($this->conditions, $conditions); |     $this->conditions[] = (count($conditions) === 1 ? $conditions : new CondOr($conditions)); | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -32,6 +34,4 @@ class Update extends Query { | |||||||
|   public function getTable() { return $this->table; } |   public function getTable() { return $this->table; } | ||||||
|   public function getConditions() { return $this->conditions; } |   public function getConditions() { return $this->conditions; } | ||||||
|   public function getValues() { return $this->values; } |   public function getValues() { return $this->values; } | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -2,16 +2,37 @@ | |||||||
| 
 | 
 | ||||||
| namespace Driver\SQL; | namespace Driver\SQL; | ||||||
| 
 | 
 | ||||||
|  | use Driver\SQL\Column\Column; | ||||||
|  | use Driver\SQL\Condition\Compare; | ||||||
|  | use Driver\SQL\Condition\CondBool; | ||||||
|  | use Driver\SQL\Condition\CondIn; | ||||||
|  | use Driver\SQL\Condition\Condition; | ||||||
|  | use Driver\SQL\Condition\CondKeyword; | ||||||
|  | use Driver\SQL\Condition\CondNot; | ||||||
|  | use Driver\SQL\Condition\CondOr; | ||||||
|  | use Driver\SQL\Constraint\Constraint; | ||||||
| use \Driver\SQL\Constraint\Unique; | use \Driver\SQL\Constraint\Unique; | ||||||
| use \Driver\SQL\Constraint\PrimaryKey; | use \Driver\SQL\Constraint\PrimaryKey; | ||||||
| use \Driver\SQL\Constraint\ForeignKey; | use \Driver\SQL\Constraint\ForeignKey; | ||||||
|  | use Driver\SQL\Query\CreateTable; | ||||||
|  | use Driver\SQL\Query\Delete; | ||||||
|  | use Driver\SQL\Query\Insert; | ||||||
|  | use Driver\SQL\Query\Query; | ||||||
|  | use Driver\SQL\Query\Select; | ||||||
|  | use Driver\SQL\Query\Truncate; | ||||||
|  | use Driver\SQL\Query\Update; | ||||||
|  | use Driver\SQL\Strategy\CascadeStrategy; | ||||||
|  | use Driver\SQL\Strategy\SetDefaultStrategy; | ||||||
|  | use Driver\SQL\Strategy\SetNullStrategy; | ||||||
|  | use Driver\SQL\Strategy\Strategy; | ||||||
|  | use Objects\ConnectionData; | ||||||
| 
 | 
 | ||||||
| abstract class SQL { | abstract class SQL { | ||||||
| 
 | 
 | ||||||
|   protected $lastError; |   protected string $lastError; | ||||||
|   protected $connection; |   protected $connection; | ||||||
|   protected $connectionData; |   protected ConnectionData $connectionData; | ||||||
|   protected $lastInsertId; |   protected int $lastInsertId; | ||||||
| 
 | 
 | ||||||
|   public function __construct($connectionData) { |   public function __construct($connectionData) { | ||||||
|     $this->connection = NULL; |     $this->connection = NULL; | ||||||
| @ -29,27 +50,27 @@ abstract class SQL { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function createTable($tableName) { |   public function createTable($tableName) { | ||||||
|     return new Query\CreateTable($this, $tableName); |     return new CreateTable($this, $tableName); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function insert($tableName, $columns=array()) { |   public function insert($tableName, $columns=array()) { | ||||||
|     return new Query\Insert($this, $tableName, $columns); |     return new Insert($this, $tableName, $columns); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function select(...$columNames) { |   public function select(...$columNames) { | ||||||
|     return new Query\Select($this, $columNames); |     return new Select($this, $columNames); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function truncate($table) { |   public function truncate($table) { | ||||||
|     return new Query\Truncate($this, $table); |     return new Truncate($this, $table); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function delete($table) { |   public function delete($table) { | ||||||
|     return new Query\Delete($this, $table); |     return new Delete($this, $table); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function update($table) { |   public function update($table) { | ||||||
|     return new Query\Update($this, $table); |     return new Update($this, $table); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // ####################
 |   // ####################
 | ||||||
| @ -65,7 +86,54 @@ abstract class SQL { | |||||||
|   public abstract function disconnect(); |   public abstract function disconnect(); | ||||||
| 
 | 
 | ||||||
|   // Querybuilder
 |   // Querybuilder
 | ||||||
|   public function executeCreateTable($createTable) { |   protected function buildQuery(Query $query, array &$params) { | ||||||
|  |     if ($query instanceof Select) { | ||||||
|  |       $select = $query; | ||||||
|  |       $columns = $this->columnName($select->getColumns()); | ||||||
|  |       $tables = $select->getTables(); | ||||||
|  | 
 | ||||||
|  |       if (!$tables) { | ||||||
|  |         return $this->execute("SELECT $columns", $params, true); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $tables = $this->tableName($tables); | ||||||
|  |       $where = $this->getWhereClause($select->getConditions(), $params); | ||||||
|  | 
 | ||||||
|  |       $joinStr = ""; | ||||||
|  |       $joins = $select->getJoins(); | ||||||
|  |       if (!empty($joins)) { | ||||||
|  |         foreach($joins as $join) { | ||||||
|  |           $type = $join->getType(); | ||||||
|  |           $joinTable = $this->tableName($join->getTable()); | ||||||
|  |           $columnA = $this->columnName($join->getColumnA()); | ||||||
|  |           $columnB = $this->columnName($join->getColumnB()); | ||||||
|  |           $joinStr .= " $type JOIN $joinTable ON $columnA=$columnB"; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $groupBy = ""; | ||||||
|  |       $groupColumns = $select->getGroupBy(); | ||||||
|  |       if (!empty($groupColumns)) { | ||||||
|  |         $groupBy = " GROUP BY " . $this->columnName($groupColumns); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $orderBy = ""; | ||||||
|  |       $orderColumns = $select->getOrderBy(); | ||||||
|  |       if (!empty($orderColumns)) { | ||||||
|  |         $orderBy = " ORDER BY " . $this->columnName($orderColumns); | ||||||
|  |         $orderBy .= ($select->isOrderedAscending() ? " ASC" : " DESC"); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $limit = ($select->getLimit() > 0 ? (" LIMIT " . $select->getLimit()) : ""); | ||||||
|  |       $offset = ($select->getOffset() > 0 ? (" OFFSET " . $select->getOffset()) : ""); | ||||||
|  |       return "SELECT $columns FROM $tables$joinStr$where$groupBy$orderBy$limit$offset"; | ||||||
|  |     } else { | ||||||
|  |       $this->lastError = "buildQuery() not implemented for type: " . get_class($query); | ||||||
|  |       return FALSE; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function executeCreateTable(CreateTable $createTable) { | ||||||
|     $tableName = $this->tableName($createTable->getTableName()); |     $tableName = $this->tableName($createTable->getTableName()); | ||||||
|     $ifNotExists = $createTable->ifNotExists() ? " IF NOT EXISTS": ""; |     $ifNotExists = $createTable->ifNotExists() ? " IF NOT EXISTS": ""; | ||||||
| 
 | 
 | ||||||
| @ -89,73 +157,94 @@ abstract class SQL { | |||||||
|     return $this->execute($query); |     return $this->execute($query); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // TODO pull this function up
 |   public function executeInsert(Insert $insert) { | ||||||
|   public abstract function executeInsert($query); |  | ||||||
| 
 | 
 | ||||||
|   public function executeSelect($select) { |     $tableName = $this->tableName($insert->getTableName()); | ||||||
|  |     $columns = $insert->getColumns(); | ||||||
|  |     $rows = $insert->getRows(); | ||||||
| 
 | 
 | ||||||
|     $columns = $this->columnName($select->getColumns()); |     if (empty($rows)) { | ||||||
|     $tables = $select->getTables(); |       $this->lastError = "No rows to insert given."; | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (is_null($columns) || empty($columns)) { | ||||||
|  |       $columnStr = ""; | ||||||
|  |     } else { | ||||||
|  |       $columnStr = " (" . $this->columnName($columns) . ")"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     $parameters = array(); | ||||||
|  |     $values = array(); | ||||||
|  |     foreach($rows as $row) { | ||||||
|  |       $rowPlaceHolder = array(); | ||||||
|  |       foreach($row as $val) { | ||||||
|  |         $rowPlaceHolder[] = $this->addValue($val, $parameters); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       $values[] = "(" . implode(",", $rowPlaceHolder) . ")"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     $values = implode(",", $values); | ||||||
|  | 
 | ||||||
|  |     $onDuplicateKey = $this->getOnDuplicateStrategy($insert->onDuplicateKey(), $parameters); | ||||||
|  |     if ($onDuplicateKey === FALSE) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     $returningCol = $insert->getReturning(); | ||||||
|  |     $returning = $this->getReturning($returningCol); | ||||||
|  | 
 | ||||||
|  |     $query = "INSERT INTO $tableName$columnStr VALUES $values$onDuplicateKey$returning"; | ||||||
|  |     if($insert->dump) { var_dump($query); var_dump($parameters); } | ||||||
|  |     $res = $this->execute($query, $parameters, !empty($returning)); | ||||||
|  |     $success = ($res !== FALSE); | ||||||
|  | 
 | ||||||
|  |     if($success && $returningCol) { | ||||||
|  |       $this->fetchReturning($res, $returningCol); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return $success; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function executeSelect(Select $select) { | ||||||
|     $params = array(); |     $params = array(); | ||||||
| 
 |     $query = $this->buildQuery($select, $params); | ||||||
|     if (!$tables) { |     if($select->dump) { var_dump($query); var_dump($params); } | ||||||
|       return "SELECT $columns"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $tables = $this->tableName($tables); |  | ||||||
|     $where = $this->getWhereClause($select->getConditions(), $params); |  | ||||||
| 
 |  | ||||||
|     $joinStr = ""; |  | ||||||
|     $joins = $select->getJoins(); |  | ||||||
|     if (!empty($joins)) { |  | ||||||
|       foreach($joins as $join) { |  | ||||||
|         $type = $join->getType(); |  | ||||||
|         $joinTable = $this->tableName($join->getTable()); |  | ||||||
|         $columnA = $this->columnName($join->getColumnA()); |  | ||||||
|         $columnB = $this->columnName($join->getColumnB()); |  | ||||||
|         $joinStr .= " $type JOIN $joinTable ON $columnA=$columnB"; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $orderBy = ""; |  | ||||||
|     $orderColumns = $select->getOrderBy(); |  | ||||||
|     if (!empty($orderColumns)) { |  | ||||||
|       $orderBy = " ORDER BY " . $this->columnName($orderColumns); |  | ||||||
|       $orderBy .= ($select->isOrderedAscending() ? " ASC" : " DESC"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $limit = ($select->getLimit() > 0 ? (" LIMIT " . $select->getLimit()) : ""); |  | ||||||
|     $offset = ($select->getOffset() > 0 ? (" OFFSET " . $select->getOffset()) : ""); |  | ||||||
|     $query = "SELECT $columns FROM $tables$joinStr$where$orderBy$limit$offset"; |  | ||||||
|     return $this->execute($query, $params, true); |     return $this->execute($query, $params, true); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function executeDelete($delete) { |   public function executeDelete(Delete $delete) { | ||||||
| 
 | 
 | ||||||
|  |     $params = array(); | ||||||
|     $table = $this->tableName($delete->getTable()); |     $table = $this->tableName($delete->getTable()); | ||||||
|     $where = $this->getWhereClause($delete->getConditions(), $params); |     $where = $this->getWhereClause($delete->getConditions(), $params); | ||||||
| 
 | 
 | ||||||
|     $query = "DELETE FROM $table$where"; |     $query = "DELETE FROM $table$where"; | ||||||
|  |     if($delete->dump) { var_dump($query); } | ||||||
|  |     return $this->execute($query, $params); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function executeTruncate(Truncate $truncate) { | ||||||
|  |     $query = "TRUNCATE " . $this->tableName($truncate->getTable()); | ||||||
|  |     if ($truncate->dump) { var_dump($query); } | ||||||
|     return $this->execute($query); |     return $this->execute($query); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function executeTruncate($truncate) { |   public function executeUpdate(Update $update) { | ||||||
|     return $this->execute("TRUNCATE " . $truncate->getTable()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function executeUpdate($update) { |  | ||||||
| 
 | 
 | ||||||
|     $params = array(); |     $params = array(); | ||||||
|     $table = $this->tableName($update->getTable()); |     $table = $this->tableName($update->getTable()); | ||||||
| 
 | 
 | ||||||
|     $valueStr = array(); |     $valueStr = array(); | ||||||
|     foreach($update->getValues() as $key => $val) { |     foreach($update->getValues() as $key => $val) { | ||||||
|       $valueStr[] = "$key=" . $this->addValue($val, $params); |       $valueStr[] =  $this->columnName($key) . "=" . $this->addValue($val, $params); | ||||||
|     } |     } | ||||||
|     $valueStr = implode(",", $valueStr); |     $valueStr = implode(",", $valueStr); | ||||||
| 
 | 
 | ||||||
|     $where = $this->getWhereClause($update->getConditions(), $params); |     $where = $this->getWhereClause($update->getConditions(), $params); | ||||||
|     $query = "UPDATE $table SET $valueStr$where"; |     $query = "UPDATE $table SET $valueStr$where"; | ||||||
|  |     if($update->dump) { var_dump($query); var_dump($params); } | ||||||
|     return $this->execute($query, $params); |     return $this->execute($query, $params); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -167,10 +256,8 @@ abstract class SQL { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected abstract function getColumnDefinition($column); |   public function getConstraintDefinition(Constraint $constraint) { | ||||||
| 
 |     $columnName = $this->columnName($constraint->getColumnNames()); | ||||||
|   public function getConstraintDefinition($constraint) { |  | ||||||
|     $columnName = $this->columnName($constraint->getColumnName()); |  | ||||||
|     if ($constraint instanceof PrimaryKey) { |     if ($constraint instanceof PrimaryKey) { | ||||||
|       return "PRIMARY KEY ($columnName)"; |       return "PRIMARY KEY ($columnName)"; | ||||||
|     } else if ($constraint instanceof Unique) { |     } else if ($constraint instanceof Unique) { | ||||||
| @ -190,10 +277,19 @@ abstract class SQL { | |||||||
| 
 | 
 | ||||||
|       return $code; |       return $code; | ||||||
|     } else { |     } else { | ||||||
|       $this->lastError = "Unsupported constraint type: " . get_class($strategy); |       $this->lastError = "Unsupported constraint type: " . get_class($constraint); | ||||||
|  |       return false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   protected function getReturning(?string $columns) { | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected abstract function getColumnDefinition(Column $column); | ||||||
|  |   protected abstract function fetchReturning($res, string $returningCol); | ||||||
|  |   protected abstract function getOnDuplicateStrategy(?Strategy $strategy, &$params); | ||||||
|  | 
 | ||||||
|   protected abstract function getValueDefinition($val); |   protected abstract function getValueDefinition($val); | ||||||
|   protected abstract function addValue($val, &$params); |   protected abstract function addValue($val, &$params); | ||||||
| 
 | 
 | ||||||
| @ -201,17 +297,25 @@ abstract class SQL { | |||||||
|   protected abstract function columnName($col); |   protected abstract function columnName($col); | ||||||
| 
 | 
 | ||||||
|   // Special Keywords and functions
 |   // Special Keywords and functions
 | ||||||
|  |   public function now() { return $this->currentTimestamp(); } | ||||||
|   public abstract function currentTimestamp(); |   public abstract function currentTimestamp(); | ||||||
| 
 | 
 | ||||||
|   public function count($col = NULL) { |   public function count($col = NULL) { | ||||||
|     if (is_null($col)) { |     if (is_null($col)) { | ||||||
|       return new Keyword("COUNT(*) AS count"); |       return new Keyword("COUNT(*) AS count"); | ||||||
|     } else { |     } else { | ||||||
|  |       $countCol = strtolower(str_replace(".","_", $col)) .  "_count"; | ||||||
|       $col = $this->columnName($col); |       $col = $this->columnName($col); | ||||||
|       return new Keyword("COUNT($col) AS count"); |       return new Keyword("COUNT($col) AS $countCol"); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public function sum($col) { | ||||||
|  |     $sumCol = strtolower(str_replace(".","_", $col)) .  "_sum"; | ||||||
|  |     $col = $this->columnName($col); | ||||||
|  |     return new Keyword("SUM($col) AS $sumCol"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   public function distinct($col) { |   public function distinct($col) { | ||||||
|     $col = $this->columnName($col); |     $col = $this->columnName($col); | ||||||
|     return new Keyword("DISTINCT($col)"); |     return new Keyword("DISTINCT($col)"); | ||||||
| @ -221,21 +325,22 @@ abstract class SQL { | |||||||
|   protected abstract function execute($query, $values=NULL, $returnValues=false); |   protected abstract function execute($query, $values=NULL, $returnValues=false); | ||||||
| 
 | 
 | ||||||
|   protected function buildCondition($condition, &$params) { |   protected function buildCondition($condition, &$params) { | ||||||
|     if ($condition instanceof \Driver\SQL\Condition\CondOr) { | 
 | ||||||
|  |     if ($condition instanceof CondOr) { | ||||||
|       $conditions = array(); |       $conditions = array(); | ||||||
|       foreach($condition->getConditions() as $cond) { |       foreach($condition->getConditions() as $cond) { | ||||||
|         $conditions[] = $this->buildCondition($cond, $params); |         $conditions[] = $this->buildCondition($cond, $params); | ||||||
|       } |       } | ||||||
|       return "(" . implode(" OR ", $conditions) . ")"; |       return "(" . implode(" OR ", $conditions) . ")"; | ||||||
|     } else if ($condition instanceof \Driver\SQL\Condition\Compare) { |     } else if ($condition instanceof Compare) { | ||||||
|       $column = $this->columnName($condition->getColumn()); |       $column = $this->columnName($condition->getColumn()); | ||||||
|       $value = $condition->getValue(); |       $value = $condition->getValue(); | ||||||
|       $operator = $condition->getOperator(); |       $operator = $condition->getOperator(); | ||||||
|       return $column . $operator . $this->addValue($value, $params); |       return $column . $operator . $this->addValue($value, $params); | ||||||
|     } else if ($condition instanceof \Driver\SQL\Condition\CondBool) { |     } else if ($condition instanceof CondBool) { | ||||||
|       return $this->columnName($condition->getValue()); |       return $this->columnName($condition->getValue()); | ||||||
|     } else if (is_array($condition)) { |     } else if (is_array($condition)) { | ||||||
|       if (count($condition) == 1) { |       if (count($condition) === 1) { | ||||||
|         return $this->buildCondition($condition[0], $params); |         return $this->buildCondition($condition[0], $params); | ||||||
|       } else { |       } else { | ||||||
|         $conditions = array(); |         $conditions = array(); | ||||||
| @ -244,6 +349,43 @@ abstract class SQL { | |||||||
|         } |         } | ||||||
|         return implode(" AND ", $conditions); |         return implode(" AND ", $conditions); | ||||||
|       } |       } | ||||||
|  |     } else if($condition instanceof CondIn) { | ||||||
|  | 
 | ||||||
|  |       $expression = $condition->getExpression(); | ||||||
|  |       if (is_array($expression)) { | ||||||
|  |         $values = array(); | ||||||
|  |         foreach ($expression as $value) { | ||||||
|  |           $values[] = $this->addValue($value, $params); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $values = implode(",", $values); | ||||||
|  |       } else if($expression instanceof Select) { | ||||||
|  |         $values = $this->buildQuery($expression, $params); | ||||||
|  |       } else { | ||||||
|  |         $this->lastError = "Unsupported in-expression value: " . get_class($condition); | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return $this->columnName($condition->getColumn()) . " IN ($values)"; | ||||||
|  |     } else if($condition instanceof CondKeyword) { | ||||||
|  |       $left = $condition->getLeftExp(); | ||||||
|  |       $right = $condition->getRightExp(); | ||||||
|  |       $keyword = $condition->getKeyword(); | ||||||
|  |       $left = ($left instanceof Column) ? $this->columnName($left->getName()) : $this->addValue($left, $params); | ||||||
|  |       $right = ($right instanceof Column) ? $this->columnName($right->getName()) : $this->addValue($right, $params); | ||||||
|  |       return "$left $keyword $right "; | ||||||
|  |     } else if($condition instanceof CondNot) { | ||||||
|  |       $expression = $condition->getExpression(); | ||||||
|  |       if ($expression instanceof Condition) { | ||||||
|  |         $expression = $this->buildCondition($expression, $params); | ||||||
|  |       } else { | ||||||
|  |         $expression = $this->columnName($expression); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       return "NOT $expression"; | ||||||
|  |     } else { | ||||||
|  |       $this->lastError = "Unsupported condition type: " . get_class($condition); | ||||||
|  |       return false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -260,7 +402,7 @@ abstract class SQL { | |||||||
|     $this->connection = NULL; |     $this->connection = NULL; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public static function createConnection($connectionData) { |   public static function createConnection(ConnectionData $connectionData) { | ||||||
|     $type = $connectionData->getProperty("type"); |     $type = $connectionData->getProperty("type"); | ||||||
|     if ($type === "mysql") { |     if ($type === "mysql") { | ||||||
|       $sql = new MySQL($connectionData); |       $sql = new MySQL($connectionData); | ||||||
| @ -279,6 +421,10 @@ abstract class SQL { | |||||||
| 
 | 
 | ||||||
|     return $sql; |     return $sql; | ||||||
|   } |   } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| ?>
 |   public abstract function getStatus(); | ||||||
|  | 
 | ||||||
|  |   public function parseBool($val) : bool { | ||||||
|  |     return in_array($val, array(true, 1, '1', 't', 'true', 'TRUE'), true); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -7,6 +7,4 @@ class CascadeStrategy extends Strategy { | |||||||
|   public function __construct() { |   public function __construct() { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -7,6 +7,4 @@ class SetDefaultStrategy extends Strategy { | |||||||
|   public function __construct() { |   public function __construct() { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -7,6 +7,4 @@ class SetNullStrategy extends Strategy { | |||||||
|   public function __construct() { |   public function __construct() { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -4,6 +4,4 @@ namespace Driver\SQL\Strategy; | |||||||
| 
 | 
 | ||||||
| abstract class Strategy { | abstract class Strategy { | ||||||
| 
 | 
 | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -4,13 +4,17 @@ namespace Driver\SQL\Strategy; | |||||||
| 
 | 
 | ||||||
| class UpdateStrategy extends Strategy { | class UpdateStrategy extends Strategy { | ||||||
| 
 | 
 | ||||||
|   private $values; |   private array $values; | ||||||
|  |   private array $conflictingColumns; | ||||||
| 
 | 
 | ||||||
|   public function __construct($values) { |   public function __construct(array $conflictingColumns, array $values) { | ||||||
|  |     $this->conflictingColumns = $conflictingColumns; | ||||||
|     $this->values = $values; |     $this->values = $values; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getValues() { return $this->values; } |   public function getConflictingColumns() { | ||||||
| }; |     return $this->conflictingColumns; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
| ?>
 |   public function getValues() { return $this->values; } | ||||||
|  | } | ||||||
| @ -2,9 +2,8 @@ | |||||||
| 
 | 
 | ||||||
| namespace Elements; | namespace Elements; | ||||||
| 
 | 
 | ||||||
| abstract class Body extends \View { | abstract class Body extends View { | ||||||
|   public function __construct($document) { |   public function __construct($document) { | ||||||
|     parent::__construct($document); |     parent::__construct($document); | ||||||
|   } |   } | ||||||
| }; | } | ||||||
| ?>
 |  | ||||||
| @ -2,18 +2,22 @@ | |||||||
| 
 | 
 | ||||||
| namespace Elements; | namespace Elements; | ||||||
| 
 | 
 | ||||||
|  | use Objects\User; | ||||||
|  | 
 | ||||||
| abstract class Document { | abstract class Document { | ||||||
| 
 | 
 | ||||||
|   protected $head; |   protected Head $head; | ||||||
|   protected $body; |   protected Body $body; | ||||||
|   protected $user; |   protected User $user; | ||||||
|   protected $databaseRequired; |   protected bool $databaseRequired; | ||||||
|  |   private ?string $activeView; | ||||||
| 
 | 
 | ||||||
|   public function __construct($user, $headClass, $bodyClass) { |   public function __construct(User $user, $headClass, $bodyClass, ?string $view = NULL) { | ||||||
|     $this->head = new $headClass($this); |     $this->head = new $headClass($this); | ||||||
|     $this->body = new $bodyClass($this); |     $this->body = new $bodyClass($this); | ||||||
|     $this->user = $user; |     $this->user = $user; | ||||||
|     $this->databaseRequired = true; |     $this->databaseRequired = true; | ||||||
|  |     $this->activeView = $view; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getHead() { return $this->head; } |   public function getHead() { return $this->head; } | ||||||
| @ -21,36 +25,14 @@ abstract class Document { | |||||||
|   public function getSQL()  { return $this->user->getSQL(); } |   public function getSQL()  { return $this->user->getSQL(); } | ||||||
|   public function getUser() { return $this->user; } |   public function getUser() { return $this->user; } | ||||||
| 
 | 
 | ||||||
|   protected function sendHeaders() { |   public function getView() : ?View { | ||||||
|     header("X-Frame-Options: DENY"); | 
 | ||||||
|  |     $file = getClassPath($this->activeView); | ||||||
|  |     if(!file_exists($file) || !is_subclass_of($this->activeView, View::class)) { | ||||||
|  |       return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   public static function createSearchableDocument($documentClass, $user) { |     return new $this->activeView($this); | ||||||
|     return new $documentClass($user); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public static function createDocument($class) { |  | ||||||
|     // TODO: check instance, configuration, ..
 |  | ||||||
| 
 |  | ||||||
|     require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/sql.php'; |  | ||||||
|     // require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/conf/config.php';
 |  | ||||||
|     // require_once realpath($_SERVER['DOCUMENT_ROOT']) . "/php/pages/$file.php";
 |  | ||||||
|     require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/api/objects/User.php'; |  | ||||||
| 
 |  | ||||||
|     $connectionData = getSqlData($database); |  | ||||||
|     $sql = connectSQL($connectionData); |  | ||||||
|     if(!$sql->isConnected()) { |  | ||||||
|       http_response_code(500); |  | ||||||
|       die('Internal Database error'); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $user = new CUser($sql); |  | ||||||
|     $document = new $class($user); |  | ||||||
|     $code = $document->getCode(); |  | ||||||
| 
 |  | ||||||
|     $document->sendHeaders(); |  | ||||||
|     $user->sendCookies(); |  | ||||||
|     die($code); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function getCode() { |   function getCode() { | ||||||
| @ -66,15 +48,14 @@ abstract class Document { | |||||||
| 
 | 
 | ||||||
|     $body = $this->body->getCode(); |     $body = $this->body->getCode(); | ||||||
|     $head = $this->head->getCode(); |     $head = $this->head->getCode(); | ||||||
|  |     $lang = $this->user->getLanguage()->getShortCode(); | ||||||
| 
 | 
 | ||||||
|     $html = "<!DOCTYPE html>"; |     $html = "<!DOCTYPE html>"; | ||||||
|     $html .= "<html>"; |     $html .= "<html lang=\"$lang\">";
 | ||||||
|     $html .= $head; |     $html .= $head; | ||||||
|     $html .= $body; |     $html .= $body; | ||||||
|     $html .= "</html>"; |     $html .= "</html>"; | ||||||
|     return $html; |     return $html; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| }; | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
| @ -2,19 +2,20 @@ | |||||||
| 
 | 
 | ||||||
| namespace Elements; | namespace Elements; | ||||||
| 
 | 
 | ||||||
| abstract class Head extends \View { | abstract class Head extends View { | ||||||
| 
 | 
 | ||||||
|   protected $sources; |   protected array $sources; | ||||||
|   protected $title; |   protected string $title; | ||||||
|   protected $metas; |   protected array $metas; | ||||||
|   protected $rawFields; |   protected array $rawFields; | ||||||
|   protected $keywords; |   protected array $keywords; | ||||||
|   protected $description; |   protected string $description; | ||||||
|   protected $baseUrl; |   protected string $baseUrl; | ||||||
| 
 | 
 | ||||||
|   function __construct($document) { |   function __construct($document) { | ||||||
|     parent::__construct($document); |     parent::__construct($document); | ||||||
|     $this->sources = array(); |     $this->sources = array(); | ||||||
|  |     $this->searchable = false; | ||||||
|     $this->metas = $this->initMetas(); |     $this->metas = $this->initMetas(); | ||||||
|     $this->rawFields = $this->initRawFields(); |     $this->rawFields = $this->initRawFields(); | ||||||
|     $this->title = $this->initTitle(); |     $this->title = $this->initTitle(); | ||||||
| @ -45,7 +46,7 @@ abstract class Head extends \View { | |||||||
|   public function addKeywords($keywords) { array_merge($this->keywords, $keywords); } |   public function addKeywords($keywords) { array_merge($this->keywords, $keywords); } | ||||||
|   public function getTitle() { return $this->title; } |   public function getTitle() { return $this->title; } | ||||||
| 
 | 
 | ||||||
|   public function addCSS($href, $type = Link::MIME_TEXT_CSS)  { $this->sources[] = new Link("stylesheet", $href, $type); } |   public function addCSS($href, $type = Link::MIME_TEXT_CSS)  { $this->sources[] = new Link(Link::STYLESHEET, $href, $type); } | ||||||
|   public function addStyle($style) { $this->sources[] = new Style($style); } |   public function addStyle($style) { $this->sources[] = new Style($style); } | ||||||
|   public function addJS($url) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, $url, ""); } |   public function addJS($url) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, $url, ""); } | ||||||
|   public function addJSCode($code) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, "", $code); } |   public function addJSCode($code) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, "", $code); } | ||||||
| @ -54,19 +55,6 @@ abstract class Head extends \View { | |||||||
|     $this->addCSS(Link::FONTAWESOME); |     $this->addCSS(Link::FONTAWESOME); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function loadSyntaxHighlighting() { |  | ||||||
|     $this->addJS(Script::HIGHLIGHT); |  | ||||||
|     $this->addJSCode(Script::HIGHLIGHT_JS_LOADER); |  | ||||||
|     $this->addCSS(Link::HIGHLIGHT); |  | ||||||
|     $this->addCSS(Link::HIGHLIGHT_THEME); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function loadJQueryTerminal($unixFormatting = true) { |  | ||||||
|     $this->addJS(Script::JQUERY_TERMINAL); |  | ||||||
|     if($unixFormatting) $this->addJS(Script::JQUERY_TERMINAL_UNIX); |  | ||||||
|     $this->addCSS(Link::JQUERY_TERMINAL); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function loadGoogleRecaptcha($siteKey) { |   public function loadGoogleRecaptcha($siteKey) { | ||||||
|     $this->addJS("https://www.google.com/recaptcha/api.js?render=$siteKey"); |     $this->addJS("https://www.google.com/recaptcha/api.js?render=$siteKey"); | ||||||
|   } |   } | ||||||
| @ -80,11 +68,6 @@ abstract class Head extends \View { | |||||||
|     $this->addJS(Script::BOOTSTRAP); |     $this->addJS(Script::BOOTSTRAP); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function loadChartJS() { |  | ||||||
|     $this->addJS(Script::MOMENT); |  | ||||||
|     $this->addJS(Script::CHART); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function getCode() { |   public function getCode() { | ||||||
|     $header = "<head>"; |     $header = "<head>"; | ||||||
| 
 | 
 | ||||||
| @ -123,4 +106,3 @@ abstract class Head extends \View { | |||||||
|     return $header; |     return $header; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -2,41 +2,28 @@ | |||||||
| 
 | 
 | ||||||
| namespace Elements; | namespace Elements; | ||||||
| 
 | 
 | ||||||
| class Link extends Source { | class Link extends StaticView { | ||||||
| 
 | 
 | ||||||
|   const STYLESHEET    = "stylesheet"; |   const STYLESHEET    = "stylesheet"; | ||||||
|   const MIME_TEXT_CSS = "text/css"; |   const MIME_TEXT_CSS = "text/css"; | ||||||
| 
 | 
 | ||||||
|   const FONTAWESOME               = '/css/fontawesome.min.css'; |   const FONTAWESOME = "/css/fontawesome.min.css"; | ||||||
|   // const JQUERY_UI                 = '/css/jquery-ui.css';
 |   const BOOTSTRAP   = "/css/bootstrap.min.css"; | ||||||
|   // const JQUERY_TERMINAL           = '/css/jquery.terminal.min.css';
 |  | ||||||
|   const BOOTSTRAP                 = '/css/bootstrap.min.css'; |  | ||||||
|   // const BOOTSTRAP_THEME           = '/css/bootstrap-theme.min.css';
 |  | ||||||
|   // const BOOTSTRAP_DATEPICKER_CSS  = '/css/bootstrap-datepicker.standalone.min.css';
 |  | ||||||
|   // const BOOTSTRAP_DATEPICKER3_CSS = '/css/bootstrap-datepicker.standalone.min.css';
 |  | ||||||
|   // const HIGHLIGHT                 = '/css/highlight.css';
 |  | ||||||
|   // const HIGHLIGHT_THEME           = '/css/theme.css';
 |  | ||||||
|   const CORE        = "/css/style.css"; |   const CORE        = "/css/style.css"; | ||||||
|   const ADMIN                     = "/css/admin.css"; |   const ACCOUNT       = "/css/account.css"; | ||||||
|   // const HOME                      = "/css/home.css";
 |  | ||||||
|   // const REVEALJS                  = "/css/reveal.css";
 |  | ||||||
|   // const REVEALJS_THEME_MOON       = "/css/reveal_moon.css";
 |  | ||||||
|   // const REVEALJS_THEME_BLACK      = "/css/reveal_black.css";
 |  | ||||||
| 
 | 
 | ||||||
|   private $type; |   private string $type; | ||||||
|   private $rel; |   private string $rel; | ||||||
|  |   private string $href; | ||||||
| 
 | 
 | ||||||
|   function __construct($rel, $href, $type = "") { |   function __construct($rel, $href, $type = "") { | ||||||
|     parent::__construct('link', $href); |     $this->href = $href; | ||||||
|     $this->type = $type; |     $this->type = $type; | ||||||
|     $this->rel = $rel; |     $this->rel = $rel; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function getCode() { |   function getCode() { | ||||||
|     $type = (empty($this->type) ? "" : " type=\"$this->type\"");
 |     $type = (empty($this->type) ? "" : " type=\"$this->type\"");
 | ||||||
|     $link = "<link rel=\"$this->rel\" href=\"$this->url\" $type/>";
 |     return "<link rel=\"$this->rel\" href=\"$this->href\"$type/>";
 | ||||||
|     return $link; |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -2,52 +2,28 @@ | |||||||
| 
 | 
 | ||||||
| namespace Elements; | namespace Elements; | ||||||
| 
 | 
 | ||||||
| class Script extends Source { | class Script extends StaticView { | ||||||
| 
 | 
 | ||||||
|   const MIME_TEXT_JAVASCRIPT    = "text/javascript"; |   const MIME_TEXT_JAVASCRIPT    = "text/javascript"; | ||||||
| 
 | 
 | ||||||
|   const CORE      = "/js/script.js"; |   const CORE      = "/js/script.js"; | ||||||
|   // const HOME                    = "/js/home.js";
 |  | ||||||
|   const ADMIN                   = "/js/admin.js"; |  | ||||||
|   // const SORTTABLE               = "/js/sorttable.js";
 |  | ||||||
|   const JQUERY    = "/js/jquery.min.js"; |   const JQUERY    = "/js/jquery.min.js"; | ||||||
|   // const JQUERY_UI               = "/js/jquery-ui.js";
 |  | ||||||
|   // const JQUERY_MASKED_INPUT     = "/js/jquery.maskedinput.min.js";
 |  | ||||||
|   // const JQUERY_CONTEXT_MENU     = "/js/jquery.contextmenu.min.js";
 |  | ||||||
|   // const JQUERY_TERMINAL         = "/js/jquery.terminal.min.js";
 |  | ||||||
|   // const JQUERY_TERMINAL_UNIX    = "/js/unix_formatting.js";
 |  | ||||||
|   // const JSCOLOR                 = "/js/jscolor.min.js";
 |  | ||||||
|   // const SYNTAX_HIGHLIGHTER      = "/js/syntaxhighlighter.js";
 |  | ||||||
|   // const HIGHLIGHT               = "/js/highlight.pack.js";
 |  | ||||||
|   // const GOOGLE_CHARTS           = "/js/loader.js";
 |  | ||||||
|   const BOOTSTRAP               = "/js/bootstrap.min.js"; |  | ||||||
|   // const BOOTSTRAP_DATEPICKER_JS = "/js/bootstrap-datepicker.min.js";
 |  | ||||||
|   // const POPPER                  = "/js/popper.min.js";
 |  | ||||||
|   // const JSMPEG                  = "/js/jsmpeg.min.js";
 |  | ||||||
|   // const MOMENT                  = "/js/moment.min.js";
 |  | ||||||
|   // const CHART                   = "/js/chart.js";
 |  | ||||||
|   // const REVEALJS                = "/js/reveal.js";
 |  | ||||||
|   // const REVEALJS_PLUGIN_NOTES   = "/js/reveal_notes.js";
 |  | ||||||
|   const INSTALL   = "/js/install.js"; |   const INSTALL   = "/js/install.js"; | ||||||
|  |   const BOOTSTRAP = "/js/bootstrap.bundle.min.js"; | ||||||
|  |   const ACCOUNT   = "/js/account.js"; | ||||||
| 
 | 
 | ||||||
|   const HIGHLIGHT_JS_LOADER = "\$(document).ready(function(){\$('code').each(function(i, block) { hljs.highlightBlock(block); }); })"; |   private string $type; | ||||||
| 
 |   private string $content; | ||||||
|   private $type; |   private string $src; | ||||||
|   private $content; |  | ||||||
| 
 | 
 | ||||||
|   function __construct($type, $src, $content = "") { |   function __construct($type, $src, $content = "") { | ||||||
|     parent::__construct('script', $src); |     $this->src = $src; | ||||||
|     $this->type = $type; |     $this->type = $type; | ||||||
|     $this->content = $content; |     $this->content = $content; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function getCode() { |   function getCode() { | ||||||
|     $src = (empty($this->url) ? "" : " src=\"$this->url\"");
 |     $src = (empty($this->src) ? "" : " src=\"$this->src\"");
 | ||||||
|     $script = "<script type=\"$this->type\"$src>";
 |       return "<script type=\"$this->type\"$src>$this->content</script>";
 | ||||||
|     $script .= $this->content; |  | ||||||
|     $script .= '</script>'; |  | ||||||
|     return $script; |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								core/Elements/SimpleBody.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								core/Elements/SimpleBody.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Elements; | ||||||
|  | 
 | ||||||
|  | abstract class SimpleBody extends Body { | ||||||
|  |   public function __construct($document) { | ||||||
|  |     parent::__construct($document); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function getCode() { | ||||||
|  |     $content = $this->getContent(); | ||||||
|  |     return parent::getCode() . "<body>$content</body>"; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected abstract function getContent(); | ||||||
|  | } | ||||||
| @ -1,22 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace Elements; |  | ||||||
| 
 |  | ||||||
| class Source extends \View { |  | ||||||
| 
 |  | ||||||
|   protected $sourceType; |  | ||||||
|   protected $url; |  | ||||||
| 
 |  | ||||||
|   public function __construct($sourceType, $url) { |  | ||||||
|     $this->sourceType = $sourceType; |  | ||||||
|     $this->url = $url; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function getCode() { |  | ||||||
|     return "<$sourceType />"; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public function getUrl() { return $this->url; } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
							
								
								
									
										13
									
								
								core/Elements/StaticView.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										13
									
								
								core/Elements/StaticView.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Elements; | ||||||
|  | 
 | ||||||
|  | abstract class StaticView { | ||||||
|  | 
 | ||||||
|  |   public abstract function getCode(); | ||||||
|  | 
 | ||||||
|  |   public function __toString() { | ||||||
|  |     return $this->getCode(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -2,12 +2,11 @@ | |||||||
| 
 | 
 | ||||||
| namespace Elements; | namespace Elements; | ||||||
| 
 | 
 | ||||||
| class Style extends Source { | class Style extends StaticView { | ||||||
| 
 | 
 | ||||||
|   private $style; |   private string $style; | ||||||
| 
 | 
 | ||||||
|   function __construct($style) { |   function __construct($style) { | ||||||
|     parent::__construct('style', ''); |  | ||||||
|     $this->style = $style; |     $this->style = $style; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -15,5 +14,3 @@ class Style extends Source { | |||||||
|     return "<style>$this->style</style>"; |     return "<style>$this->style</style>"; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
							
								
								
									
										136
									
								
								core/Elements/View.class.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										136
									
								
								core/Elements/View.class.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,136 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Elements; | ||||||
|  | 
 | ||||||
|  | use External\PHPMailer\Exception; | ||||||
|  | 
 | ||||||
|  | abstract class View extends StaticView { | ||||||
|  | 
 | ||||||
|  |   private Document $document; | ||||||
|  |   private bool $loadView; | ||||||
|  |   protected bool $searchable; | ||||||
|  |   protected string $reference; | ||||||
|  |   protected string $title; | ||||||
|  |   protected array $langModules; | ||||||
|  | 
 | ||||||
|  |   public function __construct(Document $document, $loadView = true) { | ||||||
|  |     $this->document = $document; | ||||||
|  |     $this->searchable = false; | ||||||
|  |     $this->reference = ""; | ||||||
|  |     $this->title = "Untitled View"; | ||||||
|  |     $this->langModules = array(); | ||||||
|  |     $this->loadView = $loadView; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function getTitle() { return $this->title; } | ||||||
|  |   public function getDocument() { return $this->document; } | ||||||
|  |   public function isSearchable() { return $this->searchable; } | ||||||
|  |   public function getReference() { return $this->reference; } | ||||||
|  | 
 | ||||||
|  |   protected function load(string $viewClass) : string { | ||||||
|  |     try { | ||||||
|  |       $reflectionClass = new \ReflectionClass($viewClass); | ||||||
|  |       if ($reflectionClass->isSubclassOf(View::class) && $reflectionClass->isInstantiable()) { | ||||||
|  |         $view = $reflectionClass->newInstanceArgs(array($this->getDocument())); | ||||||
|  |         $view->loadView(); | ||||||
|  |         return $view; | ||||||
|  |       } | ||||||
|  |     } catch(\ReflectionException $e) { | ||||||
|  |       error_log($e->getMessage()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private function loadLanguageModules() { | ||||||
|  |     $lang = $this->document->getUser()->getLanguage(); | ||||||
|  |     foreach($this->langModules as $langModule) { | ||||||
|  |       $lang->loadModule($langModule); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Virtual Methods
 | ||||||
|  |   public function loadView() { } | ||||||
|  | 
 | ||||||
|  |   public function getCode() { | ||||||
|  | 
 | ||||||
|  |     // Load translations
 | ||||||
|  |     $this->loadLanguageModules(); | ||||||
|  | 
 | ||||||
|  |     // Load Meta Data + Head (title, scripts, includes, ...)
 | ||||||
|  |     if($this->loadView) { | ||||||
|  |       $this->loadView(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ''; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // UI Functions
 | ||||||
|  |   private function createList($items, $tag) { | ||||||
|  |     if(count($items) === 0) | ||||||
|  |       return "<$tag></$tag>"; | ||||||
|  |     else | ||||||
|  |       return "<$tag><li>" . implode("</li><li>", $items) . "</li></$tag>"; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function createOrderedList($items=array()) { | ||||||
|  |     return $this->createList($items, "ol"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public function createUnorderedList($items=array()) { | ||||||
|  |     return $this->createList($items, "ul"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createLink($link, $title=null) { | ||||||
|  |     if(is_null($title)) $title=$link; | ||||||
|  |     return "<a href=\"$link\">$title</a>";
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createExternalLink($link, $title=null) { | ||||||
|  |     if(is_null($title)) $title=$link; | ||||||
|  |     return "<a href=\"$link\" target=\"_blank\" class=\"external\">$title</a>"; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createIcon($icon, $type = "fas", $classes = "") { | ||||||
|  |     $iconClass = "$type fa-$icon"; | ||||||
|  | 
 | ||||||
|  |     if($icon === "spinner" || $icon === "circle-notch") | ||||||
|  |       $iconClass .= " fa-spin"; | ||||||
|  | 
 | ||||||
|  |     if($classes) | ||||||
|  |       $iconClass .= " $classes"; | ||||||
|  | 
 | ||||||
|  |     return "<i class=\"$iconClass\" ></i>";
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createErrorText($text, $id="", $hidden=false) { | ||||||
|  |     return $this->createStatusText("danger", $text, $id, $hidden); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createWarningText($text, $id="", $hidden=false) { | ||||||
|  |     return $this->createStatusText("warning", $text, $id, $hidden); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createSuccessText($text, $id="", $hidden=false) { | ||||||
|  |     return $this->createStatusText("success", $text, $id, $hidden); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createSecondaryText($text, $id="", $hidden=false) { | ||||||
|  |     return $this->createStatusText("secondary", $text, $id, $hidden); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createInfoText($text, $id="", $hidden=false) { | ||||||
|  |     return $this->createStatusText("info", $text, $id, $hidden); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createStatusText($type, $text, $id="", $hidden=false) { | ||||||
|  |     if(strlen($id) > 0) $id = " id=\"$id\"";
 | ||||||
|  |     $hidden = ($hidden?" hidden" : ""); | ||||||
|  |     return "<div class=\"alert alert-$type$hidden\" role=\"alert\"$id>$text</div>"; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   protected function createBadge($type, $text) { | ||||||
|  |     $text = htmlspecialchars($text); | ||||||
|  |     return "<span class=\"badge badge-$type\">$text</span>";
 | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										5702
									
								
								core/External/phpQuery.php
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5702
									
								
								core/External/phpQuery.php
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -6,9 +6,6 @@ abstract class ApiObject implements \JsonSerializable { | |||||||
| 
 | 
 | ||||||
|   public abstract function jsonSerialize(); |   public abstract function jsonSerialize(); | ||||||
| 
 | 
 | ||||||
|   public function __construct() { } |  | ||||||
|   public function __toString() { return json_encode($this); } |   public function __toString() { return json_encode($this); } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -4,11 +4,11 @@ namespace Objects; | |||||||
| 
 | 
 | ||||||
| class ConnectionData { | class ConnectionData { | ||||||
| 
 | 
 | ||||||
|   private $host; |   private string $host; | ||||||
|   private $port; |   private int $port; | ||||||
|   private $login; |   private string $login; | ||||||
|   private $password; |   private string $password; | ||||||
|   private $properties; |   private array $properties; | ||||||
| 
 | 
 | ||||||
|   public function __construct($host, $port, $login, $password) { |   public function __construct($host, $port, $login, $password) { | ||||||
|     $this->host = $host; |     $this->host = $host; | ||||||
| @ -32,6 +32,7 @@ class ConnectionData { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     $this->properties[$key] = $val; |     $this->properties[$key] = $val; | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function getHost() { return $this->host; } |   public function getHost() { return $this->host; } | ||||||
| @ -39,5 +40,3 @@ class ConnectionData { | |||||||
|   public function getLogin() { return $this->login; } |   public function getLogin() { return $this->login; } | ||||||
|   public function getPassword() { return $this->password; } |   public function getPassword() { return $this->password; } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -2,16 +2,18 @@ | |||||||
| 
 | 
 | ||||||
| namespace Objects { | namespace Objects { | ||||||
| 
 | 
 | ||||||
|  |     use Objects\lang\LanguageModule; | ||||||
|  | 
 | ||||||
|     class Language extends ApiObject { |     class Language extends ApiObject { | ||||||
| 
 | 
 | ||||||
|     const LANG_CODE_PATTERN = "/^[a-zA-Z]+_[a-zA-Z]+$/"; |     const LANG_CODE_PATTERN = "/^[a-zA-Z]+_[a-zA-Z]+$/"; | ||||||
| 
 | 
 | ||||||
|     private $languageId; |     private int $languageId; | ||||||
|     private $langCode; |     private string $langCode; | ||||||
|     private $langName; |     private string $langName; | ||||||
|     private $modules; |     private array $modules; | ||||||
| 
 | 
 | ||||||
|     protected $entries; |     protected array $entries; | ||||||
| 
 | 
 | ||||||
|     public function __construct($languageId, $langCode, $langName) { |     public function __construct($languageId, $langCode, $langName) { | ||||||
|       $this->languageId = $languageId; |       $this->languageId = $languageId; | ||||||
| @ -29,7 +31,7 @@ namespace Objects { | |||||||
|     public function getEntries() { return $this->entries; } |     public function getEntries() { return $this->entries; } | ||||||
|     public function getModules() { return $this->modules; } |     public function getModules() { return $this->modules; } | ||||||
| 
 | 
 | ||||||
|     public function loadModule($module) { |     public function loadModule(LanguageModule $module) { | ||||||
|       if(!is_object($module)) |       if(!is_object($module)) | ||||||
|         $module = new $module; |         $module = new $module; | ||||||
| 
 | 
 | ||||||
| @ -100,6 +102,7 @@ namespace Objects { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace { | namespace { | ||||||
|  | 
 | ||||||
|     function L($key) { |     function L($key) { | ||||||
|     if(!array_key_exists('LANGUAGE', $GLOBALS)) |     if(!array_key_exists('LANGUAGE', $GLOBALS)) | ||||||
|       return $key; |       return $key; | ||||||
| @ -132,4 +135,3 @@ namespace { | |||||||
|     return $LANGUAGE->getShortCode(); |     return $LANGUAGE->getShortCode(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| ?>
 |  | ||||||
|  | |||||||
| @ -2,28 +2,34 @@ | |||||||
| 
 | 
 | ||||||
| namespace Objects; | namespace Objects; | ||||||
| 
 | 
 | ||||||
|  | use DateTime; | ||||||
| use \Driver\SQL\Condition\Compare; | use \Driver\SQL\Condition\Compare; | ||||||
|  | use Exception; | ||||||
|  | use External\JWT; | ||||||
| 
 | 
 | ||||||
| class Session extends ApiObject { | class Session extends ApiObject { | ||||||
| 
 | 
 | ||||||
|   const DURATION = 120; |   # in minutes
 | ||||||
|  |   const DURATION = 60*24; | ||||||
| 
 | 
 | ||||||
|   private $sessionId; |   private ?int $sessionId; | ||||||
|   private $user; |   private User $user; | ||||||
|   private $expires; |   private int $expires; | ||||||
|   private $ipAddress; |   private string $ipAddress; | ||||||
|   private $os; |   private ?string $os; | ||||||
|   private $browser; |   private ?string $browser; | ||||||
|   private $stayLoggedIn; |   private bool $stayLoggedIn; | ||||||
|  |   private string $csrfToken; | ||||||
| 
 | 
 | ||||||
|   public function __construct($user, $sessionId) { |   public function __construct(User $user, ?int $sessionId, ?string $csrfToken) { | ||||||
|     $this->user = $user; |     $this->user = $user; | ||||||
|     $this->sessionId = $sessionId; |     $this->sessionId = $sessionId; | ||||||
|     $this->stayLoggedIn = true; |     $this->stayLoggedIn = true; | ||||||
|  |     $this->csrfToken = $csrfToken ?? generateRandomString(16); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public static function create($user, $stayLoggedIn) { |   public static function create($user, $stayLoggedIn) { | ||||||
|     $session = new Session($user, null); |     $session = new Session($user, null, null); | ||||||
|     if($session->insert($stayLoggedIn)) { |     if($session->insert($stayLoggedIn)) { | ||||||
|       return $session; |       return $session; | ||||||
|     } |     } | ||||||
| @ -38,7 +44,7 @@ class Session extends ApiObject { | |||||||
|       $userAgent = @get_browser($_SERVER['HTTP_USER_AGENT'], true); |       $userAgent = @get_browser($_SERVER['HTTP_USER_AGENT'], true); | ||||||
|       $this->os = $userAgent['platform'] ?? "Unknown"; |       $this->os = $userAgent['platform'] ?? "Unknown"; | ||||||
|       $this->browser = $userAgent['parent'] ?? "Unknown"; |       $this->browser = $userAgent['parent'] ?? "Unknown"; | ||||||
|     } catch(\Exception $ex) { |     } catch(Exception $ex) { | ||||||
|       $this->os = "Unknown"; |       $this->os = "Unknown"; | ||||||
|       $this->browser = "Unknown"; |       $this->browser = "Unknown"; | ||||||
|     } |     } | ||||||
| @ -56,14 +62,12 @@ class Session extends ApiObject { | |||||||
| 
 | 
 | ||||||
|   public function sendCookie() { |   public function sendCookie() { | ||||||
|     $this->updateMetaData(); |     $this->updateMetaData(); | ||||||
|     $jwt = $this->user->getConfiguration()->getJwt(); |     $settings = $this->user->getConfiguration()->getSettings(); | ||||||
|     if($jwt) { |  | ||||||
|     $token = array('userId' => $this->user->getId(), 'sessionId' => $this->sessionId); |     $token = array('userId' => $this->user->getId(), 'sessionId' => $this->sessionId); | ||||||
|       $sessionCookie = \External\JWT::encode($token, $jwt->getKey()); |     $sessionCookie = JWT::encode($token, $settings->getJwtSecret()); | ||||||
|     $secure = strcmp(getProtocol(), "https") === 0; |     $secure = strcmp(getProtocol(), "https") === 0; | ||||||
|     setcookie('session', $sessionCookie, $this->getExpiresTime(), "/", "", $secure); |     setcookie('session', $sessionCookie, $this->getExpiresTime(), "/", "", $secure); | ||||||
|   } |   } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   public function getExpiresTime() { |   public function getExpiresTime() { | ||||||
|     return ($this->stayLoggedIn == 0 ? 0 : $this->expires); |     return ($this->stayLoggedIn == 0 ? 0 : $this->expires); | ||||||
| @ -81,6 +85,7 @@ class Session extends ApiObject { | |||||||
|       'ipAddress' => $this->ipAddress, |       'ipAddress' => $this->ipAddress, | ||||||
|       'os' => $this->os, |       'os' => $this->os, | ||||||
|       'browser' => $this->browser, |       'browser' => $this->browser, | ||||||
|  |       'csrf_token' => $this->csrfToken | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -88,19 +93,20 @@ class Session extends ApiObject { | |||||||
|     $this->updateMetaData(); |     $this->updateMetaData(); | ||||||
|     $sql = $this->user->getSQL(); |     $sql = $this->user->getSQL(); | ||||||
| 
 | 
 | ||||||
|     $hours = Session::DURATION; |     $minutes = Session::DURATION; | ||||||
|     $columns = array("expires", "user_id", "ipAddress", "os", "browser", "data", "stay_logged_in"); |     $columns = array("expires", "user_id", "ipAddress", "os", "browser", "data", "stay_logged_in", "csrf_token"); | ||||||
| 
 | 
 | ||||||
|     $success = $sql |     $success = $sql | ||||||
|       ->insert("Session", $columns) |       ->insert("Session", $columns) | ||||||
|       ->addRow( |       ->addRow( | ||||||
|         (new \DateTime)->modify("+$hours hour"), |         (new DateTime())->modify("+$minutes minute"), | ||||||
|         $this->user->getId(), |         $this->user->getId(), | ||||||
|         $this->ipAddress, |         $this->ipAddress, | ||||||
|         $this->os, |         $this->os, | ||||||
|         $this->browser, |         $this->browser, | ||||||
|         json_encode($_SESSION), |         json_encode($_SESSION), | ||||||
|         $stayLoggedIn) |         $stayLoggedIn, | ||||||
|  |         $this->csrfToken) | ||||||
|       ->returning("uid") |       ->returning("uid") | ||||||
|       ->execute(); |       ->execute(); | ||||||
| 
 | 
 | ||||||
| @ -113,32 +119,31 @@ class Session extends ApiObject { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function destroy() { |   public function destroy() { | ||||||
|     $success = $this->user->getSQL()->update("Session") |     return $this->user->getSQL()->update("Session") | ||||||
|       ->set("active", false) |       ->set("active", false) | ||||||
|       ->where(new Compare("Session.uid", $this->sessionId)) |       ->where(new Compare("Session.uid", $this->sessionId)) | ||||||
|       ->where(new Compare("Session.user_id", $this->user->getId())) |       ->where(new Compare("Session.user_id", $this->user->getId())) | ||||||
|       ->execute(); |       ->execute(); | ||||||
| 
 |  | ||||||
|     return $success; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public function update() { |   public function update() { | ||||||
|     $this->updateMetaData(); |     $this->updateMetaData(); | ||||||
|     $hours = Session::DURATION; |     $minutes = Session::DURATION; | ||||||
| 
 | 
 | ||||||
|     $sql = $this->user->getSQL(); |     $sql = $this->user->getSQL(); | ||||||
|     $success = $sql->update("Session") |     return $sql->update("Session") | ||||||
|       ->set("Session.expires", (new \DateTime)->modify("+$hours hour")) |       ->set("Session.expires", (new DateTime())->modify("+$minutes minute")) | ||||||
|       ->set("Session.ipAddress", $this->ipAddress) |       ->set("Session.ipAddress", $this->ipAddress) | ||||||
|       ->set("Session.os", $this->os) |       ->set("Session.os", $this->os) | ||||||
|       ->set("Session.browser", $this->browser) |       ->set("Session.browser", $this->browser) | ||||||
|       ->set("Session.data", json_encode($_SESSION)) |       ->set("Session.data", json_encode($_SESSION)) | ||||||
|  |       ->set("Session.csrf_token", $this->csrfToken) | ||||||
|       ->where(new Compare("Session.uid", $this->sessionId)) |       ->where(new Compare("Session.uid", $this->sessionId)) | ||||||
|       ->where(new Compare("Session.user_id", $this->user->getId())) |       ->where(new Compare("Session.user_id", $this->user->getId())) | ||||||
|       ->execute(); |       ->execute(); | ||||||
| 
 |  | ||||||
|     return $success; |  | ||||||
|   } |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| ?>
 |   public function getCsrfToken(): string { | ||||||
|  |     return $this->csrfToken; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user