From 05095a9c8ed75e3660ecce406e7578af426de75d Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 10:41:04 +0200 Subject: [PATCH 01/11] DB Migration: 20180401083402_create_activity_log.php --- .../20180401083402_create_activity_log.php | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 app/migrations/20180401083402_create_activity_log.php diff --git a/app/migrations/20180401083402_create_activity_log.php b/app/migrations/20180401083402_create_activity_log.php new file mode 100644 index 0000000..6b49d51 --- /dev/null +++ b/app/migrations/20180401083402_create_activity_log.php @@ -0,0 +1,32 @@ +table('activity_log'); + + $table->addColumn('timestamp', 'datetime', [ + 'default' => 'CURRENT_TIMESTAMP', + 'after' => 'email' + ]); + + $table->addColumn('user_id', 'integer') + ->addForeignKey('user_id', 'user', ['id']); + + $table->addColumn('ip', 'string', [ + 'null' => true, + 'length' => 50, + ]); + + $table->addColumn('message', 'string', [ + 'null' => true, + 'length' => 255, + ]); + + $table->save(); + } +} From 3f99105588290cf156417b1cf9eb0df36737226f Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 11:04:07 +0200 Subject: [PATCH 02/11] adding app/models/Data/ActivityLog.php --- app/models/Data/ActivityLog.php | 131 ++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 app/models/Data/ActivityLog.php diff --git a/app/models/Data/ActivityLog.php b/app/models/Data/ActivityLog.php new file mode 100644 index 0000000..91f3158 --- /dev/null +++ b/app/models/Data/ActivityLog.php @@ -0,0 +1,131 @@ +id; + } + + /** + * @param mixed $id + * @return User + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * @return mixed + */ + public function getTimestamp() + { + return $this->timestamp; + } + + /** + * @param mixed $timestamp + * @return ActivityLog + */ + public function setTimestamp($timestamp) + { + $this->timestamp = $timestamp; + return $this; + } + + /** + * @return mixed + */ + public function getUserId() + { + return $this->user_id; + } + + /** + * @param mixed $user_id + * @return ActivityLog + */ + public function setUserId($user_id) + { + $this->user_id = $user_id; + return $this; + } + + /** + * @return mixed + */ + public function getIp() + { + return $this->ip; + } + + /** + * @param mixed $ip + * @return ActivityLog + */ + public function setIp($ip) + { + $this->ip = $ip; + return $this; + } + + /** + * @return mixed + */ + public function getMessage() + { + return $this->message; + } + + /** + * @param mixed $message + * @return ActivityLog + */ + public function setMessage($message) + { + $this->message = $message; + return $this; + } + + /** + * @param $userid + * @param int $page + * @param int $limit + * @return \Phalcon\Paginator\AdapterInterface + */ + public static function getPaginationList($userid, $page = 1, $limit = 30) + { + $builder = (new self())->getModelsManager()->createBuilder(); + + $builder->from(self::class) + ->where('user_id = :uid:', array('uid' => $userid)) + ->orderBy('timestamp DESC'); + + $paginator = new QueryBuilder(array( + 'builder' => $builder, + 'page' => $page, + 'limit' => $limit + )); + + return $paginator; + } +} From 589033717965b373f274bd477abe18ee87e903ba Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 11:04:33 +0200 Subject: [PATCH 03/11] app/controllers/UserController.php: adding activity action --- app/controllers/UserController.php | 13 ++++++++++++- app/views/user/activity.volt | 31 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 app/views/user/activity.volt diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index b87fb23..0d038d3 100644 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -3,7 +3,8 @@ namespace App\Controller; use App\Controller\ControllerBase, - App\Form\UserSettings as UserSettingsForm; + App\Form\UserSettings as UserSettingsForm, + App\Model\Data\ActivityLog; class UserController extends ControllerBase { @@ -34,4 +35,14 @@ class UserController extends ControllerBase $this->view->form = $form; } + + public function activityAction($page = 1) + { + $user = $this->_getAuth()->getUser(); + + $paginator = ActivityLog::getPaginationList($user->getId(), $page); + + $this->view->page = $paginator->getPaginate(); + $this->view->pagination_url = '/user/activity/'; + } } diff --git a/app/views/user/activity.volt b/app/views/user/activity.volt new file mode 100644 index 0000000..be1aa4a --- /dev/null +++ b/app/views/user/activity.volt @@ -0,0 +1,31 @@ + +
+ +

Activity Log

+ + + + + + + + + + + + {% for item in page.items %} + + + + + + {% endfor %} + +
DateIpMessage
{{ item.getTimestamp() }}{{ item.getIp() }}{{ item.getMessage() }}
+ + +
+ + From 8666e3b707155e82c2d64eee48ba59c4f589b7e3 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 18:27:11 +0200 Subject: [PATCH 04/11] adding app/listeners/ActivityLog.php --- app/listeners/ActivityLog.php | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 app/listeners/ActivityLog.php diff --git a/app/listeners/ActivityLog.php b/app/listeners/ActivityLog.php new file mode 100644 index 0000000..2b62892 --- /dev/null +++ b/app/listeners/ActivityLog.php @@ -0,0 +1,68 @@ +_log($auth->getUser(), "Logged in ({$type})"); + } + + /** + * @param Event $event + * @param User $auth + */ + public function onPasswordCreated(Event $event, User $user) + { + $this->_log($user, "Created password"); + } + + /** + * @param Event $event + * @param User $auth + */ + public function onPasswordChanged(Event $event, User $user) + { + $this->_log($user, "Changed password"); + } + + protected function _log(User $user, $message) + { + $ip = (new \Phalcon\Http\Request())->getClientAddress(); + + $data = [ + 'user_id' => $user->getId(), + 'ip' => $ip, + 'message' => $message + ]; + + return $this->_getLogger()->create($data); + } + + protected function _getLogger() + { + if ($this->_table === null) { + $this->_table = new ActivityLogger(); + } + return $this->_table; + } +} From aab77e9608a7fc50822a4fcf0084997320d182a2 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 18:28:19 +0200 Subject: [PATCH 05/11] app/library/Auth.php: fire events when users log in. --- app/library/Auth.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/library/Auth.php b/app/library/Auth.php index ac77a2c..0aa51b5 100644 --- a/app/library/Auth.php +++ b/app/library/Auth.php @@ -28,7 +28,11 @@ class Auth extends Component // Verify password $hash = $user->getPassword(); if (strlen($hash) > 1 && password_verify($password, $hash)) { + $this->setIdentity($user->getId()); + + $this->_eventsManager->fire('auth:onLogin', $this, 'password'); + return true; } } @@ -68,6 +72,9 @@ class Auth extends Component } $this->setIdentity($user->getId()); + + $this->_eventsManager->fire('auth:onLogin', $this, + "OAuth {$auth['provider']}"); } /** From b2ca9e3fbad38785c7e27cca66e42edadafd26c9 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 19:35:09 +0200 Subject: [PATCH 06/11] app/config/services.php: adding "eventsManager" --- app/config/services.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/config/services.php b/app/config/services.php index c9112e9..e639b69 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -30,7 +30,8 @@ use Httpcb\Auth, Httpcb\Menu; use App\Listener\AclListener, - App\Listener\DispatchListener; + App\Listener\DispatchListener, + App\Listener\ActivityLog; /** * The FactoryDefault Dependency Injector automatically register the right services providing a full stack framework @@ -216,6 +217,17 @@ $di->setShared('db', function () use ($di, $config) { return $db; }); +$di->setShared('eventsManager', function () { + + $activityLog = new ActivityLog(); + + $eventsManager = new Phalcon\Events\Manager(); + $eventsManager->attach('user', $activityLog); + $eventsManager->attach('auth', $activityLog); + + return $eventsManager; +}); + /** * If the configuration specify the use of metadata adapter use it or use memory otherwise */ From ae6bf194b12d6b0270ccd61478d9d565a0d24080 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 19:35:31 +0200 Subject: [PATCH 07/11] app/config/services.php: add default event manager to Auth. --- app/config/services.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/config/services.php b/app/config/services.php index e639b69..0193e1f 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -298,8 +298,11 @@ $di->set('oauth', function() use ($config) { return new OAuth($config); }); -$di->set('auth', function() use ($config) { - return new Auth($config); +$di->set('auth', function() use ($di, $config) { + $auth = new Auth($config); + $auth->setEventsManager($di->get('eventsManager')); + + return $auth; }); $di->set('acl', 'Httpcb\Acl'); From a3c6ae442939a7d14034aab826edc6c3e65b5ab2 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 19:39:00 +0200 Subject: [PATCH 08/11] app/models/Data/User.php: keep snapshots. --- app/models/Data/User.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/Data/User.php b/app/models/Data/User.php index 2f3252c..5182779 100644 --- a/app/models/Data/User.php +++ b/app/models/Data/User.php @@ -30,6 +30,9 @@ class User extends Model public function initialize() { $this->useDynamicUpdate(true); + + // Keep snapshots so we know if something changes. + $this->keepSnapshots(true); } /** From 8061c674f44a0c59f7840b99a6af3f502a9a18c6 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 19:39:30 +0200 Subject: [PATCH 09/11] app/models/Data/User.php: set default event manager from DI --- app/models/Data/User.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/Data/User.php b/app/models/Data/User.php index 5182779..eefc1dc 100644 --- a/app/models/Data/User.php +++ b/app/models/Data/User.php @@ -33,6 +33,9 @@ class User extends Model // Keep snapshots so we know if something changes. $this->keepSnapshots(true); + + // Set default event manager + $this->setEventsManager($this->getDI()->get('eventsManager')); } /** From bebb0ba5f9842f274f2ccef0c3c70677edcce083 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 1 Apr 2018 19:42:41 +0200 Subject: [PATCH 10/11] app/models/Data/User.php: implement beforeSave() and trigger "user:onPasswordCreated" and "user:onPasswordChanged" --- app/models/Data/User.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/models/Data/User.php b/app/models/Data/User.php index eefc1dc..1f1bc92 100644 --- a/app/models/Data/User.php +++ b/app/models/Data/User.php @@ -206,4 +206,22 @@ class User extends Model "bind" => [ 'v' => $value ] ]); } + + public function beforeSave() + { + $manager = $this->getEventsManager(); + + // EventManager exist and password field has changed. + if ($manager && $this->hasChanged('password')) { + + $old_value = $this->getOldSnapshotData()['password']; + + // Empty password before + if (strlen($old_value) < 1) { + $manager->fire('user:onPasswordCreated', $this); + } else { + $manager->fire('user:onPasswordChanged', $this); + } + } + } } From 16c8bf5c0c87368ef5ff1ead273b13786600ae2c Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Thu, 5 Apr 2018 01:09:36 +0200 Subject: [PATCH 11/11] app/views/_templates/navigation.volt: adding activity link --- app/views/_templates/navigation.volt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/_templates/navigation.volt b/app/views/_templates/navigation.volt index 0d0d072..ef7d12a 100644 --- a/app/views/_templates/navigation.volt +++ b/app/views/_templates/navigation.volt @@ -16,6 +16,7 @@