Solving conflicts updating with last changes in develop branch

This commit is contained in:
Julio Cesar Laura Avendaño
2020-12-03 20:19:49 +00:00
66 changed files with 3721 additions and 1224 deletions

View File

@@ -59,7 +59,7 @@ class ResponseReader
try {
if (!extension_loaded('imap')) {
G::outRes(G::LoadTranslation("ID_EXCEPTION_LOG_INTERFAZ", ['php_imap']) . "\n");
exit;
return;
}
if (PMLicensedFeatures
::getSingleton()
@@ -145,6 +145,7 @@ class ResponseReader
$emailSetup['MESS_ACCOUNT'],
$this->decryptPassword($emailSetup)
);
Log::channel(':' . $this->channel)->debug("Open mailbox", Bootstrap::context($emailSetup));
// Read all messages into an array
$mailsIds = $mailbox->searchMailbox('UNSEEN');
@@ -153,6 +154,7 @@ class ResponseReader
foreach ($mailsIds as $key => $mailId) {
/** @var IncomingMail $mail */
$mail = $mailbox->getMail($mailId, false);
Log::channel(':' . $this->channel)->debug("Get mail", Bootstrap::context(['mailId' => $mailId]));
if (!empty($mail->textPlain)) {
preg_match("/{(.*)}/", $mail->textPlain, $matches);
if ($matches) {

View File

@@ -17,6 +17,7 @@ use Applications;
use AppNotes;
use AppNotesPeer;
use AppSolr;
use AppTimeoutActionExecuted;
use BasePeer;
use Bootstrap;
use BpmnEngineServicesSearchIndex;
@@ -25,12 +26,14 @@ use CasesPeer;
use Configurations;
use CreoleTypes;
use Criteria;
use DateTime;
use DBAdapter;
use EntitySolrRequestData;
use Exception;
use G;
use Groups;
use GroupUserPeer;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use InputDocument;
use InvalidIndexSearchTextException;
@@ -44,8 +47,11 @@ use ProcessMaker\Exception\UploadException;
use ProcessMaker\Exception\CaseNoteUploadFile;
use ProcessMaker\Model\Application as ModelApplication;
use ProcessMaker\Model\AppNotes as Notes;
use ProcessMaker\Model\AppTimeoutAction;
use ProcessMaker\Model\Delegation;
use ProcessMaker\Model\Documents;
use ProcessMaker\Model\ListUnassigned;
use ProcessMaker\Model\Triggers;
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Services\OAuth2\Server;
use ProcessMaker\Util\DateTime as UtilDateTime;
@@ -4107,4 +4113,171 @@ class Cases
return true;
}
/**
* Get the cases related to the self services timeout that needs to execute the trigger related
*
* @return array
* @throws Exception
*/
public static function executeSelfServiceTimeout()
{
try {
$casesSelfService = ListUnassigned::selfServiceTimeout();
$casesExecuted = [];
foreach ($casesSelfService as $row) {
$appUid = $row["APP_UID"];
$appNumber = $row["APP_NUMBER"];
$delIndex = $row["DEL_INDEX"];
$delegateDate = $row["DEL_DELEGATE_DATE"];
$proUid = $row["PRO_UID"];
$taskUid = $row["TAS_UID"];
$taskSelfServiceTime = intval($row["TAS_SELFSERVICE_TIME"]);
$taskSelfServiceTimeUnit = $row["TAS_SELFSERVICE_TIME_UNIT"];
$triggerUid = $row["TAS_SELFSERVICE_TRIGGER_UID"];
/*----------------------------------********---------------------------------*/
$typeOfExecution = $row["TAS_SELFSERVICE_EXECUTION"];
$flagExecuteOnce = true;
// This option will be executed just once, can check if was executed before
if ($typeOfExecution == 'ONCE') {
$appTimeout = new AppTimeoutAction();
$appTimeout->setCaseUid($appUid);
$appTimeout->setIndex($delIndex);
$caseExecuted = $appTimeout->cases();
$flagExecuteOnce = !empty($caseExecuted) ? false : true;
}
/*----------------------------------********---------------------------------*/
// Add the time in the corresponding unit to the delegation date
$delegateDate = calculateDate($delegateDate, $taskSelfServiceTimeUnit, $taskSelfServiceTime);
// Define the current time
$datetime = new DateTime('now');
$currentDate = $datetime->format('Y-m-d H:i:s');
// Check if the triggers to be executed
if ($currentDate >= $delegateDate && $flagExecuteOnce) {
// Review if the session process is defined
$sessProcess = null;
$sessProcessSw = false;
if (isset($_SESSION["PROCESS"])) {
$sessProcess = $_SESSION["PROCESS"];
$sessProcessSw = true;
}
// Load case data
$case = new ClassesCases();
$appFields = $case->loadCase($appUid);
$appFields["APP_DATA"]["APPLICATION"] = $appUid;
// Set the process defined in the case related
$_SESSION["PROCESS"] = $appFields["PRO_UID"];
// Get the trigger related and execute
$triggersList = [];
if (!empty($triggerUid)) {
$trigger = new Triggers();
$trigger->setTrigger($triggerUid);
$triggersList = $trigger->triggers();
}
// If the trigger exist, let's to execute
if (!empty($triggersList)) {
// Execute the trigger defined in the self service timeout
$fieldsCase['APP_DATA'] = $case->executeTriggerFromList(
$triggersList,
$appFields['APP_DATA'],
'SELF_SERVICE_TIMEOUT',
'',
'',
'',
false
);
// Update the case
$case->updateCase($appUid, $fieldsCase);
/*----------------------------------********---------------------------------*/
if ($typeOfExecution == 'ONCE') {
// Saving the case`s data if the 'Execution' is set in ONCE.
$appTimeoutActionExecuted = new AppTimeoutActionExecuted();
$dataSelf = [];
$dataSelf["APP_UID"] = $appUid;
$dataSelf["DEL_INDEX"] = $delIndex;
$dataSelf["EXECUTION_DATE"] = time();
$appTimeoutActionExecuted->create($dataSelf);
}
/*----------------------------------********---------------------------------*/
array_push($casesExecuted, $appNumber); // Register the cases executed
// Logging this action
$context = [
'appUid' => $appUid,
'appNumber' => $appNumber,
'triUid' => $triggerUid,
'proUid' => $proUid,
'tasUid' => $taskUid,
'selfServiceTime' => $taskSelfServiceTime,
'selfServiceTimeUnit' => $taskSelfServiceTimeUnit,
];
Log::channel(':TriggerExecution')->info('Timeout trigger execution', Bootstrap::context($context));
}
unset($_SESSION["PROCESS"]);
if ($sessProcessSw) {
$_SESSION["PROCESS"] = $sessProcess;
}
}
}
return $casesExecuted;
} catch (Exception $e) {
throw $e;
}
}
/**
* Get DynaForms Uids assigned as steps in the related process by application Uid
*
* @param string $appUid
* @param int $sourceTask
* @param string $dynUid
* @param string $caseStatus
* @return array
*/
public static function dynaFormsByApplication($appUid, $sourceTask = 0, $dynUid = '', $caseStatus = '')
{
// Select distinct DYN_UID
$query = ModelApplication::query()->select('STEP.STEP_UID_OBJ AS DYN_UID')->distinct();
// Join with STEP table
$query->join('STEP', function ($join) {
$join->on('APPLICATION.PRO_UID', '=', 'STEP.PRO_UID');
$join->on('STEP.STEP_TYPE_OBJ', '=', DB::raw("'DYNAFORM'"));
});
// Filter by application Uid
$query->where('APPLICATION.APP_UID', '=', $appUid);
// Filter by source task
if ($caseStatus != 'COMPLETED' && $sourceTask != '' && (int)$sourceTask != 0) {
$query->where('STEP.TAS_UID', '=', $sourceTask);
}
// Filter by DynaForm Uid
if ($dynUid != '' && $dynUid != '0') {
$query->where('STEP.STEP_UID_OBJ', '=', $dynUid);
}
// Get results
$dynaForms = [];
$items = $query->get();
$items->each(function ($item) use (&$dynaForms) {
$dynaForms[] = $item->DYN_UID;
});
// Return results
return $dynaForms;
}
}

View File

@@ -42,84 +42,94 @@ class FilesManager
/**
* Return the Process Files Manager Path
*
* @param string $sProcessUID {@min 32} {@max 32}
* @param string $processUid
* @param string $path
* @param boolean $getContent
*
* return array
* @return array
* @throws Exception
*
* @access public
*/
public function getProcessFilesManagerPath($sProcessUID, $path, $getContent = true)
public function getProcessFilesManagerPath($processUid, $path, $getContent = true)
{
try {
$checkPath = substr($path, -1);
if ($checkPath == '/') {
$path = substr($path, 0, -1);
}
$sMainDirectory = current(explode("/", $path));
$mainDirectory = current(explode('/', $path));
if (strstr($path,'/')) {
$sSubDirectory = substr($path, strpos($path, "/")+1). PATH_SEP ;
$subDirectory = substr($path, strpos($path, '/') + 1) . PATH_SEP;
} else {
$sSubDirectory = '';
$subDirectory = '';
}
switch ($sMainDirectory) {
switch ($mainDirectory) {
case 'templates':
$sDirectory = PATH_DATA_MAILTEMPLATES . $sProcessUID . PATH_SEP . $sSubDirectory;
$currentDirectory = PATH_DATA_MAILTEMPLATES . $processUid . PATH_SEP . $subDirectory;
break;
case 'public':
$sDirectory = PATH_DATA_PUBLIC . $sProcessUID . PATH_SEP . $sSubDirectory;
$currentDirectory = PATH_DATA_PUBLIC . $processUid . PATH_SEP . $subDirectory;
break;
default:
throw new \Exception(\G::LoadTranslation("ID_INVALID_VALUE_FOR", array('path')));
throw new Exception(G::LoadTranslation('ID_INVALID_VALUE_FOR', ['path']));
break;
}
\G::verifyPath($sDirectory, true);
$aTheFiles = array();
$aFiles = array();
$oDirectory = dir($sDirectory);
while ($sObject = $oDirectory->read()) {
if (($sObject !== '.') && ($sObject !== '..')) {
$sPath = $sDirectory . $sObject;
if (is_dir($sPath)) {
$aTheFiles[] = array('prf_name' => $sObject,
'prf_type' => "folder",
'prf_path' => $sMainDirectory);
G::verifyPath($currentDirectory, true);
$filesToList = [];
$files = [];
$directory = dir($currentDirectory);
while ($object = $directory->read()) {
if (($object !== '.') && ($object !== '..')) {
// Skip files related to web entries
if ($object === 'wsClient.php' || WebEntry::isWebEntry($processUid, $object)) {
continue;
}
$path = $currentDirectory . $object;
if (is_dir($path)) {
$filesToList[] = [
'prf_name' => $object,
'prf_type' => 'folder',
'prf_path' => $mainDirectory
];
} else {
$aAux = pathinfo($sPath);
$aAux['extension'] = (isset($aAux['extension'])?$aAux['extension']:'');
$aFiles[] = array('FILE' => $sObject, 'EXT' => $aAux['extension'] );
$aux = pathinfo($path);
$aux['extension'] = (isset($aux['extension']) ? $aux['extension'] : '');
$files[] = ['FILE' => $object, 'EXT' => $aux['extension']];
}
}
}
foreach ($aFiles as $aFile) {
$arrayFileUid = $this->getFileManagerUid($sDirectory.$aFile['FILE'], $aFile['FILE']);
$fcontent = "";
foreach ($files as $file) {
$arrayFileUid = $this->getFileManagerUid($currentDirectory.$file['FILE'], $file['FILE']);
$content = '';
if ($getContent === true) {
$fcontent = file_get_contents($sDirectory . $aFile['FILE']);
$content = file_get_contents($currentDirectory . $file['FILE']);
}
$fileUid = isset($arrayFileUid["PRF_UID"]) ? $arrayFileUid["PRF_UID"] : '';
$derivationScreen = isset($arrayFileUid["DERIVATION_SCREEN_TPL"]) ? true : false;
$fileUid = isset($arrayFileUid['PRF_UID']) ? $arrayFileUid['PRF_UID'] : '';
$derivationScreen = isset($arrayFileUid['DERIVATION_SCREEN_TPL']) ? true : false;
if ($fileUid != null) {
$oProcessFiles = \ProcessFilesPeer::retrieveByPK($fileUid);
$editable = $oProcessFiles->getPrfEditable();
$processFiles = ProcessFilesPeer::retrieveByPK($fileUid);
$editable = $processFiles->getPrfEditable();
if ($editable == '1') {
$editable = 'true';
} else {
$editable = 'false';
}
$aTheFiles[] = array( 'prf_uid' => $oProcessFiles->getPrfUid(),
'prf_filename' => $aFile['FILE'],
'usr_uid' => $oProcessFiles->getUsrUid(),
'prf_update_usr_uid' => $oProcessFiles->getPrfUpdateUsrUid(),
'prf_path' => $sMainDirectory. PATH_SEP .$sSubDirectory,
'prf_type' => $oProcessFiles->getPrfType(),
'prf_editable' => $editable,
'prf_create_date' => $oProcessFiles->getPrfCreateDate(),
'prf_update_date' => $oProcessFiles->getPrfUpdateDate(),
'prf_content' => $fcontent,
'prf_derivation_screen' => $derivationScreen);
$filesToList[] = [
'prf_uid' => $processFiles->getPrfUid(),
'prf_filename' => $file['FILE'],
'usr_uid' => $processFiles->getUsrUid(),
'prf_update_usr_uid' => $processFiles->getPrfUpdateUsrUid(),
'prf_path' => $mainDirectory. PATH_SEP .$subDirectory,
'prf_type' => $processFiles->getPrfType(),
'prf_editable' => $editable,
'prf_create_date' => $processFiles->getPrfCreateDate(),
'prf_update_date' => $processFiles->getPrfUpdateDate(),
'prf_content' => $content,
'prf_derivation_screen' => $derivationScreen
];
} else {
$explodeExt = explode(".", $aFile['FILE']);
$explodeExt = explode('.', $file['FILE']);
$extension = end($explodeExt);
if ($extension == 'docx' || $extension == 'doc' || $extension == 'html' || $extension == 'php' || $extension == 'jsp'
|| $extension == 'xlsx' || $extension == 'xls' || $extension == 'js' || $extension == 'css' || $extension == 'txt') {
@@ -127,21 +137,23 @@ class FilesManager
} else {
$editable = 'false';
}
$aTheFiles[] = array('prf_uid' => '',
'prf_filename' => $aFile['FILE'],
'usr_uid' => '',
'prf_update_usr_uid' => '',
'prf_path' => $sMainDirectory. PATH_SEP .$sSubDirectory,
'prf_type' => 'file',
'prf_editable' => $editable,
'prf_create_date' => '',
'prf_update_date' => '',
'prf_content' => $fcontent,
'prf_derivation_screen' => false);
$filesToList[] = [
'prf_uid' => '',
'prf_filename' => $file['FILE'],
'usr_uid' => '',
'prf_update_usr_uid' => '',
'prf_path' => $mainDirectory. PATH_SEP .$subDirectory,
'prf_type' => 'file',
'prf_editable' => $editable,
'prf_create_date' => '',
'prf_update_date' => '',
'prf_content' => $content,
'prf_derivation_screen' => false
];
}
}
return $aTheFiles;
} catch (\Exception $e) {
return $filesToList;
} catch (Exception $e) {
throw $e;
}
}

View File

@@ -6,6 +6,7 @@ use G;
use Criteria;
use PMLicensedFeatures;
use ProcessMaker\Model\Delegation;
use ProcessMaker\Model\User;
use UsersPeer;
/**
@@ -213,30 +214,51 @@ class Lists
$result = $list->loadList($userUid, $filters);
if (!empty($result)) {
foreach ($result as &$value) {
// For backward compatibility with "light" endpoints, we need to cast to string
$value['APP_NUMBER'] = (string)$value['APP_NUMBER'];
$value['DEL_INDEX'] = (string)$value['DEL_INDEX'];
if (isset($value['DEL_PREVIOUS_USR_UID'])) {
$value['PREVIOUS_USR_UID'] = $value['DEL_PREVIOUS_USR_UID'];
$value['PREVIOUS_USR_USERNAME'] = $value['DEL_PREVIOUS_USR_USERNAME'];
$value['PREVIOUS_USR_FIRSTNAME'] = $value['DEL_PREVIOUS_USR_FIRSTNAME'];
$value['PREVIOUS_USR_LASTNAME'] = $value['DEL_PREVIOUS_USR_LASTNAME'];
} elseif (!empty($value["USR_ID"])) {
$user = User::where("USR_ID", $value["USR_ID"])->first();
$value["PREVIOUS_USR_UID"] = $value["DEL_PREVIOUS_USR_UID"] = $user->USR_UID;
$value["PREVIOUS_USR_USERNAME"] = $value["DEL_PREVIOUS_USR_USERNAME"] = $user->USR_USERNAME;
$value["PREVIOUS_USR_FIRSTNAME"] = $value["DEL_PREVIOUS_USR_FIRSTNAME"] = $user->USR_FIRSTNAME;
$value["PREVIOUS_USR_LASTNAME"] = $value["DEL_PREVIOUS_USR_LASTNAME"] = $user->USR_LASTNAME;
}
if (isset($value['DEL_DUE_DATE'])) {
$value['DEL_TASK_DUE_DATE'] = $value['DEL_DUE_DATE'];
}
if (isset($value['APP_PAUSED_DATE'])) {
$value['APP_UPDATE_DATE'] = $value['APP_PAUSED_DATE'];
}
if (isset($value['DEL_CURRENT_USR_USERNAME'])) {
$value['USR_USERNAME'] = $value['DEL_CURRENT_USR_USERNAME'];
$value['USR_FIRSTNAME'] = $value['DEL_CURRENT_USR_FIRSTNAME'];
$value['USR_LASTNAME'] = $value['DEL_CURRENT_USR_LASTNAME'];
$value['APP_UPDATE_DATE'] = $value['DEL_DELEGATE_DATE'];
}
if (isset($value['DEL_CURRENT_TAS_TITLE']) && $value['DEL_CURRENT_TAS_TITLE'] != '') {
$value['APP_TAS_TITLE'] = $value['DEL_CURRENT_TAS_TITLE'];
} elseif (!empty($value["TAS_TITLE"]) && empty($value["APP_TAS_TITLE"])) {
$value["APP_TAS_TITLE"] = $value["TAS_TITLE"];
}
if (isset($value['APP_STATUS'])) {
$value['APP_STATUS_LABEL'] = G::LoadTranslation("ID_{$value['APP_STATUS']}");
}
//$value = array_change_key_case($value, CASE_LOWER);
if (!empty($value["PRO_TITLE"]) && empty($value["APP_PRO_TITLE"])) {
$value["APP_PRO_TITLE"] = $value["PRO_TITLE"];
}
}
}
$response = array();

View File

@@ -30,12 +30,12 @@ class TaskSchedulerBM
"category" => "case_actions",
"file" => "workflow/engine/bin/cron.php",
"filew" => "workflow\\engine\bin\cron.php",
"startingTime" => "0:00",
"endingTime" => "0:30",
"startingTime" => null,
"endingTime" => null,
"timezone" => "default",
"everyOn" => "1",
"interval" => "week",
"expression" => "0 */1 * * 0,1,2,3,4,5,6",
"expression" => "0 0 * * 0,1,2,3,4,5,6",
"description" => 'ID_TASK_SCHEDULER_CALCULATE_ELAPSED_DESC'
],
[
@@ -60,12 +60,12 @@ class TaskSchedulerBM
"category" => "case_actions",
"file" => "workflow/engine/bin/cron.php",
"filew" => "workflow\\engine\bin\cron.php",
"startingTime" => "0:00",
"endingTime" => "0:30",
"startingTime" => null,
"endingTime" => null,
"timezone" => "default",
"everyOn" => "1",
"interval" => "week",
"expression" => "0 */1 * * 0,1,2,3,4,5,6",
"expression" => "0 0 * * 0,1,2,3,4,5,6",
"description" => 'ID_TASK_SCHEDULER_CLEAN_SELF_DESC'
],
[
@@ -83,6 +83,21 @@ class TaskSchedulerBM
"expression" => "*/1 * * * 0,1,2,3,4,5,6",
"description" => "ID_TIMER_EVENT_DESC"
],
[
"title" => "ID_CLEAN_WEBENTRIES",
"enable" => "0",
"service" => "",
"category" => "case_actions",
"file" => "workflow/engine/bin/webentriescron.php",
"filew" => "workflow\\engine\bin\\webentriescron.php",
"startingTime" => null,
"endingTime" => null,
"timezone" => null,
"everyOn" => "1",
"interval" => "week",
"expression" => "0 20 * * 5",
"description" => "ID_CLEAN_WEBENTRIES_DESC"
],
[
"title" => "ID_TASK_SCHEDULER_CASE_EMAILS",
"enable" => "1",
@@ -183,12 +198,12 @@ class TaskSchedulerBM
"category" => "processmaker_sync",
"file" => "workflow/engine/bin/ldapcron.php",
"filew" => "workflow\\engine\bin\ldapcron.php",
"startingTime" => "0:00",
"endingTime" => "0:30",
"startingTime" => null,
"endingTime" => null,
"timezone" => "default",
"everyOn" => "1",
"interval" => "week",
"expression" => "0 */1 * * 0,1,2,3,4,5,6",
"expression" => "0 0 * * 0,1,2,3,4,5,6",
"description" => "ID_TASK_SCHEDULER_LDAP"
],
[
@@ -198,12 +213,12 @@ class TaskSchedulerBM
"category" => "plugins",
"file" => "workflow/engine/bin/cron.php",
"filew" => "workflow\\engine\bin\cron.php",
"startingTime" => "0:00",
"endingTime" => "0:30",
"startingTime" => null,
"endingTime" => null,
"timezone" => "default",
"everyOn" => "1",
"interval" => "week",
"expression" => "0 */1 * * 0,1,2,3,4,5,6",
"expression" => "0 0 * * 0,1,2,3,4,5,6",
"description" => "ID_TASK_SCHEDULER_PM_PLUGINS_DESC"
]
/*----------------------------------********---------------------------------*/

View File

@@ -1,8 +1,12 @@
<?php
namespace ProcessMaker\BusinessModel;
use AppSequence;
use Cases;
use Criteria;
use Illuminate\Support\Facades\DB;
use ProcessMaker\Core\System;
use ProcessMaker\Model\Application;
use ResultSet;
use WebEntryPeer;
@@ -1125,5 +1129,92 @@ class WebEntry
}
return $message;
}
}
/**
* Swap temporary web entry application number to a normal application number
*
* @param string $appUid
* @return int
*/
public function swapTemporaryAppNumber($appUid)
{
// Get the application
$application = Application::query()->select(['APP_NUMBER'])->where('APP_UID', '=', $appUid)->first()->toArray();
// If application exists, swap the number
if (!empty($application)) {
// Get a normal sequence number
$appSequence = new AppSequence();
$appNumber = $appSequence->sequenceNumber(AppSequence::APP_TYPE_NORMAL);
// Update case with the new application number
$cases = new Cases();
$casesData = $cases->loadCase($appUid);
$casesData['APP_NUMBER'] = $casesData['APP_DATA']['APP_NUMBER'] = $appNumber;
$cases->updateCase($appUid, $casesData);
// Build the query to update related tables and fields
$query = "UPDATE `APPLICATION` SET `APP_TITLE` = '#{$appNumber}' WHERE `APP_UID` = '{$appUid}';";
$query .= "UPDATE `APP_DATA_CHANGE_LOG` SET `APP_NUMBER` = {$appNumber} WHERE `APP_NUMBER` = {$application['APP_NUMBER']};";
$query .= "UPDATE `APP_DELEGATION` SET `APP_NUMBER` = {$appNumber} WHERE `APP_UID` = '{$appUid}';";
$query .= "UPDATE `LIST_INBOX` SET `APP_NUMBER` = {$appNumber}, `APP_TITLE` = '#{$appNumber}' WHERE `APP_UID` = '{$appUid}';";
$query .= "UPDATE `LIST_PARTICIPATED_HISTORY` SET `APP_NUMBER` = {$appNumber}, `APP_TITLE` = '#{$appNumber}' WHERE `APP_UID` = '{$appUid}';";
$query .= "UPDATE `LIST_PARTICIPATED_LAST` SET `APP_NUMBER` = {$appNumber}, `APP_TITLE` = '#{$appNumber}' WHERE `APP_UID` = '{$appUid}';";
// Execute the query
DB::connection('workflow')->unprepared($query);
// Return new application number
return $appNumber;
}
}
/**
* Convert Web Entries v1.0 to v2.0
*/
public static function convertFromV1ToV2()
{
// Build query
$query = "UPDATE
`WEB_ENTRY`
LEFT JOIN
`BPMN_PROCESS`
ON
(`WEB_ENTRY`.`PRO_UID` = `BPMN_PROCESS`.`PRJ_UID`)
SET
`WEB_ENTRY`.`DYN_UID` = '', `WEB_ENTRY`.`WE_TYPE` = 'MULTIPLE'
WHERE
`WE_TYPE` = 'SINGLE' AND `WE_AUTHENTICATION` = 'ANONYMOUS' AND
`WE_CALLBACK` = 'PROCESSMAKER' AND `BPMN_PROCESS`.`PRJ_UID` IS NOT NULL";
// Execute query
DB::connection('workflow')->statement($query);
}
/**
* Delete web entries created one week ago or more
*/
public static function deleteOldWebEntries()
{
// Define some values for PM tables classes
if (!defined('PATH_WORKSPACE')) {
define('PATH_WORKSPACE', PATH_DB . config('system.workspace') . PATH_SEP);
}
set_include_path(get_include_path() . PATH_SEPARATOR . PATH_WORKSPACE);
// Calculate date, one week ago from today
$date = now()->subWeek()->format('Y-m-d H:i:s');
// Build query
$query = "SELECT `APP_UID` FROM `APPLICATION` WHERE `APP_NUMBER` < 0 AND `APP_CREATE_DATE` < '{$date}'";
// Execute query
$cases = DB::connection('workflow')->select($query);
// Delete cases, one by one with all related records
$casesInstance = new Cases();
foreach ($cases as $case) {
$casesInstance->removeCase($case->APP_UID);
}
}
}

View File

@@ -1,6 +1,6 @@
<?php
namespace ProcessMaker\AuditLog;
namespace ProcessMaker\Log;
use Bootstrap;
use Configurations;

View File

@@ -0,0 +1,103 @@
<?php
namespace ProcessMaker\Model;
use Illuminate\Database\Eloquent\Model;
class AppTimeoutAction extends Model
{
protected $table = 'APP_TIMEOUT_ACTION_EXECUTED';
// We do not have create/update timestamps for this table
public $timestamps = false;
// Filter by a specific case using case number
private $caseUid = '';
// Filter by a specific index
private $index = 0;
/**
* Set Case Uid
*
* @param string $caseUid
*/
public function setCaseUid($caseUid)
{
$this->caseUid = $caseUid;
}
/**
* Get Case Uid
*
* @return string
*/
public function getCaseUid()
{
return $this->caseUid;
}
/**
* Set index
*
* @param int $index
*/
public function setIndex($index)
{
$this->index = $index;
}
/**
* Get index
*
* @return int
*/
public function getIndex()
{
return $this->index;
}
/**
* Scope a query to get specific case uid
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $appUid
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeCase($query, $appUid)
{
return $query->where('APP_UID', $appUid);
}
/**
* Scope a query to get index
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param int $index
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeIndex($query, $index)
{
return $query->where('DEL_INDEX', $index);
}
/**
* Get the records related to the case and index if it was defined
*
* @return array
*/
public function cases()
{
$query = AppTimeoutAction::query()->select();
// Specific case uid
if (!empty($this->getCaseUid())) {
$query->case($this->getCaseUid());
}
// Specific index
if (!empty($this->getIndex())) {
$query->index($this->getIndex());
}
$results = $query->get()->toArray();
return $results;
}
}

View File

@@ -35,6 +35,19 @@ class Application extends Model
return $this->belongsTo(User::class, 'APP_INIT_USER', 'USR_UID');
}
/**
* Scope for query to get the positive cases
*
* @param \Illuminate\Database\Eloquent\Builder $query
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopePositivesCases($query)
{
$result = $query->where('APP_NUMBER', '>', 0);
return $result;
}
/**
* Scope for query to get the application by APP_UID.
*
@@ -49,6 +62,20 @@ class Application extends Model
return $result;
}
/**
* Scope for query to get the application by status Id
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param integer $status
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeStatusId($query, int $status)
{
$result = $query->where('APP_STATUS_ID', '=', $status);
return $result;
}
/**
* Scope for query to get the applications by PRO_UID.
*
@@ -76,6 +103,7 @@ class Application extends Model
$query = Application::query()
->select()
->proUid($proUid)
->positivesCases()
->orderBy('APP_NUMBER', 'ASC');
return $query->get();
}
@@ -118,4 +146,24 @@ class Application extends Model
return $properties;
}
/**
* Get Applications by PRO_UID, ordered by APP_NUMBER.
*
* @param string $proUid
* @param int $status
*
* @return object
* @see ReportTables->populateTable()
*/
public static function getCountByProUid(string $proUid, $status = 2)
{
$query = Application::query()
->select()
->proUid($proUid)
->statusId($status)
->positivesCases();
return $query->get()->count();
}
}

View File

@@ -13,4 +13,20 @@ class BpmnProject extends Model
// We do not have create/update timestamps for this table
public $timestamps = false;
/**
* Check is the Process is BPMN.
*
* @param string $proUid
*
* @return int 1 if is BPMN process or 0 if a Normal process
*/
public static function isBpmnProcess(string $proUid)
{
$query = BpmnProject::query()
->select()
->where('PRJ_UID', '=', $proUid);
$result = $query->get()->values()->toArray();
return empty($result) ? 0 : 1;
}
}

View File

@@ -46,8 +46,9 @@ class ListUnassigned extends Model
/**
* Scope a query to only include specific tasks
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $tasks
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $tasks
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeTasksIn($query, array $tasks)
@@ -58,8 +59,8 @@ class ListUnassigned extends Model
/**
* Scope a query to only include a specific case
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param integer $appNumber
* @param \Illuminate\Database\Eloquent\Builder $query
* @param integer $appNumber
*
* @return \Illuminate\Database\Eloquent\Builder
*/
@@ -71,8 +72,8 @@ class ListUnassigned extends Model
/**
* Scope a query to only include a specific index
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param integer $index
* @param \Illuminate\Database\Eloquent\Builder $query
* @param integer $index
*
* @return \Illuminate\Database\Eloquent\Builder
*/
@@ -84,8 +85,8 @@ class ListUnassigned extends Model
/**
* Scope a query to only include a specific task
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param integer $task
* @param \Illuminate\Database\Eloquent\Builder $query
* @param integer $task
*
* @return \Illuminate\Database\Eloquent\Builder
*/
@@ -100,7 +101,7 @@ class ListUnassigned extends Model
* @param string $userUid
* @param array $filters
*
* @return array
* @return int
*/
public static function doCount($userUid, $filters = [])
{
@@ -125,4 +126,21 @@ class ListUnassigned extends Model
return $result;
}
/**
* Get the unassigned cases related to the self service timeout
*
* @return array
*/
public static function selfServiceTimeout()
{
$query = ListUnassigned::query()->select();
$query->join('TASK', function ($join) {
$join->on('LIST_UNASSIGNED.TAS_ID', '=', 'TASK.TAS_ID')
->where('TASK.TAS_SELFSERVICE_TIMEOUT', '=', 1);
});
$results = $query->get()->toArray();
return $results;
}
}

View File

@@ -2,8 +2,10 @@
namespace ProcessMaker\Model;
use Configurations;
use Exception;
use G;
use Illuminate\Database\Eloquent\Model;
use RbacUsers;
use RBAC;
/**
@@ -20,22 +22,164 @@ class Process extends Model
// Our custom timestamp columns
const CREATED_AT = 'PRO_CREATE_DATE';
const UPDATED_AT = 'PRO_UPDATE_DATE';
// Columns to see in the process list
public $listColumns = [
'PRO_UID',
'PRO_TITLE',
'PRO_DESCRIPTION',
'PRO_PARENT',
'PRO_STATUS',
'PRO_TYPE',
'PRO_CATEGORY',
'PRO_UPDATE_DATE',
'PRO_CREATE_DATE',
'PRO_CREATE_USER',
'PRO_DEBUG',
'PRO_TYPE_PROCESS',
'USR_UID',
'USR_USERNAME',
'USR_FIRSTNAME',
'USR_LASTNAME',
'CATEGORY_UID',
'CATEGORY_NAME'
];
/**
* Get the columns related to the process list
* @return array
*/
public function getListColumns()
{
return $this->listColumns;
}
/**
* Returns the task related to the process belongs to
*/
public function tasks()
{
return $this->belongsTo(Task::class, 'PRO_ID', 'PRO_ID');
}
/**
* Returns the user creator belongs to
*/
public function creator()
{
return $this->belongsTo(User::class, 'PRO_CREATE_USER', 'USR_UID');
}
/**
* Returns the category related to the process belongs to
*/
public function category()
{
return $this->belongsTo(ProcessCategory::class, 'PRO_CATEGORY', 'CATEGORY_UID');
}
/**
* Scope a query to specific process
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $proUid
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeProcess($query, $proUid)
{
return $query->where('PRO_UID', '=', $proUid);
}
/**
* Scope a query to specific title
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $title
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeTitle($query, $title)
{
return $query->where('PRO_TITLE', 'LIKE', "%{$title}%");
}
/**
* Scope a query to exclude a specific status
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $status
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeNoStatus($query, $status = 'DISABLED')
{
return $query->where('PRO_STATUS', '!=', $status);
}
/**
* Scope a query to include subprocess
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeSubProcess($query)
{
return $query->where('PRO_SUBPROCESS', '=', 1);
}
/**
* Scope a query to include a specific process category
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $category
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeCategory($query, $category)
{
return $query->where('PROCESS.PRO_CATEGORY', $category);
}
/**
* Scope a query to include the user owner or public process
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $userUid
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopePerUser($query, string $userUid)
{
$query->where(function ($query) use ($userUid) {
$query->orWhere('PRO_CREATE_USER', $userUid);
$query->orWhere('PRO_TYPE_PROCESS', 'PUBLIC');
});
return $query;
}
/**
* Scope a query to include the process related to the specific user
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeJoinUsers($query)
{
$query->join('USERS', function ($join) {
$join->on('PROCESS.PRO_CREATE_USER', '=', 'USERS.USR_UID');
});
return $query;
}
/**
* Scope a query to join with categories
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeJoinCategory($query)
{
$query->leftJoin('PROCESS_CATEGORY', function ($join) {
$join->on('PROCESS.PRO_CATEGORY', '=', 'PROCESS_CATEGORY.CATEGORY_UID');
});
return $query;
}
/**
* Obtains the process list for an specific user and/or for the specific category
*
@@ -82,12 +226,168 @@ class Process extends Model
* @param array $privateProcesses
* @return void
*/
public static function convertPrivateProcessesToPublic($privateProcesses)
public static function convertPrivateProcessesToPublicAndUpdateUser($privateProcesses, $userUid)
{
$admin = RBAC::ADMIN_USER_UID;
$processes = array_column($privateProcesses, 'PRO_ID');
Process::whereIn('PRO_ID', $processes)
->update(['PRO_TYPE_PROCESS' => 'PUBLIC', 'PRO_CREATE_USER' => $admin]);
->update(['PRO_TYPE_PROCESS' => 'PUBLIC']);
Process::where('PRO_CREATE_USER', $userUid)
->update(['PRO_CREATE_USER' => $admin]);
}
/**
* Get the process list applying some extra filters
*
* @param string $catUid
* @param string $proUid
* @param string $title
* @param string $userUid
* @param int $start
* @param int $limit
* @param string $dir
* @param string $sort
* @param boolean $counterByProcess
* @param boolean $subProcess
*
* @return array
* @throw Exception
*/
public static function getProcessesFilter(
$catUid = null,
$proUid = null,
$title = null,
$userUid = null,
$start = 0,
$limit = 25,
$dir = 'ASC',
$sort = 'PRO_CREATE_DATE',
$counterByProcess = true,
$subProcess = false
) {
$process = new Process();
$rows = $process->getListColumns();
if (!in_array($sort, $rows)) {
throw new Exception('The column ' . $sort . ' does not exist');
}
// Select rows
$query = Process::query()->select($rows)->noStatus();
// Join with users
$query->joinUsers();
// Join with category
$query->joinCategory();
// Check if the owner is the user logged or if the process is PUBLIC
if (!empty($userUid)) {
//Only process PRO_TYPE_PROCESS = "PUBLIC" or related user owner
$query->perUser($userUid);
}
// Check if we can list only the sub-process
if ($subProcess) {
$query->subProcess();
}
// Specific process
if ($proUid) {
$query->process($proUid);
}
// Specific process title
if ($title) {
$query->title($title);
}
// Search a specific category
if (!empty($catUid)) {
if ($catUid == 'NONE') {
// Processes without category
$query->category('');
} else {
// Processes with the category $catUid
$query->category($catUid);
}
}
// Order the data
$query->orderBy($sort, $dir);
// Define the pagination
$query->offset($start)->limit($limit);
// Get the results
$results = $query->get();
// Define the class for get workspace configurations
$systemConf = new Configurations();
$systemConf->loadConfig($obj, 'ENVIRONMENT_SETTINGS', '');
$mask = isset($systemConf->aConfig['dateFormat']) ? $systemConf->aConfig['dateFormat'] : '';
// Prepare the final result
$results->transform(function ($item, $key) use ($counterByProcess, $systemConf, $mask){
// Get the counter related to the status
// todo: those counters needs to remove when the PMCORE-2314 was implemented
$item['CASES_COUNT_DRAFT'] = $counterByProcess ? Application::getCountByProUid($item['PRO_UID'], 1) : 0;
$item['CASES_COUNT_TO_DO'] = $counterByProcess ? Application::getCountByProUid($item['PRO_UID'], 2) : 0;
$item['CASES_COUNT_COMPLETED'] = $counterByProcess ? Application::getCountByProUid($item['PRO_UID'], 3) : 0;
$item['CASES_COUNT_CANCELLED'] = $counterByProcess ? Application::getCountByProUid($item['PRO_UID'], 4) : 0;
$item['CASES_COUNT'] = $item['CASES_COUNT_DRAFT'] + $item['CASES_COUNT_TO_DO'] + $item['CASES_COUNT_COMPLETED'] + $item['CASES_COUNT_CANCELLED'];
// Get the description
// todo: we will to remove htmlspecialchars but frontEnd needs to add application wide XSS prevention measures
$item['PRO_DESCRIPTION'] = empty($item['PRO_DESCRIPTION']) ? '' : htmlspecialchars($item['PRO_DESCRIPTION']);
// Get the type: bpmn or classic
$bpmnProcess = BpmnProject::isBpmnProcess($item['PRO_UID']);
$item['PROJECT_TYPE'] = ($bpmnProcess) ? 'bpmn' : 'classic';
// Get the process type: PUBLIC or PRIVATE
$item['PRO_TYPE_PROCESS'] = ($item['PRO_TYPE_PROCESS'] == 'PUBLIC') ? G::LoadTranslation("ID_PUBLIC") : G::LoadTranslation("ID_PRIVATE");;
// Get information about the owner, with the format defined
$creatorOwner = $systemConf->usersNameFormat($item['USR_USERNAME'], $item['USR_FIRSTNAME'], $item['USR_LASTNAME']);
$item['PRO_CREATE_USER_LABEL'] = empty($creatorOwner) ? $item['USR_FIRSTNAME'] . ' ' . $item['USR_LASTNAME'] : $creatorOwner;
// Get debug label
$item['PRO_DEBUG_LABEL'] = ($item['PRO_DEBUG'] == '1') ? G::LoadTranslation('ID_ON') : G::LoadTranslation('ID_OFF');
// Get status label
$item['PRO_STATUS_LABEL'] = $item['PRO_STATUS'] == 'ACTIVE' ? G::LoadTranslation('ID_ACTIVE') : G::LoadTranslation('ID_INACTIVE');
// Get category label
$item['PRO_CATEGORY_LABEL'] = trim($item['PRO_CATEGORY']) != '' ? $item['CATEGORY_NAME'] : G::LoadTranslation('ID_PROCESS_NONE_CATEGORY');
// Apply the date format defined in environment
if (!empty($mask)) {
$item['PRO_CREATE_DATE_LABEL'] = $item['PRO_CREATE_DATE']->format($mask);
$item['PRO_UPDATE_DATE_LABEL'] = $item['PRO_UPDATE_DATE']->format($mask);
}
return $item;
});
return $results->values()->toArray();
}
/**
* Get the number of rows corresponding to the process
*
* @param string $userUid
* @return integer
*/
public static function getCounter($userUid = '')
{
$query = Process::query()->select();
$query->noStatus();
if (!empty($userUid)) {
//Only process PRO_TYPE_PROCESS = "PUBLIC" or related user owner
$query->perUser($userUid);
}
return $query->count();
}
}

View File

@@ -16,4 +16,26 @@ class ProcessCategory extends Model
protected $table = 'PROCESS_CATEGORY';
public $timestamps = false;
/**
* Get the categories
*
* @param string $dir
*
* @return array
*
* @see ProcessProxy::categoriesList()
* @link https://wiki.processmaker.com/3.0/Process_Categories
*/
public static function getCategories( $dir = 'ASC')
{
$query = ProcessCategory::query()
->select([
'CATEGORY_UID',
'CATEGORY_NAME'
])
->orderBy('CATEGORY_NAME', $dir);
return $query->get()->values()->toArray();
}
}

View File

@@ -10,11 +10,34 @@ class Triggers extends Model
protected $table = 'TRIGGERS';
// No timestamps
public $timestamps = false;
//primary key
// Primary key
protected $primaryKey = 'TRI_UID';
//No incrementing
// No incrementing
public $incrementing = false;
// Filter by a specific uid
private $triUid = '';
/**
* Set trigger uid
*
* @param string $triUid
*/
public function setTrigger($triUid)
{
$this->triUid = $triUid;
}
/**
* Get trigger uid
*
* @return int
*/
public function getTrigger()
{
return $this->triUid;
}
/**
* Scope a query to filter an specific process
*
@@ -22,8 +45,37 @@ class Triggers extends Model
* @param string $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeProcess($query, string $proUID)
public function scopeProcess($query, string $proUid)
{
return $query->where('PRO_UID', $proUID);
return $query->where('PRO_UID', $proUid);
}
/**
* Scope a query to filter an specific trigger
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $triUid
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeTrigger($query, string $triUid)
{
return $query->where('TRI_UID', $triUid);
}
/**
* Get the records
*
* @return array
*/
public function triggers()
{
$query = Triggers::query()->select();
// Specific trigger
if (!empty($this->getTrigger())) {
$query->trigger($this->getTrigger());
}
$results = $query->get()->toArray();
return $results;
}
}

View File

@@ -0,0 +1,687 @@
<?php
namespace ProcessMaker\TaskScheduler;
use Application;
use AppAssignSelfServiceValueGroupPeer;
use AppAssignSelfServiceValuePeer;
use AppCacheView;
use AppDelegation;
use App\Jobs\TaskScheduler;
use Bootstrap;
use Cases;
use ConfigurationPeer;
use Criteria;
use Exception;
use G;
use Illuminate\Support\Facades\Log;
use ldapadvancedClassCron;
use NotificationQueue;
use ProcessMaker\BusinessModel\ActionsByEmail\ResponseReader;
use ProcessMaker\BusinessModel\Cases as BmCases;
use ProcessMaker\BusinessModel\Light\PushMessageAndroid;
use ProcessMaker\BusinessModel\Light\PushMessageIOS;
use ProcessMaker\BusinessModel\MessageApplication;
use ProcessMaker\BusinessModel\TimerEvent;
use ProcessMaker\Core\JobsManager;
use ProcessMaker\Plugins\PluginRegistry;
use Propel;
use ResultSet;
use SpoolRun;
class Task
{
/**
* Property asynchronous,
* @var bool
*/
private $asynchronous;
/**
* Property object
* @var mix
*/
private $object;
/**
* Constructor class.
* @param bool $async
* @param mix $object
*/
public function __construct(bool $asynchronous, $object)
{
$this->asynchronous = $asynchronous;
$this->object = $object;
}
/**
* Run job, the property async indicate if is synchronous or asynchronous.
* @param callable $job
*/
private function runTask(callable $job)
{
if ($this->asynchronous === false) {
$job();
}
if ($this->asynchronous === true) {
JobsManager::getSingleton()->dispatch(TaskScheduler::class, $job);
}
}
/**
* Print start message in console.
* @param string $message
*/
public function setExecutionMessage(string $message)
{
Log::channel('taskScheduler:taskScheduler')->info($message, Bootstrap::context());
if ($this->asynchronous === false) {
$len = strlen($message);
$linesize = 60;
$rOffset = $linesize - $len;
eprint("* $message");
for ($i = 0; $i < $rOffset; $i++) {
eprint('.');
}
}
}
/**
* Print result message in console.
* @param string $message
* @param string $type
*/
public function setExecutionResultMessage(string $message, string $type = '')
{
$color = 'green';
if ($type == 'error') {
$color = 'red';
Log::channel('taskScheduler:taskScheduler')->error($message, Bootstrap::context());
}
if ($type == 'info') {
$color = 'yellow';
Log::channel('taskScheduler:taskScheduler')->info($message, Bootstrap::context());
}
if ($type == 'warning') {
$color = 'yellow';
Log::channel('taskScheduler:taskScheduler')->warning($message, Bootstrap::context());
}
if ($this->asynchronous === false) {
eprintln("[$message]", $color);
}
}
/**
* Save logs.
* @param string $source
* @param string $type
* @param string $description
*/
public function saveLog(string $source, string $type, string $description)
{
if ($this->asynchronous === true) {
$context = [
'type' => $type,
'description' => $description
];
Log::channel('taskScheduler:taskScheduler')->info($source, Bootstrap::context($context));
}
if ($this->asynchronous === false) {
try {
G::verifyPath(PATH_DATA . "log" . PATH_SEP, true);
G::log("| $this->object | " . $source . " | $type | " . $description, PATH_DATA);
} catch (Exception $e) {
Log::channel('taskScheduler:taskScheduler')->error($e->getMessage(), Bootstrap::context());
}
}
}
/**
* This resend the emails.
* @param string $now
* @param string $dateSystem
*/
public function resendEmails($now, $dateSystem)
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($now, $dateSystem, $scheduledTaskIdentifier) {
$this->setExecutionMessage("Resending emails");
try {
$dateResend = $now;
if ($now == $dateSystem) {
$arrayDateSystem = getdate(strtotime($dateSystem));
$mktDateSystem = mktime(
$arrayDateSystem["hours"],
$arrayDateSystem["minutes"],
$arrayDateSystem["seconds"],
$arrayDateSystem["mon"],
$arrayDateSystem["mday"],
$arrayDateSystem["year"]
);
$dateResend = date("Y-m-d H:i:s", $mktDateSystem - (7 * 24 * 60 * 60));
}
$spoolRun = new SpoolRun();
$spoolRun->resendEmails($dateResend, 1);
$this->saveLog("resendEmails", "action", "Resending Emails", "c");
$spoolWarnings = $spoolRun->getWarnings();
if ($spoolWarnings !== false) {
foreach ($spoolWarnings as $warning) {
print("MAIL SPOOL WARNING: " . $warning . "\n");
$this->saveLog("resendEmails", "warning", "MAIL SPOOL WARNING: " . $warning);
}
}
$this->setExecutionResultMessage("DONE");
} catch (Exception $e) {
$context = [
"trace" => $e->getTraceAsString()
];
Log::channel('taskScheduler:taskScheduler')->error($e->getMessage(), Bootstrap::context($context));
$criteria = new Criteria("workflow");
$criteria->clearSelectColumns();
$criteria->addSelectColumn(ConfigurationPeer::CFG_UID);
$criteria->add(ConfigurationPeer::CFG_UID, "Emails");
$result = ConfigurationPeer::doSelectRS($criteria);
$result->setFetchmode(ResultSet::FETCHMODE_ASSOC);
if ($result->next()) {
$this->setExecutionResultMessage("WARNING", "warning");
$message = "Emails won't be sent, but the cron will continue its execution";
if ($this->asynchronous === false) {
eprintln(" '-" . $message, "yellow");
}
} else {
$this->setExecutionResultMessage("WITH ERRORS", "error");
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), "red");
}
}
$this->saveLog("resendEmails", "error", "Error Resending Emails: " . $e->getMessage());
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This unpause applications.
* @param string $now
*/
public function unpauseApplications($now)
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($now, $scheduledTaskIdentifier) {
$this->setExecutionMessage("Unpausing applications");
try {
$cases = new Cases();
$cases->ThrowUnpauseDaemon($now, 1);
$this->setExecutionResultMessage('DONE');
$this->saveLog('unpauseApplications', 'action', 'Unpausing Applications');
} catch (Exception $e) {
$this->setExecutionResultMessage('WITH ERRORS', 'error');
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), 'red');
}
$this->saveLog('unpauseApplications', 'error', 'Error Unpausing Applications: ' . $e->getMessage());
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* Check if some task unassigned has enable the setting timeout and execute the trigger related
*
* @link https://wiki.processmaker.com/3.2/Tasks#Self-Service
*/
function executeCaseSelfService()
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($scheduledTaskIdentifier) {
try {
$this->setExecutionMessage("Unassigned case");
$this->saveLog("unassignedCase", "action", "Unassigned case", "c");
$casesExecuted = BmCases::executeSelfServiceTimeout();
foreach ($casesExecuted as $caseNumber) {
$this->saveLog("unassignedCase", "action", "OK Executed trigger to the case $caseNumber");
}
$this->setExecutionResultMessage(count($casesExecuted) . " Cases");
} catch (Exception $e) {
$this->setExecutionResultMessage("WITH ERRORS", "error");
$this->saveLog("unassignedCase", "action", "Unassigned case", "c");
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), "red");
}
$this->saveLog("unassignedCase", "error", "Error in unassigned case: " . $e->getMessage());
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This calculate duration.
*/
public function calculateDuration()
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($scheduledTaskIdentifier) {
$this->setExecutionMessage("Calculating Duration");
try {
$appDelegation = new AppDelegation();
$appDelegation->calculateDuration(1);
$this->setExecutionResultMessage('DONE');
$this->saveLog('calculateDuration', 'action', 'Calculating Duration');
} catch (Exception $e) {
$this->setExecutionResultMessage('WITH ERRORS', 'error');
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), 'red');
}
$this->saveLog('calculateDuration', 'error', 'Error Calculating Duration: ' . $e->getMessage());
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This calculate application duration.
*/
public function calculateAppDuration()
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($scheduledTaskIdentifier) {
$this->setExecutionMessage("Calculating Duration by Application");
try {
$application = new Application();
$application->calculateAppDuration(1);
$this->setExecutionResultMessage('DONE');
$this->saveLog('calculateDurationByApp', 'action', 'Calculating Duration by Application');
} catch (Exception $e) {
$this->setExecutionResultMessage('WITH ERRORS', 'error');
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), 'red');
}
$this->saveLog('calculateDurationByApp', 'error', 'Error Calculating Duration: ' . $e->getMessage());
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* Clean unused records in tables related to the Self-Service Value Based feature.
*/
public function cleanSelfServiceTables()
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($scheduledTaskIdentifier) {
try {
// Start message
$this->setExecutionMessage("Clean unused records for Self-Service Value Based feature");
// Get Propel connection
$cnn = Propel::getConnection(AppAssignSelfServiceValueGroupPeer::DATABASE_NAME);
// Delete related rows and missing relations, criteria don't execute delete with joins
$cnn->begin();
$stmt = $cnn->createStatement();
$stmt->executeQuery("DELETE " . AppAssignSelfServiceValueGroupPeer::TABLE_NAME . "
FROM " . AppAssignSelfServiceValueGroupPeer::TABLE_NAME . "
LEFT JOIN " . AppAssignSelfServiceValuePeer::TABLE_NAME . "
ON (" . AppAssignSelfServiceValueGroupPeer::ID . " = " . AppAssignSelfServiceValuePeer::ID . ")
WHERE " . AppAssignSelfServiceValuePeer::ID . " IS NULL");
$cnn->commit();
// Success message
$this->setExecutionResultMessage("DONE");
} catch (Exception $e) {
$cnn->rollback();
$this->setExecutionResultMessage("WITH ERRORS", "error");
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), "red");
}
$this->saveLog("ExecuteCleanSelfServiceTables", "error", "Error when try to clean self-service tables " . $e->getMessage());
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This execute plugins cron.
* @return boolean
*/
public function executePlugins()
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($scheduledTaskIdentifier) {
$pathCronPlugins = PATH_CORE . 'bin' . PATH_SEP . 'plugins' . PATH_SEP;
// Executing cron files in bin/plugins directory
if (!is_dir($pathCronPlugins)) {
return false;
}
if ($handle = opendir($pathCronPlugins)) {
$this->setExecutionMessage('Executing cron files in bin/plugins directory in Workspace: ' . config("system.workspace"));
while (false !== ($file = readdir($handle))) {
if (strpos($file, '.php', 1) && is_file($pathCronPlugins . $file)) {
$filename = str_replace('.php', '', $file);
$className = $filename . 'ClassCron';
// Execute custom cron function
$this->executeCustomCronFunction($pathCronPlugins . $file, $className);
}
}
}
// Executing registered cron files
// -> Get registered cron files
$pluginRegistry = PluginRegistry::loadSingleton();
$cronFiles = $pluginRegistry->getCronFiles();
// -> Execute functions
if (!empty($cronFiles)) {
$this->setExecutionMessage('Executing registered cron files for Workspace: ' . config('system.workspace'));
/**
* @var \ProcessMaker\Plugins\Interfaces\CronFile $cronFile
*/
foreach ($cronFiles as $cronFile) {
$path = PATH_PLUGINS . $cronFile->getNamespace() . PATH_SEP . 'bin' . PATH_SEP . $cronFile->getCronFile() . '.php';
if (file_exists($path)) {
$this->executeCustomCronFunction($path, $cronFile->getCronFile());
} else {
$this->setExecutionMessage('File ' . $cronFile->getCronFile() . '.php ' . 'does not exist.');
}
}
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This execute custom cron function.
* @param string $pathFile
* @param string $className
*/
public function executeCustomCronFunction($pathFile, $className)
{
include_once $pathFile;
$plugin = new $className();
if (method_exists($plugin, 'executeCron')) {
$arrayCron = unserialize(trim(@file_get_contents(PATH_DATA . "cron")));
$arrayCron["processcTimeProcess"] = 60; //Minutes
$arrayCron["processcTimeStart"] = time();
@file_put_contents(PATH_DATA . "cron", serialize($arrayCron));
//Try to execute Plugin Cron. If there is an error then continue with the next file
$this->setExecutionMessage("\n--- Executing cron file: $pathFile");
try {
$plugin->executeCron();
$this->setExecutionResultMessage('DONE');
} catch (Exception $e) {
$this->setExecutionResultMessage('FAILED', 'error');
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), 'red');
}
$this->saveLog('executePlugins', 'error', 'Error executing cron file: ' . $pathFile . ' - ' . $e->getMessage());
}
}
}
/**
* This fills the report by user.
* @param string $dateInit
* @param string $dateFinish
* @return boolean
*/
public function fillReportByUser($dateInit, $dateFinish)
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
if ($dateInit == null) {
if ($this->asynchronous === false) {
eprintln("You must enter the starting date.", "red");
eprintln('Example: +init-date"YYYY-MM-DD HH:MM:SS" +finish-date"YYYY-MM-DD HH:MM:SS"', "red");
}
if ($this->asynchronous === true) {
$message = 'You must enter the starting date. Example: +init-date"YYYY-MM-DD HH:MM:SS" +finish-date"YYYY-MM-DD HH:MM:SS"';
Log::channel('taskScheduler:taskScheduler')->info($message, Bootstrap::context());
}
return false;
}
$job = function() use($dateInit, $dateFinish, $scheduledTaskIdentifier) {
try {
$dateFinish = ($dateFinish != null) ? $dateFinish : date("Y-m-d H:i:s");
$appCacheView = new AppCacheView();
$appCacheView->setPathToAppCacheFiles(PATH_METHODS . 'setup' . PATH_SEP . 'setupSchemas' . PATH_SEP);
$this->setExecutionMessage("Calculating data to fill the 'User Reporting'...");
$appCacheView->fillReportByUser($dateInit, $dateFinish);
setExecutionResultMessage("DONE");
} catch (Exception $e) {
$this->setExecutionResultMessage("WITH ERRORS", "error");
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), "red");
}
$this->saveLog("fillReportByUser", "error", "Error in fill report by user: " . $e->getMessage());
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This fills the report by process.
* @param string $dateInit
* @param string $dateFinish
* @return boolean
*/
public function fillReportByProcess($dateInit, $dateFinish)
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
if ($dateInit == null) {
if ($this->asynchronous === false) {
eprintln("You must enter the starting date.", "red");
eprintln('Example: +init-date"YYYY-MM-DD HH:MM:SS" +finish-date"YYYY-MM-DD HH:MM:SS"', "red");
}
if ($this->asynchronous === true) {
$message = 'You must enter the starting date. Example: +init-date"YYYY-MM-DD HH:MM:SS" +finish-date"YYYY-MM-DD HH:MM:SS"';
Log::channel('taskScheduler:taskScheduler')->info($message, Bootstrap::context());
}
return false;
}
$job = function() use($dateInit, $dateFinish, $scheduledTaskIdentifier) {
try {
$dateFinish = ($dateFinish != null) ? $dateFinish : date("Y-m-d H:i:s");
$appcv = new AppCacheView();
$appcv->setPathToAppCacheFiles(PATH_METHODS . 'setup' . PATH_SEP . 'setupSchemas' . PATH_SEP);
$this->setExecutionMessage("Calculating data to fill the 'Process Reporting'...");
$appcv->fillReportByProcess($dateInit, $dateFinish);
$this->setExecutionResultMessage("DONE");
} catch (Exception $e) {
$this->setExecutionResultMessage("WITH ERRORS", "error");
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), "red");
}
$this->saveLog("fillReportByProcess", "error", "Error in fill report by process: " . $e->getMessage());
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This execute ldap cron.
* @param boolean $debug
*/
public function ldapcron($debug)
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($debug, $scheduledTaskIdentifier) {
require_once(PATH_HOME . 'engine' . PATH_SEP . 'methods' . PATH_SEP . 'services' . PATH_SEP . 'ldapadvanced.php');
$ldapadvancedClassCron = new ldapadvancedClassCron();
$ldapadvancedClassCron->executeCron($debug);
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This execute the sending of notifications.
*/
function sendNotifications()
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($scheduledTaskIdentifier) {
try {
$this->setExecutionMessage("Resending Notifications");
$this->setExecutionResultMessage("PROCESSING");
$notQueue = new NotificationQueue();
$notQueue->checkIfCasesOpenForResendingNotification();
$notificationsAndroid = $notQueue->loadStatusDeviceType('pending', 'android');
if ($notificationsAndroid) {
$this->setExecutionMessage("|-- Send Android's Notifications");
$n = 0;
foreach ($notificationsAndroid as $key => $item) {
$notification = new PushMessageAndroid();
$notification->setSettingNotification();
$notification->setDevices(unserialize($item['DEV_UID']));
$response['android'] = $notification->send($item['NOT_MSG'], unserialize($item['NOT_DATA']));
$notQueue = new NotificationQueue();
$notQueue->changeStatusSent($item['NOT_UID']);
$n += $notification->getNumberDevices();
}
$this->setExecutionResultMessage("Processed $n");
}
$notificationsApple = $notQueue->loadStatusDeviceType('pending', 'apple');
if ($notificationsApple) {
$this->setExecutionMessage("|-- Send Apple Notifications");
$n = 0;
foreach ($notificationsApple as $key => $item) {
$notification = new PushMessageIOS();
$notification->setSettingNotification();
$notification->setDevices(unserialize($item['DEV_UID']));
$response['apple'] = $notification->send($item['NOT_MSG'], unserialize($item['NOT_DATA']));
$notQueue = new NotificationQueue();
$notQueue->changeStatusSent($item['NOT_UID']);
$n += $notification->getNumberDevices();
}
$this->setExecutionResultMessage("Processed $n");
}
} catch (Exception $e) {
$this->setExecutionResultMessage("WITH ERRORS", "error");
if ($this->asynchronous === false) {
eprintln(" '-" . $e->getMessage(), "red");
}
$this->saveLog("ExecuteSendNotifications", "error", "Error when sending notifications " . $e->getMessage());
}
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This executes an actions by email responses.
*/
public function actionsByEmailResponse()
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($scheduledTaskIdentifier) {
$responseReader = new ResponseReader();
$responseReader->actionsByEmailEmailResponse();
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* This execute message event cron.
*/
public function messageeventcron()
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use($scheduledTaskIdentifier) {
$messageApplication = new MessageApplication();
$messageApplication->catchMessageEvent(true);
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
/**
* Start/Continue cases by Timer-Event
*
* @param string $datetime
* @param bool $frontEnd
*/
public function timerEventCron($datetime, $frontEnd)
{
$scheduledTaskIdentifier = uniqid(__FUNCTION__ . "#");
Log::channel('taskScheduler:taskScheduler')->info("Start {$scheduledTaskIdentifier}", Bootstrap::context());
$job = function() use ($datetime, $frontEnd, $scheduledTaskIdentifier) {
$timerEvent = new TimerEvent();
$timerEvent->startContinueCaseByTimerEvent($datetime, $frontEnd);
Log::channel('taskScheduler:taskScheduler')->info("Finish {$scheduledTaskIdentifier}", Bootstrap::context());
};
$this->runTask($job);
}
}

View File

@@ -688,3 +688,33 @@ function saveAppDocument($file, $appUid, $appDocUid, $version = 1, $upload = tru
throw $e;
}
}
/**
* Add a specific date minutes, hours or days
*
* @param string $iniDate
* @param string $timeUnit
* @param int $time
*
* @return string
*
* @link https://www.php.net/manual/en/datetime.modify.php
*/
function calculateDate($iniDate, $timeUnit, $time)
{
$datetime = new DateTime($iniDate);
switch ($timeUnit) {
case 'DAYS':
$datetime->modify('+' . $time . ' day');
break;
case 'HOURS':
$datetime->modify('+' . $time . ' hour');
break;
case 'MINUTES':
$datetime->modify('+' . $time . ' minutes');
break;
}
return $datetime->format('Y-m-d H:i:s');
}