static forum stats

This commit is contained in:
flash 2016-12-22 19:10:09 +01:00
parent de1f8acb59
commit 9575403ea4
13 changed files with 642 additions and 199 deletions

View file

@ -29,6 +29,7 @@ class CronCommand extends ChainedCommand
SessionPurgeCommand::class,
PremiumPurgeCommand::class,
StatusCheckCommand::class,
ResyncForumStatsCommand::class,
RebuildForumCacheCommand::class,
OsuLeaderboardUpdateCommand::class,
];

View file

@ -0,0 +1,195 @@
<?php
/**
* Holds the forum stats resyncer.
* @package Sakura
*/
namespace Sakura\Console\Command;
use CLIFramework\Command;
use Illuminate\Database\Query\JoinClause;
use Sakura\DB;
use Sakura\Forum\Post;
/**
* Resyncs forum stats.
* @package Sakura
* @author Julian van de Groep <me@flash.moe>
*/
class ResyncForumStatsCommand extends Command
{
/**
* A quick description of this command.
* @return string.
*/
public function brief(): string
{
return 'Resynchronises the user topics and posts counts.';
}
/**
* Does the repository installing.
*/
public function execute(): void
{
$this->getLogger()->writeln("This might take a while...");
$this->getLogger()->writeln("");
$this->forumStats();
$this->topicStats();
$this->userStats();
$this->getLogger()->writeln("Done!");
}
private function forumStats(): void
{
$this->getLogger()->writeln("=> Forums");
$forums = DB::table('forums')
->where('forum_type', 0)
->get(['forum_id']);
foreach ($forums as $forum) {
$this->getLogger()->writeln("==> Forum {$forum->forum_id}");
$topic_count = DB::table('topics')
->where('forum_id', $forum->forum_id)
->count();
// if topic count is 0 then there's no point in continuing
if (!$topic_count) {
$this->getLogger()->writeln("No posts found, skipping...");
continue;
}
$post_count = DB::table('posts')
->where('forum_id', $forum->forum_id)
->count();
$last_post_id = DB::table('posts')
->where('forum_id', $forum->forum_id)
->orderBy('post_id', 'desc')
->take(1)
->value('post_id');
$last_post = new Post($last_post_id);
DB::table('forums')
->where('forum_id', $forum->forum_id)
->update([
'forum_count_topics' => $topic_count,
'forum_count_posts' => $post_count,
'last_post_id' => $last_post->id,
'last_post_title' => $last_post->subject,
'last_post_time' => $last_post->time,
'last_post_user_id' => $last_post->poster->id,
'last_post_username' => $last_post->poster->username,
'last_post_user_colour' => $last_post->poster->colour,
]);
}
$this->getLogger()->writeln("");
}
private function topicStats(): void
{
$this->getLogger()->writeln("=> Topics");
$topics = DB::table('topics')
->get(['topic_id', 'post_id']);
foreach ($topics as $topic) {
$this->getLogger()->writeln("==> Topic {$topic->topic_id}");
$reply_count = DB::table('posts')
->where('topic_id', $topic->topic_id)
->count();
// delete the topic record if there's no posts presents
if ($reply_count === 0) {
$this->getLogger()->writeln("No posts found, deleting record...");
DB::table('topics')
->where('topic_id', $topic->topic_id)
->delete();
continue;
}
// take one off the reply count because the OP technically isn't a reply
$reply_count--;
$last_post_id = DB::table('posts')
->where('topic_id', $topic->topic_id)
->orderBy('post_id', 'desc')
->take(1)
->value('post_id');
$last_post = new Post($last_post_id);
$update_data = [
'topic_replies' => $reply_count,
'last_post_id' => $last_post->id,
'last_post_user_id' => $last_post->poster->id,
'last_post_username' => $last_post->poster->username,
'last_post_user_colour' => $last_post->poster->colour,
];
if (intval($topic->post_id) === 0) {
$this->getLogger()->writeln("Missing first post record, resolving...");
$first_post_id = DB::table('posts')
->where('topic_id', $topic->topic_id)
->orderBy('post_id')
->take(1)
->value('post_id');
$first_post = new Post($first_post_id);
$update_data = array_merge($update_data, [
'post_id' => $first_post->id,
'user_id' => $first_post->poster->id,
'first_post_username' => $first_post->poster->username,
'first_post_user_colour' => $first_post->poster->colour,
]);
$this->getLogger()->writeln("Linked post {$first_post->id} to topic {$topic->topic_id}.");
}
DB::table('topics')
->where('topic_id', $topic->topic_id)
->update($update_data);
}
$this->getLogger()->writeln("");
}
private function userStats(): void
{
$this->getLogger()->writeln("=> Users");
$users = DB::table('users')
->orderBy('user_id')
->get(['user_id']);
foreach ($users as $user) {
$this->getLogger()->writeln("==> User {$user->user_id}");
$posts_count = DB::table('posts')
->where('poster_id', $user->user_id)
->count();
$topics_count = DB::table('topics')
->where('user_id', $user->user_id)
->count();
DB::table('users')
->where('user_id', $user->user_id)
->update([
'user_count_topics' => $topics_count,
'user_count_posts' => $posts_count,
]);
}
$this->getLogger()->writeln("");
}
}

View file

@ -121,10 +121,10 @@ class PostController extends Controller
// Checks
$titleTooShort = $title !== null
&& $post->id === $topic->firstPost()->id
&& $post->id === $topic->post
&& $titleLength < $titleMin;
$titleTooLong = $title !== null
&& $post->id === $topic->firstPost()->id
&& $post->id === $topic->post
&& $titleLength > $titleMax;
$textTooShort = $textLength < $textMin;
$textTooLong = $textLength > $textMax;
@ -157,7 +157,7 @@ class PostController extends Controller
unset($_SESSION['replyText']["t{$forum->id}"]);
if ($post->id !== $topic->firstPost()->id || $title === null) {
if ($post->id !== $topic->post || $title === null) {
$title = "Re: {$topic->title}";
} else {
$topic->title = $title;
@ -172,6 +172,10 @@ class PostController extends Controller
$post->editUser = CurrentSession::$user;
$post = $post->update();
if ($forum->lastPostId === $post->id) {
$forum->updateLastPost($post);
}
return $this->json([
'id' => $post->id,
'title' => $post->subject,
@ -195,7 +199,7 @@ class PostController extends Controller
|| $topic->id === 0
|| !$forum->perms->view;
$replies = $topic->replyCount();
$delete_topic = $topic->replies === 1;
$noDelete = (
$post->poster->id === CurrentSession::$user->id
@ -205,7 +209,7 @@ class PostController extends Controller
$topic->status === 1
&& !$forum->perms->changeStatus
) || (
$replies === 1 &&
$delete_topic &&
!$forum->perms->topicDelete
);
@ -214,13 +218,16 @@ class PostController extends Controller
throw new HttpMethodNotAllowedException;
}
// Check if the topic only has 1 post
if ($replies === 1) {
if ($delete_topic) {
// Delete the entire topic
$topic->delete();
} else {
// Just delete the post (replace this with soft deleting)
$post->purge();
}
$forum->updateLastPost();
$forum->decrementPostCount($delete_topic);
CurrentSession::$user->incrementPostsCount($delete_topic);
}
}

View file

@ -138,10 +138,12 @@ class TopicController extends Controller
if ($topic->forum === $trash
&& $forum->perms->deleteAny) {
$redirect = route('forums.forum', $trash);
$forum->decrementPostsCount(true, $topic->replies);
$topic->delete();
$forum->updateLastPost();
} elseif ($forum->perms->topicMove) {
$redirect = route('forums.topic', $topic->id);
$topic->move($trash);
$this->move($topic->id, $trash);
} else {
throw new HttpMethodNotAllowedException;
}
@ -159,12 +161,8 @@ class TopicController extends Controller
{
extract($this->modBase($id));
if (!$forum->perms->topicMove) {
throw new HttpMethodNotAllowedException;
}
if ($topic->oldForum) {
$topic->move($topic->oldForum, false);
$this->move($topic->id, $topic->oldForum, false);
}
return redirect(route('forums.topic', $topic->id));
@ -177,10 +175,10 @@ class TopicController extends Controller
* @throws HttpMethodNotAllowedException
* @return string
*/
public function move(int $id): string
public function move(int $id, int $destination = 0, bool $track_previous = true): string
{
extract($this->modBase($id));
$dest_forum = new Forum($_POST['destination'] ?? 0);
$dest_forum = new Forum($_POST['destination'] ?? $destination);
if ($dest_forum->id === 0 || !$dest_forum->perms->view) {
throw new HttpRouteNotFoundException;
@ -190,7 +188,13 @@ class TopicController extends Controller
throw new HttpMethodNotAllowedException;
}
$topic->move($dest_forum->id);
$topic->move($dest_forum->id, $track_previous);
$forum->decrementPostsCount(true, $topic->replies);
$forum->updateLastPost();
$dest_forum->incrementPostsCount(true, $topic->replies);
$dest_forum->updateLastPost();
return route('forums.topic', $topic->id);
}
@ -247,6 +251,11 @@ class TopicController extends Controller
$forum->id
);
$topic->incrementReplyCount();
$forum->updateLastPost($post);
$forum->incrementPostsCount();
CurrentSession::$user->incrementPostsCount();
return $this->json(['error' => null, 'go' => route('forums.post', $post->id)]);
}
@ -324,6 +333,10 @@ class TopicController extends Controller
$forum->id
);
$forum->updateLastPost($post);
$forum->incrementPostsCount(true);
CurrentSession::$user->incrementPostsCount(true);
return $this->json(['error' => null, 'go' => route('forums.post', $post->id)]);
}

View file

@ -64,18 +64,60 @@ class Forum
*/
public $icon = "";
/**
* Amount of topics in this forum.
* @var int
*/
public $countTopics = 0;
/**
* Amount of posts in this forum.
* @var int
*/
public $countPosts = 0;
/**
* Id of the last post made in this forum.
* @var int
*/
public $lastPostId = 0;
/**
* Title of the last post made in this forum.
* @var string
*/
public $lastPostTitle = "";
/**
* Post time of the last post made in this forum.
* @var int
*/
public $lastPostTime = 0;
/**
* User id which last posted in this forum.
* @var int
*/
public $lastPostUserId = 0;
/**
* Username which last posted in this forum.
* @var string
*/
public $lastPostUsername = "";
/**
* Colour of user which last posted in this forum.
* @var string
*/
public $lastPostUserColour = "";
/**
* Holds the permission handler.
* @var ForumPerms
*/
public $perms;
/**
* A cached instance of the first post in this forum.
* @var Post
*/
private $firstPostCache = null;
/**
* A cached instance of the last post in this forum.
* @var Post
@ -115,6 +157,14 @@ class Forum
$this->category = intval($forumRow->forum_category);
$this->type = intval($forumRow->forum_type);
$this->icon = $forumRow->forum_icon;
$this->countTopics = intval($forumRow->forum_count_topics);
$this->countPosts = intval($forumRow->forum_count_posts);
$this->lastPostId = intval($forumRow->last_post_id);
$this->lastPostTitle = $forumRow->last_post_title;
$this->lastPostTime = intval($forumRow->last_post_time);
$this->lastPostUserId = intval($forumRow->last_post_user_id);
$this->lastPostUsername = $forumRow->last_post_username;
$this->lastPostUserColour = $forumRow->last_post_user_colour;
} elseif ($forumId !== 0) {
$this->id = -1;
}
@ -183,81 +233,69 @@ class Forum
}
/**
* Gets the first post in this forum.
* @return Post
* Increment counts.
* @param bool $topic
* @param int $amount_posts
* @param int $amount_topics
*/
public function firstPost(): Post
public function incrementPostsCount(bool $topic = false, int $amount_posts = 1, int $amount_topics = 1): void
{
// Check if firstPostCache is set
if ($this->firstPostCache === null) {
// Get the row
$firstPost = DB::table('posts')
$this->countPosts = (int) DB::table('forums')
->where('forum_id', $this->id)
->increment('forum_count_posts', $amount_posts);
if ($topic) {
$this->countTopics = (int) DB::table('forums')
->where('forum_id', $this->id)
->orderBy('post_id')
->limit(1)
->first(['post_id']);
// Create the post object
$post = new Post($firstPost->post_id ?? 0);
// Assign it to a "cache" variable
$this->firstPostCache = $post;
// Return the post object
return $post;
} else {
return $this->firstPostCache;
->increment('forum_count_topics', $amount_topics);
}
}
/**
* Gets the last post in this forum.
* @return Post
* Decrement counts.
* @param bool $topic
* @param int $amount_posts
* @param int $amount_topics
*/
public function lastPost(): Post
public function decrementPostsCount(bool $topic = false, int $amount_posts = 1, int $amount_topics = 1): void
{
// Check if lastPostCache is set
if ($this->lastPostCache === null) {
// Get the row
$lastPost = DB::table('posts')
$this->countPosts = (int) DB::table('forums')
->where('forum_id', $this->id)
->decrement('forum_count_posts', $amount_posts);
if ($topic) {
$this->countTopics = (int) DB::table('forums')
->where('forum_id', $this->id)
->decrement('forum_count_topics', $amount_topics);
}
}
/**
* Updates last post information for this forum.
* @param Post $post
*/
public function updateLastPost(Post $post = null): void
{
if ($post === null) {
$post_id = DB::table('posts')
->where('forum_id', $this->id)
->orderBy('post_id', 'desc')
->limit(1)
->first(['post_id']);
->take(1)
->value('post_id');
// Create the post object
$post = new Post($lastPost->post_id ?? 0);
// Assign it to a "cache" variable
$this->lastPostCache = $post;
// Return the post object
return $post;
} else {
return $this->lastPostCache;
$post = new Post($post_id);
}
}
/**
* Counts the amount of topics in this forum.
* @return int
*/
public function topicCount(): int
{
return DB::table('topics')
DB::table('forums')
->where('forum_id', $this->id)
->count();
}
/**
* Counts the amount of posts in this forum.
* @return int
*/
public function postCount(): int
{
return DB::table('posts')
->where('forum_id', $this->id)
->count();
->update([
'last_post_id' => $this->lastPostId = $post->id,
'last_post_title' => $this->lastPostTitle = $post->subject,
'last_post_time' => $this->lastPostTime = $post->time,
'last_post_user_id' => $this->lastPostUserId = $post->poster->id,
'last_post_username' => $this->lastPostUsername = $post->poster->username,
'last_post_user_colour' => $this->lastPostUserColour = $post->poster->colour,
]);
}
/**

View file

@ -27,6 +27,18 @@ class Topic
*/
public $forum = 0;
/**
* Id of the opening post this topic is associated with.
* @var int
*/
public $post = 0;
/**
* Id of the user that created this topic.
* @var int
*/
public $user = 0;
/**
* Is this forum hidden from the listing?
* @var bool
@ -51,6 +63,12 @@ class Topic
*/
public $timeLimit = 0;
/**
* Replies to this topic.
* @var int
*/
public $replies = 0;
/**
* The amount of times this topic has been viewed.
* @var int
@ -80,30 +98,60 @@ class Topic
*/
public $type = 0;
/**
* Time when this topic was last replied to.
* @var int
*/
public $lastReply = 0;
/**
* The ID of the forum this topic was a part of before the last move.
* @var int
*/
public $oldForum = 0;
/**
* Username of the person that created this topic.
* @var string
*/
public $firstPostUsername = "";
/**
* User colour of the person that created this topic.
* @var string
*/
public $firstPostUserColour = "";
/**
* Id of the last reply to this topic.
* @var int
*/
public $lastPostId = 0;
/**
* User id of the person that last replied to this topic.
* @var int
*/
public $lastPostUserId = 0;
/**
* Username of the person that last replied to this topic.
* @var string
*/
public $lastPostUsername = "";
/**
* User colour of the person that last replied to this topic.
* @var string
*/
public $lastPostUserColour = "";
/**
* The post object cache.
* @var array
*/
private $postsCache = [];
/**
* A cached instance of opening post.
* @var Post
*/
private $firstPostCache = null;
/**
* A cached instance of the last reply.
* @var Post
*/
private $lastPostCache = null;
/**
* Constructor.
* @param int $topicId
@ -119,15 +167,25 @@ class Topic
if ($topicRow) {
$this->id = intval($topicRow->topic_id);
$this->forum = intval($topicRow->forum_id);
$this->post = intval($topicRow->post_id);
$this->user = intval($topicRow->user_id);
$this->hidden = boolval($topicRow->topic_hidden);
$this->title = $topicRow->topic_title;
$this->time = intval($topicRow->topic_time);
$this->timeLimit = intval($topicRow->topic_time_limit);
$this->replies = intval($topicRow->topic_replies);
$this->views = intval($topicRow->topic_views);
$this->status = intval($topicRow->topic_status);
$this->statusChange = intval($topicRow->topic_status_change);
$this->type = intval($topicRow->topic_type);
$this->lastReply = intval($topicRow->topic_last_reply);
$this->oldForum = intval($topicRow->topic_old_forum);
$this->firstPostUsername = $topicRow->first_post_username;
$this->firstPostUserColour = $topicRow->first_post_user_colour;
$this->lastPostId = intval($topicRow->last_post_id);
$this->lastPostUserId = intval($topicRow->last_post_user_id);
$this->lastPostUsername = $topicRow->last_post_username;
$this->lastPostUserColour = $topicRow->last_post_user_colour;
}
}
@ -242,73 +300,6 @@ class Topic
return $this->postsCache;
}
/**
* Get the opening post.
* @return Post
*/
public function firstPost(): Post
{
// Check if the cache var is set
if ($this->firstPostCache !== null) {
return $this->firstPostCache;
}
// Get the row from the database
$post = DB::table('posts')
->where('topic_id', $this->id)
->orderBy('post_id')
->limit(1)
->first(['post_id']);
// Create the post class
$post = new Post($post->post_id ?? 0);
// Assign it to the cache var
$this->firstPostCache = $post;
// Return
return $post;
}
/**
* Get the latest reply.
* @return Post
*/
public function lastPost(): Post
{
// Check if the cache var is set
if ($this->lastPostCache !== null) {
return $this->lastPostCache;
}
// Get the row from the database
$post = DB::table('posts')
->where('topic_id', $this->id)
->orderBy('post_id', 'desc')
->limit(1)
->first(['post_id']);
// Create the post class
$post = new Post($post->post_id ?? 0);
// Assign it to the cache var
$this->lastPostCache = $post;
// Return
return $post;
}
/**
* Get the amount of replies.
* @return int
*/
public function replyCount(): int
{
return DB::table('posts')
->where('topic_id', $this->id)
->count();
}
/**
* Check if a user has read this topic before.
* @param int $user
@ -322,7 +313,7 @@ class Topic
$track = DB::table('topics_track')
->where('user_id', $user)
->where('topic_id', $this->id)
->where('mark_time', '>', $this->lastPost()->time)
->where('mark_time', '>', $this->lastReply)
->count();
return !$track;
@ -385,4 +376,26 @@ class Topic
->where('topic_id', $this->id)
->update(['topic_last_reply' => time()]);
}
/**
* Increment reply count.
* @param int $amount
*/
public function incrementReplyCount(int $amount = 1): void
{
$this->replies = (int) DB::table('topics')
->where('topic_id', $this->id)
->increment('topic_replies', $amount);
}
/**
* Decrement reply count.
* @param int $amount
*/
public function decrementPostsCount(int $amount = 1): void
{
$this->replies = (int) DB::table('topics')
->where('topic_id', $this->id)
->decrement('topic_replies', $amount);
}
}

View file

@ -248,6 +248,18 @@ class User
*/
public $restricted = false;
/**
* Amount of topics this user has created.
* @var int
*/
public $countTopics = 0;
/**
* Amount of posts this user has made
* @var int
*/
public $countPosts = 0;
/**
* The user's birthday.
* @var string
@ -368,6 +380,8 @@ class User
$this->musicCheck = intval($userRow->user_music_check);
$this->activated = boolval($userRow->user_activated);
$this->restricted = boolval($userRow->user_restricted);
$this->countTopics = intval($userRow->user_count_topics);
$this->countPosts = intval($userRow->user_count_posts);
// Temporary backwards compatible IP storage system
try {
@ -523,22 +537,41 @@ class User
}
/**
* Get a few forum statistics.
* @return array
* Increment forum counters.
* @param bool $topic
* @param int $amount_posts
* @param int $amount_topics
*/
public function forumStats(): array
public function incrementPostsCount(bool $topic = false, int $amount_posts = 1, int $amount_topics = 1): void
{
$posts = DB::table('posts')
->where('poster_id', $this->id)
->count();
$this->countPosts = (int) DB::table('users')
->where('user_id', $this->id)
->increment('user_count_posts', $amount_posts);
$topics = DB::table('posts')
->where('poster_id', $this->id)
->distinct()
->groupBy('topic_id')
->count();
if ($topic) {
$this->countTopics = (int) DB::table('users')
->where('user_id', $this->id)
->increment('user_count_topics', $amount_topics);
}
}
return compact('posts', 'topics');
/**
* Decrement forum counters.
* @param bool $topic
* @param int $amount_posts
* @param int $amount_topics
*/
public function decrementPostsCount(bool $topic = false, int $amount_posts = 1, int $amount_topics = 1): void
{
$this->countPosts = (int) DB::table('users')
->where('user_id', $this->id)
->decrement('user_count_posts', $amount_posts);
if ($topic) {
$this->countTopics = (int) DB::table('users')
->where('user_id', $this->id)
->decrement('user_count_topics', $amount_topics);
}
}
/**

View file

@ -0,0 +1,141 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Sakura\DB;
class StaticForumStats extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
$schema = DB::getSchemaBuilder();
$schema->table('forums', function (Blueprint $table) {
$table->integer('forum_count_topics')
->unsigned()
->default(0);
$table->integer('forum_count_posts')
->unsigned()
->default(0);
$table->integer('last_post_id')
->unsigned()
->default(0);
$table->string('last_post_title')
->nullable()
->default(null);
$table->integer('last_post_time')
->unsigned()
->default(0);
$table->integer('last_post_user_id')
->unsigned()
->default(0);
$table->string('last_post_username')
->nullable()
->default(null);
$table->string('last_post_user_colour')
->nullable()
->default(null);
});
$schema->table('topics', function (Blueprint $table) {
$table->integer('topic_replies')
->unsigned()
->default(0);
$table->integer('post_id')
->unsigned()
->default(0);
$table->integer('user_id')
->unsigned()
->default(0);
$table->string('first_post_username')
->nullable()
->default(null);
$table->string('first_post_user_colour')
->nullable()
->default(null);
$table->integer('last_post_id')
->unsigned()
->default(0);
$table->integer('last_post_user_id')
->unsigned()
->default(0);
$table->string('last_post_username')
->nullable()
->default(null);
$table->string('last_post_user_colour')
->nullable()
->default(null);
});
$schema->table('users', function (Blueprint $table) {
$table->integer('user_count_topics')
->unsigned()
->default(0);
$table->integer('user_count_posts')
->unsigned()
->default(0);
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
$schema = DB::getSchemaBuilder();
$schema->table('users', function (Blueprint $table) {
$table->dropColumn([
'user_count_topics',
'user_count_posts',
]);
});
$schema->table('topics', function (Blueprint $table) {
$table->dropColumn([
'topic_replies',
'post_id',
'user_id',
'first_post_username',
'first_post_user_colour',
'last_post_id',
'last_post_user_id',
'last_post_username',
'last_post_user_colour',
]);
});
$schema->table('forums', function (Blueprint $table) {
$table->dropColumn([
'forum_count_topics',
'forum_count_posts',
'last_post_id',
'last_post_title',
'last_post_time',
'last_post_user_id',
'last_post_username',
'last_post_user_colour',
]);
});
}
}

View file

@ -22,29 +22,29 @@
{% if forum.type != 2 %}
<div class="forum__stats">
<div class="forum__stat--big" title="Topics">
{{ forum.topicCount }}
{{ forum.countTopics }}
</div>
<div class="forum__stat" title="Posts">
{{ forum.postCount }}
{{ forum.countPosts }}
</div>
</div>
<div class="forum__recent">
{% if forum.lastPost.id %}
{% if forum.lastPostUserId %}
<div class="forum__preview">
<div class="forum__preview-avatar avatar avatar--border" style="background-image: url('{{ route('user.avatar', forum.lastPost.poster.id) }}')"></div>
<div class="forum__preview-avatar avatar avatar--border" style="background-image: url('{{ route('user.avatar', forum.lastPostUserId) }}')"></div>
<div class="forum__preview-info">
<div class="forum__preview-info-row">
<a href="forum__post-link" href="{{ route('forums.post', forum.lastPost.id) }}">
{{ forum.lastPost.subject|slice(0, 30)|trim }}{% if forum.lastPost.subject|length > 30 %}...{% endif %}
<a class="forum__post-link" href="{{ route('forums.post', forum.lastPostUserId) }}">
{{ forum.lastPostTitle|slice(0, 30)|trim }}{% if forum.lastPostTitle|length > 30 %}...{% endif %}
</a>
</div>
<div class="forum__preview-info-row">
<time class="time-ago" datetime="{{ forum.lastPost.time|date('r') }}">
{{ forum.lastPost.time|date(config('general.date_format')) }}
<time class="time-ago" datetime="{{ forum.lastPostTime|date('r') }}">
{{ forum.lastPostTime|date(config('general.date_format')) }}
</time>
by
<a href="{{ route('user.profile', forum.lastPost.poster.id) }}" style="color: {{ forum.lastPost.poster.colour }}; text-shadow: 0 0 5px {% if forum.lastPost.poster.colour != 'inherit' %}{{ forum.lastPost.poster.colour }}{% else %}#222{% endif %}">
{{ forum.lastPost.poster.username }}
<a href="{{ route('user.profile', forum.lastPostUserId) }}" style="color: {{ forum.lastPostUserColour }}; text-shadow: 0 0 5px {% if forum.lastPostUserColour != 'inherit' %}{{ forum.lastPostUserColour }}{% else %}#222{% endif %}">
{{ forum.lastPostUsername }}
</a>
</div>
</div>

View file

@ -58,8 +58,8 @@
rText = document.getElementById('previewText'),
postFetch = new Sakura.AJAX(),
parserActive = false,
op = {{ topic is defined ? topic.firstPost.id : 0 }},
topicName = "{{ topic is defined ? topic.firstPost.subject : '' }}",
op = {{ topic is defined ? topic.post : 0 }},
topicName = "{{ topic is defined ? topic.title : '' }}",
editing = 0;
pText.addEventListener("focus", function () {

View file

@ -9,38 +9,40 @@
<a class="topic__title" href="{{ route('forums.topic', topic.id) }}">
{{ topic.title }}
</a>
{% if topic.firstPost.poster.id %}
{% if topic.user %}
<div class="topic__author">
by
<a class="topic__author-link" href="{{ route('user.profile', topic.firstPost.poster.id) }}" style="color: {{ topic.firstPost.poster.colour }}; text-shadow: 0 0 5px {% if topic.firstPost.poster.colour != 'inherit' %}{{ topic.firstPost.poster.colour }}{% else %}#222{% endif %}">
{{ topic.firstPost.poster.username }}
<a class="topic__author-link" href="{{ route('user.profile', topic.user) }}" style="color: {{ topic.firstPostUserColour }}; text-shadow: 0 0 5px {% if topic.firstPostUserColour != 'inherit' %}{{ topic.firstPostUserColour }}{% else %}#222{% endif %}">
{{ topic.firstPostUsername }}
</a>
</div>
{% endif %}
</div>
<div class="topic__stats">
<div class="topic__stat--big" title="Replies">
{{ topic.replyCount }}
{{ topic.replies }}
</div>
<div class="topic__stat" title="Views">
{{ topic.views }}
</div>
</div>
<div class="topic__recent">
<div class="topic__recent-avatar avatar avatar--border" style="background-image: url('{{ route('user.avatar', topic.lastPost.poster.id) }}')"></div>
<div class="topic__recent-avatar avatar avatar--border" style="background-image: url('{{ route('user.avatar', topic.lastPostUserId) }}')"></div>
<div class="topic__recent-info">
<div class="topic__recent-info-row">
<a href="{{ route('forums.post', topic.lastPost.id) }}">Last reply</a>
<a href="{{ route('forums.post', topic.lastPostId) }}">Last reply</a>
by
{% if topic.lastPost.poster.id %}
<a href="{{ route('user.profile', topic.lastPost.poster.id) }}" style="color: {{ topic.lastPost.poster.colour }}; text-shadow: 0 0 5px {% if topic.lastPost.poster.colour != 'inherit' %}{{ topic.lastPost.poster.colour }}{% else %}#222{% endif %};">{{ topic.lastPost.poster.username }}</a>
{% if topic.lastPostUserId %}
<a href="{{ route('user.profile', topic.lastPostUserId) }}" style="color: {{ topic.lastPostUserColour }}; text-shadow: 0 0 5px {% if topic.lastPostUserColour != 'inherit' %}{{ topic.lastPostUserColour }}{% else %}#222{% endif %};">
{{ topic.lastPostUsername }}
</a>
{% else %}
[deleted user]
{% endif %}
</div>
<div class="topic__recent-info-row">
<time class="time-ago" datetime="{{ topic.lastPost.time|date('r') }}">
{{ topic.lastPost.time|date(config('general.date_format')) }}
<time class="time-ago" datetime="{{ topic.lastReply|date('r') }}">
{{ topic.lastReply|date(config('general.date_format')) }}
</time>
</div>
</div>

View file

@ -17,7 +17,7 @@
<td class="sidepanel-table__column" style="text-align: left; border-bottom: 1px solid #9475b2;">
<a href="{{ route('forums.topic', _t.id) }}">{{ _t.title }}</a>
</td>
<td class="sidepanel-table__column" style="text-align: right; border-bottom: 1px solid #9475b2;"><time class="time-ago" datetime="{{ _t.lastPost.time|date('r') }}">{{ _t.lastPost.time|date(config('general.date_format')) }}</time></td>
<td class="sidepanel-table__column" style="text-align: right; border-bottom: 1px solid #9475b2;"><time class="time-ago" datetime="{{ _t.lastReply|date('r') }}">{{ _t.lastReply|date(config('general.date_format')) }}</time></td>
</tr>
{% endfor %}
</table>

View file

@ -143,11 +143,11 @@
<table style="width: 100%;">
<tr>
<td style="text-align: left; font-weight: bold;">Topics</td>
<td style="text-align: right;">{{ profile.forumStats.topics }}</td>
<td style="text-align: right;">{{ profile.countTopics }}</td>
</tr>
<tr>
<td style="text-align: left; font-weight: bold;">Posts</td>
<td style="text-align: right;">{{ profile.forumStats.posts }}</td>
<td style="text-align: right;">{{ profile.countPosts }}</td>
</tr>
<tr>
<td style="text-align: left; font-weight: bold;">Friends</td>