static forum stats
This commit is contained in:
parent
de1f8acb59
commit
9575403ea4
13 changed files with 642 additions and 199 deletions
|
@ -29,6 +29,7 @@ class CronCommand extends ChainedCommand
|
|||
SessionPurgeCommand::class,
|
||||
PremiumPurgeCommand::class,
|
||||
StatusCheckCommand::class,
|
||||
ResyncForumStatsCommand::class,
|
||||
RebuildForumCacheCommand::class,
|
||||
OsuLeaderboardUpdateCommand::class,
|
||||
];
|
||||
|
|
195
app/Console/Command/ResyncForumStatsCommand.php
Normal file
195
app/Console/Command/ResyncForumStatsCommand.php
Normal 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("");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
57
app/User.php
57
app/User.php
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
141
database/2016_12_22_152950_static_forum_stats.php
Normal file
141
database/2016_12_22_152950_static_forum_stats.php
Normal 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',
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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 () {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Reference in a new issue