<?php
//----------------------------------------------------------------------
// src/Services/Logging.php
//----------------------------------------------------------------------
namespace App\Services;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Security\Core\Security;
use App\Entity\Access;
use App\Entity\AccessClient\AccessClient;
use App\Entity\APIRest\AccessAPI;
use App\Entity\Ding\AdvancedNotificationLog;
use App\Entity\Ding\Notification as DingNotification;
use App\Entity\Ding\NotificationType;
use App\Entity\HR\Log as HRLog;
use App\Entity\Ikea\Log as IkeaLog;
use App\Entity\Log\Log;
use App\Entity\Log\LogEntity;
use App\Entity\ProjectManager\Log as ProjectManagerLog;
use App\Services\Common\TextTools;
class Logging
{
const log_to_file_global = 1;
const log_to_file_mission = 2;
const log_to_file_client = 3;
const log_to_file_human_resource = 4;
const log_to_file_project_notebook = 5;
public function __construct(ManagerRegistry $doctrine, TranslatorInterface $translator, Security $security, TextTools $textTools)
{
$this->em = $doctrine->getManager();
$this->translator = $translator;
$this->security = $security;
$this->textTools = $textTools;
// Plan.io Task #3946
// This will only be set as true by isApi method, and only
// if the current user (this->security->getUser()) is not null and is instanceof AccessAPI
// Special case : Request incoming from Rekto/Jcaf
// In this case the AccessAPI is either AccessAPI::ACCESS_API_JCAF or AccessAPI::ACCESS_API_REKTO
// In this particular case, we set the $this->api to false
$this->api = false;
}
public function ploopLog($msg)
{
error_log ("\n".$msg."\n", 3, "ploop.log");
}
//--------------------------------------------------------------------------
// Plan.io Task #3922
// DMS Global, Email and Object Logs
//--------------------------------------------------------------------------
// DMS/Logs/Global/
public function getDMS_GlobalLogsDir()
{
// $home = dirname(__FILE__, 3);
// $home .= "/custom_logs/global_logs/";
// Plan.io Task #3922
// Move file logging to DMS/Logs
$home = dirname(__FILE__, 3);
$home .= "/DMS/Logs/Global/";
return $home;
}
// DMS/Logs/Email/
public function getDMS_EmailLogsDir()
{
$home = dirname(__FILE__, 3);
$home .= "/DMS/Logs/Email/";
return $home;
}
// DMS/Logs/Mission/
public function getDMS_MissionLogsDir()
{
$home = dirname(__FILE__, 3);
$home .= "/DMS/Logs/Mission/";
return $home;
}
// DMS/Logs/Client/
public function getDMS_ClientLogsDir()
{
$home = dirname(__FILE__, 3);
$home .= "/DMS/Logs/Client/";
return $home;
}
// DMS/Logs/HumanResource/
public function getDMS_HumanResourceLogsDir()
{
$home = dirname(__FILE__, 3);
$home .= "/DMS/Logs/HumanResource/";
return $home;
}
// DMS/Logs/ProjectManager/
public function getDMS_ProjectManagerDir()
{
$home = dirname(__FILE__, 3);
$home .= "/DMS/Logs/ProjectManager/";
return $home;
}
// DMS/Logs/ProjectManager/Notebook/
public function getDMS_ProjectManagerNotebookLogsDir()
{
$home = dirname(__FILE__, 3);
$home .= "/DMS/Logs/ProjectManager/Notebook/";
return $home;
}
//--------------------------------------------------------------------------
// Plan.io Task #3922
// No Persist, No Flush
// Returns the $log object
public function smartLog($args)
{
$emptyAccess = $this->em->getRepository(Access::class)
->findOneByEmail(Access::EMPTY_ACCESS);
// Get the arguments
if (array_key_exists("action", $args)) $action = $args["action"];
else $action = null;
// Action is mandatory, all the rest isn't
if ($action === null)
return null;
if (array_key_exists("object_id", $args)) $objectId = $args["object_id"];
else $objectId = null;
if (array_key_exists("object_bundle", $args)) $objectBundle = $args["object_bundle"];
else $objectBundle = null;
if (array_key_exists("object_entity", $args)) $objectEntity = $args["object_entity"];
else $objectEntity = null;
if (array_key_exists("object_display", $args)) $objectDisplay = $this->textTools->cleanTextWithoutHtmlentities($args["object_display"]);
else $objectDisplay = null;
if (array_key_exists("object_client_id", $args)) $objectClientId = $args["object_client_id"];
else $objectClientId = null;
if (array_key_exists("object_client_display", $args)) $objectClientDisplay = $this->textTools->cleanTextWithoutHtmlentities($args["object_client_display"]);
else $objectClientDisplay = null;
if (array_key_exists("object_mission_id", $args)) $objectMissionId = $args["object_mission_id"];
else $objectMissionId = null;
if (array_key_exists("object_mission_display", $args)) $objectMissionDisplay = $this->textTools->cleanTextWithoutHtmlentities($args["object_mission_display"]);
else $objectMissionDisplay = null;
if (array_key_exists("trace", $args)) $trace = $args["trace"];
else $trace = null;
if (array_key_exists("old_value", $args)) $oldValue = $this->textTools->cleanTextWithoutHtmlentities($args["old_value"]);
else $oldValue = null;
if (array_key_exists("new_value", $args)) $newValue = $this->textTools->cleanTextWithoutHtmlentities($args["new_value"]);
else $newValue = null;
if (array_key_exists("info", $args)) $info = $args["info"];
else $info = null;
if (array_key_exists("society_group", $args)) $societyGroup = $args["society_group"];
else $societyGroup = null;
if (array_key_exists("society", $args)) $society = $args["society"];
else $society = null;
if (array_key_exists("special_author", $args)) $specialAuthor = $args["special_author"];
else $specialAuthor = null;
if (array_key_exists("object_human_resource_id", $args)) $objectHumanResourceId = $args["object_human_resource_id"];
else $objectHumanResourceId = null;
if (array_key_exists("object_human_resource_display", $args)) $objectHumanResourceDisplay = $this->textTools->cleanTextWithoutHtmlentities($args["object_human_resource_display"]);
else $objectHumanResourceDisplay = null;
// Plan.io Task #4624
if (array_key_exists("project_notebook_id", $args)) $projectNotebookId = $args["project_notebook_id"];
else $projectNotebookId = null;
if (array_key_exists("module_code", $args)) $moduleCode = $args["module_code"];
else $moduleCode = null;
if (array_key_exists("module_display", $args)) $moduleDisplay = $args["module_display"];
else $moduleDisplay = null;
// Handle special authors better than passing data in the $info field
// if (array_key_exists("info_special_author", $args)) $infoSpecialAuthor = $args["info_special_author"];
// else $infoSpecialAuthor = null;
// Switch user case
// Plan.io Task #3621
$trueAccess = null;
$falseAccess = null;
// Plan.io Task #3946
$this->api = $this->isApi();
if (array_key_exists("access", $args))
{
$access = $args['access'];
}
else
{
if ($specialAuthor !== null && in_array($specialAuthor, ["api_action", "jcaf_local", "ikea_service_order", "sms_client_response"]))
{
$logData = $this->handleSpecialCases($specialAuthor, $action);
$access = $logData['access'];
if (array_key_exists('info', $logData) && !empty($logData['info']))
{
$info = $logData['info'];
}
}
else
{
$logData = $this->handleNormalCases();
$access = $logData['access'];
$trueAccess = $logData['trueAccess'];
$falseAccess = $logData['falseAccess'];
}
}
// Plan.io Task #4327 : Handle logging for AccessClient users
// At this point $access holds a valid not null object
// However, this object can be either an Access or an AccessClient
if ($access instanceof Access)
{
// $this->ploopLog("[Logging][smartLog] access is Access");
}
else
{
if ($access instanceof AccessClient)
{
// $this->ploopLog("[Logging][smartLog] access is AccessClient");
}
}
if ($trueAccess !== null)
{
// $this->ploopLog("[Logging][smartLog] trueAccess is ".$trueAccess->displayForLog());
}
if ($falseAccess !== null)
{
// $this->ploopLog("[Logging][smartLog] falseAccess is ".$falseAccess->displayForLog());
}
$logEntityRep = $this->em->getRepository(LogEntity::class);
$log = new Log();
// $this->ploopLog("[smartLog] objectBundle = $objectBundle");
// Plan.io Task #3621 #3751 #3865 #4624
$specials = array("Ikea", "Ding", "HR", "Equipment", "ProjectManager");
if (!in_array($objectBundle, $specials))
{
$log = new Log();
// $this->ploopLog("[smartLog] objectBundle = $objectBundle => Creating a Log object");
}
else
{
switch ($objectBundle)
{
case "Ikea":
$log = new IkeaLog();
break;
case "Ding":
$log = new AdvancedNotificationLog();
break;
case "HR":
$log = new HRLog();
break;
case "Equipment":
$log = new HRLog();
break;
// Plan.io Task #4624
case "ProjectManager":
{
// $this->ploopLog("[smartLog] objectBundle = $objectBundle => Creating a ProjectManagerLog object");
$log = new ProjectManagerLog();
break;
}
default:
$log = new Log();
break;
}
}
$log->setSmartLog(1);
$log->setAction($action);
$log->setObjectId($objectId);
$log->setObjectBundle($objectBundle);
$log->setObjectEntity($objectEntity);
$log->setObjectDisplay($objectDisplay);
$log->setObjectClientId($objectClientId);
$log->setObjectClientDisplay($objectClientDisplay);
$log->setObjectMissionId($objectMissionId);
$log->setObjectMissionDisplay($objectMissionDisplay);
$log->setTrace($trace);
$log->setOldValue($oldValue);
$log->setNewValue($newValue);
$log->setInfo($info);
if ($log instanceof HRLog)
{
$log->setObjectHumanResourceId($objectHumanResourceId);
$log->setObjectHumanResourceDisplay($objectHumanResourceDisplay);
}
if ($log instanceof ProjectManagerLog)
{
$log->setNotebookId($projectNotebookId);
$log->setModuleCode($moduleCode);
$log->setModuleDisplay($moduleDisplay);
}
if ($societyGroup !== null)
{
$log->setSocietyGroupId($societyGroup->getId());
$log->setSocietyGroupInternalRef($societyGroup->getInternalRef());
$log->setSocietyGroupRef($societyGroup->getRef());
$log->setSocietyGroupName($societyGroup->getName());
}
if ($society !== null)
{
$log->setSocietyId($society->getId());
$log->setSocietyRef($society->getRef());
$log->setSocietyName($society->getName());
}
if ($access !== null)
{
$log->setAccessId($access->getId());
$log->setAccessUsername($access->getUsername());
}
if ($trueAccess !== null)
{
// Plan.io Task #4327
if ($trueAccess instanceof Access)
{
$log->setTrueAccessId($trueAccess->getId());
$log->setTrueAccessUsername($trueAccess->getUsername());
}
else
{
// Plan.io Task #4327
if ($trueAccess instanceof AccessClient)
{
$log->setTrueAccessClientId($trueAccess->getId());
$log->setTrueAccessClientUsername($trueAccess->getUsername());
}
}
}
if ($falseAccess !== null)
{
if ($falseAccess instanceof Access)
{
$log->setFalseAccessId($falseAccess->getId());
$log->setFalseAccessUsername($falseAccess->getUsername());
}
else
{
// Plan.io Task #4327
if ($falseAccess instanceof AccessClient)
{
$log->setFalseAccessClientId($falseAccess->getId());
$log->setFalseAccessClientUsername($falseAccess->getUsername());
}
}
}
// Plan.io Task #4327
if ($access instanceof AccessClient)
{
if ($access->hasRoleAdmin())
{
// Username is used for display : Do not display admin username
$log->setAccessUsername("@rekapp");
}
else
{
// Username is used for display : Use the username from the AccessClient
$log->setAccessUsername("[Client] ".$access->getUsername());
}
// Keep the accessId not null by setting the ID of the EMPTY_ACCESS
$log->setAccessId($emptyAccess->getId());
// Set the correct AccessClient ID to the correct field
$log->setAccessClientId($access->getId());
}
// Log_Entity
$logEntity = $logEntityRep->findOneByEntity($log->getObjectEntity());
if ($logEntity !== null)
{
$log->setLogEntityId($logEntity->getId());
}
// Translations
$identicalTranslations = array('Devis', 'Article', 'Note', 'Config');
if (!empty($log->getObjectEntity()))
{
$translation = $this->translator->trans($log->getObjectEntity(), array(), 'logging');
if ($translation == $log->getObjectEntity() && !in_array($translation, $identicalTranslations))
{
// Translation not found
// $this->createNotification($log->getObjectEntity());
}
$log->setObjectEntityTranslation($translation);
}
$translation = $this->translator->trans($log->getAction(), array(), 'logging');
if ($translation == $log->getAction())
{
// Translation not found
// $this->createNotification($log->getAction());
}
$log->setActionTranslation($translation);
// Plan.io Task #3946
$log->setMobileApi($this->api);
// In all cases, log to file
// Nope, not in all cases
if (!($log instanceof ProjectManagerLog))
{
$this->logToFile($log);
}
else
{
$this->logToProjectNotebookFile($log);
}
// Also log to custom object files
$this->logToClientFile($log);
$this->logToMissionFile($log);
$this->logToHumanResourceFile($log);
return $log;
}
public function handleSpecialCases($info, $action)
{
if ($info == 'api_action')
{
$info = null;
// Plan.io Task #3946
$access = $this->getCustomApiAccess();
if ($access === null)
{
$access = $this->em->getRepository(Access::class)
->findOneByUsername(Access::API_ACCESS);
}
// Plan.io Task #3946
// Old Code
// $access = $this->em->getRepository(Access::class)
// ->findOneByUsername(Access::API_ACCESS);
}
if ($info == 'jcaf_local')
{
$access = $this->em->getRepository(Access::class)
->findOneByUsername(Access::JCAF_LOCAL);
$info = null;
}
// Plan.io Task #3980
if ($info == 'sms_client_response')
{
$access = $this->em->getRepository(Access::class)
->findOneByUsername(Access::EMPTY_ACCESS);
$info = $this->translator->trans($info, array(), 'logging');
}
// Plan.io Task #3621
if ($info == 'ikea_service_order')
{
$access = $this->em->getRepository(Access::class)
->findOneByUsername(Access::IKEA_SO);
$info = null;
}
// Plan.io Task #3846
if ($action == "ikea_service_order_edit_status_forced")
{
// Plan.io Task #4040
// Desired display :
// actual.user@rekapp.fr
// If the actual user is logged in
// @rekapp | brute_force_access : [1] oanalivia
// If the user is impersonated by oanalivia, and an open_sesame user is viewing the page
// @rekapp
// If the user is impersonated by oanalivia, and a normal user is viewing the page
$originalUser = $this->getOriginalUser();
// Switch user case
if ($originalUser !== null)
{
// We have two users
$bruteForceAccess = $originalUser;
// In this case we want to display a standard value in the user field
$access = $this->em->getRepository(Access::class)
->findOneByUsername(Access::REKAPP);
$info = "brute_force_access : ".$bruteForceAccess->displayForLog();
}
else
{
// We only have one user, the real one
$bruteForceAccess = $this->getCurrentUser();
$access = $this->getCurrentUser();
$info = null;
}
// In this case we want to display a standard value in the user field
// $access = $this->em->getRepository(Access::class)
// ->findOneByUsername(Access::REKAPP);
}
return array(
'access' => $access,
'info' => $info,
);
}
public function createNotification($msg)
{
$devs = $this->em->getRepository(Access::class)->getDevs();
$origin = "Services :: Logging :: log";
$type = $this->em->getRepository(NotificationType::class)
->findOneBy(array(
'dev' => 1,
'warning' => 1,
));
if ($this->em->isOpen())
{
foreach ($devs as $dev)
{
$notification = new DingNotification();
$notification->setType($type);
$notification->setAccess($dev);
$notification->setTitle("Translation not found");
$notification->setBody($msg);
$notification->setOrigin($origin);
$this->em->persist($notification);
}
return true;
}
else
{
error_log("Translation not found : ".$msg, 1, 'd.bernard@dvlpr.fr');
}
return false;
}
public function logToFile($log)
{
// Get the log directory
// Plan.io Task #3922
// Old path : ROOT/custom_logs/global_logs
// New path : ROOT/DMS/Logs/Global/
$logPath = $this->getDMS_GlobalLogsDir();
// Construct path to file
$logFile = $this->getLogFilePath($log, $logPath, self::log_to_file_global);
// $this->ploopLog("[Logging][logToFile] Logging to ".$logFile);
$this->logColumnHeaders($logFile);
$this->logLine($logFile, $log);
return true;
}
private function logColumnHeaders($logFile)
{
// If the log file does not exist, create a first line with the column haders
if (file_exists($logFile))
return;
// Write title
error_log("\n",3,$logFile);
error_log("Date de creation",3,$logFile);
error_log(";",3,$logFile);
error_log("Id Utilisateur",3,$logFile);
error_log(";",3,$logFile);
error_log("Utilisateur",3,$logFile);
error_log(";",3,$logFile);
// Society Group
error_log("Id Groupe de sociétés",3,$logFile);
error_log(";",3,$logFile);
error_log("Référence interne groupe de sociétés",3,$logFile);
error_log(";",3,$logFile);
error_log("Référence groupe de sociétés",3,$logFile);
error_log(";",3,$logFile);
error_log("Nom groupe de sociétés",3,$logFile);
error_log(";",3,$logFile);
// Society
error_log("Id société",3,$logFile);
error_log(";",3,$logFile);
error_log("Référence société",3,$logFile);
error_log(";",3,$logFile);
error_log("Nom société",3,$logFile);
error_log(";",3,$logFile);
// Action
error_log("Action",3,$logFile);
error_log(";",3,$logFile);
error_log("Action (fr)",3,$logFile);
error_log(";",3,$logFile);
// Object
error_log("Id objet",3,$logFile);
error_log(";",3,$logFile);
error_log("Bundle objet",3,$logFile);
error_log(";",3,$logFile);
error_log("Entité objet",3,$logFile);
error_log(";",3,$logFile);
error_log("Entité objet (fr)",3,$logFile);
error_log(";",3,$logFile);
error_log("Objet",3,$logFile);
error_log(";",3,$logFile);
// Object Client
error_log("Id client",3,$logFile);
error_log(";",3,$logFile);
error_log("Client",3,$logFile);
error_log(";",3,$logFile);
// Values
error_log("Ancienne valeur",3,$logFile);
error_log(";",3,$logFile);
error_log("Nouvelle valeur",3,$logFile);
error_log(";",3,$logFile);
// Info
error_log("Info",3,$logFile);
error_log(";",3,$logFile);
// Log Entity Id
error_log("Id LogEntity",3,$logFile);
error_log(";",3,$logFile);
// Switch user
error_log("Id Utilisateur réel",3,$logFile);
error_log(";",3,$logFile);
error_log("Utilisateur réel",3,$logFile);
error_log(";",3,$logFile);
error_log("Id Utilisateur impersonifié",3,$logFile);
error_log(";",3,$logFile);
error_log("Utilisateur impersonifié",3,$logFile);
error_log(";",3,$logFile);
// Plan.io Task #3815
error_log("Trace",3,$logFile);
error_log(";",3,$logFile);
// Object Mission
// Add them at the end of the file
// to ensure backwards compatibility with older files
error_log("Id dossier",3,$logFile);
error_log(";",3,$logFile);
error_log("Dossier",3,$logFile);
error_log(";",3,$logFile);
// Object HumanResource
// Add them at the end of the file
// to ensure backwards compatibility with older files
error_log("Id ressource humaine",3,$logFile);
error_log(";",3,$logFile);
error_log("Ressource humaine",3,$logFile);
error_log(";",3,$logFile);
}
// Modified by Plan.io Task #3953
private function logLine($logFile, $log)
{
error_log("\n",3,$logFile);
error_log($this->formatForLog($log->getCreationDate()->format('Y-m-d H:i:s')),3,$logFile);
error_log(";",3,$logFile);
// Access
$value = $log->getAccessId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getAccessUsername());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Society Group
$value = $log->getSocietyGroupId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getSocietyGroupInternalRef());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getSocietyGroupRef());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getSocietyGroupName());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Society
$value = $log->getSocietyId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getSocietyRef());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getSocietyName());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Action
$value = $this->formatForLog($log->getAction());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getActionTranslation());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Object
$value = $log->getObjectId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getObjectBundle());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getObjectEntity());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getObjectEntityTranslation());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getObjectDisplay());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Object Client
$value = $log->getObjectClientId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getObjectClientDisplay());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Values
$value = $this->formatForLog($log->getOldValue());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getNewValue());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Info
$value = $this->formatForLog($log->getInfo());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Log Entity Id
$value = $log->getLogEntityId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Switch user
$value = $log->getTrueAccessId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
error_log($this->formatForLog($log->getTrueAccessUsername()),3,$logFile);
error_log(";",3,$logFile);
$value = $log->getFalseAccessId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getFalseAccessUsername());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Plan.io Task #3815
$value = $this->formatForLog($log->getTrace());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Object Mission
// Add them at the end of the file
// to ensure backwards compatibility with older files
$value = $log->getObjectMissionId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getObjectMissionDisplay());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Object HumanResource
// Add them at the end of the file
// to ensure backwards compatibility with older files
if ($log instanceof HRLog)
{
$value = $log->getObjectHumanResourceId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getObjectHumanResourceDisplay());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
}
else
{
$value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
}
}
private function formatForLog($text)
{
if (!empty($text))
{
$text = str_replace('"', "", $text);
$text = str_replace(";", "", $text);
}
$text = "\"".$text."\"";
return $text;
}
// Plan.io Task #3946
public function isApi()
{
$this->api = false;
$access = $this->security->getUser();
if (!empty($access) && ($access instanceof AccessAPI))
{
$this->api = true;
return true;
}
return false;
}
// Plan.io Task #3946
// Matches
// AccessAPI::ACCESS_API_JCAF with Access::API_ACCESS_JCAF
// AccessAPI::ACCESS_API_REKTO with Access::API_ACCESS_REKTO
public function getCustomApiAccess()
{
$access = $this->security->getUser();
if (!empty($access) && ($access instanceof AccessAPI))
{
// Access is AccessAPI (maybe not in all cases),
// but either Jcaf or Rekto, so it does not count
$this->api = false;
if ($access->getUsername() == AccessAPI::ACCESS_API_JCAF)
{
$access = $this->em->getRepository(Access::class)
->findOneByUsername(Access::API_ACCESS_JCAF);
return $access;
}
if ($access->getUsername() == AccessAPI::ACCESS_API_REKTO)
{
$access = $this->em->getRepository(Access::class)
->findOneByUsername(Access::API_ACCESS_REKTO);
return $access;
}
}
return null;
}
// Always return an object of type Access
// If the $this->security->getUser() is instanceof AccessAPI,
// the method returns the access corresponing to the AccessAPI
// Exception : JCAF and REKTO AccessAPI do not have corresponing accesses
// In this case we call the getCustomApiAccess() method,
// which identifies the two correct Accesses :
// Matches
// AccessAPI::ACCESS_API_JCAF with Access::API_ACCESS_JCAF
// AccessAPI::ACCESS_API_REKTO with Access::API_ACCESS_REKTO
public function getCurrentUser()
{
$emptyAccess = $this->em->getRepository(Access::class)->findOneByEmail(Access::EMPTY_ACCESS);
// Get the Access|AccessAPI|AccessClient object returned by the security
$access = $this->security->getUser();
if (empty($access))
{
// This occurs when the code is execuded by a Command (CRON Task for example)
// In this case there is no firewall, and thus no Access|AccessAPI
$access = $emptyAccess;
}
else
{
// The firewall has been bypassed => We have an user provider,
// either Access or AccessAPI
// Plan.io Task #4327 ... or an AccessClient :)
if (!($access instanceof Access) && !($access instanceof AccessAPI) && !($access instanceof AccessClient))
{
// This should not happen, but hey, life is weird, who knows
// Even VSCode proved to be worse than Atom ;)
$access = $emptyAccess;
}
}
// Plan.io Task #3946
if ($access instanceof AccessAPI)
{
// Almost all AccessAPI have a corresponding Access, so retrive it
$access = $access->getAccess();
}
// Plan.io Task #4327
if ($access instanceof AccessClient)
{
// Return it
return $access;
}
// Exception : AccessAPI used for Jcaf and Rekto Api
// In this case AccessAPI.access is null
if ($access === null)
{
// So now we know that we are in the special case of Jcaf or Rekto
// so try to match the correct Access
$access = $this->getCustomApiAccess();
if ($access === null)
{
// Once again this should not happen, but life is strange and impredictable
$access = $emptyAccess;
}
// Cas special Jcaf/Rekto
// Ah, by the way, if the api is the one used by Jcaf / Rekto
// we don't want to tag the log as being mobile api (reserve that title for Synertic for now)
$this->api = false;
}
// if (empty($access) || !($access instanceof Access))
// {
// $access = $this->em->getRepository(Access::class)->findOneByEmail(Access::EMPTY_ACCESS);
// }
return $access;
}
public function handleNormalCases()
{
$originalUser = $this->getOriginalUser();
// Switch user case
if ($originalUser !== null)
{
// We have two users,
// an impersonator (trueAccess)
// and an impersonated one (falseAccess)
$trueAccess = $originalUser;
$falseAccess = $this->getCurrentUser();
// In this case we want to display a standard value in the user field
// depending on the type of user (Access or AccessClient)
if ($falseAccess instanceof Access)
{
$access = $this->em->getRepository(Access::class)
->findOneByUsername(Access::REKAPP);
}
else
{
// Plan.io Task #4327
// When impersonating an AccessClient we want to have some knowledge that
// the modifications were done on the Client Platform and not the usual @rekapp user
if ($falseAccess instanceof AccessClient)
{
$access = $this->em->getRepository(Access::class)
->findOneByUsername(Access::CLIENT_PLATFORM);
}
}
}
else
{
// We only have one user, the real one
$trueAccess = null;
$falseAccess = null;
$access = $this->getCurrentUser();
}
return array(
'access' => $access,
'trueAccess' => $trueAccess,
'falseAccess' => $falseAccess,
);
}
// https://symfony.com/doc/5.4/security/impersonating_user.html
// This is also in AdminVoter
// This is also in Logger
// This is also in LogTools
public function getOriginalUser()
{
$originalUser = null;
// #3251 Fix to avoid infinity loop
$currentUser = $this->getCurrentUser();
if ($currentUser === null || $currentUser->getEmail() == Access::EMPTY_ACCESS)
{
return null;
}
$token = $this->security->getToken();
if ($token instanceof SwitchUserToken)
{
$originalUser = $token->getOriginalToken()->getUser();
}
return $originalUser;
}
public function logToClientFile($log)
{
if (empty($log->getObjectClientId()))
{
// Nothing to do here
return true;
}
// Get the log directory
// ROOT/DMS/Logs/Client/
$logPath = $this->getDMS_ClientLogsDir();
// Construct path to file
$logFile = $this->getLogFilePath($log, $logPath, self::log_to_file_client);
$this->logColumnHeaders($logFile);
$this->logLine($logFile, $log);
return true;
}
public function logToMissionFile($log)
{
if (empty($log->getObjectMissionId()))
{
// Nothing to do here
return true;
}
if ($log instanceof ProjectManagerLog)
{
// Do not log ProjectNotebookItem actions to mission
// Only log the creation / removal of the actual notebook
if ($log->getObjectEntity() == "ProjectNotebookItem")
{
return true;
}
}
// Get the log directory
// ROOT/DMS/Logs/Mission/
$logPath = $this->getDMS_MissionLogsDir();
// Construct path to file
$logFile = $this->getLogFilePath($log, $logPath, self::log_to_file_mission);
$this->logColumnHeaders($logFile);
$this->logLine($logFile, $log);
return true;
}
public function logToHumanResourceFile($log)
{
if (!($log instanceof HRLog))
{
// Nothing to do here
return true;
}
if (empty($log->getObjectHumanResourceId()))
{
// Nothing to do here
return true;
}
// Get the log directory
// ROOT/DMS/Logs/HumanResource/
$logPath = $this->getDMS_HumanResourceLogsDir();
// Construct path to file
$logFile = $this->getLogFilePath($log, $logPath, self::log_to_file_human_resource);
$this->logColumnHeaders($logFile);
$this->logLine($logFile, $log);
return true;
}
public function logToProjectNotebookFile($log)
{
if (!($log instanceof ProjectManagerLog))
{
// $this->ploopLog("[logToProjectNotebookFile] log is not ProjectManagerLog");
// Nothing to do here
return true;
}
if (empty($log->getNotebookId()))
{
// $this->ploopLog("[logToProjectNotebookFile] notebookId is empty");
// Nothing to do here
return true;
}
// $this->ploopLog("[logToProjectNotebookFile] All looks good");
// Get the log directory
// DMS/Logs/ProjectManager/Notebook/
$logPath = $this->getDMS_ProjectManagerNotebookLogsDir();
// Construct path to file
$logFile = $this->getLogFilePath($log, $logPath, self::log_to_file_project_notebook);
$this->logColumnHeadersForProjectManager($logFile);
$this->logLineForProjectManager($logFile, $log);
return true;
}
public function getLogFilePath($log, string $logPath, int $type)
{
$logFileName = null;
$logFolderName = null;
// Get the log directory
$today = new \DateTime();
// Plan.io Task #3922
// Old path : ROOT/custom_logs/global_logs
// New path : ROOT/DMS/Logs/Global/
// $logPath = $this->getDMS_GlobalLogsDir();
$originalLogPath = $logPath;
if (!file_exists($originalLogPath))
{
// Create it
$folderCreated = mkdir($originalLogPath, 0755, true);
if (!$folderCreated)
{
// This should not happen
error_log("mkdir fail for ".$originalLogPath, 1, 'oanalivia@gmail.com');
return false;
}
}
// Get the society group
$societyGroupId = $log->getSocietyGroupId();
$societyGroupRef = strtoupper($log->getSocietyGroupInternalRef());
if (!empty($societyGroupId) && !empty($societyGroupRef))
{
// If one is not empty the other is also not empty
// Craft folder name
$logFolderName = $societyGroupId."_".$societyGroupRef;
// Craft file name
if ($type == self::log_to_file_global)
{
// Global Logs
$logFileName = "app_log_".$societyGroupId."_".$societyGroupRef;
$logFileName .= "_".$today->format("Y_m").".csv";
}
elseif ($type == self::log_to_file_mission)
{
// Mission Logs
$id = $log->getObjectMissionId();
$logFileName = "mission_log_".$id.".csv";
}
elseif ($type == self::log_to_file_client)
{
// Client Logs
$id = $log->getObjectClientId();
$logFileName = "client_log_".$id.".csv";
}
elseif ($type == self::log_to_file_human_resource)
{
// Client Logs
$id = $log->getObjectHumanResourceId();
$logFileName = "human_resource_log_".$id.".csv";
}
elseif ($type == self::log_to_file_project_notebook)
{
// Client Logs
$id = $log->getNotebookId();
$logFileName = "project_notebook_log_".$id.".csv";
}
}
else
{
$logFolderName = null;
$logFileName = "app_log_".$today->format("Y_m").".csv";
}
if ($logFolderName !== null)
{
// Does the folder exist ?
$folderPath = $originalLogPath.$logFolderName;
if (!file_exists($folderPath))
{
// Create it
$folderCreated = mkdir($folderPath, 0755, true);
if ($folderCreated)
{
$logPath = $originalLogPath.$logFolderName."/";
}
else
{
// This should not happen
error_log("mkdir fail for ".$folderPath, 1, 'oanalivia@gmail.com');
$logPath = $originalLogPath;
}
}
else
{
$logPath = $originalLogPath.$logFolderName."/";
}
}
else
{
$logPath = $originalLogPath;
}
// In both cases, construct the log file path
$logFile = $logPath.$logFileName;
return $logFile;
}
private function logColumnHeadersForProjectManager($logFile)
{
// If the log file does not exist, create a first line with the column haders
if (file_exists($logFile))
return;
// Write title
error_log("\n",3,$logFile);
error_log("Date de creation",3,$logFile);
error_log(";",3,$logFile);
error_log("Id Utilisateur",3,$logFile);
error_log(";",3,$logFile);
error_log("Utilisateur",3,$logFile);
error_log(";",3,$logFile);
// Action
error_log("Action",3,$logFile);
error_log(";",3,$logFile);
error_log("Action (fr)",3,$logFile);
error_log(";",3,$logFile);
// Object
error_log("Id Notebook",3,$logFile);
error_log(";",3,$logFile);
error_log("Code Module",3,$logFile);
error_log(";",3,$logFile);
error_log("Objet Module",3,$logFile);
error_log(";",3,$logFile);
error_log("Id objet",3,$logFile);
error_log(";",3,$logFile);
error_log("Objet",3,$logFile);
error_log(";",3,$logFile);
// Values
error_log("Ancienne valeur",3,$logFile);
error_log(";",3,$logFile);
error_log("Nouvelle valeur",3,$logFile);
error_log(";",3,$logFile);
// Info
error_log("Info",3,$logFile);
error_log(";",3,$logFile);
// Switch user
error_log("Id Utilisateur réel",3,$logFile);
error_log(";",3,$logFile);
error_log("Utilisateur réel",3,$logFile);
error_log(";",3,$logFile);
error_log("Id Utilisateur impersonifié",3,$logFile);
error_log(";",3,$logFile);
error_log("Utilisateur impersonifié",3,$logFile);
error_log(";",3,$logFile);
}
private function logLineForProjectManager($logFile, $log)
{
error_log("\n",3,$logFile);
error_log($this->formatForLog($log->getCreationDate()->format('Y-m-d H:i:s')),3,$logFile);
error_log(";",3,$logFile);
// Access
$value = $log->getAccessId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getAccessUsername());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Action
$value = $this->formatForLog($log->getAction());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getActionTranslation());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Object
$value = $log->getNotebookId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $log->getModuleCode();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getModuleDisplay());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $log->getObjectId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getObjectDisplay());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Values
$value = $this->formatForLog($log->getOldValue());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getNewValue());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Info
$value = $this->formatForLog($log->getInfo());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
// Switch user
$value = $log->getTrueAccessId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
error_log($this->formatForLog($log->getTrueAccessUsername()),3,$logFile);
error_log(";",3,$logFile);
$value = $log->getFalseAccessId();
if (empty($value)) $value = 0;
error_log($value,3,$logFile);
error_log(";",3,$logFile);
$value = $this->formatForLog($log->getFalseAccessUsername());
if (empty($value)) $value = "";
error_log($value,3,$logFile);
error_log(";",3,$logFile);
}
}