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, SessionPurgeCommand::class,
PremiumPurgeCommand::class, PremiumPurgeCommand::class,
StatusCheckCommand::class, StatusCheckCommand::class,
ResyncForumStatsCommand::class,
RebuildForumCacheCommand::class, RebuildForumCacheCommand::class,
OsuLeaderboardUpdateCommand::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 // Checks
$titleTooShort = $title !== null $titleTooShort = $title !== null
&& $post->id === $topic->firstPost()->id && $post->id === $topic->post
&& $titleLength < $titleMin; && $titleLength < $titleMin;
$titleTooLong = $title !== null $titleTooLong = $title !== null
&& $post->id === $topic->firstPost()->id && $post->id === $topic->post
&& $titleLength > $titleMax; && $titleLength > $titleMax;
$textTooShort = $textLength < $textMin; $textTooShort = $textLength < $textMin;
$textTooLong = $textLength > $textMax; $textTooLong = $textLength > $textMax;
@ -157,7 +157,7 @@ class PostController extends Controller
unset($_SESSION['replyText']["t{$forum->id}"]); 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}"; $title = "Re: {$topic->title}";
} else { } else {
$topic->title = $title; $topic->title = $title;
@ -172,6 +172,10 @@ class PostController extends Controller
$post->editUser = CurrentSession::$user; $post->editUser = CurrentSession::$user;
$post = $post->update(); $post = $post->update();
if ($forum->lastPostId === $post->id) {
$forum->updateLastPost($post);
}
return $this->json([ return $this->json([
'id' => $post->id, 'id' => $post->id,
'title' => $post->subject, 'title' => $post->subject,
@ -195,7 +199,7 @@ class PostController extends Controller
|| $topic->id === 0 || $topic->id === 0
|| !$forum->perms->view; || !$forum->perms->view;
$replies = $topic->replyCount(); $delete_topic = $topic->replies === 1;
$noDelete = ( $noDelete = (
$post->poster->id === CurrentSession::$user->id $post->poster->id === CurrentSession::$user->id
@ -205,7 +209,7 @@ class PostController extends Controller
$topic->status === 1 $topic->status === 1
&& !$forum->perms->changeStatus && !$forum->perms->changeStatus
) || ( ) || (
$replies === 1 && $delete_topic &&
!$forum->perms->topicDelete !$forum->perms->topicDelete
); );
@ -214,13 +218,16 @@ class PostController extends Controller
throw new HttpMethodNotAllowedException; throw new HttpMethodNotAllowedException;
} }
// Check if the topic only has 1 post if ($delete_topic) {
if ($replies === 1) {
// Delete the entire topic // Delete the entire topic
$topic->delete(); $topic->delete();
} else { } else {
// Just delete the post (replace this with soft deleting) // Just delete the post (replace this with soft deleting)
$post->purge(); $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 if ($topic->forum === $trash
&& $forum->perms->deleteAny) { && $forum->perms->deleteAny) {
$redirect = route('forums.forum', $trash); $redirect = route('forums.forum', $trash);
$forum->decrementPostsCount(true, $topic->replies);
$topic->delete(); $topic->delete();
$forum->updateLastPost();
} elseif ($forum->perms->topicMove) { } elseif ($forum->perms->topicMove) {
$redirect = route('forums.topic', $topic->id); $redirect = route('forums.topic', $topic->id);
$topic->move($trash); $this->move($topic->id, $trash);
} else { } else {
throw new HttpMethodNotAllowedException; throw new HttpMethodNotAllowedException;
} }
@ -159,12 +161,8 @@ class TopicController extends Controller
{ {
extract($this->modBase($id)); extract($this->modBase($id));
if (!$forum->perms->topicMove) {
throw new HttpMethodNotAllowedException;
}
if ($topic->oldForum) { if ($topic->oldForum) {
$topic->move($topic->oldForum, false); $this->move($topic->id, $topic->oldForum, false);
} }
return redirect(route('forums.topic', $topic->id)); return redirect(route('forums.topic', $topic->id));
@ -177,10 +175,10 @@ class TopicController extends Controller
* @throws HttpMethodNotAllowedException * @throws HttpMethodNotAllowedException
* @return string * @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)); 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) { if ($dest_forum->id === 0 || !$dest_forum->perms->view) {
throw new HttpRouteNotFoundException; throw new HttpRouteNotFoundException;
@ -190,7 +188,13 @@ class TopicController extends Controller
throw new HttpMethodNotAllowedException; 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); return route('forums.topic', $topic->id);
} }
@ -247,6 +251,11 @@ class TopicController extends Controller
$forum->id $forum->id
); );
$topic->incrementReplyCount();
$forum->updateLastPost($post);
$forum->incrementPostsCount();
CurrentSession::$user->incrementPostsCount();
return $this->json(['error' => null, 'go' => route('forums.post', $post->id)]); return $this->json(['error' => null, 'go' => route('forums.post', $post->id)]);
} }
@ -324,6 +333,10 @@ class TopicController extends Controller
$forum->id $forum->id
); );
$forum->updateLastPost($post);
$forum->incrementPostsCount(true);
CurrentSession::$user->incrementPostsCount(true);
return $this->json(['error' => null, 'go' => route('forums.post', $post->id)]); return $this->json(['error' => null, 'go' => route('forums.post', $post->id)]);
} }

View file

@ -64,18 +64,60 @@ class Forum
*/ */
public $icon = ""; 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. * Holds the permission handler.
* @var ForumPerms * @var ForumPerms
*/ */
public $perms; 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. * A cached instance of the last post in this forum.
* @var Post * @var Post
@ -115,6 +157,14 @@ class Forum
$this->category = intval($forumRow->forum_category); $this->category = intval($forumRow->forum_category);
$this->type = intval($forumRow->forum_type); $this->type = intval($forumRow->forum_type);
$this->icon = $forumRow->forum_icon; $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) { } elseif ($forumId !== 0) {
$this->id = -1; $this->id = -1;
} }
@ -183,81 +233,69 @@ class Forum
} }
/** /**
* Gets the first post in this forum. * Increment counts.
* @return Post * @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 $this->countPosts = (int) DB::table('forums')
if ($this->firstPostCache === null) {
// Get the row
$firstPost = DB::table('posts')
->where('forum_id', $this->id) ->where('forum_id', $this->id)
->orderBy('post_id') ->increment('forum_count_posts', $amount_posts);
->limit(1)
->first(['post_id']);
// Create the post object if ($topic) {
$post = new Post($firstPost->post_id ?? 0); $this->countTopics = (int) DB::table('forums')
->where('forum_id', $this->id)
// Assign it to a "cache" variable ->increment('forum_count_topics', $amount_topics);
$this->firstPostCache = $post;
// Return the post object
return $post;
} else {
return $this->firstPostCache;
} }
} }
/** /**
* Gets the last post in this forum. * Decrement counts.
* @return Post * @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 $this->countPosts = (int) DB::table('forums')
if ($this->lastPostCache === null) { ->where('forum_id', $this->id)
// Get the row ->decrement('forum_count_posts', $amount_posts);
$lastPost = DB::table('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) ->where('forum_id', $this->id)
->orderBy('post_id', 'desc') ->orderBy('post_id', 'desc')
->limit(1) ->take(1)
->first(['post_id']); ->value('post_id');
// Create the post object $post = new Post($post_id);
$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;
}
} }
/** DB::table('forums')
* Counts the amount of topics in this forum.
* @return int
*/
public function topicCount(): int
{
return DB::table('topics')
->where('forum_id', $this->id) ->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,
* Counts the amount of posts in this forum. 'last_post_user_id' => $this->lastPostUserId = $post->poster->id,
* @return int 'last_post_username' => $this->lastPostUsername = $post->poster->username,
*/ 'last_post_user_colour' => $this->lastPostUserColour = $post->poster->colour,
public function postCount(): int ]);
{
return DB::table('posts')
->where('forum_id', $this->id)
->count();
} }
/** /**

View file

@ -27,6 +27,18 @@ class Topic
*/ */
public $forum = 0; 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? * Is this forum hidden from the listing?
* @var bool * @var bool
@ -51,6 +63,12 @@ class Topic
*/ */
public $timeLimit = 0; public $timeLimit = 0;
/**
* Replies to this topic.
* @var int
*/
public $replies = 0;
/** /**
* The amount of times this topic has been viewed. * The amount of times this topic has been viewed.
* @var int * @var int
@ -80,30 +98,60 @@ class Topic
*/ */
public $type = 0; 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. * The ID of the forum this topic was a part of before the last move.
* @var int * @var int
*/ */
public $oldForum = 0; 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. * The post object cache.
* @var array * @var array
*/ */
private $postsCache = []; 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. * Constructor.
* @param int $topicId * @param int $topicId
@ -119,15 +167,25 @@ class Topic
if ($topicRow) { if ($topicRow) {
$this->id = intval($topicRow->topic_id); $this->id = intval($topicRow->topic_id);
$this->forum = intval($topicRow->forum_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->hidden = boolval($topicRow->topic_hidden);
$this->title = $topicRow->topic_title; $this->title = $topicRow->topic_title;
$this->time = intval($topicRow->topic_time); $this->time = intval($topicRow->topic_time);
$this->timeLimit = intval($topicRow->topic_time_limit); $this->timeLimit = intval($topicRow->topic_time_limit);
$this->replies = intval($topicRow->topic_replies);
$this->views = intval($topicRow->topic_views); $this->views = intval($topicRow->topic_views);
$this->status = intval($topicRow->topic_status); $this->status = intval($topicRow->topic_status);
$this->statusChange = intval($topicRow->topic_status_change); $this->statusChange = intval($topicRow->topic_status_change);
$this->type = intval($topicRow->topic_type); $this->type = intval($topicRow->topic_type);
$this->lastReply = intval($topicRow->topic_last_reply);
$this->oldForum = intval($topicRow->topic_old_forum); $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; 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. * Check if a user has read this topic before.
* @param int $user * @param int $user
@ -322,7 +313,7 @@ class Topic
$track = DB::table('topics_track') $track = DB::table('topics_track')
->where('user_id', $user) ->where('user_id', $user)
->where('topic_id', $this->id) ->where('topic_id', $this->id)
->where('mark_time', '>', $this->lastPost()->time) ->where('mark_time', '>', $this->lastReply)
->count(); ->count();
return !$track; return !$track;
@ -385,4 +376,26 @@ class Topic
->where('topic_id', $this->id) ->where('topic_id', $this->id)
->update(['topic_last_reply' => time()]); ->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; 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. * The user's birthday.
* @var string * @var string
@ -368,6 +380,8 @@ class User
$this->musicCheck = intval($userRow->user_music_check); $this->musicCheck = intval($userRow->user_music_check);
$this->activated = boolval($userRow->user_activated); $this->activated = boolval($userRow->user_activated);
$this->restricted = boolval($userRow->user_restricted); $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 // Temporary backwards compatible IP storage system
try { try {
@ -523,22 +537,41 @@ class User
} }
/** /**
* Get a few forum statistics. * Increment forum counters.
* @return array * @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') $this->countPosts = (int) DB::table('users')
->where('poster_id', $this->id) ->where('user_id', $this->id)
->count(); ->increment('user_count_posts', $amount_posts);
$topics = DB::table('posts') if ($topic) {
->where('poster_id', $this->id) $this->countTopics = (int) DB::table('users')
->distinct() ->where('user_id', $this->id)
->groupBy('topic_id') ->increment('user_count_topics', $amount_topics);
->count(); }
}
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 %} {% if forum.type != 2 %}
<div class="forum__stats"> <div class="forum__stats">
<div class="forum__stat--big" title="Topics"> <div class="forum__stat--big" title="Topics">
{{ forum.topicCount }} {{ forum.countTopics }}
</div> </div>
<div class="forum__stat" title="Posts"> <div class="forum__stat" title="Posts">
{{ forum.postCount }} {{ forum.countPosts }}
</div> </div>
</div> </div>
<div class="forum__recent"> <div class="forum__recent">
{% if forum.lastPost.id %} {% if forum.lastPostUserId %}
<div class="forum__preview"> <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">
<div class="forum__preview-info-row"> <div class="forum__preview-info-row">
<a href="forum__post-link" href="{{ route('forums.post', forum.lastPost.id) }}"> <a class="forum__post-link" href="{{ route('forums.post', forum.lastPostUserId) }}">
{{ forum.lastPost.subject|slice(0, 30)|trim }}{% if forum.lastPost.subject|length > 30 %}...{% endif %} {{ forum.lastPostTitle|slice(0, 30)|trim }}{% if forum.lastPostTitle|length > 30 %}...{% endif %}
</a> </a>
</div> </div>
<div class="forum__preview-info-row"> <div class="forum__preview-info-row">
<time class="time-ago" datetime="{{ forum.lastPost.time|date('r') }}"> <time class="time-ago" datetime="{{ forum.lastPostTime|date('r') }}">
{{ forum.lastPost.time|date(config('general.date_format')) }} {{ forum.lastPostTime|date(config('general.date_format')) }}
</time> </time>
by 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 %}"> <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.lastPost.poster.username }} {{ forum.lastPostUsername }}
</a> </a>
</div> </div>
</div> </div>

View file

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

View file

@ -9,38 +9,40 @@
<a class="topic__title" href="{{ route('forums.topic', topic.id) }}"> <a class="topic__title" href="{{ route('forums.topic', topic.id) }}">
{{ topic.title }} {{ topic.title }}
</a> </a>
{% if topic.firstPost.poster.id %} {% if topic.user %}
<div class="topic__author"> <div class="topic__author">
by 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 %}"> <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.firstPost.poster.username }} {{ topic.firstPostUsername }}
</a> </a>
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="topic__stats"> <div class="topic__stats">
<div class="topic__stat--big" title="Replies"> <div class="topic__stat--big" title="Replies">
{{ topic.replyCount }} {{ topic.replies }}
</div> </div>
<div class="topic__stat" title="Views"> <div class="topic__stat" title="Views">
{{ topic.views }} {{ topic.views }}
</div> </div>
</div> </div>
<div class="topic__recent"> <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">
<div class="topic__recent-info-row"> <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 by
{% if topic.lastPost.poster.id %} {% if topic.lastPostUserId %}
<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> <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 %} {% else %}
[deleted user] [deleted user]
{% endif %} {% endif %}
</div> </div>
<div class="topic__recent-info-row"> <div class="topic__recent-info-row">
<time class="time-ago" datetime="{{ topic.lastPost.time|date('r') }}"> <time class="time-ago" datetime="{{ topic.lastReply|date('r') }}">
{{ topic.lastPost.time|date(config('general.date_format')) }} {{ topic.lastReply|date(config('general.date_format')) }}
</time> </time>
</div> </div>
</div> </div>

View file

@ -17,7 +17,7 @@
<td class="sidepanel-table__column" style="text-align: left; border-bottom: 1px solid #9475b2;"> <td class="sidepanel-table__column" style="text-align: left; border-bottom: 1px solid #9475b2;">
<a href="{{ route('forums.topic', _t.id) }}">{{ _t.title }}</a> <a href="{{ route('forums.topic', _t.id) }}">{{ _t.title }}</a>
</td> </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> </tr>
{% endfor %} {% endfor %}
</table> </table>

View file

@ -143,11 +143,11 @@
<table style="width: 100%;"> <table style="width: 100%;">
<tr> <tr>
<td style="text-align: left; font-weight: bold;">Topics</td> <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>
<tr> <tr>
<td style="text-align: left; font-weight: bold;">Posts</td> <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>
<tr> <tr>
<td style="text-align: left; font-weight: bold;">Friends</td> <td style="text-align: left; font-weight: bold;">Friends</td>