diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.htaccess | 3 | ||||
-rw-r--r-- | src/application/mystic/forum/orm/UserPermissions.php | 5 | ||||
-rw-r--r-- | src/application/views/form_addpost.php | 2 | ||||
-rw-r--r-- | src/application/views/form_delete_topic_confirm.php | 22 | ||||
-rw-r--r-- | src/application/views/nav_guest.php | 4 | ||||
-rw-r--r-- | src/application/views/nav_logged_in.php | 2 | ||||
-rw-r--r-- | src/application/views/view_topic_start.php | 39 | ||||
-rw-r--r-- | src/index.php | 151 |
8 files changed, 205 insertions, 23 deletions
diff --git a/src/.htaccess b/src/.htaccess new file mode 100644 index 0000000..f4a5e0d --- /dev/null +++ b/src/.htaccess @@ -0,0 +1,3 @@ +RewriteEngine On + +RewriteRule ^/?@([a-z0-9]([._](?![._])|[a-z0-9]){2,30}[a-z0-9])$ /index.php?_action=lookupuser&handle=$1 [L] diff --git a/src/application/mystic/forum/orm/UserPermissions.php b/src/application/mystic/forum/orm/UserPermissions.php index cd2fdf4..47af076 100644 --- a/src/application/mystic/forum/orm/UserPermissions.php +++ b/src/application/mystic/forum/orm/UserPermissions.php @@ -33,6 +33,7 @@ final class UserPermissions { public const DELETE_OTHER_USER = 0x8000; public const DELETE_OTHER_TOPIC = 0x10000; + public const EDIT_OTHER_TOPIC = 0x20000; //////// @@ -40,6 +41,7 @@ final class UserPermissions { | self::EDIT_OWN_POST | self::DELETE_OWN_POST | self::CREATE_OWN_TOPIC + | self::EDIT_OWN_TOPIC | self::DELETE_OWN_TOPIC | self::CREATE_OWN_ATTACHMENT | self::EDIT_OWN_ATTACHMENT @@ -50,7 +52,8 @@ final class UserPermissions { public const GROUP_MOD = self::GROUP_USER | self::EDIT_OTHER_POST | self::DELETE_OTHER_USER - | self::DELETE_OTHER_TOPIC; + | self::DELETE_OTHER_TOPIC + | self::EDIT_OTHER_TOPIC; public const GROUP_ADMIN = self::GROUP_MOD | self::CREATE_OTHER_USER diff --git a/src/application/views/form_addpost.php b/src/application/views/form_addpost.php index 88eda27..88648b4 100644 --- a/src/application/views/form_addpost.php +++ b/src/application/views/form_addpost.php @@ -20,7 +20,7 @@ if (($_formError = RequestUtils::getAndClearFormError()) !== null) { <textarea class="form-control" id="i_message" name="message" required rows="12" cols="60" style="resize:vertical;max-height:499px"></textarea> </div> <div class="form-group"> - <label for="i_files">Attachments: <small>(max. 4 files, max. 2 MiB each)</small></label> + <label for="i_files">Attachments: <small>(max. <?= htmlentities(MAX_ATTACHMENT_COUNT) ?> files, max. <?= htmlentities(MAX_ATTACHMENT_SIZE >> 20) ?> MiB each)</small></label> <input type="file" name="files[]" id="i_files" multiple accept="*/*"> </div> <button type="submit" class="btn btn-success">Post reply</button> diff --git a/src/application/views/form_delete_topic_confirm.php b/src/application/views/form_delete_topic_confirm.php new file mode 100644 index 0000000..d38ffaa --- /dev/null +++ b/src/application/views/form_delete_topic_confirm.php @@ -0,0 +1,22 @@ +<div class="panel panel-danger"> + <div class="panel-heading"> + <h3 class="panel-title">Do you want to delete this topic?</h3> + </div> + <div class="panel-body"> + Are you sure you want to delete the topic <strong><em><?= htmlentities($topic->title) ?></em></strong> <strong>including all posts and attachments</strong>?<br> + </div> + <div class="panel-footer"> + <div class="text-right"> + <form action="." method="get" class="seamless-inline"> + <input type="hidden" name="_action" value="viewtopic"> + <input type="hidden" name="topic" value="<?= htmlentities($topic->id) ?>"> + <button class="btn btn-default">Keep topic</button> + </form> + <form action="?_action=deletetopic" method="post" class="seamless-inline"> + <input type="hidden" name="topic" value="<?= htmlentities($topic->id) ?>"> + <input type="hidden" name="confirm" value="<?= htmlentities(base64_encode(hash("sha256", "confirm" . $topic->id, true))); ?>"> + <button class="btn btn-danger">Delete topic & posts</button> + </form> + </div> + </div> +</div> diff --git a/src/application/views/nav_guest.php b/src/application/views/nav_guest.php index 433c487..f897763 100644 --- a/src/application/views/nav_guest.php +++ b/src/application/views/nav_guest.php @@ -1,6 +1,6 @@ <ul class="nav navbar-nav navbar-right"> -<li<?= $GLOBALS["action"] === "auth" ? ' class="active"' : '' ?>><a href="?_action=auth">Log in</a></li> +<li<?= $GLOBALS["action"] === "auth" ? ' class="active"' : '' ?>><a href="?_action=auth&next=<?= htmlentities(urlencode($_SERVER["REQUEST_URI"])) ?>">Log in</a></li> <?php if (REGISTRATION_ENABLED): ?> -<li<?= $GLOBALS["action"] === "register" ? ' class="active"' : '' ?>><a href="?_action=register">Register</a></li> +<li<?= $GLOBALS["action"] === "register" ? ' class="active"' : '' ?>><a href="?_action=register&next=<?= htmlentities(urlencode($_SERVER["REQUEST_URI"])) ?>">Register</a></li> <?php endif; ?> </ul>
\ No newline at end of file diff --git a/src/application/views/nav_logged_in.php b/src/application/views/nav_logged_in.php index fd46d6e..f899ad8 100644 --- a/src/application/views/nav_logged_in.php +++ b/src/application/views/nav_logged_in.php @@ -10,5 +10,5 @@ use mystic\forum\orm\User; <?php endif; ?> </p></li> <li><a href="?_action=viewuser&user=<?= htmlentities(urlencode($user->id)) ?>"><span class="glyphicon glyphicon-user" aria-hidden="true"><span class="sr-only">View profile</span></a></li> -<li><a href="?_action=logout"><span class="glyphicon glyphicon-log-out" aria-hidden="true"><span class="sr-only">Log out</span></a></li> +<li><a href="?_action=logout&next=<?= htmlentities(urlencode($_SERVER["REQUEST_URI"])) ?>"><span class="glyphicon glyphicon-log-out" aria-hidden="true"><span class="sr-only">Log out</span></a></li> </ul> diff --git a/src/application/views/view_topic_start.php b/src/application/views/view_topic_start.php index 84a29de..4006982 100644 --- a/src/application/views/view_topic_start.php +++ b/src/application/views/view_topic_start.php @@ -3,13 +3,19 @@ use mystic\forum\orm\UserPermissions; $canReply = $GLOBALS["currentUser"]?->hasPermission(UserPermissions::CREATE_OWN_POST) ?? false; +$canEdit = ($GLOBALS["currentUser"]?->id === $topicAuthor->id && $topicAuthor->hasPermission(UserPermissions::EDIT_OWN_TOPIC)) + || ($GLOBALS["currentUser"]?->hasPermission(UserPermissions::EDIT_OTHER_TOPIC)); + $canDelete = ($GLOBALS["currentUser"]?->id === $topicAuthor->id && $topicAuthor->hasPermission(UserPermissions::DELETE_OWN_TOPIC)) || ($GLOBALS["currentUser"]?->hasPermission(UserPermissions::DELETE_OTHER_TOPIC)); ?> -<div class="page-header margin-top-0"> - <div role="heading" class="h1 margin-top-0"> +<div class="page-header margin-top-0 clearfix"> + <div role="heading" class="h1 margin-top-0" id="displayHeading"> <?= htmlentities($topic->title) ?> <div class="pull-right"> + <?php if ($canEdit): ?> + <button id="btn-edit-title" class="btn btn-default js-only"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit title</button> + <?php endif; ?> <?php if ($canReply): ?> <button id="btn-reply" class="btn btn-default js-only"><span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span> Reply</button> <?php endif; ?> @@ -21,6 +27,20 @@ $canDelete = ($GLOBALS["currentUser"]?->id === $topicAuthor->id && $topicAuthor- <?php endif; ?> </div> </div> + <?php if ($canEdit): ?> + <form action="?_action=updatetopic" method="post" id="editHeading" style="display: none;" class="form-inline seamless-inline" style="display: block"> + <input type="hidden" name="topic" value="<?= htmlentities(urlencode($topic->id)) ?>"> + <div class="row"> + <div class="col-md-8"> + <input type="text" class="form-control" name="title" id="i_edit_title" value="<?= htmlentities($topic->title) ?>" style="box-sizing: border-box; width: 100%"> + </div> + <div class="col-md-4 text-right"> + <button type="button" id="topicTitleEditCancel" class="btn btn-default"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span> Cancel</button> + <button type="submit" class="btn btn-success"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> Save changes</button> + </div> + </div> + </form> + <?php endif; ?> </div> <p> Started by @@ -31,8 +51,21 @@ Started by <?php endif; ?> on <span class="_time"><?= htmlentities($topic->creationDate->format("c")) ?></span> </p> -<?php if ($canReply): ?> <script> +<?php if ($canEdit): ?> +$(function() { + $("#btn-edit-title").click(function() { + $("#displayHeading").hide(); + $("#editHeading").show(); + $("#i_edit_title").focus(); + }); + $("#topicTitleEditCancel").click(function() { + $("#displayHeading").show(); + $("#editHeading").hide(); + }); +}); +<?php endif; ?> +<?php if ($canReply): ?> $(function() { function focusReplyBox() { var msgInput = $("#i_message"); diff --git a/src/index.php b/src/index.php index 1cc0d01..6258131 100644 --- a/src/index.php +++ b/src/index.php @@ -148,7 +148,7 @@ $GLOBALS["currentUser"] = &$currentUser; if ($_action === "auth") { if ($currentUser) { - header("Location: ."); + header("Location: " . $_GET["next"] ?? "."); exit; } @@ -167,7 +167,7 @@ if ($_action === "auth") { } RequestUtils::setAuthorizedUser($user); - header("Location: ."); + header("Location: " . $_GET["next"] ?? "."); } else { _view("template_start", ["_title" => "Forum"]); _view("template_navigation_start"); @@ -178,7 +178,7 @@ if ($_action === "auth") { } } elseif ($_action === "register") { if ($currentUser) { - header("Location: ."); + header("Location: " . $_GET["next"] ?? "."); exit; } @@ -259,7 +259,7 @@ if ($_action === "auth") { } } elseif ($_action === "logout") { RequestUtils::unsetAuthorizedUser(); - header("Location: ."); + header("Location: " . $_GET["next"] ?? "."); } elseif ($_action === "viewtopic") { $topicId = $_GET["topic"] ?? throw new Exception("Missing topic id"); $topic = new Topic(); @@ -343,8 +343,8 @@ if ($_action === "auth") { /** @var Post $post */ foreach ($posts as $post) { - /** @var ?User $postAuthor */ - $postAuthor = null; + /** @var ?User $topicAuthor */ + $topicAuthor = null; if ($post->authorId !== null && !isset($userCache[$post->authorId])) { $usr = new User(); $usr->id = $post->authorId; @@ -352,13 +352,13 @@ if ($_action === "auth") { $userCache[$post->authorId] = &$usr; } if (isset($userCache[$post->authorId])) - $postAuthor = &$userCache[$post->authorId]; + $topicAuthor = &$userCache[$post->authorId]; $attachments = $db->fetchCustom(Attachment::class, 'WHERE post_id = $1', [ $post->id ]); _view("view_post", [ "post" => $post, - "postAuthor" => $postAuthor, + "postAuthor" => $topicAuthor, "attachments" => $attachments, ]); } @@ -418,6 +418,20 @@ if ($_action === "auth") { _view("form_newtopic"); _view("template_end"); } +} elseif ($_action === "lookupuser") { + RequestUtils::ensureRequestMethod("GET"); + $userHandle = $_GET["handle"] ?? throw new Exception("Missing handle"); + + $user = new User(); + $user->name = $userHandle; + + if (!$db->fetchWhere($user, "name")) { + http_response_code(404); + Messaging::error("No user with name @$userHandle"); + exit; + } + + header("Location: ./?_action=viewuser&user=" . urlencode($user->id)); } elseif ($_action === "viewuser") { $userId = $_GET["user"] ?? throw new Exception("Missing user id"); $user = new User(); @@ -663,16 +677,16 @@ if ($_action === "auth") { exit; } - $postAuthor = new User(); - $postAuthor->id = $post->authorId; + $topicAuthor = new User(); + $topicAuthor->id = $post->authorId; - if (!$db->fetch($postAuthor)) - $postAuthor = null; + if (!$db->fetch($topicAuthor)) + $topicAuthor = null; - $canDelete = ($currentUser->id === $postAuthor?->id && $postAuthor?->hasPermission(UserPermissions::DELETE_OWN_POST)) + $canEdit = ($currentUser->id === $topicAuthor?->id && $topicAuthor?->hasPermission(UserPermissions::DELETE_OWN_POST)) || ($currentUser->hasPermission(UserPermissions::DELETE_OTHER_POST)); - if (!$canDelete) { + if (!$canEdit) { http_response_code(403); Messaging::error("You don't have permission to delete this post"); exit; @@ -714,11 +728,118 @@ if ($_action === "auth") { _view("template_navigation_end"); _view("form_delete_post_confirm", [ "post" => $post, - "postAuthor" => $postAuthor, + "postAuthor" => $topicAuthor, "attachments" => $attachments, ]); _view("template_end"); } +} elseif ($_action === "deletetopic") { + RequestUtils::ensureRequestMethod("POST"); + + if (!$currentUser) { + http_response_code(403); + Messaging::error("You need to be logged in to delete topics!"); + exit; + } + + $topicId = RequestUtils::getRequiredField("topic"); + + $topic = new Topic(); + $topic->id = $topicId; + + if (!$db->fetch($topic)) { + http_response_code(404); + Messaging::error("No topic exists with this id"); + exit; + } + + $topicAuthor = new User(); + $topicAuthor->id = $topic->createdBy; + + if (!$db->fetch($topicAuthor)) + $topicAuthor = null; + + $canEdit = ($currentUser->id === $topicAuthor?->id && $topicAuthor?->hasPermission(UserPermissions::DELETE_OWN_TOPIC)) + || ($currentUser->hasPermission(UserPermissions::DELETE_OTHER_TOPIC)); + + if (!$canEdit) { + http_response_code(403); + Messaging::error("You don't have permission to delete this topic"); + exit; + } + + $confirm = $_POST["confirm"] ?? null; + if ($confirm !== null) { + $expectedConfirm = base64_encode(hash("sha256", "confirm" . $topic->id, true)); + if ($confirm !== $expectedConfirm) { + http_response_code(400); + Messaging::error("Invalid confirmation"); + exit; + } + + if (!$db->delete($topic)) { + http_response_code(500); + Messaging::error("Failed to delete topic"); + exit; + } + + header("Location: ."); + } else { + _view("template_start", ["_title" => "Forum"]); + _view("template_navigation_start"); + _view("template_navigation", ["user" => RequestUtils::getAuthorizedUser($db)]); + _view("template_navigation_end"); + _view("form_delete_topic_confirm", [ + "topic" => $topic, + "topicAuthor" => $topicAuthor, + ]); + _view("template_end"); + } +} elseif ($_action === "updatetopic") { + RequestUtils::ensureRequestMethod("POST"); + + if (!$currentUser) { + http_response_code(403); + Messaging::error("You need to be logged in to update topics!"); + exit; + } + + $topicId = RequestUtils::getRequiredField("topic"); + $title = RequestUtils::getRequiredField("title"); + + $topic = new Topic(); + $topic->id = $topicId; + + if (!$db->fetch($topic)) { + http_response_code(404); + Messaging::error("No topic exists with this id"); + exit; + } + + $topicAuthor = new User(); + $topicAuthor->id = $topic->createdBy; + + if (!$db->fetch($topicAuthor)) + $topicAuthor = null; + + $canEdit = ($currentUser->id === $topicAuthor?->id && $topicAuthor?->hasPermission(UserPermissions::EDIT_OWN_TOPIC)) + || ($currentUser->hasPermission(UserPermissions::EDIT_OTHER_TOPIC)); + + if (!$canEdit) { + http_response_code(403); + Messaging::error("You don't have permission to update this topic"); + exit; + } + + $topic->title = $title; + + if (!$db->update($topic)) { + http_response_code(500); + Messaging::error("Failed to update topic"); + exit; + } + + header("Location: ./?_action=viewtopic&topic=" . urlencode($topicId)); } elseif ($_action === null) { _view("template_start", ["_title" => "Forum"]); _view("template_navigation_start"); |