From 04e9bad79e7c3d0e2aa037b7c74644608407bf0b Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Sat, 16 Nov 2013 21:21:43 +0100 Subject: [PATCH] Added logging engine for #61 --- config.ini | 1 + logs/.gitignore | 2 + src/Controllers/CommentController.php | 2 + src/Controllers/PostController.php | 51 ++++++++++++++++++-- src/Controllers/TagController.php | 3 ++ src/Controllers/UserController.php | 21 +++++++- src/Helpers/LogHelper.php | 69 +++++++++++++++++++++++++++ 7 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 logs/.gitignore create mode 100644 src/Helpers/LogHelper.php diff --git a/config.ini b/config.ini index cdd7965a..b7b3d13f 100644 --- a/config.ini +++ b/config.ini @@ -9,6 +9,7 @@ thumbsPath=./thumbs/ mediaPath=./public_html/media/ title=szurubooru salt = "1A2/$_4xVa" +logsPath=./logs/ [misc] featuredPostMaxDays=7 diff --git a/logs/.gitignore b/logs/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/Controllers/CommentController.php b/src/Controllers/CommentController.php index 22991dfa..43a1b54d 100644 --- a/src/Controllers/CommentController.php +++ b/src/Controllers/CommentController.php @@ -63,6 +63,7 @@ class CommentController if (InputHelper::get('sender') != 'preview') R::store($comment); $this->context->transport->textPreview = $comment->getText(); + LogHelper::logEvent('comment-add', '+{user} commented on @{post}', ['post' => $post->id]); StatusHelper::success(); } } @@ -78,6 +79,7 @@ class CommentController $comment = Model_Comment::locate($id); R::preload($comment, ['commenter' => 'user']); PrivilegesHelper::confirmWithException(Privilege::DeleteComment, PrivilegesHelper::getIdentitySubPrivilege($comment->commenter)); + LogHelper::logEvent('comment-del', '+{user} removed comment from @{post}', ['post' => $comment->post->id]); R::trash($comment); StatusHelper::success(); } diff --git a/src/Controllers/PostController.php b/src/Controllers/PostController.php index 2889d9a0..47c4321d 100644 --- a/src/Controllers/PostController.php +++ b/src/Controllers/PostController.php @@ -130,9 +130,15 @@ class PostController $tags = array_map(function($x) { return $x->name; }, $post->sharedTag); if (in_array($tag, $tags)) + { $tags = array_diff($tags, [$tag]); + LogHelper::logEvent('post-tag-del', '+{user} untagged @{post} with #{tag}', ['post' => $post->id, 'tag' => $tag]); + } else + { $tags += [$tag]; + LogHelper::logEvent('post-tag-add', '+{user} tagged @{post} with #{tag}', ['post' => $post->id, 'tag' => $tag]); + } $dbTags = Model_Tag::insertOrUpdate($tags); $post->sharedTag = $dbTags; @@ -339,6 +345,12 @@ class PostController } R::store($dbPost); + LogHelper::logEvent('post-new', + '+{user} added @{post} tagged with ' + . join(', ', array_map(function($dbTag) { return '#' . $dbTag->name; }, $dbTags)) + . ' marked as ' . PostSafety::toString($dbPost->safety), + ['post' => $dbPost->id]); + StatusHelper::success(); } } @@ -356,14 +368,17 @@ class PostController if (InputHelper::get('submit')) { + LogHelper::bufferChanges(); + /* safety */ $suppliedSafety = InputHelper::get('safety'); - if ($suppliedSafety !== null) + if ($suppliedSafety !== null and $suppliedSafety != $post->safety) { PrivilegesHelper::confirmWithException(Privilege::EditPostSafety, PrivilegesHelper::getIdentitySubPrivilege($post->uploader)); $suppliedSafety = Model_Post::validateSafety($suppliedSafety); $post->safety = $suppliedSafety; $edited = true; + LogHelper::logEvent('post-edit', '+{user} changed safety for @{post} to {safety}', ['post' => $post->id, 'safety' => PostSafety::toString($post->safety)]); } @@ -378,8 +393,15 @@ class PostController $suppliedTags = Model_Tag::validateTags($suppliedTags); $dbTags = Model_Tag::insertOrUpdate($suppliedTags); + + $oldTags = array_map(function($tag) { return $tag->name; }, $post->sharedTag); $post->sharedTag = $dbTags; $edited = true; + + foreach (array_diff($oldTags, $suppliedTags) as $tag) + LogHelper::logEvent('post-tag-del', '+{user} untagged @{post} with #{tag}', ['post' => $post->id, 'tag' => $tag]); + foreach (array_diff($suppliedTags, $oldTags) as $tag) + LogHelper::logEvent('post-tag-add', '+{user} tagged @{post} with #{tag}', ['post' => $post->id, 'tag' => $tag]); } @@ -401,17 +423,19 @@ class PostController $path = $this->config->main->thumbsPath . DS . $post->name . '.custom'; move_uploaded_file($suppliedFile['tmp_name'], $path); + LogHelper::logEvent('post-edit', '+{user} added custom thumb for @{post}', ['post' => $post->id]); } /* source */ $suppliedSource = InputHelper::get('source'); - if ($suppliedSource !== null) + if ($suppliedSource !== null and $suppliedSource != $post->sorce) { PrivilegesHelper::confirmWithException(Privilege::EditPostSource, PrivilegesHelper::getIdentitySubPrivilege($post->uploader)); $suppliedSource = Model_Post::validateSource($suppliedSource); $post->source = $suppliedSource; $edited = true; + LogHelper::logEvent('post-edit', '+{user} changed source for @{post} to {source}', ['post' => $post->id, 'source' => $post->source]); } @@ -430,13 +454,20 @@ class PostController throw new SimpleException('Too many related posts (maximum: ' . $this->config->browsing->maxRelatedPosts . ')'); $relatedPosts []= Model_Post::locate($relatedId); } + + $oldRelatedIds = array_map(function($post) { return $post->id; }, $post->via('crossref')->sharedPost); $post->via('crossref')->sharedPost = $relatedPosts; + + foreach (array_diff($oldRelatedIds, $relatedIds) as $post2id) + LogHelper::logEvent('post-relation-del', '+{user} removed relation between @{post} and #{post2}', ['post' => $post->id, 'post2' => $post2id]); + foreach (array_diff($relatedIds, $oldRelatedIds) as $post2id) + LogHelper::logEvent('post-relation-add', '+{user} added relation between @{post} and #{post2}', ['post' => $post->id, 'post2' => $post2id]); } R::store($post); Model_Tag::removeUnused(); - + LogHelper::flush(); StatusHelper::success(); } } @@ -451,14 +482,19 @@ class PostController $post = Model_Post::locate($id); R::preload($post, ['uploader' => 'user']); PrivilegesHelper::confirmWithException(Privilege::HidePost, PrivilegesHelper::getIdentitySubPrivilege($post->uploader)); + if (InputHelper::get('submit')) { $post->hidden = true; R::store($post); + + LogHelper::logEvent('post-hide', '+{user} hidden @{post}', ['post' => $post->id]); StatusHelper::success(); } } + + /** * @route /post/{id}/unhide */ @@ -467,14 +503,19 @@ class PostController $post = Model_Post::locate($id); R::preload($post, ['uploader' => 'user']); PrivilegesHelper::confirmWithException(Privilege::HidePost, PrivilegesHelper::getIdentitySubPrivilege($post->uploader)); + if (InputHelper::get('submit')) { $post->hidden = false; R::store($post); + + LogHelper::logEvent('post-unhide', '+{user} unhidden @{post}', ['post' => $post->id]); StatusHelper::success(); } } + + /** * @route /post/{id}/delete */ @@ -483,6 +524,7 @@ class PostController $post = Model_Post::locate($id); R::preload($post, ['uploader' => 'user']); PrivilegesHelper::confirmWithException(Privilege::DeletePost, PrivilegesHelper::getIdentitySubPrivilege($post->uploader)); + if (InputHelper::get('submit')) { //remove stuff from auxiliary tables @@ -495,6 +537,8 @@ class PostController $post->sharedTag = []; R::store($post); R::trash($post); + + LogHelper::logEvent('post-delete', '+{user} deleted @{post}', ['post' => $id]); StatusHelper::success(); } } @@ -597,6 +641,7 @@ class PostController Model_Property::set(Model_Property::FeaturedPostUserId, $this->context->user->id); Model_Property::set(Model_Property::FeaturedPostDate, time()); StatusHelper::success(); + LogHelper::logEvent('post-feature', '+{user} featured @{post} on main page', ['post' => $post->id]); } diff --git a/src/Controllers/TagController.php b/src/Controllers/TagController.php index d35281aa..70c36cad 100644 --- a/src/Controllers/TagController.php +++ b/src/Controllers/TagController.php @@ -69,7 +69,9 @@ class TagController R::store($post); } R::trash($sourceTag); + \Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('tag', 'list')); + LogHelper::logEvent('tag-merge', '+{user} merged #{source} with #{target}', ['source' => $suppliedSourceTag, 'target' => $suppliedTargetTag]); StatusHelper::success(); } } @@ -101,6 +103,7 @@ class TagController R::store($sourceTag); \Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('tag', 'list')); + LogHelper::logEvent('tag-rename', '+{user} renamed #{source} to #{target}', ['source' => $suppliedSourceTag, 'target' => $suppliedTargetTag]); StatusHelper::success(); } } diff --git a/src/Controllers/UserController.php b/src/Controllers/UserController.php index 1901fb3b..60704f29 100644 --- a/src/Controllers/UserController.php +++ b/src/Controllers/UserController.php @@ -49,6 +49,8 @@ class UserController $headers []= sprintf('X-Originating-IP: %s', $_SERVER['SERVER_ADDR']); $subject = '=?UTF-8?B?' . base64_encode($subject) . '?='; mail($recipientEmail, $subject, $body, implode("\r\n", $headers), '-f' . $senderEmail); + + LogHelper::logEvent('mail', 'Sending e-mail with subject "' . $subject . '" to ' . $recipientEmail); } private static function sendEmailChangeConfirmation($user) @@ -147,6 +149,7 @@ class UserController { $user->banned = true; R::store($user); + LogHelper::logEvent('ban', '+{user} banned +{subject}', ['subject' => $user->name]); StatusHelper::success(); } } @@ -163,6 +166,7 @@ class UserController { $user->banned = false; R::store($user); + LogHelper::logEvent('unban', '+{user} unbanned +{subject}', ['subject' => $user->name]); StatusHelper::success(); } } @@ -179,6 +183,7 @@ class UserController { $user->staff_confirmed = true; R::store($user); + LogHelper::logEvent('reg-accept', '+{user} confirmed account for +{subject}', ['subject' => $user->name]); StatusHelper::success(); } } @@ -207,6 +212,7 @@ class UserController if (InputHelper::get('submit')) { + $name = $user->name; if ($this->context->user->id == $user->id) { $suppliedPasswordHash = Model_User::hashPassword($suppliedCurrentPassword, $user->pass_salt); @@ -228,7 +234,9 @@ class UserController AuthController::doLogOut(); R::store($user); R::trash($user); + \Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('index', 'index')); + LogHelper::logEvent('user-del', '+{user} removed account for +{subject}', ['subject' => $name]); StatusHelper::success(); } } @@ -303,12 +311,15 @@ class UserController if (InputHelper::get('submit')) { $confirmMail = false; + LogHelper::bufferChanges(); if ($suppliedName != '' and $suppliedName != $user->name) { PrivilegesHelper::confirmWithException(Privilege::ChangeUserName, PrivilegesHelper::getIdentitySubPrivilege($user)); $suppliedName = Model_User::validateUserName($suppliedName); + $oldName = $user->name; $user->name = $suppliedName; + LogHelper::logEvent('user-edit', '+{user} renamed +{old} to +{new}', ['old' => $oldName, 'new' => $suppliedName]); } if ($suppliedPassword1 != '') @@ -318,6 +329,7 @@ class UserController throw new SimpleException('Specified passwords must be the same'); $suppliedPassword = Model_User::validatePassword($suppliedPassword1); $user->pass_hash = Model_User::hashPassword($suppliedPassword, $user->pass_salt); + LogHelper::logEvent('user-edit', '+{user} changed password for +{subject}', ['subject' => $user->name]); } if ($suppliedEmail != '' and $suppliedEmail != $user->email_confirmed) @@ -329,11 +341,13 @@ class UserController $user->email_unconfirmed = $suppliedEmail; if (!empty($user->email_unconfirmed)) $confirmMail = true; + LogHelper::logEvent('user-edit', '+{user} changed e-mail to {mail}', ['mail' => $suppliedEmail]); } else { $user->email_unconfirmed = null; $user->email_confirmed = $suppliedEmail; + LogHelper::logEvent('user-edit', '+{user} changed e-mail for +{subject} to {mail}', ['subject' => $user->name, 'mail' => $suppliedEmail]); } } @@ -342,6 +356,7 @@ class UserController PrivilegesHelper::confirmWithException(Privilege::ChangeUserAccessRank, PrivilegesHelper::getIdentitySubPrivilege($user)); $suppliedAccessRank = Model_User::validateAccessRank($suppliedAccessRank); $user->access_rank = $suppliedAccessRank; + LogHelper::logEvent('user-edit', '+{user} changed access rank for +{subject} to {rank}', ['subject' => $user->name, 'rank' => AccessRank::toString($suppliedAccessRank)]); } if ($this->context->user->id == $user->id) @@ -355,9 +370,10 @@ class UserController if ($confirmMail) self::sendEmailChangeConfirmation($user); + LogHelper::flush(); $message = 'Account settings updated!'; if ($confirmMail) - $message .= ' You wlil be sent an e-mail address confirmation message soon.'; + $message .= ' You will be sent an e-mail address confirmation message soon.'; StatusHelper::success($message); } } @@ -519,6 +535,7 @@ class UserController elseif ($this->config->registration->staffActivation) $message .= ' Your registration must be now confirmed by staff.'; + LogHelper::logEvent('user-reg', '+{subject} just signed up', ['subject' => $dbUser->name]); StatusHelper::success($message); if (!$this->config->registration->needEmailForRegistering and !$this->config->registration->staffActivation) @@ -548,6 +565,7 @@ class UserController R::store($dbToken); R::store($dbUser); + LogHelper::logEvent('user-activation', '+{subject} just activated account', ['subject' => $dbUser->name]); $message = 'Activation completed successfully.'; if ($this->config->registration->staffActivation) $message .= ' However, your account still must be confirmed by staff.'; @@ -584,6 +602,7 @@ class UserController R::store($dbToken); R::store($dbUser); + LogHelper::logEvent('user-pass-reset', '+{subject} just reset password', ['subject' => $dbUser->name]); $message = 'Password reset successfuly. Your new password is **' . $randomPassword . '**.'; StatusHelper::success($message); diff --git a/src/Helpers/LogHelper.php b/src/Helpers/LogHelper.php new file mode 100644 index 00000000..a2724c4d --- /dev/null +++ b/src/Helpers/LogHelper.php @@ -0,0 +1,69 @@ +main->logsPath . date('Y-m') . '.log'; + self::$autoFlush = true; + + self::$content = ''; + } + + public static function bufferChanges() + { + self::$autoFlush = false; + } + + public static function flush() + { + $fh = fopen(self::getLogPath(), 'ab'); + if (!$fh) + throw new SimpleException('Cannot write to log files'); + if (flock($fh, LOCK_EX)) + { + fwrite($fh, self::$content); + fflush($fh); + flock($fh, LOCK_UN); + fclose($fh); + } + self::$content = ''; + self::$autoFlush = true; + } + + public static function getLogPath() + { + return self::$path; + } + + public static function log($text, array $tokens = []) + { + if (isset(self::$context->user)) + $tokens['user'] = self::$context->user->name; + + $text = TextHelper::replaceTokens($text, $tokens); + + $timestamp = date('Y-m-d H:i:s'); + $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; + $line = sprintf('[%s] %s: %s' . PHP_EOL, $timestamp, $ip, $text); + + self::$content .= $line; + + if (self::$autoFlush) + self::flush(); + } + + public static function logEvent($event, $text, array $tokens = []) + { + return self::log(sprintf('[%s] %s', $event, $text), $tokens); + } +} + +LogHelper::init();