From 8b603d5e377bd627d99fce7419baaaad23f937f5 Mon Sep 17 00:00:00 2001 From: flashwave Date: Wed, 14 Sep 2016 00:05:03 +0200 Subject: [PATCH] and just a heap of shit --- app/Chat/Settings.php | 2 +- app/Controllers/AuthController.php | 3 +- app/Controllers/ChatController.php | 2 +- app/Controllers/FileController.php | 223 +++++++++++------- app/Controllers/Forum/ForumController.php | 6 +- app/Controllers/Forum/PostController.php | 35 +-- app/Controllers/Forum/TopicController.php | 186 +++++---------- app/Controllers/FriendsController.php | 2 +- app/Controllers/PremiumController.php | 14 +- .../Settings/AccountController.php | 6 +- .../Settings/AdvancedController.php | 6 +- .../Settings/AppearanceController.php | 191 --------------- app/Controllers/Settings/Controller.php | 9 - app/Controllers/UserController.php | 16 +- app/Exceptions/FileException.php | 16 ++ app/Forum/Post.php | 31 +++ config/config.example.ini | 9 +- database/2016_09_13_170928_soft_deleting.php | 35 +++ resources/views/aitemu/master.twig | 2 +- resources/views/aitemu/user/profile.twig | 2 +- resources/views/yuuno/elements/comment.twig | 4 +- resources/views/yuuno/elements/comments.twig | 6 +- .../views/yuuno/elements/indexPanel.twig | 2 +- resources/views/yuuno/elements/newsPost.twig | 2 +- resources/views/yuuno/forum/index.twig | 2 +- resources/views/yuuno/forum/topic.twig | 4 +- resources/views/yuuno/global/confirm.twig | 22 -- resources/views/yuuno/global/restricted.twig | 12 - resources/views/yuuno/master.twig | 4 +- resources/views/yuuno/meta/index.twig | 21 ++ resources/views/yuuno/profile/friends.twig | 2 +- .../settings/advanced/deactivate_bye.twig | 11 + .../yuuno/settings/appearance/avatar.twig | 27 --- .../yuuno/settings/appearance/background.twig | 25 -- .../yuuno/settings/appearance/header.twig | 27 --- .../views/yuuno/settings/friends/listing.twig | 2 +- .../yuuno/settings/friends/requests.twig | 2 +- resources/views/yuuno/user/members.twig | 4 +- resources/views/yuuno/user/profile.twig | 2 +- routes.php | 21 +- utility.php | 13 +- 41 files changed, 405 insertions(+), 606 deletions(-) create mode 100644 app/Exceptions/FileException.php create mode 100644 database/2016_09_13_170928_soft_deleting.php delete mode 100644 resources/views/yuuno/global/confirm.twig delete mode 100644 resources/views/yuuno/global/restricted.twig create mode 100644 resources/views/yuuno/settings/advanced/deactivate_bye.twig delete mode 100644 resources/views/yuuno/settings/appearance/avatar.twig delete mode 100644 resources/views/yuuno/settings/appearance/background.twig delete mode 100644 resources/views/yuuno/settings/appearance/header.twig diff --git a/app/Chat/Settings.php b/app/Chat/Settings.php index 1919963..4e6959d 100644 --- a/app/Chat/Settings.php +++ b/app/Chat/Settings.php @@ -259,7 +259,7 @@ class Settings "{$cpfx}id", "{$cpfx}session", ]; - $this->avatarUrl = route('file.avatar', '{0}', true); + $this->avatarUrl = route('user.avatar', '{0}', true); $this->profileUrl = route('user.profile', '{0}', true); $this->development = config('dev.show_errors'); $this->languagePath = config('chat.language_path'); diff --git a/app/Controllers/AuthController.php b/app/Controllers/AuthController.php index f638ee8..4b749ec 100644 --- a/app/Controllers/AuthController.php +++ b/app/Controllers/AuthController.php @@ -51,8 +51,7 @@ class AuthController extends Controller CurrentSession::stop(); // Return true indicating a successful logout - header('Location: ' . route('auth.login')); - return; + redirect(route('auth.login')); } /** diff --git a/app/Controllers/ChatController.php b/app/Controllers/ChatController.php index ce392ad..3ab8c90 100644 --- a/app/Controllers/ChatController.php +++ b/app/Controllers/ChatController.php @@ -36,7 +36,7 @@ class ChatController extends Controller */ public function redirect() { - header('Location: ' . config('chat.webclient')); + redirect(config('chat.webclient')); } /** diff --git a/app/Controllers/FileController.php b/app/Controllers/FileController.php index 643c2e0..20667f4 100644 --- a/app/Controllers/FileController.php +++ b/app/Controllers/FileController.php @@ -6,8 +6,15 @@ namespace Sakura\Controllers; +use Phroute\Phroute\Exception\HttpMethodNotAllowedException; +use Phroute\Phroute\Exception\HttpRouteNotFoundException; use Sakura\Config; +use Sakura\CurrentSession; +use Sakura\DB; +use Sakura\Exceptions\FileException; use Sakura\File; +use Sakura\Perms; +use Sakura\Perms\Manage; use Sakura\Perms\Site; use Sakura\Template; use Sakura\User; @@ -19,6 +26,15 @@ use Sakura\User; */ class FileController extends Controller { + /** + * Possible modes. + */ + const MODES = [ + 'avatar', + 'background', + 'header', + ]; + /** * The base for serving a file. * @param string $data @@ -28,126 +44,171 @@ class FileController extends Controller */ private function serve($data, $mime, $name) { - // Add original filename header("Content-Disposition: inline; filename={$name}"); - - // Set content type header("Content-Type: {$mime}"); - - // Return image data return $data; } /** - * Attempt to get an avatar. - * @param int $id - * @return string + * Handles file uploads. + * @param string $mode + * @param array $file + * @return array */ - public function avatar($id = 0) + private function upload($mode, $file, $user) { - $noAvatar = ROOT . 'public/' . str_replace( - '%tplname%', - Template::$name, - config('user.avatar_none') - ); - $none = [ - 'name' => basename($noAvatar), - 'data' => file_get_contents($noAvatar), - 'mime' => getimagesizefromstring($noAvatar)['mime'], - ]; + $error = null; - $bannedPath = ROOT . 'public/' . str_replace( - '%tplname%', - Template::$name, - config('user.avatar_ban') - ); - $banned = [ - 'name' => basename($bannedPath), - 'data' => file_get_contents($bannedPath), - 'mime' => getimagesizefromstring($bannedPath)['mime'], - ]; + // Handle errors + switch ($file['error']) { + case UPLOAD_ERR_OK: + break; - $user = User::construct($id); + case UPLOAD_ERR_INI_SIZE: + case UPLOAD_ERR_FORM_SIZE: + throw new FileException("Your file was too large!"); - if ($user->permission(Site::RESTRICTED)) { - return $this->serve($banned['data'], $banned['mime'], $banned['name']); + case UPLOAD_ERR_PARTIAL: + throw new FileException("The upload failed!"); + + case UPLOAD_ERR_NO_TMP_DIR: + case UPLOAD_ERR_CANT_WRITE: + throw new FileException("Wasn't able to save the file, contact a staff member!"); + + case UPLOAD_ERR_EXTENSION: + default: + throw new FileException("Something prevented the file upload!"); } - if ($user->id < 1 || !$user->avatar || $user->permission(Site::DEACTIVATED)) { - return $this->serve($none['data'], $none['mime'], $none['name']); + // Get the temp filename + $tmpName = $file['tmp_name']; + + // Get the image meta data + $meta = getimagesize($tmpName); + + // Check if image + if (!$meta + || ( + $meta[2] !== IMAGETYPE_GIF + && $meta[2] !== IMAGETYPE_JPEG + && $meta[2] !== IMAGETYPE_PNG + ) + ) { + throw new FileException("Please upload a valid image!"); } - $serve = new File($user->avatar); + // Check dimensions + $maxWidth = config("file.{$mode}.max_width"); + $maxHeight = config("file.{$mode}.max_height"); - if (!$serve->id) { - return $this->serve($none['data'], $none['mime'], $none['name']); + if ($meta[0] > $maxWidth + || $meta[1] > $maxHeight) { + throw new FileException("Your image can't be bigger than {$maxWidth}x{$maxHeight}" . + ", yours was {$meta[0]}x{$meta[1]}!"); } - return $this->serve($serve->data, $serve->mime, $serve->name); + // Check file size + $maxFileSize = config("file.{$mode}.max_file_size"); + + if (filesize($tmpName) > $maxFileSize) { + $maxSizeFmt = byte_symbol($maxFileSize); + + throw new FileException("Your image is not allowed to be larger than {$maxSizeFmt}!"); + } + + $userId = $user->id; + $ext = image_type_to_extension($meta[2]); + + $filename = "{$mode}_{$userId}{$ext}"; + + // Create the file + $file = File::create(file_get_contents($tmpName), $filename, $user); + + // Delete the old file + $this->delete($mode, $user); + + $column = "user_{$mode}"; + + // Save new avatar + DB::table('users') + ->where('user_id', $user->id) + ->update([ + $column => $file->id, + ]); } /** - * Attempt to get a background. - * @param int $id - * @return string + * Deletes a file. + * @param string $mode */ - public function background($id = 0) + public function delete($mode, $user) { - $noBg = ROOT . "public/images/pixel.png"; - $none = [ - 'name' => basename($noBg), - 'data' => file_get_contents($noBg), - 'mime' => getimagesizefromstring($noBg)['mime'], - ]; + $fileId = $user->{$mode}; - if (!$id) { - return $this->serve($none['data'], $none['mime'], $none['name']); + if ($fileId) { + (new File($fileId))->delete(); } - - $user = User::construct($id); - - if ($user->permission(Site::DEACTIVATED) - || $user->permission(Site::RESTRICTED) - || !$user->background) { - return $this->serve($none['data'], $none['mime'], $none['name']); - } - - $serve = new File($user->background); - - if (!$serve->id) { - return $this->serve($none['data'], $none['mime'], $none['name']); - } - - return $this->serve($serve->data, $serve->mime, $serve->name); } /** - * Attempt to get a profile header. - * @param int $id + * Catchall serve. + * @param string $method + * @param array $params + * @todo add a specific permission for mods to override uploads. * @return string */ - public function header($id = 0) + public function __call($method, $params) { - $noHeader = ROOT . "public/images/pixel.png"; - $none = [ - 'name' => basename($noHeader), - 'data' => file_get_contents($noHeader), - 'mime' => getimagesizefromstring($noHeader)['mime'], - ]; - - if (!$id) { - return $this->serve($none['data'], $none['mime'], $none['name']); + if (!in_array($method, self::MODES)) { + throw new HttpRouteNotFoundException; } - $user = User::construct($id); + $user = User::construct($params[0] ?? 0); + + if (session_check()) { + if (!CurrentSession::$user->permission(Manage::USE_MANAGE, Perms::MANAGE) + && ($user->id !== CurrentSession::$user->id + || !$user->permission(constant("Sakura\Perms\Site::CHANGE_" . strtoupper($method))) + || $user->permission(Site::DEACTIVATED) + || $user->permission(Site::RESTRICTED)) + ) { + throw new HttpMethodNotAllowedException; + } + + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $error = null; + + try { + $this->upload($method, $_FILES['file'] ?? null, $user); + } catch (FileException $e) { + $error = $e->getMessage(); + } + + return $this->json(compact('error')); + } elseif ($_SERVER['REQUEST_METHOD'] === 'DELETE') { + $this->delete($method, $user); + return; + } + } + + $noFile = ROOT . 'public/' . str_replace( + '%tplname%', + Template::$name, + config("user.{$method}_none") + ); + $none = [ + 'name' => basename($noFile), + 'data' => file_get_contents($noFile), + 'mime' => getimagesizefromstring($noFile)['mime'], + ]; if ($user->permission(Site::DEACTIVATED) || $user->permission(Site::RESTRICTED) - || !$user->header) { + || !$user->{$method}) { return $this->serve($none['data'], $none['mime'], $none['name']); } - $serve = new File($user->header); + $serve = new File($user->{$method}); if (!$serve->id) { return $this->serve($none['data'], $none['mime'], $none['name']); diff --git a/app/Controllers/Forum/ForumController.php b/app/Controllers/Forum/ForumController.php index 9c820b2..d17ebd8 100644 --- a/app/Controllers/Forum/ForumController.php +++ b/app/Controllers/Forum/ForumController.php @@ -118,7 +118,7 @@ class ForumController extends Controller // Redirect forum id 0 to the main page if ($forum->id === 0) { - header("Location: " . route('forums.index')); + redirect(route('forums.index')); return; } @@ -130,7 +130,7 @@ class ForumController extends Controller // Check if the forum isn't a link if ($forum->type === 2) { - header("Location: {$forum->link}"); + redirect($forum->link); return; } @@ -158,6 +158,6 @@ class ForumController extends Controller $forum->trackUpdateAll(CurrentSession::$user->id); - header("Location: " . route('forums.forum', $forum->id)); + redirect(route('forums.forum', $forum->id)); } } diff --git a/app/Controllers/Forum/PostController.php b/app/Controllers/Forum/PostController.php index 6ffc7e4..d3c6a29 100644 --- a/app/Controllers/Forum/PostController.php +++ b/app/Controllers/Forum/PostController.php @@ -57,7 +57,7 @@ class PostController extends Controller $topicLink .= "?page={$postAt}"; } - return header("Location: {$topicLink}#p{$post->id}"); + redirect("{$topicLink}#p{$post->id}"); } /** @@ -178,7 +178,7 @@ class PostController extends Controller $postLink = route('forums.post', $post->id); - return header("Location: {$postLink}"); + redirect($postLink); } /** @@ -211,30 +211,19 @@ class PostController extends Controller throw new HttpMethodNotAllowedException(); } - if (session_check('sessionid')) { - if (isset($_POST['yes'])) { - // Check if the topic only has 1 post - if ($topic->replyCount() === 1) { - // Delete the entire topic - $topic->delete(); + // Check if the topic only has 1 post + if ($topic->replyCount() === 1) { + // Delete the entire topic + $topic->delete(); - $redirect = route('forums.forum', $forum->id); - } else { - // Just delete the post - $post->delete(); + $redirect = route('forums.forum', $forum->id); + } else { + // Just delete the post (replace this with soft deleting) + $post->purge(); - $redirect = route('forums.topic', $topic->id); - } - } else { - $redirect = route('forums.post', $post->id); - } - - header("Location: {$redirect}"); - return; + $redirect = route('forums.topic', $topic->id); } - $message = "Are you sure?"; - - return view('global/confirm', compact('message')); + redirect($redirect); } } diff --git a/app/Controllers/Forum/TopicController.php b/app/Controllers/Forum/TopicController.php index 6bb6027..c8f60bf 100644 --- a/app/Controllers/Forum/TopicController.php +++ b/app/Controllers/Forum/TopicController.php @@ -6,6 +6,8 @@ namespace Sakura\Controllers\Forum; +use Phroute\Phroute\Exception\HttpMethodNotAllowedException; +use Phroute\Phroute\Exception\HttpRouteNotFoundException; use Sakura\CurrentSession; use Sakura\Forum\Forum; use Sakura\Forum\Post; @@ -22,6 +24,7 @@ class TopicController extends Controller /** * Views a topic. * @param int $id + * @throws HttpRouteNotFoundException * @return string */ public function view($id = 0) @@ -32,10 +35,7 @@ class TopicController extends Controller // Check if the forum exists if ($topic->id === 0 || !$forum->permission(ForumPerms::VIEW, CurrentSession::$user->id)) { - $message = "This topic doesn't exist or you don't have access to it!"; - $redirect = route('forums.index'); - - return view('global/information', compact('message', 'redirect')); + throw new HttpRouteNotFoundException; } $topic->trackUpdate(CurrentSession::$user->id); @@ -47,6 +47,7 @@ class TopicController extends Controller /** * Checks if a user can moderate the topic. * @param int $id + * @throws HttpRouteNotFoundException * @return array */ private function modBase($id) @@ -60,194 +61,136 @@ class TopicController extends Controller return compact('topic', 'forum'); } - return false; + throw new HttpRouteNotFoundException; } /** * Sticky a topic. * @param int $id + * @throws HttpMethodNotAllowedException * @return string */ public function sticky($id) { - $modBase = $this->modBase($id); - $redirect = route('forums.index'); - $message = "This forum doesn't exist or you don't have access to it."; + extract($this->modBase($id)); - if ($modBase !== false) { - extract($modBase); - $redirect = route('forums.topic', $topic->id); - - if ($forum->permission(ForumPerms::STICKY, CurrentSession::$user->id)) { - $topic->type = $topic->type !== 1 ? 1 : 0; - $topic->update(); - $message = $topic->type - ? 'Changed the topic to sticky!' : 'Reverted the topic back to normal!'; - } else { - $message = "You aren't allowed to sticky topics!"; - } + if (!$forum->permission(ForumPerms::STICKY, CurrentSession::$user->id)) { + throw new HttpMethodNotAllowedException; } - return view('global/information', compact('message', 'redirect')); + $topic->type = $topic->type !== 1 ? 1 : 0; + $topic->update(); + + redirect(route('forums.topic', $topic->id)); } /** * Announce a topic. * @param int $id + * @throws HttpMethodNotAllowedException * @return string */ public function announce($id) { - $modBase = $this->modBase($id); - $redirect = route('forums.index'); - $message = "This forum doesn't exist or you don't have access to it."; + extract($this->modBase($id)); - if ($modBase !== false) { - extract($modBase); - $redirect = route('forums.topic', $topic->id); - - if ($forum->permission(ForumPerms::ANNOUNCEMENT, CurrentSession::$user->id)) { - $topic->type = $topic->type !== 2 ? 2 : 0; - $topic->update(); - $message = $topic->type - ? 'Changed the topic to an announcement!' : 'Reverted the topic back to normal!'; - } else { - $message = "You aren't allowed to announce topics!"; - } + if (!$forum->permission(ForumPerms::ANNOUNCEMENT, CurrentSession::$user->id)) { + throw new HttpMethodNotAllowedException; } - return view('global/information', compact('message', 'redirect')); + $topic->type = $topic->type !== 2 ? 2 : 0; + $topic->update(); + + redirect(route('forums.topic', $topic->id)); } /** * Lock a topic. * @param int $id + * @throws HttpMethodNotAllowedException * @return string */ public function lock($id) { - $modBase = $this->modBase($id); - $redirect = route('forums.index'); - $message = "This forum doesn't exist or you don't have access to it."; + extract($this->modBase($id)); - if ($modBase !== false) { - extract($modBase); - $redirect = route('forums.topic', $topic->id); - - if ($forum->permission(ForumPerms::LOCK, CurrentSession::$user->id)) { - $topic->status = $topic->status !== 1 ? 1 : 0; - $topic->update(); - $message = ($topic->status ? 'Locked' : 'Unlocked') . ' the topic!'; - } else { - $message = "You aren't allowed to lock topics!"; - } + if (!$forum->permission(ForumPerms::LOCK, CurrentSession::$user->id)) { + throw new HttpMethodNotAllowedException; } - return view('global/information', compact('message', 'redirect')); + $topic->status = $topic->status !== 1 ? 1 : 0; + $topic->update(); + + redirect(route('forums.topic', $topic->id)); } /** * Delete an entire topic. * @param int $id + * @throws HttpMethodNotAllowedException * @return string */ public function delete($id) { - $modBase = $this->modBase($id); - $redirect = route('forums.index'); - $message = "This forum doesn't exist or you don't have access to it."; + extract($this->modBase($id)); - if ($modBase !== false) { - extract($modBase); - $trash = config('forum.trash'); + $trash = intval(config('forum.trash')); - // Check if we're operating from the trash - if ($topic->forum === $trash) { - if ($forum->permission(ForumPerms::DELETE_ANY, CurrentSession::$user->id)) { - $topic->delete(); - $message = "Deleted the topic!"; - $redirect = route('forums.forum', $trash); - } else { - $message = "You aren't allowed to delete topics!"; - } - } else { - $redirect = route('forums.topic', $topic->id); - - if ($forum->permission(ForumPerms::MOVE, CurrentSession::$user->id)) { - $topic->move($trash); - $message = "Moved the topic to the trash!"; - } else { - $message = "You're not allowed to do this!"; - } - } + if ($topic->forum === $trash + && $forum->permission(ForumPerms::DELETE_ANY, CurrentSession::$user->id)) { + $redirect = route('forums.forum', $trash); + $topic->delete(); + } elseif ($forum->permission(ForumPerms::MOVE, CurrentSession::$user->id)) { + $redirect = route('forums.topic', $topic->id); + $topic->move($trash); + } else { + throw new HttpMethodNotAllowedException; } - return view('global/information', compact('message', 'redirect')); + redirect($redirect); } /** * Restore a topic to its previous location. * @param int $id + * @throws HttpMethodNotAllowedException * @return string */ public function restore($id) { - $modBase = $this->modBase($id); - $redirect = route('forums.index'); - $message = "This forum doesn't exist or you don't have access to it."; + extract($this->modBase($id)); - if ($modBase !== false) { - extract($modBase); - $redirect = route('forums.topic', $topic->id); - - if ($forum->permission(ForumPerms::MOVE, CurrentSession::$user->id)) { - if ($topic->oldForum) { - $topic->move($topic->oldForum, false); - - $message = "Moved the topic back to it's old location!"; - } else { - $message = "This topic has never been moved!"; - } - } else { - $message = "You aren't allowed to move threads!"; - } + if (!$forum->permission(ForumPerms::MOVE, CurrentSession::$user->id)) { + throw new HttpMethodNotAllowedException; } - return view('global/information', compact('message', 'redirect')); + if ($topic->oldForum) { + $topic->move($topic->oldForum, false); + } + + redirect(route('forums.topic', $topic->id)); } /** * Move a topic. * @param int $id + * @throws HttpMethodNotAllowedException * @return string */ public function move($id) { - $modBase = $this->modBase($id); - $redirect = route('forums.index'); - $message = "This forum doesn't exist or you don't have access to it."; + extract($this->modBase($id)); + $dest_forum = new Forum($_REQUEST['forum_id'] ?? 0); - if ($modBase !== false) { - extract($modBase); - $redirect = route('forums.topic', $topic->id); - - if ($forum->permission(ForumPerms::MOVE, CurrentSession::$user->id)) { - $dest_forum = new Forum($_REQUEST['forum_id'] ?? 0); - - if ($dest_forum->id === 0 - || $dest_forum->permission(ForumPerms::VIEW, CurrentSession::$user->id)) { - $topic->move($dest_forum->id); - - $message = "Moved to the topic to {$dest_forum->name}!"; - } else { - $message = "The destination forum doesn't exist or you don't have access to it."; - } - } else { - $message = "You aren't allowed to move threads!"; - } + if (!$forum->permission(ForumPerms::MOVE, CurrentSession::$user->id) + || $dest_forum->id === 0 + || $dest_forum->permission(ForumPerms::VIEW, CurrentSession::$user->id)) { + throw new HttpMethodNotAllowedException; } - return view('global/information', compact('message', 'redirect')); + $topic->move($dest_forum->id); + + redirect(route('forums.topic', $topic->id)); } /** @@ -330,7 +273,7 @@ class TopicController extends Controller $postLink = route('forums.post', $post->id); // Head to the post - return header("Location: {$postLink}"); + redirect($postLink); } /** @@ -418,7 +361,8 @@ class TopicController extends Controller $postLink = route('forums.post', $post->id); // Head to the post - return header("Location: {$postLink}"); + redirect($postLink); + return; } return view('forum/topic', compact('forum')); diff --git a/app/Controllers/FriendsController.php b/app/Controllers/FriendsController.php index 7c7eb50..12b4a7e 100644 --- a/app/Controllers/FriendsController.php +++ b/app/Controllers/FriendsController.php @@ -33,7 +33,7 @@ class FriendsController extends Controller $alert->time = time(); $alert->title = $title; $alert->text = $text; - $alert->image = route('file.avatar', $user->id); + $alert->image = route('user.avatar', $user->id); $alert->timeout = 60000; $alert->link = route('user.profile', $user->id); diff --git a/app/Controllers/PremiumController.php b/app/Controllers/PremiumController.php index ebbc67d..30a0222 100644 --- a/app/Controllers/PremiumController.php +++ b/app/Controllers/PremiumController.php @@ -67,7 +67,7 @@ class PremiumController extends Controller // Check months if ($months < 1 || $months > $amountLimit) { - header("Location: " . route('premium.error')); + redirect(route('premium.error')); return; } @@ -97,14 +97,14 @@ class PremiumController extends Controller // Attempt to create a transaction if (!$transaction) { - header("Location: " . route('premium.error')); + redirect(route('premium.error')); return; } // Store the amount of months in the global session array $_SESSION['premiumMonths'] = (int) $months; - return header("Location: {$transaction}"); + redirect($transaction); } /** @@ -125,7 +125,8 @@ class PremiumController extends Controller || !$payment || !$payer || !$months) { - return header("Location: {$failRoute}"); + redirect($failRoute); + return; } // Attempt to complete the transaction @@ -136,12 +137,13 @@ class PremiumController extends Controller } if (!$finalise) { - return header("Location: {$failRoute}"); + redirect($failRoute); + return; } CurrentSession::$user->addPremium(self::PERIOD_PER_PAYMENT * $months); - return header("Location: {$successRoute}"); + redirect($successRoute); } /** diff --git a/app/Controllers/Settings/AccountController.php b/app/Controllers/Settings/AccountController.php index 3a2acaa..4f6f8c6 100644 --- a/app/Controllers/Settings/AccountController.php +++ b/app/Controllers/Settings/AccountController.php @@ -80,7 +80,7 @@ class AccountController extends Controller ]); } - header("Location: {$redirect}"); + redirect($redirect); return; } @@ -212,7 +212,7 @@ class AccountController extends Controller $user->setPassword($password); } - header("Location: {$redirect}"); + redirect($redirect); return; } @@ -271,7 +271,7 @@ class AccountController extends Controller CurrentSession::$user->setMainRank($rank); - header("Location: {$redirect}"); + redirect($redirect); return; } diff --git a/app/Controllers/Settings/AdvancedController.php b/app/Controllers/Settings/AdvancedController.php index 2678496..e240517 100644 --- a/app/Controllers/Settings/AdvancedController.php +++ b/app/Controllers/Settings/AdvancedController.php @@ -54,7 +54,7 @@ class AdvancedController extends Controller // Delete it $session->delete(); - header("Location: {$redirect}"); + redirect($redirect); return; } @@ -94,9 +94,7 @@ class AdvancedController extends Controller // Destroy all active sessions CurrentSession::$user->purgeSessions(); - $redirect = route('main.index'); - $message = "Farewell!"; - return view('global/information', compact('message', 'redirect')); + return view('settings/advanced/deactivate_bye'); } return view('settings/advanced/deactivate'); diff --git a/app/Controllers/Settings/AppearanceController.php b/app/Controllers/Settings/AppearanceController.php index f8d64e2..3bf07c2 100644 --- a/app/Controllers/Settings/AppearanceController.php +++ b/app/Controllers/Settings/AppearanceController.php @@ -9,7 +9,6 @@ namespace Sakura\Controllers\Settings; use Phroute\Phroute\Exception\HttpMethodNotAllowedException; use Sakura\CurrentSession; use Sakura\DB; -use Sakura\File; use Sakura\Perms\Site; /** @@ -19,196 +18,6 @@ use Sakura\Perms\Site; */ class AppearanceController extends Controller { - /** - * Handles file uploads. - * @param string $mode - * @param array $file - * @return array - */ - private function handleUpload($mode, $file) - { - // Handle errors - switch ($file['error']) { - case UPLOAD_ERR_OK: - break; - - case UPLOAD_ERR_INI_SIZE: - case UPLOAD_ERR_FORM_SIZE: - return "Your file was too large!"; - - case UPLOAD_ERR_PARTIAL: - return "The upload failed!"; - - case UPLOAD_ERR_NO_TMP_DIR: - case UPLOAD_ERR_CANT_WRITE: - return "Wasn't able to save the file, contact a staff member!"; - - case UPLOAD_ERR_EXTENSION: - default: - return "Something prevented the file upload!"; - } - - // Get the temp filename - $tmpName = $_FILES[$mode]['tmp_name']; - - // Get the image meta data - $meta = getimagesize($tmpName); - - // Check if image - if (!$meta - || ( - $meta[2] !== IMAGETYPE_GIF - && $meta[2] !== IMAGETYPE_JPEG - && $meta[2] !== IMAGETYPE_PNG - ) - ) { - return "Please upload a valid image!"; - } - - $confp = $mode === 'header' ? 'cover' : $mode; - - // Check dimensions - $maxWidth = config("file.{$confp}.max_width"); - $maxHeight = config("file.{$confp}.max_height"); - - if ($meta[0] > $maxWidth - || $meta[1] > $maxHeight) { - return "Your image has to be at least {$minWidth}x{$minHeight}" - . " and not bigger than {$maxWidth}x{$maxHeight}, yours was {$meta[0]}x{$meta[1]}!"; - } - - // Check file size - $maxFileSize = config("file.{$confp}.max_file_size"); - - if (filesize($tmpName) > $maxFileSize) { - $maxSizeFmt = byte_symbol($maxFileSize); - - return "Your image is not allowed to be larger than {$maxSizeFmt}!"; - } - - $userId = CurrentSession::$user->id; - $ext = image_type_to_extension($meta[2]); - - $filename = "{$mode}_{$userId}{$ext}"; - - // Create the file - $file = File::create(file_get_contents($tmpName), $filename, CurrentSession::$user); - - // Delete the old file - $this->deleteFile($mode); - - $column = "user_{$mode}"; - - // Save new avatar - DB::table('users') - ->where('user_id', CurrentSession::$user->id) - ->update([ - $column => $file->id, - ]); - - return null; - } - - /** - * Deletes a file. - * @param string $mode - */ - public function deleteFile($mode) - { - $fileId = CurrentSession::$user->{$mode}; - - if ($fileId) { - (new File($fileId))->delete(); - } - } - - /** - * Renders the avatar changing page - * @return string - */ - public function avatar() - { - // Check permission - if (!CurrentSession::$user->permission(Site::CHANGE_AVATAR)) { - throw new HttpMethodNotAllowedException(); - } - - if (session_check()) { - $avatar = $_FILES['avatar'] ?? null; - $redirect = route('settings.appearance.avatar'); - - if ($avatar && $avatar['error'] !== UPLOAD_ERR_NO_FILE) { - $upload = $this->handleUpload('avatar', $_FILES['avatar']); - $message = $upload !== null ? $upload : "Changed your avatar!"; - } else { - $this->deleteFile('avatar'); - $message = "Deleted your avatar!"; - } - - return view('global/information', compact('message', 'redirect')); - } - - return view('settings/appearance/avatar'); - } - - /** - * Renders the background changing page. - * @return string - */ - public function background() - { - // Check permission - if (!CurrentSession::$user->permission(Site::CHANGE_BACKGROUND)) { - throw new HttpMethodNotAllowedException(); - } - - if (session_check()) { - $background = $_FILES['background'] ?? null; - $redirect = route('settings.appearance.background'); - - if ($background && $background['error'] !== UPLOAD_ERR_NO_FILE) { - $upload = $this->handleUpload('background', $_FILES['background']); - $message = $upload !== null ? $upload : "Changed your background!"; - } else { - $this->deleteFile('background'); - $message = "Deleted your background!"; - } - - return view('global/information', compact('message', 'redirect')); - } - - return view('settings/appearance/background'); - } - - /** - * Renders the banner changing page. - * @return string - */ - public function header() - { - // Check permission - if (!CurrentSession::$user->permission(Site::CHANGE_HEADER)) { - throw new HttpMethodNotAllowedException(); - } - - if (session_check()) { - $header = $_FILES['header'] ?? null; - $redirect = route('settings.appearance.header'); - - if ($header && $header['error'] !== UPLOAD_ERR_NO_FILE) { - $upload = $this->handleUpload('header', $_FILES['header']); - $message = $upload !== null ? $upload : "Changed your header!"; - } else { - $this->deleteFile('header'); - $message = "Deleted your header!"; - } - - return view('global/information', compact('message', 'redirect')); - } - - return view('settings/appearance/header'); - } - /** * Renders the userpage editing page. */ diff --git a/app/Controllers/Settings/Controller.php b/app/Controllers/Settings/Controller.php index fa997c9..0cba411 100644 --- a/app/Controllers/Settings/Controller.php +++ b/app/Controllers/Settings/Controller.php @@ -55,15 +55,6 @@ class Controller extends BaseController } // Appearance - if (CurrentSession::$user->permission(Site::CHANGE_AVATAR)) { - $nav["Appearance"]["Avatar"] = route('settings.appearance.avatar'); - } - if (CurrentSession::$user->permission(Site::CHANGE_BACKGROUND)) { - $nav["Appearance"]["Background"] = route('settings.appearance.background'); - } - if (CurrentSession::$user->permission(Site::CHANGE_HEADER)) { - $nav["Appearance"]["Header"] = route('settings.appearance.header'); - } if (( CurrentSession::$user->page && CurrentSession::$user->permission(Site::CHANGE_USERPAGE) diff --git a/app/Controllers/UserController.php b/app/Controllers/UserController.php index 720ce96..637dd83 100644 --- a/app/Controllers/UserController.php +++ b/app/Controllers/UserController.php @@ -6,6 +6,7 @@ namespace Sakura\Controllers; +use Phroute\Phroute\Exception\HttpMethodNotAllowedException; use Sakura\Config; use Sakura\CurrentSession; use Sakura\DB; @@ -31,7 +32,7 @@ class UserController extends Controller $profile = User::construct($id); // If the user id is zero check if there was a namechange - if ($profile->id == 0) { + if ($profile->id === 0) { // Fetch from username_history $check = DB::table('username_history') ->where('username_old_clean', clean_string($id, true, true)) @@ -40,9 +41,8 @@ class UserController extends Controller // Redirect if so if ($check) { - $message = "This user changed their username! Redirecting you to their new profile."; - $redirect = route('user.profile', $check->user_id); - return view('global/information', compact('message', 'redirect')); + redirect(route('user.profile', $check->user_id)); + return; } } @@ -52,13 +52,14 @@ class UserController extends Controller /** * Display the memberlist. * @param int $rank + * @throws HttpMethodNotAllowedException * @return string */ public function members($rank = null) { // Check permission if (!CurrentSession::$user->permission(Site::VIEW_MEMBERLIST)) { - return view('global/restricted'); + throw new HttpMethodNotAllowedException; } // Get all ranks @@ -79,10 +80,7 @@ class UserController extends Controller // Get the active rank $rank = array_key_exists($rank, $ranks) ? $rank : ($rank ? 0 : intval(config("rank.regular"))); - // Get members per page - $membersPerPage = 30; - - return view('user/members', compact('ranks', 'rank', 'membersPerPage')); + return view('user/members', compact('ranks', 'rank')); } /** diff --git a/app/Exceptions/FileException.php b/app/Exceptions/FileException.php new file mode 100644 index 0000000..e8e2e7d --- /dev/null +++ b/app/Exceptions/FileException.php @@ -0,0 +1,16 @@ + + */ +class FileException extends BaseException +{ +} diff --git a/app/Forum/Post.php b/app/Forum/Post.php index 82d1af5..5195759 100644 --- a/app/Forum/Post.php +++ b/app/Forum/Post.php @@ -91,6 +91,12 @@ class Post */ public $editUser = null; + /** + * Post deleted? + * @var bool + */ + public $deleted = false; + /** * Constructor. * @param int $postId @@ -114,6 +120,7 @@ class Post $this->editTime = intval($postRow->post_edit_time); $this->editReason = $postRow->post_edit_reason; $this->editUser = User::construct($postRow->post_edit_user); + $this->deleted = boolval($postRow->post_deleted); // Temporary backwards compatible IP storage system try { @@ -199,10 +206,34 @@ class Post return new Post($this->id); } + /** + * Undo deletion. + */ + public function restore() + { + DB::table('posts') + ->where('post_id', $this->id) + ->update([ + 'post_deleted' => 0, + ]); + } + /** * delete this. */ public function delete() + { + DB::table('posts') + ->where('post_id', $this->id) + ->update([ + 'post_deleted' => 1, + ]); + } + + /** + * DELETE THIS. + */ + public function purge() { DB::table('posts') ->where('post_id', $this->id) diff --git a/config/config.example.ini b/config/config.example.ini index 5d4e314..51138c7 100644 --- a/config/config.example.ini +++ b/config/config.example.ini @@ -124,17 +124,18 @@ max_file_size = 5242880 max_height = 1440 max_width = 2560 -; Cover requirements -[file.cover] +; Header requirements +[file.header] max_file_size = 2097152 max_height = 500 max_width = 2048 ; User settings [user] -; Avatars (relative to public/) -avatar_ban = images/%tplname%-ban.png +; Default avatar, background and header (relative to public/) avatar_none = images/%tplname%-none.png +background_none = images/pixel.png +header_none = images/pixel.png ; Username constraints name_min = 3 diff --git a/database/2016_09_13_170928_soft_deleting.php b/database/2016_09_13_170928_soft_deleting.php new file mode 100644 index 0000000..f4efd82 --- /dev/null +++ b/database/2016_09_13_170928_soft_deleting.php @@ -0,0 +1,35 @@ +table('posts', function (Blueprint $table) { + $table->tinyInteger('post_deleted') + ->nullable() + ->default(0); + }); + } + + /** + * Reverse the migrations. + * @return void + */ + public function down() + { + $schema = DB::getSchemaBuilder(); + + $schema->table('posts', function (Blueprint $table) { + $table->dropColumn('post_deleted'); + }); + } +} diff --git a/resources/views/aitemu/master.twig b/resources/views/aitemu/master.twig index 366ae1a..9ca705e 100644 --- a/resources/views/aitemu/master.twig +++ b/resources/views/aitemu/master.twig @@ -36,7 +36,7 @@ {% if user.isActive %}
{{ user.username }}
-
+
{% else %} diff --git a/resources/views/aitemu/user/profile.twig b/resources/views/aitemu/user/profile.twig index 21fb018..81f624d 100644 --- a/resources/views/aitemu/user/profile.twig +++ b/resources/views/aitemu/user/profile.twig @@ -115,7 +115,7 @@ {% block content %}
-
+
{# #}{% for id, data in hierarchies %}{# #}{% if data.display %} diff --git a/resources/views/yuuno/elements/comment.twig b/resources/views/yuuno/elements/comment.twig index 11dccd6..abf039f 100644 --- a/resources/views/yuuno/elements/comment.twig +++ b/resources/views/yuuno/elements/comment.twig @@ -1,6 +1,6 @@
  • {% endif %} -
  • +
  • {{ comment.downvotes }}
  • diff --git a/resources/views/yuuno/elements/comments.twig b/resources/views/yuuno/elements/comments.twig index cd3789e..278b2d3 100644 --- a/resources/views/yuuno/elements/comments.twig +++ b/resources/views/yuuno/elements/comments.twig @@ -2,7 +2,7 @@
    {% if user.isActive %}
    -
    +
    @@ -65,7 +65,7 @@ var avatar = document.createElement('a'); avatar.className = 'comment-avatar clean'; avatar.href = "{{ route('user.profile', 1) }}".replace(1, obj.user); - avatar.style.backgroundImage = "url('{{ route('file.avatar', 1) }}')".replace(1, obj.user); + avatar.style.backgroundImage = "url('{{ route('user.avatar', 1) }}')".replace(1, obj.user); inner.appendChild(avatar); var pointer = document.createElement('div'); @@ -104,7 +104,7 @@ controlsReply.href = 'javascript:void(0);'; controlsReply.title = 'Reply'; controlsReply.className = 'clean fa fa-reply'; - controlsReply.setAttribute('onclick', 'commentReply(' + obj.id + ', "{{ session_id() }}", "{{ route("file.avatar", user.id) }}");'); + controlsReply.setAttribute('onclick', 'commentReply(' + obj.id + ', "{{ session_id() }}", "{{ route("user.avatar", user.id) }}");'); controlsReplyContainer.appendChild(controlsReply); controlsInner.appendChild(controlsReplyContainer); diff --git a/resources/views/yuuno/elements/indexPanel.twig b/resources/views/yuuno/elements/indexPanel.twig index 62cbc8d..b0897ac 100644 --- a/resources/views/yuuno/elements/indexPanel.twig +++ b/resources/views/yuuno/elements/indexPanel.twig @@ -1,7 +1,7 @@
    {% if user.isActive %}
    -
    +

    {{ user.username }}

    {% set friendRequests = user.friends(-1, true)|length %} diff --git a/resources/views/yuuno/elements/newsPost.twig b/resources/views/yuuno/elements/newsPost.twig index 4669642..499ea68 100644 --- a/resources/views/yuuno/elements/newsPost.twig +++ b/resources/views/yuuno/elements/newsPost.twig @@ -2,7 +2,7 @@
    - {{ post.userData.username }} + {{ post.userData.username }}

    {{ post.userData.username }}

    diff --git a/resources/views/yuuno/forum/index.twig b/resources/views/yuuno/forum/index.twig index c1d6ee5..716c5be 100644 --- a/resources/views/yuuno/forum/index.twig +++ b/resources/views/yuuno/forum/index.twig @@ -46,7 +46,7 @@ {% if activePoster.id %}
    -
    +

    {{ activePoster.username }}

    {% if activePoster.isPremium %}Tenshi {% endif %}{{ activePoster.country }} {{ activePoster.title }} diff --git a/resources/views/yuuno/forum/topic.twig b/resources/views/yuuno/forum/topic.twig index cfc5d47..7281127 100644 --- a/resources/views/yuuno/forum/topic.twig +++ b/resources/views/yuuno/forum/topic.twig @@ -80,7 +80,7 @@ {% if not post.poster.permission(constant('Sakura\\Perms\\Site::DEACTIVATED')) or post.poster.permission(constant('Sakura\\Perms\\Site::RESTRICTED')) %}
    {{ post.poster.username }} - {{ post.poster.username }} + {{ post.poster.username }} {% else %} [deleted user] {% endif %} @@ -136,7 +136,7 @@ {{ user.username }} - {{ user.username }} + {{ user.username }}
    {{ user.title }}
    Tenshi {{ user.country(true) }}{% if user.id == (topic.posts|first).poster.id %} OP{% endif %} diff --git a/resources/views/yuuno/global/confirm.twig b/resources/views/yuuno/global/confirm.twig deleted file mode 100644 index 6bb069e..0000000 --- a/resources/views/yuuno/global/confirm.twig +++ /dev/null @@ -1,22 +0,0 @@ -{% extends 'master.twig' %} - -{% set title = 'Confirmation' %} - -{% block content %} -
    -
    -

    {% block header %}Confirmation{% endblock %}

    -
    - {{ message }} -
    - - - {% for key,value in conditions %} - - {% endfor %} - - -
    -
    -
    -{% endblock %} diff --git a/resources/views/yuuno/global/restricted.twig b/resources/views/yuuno/global/restricted.twig deleted file mode 100644 index bcb87b1..0000000 --- a/resources/views/yuuno/global/restricted.twig +++ /dev/null @@ -1,12 +0,0 @@ -{% extends 'master.twig' %} - -{% set title = 'Restricted' %} - -{% block content %} -
    -
    -

    You aren't allowed to view this page!

    - Please make sure that you're logged in and are supposed to be able to access this page. If you think this was a mistake please contact a staff member. -
    -
    -{% endblock %} diff --git a/resources/views/yuuno/master.twig b/resources/views/yuuno/master.twig index 1564490..5015a30 100644 --- a/resources/views/yuuno/master.twig +++ b/resources/views/yuuno/master.twig @@ -47,7 +47,7 @@