tao-test/app/taoEventLog/model/userLastActivityLog/rds/UserLastActivityLogStorage.php

248 lines
8.6 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2017 (original work) Open Assessment Technologies SA;
*
*
*/
namespace oat\taoEventLog\model\userLastActivityLog\rds;
use oat\oatbox\user\User;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Query\QueryBuilder;
use oat\taoEventLog\model\RdsLogIterator;
use oat\taoEventLog\model\userLastActivityLog\UserLastActivityLog;
use oat\oatbox\service\ConfigurableService;
use GuzzleHttp\Psr7\ServerRequest;
use oat\oatbox\event\Event;
/**
* Class UserLastActivityLogStorage
* @package oat\taoEventLog\model\userLastActivityLog\rds
* @author Aleh Hutnikau, <hutnikau@1pt.com>
*/
class UserLastActivityLogStorage extends ConfigurableService implements UserLastActivityLog
{
const OPTION_PERSISTENCE = 'persistence_id';
const TABLE_NAME = 'user_last_activity_log';
const COLUMN_USER_ID = self::USER_ID;
const COLUMN_USER_ROLES = self::USER_ROLES;
const COLUMN_ACTION = self::ACTION;
const COLUMN_EVENT_TIME = self::EVENT_TIME;
const COLUMN_DETAILS = self::DETAILS;
/** Threshold in seconds */
const OPTION_ACTIVE_USER_THRESHOLD = 'active_user_threshold';
const PHP_SESSION_LAST_ACTIVITY = 'tao_user_last_activity_timestamp';
/**
* @inheritdoc
*/
public function log(User $user, $action, array $details = [])
{
$userId = $user->getIdentifier();
if ($userId === null) {
$userId = get_class($user);
}
$data = [
self::USER_ID => $userId,
self::USER_ROLES => ','. implode(',', $user->getRoles()). ',',
self::COLUMN_ACTION => strval($action),
self::COLUMN_EVENT_TIME => microtime(true),
self::COLUMN_DETAILS => json_encode($details),
];
$this->getPersistence()->exec('DELETE FROM ' . self::TABLE_NAME . ' WHERE ' . self::USER_ID . ' = \'' . $userId . '\'');
$this->getPersistence()->insert(self::TABLE_NAME, $data);
}
/**
* @inheritdoc
*/
public function find(array $filters = [], array $options = [])
{
$queryBuilder = $this->getQueryBuilder();
$queryBuilder->select('*');
if (isset($options['limit'])) {
$queryBuilder->setMaxResults(intval($options['limit']));
}
if (isset($options['offset'])) {
$queryBuilder->setFirstResult(intval($options['offset']));
}
if (isset($options['group']) && in_array($options['group'], $this->getColumnNames())) {
$queryBuilder->groupBy($options['group']);
}
foreach ($filters as $filter) {
$this->addFilter($queryBuilder, $filter);
}
return new RdsLogIterator($this->getPersistence(), $queryBuilder);
}
/**
* @inheritdoc
*/
public function count(array $filters = [], array $options = [])
{
$queryBuilder = $this->getQueryBuilder();
$queryBuilder->select('user_id');
foreach ($filters as $filter) {
$this->addFilter($queryBuilder, $filter);
}
if (isset($options['group']) && in_array($options['group'], $this->getColumnNames())) {
$queryBuilder->select($options['group']);
$queryBuilder->groupBy($options['group']);
}
$stmt = $this->getPersistence()->query(
'SELECT count(*) as count FROM (' .$queryBuilder->getSQL() . ') as group_q', $queryBuilder->getParameters());
$data = $stmt->fetch(\PDO::FETCH_ASSOC);
return intval($data['count']);
}
/**
* @param QueryBuilder $queryBuilder
* @param array $filter
*/
private function addFilter(QueryBuilder $queryBuilder, array $filter)
{
$colName = strtolower($filter[0]);
$operation = strtolower($filter[1]);
$val = $filter[2];
$val2 = isset($filter[3]) ? $filter[3] : null;
if (!in_array($colName, $this->getColumnNames())) {
return;
}
if (!in_array($operation, ['<', '>', '<>', '<=', '>=', '=', 'between', 'like'])) {
return;
}
$params = [];
if ($operation === 'between') {
$condition = "r.$colName between ? AND ?";
$params[] = $val;
$params[] = $val2;
} else {
$condition = "r.$colName $operation ?";
$params[] = $val;
}
$queryBuilder->andWhere($condition);
$params = array_merge($queryBuilder->getParameters(), $params);
$queryBuilder->setParameters($params);
}
/**
* @return array
*/
private function getColumnNames()
{
return [
self::USER_ID,
self::USER_ROLES,
self::COLUMN_ACTION,
self::COLUMN_EVENT_TIME,
self::COLUMN_DETAILS,
];
}
/**
* @return \common_persistence_SqlPersistence
* @throws
*/
private function getPersistence()
{
$persistenceManager = $this->getServiceManager()->get(\common_persistence_Manager::SERVICE_ID);
return $persistenceManager->getPersistenceById($this->getOption(self::OPTION_PERSISTENCE));
}
/**
* @return \Doctrine\DBAL\Query\QueryBuilder
* @throws
*/
private function getQueryBuilder()
{
return $this->getPersistence()->getPlatForm()->getQueryBuilder()->from(self::TABLE_NAME, 'r');
}
/**
* Initialize log storage
*
* @param \common_persistence_Persistence $persistence
* @return \common_report_Report
*/
public static function install($persistence)
{
$schemaManager = $persistence->getDriver()->getSchemaManager();
$schema = $schemaManager->createSchema();
$fromSchema = clone $schema;
try {
$table = $schema->createTable(self::TABLE_NAME);
$table->addOption('engine', 'InnoDB');
$table->addColumn(static::COLUMN_USER_ID, "string", ["length" => 255]);
$table->addColumn(static::COLUMN_USER_ROLES, "string", ["notnull" => true, "length" => 4096]);
$table->addColumn(static::COLUMN_ACTION, "string", ["notnull" => false, "length" => 4096]);
$table->addColumn(static::COLUMN_EVENT_TIME, 'decimal', ['precision' => 14, 'scale'=>4, "notnull" => true]);
$table->addColumn(static::COLUMN_DETAILS, "text", ["notnull" => false]);
$table->addIndex([static::COLUMN_USER_ID], 'IDX_' . static::TABLE_NAME . '_' . static::COLUMN_USER_ID);
$table->addIndex([static::COLUMN_EVENT_TIME], 'IDX_' . static::TABLE_NAME . '_' . static::COLUMN_EVENT_TIME);
} catch(SchemaException $e) {
\common_Logger::i('Database Schema already up to date.');
}
$queries = $persistence->getPlatform()->getMigrateSchemaSql($fromSchema, $schema);
foreach ($queries as $query) {
$persistence->exec($query);
}
return new \common_report_Report(\common_report_Report::TYPE_SUCCESS, __('User activity log successfully registered.'));
}
/**
* @param Event $event
* @throws \common_exception_Error
*/
public function catchEvent(Event $event)
{
if (\common_session_SessionManager::isAnonymous()) {
return;
}
$phpSession = \PHPSession::singleton();
$lastStoredActivity = null;
if ($phpSession->hasAttribute(self::PHP_SESSION_LAST_ACTIVITY)) {
$lastStoredActivity = $phpSession->getAttribute(self::PHP_SESSION_LAST_ACTIVITY);
}
$threshold = $this->getOption(self::OPTION_ACTIVE_USER_THRESHOLD)?: 0;
$currentTime = microtime(true);
if (!$lastStoredActivity || $currentTime > ($lastStoredActivity + $threshold)) {
$user = \common_session_SessionManager::getSession()->getUser();
$request = ServerRequest::fromGlobals();
$phpSession->setAttribute(self::PHP_SESSION_LAST_ACTIVITY, $currentTime);
/** @var UserActivityLogStorage $userActivityLog */
$this->log($user, $request->getUri());
}
}
}