Files
Phraseanet/lib/Alchemy/Phrasea/Report/ReportActions.php
2024-06-18 09:16:13 +02:00

321 lines
13 KiB
PHP

<?php
/**
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Report;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Model\Entities\User;
class ReportActions extends Report
{
private $appKey;
/** @var \ACL */
private $acl;
private $collIds = null;
private $permalink = null;
private $sqlColSelect = null;
private $sqlFieldSelect = null;
/* those vars will be set once by computeVars() */
private $name = null;
private $sql = null;
private $columnTitles = [];
private $keyName = null;
private $actions = [];
private $isDownloadReport = false;
public function getColumnTitles()
{
$this->computeVars();
// only for group downloads all and download by record
if ((empty($this->parms['group']) || $this->parms['group'] == 'record') && !empty($this->permalink)) {
$this->columnTitles[] = 'permalink_' . $this->permalink;
}
return $this->columnTitles;
}
public function getKeyName()
{
$this->computeVars();
return $this->keyName;
}
public function getName()
{
$this->computeVars();
return $this->name;
}
public function setAppKey($appKey)
{
$this->appKey = $appKey;
return $this;
}
public function setACL($acl)
{
$this->acl = $acl;
return $this;
}
public function setCollIds($collIds)
{
$this->collIds = $collIds;
return $this;
}
public function setPermalink($permalink)
{
$this->permalink = $permalink;
return $this;
}
public function setActions(array $actions)
{
$this->actions = $actions;
return $this;
}
public function setAsDownloadReport(bool $isDownloadReport)
{
$this->isDownloadReport = !!$isDownloadReport;
return $this;
}
public function getAllRows($callback)
{
$app = $this->getDatabox()->getPhraseApplication();
$userRepository = $app['repo.users'];
$this->computeVars();
$stmt = $this->databox->get_connection()->executeQuery($this->sql, []);
while (($row = $stmt->fetch())) {
// only for group downloads all and download by user
if (empty($this->parms['group']) || $this->parms['group'] == 'user') {
try {
/** @var User $user */
$user = $userRepository->find($row['usrid']);
$row['user'] = $user->getDisplayName();
$row['email'] = $user->getEmail();
} catch (\Exception $e) {
}
}
// only for group downloads all and download by record
if ((empty($this->parms['group']) || $this->parms['group'] == 'record') && !empty($this->permalink)) {
try {
$permalinkUrl = '';
$record = $this->databox->get_record($row['record_id']);
// if from GUI, check if user has access to subdef in collection
if (!isset($this->acl) || $this->acl->has_right_on_base($record->getBaseId(), \ACL::CANDWNLDPREVIEW)) {
$permalinkUrl = $record->get_subdef($this->permalink)->get_permalink()->get_url()->__toString();
}
} catch (\Exception $e) {
// the record or subdef is not found
} catch (\Throwable $e) {
// there is no permalink created ???
}
$row['permalink_' . $this->permalink] = $permalinkUrl;
}
$callback($row);
}
$stmt->closeCursor();
}
private function computeVars()
{
if(!is_null($this->name)) {
// vars already computed
return;
}
switch ($this->parms['group']) {
case null:
if ($this->isDownloadReport) {
$this->name = "Downloads";
$this->columnTitles = ['id', 'usrid', 'user', 'email', 'fonction', 'societe', 'activite', 'pays', 'date', 'record_id', 'record_type', 'coll_id' ,'coll_name' ,'subdef', 'action', 'destinataire'];
} else {
$this->columnTitles = ['id', 'usrid', 'user', 'email', 'fonction', 'societe', 'activite', 'pays', 'date', 'record_id', 'record_type', 'coll_id','coll_name' ,'final', 'action', 'comment'];
}
$this->sqlColSelect = [];
$this->sqlFiedlSelect = [];
foreach($this->getDatabox()->get_meta_structure() as $field) {
// skip the fields that can't be reported
if(!$field->is_report()) {
continue;
}
// column names is not important in the result, simply match the 'title' position
$this->columnTitles[] = $field->get_name();
$this->sqlColSelect[] = sprintf("GROUP_CONCAT(IF(`m`.`meta_struct_id`=%s, `m`.`value`, NULL)) AS `f%s`", $field->get_id(), $field->get_id());
$this->sqlFieldSelect[] = sprintf("`F`.`f%s`", $field->get_id());
}
$this->sqlColSelect = join(",\n", $this->sqlColSelect);
$this->sqlFieldSelect = join(",\n", $this->sqlFieldSelect);
if($this->parms['anonymize']) {
$sql = "SELECT `ld`.`id`, `l`.`usrid`, '-' AS `user`, '-' AS `email`, '-' AS `fonction`, '-' AS `societe`, '-' AS `activite`, '-' AS `pays`,\n"
. " `ld`.`date`, `ld`.`record_id`, IF(`r`.`parent_record_id` = 0 , 'record' , 'story') AS `record_type`, `ld`.`coll_id`, `c`.`asciiname` AS `coll_name`, `ld`.`final`, `ld`.`action`, `ld`.`comment` AS `destinataire`,\n"
. $this->sqlFieldSelect . " \n"
. " FROM `log_docs` AS `ld` INNER JOIN `log` AS `l` ON `l`.`id`=`ld`.`log_id`\n"
. " LEFT JOIN `coll` AS `c` ON `ld`.`coll_id` = `c`.`coll_id` \n"
. " LEFT JOIN `record` AS `r` ON `ld`.`record_id` = `r`.`record_id`"
. " LEFT JOIN (SELECT `m`.`record_id`, " . $this->sqlColSelect . " FROM `metadatas` AS `m` GROUP BY `m`.`record_id` ) AS `F` ON `ld`.`record_id` = `F`.`record_id` \n"
. " WHERE {{GlobalFilter}}";
}
else {
$sql = "SELECT `ld`.`id`, `l`.`usrid`, `l`.`user`, '-' AS `email`, `l`.`fonction`, `l`.`societe`, `l`.`activite`, `l`.`pays`,\n"
. " `ld`.`date`, `ld`.`record_id`, IF(`r`.`parent_record_id` = 0 , 'record' , 'story') AS `record_type`, `ld`.`coll_id`, `c`.`asciiname` AS `coll_name`, `ld`.`final`, `ld`.`action`, `ld`.`comment` AS `destinataire`,\n"
. $this->sqlFieldSelect . " \n"
. " FROM `log_docs` AS `ld` INNER JOIN `log` AS `l` ON `l`.`id`=`ld`.`log_id`\n"
. " LEFT JOIN `coll` AS `c` ON `ld`.`coll_id` = `c`.`coll_id` \n"
. " LEFT JOIN `record` AS `r` ON `ld`.`record_id` = `r`.`record_id`"
. " LEFT JOIN (SELECT `m`.`record_id`, " . $this->sqlColSelect . " FROM `metadatas` AS `m` GROUP BY `m`.`record_id` ) AS `F` ON `ld`.`record_id` = `F`.`record_id` \n"
. " WHERE {{GlobalFilter}}";
}
$this->keyName = 'id';
break;
case 'user':
$this->name = "Downloads by user";
$this->columnTitles = ['usrid', 'user', 'email', 'fonction', 'societe', 'activite', 'pays', 'min_date', 'max_date', 'nb'];
if($this->parms['anonymize']) {
$sql = "SELECT `l`.`usrid`, '-' AS `user`, '-' AS `email`, '-' AS `fonction`, '-' AS `societe`, '-' AS `activite`, '-' AS `pays`,\n"
. " MIN(`ld`.`date`) AS `dmin`, MAX(`ld`.`date`) AS `dmax`, SUM(1) AS `nb`\n"
. " FROM `log_docs` AS `ld` INNER JOIN `log` AS `l` ON `l`.`id`=`ld`.`log_id`\n"
. " WHERE {{GlobalFilter}}\n"
. " GROUP BY `l`.`usrid`\n"
. " ORDER BY `nb` DESC";
}
else {
$sql = "SELECT `l`.`usrid`, `l`.`user`, '-' AS `email`, `l`.`fonction`, `l`.`societe`, `l`.`activite`, `l`.`pays`,\n"
. " MIN(`ld`.`date`) AS `dmin`, MAX(`ld`.`date`) AS `dmax`, SUM(1) AS `nb`\n"
. " FROM `log_docs` AS `ld` INNER JOIN `log` AS `l` ON `l`.`id`=`ld`.`log_id`\n"
. " WHERE {{GlobalFilter}}\n"
. " GROUP BY `l`.`usrid`\n"
. " ORDER BY `nb` DESC";
}
$this->keyName = 'usrid';
break;
case 'record':
$this->name = "Downloads by record";
$this->columnTitles = ['record_id', 'min_date', 'max_date', 'nb'];
$sql = "SELECT `ld`.`record_id`,\n"
. " MIN(`ld`.`date`) AS `dmin`, MAX(`ld`.`date`) AS `dmax`, SUM(1) AS `nb`\n"
. " FROM `log_docs` AS `ld` INNER JOIN `log` AS `l` ON `l`.`id`=`ld`.`log_id`\n"
. " WHERE {{GlobalFilter}}\n"
. " GROUP BY `l`.`usrid`\n"
. " ORDER BY `nb` DESC"
;
$this->keyName = 'record_id';
break;
case 'field':
$this->name = "Downloads by field";
foreach($this->getDatabox()->get_meta_structure() as $field) {
if ($field->get_id() == $this->parms['meta_struct_id']) {
$this->columnTitles =[$field->get_name()];
}
}
$this->columnTitles[] = 'nb';
$sql = "SELECT `m`.`value`, count(`ld`.`record_id`) as `nb`\n"
. " FROM `log_docs` AS `ld` INNER JOIN `log` AS `l` ON `l`.`id`=`ld`.`log_id`\n"
. " LEFT JOIN `metadatas` AS `m` ON (`ld`.`record_id`=`m`.`record_id` AND `m`.`meta_struct_id`=". $this->parms['meta_struct_id'] .") "
. " WHERE {{GlobalFilter}}\n"
. " GROUP BY `m`.`value`\n"
. " ORDER BY `nb` DESC"
;
$this->keyName = 'value';
break;
default:
throw new InvalidArgumentException('invalid "group" argument');
break;
}
if (isset($this->acl)) {
// get acl-filtered coll_id(s) as already sql-quoted
$collIds = $this->getCollIds($this->acl, $this->parms['bases']);
} else {
$collIds = $this->collIds;
}
if ($this->isDownloadReport) {
$this->actions = ['download', 'mail'];
} else {
$this->name = "export databox action";
}
if(!empty($collIds)) {
$filter = "";
if (!empty($this->actions)) {
$actionFilter = join("' ,'", $this->actions);
$filter = "`action` IN('" . $actionFilter . "') AND ";
}
$filter .= " `ld`.`coll_id` IN(" . join(',', $collIds) . ")\n"
. " AND `l`.`usrid`>0";
if ($this->isDownloadReport) {
// filter subdefs by class
$subdefsToReport = ['document' => $this->databox->get_connection()->quote('document')];
foreach ($this->getDatabox()->get_subdef_structure() as $subGroup) {
foreach ($subGroup->getIterator() as $sub) {
if(in_array($sub->get_class(), ['document', 'preview'])) {
// keep only unique names
$subdefsToReport[$sub->get_name()] = $this->databox->get_connection()->quote($sub->get_name());
}
}
}
$subdefsToReport = join(',', $subdefsToReport);
$filter .=" AND `ld`.`final` IN(" . $subdefsToReport . ")";
}
// next line : comment to disable "site", to test on an imported dataset from another instance
$filter .= "\n AND `l`.`site` = " . $this->databox->get_connection()->quote($this->appKey);
if($this->parms['dmin']) {
$filter .= "\n AND `ld`.`date` >= " . $this->databox->get_connection()->quote($this->parms['dmin']);
}
if($this->parms['dmax']) {
$filter .= "\n AND `ld`.`date` <= " . $this->databox->get_connection()->quote($this->parms['dmax'] . " 23:59:59");
}
}
else {
// no collections report ?
// keep the sql intact (to match placeholders/parameters), but enforce empty result
$filter = "FALSE";
}
$this->sql = str_replace('{{GlobalFilter}}', $filter, $sql);
// file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n", __FILE__, __LINE__, $this->sql), FILE_APPEND);
}
}