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 %}
{% else %}
{{ 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 }}
{{ activePoster.username }}
{% if activePoster.isPremium %} {% endif %} {{ 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 @@{% block header %}Confirmation{% endblock %}
-- {{ message }} - -
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. -avatarbackground upload test form!!avatar backgroundheader upload test form!!Farewell!
+ +Remember that you can reactivate your account anytime if you decide to come back!
+Maximum image size is {{ config('file.avatar.max_width') }}x{{ config('file.avatar.max_height') }} and can't be larger than {{ config('file.avatar.max_file_size')|byte_symbol }}.
-{% endblock %} - -{% block settingsContent %} - -{% endblock %} diff --git a/resources/views/yuuno/settings/appearance/background.twig b/resources/views/yuuno/settings/appearance/background.twig deleted file mode 100644 index 07fd8d8..0000000 --- a/resources/views/yuuno/settings/appearance/background.twig +++ /dev/null @@ -1,25 +0,0 @@ -{% extends 'settings/appearance/master.twig' %} - -{% set mode = 'Background' %} -{% set showBG = true %} - -{% block description %} -Maximum image size is {{ config('file.background.max_width') }}x{{ config('file.background.max_height') }} and can't be larger than {{ config('file.background.max_file_size')|byte_symbol }}.
-{% endblock %} - -{% block settingsContent %} - -{% endblock %} diff --git a/resources/views/yuuno/settings/appearance/header.twig b/resources/views/yuuno/settings/appearance/header.twig deleted file mode 100644 index 690645f..0000000 --- a/resources/views/yuuno/settings/appearance/header.twig +++ /dev/null @@ -1,27 +0,0 @@ -{% extends 'settings/appearance/master.twig' %} - -{% set mode = 'Header' %} - -{% block description %} -Maximum image size is {{ config('file.cover.max_width') }}x{{ config('file.cover.max_height') }} and can't be larger than {{ config('file.cover.max_file_size')|byte_symbol }}.
-{% endblock %} - -{% block settingsContent %} - -{% endblock %} diff --git a/resources/views/yuuno/settings/friends/listing.twig b/resources/views/yuuno/settings/friends/listing.twig index 81c40d4..a554da2 100644 --- a/resources/views/yuuno/settings/friends/listing.twig +++ b/resources/views/yuuno/settings/friends/listing.twig @@ -17,7 +17,7 @@ {% for friend in friends[get.page|default(1) - 1] %}{{ profile.username }}
{% if profile.isPremium %} {% endif %} {{ profile.title }} diff --git a/routes.php b/routes.php index 8222f8e..0dcf77f 100644 --- a/routes.php +++ b/routes.php @@ -163,7 +163,18 @@ Routerv1::group(['before' => 'maintenance'], function () { Routerv1::group(['prefix' => 'u'], function () { Routerv1::get('/{id}', 'UserController@profile', 'user.profile'); Routerv1::get('/{id}/report', 'UserController@report', 'user.report'); + + Routerv1::get('/{id}/avatar', 'FileController@avatar', 'user.avatar'); + Routerv1::post('/{id}/avatar', 'FileController@avatar', 'user.avatar'); + Routerv1::delete('/{id}/avatar', 'FileController@avatar', 'user.avatar'); + + Routerv1::get('/{id}/background', 'FileController@background', 'user.background'); + Routerv1::post('/{id}/background', 'FileController@background', 'user.background'); + Routerv1::delete('/{id}/background', 'FileController@background', 'user.background'); + Routerv1::get('/{id}/header', 'FileController@header', 'user.header'); + Routerv1::post('/{id}/header', 'FileController@header', 'user.header'); + Routerv1::delete('/{id}/header', 'FileController@header', 'user.header'); }); // Notifications @@ -185,10 +196,6 @@ Routerv1::group(['before' => 'maintenance'], function () { Routerv1::post('/{id:i}/remove', 'FriendsController@remove', 'friends.remove'); }); - // Files - Routerv1::get('/a/{id}', 'FileController@avatar', 'file.avatar'); - Routerv1::get('/bg/{id}', 'FileController@background', 'file.background'); - // Premium Routerv1::group(['prefix' => 'support', 'before' => 'loginCheck'], function () { Routerv1::get('/', 'PremiumController@index', 'premium.index'); @@ -256,12 +263,6 @@ Routerv1::group(['before' => 'maintenance'], function () { return header("Location: {$route}"); }); - Routerv1::get('/avatar', 'Settings.AppearanceController@avatar', 'settings.appearance.avatar'); - Routerv1::post('/avatar', 'Settings.AppearanceController@avatar', 'settings.appearance.avatar'); - Routerv1::get('/background', 'Settings.AppearanceController@background', 'settings.appearance.background'); - Routerv1::post('/background', 'Settings.AppearanceController@background', 'settings.appearance.background'); - Routerv1::get('/header', 'Settings.AppearanceController@header', 'settings.appearance.header'); - Routerv1::post('/header', 'Settings.AppearanceController@header', 'settings.appearance.header'); Routerv1::get('/userpage', 'Settings.AppearanceController@userpage', 'settings.appearance.userpage'); Routerv1::post('/userpage', 'Settings.AppearanceController@userpage', 'settings.appearance.userpage'); Routerv1::get('/signature', 'Settings.AppearanceController@signature', 'settings.appearance.signature'); diff --git a/utility.php b/utility.php index 0a2a2ac..c225e4d 100644 --- a/utility.php +++ b/utility.php @@ -73,6 +73,13 @@ function clean_string($string, $lower = false, $noSpecial = false, $replaceSpeci return $string; } +// Redirect with turbolinks header +function redirect($url) +{ + header("Turbolinks-Location: {$url}"); + header("Location: {$url}"); +} + function check_mx_record($email) { // Get the domain from the e-mail address @@ -126,12 +133,10 @@ function get_country_name($code) } } +// Count the amount of unique characters in the password string and calculate the entropy function password_entropy($password) { - $password = utf8_decode($password); - - // Count the amount of unique characters in the password string and calculate the entropy - return count(count_chars($password, 1)) * log(256, 2); + return count(count_chars(utf8_decode($password), 1)) * log(256, 2); } function byte_symbol($bytes)