From 12143c148d7325735fb9e7f9e00108ebb4df983f Mon Sep 17 00:00:00 2001 From: shr3dd3r Date: Tue, 31 Oct 2023 21:57:17 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B4=D0=BE=D0=BB=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B7=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B8=2023.10.31?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлен .gitignore, скрыты несколько нинужных файлов, в целом продолжен запил основных частей функционала, начат микрорефакторинг (теперь концентрация индусского кода будет чуть меньше). --- .gitignore | 4 + api/_auth.php | 3 +- api/_config.php | 12 +++ api/_errors.php | 19 ----- api/_errorslist.php | 104 ++++++++++++++++++++++++ api/_json.php | 34 ++++++-- api/_types.php | 91 +++++++++++++++++++++ api/_utils.php | 21 ++++- api/comments/index.php | 47 +++++++++++ api/post/create.php | 103 +++++++++++++++++++++--- api/user/__admin_session.php | 11 ++- api/user/create.php | 149 +++++++++++++++++++++-------------- api/user/delete.php | 72 ++++++++++------- api/user/index.php | 101 ++++++++++++++++-------- config.json | 3 + 15 files changed, 608 insertions(+), 166 deletions(-) create mode 100644 .gitignore delete mode 100644 api/_errors.php create mode 100644 api/_errorslist.php create mode 100644 api/_types.php create mode 100644 api/comments/index.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b00ecde --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +_temp/ +front/styles/bg_pattern_peace_old.png +test.png +TODO.md \ No newline at end of file diff --git a/api/_auth.php b/api/_auth.php index 6ecda49..5fdaa29 100644 --- a/api/_auth.php +++ b/api/_auth.php @@ -1,6 +1,7 @@ \ No newline at end of file diff --git a/api/_errors.php b/api/_errors.php deleted file mode 100644 index f90865b..0000000 --- a/api/_errors.php +++ /dev/null @@ -1,19 +0,0 @@ - \ No newline at end of file diff --git a/api/_errorslist.php b/api/_errorslist.php new file mode 100644 index 0000000..5d790bd --- /dev/null +++ b/api/_errorslist.php @@ -0,0 +1,104 @@ + \ No newline at end of file diff --git a/api/_json.php b/api/_json.php index d041459..172ef0c 100644 --- a/api/_json.php +++ b/api/_json.php @@ -1,24 +1,42 @@ - $Err_Int_JSONEncode)); + $data = json_encode( + array( + "error" => Errors_ResolveNameByCode(E_UNS_JSONBADINP) + ) + ); } header("Content-Type: application/json; charset=utf-8"); echo $data; exit; } -function ReturnJSONError ($err, $desc) { - ReturnJSONData(array( - "error" => $err, - "description" => $desc +// Return error as JSON data to stdout and exit +function JSON_ReturnError (int $code = -1, string $name = "", string $desc = "") { + if ($code === -1 && empty($name)) + JSON_ReturnError(code: E_UNS_INTERNAL, desc: "cant return error without specified code or name"); + else if ($code === -1) + $code = Errors_ResolveCodeByName($name); + else if (empty($name)) + $name = Errors_ResolveNameByCode($code); + + JSON_ReturnData(array( + "error" => $name, // Name + "error_code" => $code, // Code + "error_hum" => Errors_ResolveDescByCode($code), // Common description + "description" => $desc // Detailed decription )); } + + ?> \ No newline at end of file diff --git a/api/_types.php b/api/_types.php new file mode 100644 index 0000000..9b9b8f7 --- /dev/null +++ b/api/_types.php @@ -0,0 +1,91 @@ +Code = $code; + $this->Name = $name; + $this->Description = $desc; + } + + // Getter for error code + public function GetCode (): int { + return $this->Code; + } + // Getter for error name + public function GetName (): string { + return $this->Name; + } + // Getter for error description + public function GetDescription (): string { + return $this->Description; + } + + // Stringify error + public function Stringify (): string { + if (isset($this->Description)) + return "error " . $this->Name . " (" . strval($this->Code) . "): " . $this->Description; + else + return "error " . $this->Name . " (" . strval($this->Code) . ")"; + } +} + +// Return type of API method +final class ReturnT { + private ErrorT $ErrorObj; + private $Data; + + + // Ctor + public function __construct($data = null, int $err_code = 0, string $err_name = "", string $err_desc = "") { + $this->ErrorObj = new ErrorT($err_code, $err_name, $err_desc); + $this->Data = $data; + } + + // Setter/getter for data + public function SetData ($d) { + $this->Data = $d; + } + public function GetData () { + return $this->Data; + } + + // Get string representation of error + public function GetError (): string { + return $this->ErrorObj->Stringify(); + } + + // Is there any error + public function IsError (): bool { + return $this->ErrorObj->GetCode() !== E_NOERROR; + } + + // Throw JSON error + function ThrowJSONError () { + JSON_ReturnError( + $this->ErrorObj->GetCode(), + $this->ErrorObj->GetName(), + $this->ErrorObj->Stringify() + ); + } +} + +?> \ No newline at end of file diff --git a/api/_utils.php b/api/_utils.php index 9c8019f..5f7d98c 100644 --- a/api/_utils.php +++ b/api/_utils.php @@ -1,12 +1,14 @@ \ No newline at end of file diff --git a/api/comments/index.php b/api/comments/index.php new file mode 100644 index 0000000..eba8520 --- /dev/null +++ b/api/comments/index.php @@ -0,0 +1,47 @@ +prepare("SELECT * FROM posts WHERE id = ?"); + $s->bind_param("s", $id); + $s->execute(); + $d = $s->get_result()->fetch_assoc(); + + if (!(bool)$d) { + return null; +} + + + +if (ThisFileIsRequested(__FILE__)) { + require_once("../_json.php"); + + $SectionID = null; + + if (isset($_REQUEST["id"])) { + if (!ctype_digit($_REQUEST["id"])) + ReturnJSONError($Err_RDP_InvalidID, "id must be numeric"); + $SectionID = intval($_REQUEST["id"]); + } else { + ReturnJSONError($Err_RDP_InvalidID, "id must be specified"); + } + + /* + $ResponseData = ComSec_GetComms($SectionID); + if ($ResponseData) + ReturnJSONData($ResponseData); + else + ReturnJSONError($Err_DP_IDNotFound, "wrong id"); + */ +} + +?> \ No newline at end of file diff --git a/api/post/create.php b/api/post/create.php index 003b00e..2f15bd9 100644 --- a/api/post/create.php +++ b/api/post/create.php @@ -1,25 +1,96 @@ prepare("INSERT ..."); - // $s->bind_param("s", $author); - // $s->execute(); - // $d = $s->get_result()->fetch_assoc(); - // - // if (!(bool)$d) { - // return null; - // } + $result = null; - return $result; + // Check post params + // Author ID should exist + if (!User_IDExist($author)) + // TODO + + // Performing SQL query + $s = $db->prepare("INSERT INTO posts (author_id,comment_section_id,tags,title,pic_path,preview_path,comments_enabled,edit_lock) VALUES (?,?,?,?,?,?,?,?)"); + $s->bind_param("ssssssss", $author, null, $tags, $title, $pic_path, $prev_path, $comms_enabled, $edit_lock); + + if ($s->execute() !== true) { + return new ReturnT(null, 601, "failed to create post record in DB"); + } + + return new ReturnT($result); } @@ -54,8 +125,16 @@ if (ThisFileIsRequested(__FILE__)) { // Check if resolution is bigger than allowed or have unacceptable aspect ratio list($SzX, $SzY, $Type, $Attr) = getimagesize($TmpFilePath); - if ($SzX > $Config["media"]["max_pic_res"]["x"] || $SzY > $Config["media"]["max_pic_res"]["y"] || (GetAspectRatio($SzX, $SzY) > $Config["media"]["max_pic_res"]["ratio"])) + if (!Post_ImageIsValid($SzX, $SzY)) ReturnJSONError($Err_DP_ImageWrongRes, "image with that resolution or aspect ratio cant be accepted"); + + // TODO: delete image if unacceptable + + // Copy picture to storage folder + Post_StoreImage($TmpFilePath, $Config) + + // Create post + //$success = Post_Create( } ?> \ No newline at end of file diff --git a/api/user/__admin_session.php b/api/user/__admin_session.php index e67fa42..2f03500 100644 --- a/api/user/__admin_session.php +++ b/api/user/__admin_session.php @@ -1,23 +1,26 @@ \ No newline at end of file diff --git a/api/user/create.php b/api/user/create.php index 96d850d..5cefc53 100644 --- a/api/user/create.php +++ b/api/user/create.php @@ -1,16 +1,85 @@ prepare("INSERT INTO users (login,email,password_hash,salt,avatar_path,role,invite_id) VALUES (?,?,?,?,?,?,?)"); $role = "newbie"; $s->bind_param("sssssss", $login, $email, $pwd_hash, $salt, $avatar_path, $role, $invite_id); - return $s->execute() !== false; + $result = ($s->execute() !== false); + + if (!$result) + return new ReturnT(err_code: E_DBE_INSERTFAIL, err_desc: "cant insert record to users DB"); + + return new ReturnT(data: $result); } -if (ThisFileIsRequested(__FILE__)) { +if (Utils_ThisFileIsRequested(__FILE__)) { require_once("../_json.php"); - // Dirty hack for debugging purposes. Will be removed later + // HACK: for debugging purposes. Will be removed later if ($Config["debug"]) $_POST = $_REQUEST; - // If registration turned off - if (!$Config["registration"]["active"]) { - ReturnJSONError($Err_DP_RegClosed, "registrations are closed"); - } + // Create account + $result = User_Create_Method($_POST); - // If user is logged in, then we should not allow creation of account - if ($LOGGED_IN) - ReturnJSONError($Err_DP_AlreadyLoggedIn, "you are already logged in"); - - // If we have some POST data - if (isset($_POST["login"]) && isset($_POST["password"])) { - $login = $_POST["login"]; - $password = $_POST["password"]; - $email = null; - $invite = null; - - // If password is too weak - if (strlen($password) < 8) - ReturnJSONError($Err_RDP_InvalidArgs, "password too weak"); - - // If we need email but it isnt supplied - if ($Config["registration"]["need_email"] && !isset($_POST["email"])) { - ReturnJSONError($Err_RDP_InvalidArgs, "email is necessary"); - } elseif (isset($_POST["email"])) { - // Validation of email - if (!filter_var($_POST["email"], FILTER_VALIDATE_EMAIL)) - ReturnJSONError($Err_RDP_InvalidArgs, "email is invalid"); - $email = $_POST["email"]; - } - // If we need invite but it isnt supplied - if ($Config["registration"]["need_invite"] && !isset($_POST["invite_id"])) { - ReturnJSONError($Err_RDP_InvalidArgs, "registrations are invite-only"); - } elseif (isset($_POST["invite_id"])) { - // TODO: check invite and reject if it invalid - //$invite = $_POST["invite_id"]; - } - - // Check login and password for pattern match - $preg_str = "/[^" . $Config["registration"]["allowed_syms"] . "]/"; - if (preg_match($preg_str, $login) || preg_match($preg_str, $password)) { - ReturnJSONError($Err_RDP_InvalidArgs, "only allowed symbols are: " . $Config["registration"]["allowed_syms"]); - } - - // Check if login already exists - if (User_LoginExist($login)) - ReturnJSONError($Err_RDP_InvalidArgs, "login already exists"); - - // Create account - $result = User_Create($login, $password, $email, $invite); - ReturnJSONData(["success" => $result]); - } else { // Not enough arguments - ReturnJSONError($Err_RDP_InvalidArgs, "not enough or no arguments were supplied"); - } + // Checking result + if ($result->IsError()) + $result->ThrowJSONError(); + else + JSON_ReturnData(["success" => $result->GetData()]); } ?> \ No newline at end of file diff --git a/api/user/delete.php b/api/user/delete.php index d57d84c..e0b2855 100644 --- a/api/user/delete.php +++ b/api/user/delete.php @@ -1,48 +1,66 @@ prepare("delete from users where id = ?"); - $s->bind_param("s", $id); - return $s->execute() !== false; -} +// Methods +/* + * METHOD + * Delete existing account + */ +function User_Delete_Method (array $req): ReturnT { + global $db, $LOGGED_IN, $THIS_USER; + $id = null; -if (ThisFileIsRequested(__FILE__)) { - require_once("../_json.php"); + // Input sanity checks - // Dirty hack for debugging purposes. Will be removed later - if ($Config["debug"]) - $_POST = $_REQUEST; - - if (isset($_POST["id"]) && $LOGGED_IN) { - if (!ctype_digit($_POST["id"])) - ReturnJSONError($Err_RDP_InvalidID, "id must be numeric"); - $UserID = intval($_POST["id"]); - } elseif (!isset($_POST["id"]) && $LOGGED_IN) { - $UserID = $_SESSION["userid"]; + if (isset($req["id"]) && $LOGGED_IN) { + if (!ctype_digit($req["id"])) + return new ReturnT(err_code: E_UIN_BADARGS, err_desc: "id must be numeric"); + $id = intval($req["id"]); + } elseif (!isset($req["id"]) && $LOGGED_IN) { + $id = $THIS_USER; } else { - ReturnJSONError($Err_RDP_InvalidID, "valid session must be provided"); + return new ReturnT(err_code: E_AUT_NOTAUTHED, err_desc: "valid session must be provided"); } // If its attempt to delete other account - if (!User_HasRole($_SESSION["userid"], "admin") && $_SESSION["userid"] !== $UserID) - ReturnJSONError($Err_DP_NotEnoughRole, "you need to be admin to delete other accounts"); + if (!User_HasRole($THIS_USER, "admin") && $THIS_USER !== $id) + return new ReturnT(err_code: E_ACS_INSUFROLE, err_desc: "you must be admin to delete other accounts"); - $result = User_Delete($UserID); + // Actions - // If it was self-deletion - if ($UserID === $_SESSION["userid"]) - EndSession(); + $s = $db->prepare("delete from users where id = ?"); + $s->bind_param("s", $id); - ReturnJSONData(["success" => $result]); + return new ReturnT(data: ($s->execute() !== false)); +} + + + +if (Utils_ThisFileIsRequested(__FILE__)) { + require_once("../_json.php"); + + // HACK: for debugging purposes. Will be removed later + if ($Config["debug"]) + $_POST = $_REQUEST; + + $result = User_Delete_Method($_POST); + + if ($result->IsError()) { + $result->ThrowJSONError(); + } else { + // If it was self-deletion + if ($id === $THIS_USER) + EndSession(); + JSON_ReturnData(["success" => $result->GetData()]); + } } ?> \ No newline at end of file diff --git a/api/user/index.php b/api/user/index.php index a8abb0d..97c2c60 100644 --- a/api/user/index.php +++ b/api/user/index.php @@ -1,11 +1,19 @@ get_result()->fetch_assoc(); } -// Check if user has specified role +/* + * FUNCTION + * Check if user with supplied ID exists + */ +function User_IDExist ($id): bool { + global $db; + + $s = $db->prepare("SELECT * FROM users WHERE id = ?"); + $s->bind_param("s", $id); + $s->execute(); + + return (bool)$s->get_result()->fetch_assoc(); +} + +/* + * FUNCTION + * Check if user has specified role + */ function User_HasRole ($id, $role) { global $db; @@ -25,18 +50,19 @@ function User_HasRole ($id, $role) { $s->execute(); $d = $s->get_result()->fetch_assoc(); - if (!(bool)$d) { + if (!(bool)$d) return null; - } - if ($d["role"] == $role) { + if ($d["role"] == $role) return true; - } return false; } -// Check if user is moderator +/* + * FUNCTION + * Check if user is moderator (or higher) + */ function User_IsMod ($id) { global $db; @@ -52,9 +78,32 @@ function User_IsMod ($id) { return in_array($d["role"], array("mod", "admin")); } -// Get user information from DB -function User_GetInfoByID ($id) { - global $db, $THIS_USER; + + +// Methods + +/* + * METHOD + * Get user information from DB + */ +function User_GetInfoByID_Method (array $req): ReturnT { + global $db, $THIS_USER, $LOGGED_IN; + + // Input sanity checks + + $id = null; + if (isset($req["id"])) { + if (!ctype_digit($req["id"])) + return new ReturnT(err_code: E_UIN_BADARGS, err_desc: "id must be numeric"); + $id = intval($req["id"]); + } else { + if ($LOGGED_IN) + $id = $THIS_USER; + else + return new ReturnT(err_code: E_UIN_BADARGS, err_desc: "id must be specified or valid session must be provided"); + } + + // Actions $result = array(); @@ -63,9 +112,9 @@ function User_GetInfoByID ($id) { $s->execute(); $d = $s->get_result()->fetch_assoc(); - if (!(bool)$d) { - return null; - } + if (!(bool)$d) + return new ReturnT(err_code: E_UIN_WRONGID, err_desc: "user not found in database"); + //return new ReturnT(err_code: E_DBE_SELECTFAIL, err_desc: "failed to get user record"); $result["id"] = $d["id"]; $result["created_at"] = $d["created_at"]; @@ -78,32 +127,22 @@ function User_GetInfoByID ($id) { $result["invite_id"] = $d["invite_id"]; } - return $result; + return new ReturnT(data: $result); } -if (ThisFileIsRequested(__FILE__)) { +if (Utils_ThisFileIsRequested(__FILE__)) { require_once("../_json.php"); - $UserID = null; + $result = User_GetInfoByID_Method($_REQUEST); - if (isset($_REQUEST["id"])) { - if (!ctype_digit($_REQUEST["id"])) - ReturnJSONError($Err_RDP_InvalidID, "id must be numeric"); - $UserID = intval($_REQUEST["id"]); - } else { - if ($LOGGED_IN) - $UserID = $THIS_USER; - else - ReturnJSONError($Err_RDP_InvalidID, "id must be specified or valid session must be provided"); - } - - $ResponseData = User_GetInfoByID($UserID); - if ($ResponseData) - ReturnJSONData($ResponseData); + if ($result->IsError()) + $result->ThrowJSONError(); else - ReturnJSONError($Err_DP_IDNotFound, "wrong id"); + JSON_ReturnData($result->GetData()); } + + ?> \ No newline at end of file diff --git a/config.json b/config.json index 95a370a..10d6c33 100644 --- a/config.json +++ b/config.json @@ -16,6 +16,9 @@ "external_avatars": false }, "media": { + "pics_path": "media/pics/", + "prevs_path": "media/prevs/", + "previews_enabled": true, "max_pic_size": 56623104, "max_pic_res": { "x": 8192,