Latest updates from IceHrmPro

This commit is contained in:
Thilina Pituwala
2020-05-20 18:47:29 +02:00
parent 60c92d7935
commit 7453a58aad
18012 changed files with 2089245 additions and 10173 deletions

View File

@@ -29,32 +29,32 @@ class AttendanceAdminManager extends AbstractModuleManager
public function setupRestEndPoints()
{
\Classes\Macaw::get(REST_API_PATH.'attendance/(:num)', function ($pathParams) {
\Classes\Macaw::get(REST_API_PATH.'attendance/(:num)', function ($pathParams = null) {
$restEndPoint = new AttendanceRestEndPoint();
$restEndPoint->process('get', $pathParams);
});
\Classes\Macaw::get(REST_API_PATH.'attendance', function ($pathParams) {
\Classes\Macaw::get(REST_API_PATH.'attendance', function ($pathParams = null) {
$restEndPoint = new AttendanceRestEndPoint();
$restEndPoint->process('listAll', $pathParams);
});
\Classes\Macaw::get(REST_API_PATH.'employee/(:num)/attendance', function ($pathParams) {
\Classes\Macaw::get(REST_API_PATH.'employee/(:num)/attendance', function ($pathParams = null) {
$restEndPoint = new AttendanceRestEndPoint();
$restEndPoint->process('listEmployeeAttendance', $pathParams);
});
\Classes\Macaw::post(REST_API_PATH.'attendance', function ($pathParams) {
\Classes\Macaw::post(REST_API_PATH.'attendance', function ($pathParams = null) {
$restEndPoint = new AttendanceRestEndPoint();
$restEndPoint->process('post', $pathParams);
});
\Classes\Macaw::delete(REST_API_PATH.'attendance/(:num)', function ($pathParams) {
\Classes\Macaw::delete(REST_API_PATH.'attendance/(:num)', function ($pathParams = null) {
$restEndPoint = new AttendanceRestEndPoint();
$restEndPoint->process('delete', $pathParams);
});
\Classes\Macaw::post(REST_API_PATH.'attendance/punch-in', function ($pathParams) {
\Classes\Macaw::post(REST_API_PATH.'attendance/punch-in', function ($pathParams = null) {
$restEndPoint = new AttendanceRestEndPoint();
$restEndPoint->process('punchIn', $pathParams);
});
@@ -64,7 +64,7 @@ class AttendanceAdminManager extends AbstractModuleManager
$restEndPoint->process('getOpenPunch', [$employeeId, $date]);
});
\Classes\Macaw::post(REST_API_PATH.'attendance/punch-out', function ($pathParams) {
\Classes\Macaw::post(REST_API_PATH.'attendance/punch-out', function ($pathParams = null) {
$restEndPoint = new AttendanceRestEndPoint();
$restEndPoint->process('punchOut', $pathParams);
});
@@ -85,10 +85,10 @@ class AttendanceAdminManager extends AbstractModuleManager
public function initQuickAccessMenu()
{
UIManager::getInstance()->addQuickAccessMenuItem(
"Clocked In Employees",
"fa-clock-o",
CLIENT_BASE_URL."?g=admin&n=attendance&m=admin_Employees#tabAttendanceStatus",
array("Admin","Manager")
'Clocked In Employees',
'fa-clock-o',
CLIENT_BASE_URL.'?g=admin&n=attendance&m=admin_Employees#tabAttendanceStatus',
array('Admin','Manager')
);
}

View File

@@ -8,6 +8,7 @@
namespace Attendance\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class Attendance extends BaseModel
@@ -33,4 +34,13 @@ class Attendance extends BaseModel
{
return array('element','save','delete');
}
public function getModuleAccess()
{
return [
new ModuleAccess('attendance', 'admin'),
new ModuleAccess('attendance', 'user'),
new ModuleAccess('attendance_sheets', 'user'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Attendance\Common\Model;
use Classes\ModuleAccess;
use Classes\SettingsManager;
use Employees\Common\Model\Employee;
use Model\BaseModel;
@@ -136,4 +137,12 @@ class AttendanceStatus extends BaseModel
{
return array("element","save","delete");
}
public function getModuleAccess()
{
return [
new ModuleAccess('attendance', 'admin'),
new ModuleAccess('attendance', 'user'),
];
}
}

View File

@@ -97,18 +97,16 @@ class AttendanceRestEndPoint extends RestEndPoint
return new IceResponse(IceResponse::ERROR, self::RESPONSE_ERR_PERMISSION_DENIED, 403);
}
$mapping = [
"employee" => ["Employee", "id", "first_name+last_name"],
];
$mapping = '{"employee": [ "Employee", "id", "first_name+last_name" ]}';
$emp = BaseService::getInstance()->getElement(
self::ELEMENT_NAME,
$parameter,
json_encode($mapping),
null,
true
);
$emp = $this->enrichElement($emp, $mapping);
$emp = $this->enrichElement($emp, json_decode($mapping));
if (!empty($emp)) {
$emp = $this->cleanObject($emp);
return new IceResponse(IceResponse::SUCCESS, $emp);

View File

@@ -52,6 +52,8 @@ class BaseService
public $modelClassMap = array();
public $currentProfileId = false;
protected $cacheService = null;
protected $pro = null;
private static $me = null;
@@ -109,14 +111,11 @@ class BaseService
$filter = json_decode($filterStr, true);
if (!empty($filter)) {
LogManager::getInstance()->debug("Building filter query");
if (method_exists($obj, 'getCustomFilterQuery')) {
LogManager::getInstance()->debug("Method: getCustomFilterQuery exists");
$response = $obj->getCustomFilterQuery($filter);
$query = $response[0];
$queryData = $response[1];
} else {
LogManager::getInstance()->debug("Method: getCustomFilterQuery not found");
$defaultFilterResp = $this->buildDefaultFilterQuery($filter);
$query = $defaultFilterResp[0];
$queryData = $defaultFilterResp[1];
@@ -134,8 +133,6 @@ class BaseService
$cemp = $this->getCurrentProfileId();
if (!empty($cemp)) {
$signInMappingField = SIGN_IN_ELEMENT_MAPPING_FIELD_NAME;
LogManager::getInstance()->debug("Query: ".$signInMappingField." = ?".$query.$orderBy);
LogManager::getInstance()->debug("Query Data: ".print_r(array_merge(array($cemp), $queryData), true));
$list = $obj->Find($signInMappingField." = ?".$query.$orderBy, array_merge(array($cemp), $queryData));
} else {
$list = array();
@@ -194,14 +191,14 @@ class BaseService
$query.=" and (";
}
$query.=$k." like ?";
$query.=$k." = ?";
if ($i < $length -1) {
$query.=" or ";
} else {
$query.=")";
}
$queryData[] = "%".$v[$i]."%";
$queryData[] = $v[$i];
}
} else {
if (!empty($v) && $v != 'NULL') {
@@ -231,6 +228,132 @@ class BaseService
return $data;
}
public function getDataCount()
{
//Get Total row count
$totalRows = 0;
if (!isset($_REQUEST['objects'])) {
$countFilterQuery = "";
$countFilterQueryData = array();
if (!empty($_REQUEST['ft'])) {
$filter = json_decode($_REQUEST['ft']);
if (!empty($filter)) {
\Utils\LogManager::getInstance()->debug("Filter:" . print_r($filter, true));
if (method_exists($obj, 'getCustomFilterQuery')) {
$response = $obj->getCustomFilterQuery($filter);
$countFilterQuery = $response[0];
$countFilterQueryData = $response[1];
} else {
$defaultFilterResp = \Classes\BaseService::getInstance()->buildDefaultFilterQuery($filter);
$countFilterQuery = $defaultFilterResp[0];
$countFilterQueryData = $defaultFilterResp[1];
}
}
}
if (in_array($table, \Classes\BaseService::getInstance()->userTables)
&& !$skipProfileRestriction && !$isSubOrdinates) {
$cemp = \Classes\BaseService::getInstance()->getCurrentProfileId();
$sql = "Select count(id) as count from "
. $obj->_table . " where " . SIGN_IN_ELEMENT_MAPPING_FIELD_NAME . " = ? " . $countFilterQuery;
array_unshift($countFilterQueryData, $cemp);
$rowCount = $obj->DB()->Execute($sql, $countFilterQueryData);
} else {
if ($isSubOrdinates) {
$cemp = \Classes\BaseService::getInstance()->getCurrentProfileId();
$profileClass = \Classes\BaseService::getInstance()->getFullQualifiedModelClassName(
ucfirst(SIGN_IN_ELEMENT_MAPPING_FIELD_NAME)
);
$subordinate = new $profileClass();
$subordinates = $subordinate->Find("supervisor = ?", array($cemp));
$cempObj = new \Employees\Common\Model\Employee();
$cempObj->Load("id = ?", array($cemp));
if ($obj->getUserOnlyMeAccessField() == 'id'
&& \Classes\SettingsManager::getInstance()->getSetting(
'System: Company Structure Managers Enabled'
) == 1
&& \Company\Common\Model\CompanyStructure::isHeadOfCompanyStructure($cempObj->department, $cemp)
) {
if (empty($subordinates)) {
$subordinates = array();
}
$childCompaniesIds = array();
if (\Classes\SettingsManager::getInstance()->getSetting(
'System: Child Company Structure Managers Enabled'
) == '1'
) {
$childCompaniesResp = \Company\Common\Model\CompanyStructure::getAllChildCompanyStructures(
$cempObj->department
);
$childCompanies = $childCompaniesResp->getObject();
foreach ($childCompanies as $cc) {
$childCompaniesIds[] = $cc->id;
}
} else {
$childCompaniesIds[] = $cempObj->department;
}
if (!empty($childCompaniesIds)) {
$childStructureSubordinates = $subordinate->Find(
"department in (" . implode(',', $childCompaniesIds) . ") and id != ?",
array($cemp)
);
$subordinates = array_merge($subordinates, $childStructureSubordinates);
}
}
$subordinatesIds = "";
foreach ($subordinates as $sub) {
if ($subordinatesIds != "") {
$subordinatesIds .= ",";
}
$subordinatesIds .= $sub->id;
}
if ($obj->allowIndirectMapping()) {
$indeirectEmployees = $subordinate->Find(
"indirect_supervisors IS NOT NULL and indirect_supervisors <> '' and status = 'Active'",
array()
);
foreach ($indeirectEmployees as $ie) {
$indirectSupervisors = json_decode($ie->indirect_supervisors, true);
if (in_array($cemp, $indirectSupervisors)) {
if ($subordinatesIds != "") {
$subordinatesIds .= ",";
}
$subordinatesIds .= $ie->id;
}
}
}
$sql = "Select count(id) as count from " . $obj->_table .
" where " . $obj->getUserOnlyMeAccessField() . " in (" . $subordinatesIds . ") "
. $countFilterQuery;
$rowCount = $obj->DB()->Execute($sql, $countFilterQueryData);
} else {
$sql = "Select count(id) as count from " . $obj->_table;
if (!empty($countFilterQuery)) {
$sql .= " where 1=1 " . $countFilterQuery;
}
$rowCount = $obj->DB()->Execute($sql, $countFilterQueryData);
}
}
}
if (isset($rowCount) && !empty($rowCount)) {
foreach ($rowCount as $cnt) {
$totalRows = $cnt['count'];
}
}
return $totalRows;
}
/**
* An extention of get method for the use of data tables with ability to search
* @method getData
@@ -545,7 +668,13 @@ class BaseService
foreach ($map as $k => $v) {
$fTable = $this->getFullQualifiedModelClassName($v[0]);
$tObj = new $fTable();
$tObj->Load($v[1]."= ?", array($item->$k));
$tObj = $tObj->Find($v[1]."= ?", array($item->$k));
if (is_array($tObj)) {
$tObj = $tObj[0];
} else {
continue;
}
if ($tObj->{$v[1]} == $item->$k) {
$v[2] = str_replace("+", " ", $v[2]);
@@ -556,11 +685,11 @@ class BaseService
$item->$k = $tObj->{$v[2]};
} else {
$objVal = "";
foreach ($values as $v) {
foreach ($values as $val2) {
if ($objVal != "") {
$objVal .= " ";
}
$objVal .= $tObj->$v;
$objVal .= $tObj->$val2;
}
$idField = $k."_id";
$item->$idField = $item->$k;
@@ -629,12 +758,16 @@ class BaseService
if (count($values) == 1) {
return $targetObject->{$nameField};
}
$objVal = "";
$objVal = '';
foreach ($values as $value) {
if ($objVal != "") {
$objVal .= " ";
}
$objVal .= $targetObject->$value;
if (substr($value, 0, 1) !== ':') {
$objVal .= $targetObject->{$value};
} else {
$objVal .= substr($value, 1);
}
}
return $objVal;
@@ -646,7 +779,9 @@ class BaseService
* @param $table {String} model class name of the table to add data (e.g for Users table model class name is User)
* @param $obj {Array} an associative array with field names and values for the new object.
* If the object id is not empty an existing object will be updated
* @return {Object} newly added or updated element of type $table
* @param null $postObject
* @return IceResponse {Object} newly added or updated element of type $table newly added or updated
* element of type $table
*/
public function addElement($table, $obj, $postObject = null)
@@ -757,7 +892,6 @@ class BaseService
}
$customFields = $ele->getCustomFields($obj);
LogManager::getInstance()->error("Custom:".json_encode($customFields));
foreach ($obj as $k => $v) {
if (isset($customFields[$k])) {
$this->customFieldManager->addCustomField($table, $ele->id, $k, $v);
@@ -898,7 +1032,7 @@ class BaseService
$list = $ele->$method(array());
}
} else {
LogManager::getInstance()->debug("Could not find method:".$method." in Class:".$table);
LogManager::getInstance()->error("Could not find method:".$method." in Class:".$table);
$list = $ele->Find('1 = 1', array());
}
} else {
@@ -1106,10 +1240,12 @@ class BaseService
public function cleanUpUser($obj)
{
$obj = $this->cleanUpAdoDB($obj);
$obj = $this->cleanUpAll($obj);
unset($obj->password);
unset($obj->login_hash);
unset($obj->googleUserData);
unset($obj->wrong_password_count);
unset($obj->last_wrong_attempt_at);
return $obj;
}
@@ -1137,14 +1273,12 @@ class BaseService
public function checkSecureAccess($type, $object, $table, $request)
{
$accessMatrix = array();
//Construct permission method
$permMethod = "get".$this->currentUser->user_level."Access";
$permMethod = "get".str_replace(' ', '', $this->currentUser->user_level)."Access";
$userOnlyMeAccessRequestField = $object->getUserOnlyMeAccessRequestField();
$userOnlyMeAccessField = $object->getUserOnlyMeAccessField();
if (method_exists($object, $permMethod)) {
$accessMatrix = $object->$permMethod();
$accessMatrix = $object->$permMethod($this->currentUser->user_roles);
} else {
$accessMatrix = $object->getDefaultAccessLevel();
}
@@ -1174,7 +1308,7 @@ class BaseService
// Employees should be able to update their own records
if (!empty($table) && in_array($type, $accessMatrix)) {
if (!empty($this->currentUser->$userOnlyMeAccessRequestField)
&& in_array($table, $this->userTables) ) {
&& in_array($table, $this->userTables)) {
return true;
}
}
@@ -1183,7 +1317,15 @@ class BaseService
$ret['status'] = "ERROR";
$ret['message'] = $type." ".get_class($object)." Access violation";
echo json_encode($ret);
exit();
$exception = new \Exception(
sprintf(
'%s : %s',
'Access violation',
json_encode([$type, $table, get_class($object), $request, json_encode($this->currentUser)])
)
);
LogManager::getInstance()->notifyException($exception);
throw $exception;
}
public function getInstanceId()
@@ -1740,13 +1882,19 @@ END;
if ($obj->$name != '') {
$obj->$name .= ', ';
}
$tObj->Load($v[1] . "= ?", array($partialId));
$obj->$name .= $this->getCombinedValue($v[2], $tObj);
$tObjArr = $tObj->Find($v[1] . "= ?", [$partialId]);
if (!is_array($tObjArr) || empty($tObjArr[0])) {
continue;
}
$obj->$name .= $this->getCombinedValue($v[2], $tObjArr[0]);
}
}
} else {
$tObj->Load($v[1] . "= ?", array($obj->$k));
$obj->$name = $this->getCombinedValue($v[2], $tObj);
$tObjArr = $tObj->Find($v[1] . "= ?", [$obj->$k]);
if (!is_array($tObjArr) || empty($tObjArr[0])) {
continue;
}
$obj->$name = $this->getCombinedValue($v[2], $tObjArr[0]);
}
}
}
@@ -1767,4 +1915,25 @@ END;
}
return $obj;
}
/**
* @return RedisCacheService
*/
public function getCacheService()
{
return $this->cacheService;
}
/**
* @param CacheService $redisCacheService
*/
public function setCacheService($redisCacheService)
{
$this->cacheService = $redisCacheService;
}
public function queryCacheEnabled()
{
return defined('QUERY_CACHE') && QUERY_CACHE === true;
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Classes;
interface CacheService
{
public function setDBQuery($entity, $query, $params, $result, $ttl = 600);
public function getDBQuery($entity, $query, $params);
public function deleteByEntity($entity);
}

View File

@@ -42,7 +42,7 @@ class IceCron
$time = intval($this->cron->time);
if (empty($frequency) || !is_int($frequency)) {
LogManager::getInstance()->debug(
LogManager::getInstance()->error(
"Cron ".$this->cron->name." is not running since frequency is not an integer"
);
return false;

View File

@@ -26,6 +26,7 @@ class EmailSenderTask implements IceTask
$emailSender->sendEmailFromDB($email);
} catch (\Exception $e) {
LogManager::getInstance()->error("Error sending email:".$e->getMessage());
LogManager::getInstance()->notifyException($e);
}
$email->status = 'Sent';

View File

@@ -0,0 +1,64 @@
<?php
namespace Classes\Cron\Task;
use Candidates\Admin\Api\CandidatesActionManager;
use Candidates\Common\Email\CandidatesEmailSender;
use Candidates\Common\Model\Candidate;
use Classes\BaseService;
use Classes\Cron\IceTask;
use Employees\Common\Model\Employee;
use JobPositions\Common\Model\Job;
use Users\Common\Model\User;
class NewCandidateEmailTask implements IceTask
{
public function execute($cron)
{
$candidate = new Candidate();
$candidates = $candidate->Find('source = ? and emailSent = ?', [Candidate::SOURCE_APPLIED, 0]);
foreach ($candidates as $candidate) {
$job = new Job();
$job->Load('id = ?', [$candidate->jobId]);
$candidateActionManager = new CandidatesActionManager();
$candidateActionManager->setBaseService(BaseService::getInstance());
$candidateEmailSender = new CandidatesEmailSender(
BaseService::getInstance()->getEmailSender(),
$candidateActionManager
);
$candidate->emailSent = 1;
$ok = $candidate->Save();
if (!$ok) {
continue;
}
$candidateEmailSender->sendNewCandidateUserEmail($job->title, $candidate);
if (empty($job->hiringManager)) {
continue;
}
$manager = new Employee();
$manager->Load('id = ?', [$job->hiringManager]);
$managerUser = new User();
$managerUser->Load('employee = ?', [$manager->id]);
if (empty($managerUser->email)) {
continue;
}
$candidateEmailSender->sendNewCandidateManagerEmail(
$job->title,
$candidate,
$manager->first_name,
$managerUser->email
);
}
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace Classes\Cron\Task;
use Candidates\Admin\Api\CandidatesActionManager;
use Candidates\Common\Email\CandidatesEmailSender;
use Candidates\Common\Model\Candidate;
use Candidates\Common\Model\Interview;
use Classes\BaseService;
use Classes\Cron\IceTask;
use Employees\Common\Model\Employee;
use JobPositions\Common\Model\Job;
use Users\Common\Model\User;
use Utils\LogManager;
class RecruitmentEmailTask implements IceTask
{
public function execute($cron)
{
$interview = new Interview();
$interviews = $interview->Find('scheduleUpdated = ?', [1]);
foreach ($interviews as $interview) {
$job = new Job();
$job->Load('id = ?', [$interview->job]);
$candidate = new Candidate();
$candidate->Load('id = ?', [$interview->candidate]);
$manager = new Employee();
$manager->Load('id = ?', [$job->hiringManager]);
$managerUser = new User();
$managerUser->Load('employee = ?', [$manager->id]);
$candidateActionManager = new CandidatesActionManager();
$candidateActionManager->setBaseService(BaseService::getInstance());
$candidateEmailSender = new CandidatesEmailSender(
BaseService::getInstance()->getEmailSender(),
$candidateActionManager
);
$interview->scheduleUpdated = 0;
$ok = $interview->Save();
if (!$ok) {
continue;
}
if (!empty($job->hiringManager)) {
$manager = new Employee();
$manager->Load('id = ?', [$job->hiringManager]);
$managerUser = new User();
$managerUser->Load('employee = ?', [$manager->id]);
if (empty($managerUser->email)) {
continue;
}
$candidateEmailSender->interviewScheduledManagerEmail(
$job->title,
$candidate,
$manager->first_name,
$managerUser->email,
$interview
);
}
if (empty($interview->interviewers)) {
continue;
}
$interviewerIds = null;
try {
$interviewerIds = json_decode($interview->interviewers, true);
} catch (\Exception $e) {
LogManager::getInstance()->notifyException($e);
}
if (empty($interviewerIds) && !is_array($interviewerIds)) {
continue;
}
foreach ($interviewerIds as $interviewerId) {
$interviewer = new Employee();
$interviewer->Load('id = ?', [$interviewerId]);
$interviewerUser = new User();
$interviewerUser->Load('employee = ?', [$interviewer->id]);
if (empty($interviewerUser->email)) {
continue;
}
$candidateEmailSender->interviewScheduledInterviewerEmail(
$job->title,
$candidate,
$manager->first_name,
$managerUser->email,
$interviewerUser->email,
$interview,
$interviewer
);
}
}
}
}

View File

@@ -23,8 +23,7 @@ class Aes
$Nr = count($w)/$Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
$state = array(); // initialise 4xNb byte-array 'state' with input [<5B>3.4]
for ($i = 0; $i<4*$Nb;
$i++) {
for ($i = 0; $i<4*$Nb; $i++) {
$state[$i%4][floor($i/4)] = $input[$i];
}
@@ -42,8 +41,7 @@ class Aes
$state = self::addRoundKey($state, $w, $Nr, $Nb);
$output = array(4*$Nb); // convert state to 1-d array before returning [<5B>3.4]
for ($i = 0; $i<4*$Nb;
$i++) {
for ($i = 0; $i<4*$Nb; $i++) {
$output[$i] = $state[$i%4][floor($i/4)];
}
return $output;
@@ -53,8 +51,7 @@ class Aes
{
// xor Round Key into state S [<5B>5.1.4]
for ($r = 0; $r<4; $r++) {
for ($c = 0; $c<$Nb;
$c++) {
for ($c = 0; $c<$Nb; $c++) {
$state[$r][$c] ^= $w[$rnd*4+$c][$r];
}
}
@@ -65,8 +62,7 @@ class Aes
{
// apply SBox to state S [<5B>5.1.1]
for ($r = 0; $r<4; $r++) {
for ($c = 0; $c<$Nb;
$c++) {
for ($c = 0; $c<$Nb; $c++) {
$s[$r][$c] = self::$sBox[$s[$r][$c]];
}
}
@@ -78,12 +74,10 @@ class Aes
// shift row r of state S left by r bytes [<5B>5.1.2]
$t = array(4);
for ($r = 1; $r<4; $r++) {
for ($c = 0; $c<4;
$c++) {
for ($c = 0; $c<4; $c++) {
$t[$c] = $s[$r][($c+$r)%$Nb]; // shift into temp copy
}
for ($c = 0; $c<4;
$c++) {
for ($c = 0; $c<4; $c++) {
$s[$r][$c] = $t[$c]; // and copy back
}
} // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
@@ -133,21 +127,18 @@ class Aes
for ($i = $Nk; $i<($Nb*($Nr+1)); $i++) {
$w[$i] = array();
for ($t = 0; $t<4;
$t++) {
for ($t = 0; $t<4; $t++) {
$temp[$t] = $w[$i-1][$t];
}
if ($i % $Nk == 0) {
$temp = self::subWord(self::rotWord($temp));
for ($t = 0; $t<4;
$t++) {
for ($t = 0; $t<4; $t++) {
$temp[$t] ^= self::$rCon[$i/$Nk][$t];
}
} elseif ($Nk > 6 && $i%$Nk == 4) {
$temp = self::subWord($temp);
}
for ($t = 0; $t<4;
$t++) {
for ($t = 0; $t<4; $t++) {
$w[$i][$t] = $w[$i-$Nk][$t] ^ $temp[$t];
}
}
@@ -157,8 +148,7 @@ class Aes
private static function subWord($w)
{
// apply SBox to 4-byte word w
for ($i = 0; $i<4;
$i++) {
for ($i = 0; $i<4; $i++) {
$w[$i] = self::$sBox[$w[$i]];
}
return $w;
@@ -168,8 +158,7 @@ class Aes
{
// rotate 4-byte word w left by one byte
$tmp = $w[0];
for ($i = 0; $i<3;
$i++) {
for ($i = 0; $i<3; $i++) {
$w[$i] = $w[$i+1];
}
$w[3] = $tmp;

View File

@@ -32,8 +32,7 @@ class AesCtr extends Aes
// key expansion) - gives us well encrypted key
$nBytes = $nBits/8; // no bytes in key
$pwBytes = array();
for ($i = 0; $i<$nBytes;
$i++) {
for ($i = 0; $i<$nBytes; $i++) {
$pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
}
$key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
@@ -47,23 +46,19 @@ class AesCtr extends Aes
$nonceSec = floor($nonce/1000);
$nonceRnd = floor(rand(0, 0xffff));
for ($i = 0; $i<2;
$i++) {
for ($i = 0; $i<2; $i++) {
$counterBlock[$i] = self::urs($nonceMs, $i*8) & 0xff;
}
for ($i = 0; $i<2;
$i++) {
for ($i = 0; $i<2; $i++) {
$counterBlock[$i+2] = self::urs($nonceRnd, $i*8) & 0xff;
}
for ($i = 0; $i<4;
$i++) {
for ($i = 0; $i<4; $i++) {
$counterBlock[$i+4] = self::urs($nonceSec, $i*8) & 0xff;
}
// and convert it to a string to go on the front of the ciphertext
$ctrTxt = '';
for ($i = 0; $i<8;
$i++) {
for ($i = 0; $i<8; $i++) {
$ctrTxt .= chr($counterBlock[$i]);
}
@@ -77,12 +72,10 @@ class AesCtr extends Aes
for ($b = 0; $b<$blockCount; $b++) {
// set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
// done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
for ($c = 0; $c<4;
$c++) {
for ($c = 0; $c<4; $c++) {
$counterBlock[15-$c] = self::urs($b, $c*8) & 0xff;
}
for ($c = 0; $c<4;
$c++) {
for ($c = 0; $c<4; $c++) {
$counterBlock[15-$c-4] = self::urs($b/0x100000000, $c*8);
}
@@ -124,8 +117,7 @@ class AesCtr extends Aes
// use AES to encrypt password (mirroring encrypt routine)
$nBytes = $nBits/8; // no bytes in key
$pwBytes = array();
for ($i = 0; $i<$nBytes;
$i++) {
for ($i = 0; $i<$nBytes; $i++) {
$pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
}
$key = Aes::cipher($pwBytes, Aes::keyExpansion($pwBytes));
@@ -134,8 +126,7 @@ class AesCtr extends Aes
// recover nonce from 1st element of ciphertext
$counterBlock = array();
$ctrTxt = substr($ciphertext, 0, 8);
for ($i = 0; $i<8;
$i++) {
for ($i = 0; $i<8; $i++) {
$counterBlock[$i] = ord(substr($ctrTxt, $i, 1));
}
@@ -145,8 +136,7 @@ class AesCtr extends Aes
// separate ciphertext into blocks (skipping past initial 8 bytes)
$nBlocks = ceil((strlen($ciphertext)-8) / $blockSize);
$ct = array();
for ($b = 0; $b<$nBlocks;
$b++) {
for ($b = 0; $b<$nBlocks; $b++) {
$ct[$b] = substr($ciphertext, 8+$b*$blockSize, 16);
}
$ciphertext = $ct; // ciphertext is now array of block-length strings
@@ -156,12 +146,10 @@ class AesCtr extends Aes
for ($b = 0; $b<$nBlocks; $b++) {
// set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
for ($c = 0; $c<4;
$c++) {
for ($c = 0; $c<4; $c++) {
$counterBlock[15-$c] = self::urs($b, $c*8) & 0xff;
}
for ($c = 0; $c<4;
$c++) {
for ($c = 0; $c<4; $c++) {
$counterBlock[15-$c-4] = self::urs(($b+1)/0x100000000-1, $c*8) & 0xff;
}

View File

@@ -14,8 +14,8 @@ class DataReader
$sortData = $query->getSortingData();
$data = \Classes\BaseService::getInstance()->getData(
$table,
$query->getFieldMapping(),
json_encode($query->getFilters()),
null,
$query->getFilters(),
$query->getOrderBy(),
$sLimit,
json_encode($query->getColumns()),

View File

@@ -59,7 +59,7 @@ class DataQuery
}
/**
* @return array
* @return string
*/
public function getFieldMapping()
{
@@ -197,7 +197,7 @@ class DataQuery
}
/**
* @param array $fieldMapping
* @param string $fieldMapping
*/
public function setFieldMapping($fieldMapping)
{
@@ -205,9 +205,9 @@ class DataQuery
}
/**
* @param array $filters
* @param $filters
*/
public function setFilters(array $filters)
public function setFilters($filters)
{
$this->filters = $filters;
}
@@ -229,9 +229,9 @@ class DataQuery
}
/**
* @param bool $sortColumn
* @param string $sortColumn
*/
public function setSortColumn(bool $sortColumn)
public function setSortColumn($sortColumn)
{
$this->sortColumn = $sortColumn;
}

View File

@@ -0,0 +1,97 @@
<?php
namespace Classes;
class DomainAwareInputCleaner
{
public function cleanTableColumn($input)
{
if ($this->isEmpty($input) || $this->isValidColumnName($input)) {
return $input;
}
return '';
}
public function cleanMapping($mapping)
{
return $mapping;
}
public function cleanOrderBy($orderBy)
{
if (empty($orderBy)) {
return $orderBy;
}
$suffix = '';
if (strstr($orderBy, ' desc')) {
$suffix = ' desc';
$orderBy = str_replace(' desc', '', $orderBy);
}
if (!$this->cleanTableColumn($orderBy)) {
return '';
}
return $orderBy.$suffix;
}
public function cleanColumns($columns)
{
if (empty($columns)) {
return $columns;
}
$columnData = json_decode($columns, true);
foreach ($columnData as $column) {
if (!$this->isValidColumnName($column)) {
return '[]';
}
}
return $columns;
}
public function cleanFilters($filters)
{
if (empty($filters)) {
return $filters;
}
$filterData = json_decode($filters, true);
foreach ($filterData as $name => $value) {
if (!$this->isValidColumnName($name) || !$this->isValidFilterValue($value)) {
return '';
}
}
return $filters;
}
public function cleanSearch($searchTerm) {
if (!$this->isValidFilterValue($searchTerm)) {
return '';
}
return $searchTerm;
}
private function isEmpty($input)
{
return empty($input) || trim($input) === '';
}
private function isValidColumnName($input)
{
return !!preg_match('/^[a-zA-Z_]+$/', $input);
}
private function isValidFilterValue($input)
{
return !!preg_match('/^[-_: \p{L}]+$/u', $input);
}
}

View File

@@ -8,9 +8,10 @@
namespace Classes\Email;
use Classes\Crypt\AesCtr;
use Classes\PasswordManager;
use Classes\UIManager;
use Employees\Common\Model\Employee;
use Model\EmailLogEntry;
use Model\IceEmail;
use Users\Common\Model\User;
use Utils\LogManager;
@@ -145,7 +146,16 @@ abstract class EmailSender
$emailBody = str_replace("#_".$k."_#", $v, $emailBody);
}
return $this->sendMail($subject, $emailBody, $toEmail, $fromEmail, $user->email, $ccList, $bccList, APP_NAME);
return $this->sendEmailWithLogging(
$subject,
$emailBody,
$toEmail,
$fromEmail,
$user->email,
$ccList,
$bccList,
APP_NAME
);
}
public function sendEmailWithoutWrap($subject, $toEmail, $template, $params, $ccList = array(), $bccList = array())
@@ -181,7 +191,47 @@ abstract class EmailSender
$emailBody = str_replace("#_".$k."_#", $v, $emailBody);
}
$this->sendMail($subject, $emailBody, $toEmail, $fromEmail, $user->email, $ccList, $bccList);
$this->sendEmailWithLogging($subject, $emailBody, $toEmail, $fromEmail, $user->email, $ccList, $bccList);
}
protected function sendEmailWithLogging(
$subject,
$body,
$toEmail,
$fromEmail,
$replyToEmail = null,
$ccList = array(),
$bccList = array(),
$fromName = null
) {
$emailLogEntry = new EmailLogEntry();
$emailLogEntry->subject = $subject;
$emailLogEntry->toEmail = $toEmail;
$emailLogEntry->body = $body;
$emailLogEntry->cclist = implode(',', $ccList);
$emailLogEntry->bcclist = implode(',', $bccList);
$emailLogEntry->created = date('Y-m-d H:i:s');
$emailLogEntry->updated = date('Y-m-d H:i:s');
$result = $this->sendMail(
$subject,
$body,
$toEmail,
$fromEmail,
$replyToEmail,
$ccList,
$bccList,
$fromName
);
$emailLogEntry->status = $result ? 'Sent' : 'Failed';
$ok = $emailLogEntry->Save();
if (!$ok) {
LogManager::getInstance()->error('Error adding email log for '.json_encode([$toEmail, $subject, $body]));
}
return $result;
}
abstract protected function sendMail(
@@ -211,15 +261,8 @@ abstract class EmailSender
//$params['user'] = $user->first_name." ".$user->last_name;
$params['url'] = CLIENT_BASE_URL;
$newPassHash = array();
$newPassHash["CLIENT_NAME"] = CLIENT_NAME;
$newPassHash["oldpass"] = $user->password;
$newPassHash["email"] = $user->email;
$newPassHash["time"] = time();
$json = json_encode($newPassHash);
$encJson = PasswordManager::createPasswordRestKey($user);
$encJson = AesCtr::encrypt($json, $user->password, 256);
$encJson = urlencode($user->id."-".$encJson);
$params['passurl'] = CLIENT_BASE_URL."service.php?a=rsp&key=".$encJson;
$emailBody = file_get_contents(APP_BASE_PATH.'/templates/email/passwordReset.html');

View File

@@ -51,10 +51,11 @@ class PHPMailer extends EmailSender
}
$headers .= 'ReplyTo: ' . $replyToEmail . "\r\n";
$headers .= 'Ice-Mailer: PHP/' . phpversion();
return mail($toEmail, $subject, $body, $headers);
} catch (\Exception $e) {
LogManager::getInstance()->error("Error sending email:" . $e->getMessage());
LogManager::getInstance()->notifyException($e);
return false;
}
}

View File

@@ -83,6 +83,7 @@ class SMTPEmailSender extends EmailSender
return true;
} catch (\Exception $e) {
LogManager::getInstance()->error("Error sending email:" . $e->getMessage());
LogManager::getInstance()->notifyException($e);
return false;
}
}

View File

@@ -77,6 +77,7 @@ class SNSEmailSender extends EmailSender
return true;
} catch (\Exception $e) {
LogManager::getInstance()->error("Error sending email:" . $e->getMessage());
LogManager::getInstance()->notifyException($e);
return false;
}
}

View File

@@ -57,6 +57,7 @@ class SwiftMailer extends EmailSender
return $mailer->send($mail);
} catch (\Exception $e) {
LogManager::getInstance()->error("Error sending email:" . $e->getMessage());
LogManager::getInstance()->notifyException($e);
return false;
}
}

View File

@@ -35,6 +35,7 @@ class FileService
return null;
} catch (\Exception $e) {
LogManager::getInstance()->notifyException($e);
return null;
}
}
@@ -51,6 +52,7 @@ class FileService
}
$this->memcache->set($key, $data, $expire);
} catch (\Exception $e) {
LogManager::getInstance()->notifyException($e);
}
}
@@ -144,6 +146,7 @@ class FileService
$profile->image = $expireUrl;
} catch (\Exception $e) {
LogManager::getInstance()->error("Error generating profile image: ".$e->getMessage());
LogManager::getInstance()->notifyException($e);
if ($profile->gender == 'Female') {
$profile->image = BASE_URL."images/user_female.png";
} else {

View File

@@ -49,7 +49,7 @@ class LDAPManager
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
// verify user and password
$bind = @ldap_bind($ldap, $managerDN, $managerPassword);
$bind = ldap_bind($ldap, $managerDN, $managerPassword);
LogManager::getInstance()->debug("LDAP Manager Bind:".print_r($bind, true));
@@ -60,6 +60,7 @@ class LDAPManager
$result = ldap_search($ldap, $ldap_dn, $filter);
LogManager::getInstance()->debug("LDAP Search Result:".print_r($result, true));
if (!$result) {
LogManager::getInstance()->error("Unable to search LDAP server");
exit("Unable to search LDAP server");
}
$entries = ldap_get_entries($ldap, $result);

View File

@@ -52,7 +52,6 @@ class LanguageManager
$user = BaseService::getInstance()->getCurrentUser();
if (empty($user) || empty($user->lang) || $user->lang == "NULL") {
$lang = SettingsManager::getInstance()->getSetting('System: Language');
LogManager::getInstance()->info("System Lang:".$lang);
} else {
$supportedLang = new SupportedLanguage();
$supportedLang->Load("id = ?", array($user->lang));

View File

@@ -41,6 +41,8 @@ class Macaw
array_push(self::$routes, $uri);
array_push(self::$methods, strtoupper($method));
array_push(self::$callbacks, $callback);
return $uri;
}
/**

View File

@@ -0,0 +1,57 @@
<?php
namespace Classes;
class MemoryCacheService implements CacheService
{
protected $appName = null;
protected $store = [];
public function __construct($appName)
{
$this->appName = $appName;
}
protected function getAppKey($keyData)
{
return sprintf('%s-%s', $this->appName, implode('-', $keyData));
}
public function setDBQuery($entity, $query, $params, $result, $ttl = 600)
{
$this->store[$this->getAppKey($entity, $query, implode('-', $params))] = serialize($result);
}
public function getDBQuery($entity, $query, $params)
{
$data = $this->store[$this->getAppKey([$entity, $query, implode('-', $params)])];
if (empty($data)) {
return null;
}
$data = unserialize($data);
if (empty($data)) {
return null;
}
return $data;
}
public function deleteByEntity($entity)
{
$this->deleteByPrefix($entity.'-');
$newStore = [];
foreach ($this->store as $key => $val) {
if (substr($key, 0, strlen($entity.'-')) === $entity.'-') {
continue;
}
$newStore[$key] = $val;
}
$this->store = $newStore;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Classes;
class ModuleAccess
{
protected $name;
protected $group;
/**
* ModuleAccess constructor.
* @param $name
* @param $group
*/
public function __construct($name, $group)
{
$this->name = $name;
$this->group = $group;
}
/**
* @return mixed
*/
public function getName()
{
return $this->name;
}
/**
* @return mixed
*/
public function getGroup()
{
return $this->group;
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Classes;
use Modules\Common\Model\Module;
class ModuleAccessService
{
protected $moduleMap = [];
protected $moduleIdMap = [];
private static $me = null;
private function __construct()
{
}
public static function getInstance()
{
if (empty(self::$me)) {
self::$me = new ModuleAccessService();
}
return self::$me;
}
public function setModule($name, $group, $module)
{
$this->moduleMap[$group.'-'.$name] = $module;
$this->moduleIdMap[$module->id] = $module;
}
public function getModule($name, $group)
{
return $this->moduleMap[$group.'-'.$name];
}
public function getModules()
{
return array_values($this->moduleMap);
}
public function isModuleEnabledForUser($moduleId, $user)
{
$module = $this->moduleIdMap[$moduleId];
$moduleUserLevels = json_decode($module->user_levels, true);
$moduleUserRoles = json_decode($module->user_roles, true);
$userRoles = json_decode($user->user_roles, true);
if (empty($moduleUserLevels)) {
return false;
}
if (in_array($user->user_level, PermissionManager::RESTRICTED_USER_LEVELS)) {
if (empty($userRoles)) {
return false;
}
$baseUserLevel = str_replace('Restricted ', '', $user->user_level);
// In this case base user level should have access to the module
if (!in_array($baseUserLevel, $moduleUserLevels)) {
return false;
}
return count(array_intersect($userRoles, $moduleUserRoles)) > 0;
}
return in_array($user->user_level, $moduleUserLevels);
}
}

View File

@@ -0,0 +1,138 @@
<?php
namespace Classes;
use Classes\Crypt\AesCtr;
use Users\Common\Model\User;
use Utils\CalendarTools;
class PasswordManager
{
public static function verifyPassword($password, $hash)
{
$result = password_verify($password, $hash);
if ($result) {
return true;
}
if (strlen($hash) === 32) {
return md5($password) === $hash;
}
return false;
}
public static function createPasswordHash($password)
{
return password_hash($password, PASSWORD_BCRYPT, ['cost' => 13]);
}
public static function passwordChangeWaitingTimeMinutes($user)
{
if (empty($user->last_password_requested_at)) {
$user->last_password_requested_at = date('Y-m-d H:i:s');
$user->Save();
return 0;
}
$diff = CalendarTools::getTimeDiffInMinutes($user->last_password_requested_at, date('Y-m-d H:i:s'));
if ($diff < 1) {
return ceil($diff);
}
$user->last_password_requested_at = date('Y-m-d H:i:s');
$user->Save();
return 0;
}
public static function createPasswordRestKey($user)
{
$newPassHash = array();
$newPassHash["client"] = CLIENT_NAME;
$newPassHash["email"] = $user->email;
$newPassHash["time"] = date('Y-m-d H:i:s');
$json = json_encode($newPassHash);
$encJson = AesCtr::encrypt($json, $user->password, 256);
return urlencode(AesCtr::encrypt($user->id, APP_PASSWORD, 256).'-'.$encJson);
}
public static function verifyPasswordRestKey($key)
{
$arr = explode("-", $key);
$userId = AesCtr::decrypt($arr[0], APP_PASSWORD, 256);
$user = new User();
$user->Load("id = ?", array($userId));
if (empty($user->id)) {
return false;
}
array_shift($arr);
$data = AesCtr::decrypt(implode('', $arr), $user->password, 256);
if (empty($data)) {
return false;
}
$data = json_decode($data, true);
if (empty($data)) {
return false;
}
if ($data['client'] != CLIENT_NAME || $data['email'] != $user->email) {
return false;
}
if (CalendarTools::getTimeDiffInMinutes($data['time'], date('Y-m-d H:i:s')) < 30) {
return $user;
}
return false;
}
public static function isQualifiedPassword($password)
{
if (strlen($password) < 8) {
$error = "Password too short";
return new IceResponse(IceResponse::ERROR, $error);
}
if (strlen($password) > 20) {
$error = "Password too long";
return new IceResponse(IceResponse::ERROR, $error);
}
if (!preg_match("#[0-9]+#", $password)) {
$error = "Password must include at least one number";
return new IceResponse(IceResponse::ERROR, $error);
}
if (!preg_match("#[a-z]+#", $password)) {
$error = "Password must include at least one lowercase letter";
return new IceResponse(IceResponse::ERROR, $error);
}
if (!preg_match("#[A-Z]+#", $password)) {
$error = "Password must include at least one uppercase letter";
return new IceResponse(IceResponse::ERROR, $error);
}
if (!preg_match("#\W+#", $password)) {
$error = "Password must include at least one symbol";
return new IceResponse(IceResponse::ERROR, $error);
}
return new IceResponse(IceResponse::SUCCESS);
}
}

View File

@@ -14,6 +14,13 @@ use Model\BaseModel;
class PermissionManager
{
const RESTRICTED_USER_LEVELS = ['Restricted Admin', 'Restricted Manager', 'Restricted Employee'];
public function isRestrictedUserLevel($userLevel)
{
return in_array($userLevel, self::RESTRICTED_USER_LEVELS);
}
public static function manipulationAllowed($employeeId, BaseModel $object)
{
$subIds = self::getSubordinateIds($employeeId, $object->allowIndirectMapping());

View File

@@ -0,0 +1,106 @@
<?php
namespace Classes;
use Predis\Client;
class RedisCacheService implements CacheService
{
protected $client = null;
protected $appName = null;
public function __construct($uri, $appName)
{
$this->uri = $uri;
$this->appName = $appName;
}
protected function getClient()
{
if ($this->client === null && !empty($this->uri)) {
$this->client = new Client($this->uri);
}
return $this->client;
}
protected function getAppKey($keyData)
{
return sprintf('%s-%s', $this->appName, implode('-', $keyData));
}
public function setDBQuery($entity, $query, $params, $result, $ttl = 600)
{
/** @var Client $client */
$client = $this->getClient();
if ($client == null) {
return null;
}
$client->set($this->getAppKey([$entity, $query, implode('-', $params)]), base64_encode(serialize($result)));
$client->expire($this->getAppKey([$query, $params]), $ttl);
}
public function getDBQuery($entity, $query, $params)
{
/** @var Client $client */
$client = $this->getClient();
if ($client == null) {
return null;
}
$base64 = $client->get($this->getAppKey([$entity, $query, implode('-', $params)]));
if (empty($base64)) {
return null;
}
$data = unserialize(base64_decode($base64));
if (empty($data)) {
return null;
}
return $data;
}
public function deleteDatabaseEntity($table, $id)
{
/** @var Client $client */
$client = $this->getClient();
if ($client == null) {
return null;
}
$client->del([$this->getAppKey([$table, $id])]);
}
public function deleteQuery($query)
{
/** @var Client $client */
$client = $this->getClient();
if ($client == null) {
return null;
}
$client->del([$this->getAppKey([$query])]);
}
protected function deleteByPrefix($prefix)
{
/** @var Client $client */
$client = $this->getClient();
if ($client == null) {
return null;
}
$list = $client->keys($this->getAppKey([$prefix]).'*');
if (!empty($list)) {
$client->del($list);
}
}
public function deleteByEntity($entity)
{
$this->deleteByPrefix($entity.'-');
}
}

View File

@@ -5,11 +5,38 @@ use Classes\Data\DataReader;
use Classes\Data\Query\DataQuery;
use Classes\Upload\Uploader;
use Employees\Common\Model\Employee;
use Model\BaseModel;
use Users\Common\Model\User;
use Utils\SessionUtils;
class RestEndPoint
{
/*
200
GET/PUT
Response entity details or list of entities.
201
POST
To create a new entity.
400
GET/POST/PUT/DELETE
Request payload and query params validation error
401
GET/POST/PUT/DELETE
Authentication error
403
GET/POST/PUT/DELETE
Authorization issue
404
GET/POST/PUT/DELETE
We dont have the endpoint
*/
const RESPONSE_ERR_ENTITY_NOT_FOUND = 'Entity not found';
const RESPONSE_ERR_PERMISSION_DENIED = 'Permission denied';
const RESPONSE_ERR_UNPROCESSABLE = 'Unprocessable Entity';
@@ -19,6 +46,8 @@ class RestEndPoint
const ELEMENT_NAME = '';
protected $cachedObjects = [];
public function getModelObject($id)
{
return false;
@@ -56,21 +85,38 @@ class RestEndPoint
return new IceResponse(IceResponse::SUCCESS);
}
public function process($type, $parameters = [])
public function process($type, $parameters = [], $requireAccessToken = true)
{
if ($parameters === null) {
$parameters = [];
}
if (!is_array($parameters)) {
$parameters = [$parameters];
}
$accessTokenValidation = $this->validateAccessToken();
if (!empty($accessTokenValidation) && $accessTokenValidation->getStatus() == IceResponse::ERROR) {
$resp = $accessTokenValidation;
} else {
if ($requireAccessToken) {
$accessTokenValidation = $this->validateAccessToken();
if (!empty($accessTokenValidation) && $accessTokenValidation->getStatus() == IceResponse::ERROR) {
$resp = $accessTokenValidation;
return $this->sendResponse($resp);
}
BaseService::getInstance()->setCurrentUser($accessTokenValidation->getData());
SessionUtils::saveSessionObject('user', $accessTokenValidation->getData());
array_unshift($parameters, $accessTokenValidation->getData());
$resp = call_user_func_array(array($this, $type), $parameters);
} else {
array_unshift($parameters, new User());
}
$resp = call_user_func_array(array($this, $type), $parameters);
return $this->sendResponse($resp);
}
protected function sendResponse($resp)
{
header('Content-Type: application/json');
if ($resp->getStatus() == IceResponse::SUCCESS && $resp->getCode() == null) {
@@ -91,25 +137,64 @@ class RestEndPoint
);
$this->printResponse(array("error" => [$messages]));
}
return true;
}
/**
* @param BaseModel $obj
* @param $map
* @return mixed
*/
protected function enrichElement($obj, $map)
{
if (!empty($map)) {
foreach ($map as $k => $v) {
if ($obj->$k !== null) {
$obj->$k = [
'type' => $v[0],
$v[1] => $obj->$k,
'display' => $obj->{$k . '_Name'}
];
} else {
unset($obj->$k);
}
unset($obj->{$k . '_Name'});
if (empty($map)) {
return $obj;
}
foreach ($map as $k => $v) {
$fTable = BaseService::getInstance()->getFullQualifiedModelClassName($v[0]);
$tObj = new $fTable();
$tObjArr = $tObj->Find($v[1] . "= ?", [$obj->$k], true);
if (!is_array($tObjArr) || empty($tObjArr[0])) {
continue;
}
$obj->$k = [
'type' => $v[0],
$v[1] => $obj->$k,
'display' => $this->getCombinedValue($v[2], $tObjArr[0])
];
}
return $obj;
}
protected function enrichElements($items, $map)
{
return array_map(function ($item) use ($map) {
return $this->enrichElement($item, $map);
}, $items);
}
protected function getCombinedValue($nameField, $targetObject)
{
$values = explode("+", $nameField);
if (count($values) == 1) {
return $targetObject->{$nameField};
}
$objVal = '';
foreach ($values as $value) {
if ($objVal != "") {
$objVal .= " ";
}
if (substr($value, 0, 1) !== ':') {
$objVal .= $targetObject->{$value};
} else {
$objVal .= substr($value, 1);
}
}
return $obj;
return $objVal;
}
protected function cleanObject($obj)
@@ -164,6 +249,10 @@ class RestEndPoint
$output = array();
$columns = $query->getColumns();
foreach ($data as $item) {
if (!empty($query->getFieldMapping())) {
$map = json_decode($query->getFieldMapping(), true);
$item = $this->enrichElement($item, $map);
}
if (!empty($columns)) {
$obj = new \stdClass();
foreach ($columns as $column) {

View File

@@ -37,6 +37,7 @@ class S3FileSystem
));
} catch (\Exception $e) {
LogManager::getInstance()->error($e->getMessage());
LogManager::getInstance()->error($e);
return null;
}
@@ -60,7 +61,8 @@ class S3FileSystem
'Key' => $key
));
} catch (\Exception $e) {
LogManager::getInstance()->info($e->getMessage());
LogManager::getInstance()->error($e->getMessage());
LogManager::getInstance()->notifyException($e);
return null;
}

View File

@@ -150,7 +150,7 @@ class UIManager
}
$menuItems[] = new MenuItemTemplate('menuButtonNotification', array());
if ($this->user->user_level == "Admin") {
if ($this->user->user_level == 'Admin') {
$menuItems[] = new MenuItemTemplate('menuButtonSwitchProfile', array());
}
@@ -197,7 +197,7 @@ class UIManager
));
}
if ($this->user->user_level == "Admin") {
if ($this->user->user_level == 'Admin') {
$other = '';
if (class_exists('\\Classes\\ProVersion')) {
$pro = new ProVersion();

View File

@@ -0,0 +1,29 @@
<?php
namespace Classes\Upload;
class TempFile
{
protected $data;
public function __construct($data)
{
$this->data = $data;
}
public function save($path)
{
if (!move_uploaded_file($this->data['file']['tmp_name'], $path)) {
return false;
}
return true;
}
public function getName()
{
return $this->data['file']['name'];
}
public function getSize()
{
return $this->data['file']['size'];
}
}

View File

@@ -0,0 +1,159 @@
<?php
namespace Classes\Upload;
use Classes\BaseService;
use Classes\FileService;
use Classes\IceResponse;
use Classes\S3FileSystem;
use Classes\SettingsManager;
use Model\File;
use Utils\LogManager;
class Uploader
{
private $allowedExtensions = array();
private $sizeLimit = 10485760;
private $file;
public function __construct($file, array $allowedExtensions = array(), $sizeLimit = 10485760)
{
$allowedExtensions = array_map("strtolower", $allowedExtensions);
$this->allowedExtensions = $allowedExtensions;
$this->sizeLimit = $sizeLimit;
$this->file = $file;
}
protected function handleUpload($uploadDirectory, $saveFileName, $replaceOldFile = false)
{
if (!is_writable($uploadDirectory)) {
return new IceResponse(
IceResponse::ERROR,
"Server error. Upload directory ($uploadDirectory) is not writable"
);
}
if (!$this->file) {
return new IceResponse(
IceResponse::ERROR,
'No files were uploaded.'
);
}
$size = $this->file->getSize();
LogManager::getInstance()->info('file size ='.$size);
LogManager::getInstance()->info('file size limit ='.$this->sizeLimit);
if ($size == 0) {
return new IceResponse(
IceResponse::ERROR,
'File is empty'
);
}
if ($size > $this->sizeLimit) {
return new IceResponse(
IceResponse::ERROR,
'File is too large'
);
}
$pathinfo = pathinfo($this->file->getName());
$ext = $pathinfo['extension'];
if ($this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions)) {
$these = implode(', ', $this->allowedExtensions);
return new IceResponse(
IceResponse::ERROR,
'File has an invalid extension, it should be one of '. $these . '.'
);
}
$saveFileName = $saveFileName.'.'.strtolower($ext);
$finalFileLocation = $uploadDirectory . $saveFileName;
if ($this->file->save($finalFileLocation)) {
$arr = explode("/", $finalFileLocation);
return new IceResponse(
IceResponse::SUCCESS,
$arr[count($arr)-1]
);
//return array('success'=>1,'filename'=>$arr[count($arr)-1],'error'=>'');
} else {
return new IceResponse(
IceResponse::ERROR,
'The upload was cancelled, or server error encountered'
);
}
}
public static function upload($postData, $fileData)
{
//Generate File Name
$saveFileName = $postData['file_name'];
$saveFileName = str_replace("..", "", $saveFileName);
$saveFileName = str_replace("/", "", $saveFileName);
if (stristr($saveFileName, ".php")) {
$saveFileName = str_replace(".php", "", $saveFileName);
}
if (empty($saveFileName) || $saveFileName == "_NEW_") {
$saveFileName = microtime();
$saveFileName = str_replace(".", "", $saveFileName);
$saveFileName = str_replace(" ", "", $saveFileName);
}
$file = new File();
$file->Load("name = ?", array($saveFileName));
$allowedExtensions = explode(',', "csv,doc,xls,docx,xlsx,txt,ppt,pptx,rtf,pdf,xml,jpg,bmp,gif,png,jpeg");
// max file size in bytes
$sizeLimit =MAX_FILE_SIZE_KB * 1024;
$uploader = new Uploader(new TempFile($fileData), $allowedExtensions, $sizeLimit);
$result = $uploader->handleUpload(CLIENT_BASE_PATH.'data/', $saveFileName);
if ($result->getStatus() !== IceResponse::SUCCESS) {
return $result;
}
$uploadFilesToS3 = SettingsManager::getInstance()->getSetting("Files: Upload Files to S3");
$uploadFilesToS3Key = SettingsManager::getInstance()->getSetting("Files: Amazon S3 Key for File Upload");
$uploadFilesToS3Secret = SettingsManager::getInstance()->getSetting(
"Files: Amazone S3 Secret for File Upload"
);
$s3Bucket = SettingsManager::getInstance()->getSetting("Files: S3 Bucket");
$s3WebUrl = SettingsManager::getInstance()->getSetting("Files: S3 Web Url");
$localFile = CLIENT_BASE_PATH.'data/'.$result->getData();
$uploadedFileSize = filesize($localFile);
if ($uploadFilesToS3.'' == '1' && !empty($uploadFilesToS3Key) && !empty($uploadFilesToS3Secret) &&
!empty($s3Bucket) && !empty($s3WebUrl)) {
$uploadName = CLIENT_NAME."/".$result->getData();
LogManager::getInstance()->info("Upload file to s3:".$uploadName);
LogManager::getInstance()->info("Local file:".$localFile);
LogManager::getInstance()->info("Local file size:".$uploadedFileSize);
$s3FileSys = new S3FileSystem($uploadFilesToS3Key, $uploadFilesToS3Secret);
$res = $s3FileSys->putObject($s3Bucket, $uploadName, $localFile, 'authenticated-read');
LogManager::getInstance()->info("Response from s3 file sys:".print_r($res, true));
unlink($localFile);
}
$file->name = $saveFileName;
$file->filename = $result->getData();
$signInMappingField = SIGN_IN_ELEMENT_MAPPING_FIELD_NAME;
$file->$signInMappingField = $postData['user']=="_NONE_"?null:$postData['user'];
$file->file_group = $postData['file_group'];
$file->size = $uploadedFileSize;
$file->size_text = FileService::getInstance()->getReadableSize($uploadedFileSize);
$file->Save();
return new IceResponse(
IceResponse::SUCCESS,
$saveFileName
);
}
}

View File

@@ -2,6 +2,7 @@
namespace Company\Common\Model;
use Classes\IceResponse;
use Classes\ModuleAccess;
use Employees\Common\Model\Employee;
use Model\BaseModel;
@@ -16,7 +17,7 @@ class CompanyStructure extends BaseModel
public function getManagerAccess()
{
return array("get","element","save","delete");
return array("get","element");
}
public function getUserAccess()
@@ -24,6 +25,14 @@ class CompanyStructure extends BaseModel
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('employees', 'user'),
];
}
public function validateSave($obj)
{
if ($obj->id == $obj->parent && !empty($obj->parent)) {

View File

@@ -2,6 +2,7 @@
namespace Company\Common\Model;
use Model\BaseModel;
use Utils\LogManager;
class Timezone extends BaseModel
{
@@ -22,6 +23,11 @@ class Timezone extends BaseModel
return array("get","element");
}
public function getAnonymousAccess()
{
return array("get","element");
}
public function getTimezonesWithOffset()
{
$tz = new Timezone();
@@ -34,6 +40,7 @@ class Timezone extends BaseModel
$tz->details = sprintf("(%s) %s", $this->formatOffset($z->getOffset($c)), $tz->name);
$modifiedTimeZones[] = $tz;
} catch (\Exception $e) {
LogManager::getInstance()->notifyException($e);
}
}

View File

@@ -22,6 +22,8 @@ abstract class AbstractDataImporter implements DataImporter
protected $columnsCompeted = array();
protected $relatedColumns = array();
protected $status = IceResponse::SUCCESS;
public function getResult()
{
return $this->rowObjects;
@@ -37,24 +39,48 @@ abstract class AbstractDataImporter implements DataImporter
$columns = $this->dataImport->columns;
$headers = json_decode($columns);
$counter = 0;
$expectedColumnOrder = [];
$actualColumnOrder = [];
$headerValidationFailed = false;
if (count($headers) != count($data)) {
if ($headerValidationFailed) {
return new IceResponse(
IceResponse::ERROR,
[
'Column count in the file do not match the header count'
]
);
}
}
foreach ($headers as $testColumn) {
$expectedColumnOrder[] = $testColumn->name;
$actualColumnOrder[] = $data[$counter];
if (trim($testColumn->name) !== trim($data[$counter])) {
$headerValidationFailed = true;
}
$counter++;
}
if ($headerValidationFailed) {
return new IceResponse(
IceResponse::ERROR,
[
'expected' => $expectedColumnOrder,
'actual'=> $actualColumnOrder
]
);
}
$counter = 0;
foreach ($headers as $column) {
$this->headerMapping[] = $column;
if ($column->idField == "Yes") {
$this->primaryKeyColumn = $counter;
}
//Update related columns
if (($column->type == "Reference" || $column->type == "Attached") && $column->isKeyField == "Yes") {
$this->relatedColumns[$counter] = array();
for ($i = 0; $i< count($headers); $i++) {
$columnNew = $headers[$i];
if ($columnNew->id != $column->id &&
$columnNew->dependOn == $column->dependOn && $column->dependOn != "NULL") {
$this->relatedColumns[$counter][$i] = $columnNew;
}
}
}
$counter++;
}
@@ -63,6 +89,7 @@ abstract class AbstractDataImporter implements DataImporter
$this->objectKeys = $obj->getObjectKeys();
$this->updateCustomFields();
return new IceResponse(IceResponse::SUCCESS);
}
public function setDataImportId($dataImportId)
@@ -74,26 +101,13 @@ abstract class AbstractDataImporter implements DataImporter
public function updateCustomFields()
{
$customField = new CustomField();
$customFields = $customField->Find("type = ?", array($this->getModelObject()));
$customFields = $customField->Find("type = ?", array($this->getModelObjectName()));
$this->customFields = array();
foreach ($customFields as $cf) {
$this->customFields[$cf->name] = $cf;
}
}
public function addCustomField($column)
{
$customField = new CustomField();
$customField->type = $this->getModelObject();
$customField->name = $column->name;
$customField->display = "Form";
$customField->field_type = "text";
$customField->field_label = $column->title;
$customField->field_validation = "none";
$customField->display_order = 0;
$customField->Save();
}
public function markCellCompleted($row, $col)
{
if (!isset($this->columnsCompeted[$row])) {
@@ -136,48 +150,15 @@ abstract class AbstractDataImporter implements DataImporter
}
}
//Check for non existing column names
if (!isset($this->objectKeys[$headerColumn->name])) {
if (!isset($this->customFields[$headerColumn->name])) {
$this->addCustomField($headerColumn);
$this->updateCustomFields();
}
}
if ($headerColumn->type == "Normal") {
$this->rowObjects[$row]->{$headerColumn->name} = $data;
} elseif ($headerColumn->type == "Reference" || $headerColumn->type == "Attached") {
if ($headerColumn->isKeyField == "Yes") {
$hcClass = BaseService::getInstance()->getFullQualifiedModelClassName($headerColumn->dependOn);
$hcField = $headerColumn->dependOnField;
/* @var \Model\BaseModel $hcObject */
$hcObject = new $hcClass();
if ($headerColumn->type == "Attached" && !empty($this->rowObjects[$row]->id)) {
$hcObject->Load("$hcField = ? and employee = ?", array($data,$this->rowObjects[$row]->id));
} else {
$hcObject->Load("$hcField = ?", array($data));
}
$hcObject->{$hcField} = $data;
foreach ($this->relatedColumns[$column] as $key => $val) {
$tempValName = $val->name;
if (strstr($val->name, "/")) {
$tempValName = explode("/", $val->name)[1];
}
$hcObject->{$tempValName} = $allData[$key];
$this->markCellCompleted($row, $key);
}
if ($headerColumn->type == "Reference") {
$hcObject->Save();
} else {
if (!isset($this->attachedObjects[$row])) {
$this->attachedObjects[$row] = array();
}
$this->attachedObjects[$row][] = $hcObject;
}
$this->rowObjects[$row]->{$headerColumn->name} = $hcObject->id;
}
} elseif ($headerColumn->type == "Reference") {
$hcClass = BaseService::getInstance()->getFullQualifiedModelClassName($headerColumn->dependOn);
$hcField = $headerColumn->dependOnField;
/* @var \Model\BaseModel $hcObject */
$hcObject = new $hcClass();
$hcObject->Load("$hcField = ?", array($data));
$this->rowObjects[$row]->{$headerColumn->name} = $hcObject->id;
}
$this->markCellCompleted($row, $column);
@@ -215,20 +196,10 @@ abstract class AbstractDataImporter implements DataImporter
foreach ($this->rowObjects[$row] as $k => $v) {
if (isset($customFields[$k])) {
BaseService::getInstance()->customFieldManager
->addCustomField($class, $this->rowObjects[$row]->id, $k, $v);
->addCustomField($this->getModelObjectName(), $this->rowObjects[$row]->id, $k, $v);
$result['CustomFields'][] = array($class, $this->rowObjects[$row]->id, $k, $v);
}
}
if (!empty($this->attachedObjects[$row])) {
/* @var \Model\BaseModel $aObj */
foreach ($this->attachedObjects[$row] as $aObj) {
$aObj->employee = $this->rowObjects[$row]->id;
$aObj->Save();
$result['attachedObjects'][] = $aObj;
}
}
}
} else {
$result['Error'] = "Duplicate Object Found";
@@ -238,6 +209,10 @@ abstract class AbstractDataImporter implements DataImporter
}
abstract public function getModelObject();
abstract public function getModelObjectName();
public function setModelObjectName($name)
{
}
public function isDuplicate($obj)
{
return false;
@@ -264,7 +239,12 @@ abstract class AbstractDataImporter implements DataImporter
$cells = str_getcsv($line, ",");
if ($headerProcessed === false) {
$this->setDataImportId($dataImportId);
$this->processHeader($cells);
$result = $this->processHeader($cells);
if ($result->getStatus() === IceResponse::ERROR) {
$this->status = IceResponse::ERROR;
$this->rowObjects = $result->getData();
return $result->getData();
}
$headerProcessed = true;
} else {
$result = $this->processDataRow($counter, $cells);
@@ -278,6 +258,6 @@ abstract class AbstractDataImporter implements DataImporter
public function getLastStatus()
{
return IceResponse::SUCCESS;
return $this->status;
}
}

View File

@@ -44,10 +44,12 @@ class DataActionManager extends SubActionManager
$processClass = '\\Data\Admin\Import\\'.$dataImport->dataType;
$processObj = new $processClass();
$processObj->setModelObjectName($dataImport->objectType);
$res = $processObj->process($data, $dataImport->id);
if ($processObj->getLastStatus() === IceResponse::SUCCESS) {
$dataFile->status = "Processed";
} else {
$dataFile->status = "Failed";
}
$dataFile->details = json_encode($res, JSON_PRETTY_PRINT);
$dataFile->Save();
@@ -57,4 +59,29 @@ class DataActionManager extends SubActionManager
private function processHeader($dataImportId, $data)
{
}
public function downloadTemplate($req)
{
$dataImport = new DataImport();
$dataImport->Load("id =?", array($req->id));
$columns = json_decode($dataImport->columns);
$headers = [];
$sample = [];
foreach ($columns as $column) {
$headers[] = $column->name;
$sample[] = $column->sampleValue;
}
$output = fopen('php://output', 'w');
header('Content-Type:application/csv');
header('Content-Disposition:attachment;filename='.$dataImport->name.'.csv');
fputcsv($output, $headers);
fputcsv($output, $sample);
fclose($output);
ob_flush();
flush();
}
}

View File

@@ -14,6 +14,11 @@ class AttendanceDataImporter extends AbstractDataImporter
return "\\Attendance\\Common\\Model\\Attendance";
}
public function getModelObjectName()
{
return 'Attendance';
}
public function fixBeforeSave($object, $data)
{
return $object;

View File

@@ -0,0 +1,34 @@
<?php
namespace Data\Admin\Import;
use Classes\BaseService;
use Data\Admin\Api\AbstractDataImporter;
class CommonDataImporter extends AbstractDataImporter
{
protected $processed = array();
protected $modelObjectName;
public function getModelObject()
{
return BaseService::getInstance()->getFullQualifiedModelClassName($this->modelObjectName);
}
public function getModelObjectName()
{
return $this->modelObjectName;
}
public function setModelObjectName($name)
{
return $this->modelObjectName = $name;
}
public function fixBeforeSave($object, $data)
{
return $object;
}
}

View File

@@ -13,6 +13,11 @@ class EmployeeDataImporter extends AbstractDataImporter
return "\\Employees\\Common\\Model\\Employee";
}
public function getModelObjectName()
{
return 'Employee';
}
public function fixBeforeSave($object, $data)
{

View File

@@ -315,4 +315,8 @@ class PayrollDataImporter implements DataImporter
{
return $this->lastStatus;
}
public function setModelObjectName($name)
{
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Data\Admin\Import;
use Data\Admin\Api\AbstractDataImporter;
class UserDataImporter extends AbstractDataImporter
{
protected $processed = array();
public function getModelObject()
{
return "\\Users\\Common\\Model\\User";
}
public function getModelObjectName()
{
return 'User';
}
public function fixBeforeSave($object, $data)
{
if (empty($object->password)) {
$object->password = md5($object->password);
}
return $object;
}
}

View File

@@ -1,6 +1,7 @@
<?php
namespace Data\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class DataImport extends BaseModel
@@ -16,4 +17,11 @@ class DataImport extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('data', 'admin'),
];
}
}

View File

@@ -2,6 +2,7 @@
namespace Data\Common\Model;
use Classes\IceResponse;
use Classes\ModuleAccess;
use Model\BaseModel;
class DataImportFile extends BaseModel
@@ -25,4 +26,11 @@ class DataImportFile extends BaseModel
}
return new IceResponse(IceResponse::SUCCESS, $obj);
}
public function getModuleAccess()
{
return [
new ModuleAccess('data', 'admin'),
];
}
}

View File

@@ -2,6 +2,7 @@
namespace Dependents\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class EmployeeDependent extends BaseModel
@@ -27,4 +28,12 @@ class EmployeeDependent extends BaseModel
{
return array("element","save","delete");
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('employees', 'user'),
];
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Documents\Admin\Api;
use Classes\AbstractModuleManager;
class DocumentsAdminManager extends AbstractModuleManager
{
public function initializeUserClasses()
{
}
public function initializeFieldMappings()
{
$this->addFileFieldMapping('EmployeeDocument', 'attachment', 'name');
}
public function initializeDatabaseErrorMappings()
{
$this->addDatabaseErrorMapping(
'CONSTRAINT `Fk_EmployeeDocuments_Documents` FOREIGN KEY',
'Can not delete Document Type, users have already uploaded these types of documents'
);
}
public function setupModuleClassDefinitions()
{
$this->addModelClass('Document');
$this->addModelClass('CompanyDocument');
$this->addModelClass('EmployeeDocument');
$this->addModelClass('EmployeeDocumentNotification');
}
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* Created by PhpStorm.
* User: Thilina
* Date: 8/19/17
* Time: 8:25 AM
*/
namespace Documents\Common\Model;
use Classes\BaseService;
use Classes\FileService;
use Classes\IceResponse;
use Classes\ModuleAccess;
use Employees\Common\Model\Employee;
use Model\BaseModel;
class CompanyDocument extends BaseModel
{
public $table = 'CompanyDocuments';
public function getAdminAccess()
{
return array("get","element","save","delete");
}
public function getManagerAccess()
{
return array("get","element");
}
public function getUserAccess()
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('documents', 'admin'),
new ModuleAccess('documents', 'user'),
];
}
// @codingStandardsIgnoreStart
public function Find($whereOrderBy, $bindarr = false, $pkeysArr = false, $extra = array())
{
// @codingStandardsIgnoreEnd
$res = parent::Find($whereOrderBy, $bindarr, $pkeysArr, $extra);
$user = BaseService::getInstance()->getCurrentUser();
if ($user->user_level == 'Admin') {
foreach ($res as $entry) {
$file = FileService::getInstance()->getFileData($entry->attachment);
$entry->type = $file->type;
$entry->size = $file->size_text;
}
return $res;
}
$emp = BaseService::getInstance()->getCurrentProfileId();
$employee = new Employee();
$employee->Load("id = ?", array($emp));
$data = array();
foreach ($res as $entry) {
if ($entry->status != 'Active') {
continue;
}
$file = FileService::getInstance()->getFileData($entry->attachment);
$entry->type = $file->type;
$entry->size = $file->size_text;
if (!empty($entry->share_departments)) {
$shareDepartments = json_decode($entry->share_departments, true);
if (count($shareDepartments) == 1 && $shareDepartments[0] == "NULL") {
//Shared with All Departments
$data[] = $entry;
continue;
} else {
if (in_array($employee->department, $shareDepartments)) {
//Document is shared with employee's department
$data[] = $entry;
continue;
}
}
}
if (!empty($entry->share_employees)) {
$shareEmployees = json_decode($entry->share_employees, true);
if (in_array($employee->id, $shareEmployees)) {
//Document is shared with the employee
$data[] = $entry;
continue;
}
}
}
return $data;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Documents\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class Document extends BaseModel
{
public $table = 'Documents';
public function getAdminAccess()
{
return array("get","element","save","delete");
}
public function getManagerAccess()
{
return array("get","element","save","delete");
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('documents', 'admin'),
new ModuleAccess('documents', 'user'),
];
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* Created by PhpStorm.
* User: Thilina
* Date: 8/19/17
* Time: 8:26 AM
*/
namespace Documents\Common\Model;
use Classes\IceResponse;
use Classes\ModuleAccess;
use Model\BaseModel;
class EmployeeDocument extends BaseModel
{
public $table = 'EmployeeDocuments';
public function getAdminAccess()
{
return array("get","element","save","delete");
}
public function getManagerAccess()
{
return array("get","element","save","delete");
}
public function getUserAccess()
{
return array("get");
}
public function getUserOnlyMeAccess()
{
return array("element","save","delete");
}
// @codingStandardsIgnoreStart
public function Insert()
{
// @codingStandardsIgnoreEnd
if (empty($this->date_added)) {
$this->date_added = date("Y-m-d H:i:s");
}
return parent::Insert();
}
public function executePreSaveActions($obj)
{
$obj->expire_notification_last = -1;
return new IceResponse(IceResponse::SUCCESS, $obj);
}
public function executePreUpdateActions($obj)
{
$obj->expire_notification_last = -1;
return new IceResponse(IceResponse::SUCCESS, $obj);
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('employees', 'user'),
new ModuleAccess('documents', 'admin'),
new ModuleAccess('documents', 'user'),
];
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Documents\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class EmployeeDocumentNotification extends BaseModel
{
public $table = 'EmployeeDocumentNotifications';
public function getAdminAccess()
{
return array("get","element","save","delete");
}
public function getManagerAccess()
{
return array("get","element","save","delete");
}
public function getUserAccess()
{
return array("get");
}
public function getUserOnlyMeAccess()
{
return array("element","save","delete");
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('employees', 'user'),
new ModuleAccess('documents', 'admin'),
new ModuleAccess('documents', 'user'),
];
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Documents\User\Api;
use Classes\AbstractModuleManager;
class DocumentsModulesManager extends AbstractModuleManager
{
public function initializeUserClasses()
{
if (defined('MODULE_TYPE') && MODULE_TYPE != 'admin') {
$this->addUserClass("EmployeeDocument");
}
}
public function initializeFieldMappings()
{
}
public function initializeDatabaseErrorMappings()
{
}
public function setupModuleClassDefinitions()
{
}
}

View File

@@ -1,6 +1,7 @@
<?php
namespace EmergencyContacts\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class EmergencyContact extends BaseModel
@@ -26,4 +27,12 @@ class EmergencyContact extends BaseModel
{
return array("element","save","delete");
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('employees', 'user'),
];
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace Employees\Admin\Api;
use Classes\BaseService;
class EmployeeUtil
{
public function getEmployeeDataField($employeeId, $startDate, $endDate, $field)
{
$employee = BaseService::getInstance()->getElement(
'Employee',
$employeeId,
$this->getMapping(),
true
);
return [
'string',
$employee->$field
];
}
public function getMapping()
{
$mapping = <<<JSON
{
"nationality":[
"Nationality",
"id",
"name"
],
"ethnicity":[
"Ethnicity",
"id",
"name"
],
"immigration_status":[
"ImmigrationStatus",
"id",
"name"
],
"employment_status":[
"EmploymentStatus",
"id",
"name"
],
"job_title":[
"JobTitle",
"id",
"name"
],
"pay_grade":[
"PayGrade",
"id",
"name"
],
"country":[
"Country",
"code",
"name"
],
"province":[
"Province",
"id",
"name"
],
"department":[
"CompanyStructure",
"id",
"title"
],
"supervisor":[
"Employee",
"id",
"first_name+last_name"
],
"indirect_supervisors":[
"Employee",
"id",
"first_name+last_name"
],
"approver1":[
"Employee",
"id",
"first_name+last_name"
],
"approver2":[
"Employee",
"id",
"first_name+last_name"
],
"approver3":[
"Employee",
"id",
"first_name+last_name"
]
}
JSON;
return $mapping;
}
}

View File

@@ -25,6 +25,7 @@ use Salary\Common\Model\EmployeeSalary;
use TimeSheets\Common\Model\EmployeeTimeEntry;
use TimeSheets\Common\Model\EmployeeTimeSheet;
use Travel\Common\Model\EmployeeTravelRecord;
use Utils\LogManager;
class EmployeesActionManager extends SubActionManager
{
@@ -63,7 +64,6 @@ class EmployeesActionManager extends SubActionManager
$employee->termination_date = null;
$employee->status = 'Active';
$ok = $employee->Save();
if (!$ok) {
return new IceResponse(IceResponse::ERROR, "Error occurred while activating employee");
@@ -113,7 +113,13 @@ class EmployeesActionManager extends SubActionManager
$data->timesheets = $this->getEmployeeData($employee->id, new EmployeeTimeSheet());
$data->timesheetEntries = $this->getEmployeeData($employee->id, new EmployeeTimeEntry());
$data->attendance = $this->getEmployeeData($employee->id, new Attendance());
$attendnace = $this->getEmployeeData($employee->id, new Attendance());
$data->attendance = array_map(function ($item) {
$item->image_in = '';
$item->image_out = '';
}, $attendnace);
if (class_exists('\Documents\Common\Model\EmployeeDocument')) {
$data->documents = $this->getEmployeeData($employee->id, new \Documents\Common\Model\EmployeeDocument());
}
@@ -131,12 +137,14 @@ class EmployeesActionManager extends SubActionManager
$ok = $archived->Save();
if (!$ok) {
LogManager::getInstance()->error('Error occurred while archiving employee :'.$archived->ErrorMsg());
return new IceResponse(IceResponse::ERROR, "Error occurred while archiving employee");
}
$ok = $employee->Delete();
if (!$ok) {
LogManager::getInstance()->error('Error occurred while deleting employee :'.$employee->ErrorMsg());
return new IceResponse(IceResponse::ERROR, "Error occurred while deleting employee");
}

View File

@@ -9,6 +9,7 @@
namespace Employees\Admin\Api;
use Classes\AbstractModuleManager;
use Classes\Macaw;
use Classes\UIManager;
use Employees\Common\Model\Employee;
use Employees\Rest\EmployeeRestEndPoint;
@@ -26,32 +27,32 @@ class EmployeesAdminManager extends AbstractModuleManager
public function setupRestEndPoints()
{
\Classes\Macaw::get(REST_API_PATH.'employees/me', function () {
Macaw::get(REST_API_PATH.'employees/me', function () {
$empRestEndPoint = new EmployeeRestEndPoint();
$empRestEndPoint->process('get', 'me');
});
\Classes\Macaw::get(REST_API_PATH.'employees/(:num)', function ($pathParams) {
Macaw::get(REST_API_PATH.'employees/(:num)', function ($pathParams) {
$empRestEndPoint = new EmployeeRestEndPoint();
$empRestEndPoint->process('get', $pathParams);
});
\Classes\Macaw::get(REST_API_PATH.'employees', function () {
Macaw::get(REST_API_PATH.'employees', function () {
$empRestEndPoint = new EmployeeRestEndPoint();
$empRestEndPoint->process('listAll');
});
\Classes\Macaw::post(REST_API_PATH.'employees', function () {
Macaw::post(REST_API_PATH.'employees', function () {
$empRestEndPoint = new EmployeeRestEndPoint();
$empRestEndPoint->process('post');
});
\Classes\Macaw::put(REST_API_PATH.'employees/(:num)', function ($pathParams) {
Macaw::put(REST_API_PATH.'employees/(:num)', function ($pathParams) {
$empRestEndPoint = new EmployeeRestEndPoint();
$empRestEndPoint->process('put', $pathParams);
});
\Classes\Macaw::delete(REST_API_PATH.'employees/(:num)', function ($pathParams) {
Macaw::delete(REST_API_PATH.'employees/(:num)', function ($pathParams) {
$empRestEndPoint = new EmployeeRestEndPoint();
$empRestEndPoint->process('delete', $pathParams);
});
@@ -86,16 +87,26 @@ class EmployeesAdminManager extends AbstractModuleManager
public function initQuickAccessMenu()
{
UIManager::getInstance()->addQuickAccessMenuItem(
"View Employees",
"fa-users",
CLIENT_BASE_URL."?g=admin&n=employees&m=admin_Employees",
array("Admin","Manager")
'View Employees',
'fa-users',
CLIENT_BASE_URL.'?g=admin&n=employees&m=admin_Employees',
array('Admin','Manager')
);
UIManager::getInstance()->addQuickAccessMenuItem(
"Add a New Employee",
"fa-edit",
CLIENT_BASE_URL."?g=admin&n=employees&m=admin_Employees&action=new",
array("Admin")
'Add a New Employee',
'fa-edit',
CLIENT_BASE_URL.'?g=admin&n=employees&m=admin_Employees&action=new',
array('Admin')
);
}
public function initCalculationHooks()
{
$this->addCalculationHook(
'EmployeeData_getFieldValue',
'Get Employee Data',
EmployeeUtil::class,
'getEmployeeDataField'
);
}
}

View File

@@ -1,6 +1,7 @@
<?php
namespace Employees\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class ArchivedEmployee extends BaseModel
@@ -31,5 +32,12 @@ class ArchivedEmployee extends BaseModel
return "id";
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
];
}
public $table = 'ArchivedEmployees';
}

View File

@@ -4,6 +4,7 @@ namespace Employees\Common\Model;
use Classes\BaseService;
use Classes\FileService;
use Classes\IceResponse;
use Classes\ModuleAccess;
use Company\Common\Model\CompanyStructure;
use Metadata\Common\Model\Country;
use Model\BaseModel;
@@ -235,5 +236,13 @@ class Employee extends BaseModel
return $country->id;
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('employees', 'user'),
];
}
public $table = 'Employees';
}

View File

@@ -8,6 +8,7 @@
namespace Employees\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class EmployeeApproval extends BaseModel
@@ -29,4 +30,12 @@ class EmployeeApproval extends BaseModel
{
return array();
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('employees', 'user'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Employees\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class EmploymentStatus extends BaseModel
@@ -24,4 +25,12 @@ class EmploymentStatus extends BaseModel
{
return array("get","element","save");
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
new ModuleAccess('employees', 'user'),
];
}
}

View File

@@ -24,12 +24,35 @@ class EmployeeRestEndPoint extends RestEndPoint
{
$query = new DataQuery('Employee');
$mapping = <<<JSON
{
"job_title": [ "JobTitle", "id", "name" ],
"country": [ "Country", "code", "name" ],
"province": [ "Province", "id", "name" ],
"department": [ "CompanyStructure", "id", "title" ],
"supervisor": [ "Employee", "id", "first_name+last_name" ]
}
JSON;
$query->setFieldMapping($mapping);
$limit = self::DEFAULT_LIMIT;
if (isset($_GET['limit']) && intval($_GET['limit']) > 0) {
$limit = intval($_GET['limit']);
}
$query->setLength($limit);
if (!empty($_GET['filters'])) {
$query->setFilters($_GET['filters']);
}
if (isset($_GET['sortField']) && !empty($_GET['sortField'])) {
$query->setSortColumn($_GET['sortField']);
$query->setSortingEnabled(true);
$query->setSortOrder(
empty($_GET['sortOrder']) || $_GET['sortOrder'] === 'ascend' ? 'ASC' : 'DESC'
);
}
if ($user->user_level !== 'Admin') {
$query->setIsSubOrdinates(true);
}
@@ -55,27 +78,36 @@ class EmployeeRestEndPoint extends RestEndPoint
return new IceResponse(IceResponse::ERROR, "Permission denied", 403);
}
$mapping = [
"nationality" => ["Nationality","id","name"],
"ethnicity" => ["Ethnicity","id","name"],
"immigration_status" => ["ImmigrationStatus","id","name"],
"employment_status" => ["EmploymentStatus","id","name"],
"job_title" => ["JobTitle","id","name"],
"pay_grade" => ["PayGrade","id","name"],
"country" => ["Country","code","name"],
"province" => ["Province","id","name"],
"department" => ["CompanyStructure","id","title"],
"supervisor" => [self::ELEMENT_NAME,"id","first_name+last_name"],
];
// https://csvjson.com/json_beautifier
$mapping = <<<JSON
{
"nationality": [ "Nationality", "id", "name" ],
"ethnicity": [ "Ethnicity", "id", "name" ],
"immigration_status": [ "ImmigrationStatus", "id", "name" ],
"employment_status": [ "EmploymentStatus", "id", "name" ],
"job_title": [ "JobTitle", "id", "name" ],
"pay_grade": [ "PayGrade", "id", "name" ],
"country": [ "Country", "code", "name" ],
"province": [ "Province", "id", "name" ],
"department": [ "CompanyStructure", "id", "title" ],
"supervisor": [ "Employee", "id", "first_name+last_name" ],
"indirect_supervisors": [ "Employee", "id", "first_name+last_name" ],
"approver1": [ "Employee", "id", "first_name+last_name" ],
"approver2": [ "Employee", "id", "first_name+last_name" ],
"approver3": [ "Employee", "id", "first_name+last_name" ]
}
JSON;
$emp = BaseService::getInstance()->getElement(
self::ELEMENT_NAME,
$parameter,
json_encode($mapping),
null,
true
);
$emp = $this->enrichElement($emp, $mapping);
$emp = $this->enrichElement($emp, json_decode($mapping, true));
//Get User for the employee
$user = new User();
$user->Load('employee = ?', [$emp->id]);

View File

@@ -11,11 +11,13 @@ namespace Employees\User\Api;
use Classes\BaseService;
use Classes\FileService;
use Classes\IceResponse;
use Classes\PasswordManager;
use Classes\SettingsManager;
use Classes\SubActionManager;
use Company\Common\Model\CompanyStructure;
use Employees\Common\Model\Employee;
use Users\Common\Model\User;
use Utils\LogManager;
class EmployeesActionManager extends SubActionManager
{
@@ -104,6 +106,7 @@ class EmployeesActionManager extends SubActionManager
try {
$employee = BaseService::getInstance()->customFieldManager->enrichObjectCustomFields('Employee', $employee);
} catch (\Exception $e) {
LogManager::getInstance()->notifyException($e);
}
if (empty($employee->id)) {
@@ -143,11 +146,18 @@ class EmployeesActionManager extends SubActionManager
if (empty($user->id)) {
return new IceResponse(IceResponse::ERROR, "Error occurred while changing password");
}
$user->password = md5($req->pwd);
$passwordStrengthResponse = PasswordManager::isQualifiedPassword($req->pwd);
if ($passwordStrengthResponse->getStatus() === IceResponse::ERROR) {
return $passwordStrengthResponse;
}
$user->password = PasswordManager::createPasswordHash($req->pwd);
$ok = $user->Save();
if (!$ok) {
return new IceResponse(IceResponse::ERROR, $user->ErrorMsg());
}
return new IceResponse(IceResponse::SUCCESS, $user);
}
}

View File

@@ -10,6 +10,7 @@ namespace FieldNames\Common\Model;
use Classes\BaseService;
use Classes\IceResponse;
use Classes\ModuleAccess;
use Model\BaseModel;
class CustomField extends BaseModel
@@ -56,4 +57,11 @@ class CustomField extends BaseModel
return new IceResponse(IceResponse::SUCCESS, "");
}
public function getModuleAccess()
{
return [
new ModuleAccess('fieldnames', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace FieldNames\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class FieldNameMapping extends BaseModel
@@ -23,4 +24,11 @@ class FieldNameMapping extends BaseModel
{
return array();
}
public function getModuleAccess()
{
return [
new ModuleAccess('fieldnames', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Jobs\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class JobTitle extends BaseModel
@@ -18,4 +19,11 @@ class JobTitle extends BaseModel
{
return array("get","element","save","delete");
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Jobs\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class PayGrade extends BaseModel
@@ -18,4 +19,11 @@ class PayGrade extends BaseModel
{
return array("get","element","save","delete");
}
public function getModuleAccess()
{
return [
new ModuleAccess('employees', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Loans\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class CompanyLoan extends BaseModel
@@ -18,4 +19,11 @@ class CompanyLoan extends BaseModel
{
return array("get","element","save","delete");
}
public function getModuleAccess()
{
return [
new ModuleAccess('loans', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Loans\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class EmployeeCompanyLoan extends BaseModel
@@ -33,4 +34,12 @@ class EmployeeCompanyLoan extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('loans', 'admin'),
new ModuleAccess('loans', 'user'),
];
}
}

View File

@@ -9,6 +9,7 @@
namespace Metadata\Common\Model;
use Classes\BaseService;
use Classes\ModuleAccess;
use Model\BaseModel;
class CalculationHook extends BaseModel

View File

@@ -8,6 +8,7 @@
namespace Metadata\Common\Model;
use Classes\ModuleAccess;
use Classes\SettingsManager;
use Model\BaseModel;
@@ -46,4 +47,11 @@ class Country extends BaseModel
return parent::Find($whereOrderBy, $bindarr, $pkeysArr, $extra);
}
// @codingStandardsIgnoreEnd
public function getModuleAccess()
{
return [
new ModuleAccess('metadata', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Metadata\Common\Model;
use Classes\ModuleAccess;
use Classes\SettingsManager;
use Model\BaseModel;
@@ -46,4 +47,11 @@ class CurrencyType extends BaseModel
return parent::Find($whereOrderBy, $bindarr, $pkeysArr, $extra);
}
// @codingStandardsIgnoreEnd
public function getModuleAccess()
{
return [
new ModuleAccess('metadata', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Metadata\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class Ethnicity extends BaseModel
@@ -28,4 +29,11 @@ class Ethnicity extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('metadata', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Metadata\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class ImmigrationStatus extends BaseModel
@@ -28,4 +29,11 @@ class ImmigrationStatus extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('metadata', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Metadata\Common\Model;
use Classes\ModuleAccess;
use Classes\SettingsManager;
use Model\BaseModel;
@@ -45,4 +46,11 @@ class Nationality extends BaseModel
return parent::Find($whereOrderBy, $bindarr, $pkeysArr, $extra);
}
// @codingStandardsIgnoreEnd
public function getModuleAccess()
{
return [
new ModuleAccess('metadata', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Metadata\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class Province extends BaseModel
@@ -23,4 +24,11 @@ class Province extends BaseModel
{
return array("get", "element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('metadata', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Metadata\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class SupportedLanguage extends BaseModel
@@ -28,4 +29,11 @@ class SupportedLanguage extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('metadata', 'admin'),
];
}
}

View File

@@ -60,9 +60,9 @@ abstract class ApproveModel extends BaseModel
if ($user->user_level == "Admin") {
//Auto approve
$obj->status = "Approved";
$notificationMsg = "Your ".$this->notificationUnitName
." is auto approved since you are an administrator and do not have any supervisor assigned";
$obj->status = 'Approved';
$notificationMsg = 'Your '.$this->notificationUnitName
.' is auto approved since you are an administrator and do not have any supervisor assigned';
BaseService::getInstance()->notificationManager->addNotification(
null,
$notificationMsg,
@@ -76,11 +76,11 @@ abstract class ApproveModel extends BaseModel
//If the user do not have a supervisor, notify all admins
$admins = BaseService::getInstance()->getAllAdmins();
foreach ($admins as $admin) {
$notificationMsg = "A new ".$this->notificationUnitName." has been added by "
.$employee->first_name . " " . $employee->last_name . ". Please visit "
$notificationMsg = 'A new '.$this->notificationUnitName.' has been added by '
.$employee->first_name . ' ' . $employee->last_name . '. Please visit '
.$this->notificationModuleName
." module to review it. You are getting this notification since you are an "
."administrator and the user do not have any supervisor assigned.";
.' module to review it. You are getting this notification since you are an '
.'administrator and the user do not have any supervisor assigned.';
BaseService::getInstance()->notificationManager->addNotification(
null,
$notificationMsg,
@@ -151,22 +151,22 @@ abstract class ApproveModel extends BaseModel
} else {
$user = BaseService::getInstance()->getCurrentUser();
if ($user->user_level == "Admin") {
if ($user->user_level == 'Admin') {
} else {
//If the user do not have a supervisor, notify all admins
$admins = BaseService::getInstance()->getAllAdmins();
foreach ($admins as $admin) {
$notificationMsg = $this->notificationUnitPrefix." "
.$this->notificationUnitName." request has been updated by "
.$employee->first_name . " " . $employee->last_name
.". Please visit ".$this->notificationModuleName
." module to review it. You are getting this notification since you are "
."an administrator and the user do not have any supervisor assigned.";
$notificationMsg = $this->notificationUnitPrefix.' '
.$this->notificationUnitName.' request has been updated by '
.$employee->first_name . ' ' . $employee->last_name
.'. Please visit '.$this->notificationModuleName
.' module to review it. You are getting this notification since you are '
.'an administrator and the user do not have any supervisor assigned.';
BaseService::getInstance()->notificationManager->addNotification(
null,
$notificationMsg,
'{"type":"url","url":"g=admin&n=travel&m=admin_Employees"}',
"Travel Module",
'Travel Module',
$admin->id,
false,
$sendNotificationEmail

View File

@@ -8,6 +8,8 @@
namespace Model;
use Classes\ModuleAccess;
class Audit extends BaseModel
{
public $table = 'AuditLog';
@@ -21,4 +23,11 @@ class Audit extends BaseModel
{
return array();
}
public function getModuleAccess()
{
return [
new ModuleAccess('audit', 'admin'),
];
}
}

View File

@@ -1,7 +1,12 @@
<?php
namespace Model;
use Classes\BaseService;
use Classes\IceResponse;
use Classes\ModuleAccess;
use Classes\ModuleAccessService;
use Modules\Common\Model\Module;
use Utils\LogManager;
class BaseModel extends \ADOdb_Active_Record
{
@@ -24,9 +29,62 @@ class BaseModel extends \ADOdb_Active_Record
return array("get","element","save","delete");
}
public function getOtherAccess()
private function getRestrictedAccess($userRoles, $allowedAccessMatrix)
{
return array();
if (empty($userRoles)) {
return $this->getDefaultAccessLevel();
}
$userRoles = json_decode($userRoles, true);
if (empty($userRoles)) {
return $this->getDefaultAccessLevel();
}
$moduleAccessData = $this->getModuleAccess();
if (empty($moduleAccessData)) {
return $this->getDefaultAccessLevel();
}
$modules = [];
/** @var ModuleAccess $moduleAccess */
foreach ($moduleAccessData as $moduleAccess) {
$modules[] = ModuleAccessService::getInstance()->getModule(
$moduleAccess->getName(),
$moduleAccess->getGroup()
);
}
if (empty($modules)) {
return $this->getDefaultAccessLevel();
}
foreach ($modules as $module) {
if (empty($module->user_roles) || $module->user_roles == '[]') {
continue;
}
if (count(array_intersect($userRoles, json_decode($module->user_roles, true))) > 0) {
return $allowedAccessMatrix;
}
}
return $this->getDefaultAccessLevel();
}
public function getRestrictedAdminAccess($userRoles)
{
return $this->getRestrictedAccess($userRoles, $this->getAdminAccess());
}
public function getRestrictedManagerAccess($userRoles)
{
return $this->getRestrictedAccess($userRoles, $this->getAdminAccess());
}
public function getRestrictedEmployeeAccess($userRoles)
{
return $this->getRestrictedAccess($userRoles, $this->getAdminAccess());
}
public function getManagerAccess()
@@ -69,6 +127,11 @@ class BaseModel extends \ADOdb_Active_Record
return "employee";
}
public function getModuleAccess()
{
return [];
}
public function validateSave($obj)
{
return new IceResponse(IceResponse::SUCCESS, "");
@@ -109,7 +172,7 @@ class BaseModel extends \ADOdb_Active_Record
public function getDefaultAccessLevel()
{
return array("get","element","save","delete");
return $this->getAnonymousAccess();
}
public function getVirtualFields()
@@ -125,7 +188,7 @@ class BaseModel extends \ADOdb_Active_Record
public function getDisplayName()
{
return get_called_class();
return $this->getEntity();
}
public function fieldValueMethods()
@@ -179,4 +242,67 @@ class BaseModel extends \ADOdb_Active_Record
return $keys;
}
// @codingStandardsIgnoreStart
public function Find($whereOrderBy, $bindarr = false, $cache = false, $pkeysArr = false, $extra = array())
{
if ($cache && BaseService::getInstance()->queryCacheEnabled()) {
$data = BaseService::getInstance()->getCacheService()->getDBQuery($this->getEntity(),$whereOrderBy, $bindarr);
if ($data !== null) {
return $data;
}
}
$data = parent::Find($whereOrderBy, $bindarr, $pkeysArr, $extra);
if (empty($data)) {
return $data;
}
if ($cache && BaseService::getInstance()->queryCacheEnabled()) {
BaseService::getInstance()->getCacheService()->setDBQuery($this->getEntity(),$whereOrderBy, $bindarr, $data);
}
return $data;
}
protected function getEntity()
{
$data = explode('\\', get_called_class());
return end($data);
}
public function Save()
{
$ok = parent::Save();
if (!$ok) {
$message = sprintf('%s: (%s) %s', 'Error saving :', $this->ErrorMsg(), json_encode($this));
LogManager::getInstance()->error($message);
LogManager::getInstance()->notifyException(new \Exception($message));
}
if (BaseService::getInstance()->queryCacheEnabled()) {
BaseService::getInstance()->getCacheService()->deleteByEntity($this->getEntity());
}
return $ok;
}
public function Delete()
{
$ok = parent::Delete();
if (!$ok) {
$message = sprintf('%s: (%s) %s', 'Error deleting', $this->ErrorMsg(), json_encode($this));
LogManager::getInstance()->error($message);
LogManager::getInstance()->notifyException(new \Exception($message));
}
if (BaseService::getInstance()->queryCacheEnabled()) {
BaseService::getInstance()->getCacheService()->deleteByEntity($this->getEntity());
}
return $ok;
}
// @codingStandardsIgnoreEnd
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Model;
class EmailLogEntry extends BaseModel
{
public $table = 'EmailLog';
}

View File

@@ -8,6 +8,8 @@
namespace Model;
use Classes\ModuleAccess;
class Report extends BaseModel
{
public function getAdminAccess()
@@ -25,6 +27,13 @@ class Report extends BaseModel
return array();
}
public function getModuleAccess()
{
return [
new ModuleAccess('reports', 'admin'),
];
}
public function postProcessGetData($entry)
{
$entry->icon = '<img src="'.BASE_URL.'images/file-icons/'.strtolower($entry->output).".png".'"/>';

View File

@@ -8,6 +8,8 @@
namespace Model;
use Classes\ModuleAccess;
class ReportFile extends BaseModel
{
public function getAdminAccess()
@@ -30,6 +32,13 @@ class ReportFile extends BaseModel
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('report_files', 'admin'),
];
}
public function postProcessGetData($entry)
{
$data = explode(".", $entry->name);

View File

@@ -10,6 +10,7 @@ namespace Model;
use Classes\BaseService;
use Classes\IceResponse;
use Classes\ModuleAccess;
use Classes\RestApiManager;
use Users\Common\Model\User;
@@ -30,6 +31,13 @@ class Setting extends BaseModel
return array();
}
public function getModuleAccess()
{
return [
new ModuleAccess('settings', 'admin'),
];
}
public function postProcessGetElement($obj)
{
if ($obj->name == 'Api: REST Api Token') {

View File

@@ -8,6 +8,8 @@
namespace Model;
use Classes\ModuleAccess;
class UserReport extends BaseModel
{
public function getAdminAccess()
@@ -25,6 +27,13 @@ class UserReport extends BaseModel
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('reports', 'user'),
];
}
public function postProcessGetData($entry)
{
$entry->icon = '<img src="'.BASE_URL.'images/file-icons/'.strtolower($entry->output).".png".'"/>';

View File

@@ -31,10 +31,10 @@ class ModulesAdminManager extends AbstractModuleManager
public function initQuickAccessMenu()
{
UIManager::getInstance()->addQuickAccessMenuItem(
"Setup Modules",
"fa-cogs",
CLIENT_BASE_URL."?g=admin&n=modules&m=admin_System",
array("Admin")
'Setup Modules',
'fa-cogs',
CLIENT_BASE_URL.'?g=admin&n=modules&m=admin_System',
array('Admin')
);
}
}

View File

@@ -6,10 +6,14 @@
namespace Modules\Common\Model;
use Classes\ModuleAccess;
use Classes\ModuleAccessService;
use Model\BaseModel;
class Module extends BaseModel
{
public $table = 'Modules';
public function getAdminAccess()
{
return array("get","element","save","delete");
@@ -19,5 +23,28 @@ class Module extends BaseModel
{
return array();
}
public $table = 'Modules';
public function getUserModules()
{
$moduleList = [];
$modules = ModuleAccessService::getInstance()->getModules();
foreach ($modules as $md) {
$md->name = sprintf('[%s] %s => %s', $md->mod_group, $md->menu, $md->label);
$moduleList[] = $md;
}
return $moduleList;
}
public function fieldValueMethods()
{
return ['getUserModules'];
}
public function getModuleAccess()
{
return [
new ModuleAccess('modules', 'admin'),
];
}
}

View File

@@ -9,6 +9,7 @@
namespace Overtime\Common\Model;
use Classes\IceResponse;
use Classes\ModuleAccess;
use Classes\SettingsManager;
use Model\ApproveModel;
@@ -75,4 +76,12 @@ class EmployeeOvertime extends ApproveModel
}
return new IceResponse(IceResponse::SUCCESS, "");
}
public function getModuleAccess()
{
return [
new ModuleAccess('overtime', 'admin'),
new ModuleAccess('overtime', 'user'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Overtime\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class OvertimeCategory extends BaseModel
@@ -28,4 +29,11 @@ class OvertimeCategory extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('overtime', 'admin'),
];
}
}

View File

@@ -14,6 +14,7 @@ use Classes\SubActionManager;
use Company\Common\Model\CompanyStructure;
use Employees\Common\Model\Employee;
use Payroll\Common\Model\Deduction;
use Payroll\Common\Model\DeductionGroup;
use Payroll\Common\Model\Payroll;
use Payroll\Common\Model\PayrollCalculations;
use Payroll\Common\Model\PayrollColumn;
@@ -23,6 +24,8 @@ use Salary\Common\Model\PayrollEmployee;
use Salary\Common\Model\SalaryComponent;
use Utils\LogManager;
use Utils\Math\EvalMath;
use Utils\ScriptRunner;
use Classes\Migration\AbstractMigration;
class PayrollActionManager extends SubActionManager
{
@@ -52,19 +55,24 @@ class PayrollActionManager extends SubActionManager
$payrollEmployeeId,
$noColumnCalculations = false
) {
$val = $this->getFromCalculationCache($col->id."-".$payroll->id."-".$employeeId);
if (!empty($val)) {
return $val;
}
if (!empty($col->calculation_hook)) {
$sum = BaseService::getInstance()->executeCalculationHook(
$valueData = BaseService::getInstance()->executeCalculationHook(
array($employeeId, $payroll->date_start, $payroll->date_end),
$col->calculation_hook,
$col->calculation_function
);
$val = number_format(round($sum, 2), 2, '.', '');
if (is_array($valueData) && $valueData[0] == 'string') {
$val = $valueData[1];
} else {
$val = number_format(round($valueData, 2), 2, '.', '');
}
$this->addToCalculationCache($col->id."-".$payroll->id."-".$employeeId, $val);
return $val;
}
@@ -118,8 +126,10 @@ class PayrollActionManager extends SubActionManager
if (!$noColumnCalculations) {
$evalMath = new EvalMath();
$evalMath->evaluate('max(x,y) = (y - x) * ceil(tanh(exp(tanh(y - x)) - exp(0))) + x');
$evalMath->evaluate('min(x,y) = y - (y - x) * ceil(tanh(exp(tanh(y - x)) - exp(0)))');
if ($col->function_type === 'Simple') {
$evalMath->evaluate('max(x,y) = (y - x) * ceil(tanh(exp(tanh(y - x)) - exp(0))) + x');
$evalMath->evaluate('min(x,y) = y - (y - x) * ceil(tanh(exp(tanh(y - x)) - exp(0)))');
}
if (!empty($col->add_columns) &&
!empty(json_decode($col->add_columns, true))) {
@@ -157,17 +167,27 @@ class PayrollActionManager extends SubActionManager
!empty(json_decode($col->calculation_columns, true)) && !empty($col->calculation_function)) {
$cc = json_decode($col->calculation_columns);
$func = $col->calculation_function;
$variableList = [];
foreach ($cc as $c) {
$value = $this->getFromCalculationCache($c->column."-".$payroll->id."-".$employeeId);
if (empty($value)) {
$value = 0.00;
if ($col->function_type === 'Simple') {
if (empty($value)) {
$value = 0.00;
}
$func = str_replace($c->name, $value, $func);
} else {
$variableList[$c->name] = $value;
}
$func = str_replace($c->name, $value, $func);
}
try {
$sum += $evalMath->evaluate($func);
if ($col->function_type === 'Simple') {
$sum += $evalMath->evaluate($func);
} else {
$sum = ScriptRunner::executeJs($variableList, $func);
}
} catch (\Exception $e) {
LogManager::getInstance()->info("Error:".$e->getMessage());
LogManager::getInstance()->error("Error:".$e->getMessage());
LogManager::getInstance()->notifyException($e);
}
}
}
@@ -495,4 +515,62 @@ class PayrollActionManager extends SubActionManager
return new IceResponse(IceResponse::SUCCESS, true);
}
public function deletePayrollGroup($req)
{
$employee = new PayrollEmployee();
$report = new Payroll();
$payrollGroup = new DeductionGroup();
$payrollColumn = new PayrollColumn();
$calcMethod =new Deduction();
$payrollGroup->Load("id = ?", array($req->id));
if (empty($payrollGroup->id)) {
return new IceResponse(IceResponse::ERROR);
}
$this->baseService->checkSecureAccess('delete', $payrollGroup, 'DeductionGroup', $_POST);
$this->baseService->checkSecureAccess('delete', $payrollColumn, 'payrollColumn', $_POST);
$this->baseService->checkSecureAccess('delete', $calcMethod, 'Deduction', $_POST);
$employee->Load("deduction_group = ?", $payrollGroup->id);
$report->Load("deduction_group = ?", $payrollGroup->id);
$payrollColumn->Load("deduction_group = ?", $payrollGroup->id);
$calcMethod->Load("deduction_group = ?", $payrollGroup->id);
if (!empty($employee->id)) {
return new IceResponse(
IceResponse::ERROR,
"There are employees attached to this payroll group,
please re-assign employees to a different payroll group"
);
}
if (!empty($report->id)) {
return new IceResponse(
IceResponse::ERROR,
"There are payroll reports attached to this group,
please move the payroll reports to a different payroll group before deleting this group"
);
}
BaseService::getInstance()->getDB()->Execute(
'DELETE FROM PayrollColumns WHERE deduction_group= ? ',
array($req->id)
);
BaseService::getInstance()->getDB()->Execute(
'DELETE FROM Deductions WHERE deduction_group= ? ',
array($req->id)
);
$ok = $payrollGroup->Delete();
if (!$ok) {
return new IceResponse(
IceResponse::ERROR,
"Error occurred while deleting payroll group"
);
}
return new IceResponse(IceResponse::SUCCESS);
}
}

View File

@@ -8,6 +8,7 @@
namespace Payroll\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class Deduction extends BaseModel
@@ -23,4 +24,11 @@ class Deduction extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('payroll', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Payroll\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class DeductionGroup extends BaseModel
@@ -23,4 +24,11 @@ class DeductionGroup extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('payroll', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Payroll\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class PayFrequency extends BaseModel
@@ -27,4 +28,11 @@ class PayFrequency extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('payroll', 'admin'),
];
}
}

View File

@@ -9,6 +9,7 @@
namespace Payroll\Common\Model;
use Classes\BaseService;
use Classes\ModuleAccess;
use Model\BaseModel;
class Payroll extends BaseModel
@@ -52,4 +53,11 @@ class Payroll extends BaseModel
{
return ['getEmployeePayrolls'];
}
public function getModuleAccess()
{
return [
new ModuleAccess('payroll', 'admin'),
];
}
}

View File

@@ -9,6 +9,7 @@
namespace Payroll\Common\Model;
use Attendance\Common\Model\Attendance;
use Classes\ModuleAccess;
use Model\BaseModel;
use Salary\Common\Model\EmployeeSalary;
use TimeSheets\Common\Model\EmployeeTimeSheet;
@@ -119,4 +120,11 @@ class PayrollCalculations extends BaseModel
return round($hoursPartial, 2) . "(".round($hoursPartialUnapproved, 2).")";
}
public function getModuleAccess()
{
return [
new ModuleAccess('payroll', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Payroll\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class PayrollColumn extends BaseModel
@@ -27,4 +28,11 @@ class PayrollColumn extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('payroll', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Payroll\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class PayrollColumnTemplate extends BaseModel
@@ -27,4 +28,11 @@ class PayrollColumnTemplate extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('payroll', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Payroll\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class PayrollData extends BaseModel
@@ -28,4 +29,11 @@ class PayrollData extends BaseModel
{
return array();
}
public function getModuleAccess()
{
return [
new ModuleAccess('payroll', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Payroll\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class PayslipTemplate extends BaseModel
@@ -23,4 +24,11 @@ class PayslipTemplate extends BaseModel
{
return array("get","element");
}
public function getModuleAccess()
{
return [
new ModuleAccess('payroll', 'admin'),
];
}
}

View File

@@ -8,6 +8,7 @@
namespace Permissions\Common\Model;
use Classes\ModuleAccess;
use Model\BaseModel;
class Permission extends BaseModel
@@ -23,4 +24,11 @@ class Permission extends BaseModel
{
return array();
}
public function getModuleAccess()
{
return [
new ModuleAccess('permissions', 'admin'),
];
}
}

Some files were not shown because too many files have changed in this diff Show More