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");  |