diff --git a/config/logs.php b/config/logs.php index 54521c3e12..1a21c8b94e 100644 --- a/config/logs.php +++ b/config/logs.php @@ -56,6 +56,11 @@ 'app.log.assets' => env('LOG_ASSETS', false), 'app.log.auth' => env('LOG_AUTH', false), + 'app.log.evaluations' => env('LOG_EVALUATIONS', false), + 'app.log.summary' => env('LOG_SUMMARY', false), + + 'app.log.lockfile' => env('LOG_LOCKFILE', false), + 'app.log.components' => env('LOG_COMPONENTS', false), 'app.log.assetManager' => env('LOG_ASSETMANAGER', false), @@ -63,6 +68,8 @@ 'app.log.pcache' => env('LOG_PCACHE', false), 'app.log.pcache.users' => env('LOG_PCACHE_USERS', false), - 'app.queryLogger' => env('LOG_QUERYLOG_CLASS', null) + 'app.queryLogger' => env('LOG_QUERYLOG_CLASS', null), + + ]; \ No newline at end of file diff --git a/src/core/ApiQuery.php b/src/core/ApiQuery.php index a4d34278e0..50e4439786 100644 --- a/src/core/ApiQuery.php +++ b/src/core/ApiQuery.php @@ -1070,7 +1070,7 @@ protected function generateWhere() { $where = $where_dqls; } - if($this->usesStatus && (!isset($this->apiParams['status']) || !$this->_permission)){ + if($app->isAccessControlEnabled() && $this->usesStatus && (!isset($this->apiParams['status']) || !$this->_permission)){ $params = $this->apiParams; if($this->rootEntityClassName === Opportunity::class && (isset($params['id']) || isset($params['status']) || isset($params['parent']))) { @@ -1319,7 +1319,7 @@ protected function processEntities(array &$entities) { $entity['originSiteUrl'] = $main_site_url; } if($this->_selectingType && isset($entity['_type'])){ - $entity['type'] = $types[$entity['_type']]; + $entity['type'] = $types[$entity['_type']] ?? null; unset($entity['_type']); } @@ -3156,6 +3156,11 @@ protected function _setPermissionsUser($value) { protected function _addFilterByPermissions($value) { $app = App::i(); + + if(!$app->isAccessControlEnabled()) { + return; + } + $user = $this->_permissionsUser ? $app->repo('User')->find($this->_permissionsUser) : $app->user; diff --git a/src/core/App.php b/src/core/App.php index cc5fa52df3..686fe887c8 100644 --- a/src/core/App.php +++ b/src/core/App.php @@ -1799,8 +1799,20 @@ public function enqueueJob(string $type_slug, array $data, string $start_string $conn->delete('job', ['id' => $id]); } + /** @var Entities\Job $job */ if ($job = $this->repo('Job')->find($id)) { - return $job; + $job_create_timestamp = $job->createTimestamp; + + // o job tem mais que 5 minutos? + $is_old = $job_create_timestamp->getTimestamp() < (time() - 5 * MINUTE_IN_SECONDS); + + // remove o job se ele estiver com status de processamento e for mais velho que 5 minutos + if($job->status == Job::STATUS_PROCESSING && $iterations == 1 && $is_old) { + $conn = $this->em->getConnection(); + $conn->delete('job', ['id' => $id]); + } else { + return $job; + } } $job = new Job($type); diff --git a/src/core/Controllers/EvaluationMethodConfiguration.php b/src/core/Controllers/EvaluationMethodConfiguration.php index 6c01098048..b0ab047478 100644 --- a/src/core/Controllers/EvaluationMethodConfiguration.php +++ b/src/core/Controllers/EvaluationMethodConfiguration.php @@ -6,6 +6,7 @@ use MapasCulturais\Controller; use MapasCulturais\Entities\EvaluationMethodConfiguration as EvaluationMethodConfigurationEntity; use MapasCulturais\Traits; +use Opportunities\Jobs\RedistributeCommitteeRegistrations; // use MapasCulturais\Entities\EvaluationMethodConfiguration; @@ -187,4 +188,21 @@ protected function _setPermissionCacheUsers(){ $entity->__skipQueuingPCacheRecreation = true; } + + function POST_registributeEvaluations() { + $app = App::i(); + + $this->requireAuthentication(); + + $emc = $this->requestedEntity; + + if(!$emc) { + $app->pass(); + } + $emc->checkPermission('manageEvaluationCommittee'); + + $app->enqueueOrReplaceJob(RedistributeCommitteeRegistrations::SLUG, ['evaluationMethodConfiguration' => $emc], 'now'); + + $this->json(true); + } } diff --git a/src/core/Controllers/Opportunity.php b/src/core/Controllers/Opportunity.php index f886d0fd1b..c659008a8e 100644 --- a/src/core/Controllers/Opportunity.php +++ b/src/core/Controllers/Opportunity.php @@ -518,7 +518,8 @@ function apiFindRegistrations($opportunity, $query_data) { } } - + $opportunity->registerRegistrationMetadata(); + return (object) ['count' => $current_phase_query->count(), 'registrations' => $current_phase_result,]; } @@ -942,8 +943,8 @@ function apiFindEvaluations(int $opportunity_id = null, array $query_data = []) $rdata = [ '@select' => 'id', 'opportunity' => "EQ({$opportunity->id})", - '@permissions' => 'viewUserEvaluation', - '@order' => 'id ASC' + '@order' => 'id ASC', + 'status' => API::GT(0) ]; foreach($query_data as $k => $v){ @@ -960,9 +961,10 @@ function apiFindEvaluations(int $opportunity_id = null, array $query_data = []) } } + $app->disableAccessControl(); $registrations_query = new ApiQuery('MapasCulturais\Entities\Registration', $rdata); - $registration_ids = implode(",", $registrations_query->findIds() ?: [-1]); + $app->enableAccessControl(); $query = " SELECT @@ -1035,6 +1037,7 @@ function apiFindEvaluations(int $opportunity_id = null, array $query_data = []) $evaluations = $conn->fetchAll($query, $params); + $app->disableAccessControl(); $registration_numbers = array_filter(array_unique(array_map(function($r) { return $r['registration_number']; }, $evaluations))); $evaluations_ids = array_filter(array_unique(array_map(function($r) { return $r['evaluation_id']; }, $evaluations))); @@ -1042,6 +1045,8 @@ function apiFindEvaluations(int $opportunity_id = null, array $query_data = []) $_registrations = $this->_getOpportunityRegistrations($opportunity, $registration_numbers, $query_data); $_evaluations = $this->_getOpportunityEvaluations($opportunity, $evaluations_ids); + $app->disableAccessControl(); + $_result = []; foreach($evaluations as $eval) { @@ -1473,5 +1478,29 @@ public function ALL_fixNextPhaseRegistrationIds():void $opportunity->fixNextPhaseRegistrationIds(); } + + public function API_findEvaluable(): void { + $this->requireAuthentication(); + + $app = App::i(); + + $user_id = $this->data['@user'] ?? $app->user->id; + $user = $app->repo('User')->find($user_id); + + $user->profile->checkPermission('@control'); + + $opportunity_ids = $app->repo('Opportunity')->findValuerOpportunities($user->id, only_ids: true); + + $query_params = $this->data; + $query_params['id'] = API::IN($opportunity_ids); + + unset($query_params['@user']); + + $query = new ApiQuery(EntitiesOpportunity::class, $query_params); + $result = $query->find(); + + $this->apiAddHeaderMetadata($query_params, $result, $query->count()); + $this->apiResponse($result); + } } \ No newline at end of file diff --git a/src/core/Entities/EvaluationMethodConfiguration.php b/src/core/Entities/EvaluationMethodConfiguration.php index 51aa2364ea..211e3e1108 100644 --- a/src/core/Entities/EvaluationMethodConfiguration.php +++ b/src/core/Entities/EvaluationMethodConfiguration.php @@ -325,6 +325,11 @@ public function getSummary($skip_cache = false): array { return $app->mscache->fetch($cache_key); } } + + if ($app->config['app.log.summary']) { + $app->log->debug("SUMMARY: Atualizando o resumo de avaliações da fase {$this->name} ($this->id)"); + } + $em = $this->evaluationMethod; $conn = $app->em->getConnection(); $opportunity = $this->owner; @@ -402,7 +407,65 @@ public function getSummary($skip_cache = false): array { return $data; } - public function enqueueUpdateSummary($start_string = '10 seconds') { + + + public function getValuerSummary(?User $user = null): array { + $app = App::i(); + + /** @var \MapasCulturais\Connection $conn */ + $conn = $app->em->getConnection(); + $opportunity = $this->opportunity; + $data = []; + if($user) { + $user_ids = [$user->id]; + } else { + $agent_relations = $this->getAgentRelations(); + + $user_ids = array_map(fn($agent_relation) => $agent_relation->agent->user->id, $agent_relations); + } + + $user_ids = implode(',', $user_ids); + /** + * Constrói a query para contar as avaliações com base no status. + * + * @param int|null $status Status da avaliação (0 = iniciada, 1 = concluída, 2 = enviada). + * @return int Retorna a contagem de avaliações. + */ + $buildQuery = function ($status = null) use ($user_ids, $opportunity, $conn): int { + $statusCondition = is_null($status) ? "e.status IS NULL" : "e.status = {$status} AND e.registration_id IN (SELECT r.id FROM registration r WHERE r.opportunity_id = {$opportunity->id})"; + + + $query = " + SELECT DISTINCT count(e.registration_id) + FROM registration_evaluation e + WHERE {$statusCondition} AND user_id IN($user_ids) + "; + + return $conn->fetchScalar($query); + }; + + // Avaliações pendentes + $query = " + SELECT DISTINCT count(e.registration_id) + FROM evaluations e + WHERE opportunity_id = {$opportunity->id} AND e.evaluation_status IS NULL AND valuer_user_id IN ($user_ids) + "; + + $data['pending'] = $conn->fetchScalar($query); + + // Avaliações iniciadas + $data['started'] = $buildQuery(0); + + // Avaliações concluídas + $data['completed'] = $buildQuery(1); + + // Avaliações enviadas + $data['sent'] = $buildQuery(2); + + return $data; + } + + public function enqueueUpdateSummary(string $start_string = 'now') { $app = App::i(); $app->enqueueOrReplaceJob(UpdateSummaryCaches::SLUG, [ 'evaluationMethodConfiguration' => $this @@ -488,11 +551,7 @@ protected function canUserRemove($user){ } protected function canUserManageEvaluationCommittee($user){ - if(!$this->canUser('@controll', $user)){ - return false; - } - - return true; + return $this->opportunity->canUser('@control', $user); } protected function canUserCreateAgentRelationWithControl($user){ diff --git a/src/core/Entities/EvaluationMethodConfigurationAgentRelation.php b/src/core/Entities/EvaluationMethodConfigurationAgentRelation.php index a0fef5a2e4..5719d370bd 100644 --- a/src/core/Entities/EvaluationMethodConfigurationAgentRelation.php +++ b/src/core/Entities/EvaluationMethodConfigurationAgentRelation.php @@ -3,6 +3,7 @@ use MapasCulturais\App; use Doctrine\ORM\Mapping as ORM; +use MapasCulturais\EvaluationMethod; use MapasCulturais\Exceptions\PermissionDenied; use MapasCulturais\Exceptions\WorkflowRequest; use MapasCulturais\GuestUser; @@ -46,6 +47,12 @@ public function __construct() parent::__construct(); } + function save($flush = false) + { + $this->owner->__skipQueuingPCacheRecreation = true; + $this->owner->opportunity->__skipQueuingPCacheRecreation = true; + parent::save($flush); + } function delete($flush = false) { $app = App::i(); @@ -59,7 +66,9 @@ function delete($flush = false) { } $app->enableAccessControl(); - $this->owner->opportunity->enqueueToPCacheRecreation([$this->agent->user]); + $this->owner->opportunity->__skipQueuingPCacheRecreation = true; + $this->owner->__skipQueuingPCacheRecreation = true; + parent::delete($flush); } @@ -69,8 +78,8 @@ function reopen($flush = true){ $app = App::i(); $app->applyHookBoundTo($this,"{$this->hookPrefix}.reopen:before"); + $this->status = self::STATUS_ENABLED; - $this->save($flush); $job = $app->enqueueJob(ReopenEvaluations::SLUG, ['agentRelation' => $this]); @@ -125,65 +134,12 @@ function enable($flush = true){ * @throws PermissionDenied * @throws WorkflowRequest */ - function updateSummary(bool $flush = false, bool $pending = true, bool $started = true, bool $completed = true, bool $sent = true): void + function updateSummary(): void { - $entity = $this->owner; $app = App::i(); - /** @var \MapasCulturais\Connection $conn */ - $conn = $app->em->getConnection(); - - $user = $this->agent->user; - $data = $this->metadata["summary"] ?? []; - - /** - * Constrói a query para contar as avaliações com base no status. - * - * @param int|null $status Status da avaliação (0 = iniciada, 1 = concluída, 2 = enviada). - * @return int Retorna a contagem de avaliações. - */ - $buildQuery = function ($status = null) use ($user, $entity, $conn): int { - $statusCondition = is_null($status) ? "e.status IS NULL" : "e.status = {$status} AND e.registration_id IN (SELECT r.id FROM registration r WHERE r.opportunity_id = {$entity->opportunity->id})"; - - $query = " - SELECT DISTINCT count(e.registration_id) - FROM registration_evaluation e - WHERE {$statusCondition} AND user_id = {$user->id} - "; - - return $conn->fetchScalar($query); - }; - - // Atualiza as avaliações pendentes - if ($pending) { - $query = " - SELECT DISTINCT count(e.registration_id) - FROM evaluations e - WHERE opportunity_id = {$entity->opportunity->id} AND e.evaluation_status IS NULL AND valuer_user_id = {$user->id} - "; - $data['pending'] = $conn->fetchScalar($query); - } else { - $data['pending'] = $data['pending'] ?? 0; - } - - // Atualiza as avaliações iniciadas - if ($started) { - $data['started'] = $buildQuery(0); - } else { - $data['started'] = $data['started'] ?? 0; - } - - // Atualiza as avaliações concluídas - if ($completed) { - $data['completed'] = $buildQuery(1); - } else { - $data['completed'] = $data['completed'] ?? 0; - } - - // Atualiza as avaliações enviadas - if ($sent) { - $data['sent'] = $buildQuery(2); - } else { - $data['sent'] = $data['sent'] ?? 0; + + if ($app->config['app.log.summary']) { + $app->log->debug("SUMMARY: Atualizando o resumo de avaliações do avaliador {$this->agent->name}"); } if(is_object($this->metadata)) { @@ -192,8 +148,11 @@ function updateSummary(bool $flush = false, bool $pending = true, bool $started $metadata = (object) []; } - $metadata->summary = $data; + $user = $this->agent->user; + $evaluation_method_configuration = $this->owner; + $metadata->summary = $evaluation_method_configuration->getValuerSummary($user); + $conn = $app->em->getConnection(); $conn->update('agent_relation', ['metadata' => json_encode($metadata)], ['id' => $this->id]); } @@ -201,4 +160,9 @@ protected function canUserRemove($user): bool { return $this->owner->canUser('manageEvaluationCommittee', $user); } + + protected function canUserModify($user): bool + { + return $this->owner->canUser('manageEvaluationCommittee', $user); + } } diff --git a/src/core/Entities/Opportunity.php b/src/core/Entities/Opportunity.php index f108105d34..e25da76723 100644 --- a/src/core/Entities/Opportunity.php +++ b/src/core/Entities/Opportunity.php @@ -773,13 +773,7 @@ function setRegistrationCategories(string|array $categories) { $new_categories = Utils::nl2array($categories); } - if (is_array($new_categories)) { - $new_categories = array_filter($new_categories , function($category){ - return !empty($category); - }); - } - - $removed_categories = array_diff($this->registrationCategories, $new_categories); + $removed_categories = array_filter(array_diff($this->registrationCategories, $new_categories)); $errors = []; foreach ($removed_categories as $removed_category) { @@ -1388,11 +1382,14 @@ public function getSummary($skip_cache = false): array { $cache_key = $this->summaryCacheKey; if(!$skip_cache && $app->config['app.useOpportunitySummaryCache']) { - if ($app->mscache->contains($cache_key)) { return $app->mscache->fetch($cache_key); } } + + if ($app->config['app.log.summary']) { + $app->log->debug("SUMMARY: Atualizando o resumo de inscrições da fase {$this->name} ({$this->id})"); + } $params = ["opp" => $this]; diff --git a/src/core/Entities/Registration.php b/src/core/Entities/Registration.php index 7b6b73e962..d1b8dc2c7a 100644 --- a/src/core/Entities/Registration.php +++ b/src/core/Entities/Registration.php @@ -165,9 +165,9 @@ class Registration extends \MapasCulturais\Entity /** * @var integer * - * @ORM\Column(name="valuers_exceptions_list", type="text", nullable=false) + * @ORM\Column(name="valuers_exceptions_list", type="json", nullable=false) */ - protected $__valuersExceptionsList = '{"include": [], "exclude": []}'; + protected $__valuersExceptionsList; @@ -273,6 +273,8 @@ class Registration extends \MapasCulturais\Entity function __construct() { $app = App::i(); + $this->__valuersExceptionsList = (object) ["include" => [], "exclude" => []]; + $this->owner = $app->user->profile; if(!self::$hooked){ @@ -737,19 +739,20 @@ function randomIdGeneratorInitialRange(){ * @return mixed */ function getValuersExceptionsList(){ - return json_decode($this->__valuersExceptionsList); + if(is_string($this->__valuersExceptionsList) && json_validate($this->__valuersExceptionsList)) { + $this->__valuersExceptionsList = json_decode($this->__valuersExceptionsList); + } + return (object) $this->__valuersExceptionsList; } protected function _setValuersExceptionsList($object){ $this->checkPermission('modifyValuers'); if(is_object($object) && isset($object->exclude) && is_array($object->exclude) && isset($object->include) && is_array($object->include)){ - $this->__valuersExceptionsList = json_encode($object); + $this->__valuersExceptionsList = $object; } else { throw new \Exception('Invalid __valuersExceptionsList format'); } - - $this->enqueueToPCacheRecreation(); } function setValuersExcludeList(array $user_ids){ @@ -771,7 +774,7 @@ function setValuersIncludeList(array $user_ids){ */ function getValuersIncludeList(){ $exceptions = $this->getValuersExceptionsList(); - return $exceptions->include; + return (array) $exceptions->include; } /** @@ -780,7 +783,7 @@ function getValuersIncludeList(){ */ function getValuersExcludeList(){ $exceptions = $this->getValuersExceptionsList(); - return $exceptions->exclude; + return (array) $exceptions->exclude; } /** diff --git a/src/core/Entities/RegistrationEvaluation.php b/src/core/Entities/RegistrationEvaluation.php index 64f6758702..7bfa93d3f1 100644 --- a/src/core/Entities/RegistrationEvaluation.php +++ b/src/core/Entities/RegistrationEvaluation.php @@ -2,21 +2,29 @@ namespace MapasCulturais\Entities; +use Doctrine\ORM\Exception\NotSupported; use MapasCulturais; use MapasCulturais\i; use MapasCulturais\Traits; use Doctrine\ORM\Mapping as ORM; use Doctrine\Persistence\Mapping\MappingException; use MapasCulturais\App; +use MapasCulturais\Exceptions\PermissionDenied; +use MapasCulturais\Exceptions\WorkflowRequest; use ReflectionException; +use RuntimeException; /** * RegistrationMeta * + * @property-read \MapasCulturais\Definitions\EvaluationMethod $evaluationMethodDefinition + * @property-read EvaluationMethodConfiguration $evaluationMethodConfiguration + * @property-read \MapasCulturais\EvaluationMethod $evaluationMethod + * @property-read string $resultString + * @property-read string $statusString * @property-read string $result * * @property integer $id - * @property mexed $result * @property object $evaluationData * @property Registration $registration * @property User $user @@ -167,7 +175,7 @@ public function getEvaluationMethodDefinition() { /** * Returns the Evaluation Method Configuration - * @return \MapasCulturais\Definitions\EvaluationMethodConfiguration + * @return EvaluationMethodConfiguration */ public function getEvaluationMethodConfiguration() { return $this->registration->evaluationMethodConfiguration; @@ -287,6 +295,20 @@ public static function getEntityTypeLabel($plural = false): string { return \MapasCulturais\i::__('Avaliação de Inscrição'); } + /** + * Atualiza os resumos do avaliador + * + * @return void + */ + public function updateValuerSummaries() { + /** @var EvaluationMethodConfigurationAgentRelation[] */ + $relations = $this->evaluationMethodConfiguration->getAgentRelationOfUser($this->user); + + foreach($relations as $relation) { + $relation->updateSummary(); + } + } + //============================================================= // // The following lines ara used by MapasCulturais hook system. // Please do not change them. @@ -304,6 +326,7 @@ public function postPersist($args = null){ parent::postPersist($args); $this->registration->consolidateResult(true, $this); + $this->updateValuerSummaries(); } /** @ORM\PreRemove */ @@ -313,6 +336,7 @@ public function postRemove($args = null){ parent::postRemove($args); $this->registration->consolidateResult(true, $this); + $this->updateValuerSummaries(); } /** @ORM\PreUpdate */ @@ -322,9 +346,6 @@ public function postUpdate($args = null){ parent::postUpdate($args); $this->registration->consolidateResult(true, $this); - } - - public function getResult() { - return $this->result; + $this->updateValuerSummaries(); } } diff --git a/src/core/EvaluationMethod.php b/src/core/EvaluationMethod.php index 463f7b16cb..c5dc5dd873 100644 --- a/src/core/EvaluationMethod.php +++ b/src/core/EvaluationMethod.php @@ -4,6 +4,7 @@ use MapasCulturais\Entities\RegistrationEvaluation; use MapasCulturais\i; use MapasCulturais\Entities; +use MapasCulturais\Entities\EvaluationMethodConfiguration; use MapasCulturais\Entities\EvaluationMethodConfigurationAgentRelation; use MapasCulturais\Entities\Opportunity; use MapasCulturais\Entities\Registration; @@ -27,6 +28,13 @@ abstract function _getEvaluationDetails(Entities\RegistrationEvaluation $evaluat abstract function _getConsolidatedDetails(Entities\Registration $registration): ?array; + static function getNextRedistributionDateTime(): \DateTime { + $app = App::i(); + $str_time = date($app->config['registrations.distribution.dateString']) . ' ' . $app->config['registrations.distribution.incrementString']; + $datetime = new \DateTime($str_time); + return $datetime; + } + public function cmpValues($value1, $value2){ if($value1 > $value2){ return 1; @@ -266,6 +274,12 @@ function getConsolidatedDetails(Entities\Registration $registration): array { * @return Entities\User[][] */ function getCommitteeGroups(Entities\EvaluationMethodConfiguration $evaluation_config): array { + $cache_key = __METHOD__ . ':' . $evaluation_config->id; + $app = App::i(); + + if($app->rcache->contains($cache_key)){ + return $app->rcache->fetch($cache_key); + } $committee = []; foreach($evaluation_config->getAgentRelations(null, false) as $relation) { @@ -275,6 +289,8 @@ function getCommitteeGroups(Entities\EvaluationMethodConfiguration $evaluation_c } } + $app->rcache->save($cache_key, $committee); + return $committee; } @@ -291,6 +307,11 @@ function evaluationPhaseUsesTiebreaker(Entities\EvaluationMethodConfiguration|nu return false; } + $cache_key = __METHOD__ . ':' . $evaluation_method_configuration->id; + if($app->rcache->contains($cache_key)){ + return $app->rcache->fetch($cache_key); + } + /** @var Connection */ $conn = $app->em->getConnection(); @@ -308,6 +329,8 @@ function evaluationPhaseUsesTiebreaker(Entities\EvaluationMethodConfiguration|nu 'id' => $evaluation_method_configuration->id ]); + $app->rcache->save($cache_key, (bool) $uses); + return (bool) $uses; } @@ -324,6 +347,11 @@ function registrationNeedsTiebreaker(Registration $registration): bool { return false; } + $cache_key = __METHOD__ . ':' . $registration->id; + if($app->rcache->contains($cache_key)){ + return $app->rcache->fetch($cache_key); + } + $registration_committee = $registration->getCommittees(true); $valuer_users = []; @@ -365,6 +393,7 @@ function registrationNeedsTiebreaker(Registration $registration): bool { } if($num > 0) { + $app->rcache->save($cache_key, false); return false; } } @@ -382,14 +411,19 @@ function registrationNeedsTiebreaker(Registration $registration): bool { // se há mais que um valor no array, então há divergência if(count(array_unique($results)) > 1) { - return true; + $result = true; } else { - return false; + $result = false; } + + $app->rcache->save($cache_key, $result); + return $result; } public function redistributeRegistrations(Entities\Opportunity $opportunity) { $app = App::i(); + $opportunity->registerRegistrationMetadata(); + $evaluation_config = $opportunity->evaluationMethodConfiguration; $conn = $app->em->getConnection(); @@ -404,19 +438,12 @@ public function redistributeRegistrations(Entities\Opportunity $opportunity) { $committee['@tiebreaker'] = $tiebreaker_committee; } - $must_enqueue_evaluation_config = false; - $non_tiebreaker_valuers = []; foreach($committee as $group => $committee_users) { $valuers_per_registration = (int) ($evaluation_config->valuersPerRegistration->$group ?? 0); $ignore_started_evaluations = $evaluation_config->ignoreStartedEvaluations->$group ?? false; - if(!$valuers_per_registration) { - $must_enqueue_evaluation_config = true; - continue; - } - $committee_user_ids = array_map(fn($user) => $user->id, $committee_users); $_user_ids = implode(',', $committee_user_ids); @@ -493,16 +520,40 @@ public function redistributeRegistrations(Entities\Opportunity $opportunity) { } foreach($result as &$reg) { + /** @var Registration $registration */ + $registration = $app->repo('Registration')->find($reg->id); + + if(!$this->mustBeEvaluatedByCommittee($evaluation_config, $registration, $group)) { + if($app->config['app.log.evaluations']) { + $app->log->debug("Registration:: {$reg->id} não pode ser avaliada pela comissão: $group"); + } + continue; + } + + if($valuers_per_registration && (count($reg->valuers) >= $valuers_per_registration)) { + if($app->config['app.log.evaluations']) { + $app->log->debug("Registration:: {$reg->id} já conta com todos os avaliadores necessários"); + } + continue; + } + foreach($valuers as &$valuer) { $user = $valuer->user; + + if($valuers_per_registration && (count($reg->valuers) >= $valuers_per_registration)) { + if($app->config['app.log.evaluations']) { + $app->log->debug("Registration:: {$reg->id} já conta com todos os avaliadores necessários"); + } + break; + } - if(count($reg->valuers) >= $valuers_per_registration || in_array($user->id, $reg->valuers)) { + if(in_array($user->id, $reg->valuers)) { + if($app->config['app.log.evaluations']) { + $app->log->debug("Registration:: {$reg->id} - User: {$valuer->user->id} já é avaliador"); + } continue; } - /** @var Registration $registration */ - $registration = $app->repo('Registration')->find($reg->id); - if($group == '@tiebreaker' && !$this->registrationNeedsTiebreaker($registration)) { continue; } @@ -511,9 +562,15 @@ public function redistributeRegistrations(Entities\Opportunity $opportunity) { $reg->valuers[] = $user->id; $valuer->count++; } + + if($app->config['app.log.evaluations']) { + $app->log->debug("Registration: {$reg->id} - User: {$valuer->user->id} - Count: {$valuer->count}"); + } + } usort($valuers, fn($u1, $u2) => $u1->count <=> $u2->count); + $app->em->clear(); } foreach($result as $r) { @@ -526,18 +583,176 @@ public function redistributeRegistrations(Entities\Opportunity $opportunity) { } foreach($registrations_valuers as $registration_id => $r) { - $app->log->debug(print_r($r->valuers, true)); - $users = array_merge($r->valuers_exceptions_list->include, $r->valuers_exceptions_list->exclude, $r->valuers); $r->valuers_exceptions_list->include = $r->valuers; $json = json_encode ($r->valuers_exceptions_list); - - $app->log->debug("$registration_id $json"); $conn->update('registration', ['valuers_exceptions_list' => $json], ['id' => $registration_id]); - $r = $app->repo('Registration')->find($registration_id); - $r->enqueueToPCacheRecreation($users); + + if($app->config['app.log.evaluations']) { + $app->log->debug("Avaliadores da inscrição {$registration_id}: " . json_encode($r->valuers)); + } + } + + // atualiza os resumos das avaliações + $evaluationMethodConfiguration = $opportunity->evaluationMethodConfiguration; + $app->mscache->delete($evaluationMethodConfiguration->summaryCacheKey); + + if($app->config['app.log.evaluations']) { + $app->log->debug("Atualizando o resumo de avaliações da fase {$evaluationMethodConfiguration->name} ({$evaluationMethodConfiguration->id})"); + + } + $evaluationMethodConfiguration->getSummary(true); + + /** @var EvaluationMethodConfigurationAgentRelation[] */ + $relations = $evaluationMethodConfiguration->getAgentRelations(); + foreach($relations as $relation) { + $relation->updateSummary(); + } + } + + /** + * Verifica se a inscrição deve ser avaliada por um determinado comitê + * @param mixed $registration + * @param string $committee_name + * @return bool + */ + public function mustBeEvaluatedByCommittee(EvaluationMethodConfiguration $evaluation_config, Registration $registration, string $committee_name): bool { + $can = true; + + $global_filter_configs = $evaluation_config->fetchFields; + $global_filter_configs = (array) ($global_filter_configs->$committee_name ?? []); + + if ( $categories = $global_filter_configs['category'] ?? null) { + unset($global_filter_configs['category']); + if(!$this->canEvaluateRegistrationCategory($registration, $categories)) { + $can = false; + } + } + + if ( $ranges = $global_filter_configs['range'] ?? null) { + unset($global_filter_configs['range']); + if(!$this->canEvaluateRegistrationRange($registration, $ranges)) { + $can = false; + } + } + + if ( $proponent_types = $global_filter_configs['proponentType'] ?? null) { + unset($global_filter_configs['proponentType']); + if(!$this->canEvaluateRegistrationProponentType($registration, $proponent_types)) { + $can = false; + } + } + + + if($global_filter_configs) { + if(!$this->canEvaluateRegistrationFields($registration, $global_filter_configs)) { + $can = false; + } + } + + return $can; + } + + /** + * Verifica se a categoria da inscrição deve ser avaliada pelo filtro + * @param Registration $registration + * @param array $filter_configuration + * @return bool + */ + public function canEvaluateRegistrationCategory(Entities\Registration $registration, array $filter_configuration): bool { + foreach($filter_configuration as $cat){ + $cat = trim($cat); + if(strtolower((string)$registration->category) === strtolower($cat)){ + return true; + } + } + + return false; + } + + /** + * Verifica se a faixa da inscrição deve ser avaliada pelo filtro + * @param Registration $registration + * @param array $filter_configuration + * @return bool + */ + public function canEvaluateRegistrationRange(Entities\Registration $registration, array $filter_configuration): bool { + foreach($filter_configuration as $cat){ + $cat = trim($cat); + if(strtolower((string)$registration->range) === strtolower($cat)){ + return true; + } + } + + return false; + } + + /** + * Verifica se o tipo de proponente da inscrição deve ser avaliada pelo filtro + * @param Registration $registration + * @param array $filter_configuration + * @return bool + */ + public function canEvaluateRegistrationProponentType(Entities\Registration $registration, array $filter_configuration): bool { + foreach($filter_configuration as $cat){ + $cat = trim($cat); + if(strtolower((string)$registration->proponentType) === strtolower($cat)){ + return true; + } + } + + return false; + } + + /** + * Verifica se o número da inscrição deve ser avaliada pelo filtro por número + * @param Registration $registration + * @param string $filter_configuration + * @return bool + */ + public function canEvaluateRegistrationNumber(Entities\Registration $registration, string $filter_configuration) { + $can = true; + + if(preg_match("#([0-9]+) *[-] *([0-9]+)*#", $filter_configuration, $matches)){ + $s1 = $matches[1]; + $s2 = $matches[2]; + + $len = max([strlen($s1), strlen($s2)]); + + $fin = substr($registration->number, -$len); + + if(intval($s2) == 0){ // "00" => "100" + $s2 = "1$s2"; + } + if($fin < $s1 || $fin > $s2){ + $can = false; + } + } + + return $can; + } + + public function canEvaluateRegistrationFields(Entities\Registration $registration, array $filter_configuration): bool { + $can = true; + /** @var Opportunity $opportunity */ + $opportunity = $registration->opportunity; + $opportunity->registerRegistrationMetadata(); + + foreach($filter_configuration as $field_name => $values){ + $found_field = false; + foreach($values as $val) { + $val = trim($val); + + if(strtolower((string)$registration->metadata[$field_name]) === strtolower($val)){ + $found_field = true; + } + } + + if($values && !$found_field){ + $can = false; + } } - $app->persistPCachePendingQueue(); + return $can; } public function canUserEvaluateRegistration(Entities\Registration $registration, User|GuestUser $user, $skip_exceptions = false, $skip_valuers_limit = false){ @@ -547,7 +762,7 @@ public function canUserEvaluateRegistration(Entities\Registration $registration, return false; } - $cache_key = "$registration -> $user"; + $cache_key = "$registration -> $user -> $skip_exceptions -> $skip_valuers_limit"; if(!$skip_exceptions && !$skip_valuers_limit && $app->rcache->contains($cache_key)){ return $app->rcache->fetch($cache_key); } @@ -555,11 +770,15 @@ public function canUserEvaluateRegistration(Entities\Registration $registration, $evaluation_config = $registration->evaluationMethodConfiguration; $valuers_per_registration_config = $evaluation_config->valuersPerRegistration; - - $agent_relations = $app->repo('EvaluationMethodConfigurationAgentRelation')->findBy([ - 'owner' => $evaluation_config, - 'agent' => $user->profile - ]); + $agent_relations = []; + + foreach($evaluation_config->getRelatedAgents(return_relations: true) as $relations) { + $agent_relations = array_merge($agent_relations, $relations); + } + + $agent_relations = array_filter($agent_relations, function($ar) use($user) { + return $ar->agent->user->equals($user); + }); $is_same_as_evaluator = false; $has_global_filter_configs = false; @@ -621,14 +840,14 @@ public function canUserEvaluateRegistration(Entities\Registration $registration, if($can = $evaluation_config->canUser('@control', $user) && !$has_limit){ $fetch = []; - $config_fetch = is_array($evaluation_config->fetch) ? $evaluation_config->fetch : (array) $evaluation_config->fetch; - $config_fetchCategories = is_array($evaluation_config->fetchCategories) ? $evaluation_config->fetchCategories : (array) $evaluation_config->fetchCategories; - $config_ranges = is_array($evaluation_config->fetchRanges) ? $evaluation_config->fetchRanges : (array) $evaluation_config->fetchRanges; - $config_proponent_types = is_array($evaluation_config->fetchProponentTypes) ? $evaluation_config->fetchProponentTypes : (array) $evaluation_config->fetchProponentTypes; - $config_selection_fields = is_array($evaluation_config->fetchSelectionFields) ? $evaluation_config->fetchSelectionFields : (array) $evaluation_config->fetchSelectionFields; - $global_filter_configs = isset($evaluation_config->fetchFields) && is_array($evaluation_config->fetchFields) ? $evaluation_config->fetchFields : (array) $evaluation_config->fetchFields; + $config_fetch = (array) $evaluation_config->fetch; + $config_fetchCategories = (array) $evaluation_config->fetchCategories; + $config_ranges = (array) $evaluation_config->fetchRanges; + $config_proponent_types = (array) $evaluation_config->fetchProponentTypes; + $config_selection_fields = (array) $evaluation_config->fetchSelectionFields; + $global_filter_configs = (array) $evaluation_config->fetchFields; - $relations = $registration->opportunity->evaluationMethodConfiguration->agentRelations; + $relations = $evaluation_config->agentRelations; if(is_array($global_filter_configs)) { $global_config_categories = []; @@ -637,20 +856,14 @@ public function canUserEvaluateRegistration(Entities\Registration $registration, $global_config_selection_fields = []; foreach($relations as $relation) { - if($relation->agent->id == $user->profile->id) { + if($relation->agent->user->equals($user)) { $committee_config = $global_filter_configs[$relation->group] ?? (object) []; - if(!empty($committee_config->category)) { - $global_config_categories = array_merge($global_config_categories, (array) $committee_config->category); - } + $global_config_categories = array_merge($global_config_categories, (array) ($committee_config->category ?? [])); - if(!empty($committee_config->range)) { - $global_config_ranges = array_merge($global_config_ranges, (array) $committee_config->range); - } + $global_config_ranges = array_merge($global_config_ranges, (array) ($committee_config->range ?? [])); - if(!empty($committee_config->proponentType)) { - $global_config_proponent_types = array_merge($global_config_proponent_types, (array) $committee_config->proponentType); - } + $global_config_proponent_types = array_merge($global_config_proponent_types, (array) ($committee_config->proponentType ?? [])); foreach ($committee_config as $key => $value) { if (!in_array($key, ['category', 'range', 'proponentType', 'distribution'])) { @@ -712,125 +925,38 @@ public function canUserEvaluateRegistration(Entities\Registration $registration, } } - if(isset($fetch[$user->id])){ - $ufetch = $fetch[$user->id]; - if(preg_match("#([0-9]+) *[-] *([0-9]+)*#", $ufetch, $matches)){ - $s1 = $matches[1]; - $s2 = $matches[2]; - - $len = max([strlen($s1), strlen($s2)]); - - $fin = substr($registration->number, -$len); - - if(intval($s2) == 0){ // "00" => "100" - $s2 = "1$s2"; - } - if($fin < $s1 || $fin > $s2){ - $can = false; - } + // verifica permissão de avaliação por número da inscrição + if ($ufetch = $fetch[$user->id] ?? false){ + if(!$this->canEvaluateRegistrationNumber($registration, $ufetch)){ + $can = false; } } - if(isset($fetch_categories[$user->id])){ - $ucategories = $fetch_categories[$user->id]; - if($ucategories){ - if(!is_array($ucategories)) { - $ucategories = explode(';', $ucategories); - } - - if($ucategories){ - $found = false; - - foreach($ucategories as $cat){ - $cat = trim($cat); - if(strtolower((string)$registration->category) === strtolower($cat)){ - $found = true; - } - } - - if(!$found) { - $can = false; - } - } + // verifica permissão de avaliação por categoria + if ($ucategories = $fetch_categories[$user->id] ?? false){ + if(!$this->canEvaluateRegistrationCategory($registration, $ucategories)){ + $can = false; } } - if(isset($fetch_ranges[$user->id])){ - $uranges = $fetch_ranges[$user->id]; - if($uranges){ - if(!is_array($uranges)) { - $uranges = explode(';', $uranges); - } - - if($uranges){ - $found = false; - - foreach($uranges as $ran){ - $ran = trim($ran); - if(strtolower((string)$registration->range) === strtolower($ran)){ - $found = true; - } - } - - if(!$found) { - $can = false; - } - } + // verifica permissão de avaliação por faixa + if ($uranges = $fetch_ranges[$user->id] ?? false){ + if(!$this->canEvaluateRegistrationRange($registration, $uranges)){ + $can = false; } } - - if(isset($fetch_proponent_types[$user->id])){ - $uproponet_types = $fetch_proponent_types[$user->id]; - if($uproponet_types){ - if(!is_array($uproponet_types)) { - $uproponet_types = explode(';', $uproponet_types); - } - - if($uproponet_types){ - $found = false; - foreach($uproponet_types as $ran){ - $ran = trim($ran); - if(strtolower((string)$registration->proponentType) === strtolower($ran)){ - $found = true; - } - } - - if(!$found) { - $can = false; - } - } + // verifica permissão de avaliação por tipo de proponente + if ($uproponent_types = $fetch_proponent_types[$user->id] ?? false){ + if(!$this->canEvaluateRegistrationProponentType($registration, $uproponent_types)){ + $can = false; } } - - if(isset($fetch_selection_fields[$user->id])){ - $uselection_fields = $fetch_selection_fields[$user->id]; - if($uselection_fields){ - if($uselection_fields){ - $found_selection_fields = false; - - /** @var Opportunity $opportunity */ - $opportunity = $registration->opportunity; - $opportunity->registerRegistrationMetadata(); - $fields = $opportunity->registrationFieldConfigurations; - - $field_name = []; - foreach($fields as $field) { - $field_name[$field->title] = $field->fieldName; - } - foreach($uselection_fields as $key => $values){ - foreach($values as $val) { - $val = trim($val); - - if(strtolower((string)$registration->metadata[$field_name[$key]]) === strtolower($val)){ - $found_selection_fields = true; - } - } - } - - $can = $found_selection_fields ? true : false; - } + // verifica permissão de avaliação por campos de seleção + if ($uselection_fields = $fetch_selection_fields[$user->id] ?? false){ + if(!$this->canEvaluateRegistrationFields($registration, $uselection_fields)){ + $can = false; } } } diff --git a/src/core/Repositories/Opportunity.php b/src/core/Repositories/Opportunity.php index 1fcd635ff0..0f4854bc30 100644 --- a/src/core/Repositories/Opportunity.php +++ b/src/core/Repositories/Opportunity.php @@ -4,7 +4,12 @@ use MapasCulturais\Entities\ProjectOpportunity; use MapasCulturais\Entities\Project; use DateTime; - +use Doctrine\DBAL\Exception; +use Doctrine\ORM\Query; +use LogicException; +use Doctrine\ORM\Exception\ORMException; +use MapasCulturais\App; +use Psr\Cache\InvalidArgumentException; class Opportunity extends \MapasCulturais\Repository{ use Traits\RepositoryKeyword, @@ -68,5 +73,47 @@ function findByProjectAndOpportunityMeta(Project $project, $key, $value, $status return $query->getResult(); } + + /** + * Retornar as oportunidades que o avaliador pode avaliar + * + * @param int $valuer_user_id + * @return Opportunity[]|array + */ + function findValuerOpportunities(int $valuer_user_id, $only_ids = false, $hydration_mode = Query::HYDRATE_OBJECT): array { + $app = App::i(); + + $conn = $app->em->getConnection(); + + $opportunity_ids = $conn->fetchFirstColumn(" + select distinct(opportunity_id) from evaluations where valuer_user_id = :valuer_user_id; + ", [ + 'valuer_user_id' => $valuer_user_id, + ]); + if (empty($opportunity_ids)) { + return []; + } + + if($only_ids) { + return $opportunity_ids; + } + + $query = $app->em->createQuery(" + SELECT + o + FROM + MapasCulturais\Entities\Opportunity o + WHERE + o.id in (:opportunity_ids) + AND o.status = 1 OR o.status = -1" + + ); + + $query->setParameters([ + 'opportunity_ids' => $opportunity_ids, + ]); + + return $query->getResult($hydration_mode); + } } diff --git a/src/core/Theme.php b/src/core/Theme.php index d4273364d3..43b58e92f0 100644 --- a/src/core/Theme.php +++ b/src/core/Theme.php @@ -860,7 +860,7 @@ function autoLinkString($text, $force = false) { } - function addRequestedEntityToJs(string $entity_class_name = null, int $entity_id = null, Entity $entity = null) { + function addRequestedEntityToJs(string $entity_class_name = null, int $entity_id = null, Entity $entity = null, $disable_access_control = false){ $entity_class_name = $entity_class_name ?: $this->controller->entityClassName ?? null; $entity_id = $entity_id ?: $this->controller->data['id'] ?? null; @@ -905,11 +905,17 @@ function addRequestedEntityToJs(string $entity_class_name = null, int $entity_id } $app->applyHookBoundTo($this, "view.requestedEntity($_entity).params", [&$query_params, $entity_class_name, $entity_id]); - + if($disable_access_control) { + $app->disableAccessControl(); + } + $query = new ApiQuery($entity_class_name, $query_params); $query->__useDQLCache = false; $e = $query->findOne(); + if($disable_access_control) { + $app->enableAccessControl(); + } } else { $e = $entity->jsonSerialize(); @@ -1025,5 +1031,4 @@ function addRequestedEntityToJs(string $entity_class_name = null, int $entity_id $this->jsObject['requestedEntity'] = $e; } } - -} +} \ No newline at end of file diff --git a/src/core/Traits/EntityAgentRelation.php b/src/core/Traits/EntityAgentRelation.php index cb02e7c697..4997331b3e 100644 --- a/src/core/Traits/EntityAgentRelation.php +++ b/src/core/Traits/EntityAgentRelation.php @@ -1,9 +1,12 @@ getAgentRelations($has_control, $include_pending_relations); + $result = array_filter($relations, function($relation) use ($user){ + return $relation->agent->user->id === $user->id; + }); + + return $result; + } + function getAgentRelations($has_control = null, $include_pending_relations = false){ if(!$this->id){ return []; diff --git a/src/db-updates.php b/src/db-updates.php index 1647ed1097..03aea641e6 100644 --- a/src/db-updates.php +++ b/src/db-updates.php @@ -1152,6 +1152,13 @@ function __try($sql, $cb = null){ __exec("ALTER TABLE permission_cache_pending ALTER column id SET DEFAULT nextval('permission_cache_pending_seq');"); }, + 'altera o tipo da coluna valuers_exceptions_list da tabela registration para jsonb' => function () { + __exec("ALTER TABLE registration ALTER COLUMN valuers_exceptions_list DROP DEFAULT;"); + __exec("ALTER TABLE registration ALTER COLUMN valuers_exceptions_list TYPE JSONB USING valuers_exceptions_list::JSONB"); + __exec("ALTER TABLE registration ALTER COLUMN valuers_exceptions_list SET DEFAULT '{\"include\": [], \"exclude\": []}'::jsonb;"); + __exec("CREATE INDEX registration_valuers_index ON registration USING GIN((valuers_exceptions_list->'include') jsonb_path_ops)"); + }, + /// MIGRATIONS - DATA CHANGES ========================================= 'migrate gender' => function() use ($conn) { @@ -1747,15 +1754,15 @@ function __try($sql, $cb = null){ }, - 'DROP VIEW evaluations' => function () { - __try("DROP VIEW evaluations"); + 'DROP MATERIALIZED VIEW evaluations!' => function () { + __try("DROP MATERIALIZED VIEW evaluations"); }, - 'RECREATE MATERIALIZED VIEW evaluations' => function() use($conn) { - __try("DROP MATERIALIZED VIEW IF EXISTS evaluations"); + 'Recria view evaluations!!!!' => function() use($conn) { + __try("DROP VIEW IF EXISTS evaluations"); $conn->executeQuery(" - CREATE MATERIALIZED VIEW evaluations AS ( + CREATE VIEW evaluations AS ( SELECT registration_id, registration_sent_timestamp, @@ -1786,32 +1793,29 @@ function __try($sql, $cb = null){ ON re.registration_id = r.id JOIN usr u ON u.id = re.user_id - where - r.status > 0 - UNION + WHERE + r.status > 0 + UNION SELECT r2.id AS registration_id, r2.sent_timestamp AS registration_sent_timestamp, r2.number AS registration_number, r2.category AS registration_category, r2.agent_id AS registration_agent_id, - p2.user_id AS valuer_user_id, + u2.id AS valuer_user_id, u2.profile_id AS valuer_agent_id, r2.opportunity_id, NULL AS evaluation_id, NULL AS evaluation_result, NULL AS evaluation_status + FROM registration r2 - JOIN pcache p2 - ON p2.object_id = r2.id AND - p2.object_type = 'MapasCulturais\Entities\Registration' AND - p2.action = 'evaluateOnTime' JOIN usr u2 - ON u2.id = p2.user_id + on ('[' || u2.id || ']')::jsonb <@ (r2.valuers_exceptions_list->'include') JOIN evaluation_method_configuration emc ON emc.opportunity_id = r2.opportunity_id - WHERE - r2.status > 0 + WHERE + r2.status = 1 ) AS evaluations_view GROUP BY registration_id, @@ -1826,15 +1830,8 @@ function __try($sql, $cb = null){ "); }, - 'enqueue job to refresh materialized view evaluations' => function() use($conn) { - $app = App::i(); - - $app->disableAccessControl(); - // é para rodar a cada minuto, por 10 anos - $app->enqueueOrReplaceJob(\Opportunities\Jobs\RefreshViewEvaluations::SLUG, [], interval_string: '1 minute', iterations: 60*24*365*10); - - // retorna false para executar a cada redeploy do serviço - return false; + 'delete job de refresh materialized view evaluations' => function() use($conn) { + __exec("DELETE FROM job WHERE name = 'RefreshViewEvaluations'"); }, 'adiciona oportunidades na fila de reprocessamento de cache' => function () use($conn) { @@ -2667,6 +2664,7 @@ function __try($sql, $cb = null){ 'support', 'viewUserEvaluation', 'evaluateOnTime', + 'evaluateRegistrations', 'createEvents', 'requestEventRelation');"); }, diff --git a/src/mc-updates.php b/src/mc-updates.php index d68cb33438..5fe7c4d1d2 100644 --- a/src/mc-updates.php +++ b/src/mc-updates.php @@ -554,5 +554,20 @@ } }); } - } + }, + + 'Redistribui as avaliações de todas as oportunidades para os avaliadores novamente' => function() use ($app) { + DB_UPDATE::enqueue(Opportunity::class, "id in (select opportunity_id from evaluation_method_configuration)", function (Opportunity $opportunity) use($app) { + if($opportunity->getEvaluationMethodDefinition()){ + $em = $opportunity->getEvaluationMethod(); + $app->log->debug('distribuindo avaliações da oportunidade ' . $opportunity->id . ' - ' . $opportunity->name); + $em->redistributeRegistrations($opportunity); + foreach($opportunity->getEvaluationCommittee(true) as $relation) { + $app->log->debug('atualiza sumário do avaliador ' . $relation->agent->id . ' - ' . $relation->agent->name); + $relation->updateSummary(); + } + + } + }); + }, ]; diff --git a/src/modules/Components/Module.php b/src/modules/Components/Module.php index 0543fdb592..71500c002e 100644 --- a/src/modules/Components/Module.php +++ b/src/modules/Components/Module.php @@ -124,13 +124,13 @@ function _init() $this->insideApp = false; $this->part('main-app--end'); },1000); - + if ($app->config['app.mode'] == 'development') { $app->hook('template(<<*>>):<<*>>', function () use($app) { $hook = $app->hooks->hookStack[count($app->hooks->hookStack) - 1]->name; if($this->version >= 2) { $this->import('mc-debug'); - echo "\n"; + echo "\n"; } }); } @@ -165,7 +165,7 @@ function _init() if ($app->mode == APPMODE_DEVELOPMENT) { $this->import('mc-debug'); - echo ""; + echo ""; } $app->applyHookBoundTo($this, $hook_name, $params); @@ -304,7 +304,7 @@ function _init() $app->applyHookBoundTo($this, "component({$component}):after", [$__data]); - if ($app->mode == APPMODE_DEVELOPMENT) { + if ($app->config['app.mode'] == APPMODE_DEVELOPMENT) { echo "\n"; } diff --git a/src/modules/Components/assets/js/components-base/API.js b/src/modules/Components/assets/js/components-base/API.js index fa8398d111..ae9ae75efd 100644 --- a/src/modules/Components/assets/js/components-base/API.js +++ b/src/modules/Components/assets/js/components-base/API.js @@ -90,7 +90,7 @@ globalThis.useEntitiesLists = Pinia.defineStore('entitiesLists', { globalThis.apiInstances = {}; class API { - constructor(objectType, scope, fetchOptions) { + constructor(objectType, scope = 'default', fetchOptions = undefined) { const instanceId = `${objectType}:${scope}`; if (apiInstances[instanceId]) { return apiInstances[instanceId]; @@ -99,7 +99,6 @@ class API { this.cache = useEntitiesCache(); this.lists = useEntitiesLists(); this.objectType = objectType; - this.abortController = null; this.options = { cacheMode: 'force-cache', ...fetchOptions @@ -273,11 +272,9 @@ class API { return this.fetch('find', query, {list, raw, rawProcessor}); } - async fetch(endpoint, query, {list, raw, rawProcessor, refresh}) { + async fetch(endpoint, query, { list, raw, rawProcessor, refresh, signal }) { let url = this.createApiUrl(endpoint, query); - this.abortController?.abort(); - this.abortController = new AbortController(); - return this.GET(url, {}, { signal: this.abortController.signal }).then(response => response.json().then(objs => { + return this.GET(url, {}, { signal }).then(response => response.json().then(objs => { let result; if(raw) { rawProcessor = rawProcessor || Utils.entityRawProcessor; diff --git a/src/modules/Components/components/mc-debug/template.php b/src/modules/Components/components/mc-debug/template.php index 5d075b0a5f..071b9fde85 100644 --- a/src/modules/Components/components/mc-debug/template.php +++ b/src/modules/Components/components/mc-debug/template.php @@ -4,4 +4,4 @@ * @var MapasCulturais\Themes\BaseV2\Theme $this */ ?> -{{name}} \ No newline at end of file +{{name}} \ No newline at end of file diff --git a/src/modules/Components/components/mc-entities/script.js b/src/modules/Components/components/mc-entities/script.js index 19173b09cf..f41d6170af 100644 --- a/src/modules/Components/components/mc-entities/script.js +++ b/src/modules/Components/components/mc-entities/script.js @@ -4,6 +4,7 @@ app.component('mc-entities', { data() { return { + abortController: null, api: new API(this.type, this.scope || 'default'), entities: [], page: 1, @@ -58,10 +59,7 @@ app.component('mc-entities', { }, limit: Number, permissions: String, - order: { - type: String, - default: 'id ASC' - }, + order: String, watchQuery: { type: Boolean, default: false @@ -86,36 +84,48 @@ app.component('mc-entities', { } }, - + + computed: { + defaultOrder () { + if ($DESCRIPTIONS[this.type].name) { + return 'name ASC'; + } else { + return 'id ASC'; + } + } + }, + methods: { populateQuery(query) { if (this.select) { query['@select'] = this.select; - } - + } + if (this.ids) { query[this.API.$PK] = 'IN(' + this.ids.join(',') + ')' } if (this.order) { query['@order'] = this.order; + } else if (!query['@order']) { + query['@order'] = this.defaultOrder; } - + if (this.limit) { query['@limit'] = this.limit; query['@page'] = this.page; } - + if (this.permissions) { query['@permissions'] = this.permissions; } }, getDataFromApi() { - let query = {...this.query}; - + const query = {...this.query}; + this.$emit('loading', query); - + this.populateQuery(query); const options = {list: this.entities, refresh: true}; @@ -123,12 +133,16 @@ app.component('mc-entities', { if (this.limit && this.page) { query['@page'] = this.page; } - + if (this.rawProcessor) { options.raw = true; options.rawProcessor = this.rawProcessor; }; + this.abortController?.abort(); + this.abortController = new AbortController(); + options.signal = this.abortController.signal; + const result = this.api.fetch(this.endpoint, query, options); result.then((entities) => { @@ -137,27 +151,22 @@ app.component('mc-entities', { return result; }, - - refresh(debounce) { - if (this.entities.loading) { - return; - }; + refresh(debounce) { if (this.timeout) { - clearTimeout(this.timeout) + clearTimeout(this.timeout); }; - this.entities.splice(0); this.timeout = setTimeout(() => { + this.entities.splice(0); this.entities.loading = true; - + this.getDataFromApi() .then(() => { this.entities.loading = false; }) }, debounce); }, - loadMore() { if (!this.limit) { @@ -197,4 +206,4 @@ app.component('mc-entities', { } }, }, -}); \ No newline at end of file +}); diff --git a/src/modules/Components/components/mc-status/script.js b/src/modules/Components/components/mc-status/script.js index 056f098d89..9ad0720804 100644 --- a/src/modules/Components/components/mc-status/script.js +++ b/src/modules/Components/components/mc-status/script.js @@ -33,11 +33,13 @@ app.component('mc-status', { case 'pago': case 'enviado': case 'enviada': + case 'habilitado': classes.push('mc-status--success'); break; case 'não selecionado': case 'não selecionada': + case 'inabilitado': case 'não aceito': case 'inválido': case 'inválida': @@ -59,23 +61,19 @@ app.component('mc-status', { case 'enviada': classes.push('mc-status--primary'); break; - case 'Avaliações pendentes': - case 'Avaliação pendente': + case 'avaliações pendentes': case 'avaliação pendente': classes.push('mc-status--evaluation-pending'); break; - case 'Avaliações iniciadas': - case 'Avaliação iniciada': + case 'avaliações iniciadas': case 'avaliação iniciada': classes.push('mc-status--evaluation-started'); break; - case 'Avaliações concluídas': - case 'Avaliação concluída': + case 'avaliações concluídas': case 'avaliação concluída': classes.push('mc-status--evaluation-completed'); break; - case 'Avaliações enviadas': - case 'Avaliação enviada': + case 'avaliações enviadas': case 'avaliação enviada': classes.push('mc-status--evaluation-sent'); break; diff --git a/src/modules/Components/components/mc-summary-evaluate/init.php b/src/modules/Components/components/mc-summary-evaluate/init.php index 015f9123c8..410a8f8325 100644 --- a/src/modules/Components/components/mc-summary-evaluate/init.php +++ b/src/modules/Components/components/mc-summary-evaluate/init.php @@ -5,49 +5,19 @@ $data['isActive'] = false; if($requestedEntity instanceof MapasCulturais\Entities\EvaluationMethodConfiguration){ - $entity = $requestedEntity; + $evaluation_method_configuration = $requestedEntity; }else if($requestedEntity instanceof MapasCulturais\Entities\Opportunity){ - $entity = $requestedEntity->evaluationMethodConfiguration; + $evaluation_method_configuration = $requestedEntity->evaluationMethodConfiguration; }else if($requestedEntity instanceof MapasCulturais\Entities\Registration){ - $entity = $requestedEntity->opportunity->evaluationMethodConfiguration; + $evaluation_method_configuration = $requestedEntity->opportunity->evaluationMethodConfiguration; } - - $conn = $app->em->getConnection(); +if($this->controller->action == 'allEvaluations') { + $data = $evaluation_method_configuration->getValuerSummary(); +} else { $user = isset($this->controller->data['user']) ? $app->repo("User")->find($this->controller->data['user']) : $app->user; - - if ($entity->opportunity->canUser('@control') && $this->controller->action == "allEvaluations") { - $user_filter = ' > 0'; - } else { - $user_filter = "= {$user->id}"; - } - - $buildQuery = function($colluns = "*", $params = "", $type = "fetchAll") use ($conn, $entity){ - return $conn->$type("SELECT {$colluns} FROM evaluations e WHERE opportunity_id = {$entity->opportunity->id} {$params}"); - }; - - $pending = $buildQuery("DISTINCT count(e.registration_id) as qtd", "AND e.evaluation_status IS NULL AND valuer_user_id $user_filter", "fetchAssoc"); - $data['pending'] = $pending['qtd']; - - $completed = $buildQuery("DISTINCT count(e.registration_id) as qtd", "AND e.evaluation_status = 1 AND valuer_user_id $user_filter", "fetchAssoc"); - $data['completed'] = $completed['qtd']; + $data = $evaluation_method_configuration->getValuerSummary($user); +} - $sent = $buildQuery("DISTINCT count(e.registration_id) as qtd", "AND e.evaluation_status = 2 AND valuer_user_id $user_filter", "fetchAssoc"); - $data['sent'] = $sent['qtd']; - - $started = $conn->fetchAssoc(" - SELECT DISTINCT count(e.registration_id) as qtd - FROM registration_evaluation e - WHERE - e.status = 0 AND - e.registration_id IN ( - SELECT r.id - FROM registration r - WHERE r.opportunity_id = {$entity->opportunity->id} - ) AND - user_id $user_filter"); - $data['started'] = $started['qtd']; - $data['isActive'] = true; - -$this->jsObject['config']['summaryEvaluations'] = $data; - +$data['isActive'] = true; +$this->jsObject['config']['summaryEvaluations'] = $data; \ No newline at end of file diff --git a/src/modules/Components/components/select-entity/template.php b/src/modules/Components/components/select-entity/template.php index e96816c811..4ca2c2a628 100644 --- a/src/modules/Components/components/select-entity/template.php +++ b/src/modules/Components/components/select-entity/template.php @@ -23,7 +23,7 @@