From c2fa3620e861cf88228b80e52bc7bb0e90f6cec0 Mon Sep 17 00:00:00 2001 From: Gabriel Moreira Date: Thu, 11 Dec 2025 16:14:15 -0300 Subject: [PATCH 01/16] validando no frontend(url valida, yt e vimeo id) --- .../config.d/autoload.php} | 0 .../application/themes/BaseV1/Theme.php | 5 +- .../themes/BaseV1/assets/js/editable.js | 22 +++-- .../themes/BaseV1/assets/js/mcValidations.js | 90 +++++++++++++++++++ 4 files changed, 107 insertions(+), 10 deletions(-) rename compose/{common/config.d/compose.autoload.php => local/config.d/autoload.php} (100%) create mode 100644 src/protected/application/themes/BaseV1/assets/js/mcValidations.js diff --git a/compose/common/config.d/compose.autoload.php b/compose/local/config.d/autoload.php similarity index 100% rename from compose/common/config.d/compose.autoload.php rename to compose/local/config.d/autoload.php diff --git a/src/protected/application/themes/BaseV1/Theme.php b/src/protected/application/themes/BaseV1/Theme.php index 856ed927c..8907b6031 100644 --- a/src/protected/application/themes/BaseV1/Theme.php +++ b/src/protected/application/themes/BaseV1/Theme.php @@ -1797,6 +1797,9 @@ function includeCommonAssets() { // Mensagens com base no SweetAlert2 $this->enqueueScript('app', 'mc-messages', 'js/mcMessages.js', array('mapasculturais')); + + // helpers para validação + $this->enqueueScript('app', 'mc-validations', 'js/mcValidations.js', array('mapasculturais')); } function includeIbgeJS() { @@ -1853,7 +1856,7 @@ function includeEditableEntityAssets() { 'changesSaved' => i::__('Edições salvas.'), 'unexpectedError' => i::__('Um erro inesperado aconteceu.'), 'insertVideoTitle' => i::__('Insira um título para seu vídeo.'), - 'insertVideoUrl' => i::__('Insira uma url de um vídeo do YouTube ou do Vimeo.'), + 'insertVideoUrl' => i::__('Insira uma url válida de um vídeo do YouTube ou do Vimeo.'), 'insertLinkTitle' => i::__('Insira um título para seu link.'), 'insertLinkUrl' => i::__('A url do link é inválida, insira uma url completa como http://www.google.com/.'), 'Limpar' => i::__('Limpar'), diff --git a/src/protected/application/themes/BaseV1/assets/js/editable.js b/src/protected/application/themes/BaseV1/assets/js/editable.js index 508751cab..b9832ff9d 100644 --- a/src/protected/application/themes/BaseV1/assets/js/editable.js +++ b/src/protected/application/themes/BaseV1/assets/js/editable.js @@ -895,16 +895,20 @@ MapasCulturais.MetalistManager = { var $errorTag = $form.find('.alert.danger'); $errorTag.html(''); - if(group === 'videos'){ - if($.trim($form.find('input.js-metalist-title').val()) === ''){ - $errorTag.html(labels['insertVideoTitle']).show(); - return false; - } - - var parsedURL = purl($linkField.val()); - if (parsedURL.attr('host').indexOf('youtube') === -1 && parsedURL.attr('host').indexOf('vimeo') === -1){ + if (group === 'videos') { + const title = $.trim($form.find('input.js-metalist-title').val()); + const url = $.trim($linkField.val()); + + if (!McValidations.requireHttps(url, 'insertVideoUrl', $errorTag, labels)) return false; + if (!McValidations.requireField(url, 'insertVideoUrl', $errorTag, labels)) return false; + if (!McValidations.requireField(title, 'insertVideoTitle', $errorTag, labels)) return false; + if (!McValidations.isValidUrl(url, 'insertVideoUrl', $errorTag, labels)) return false; + + const isValidYouTube = McValidations.isValidYouTube(url, 'insertVideoUrl', $errorTag, labels); + const isValidVimeo = McValidations.isValidVimeo(url, 'insertVideoUrl', $errorTag, labels); + + if (!isValidYouTube && !isValidVimeo) { $errorTag.html(labels['insertVideoUrl']).show(); - return false; } }else if (group === 'links'){ diff --git a/src/protected/application/themes/BaseV1/assets/js/mcValidations.js b/src/protected/application/themes/BaseV1/assets/js/mcValidations.js new file mode 100644 index 000000000..7eb824d77 --- /dev/null +++ b/src/protected/application/themes/BaseV1/assets/js/mcValidations.js @@ -0,0 +1,90 @@ +var McValidations = (function () { + + function showError(errorKey, $errorTag, labels) { + $errorTag.html(labels[errorKey]).show(); + return false; + } + + function requireField(value, errorKey, $errorTag, labels) { + if (!value) return showError(errorKey, $errorTag, labels); + return true; + } + + function requireHttps(url, errorKey, $errorTag, labels) { + if (!url.startsWith('https://')) return showError(errorKey, $errorTag, labels); + return true; + } + + function isValidUrl(url, errorKey, $errorTag, labels) { + if (!url) return showError(errorKey, $errorTag, labels); + + try { + new URL(url); + return true; + } catch { + return showError(errorKey, $errorTag, labels); + } + } + + function isValidYouTube(url, errorKey, $errorTag, labels) { + let parsed; + try { + parsed = new URL(url); + } catch { + return false; + } + + const host = parsed.hostname.replace(/^www\./, ''); + const youtubeHosts = ['youtube.com', 'youtu.be']; + + if (!youtubeHosts.some(h => host.endsWith(h))) { + return false; + } + + let videoId = null; + + if (host.endsWith('youtu.be')) { + videoId = parsed.pathname.slice(1); + } else if (host.endsWith('youtube.com')) { + videoId = parsed.searchParams.get('v'); + } + + if (!videoId || !/^[a-zA-Z0-9_-]{11}$/.test(videoId)) { + return false; + } + + return true; + } + + function isValidVimeo(url, errorKey, $errorTag, labels) { + let parsed; + try { + parsed = new URL(url); + } catch { + return false; + } + + const host = parsed.hostname.replace(/^www\./, ''); + const path = parsed.pathname; + + if (!host.endsWith('vimeo.com')) { + return false; + } + + if (!/\d+/.test(path)) { + return false; + } + + return true; + } + + return { + showError, + requireField, + requireHttps, + isValidUrl, + isValidYouTube, + isValidVimeo + }; + +})(); From 492512cceb68b761daf04323ab1bfbc07bf75ff6 Mon Sep 17 00:00:00 2001 From: Gabriel Moreira Date: Thu, 11 Dec 2025 16:40:42 -0300 Subject: [PATCH 02/16] =?UTF-8?q?adicionando=20valida=C3=A7=C3=A3o=20nos?= =?UTF-8?q?=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/themes/BaseV1/Theme.php | 2 +- .../themes/BaseV1/assets/js/editable.js | 20 ++++++------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/protected/application/themes/BaseV1/Theme.php b/src/protected/application/themes/BaseV1/Theme.php index 8907b6031..992e50ae9 100644 --- a/src/protected/application/themes/BaseV1/Theme.php +++ b/src/protected/application/themes/BaseV1/Theme.php @@ -1858,7 +1858,7 @@ function includeEditableEntityAssets() { 'insertVideoTitle' => i::__('Insira um título para seu vídeo.'), 'insertVideoUrl' => i::__('Insira uma url válida de um vídeo do YouTube ou do Vimeo.'), 'insertLinkTitle' => i::__('Insira um título para seu link.'), - 'insertLinkUrl' => i::__('A url do link é inválida, insira uma url completa como http://www.google.com/.'), + 'insertLinkUrl' => i::__('A url do link é inválida, insira uma url completa como https://www.google.com/.'), 'Limpar' => i::__('Limpar'), 'Crop' => i::__('Recortar'), 'CropHelp' => i::__('Arraste para recortar'), diff --git a/src/protected/application/themes/BaseV1/assets/js/editable.js b/src/protected/application/themes/BaseV1/assets/js/editable.js index b9832ff9d..47830c71c 100644 --- a/src/protected/application/themes/BaseV1/assets/js/editable.js +++ b/src/protected/application/themes/BaseV1/assets/js/editable.js @@ -894,11 +894,11 @@ MapasCulturais.MetalistManager = { var $linkField = $form.find('input.js-metalist-value'); var $errorTag = $form.find('.alert.danger'); $errorTag.html(''); + + const title = $.trim($form.find('input.js-metalist-title').val()); + const url = $.trim($linkField.val()); if (group === 'videos') { - const title = $.trim($form.find('input.js-metalist-title').val()); - const url = $.trim($linkField.val()); - if (!McValidations.requireHttps(url, 'insertVideoUrl', $errorTag, labels)) return false; if (!McValidations.requireField(url, 'insertVideoUrl', $errorTag, labels)) return false; if (!McValidations.requireField(title, 'insertVideoTitle', $errorTag, labels)) return false; @@ -912,17 +912,9 @@ MapasCulturais.MetalistManager = { return false; } }else if (group === 'links'){ - - if($.trim($form.find('input.js-metalist-title').val()) === ''){ - $errorTag.html(labels['insertLinkTitle']).show(); - return false; - } - - var pattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; - if (!pattern.test($linkField.val())){ - $errorTag.html(labels['insertLinkUrl']).show(); - return false; - } + if (!McValidations.requireHttps(url, 'insertLinkUrl', $errorTag, labels)) return false; + if (!McValidations.requireField(url, 'insertLinkUrl', $errorTag, labels)) return false; + if (!McValidations.requireField(title, 'insertLinkTitle', $errorTag, labels)) return false; } }, success: function (response, statusText, xhr, $form) { From 5aa50aa84ba64ac7d4d3f411b952586c8b9ebd6b Mon Sep 17 00:00:00 2001 From: Gabriel Moreira Date: Fri, 12 Dec 2025 10:10:49 -0300 Subject: [PATCH 03/16] =?UTF-8?q?valida=C3=A7=C3=A3o=20dos=20campos=20de?= =?UTF-8?q?=20rede=20social?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/protected/application/lib/MapasCulturais/Validator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protected/application/lib/MapasCulturais/Validator.php b/src/protected/application/lib/MapasCulturais/Validator.php index 42ca6494a..e0f3eec03 100644 --- a/src/protected/application/lib/MapasCulturais/Validator.php +++ b/src/protected/application/lib/MapasCulturais/Validator.php @@ -25,7 +25,7 @@ static function url($domain = null){ return self::call( 'parse_url', self::arrayType() - ->key('scheme', self::startsWith('http')) + ->key('scheme', self::startsWith('https')) ->key('host', $domain ? self::domain()->endsWith($domain) : self::domain()) ); From 9706c1635cda881830e7280fd9a82d54620ef813 Mon Sep 17 00:00:00 2001 From: Gabriel Moreira Date: Fri, 12 Dec 2025 16:32:00 -0300 Subject: [PATCH 04/16] Permitindo apenas superadmin e saasadmin ver o historico --- .../application/themes/BaseV1/layouts/parts/history.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protected/application/themes/BaseV1/layouts/parts/history.php b/src/protected/application/themes/BaseV1/layouts/parts/history.php index 8705ee7dd..cb2d2459c 100644 --- a/src/protected/application/themes/BaseV1/layouts/parts/history.php +++ b/src/protected/application/themes/BaseV1/layouts/parts/history.php @@ -7,7 +7,7 @@ $entityRevisions = $app->repo("EntityRevision")->findEntityRevisions($entity); $currentDate = null; ?> - 0): ?> +user->is('superAdmin') || $app->user->is('saasAdmin')) && is_array($entityRevisions) && count($entityRevisions) > 0): ?>

    From 4ebbb8ade698b6464ca1cb12746464b4c64b8cb1 Mon Sep 17 00:00:00 2001 From: Jefferson Oliveira Date: Mon, 15 Dec 2025 13:46:57 -0300 Subject: [PATCH 05/16] =?UTF-8?q?feat:=20visualizar=20contrarraz=C3=A3o=20?= =?UTF-8?q?(proponente)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/conf/conf-base.d/routes.php | 5 +- .../lib/MapasCulturais/Controllers/Panel.php | 10 +++ .../Entities/CounterArgument.php | 27 +++++--- .../Repositories/CounterArgument.php | 21 ++++++ .../Services/CounterArgumentService.php | 5 +- .../lib/modules/CounterArgument/Module.php | 6 +- .../assets/counter-argument/js/proponent.js | 12 ++++ .../layouts/parts/counter-argument/view.php | 67 +++++++++++++++++++ .../css/sass/components/_all-components.scss | 1 + .../assets/css/sass/components/_tables.scss | 17 +++++ .../themes/BaseV1/layouts/parts/panel-nav.php | 8 +++ .../BaseV1/views/panel/counter-arguments.php | 7 ++ 12 files changed, 172 insertions(+), 14 deletions(-) create mode 100644 src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php create mode 100644 src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php create mode 100644 src/protected/application/themes/BaseV1/assets/css/sass/components/_tables.scss create mode 100644 src/protected/application/themes/BaseV1/views/panel/counter-arguments.php diff --git a/src/protected/application/conf/conf-base.d/routes.php b/src/protected/application/conf/conf-base.d/routes.php index f5c69cb9e..842414f5e 100644 --- a/src/protected/application/conf/conf-base.d/routes.php +++ b/src/protected/application/conf/conf-base.d/routes.php @@ -69,7 +69,8 @@ 'agente' => 'agent', 'evento' => 'event', 'inscricao' => 'registration', - 'prestacoes-de-contas' => 'accountability' + 'prestacoes-de-contas' => 'accountability', + 'contrarrazoes' => 'counterArguments', ], 'readableNames' => [ @@ -98,4 +99,4 @@ 'search' => i::__('Busca') ] ] -]; \ No newline at end of file +]; diff --git a/src/protected/application/lib/MapasCulturais/Controllers/Panel.php b/src/protected/application/lib/MapasCulturais/Controllers/Panel.php index d2c323e91..998e5b91d 100644 --- a/src/protected/application/lib/MapasCulturais/Controllers/Panel.php +++ b/src/protected/application/lib/MapasCulturais/Controllers/Panel.php @@ -429,4 +429,14 @@ function GET_accountability() 'isFiscal' => $oppAsFiscal ? true : false, ]); } + + public function GET_counterArguments() + { + $this->requireAuthentication(); + + $agentId = App::i()->getUser()->profile->id; + $counterArguments = App::i()->repo('CounterArgument')->getAllByAgentId($agentId); + + $this->render('counter-arguments', ['counterArguments' => $counterArguments]); + } } diff --git a/src/protected/application/lib/MapasCulturais/Entities/CounterArgument.php b/src/protected/application/lib/MapasCulturais/Entities/CounterArgument.php index 8247f9231..f7c3e7c2c 100644 --- a/src/protected/application/lib/MapasCulturais/Entities/CounterArgument.php +++ b/src/protected/application/lib/MapasCulturais/Entities/CounterArgument.php @@ -3,19 +3,25 @@ namespace MapasCulturais\Entities; use Doctrine\ORM\Mapping as ORM; -use MapasCulturais\App; +use MapasCulturais\Traits; /** * CounterArgument * * @ORM\Table(name="counter_argument") * @ORM\Entity - * @ORM\entity(repositoryClass="MapasCulturais\Repository") + * @ORM\entity(repositoryClass="MapasCulturais\Repositories\CounterArgument") */ class CounterArgument extends \MapasCulturais\Entity { + use Traits\EntityFiles; + const STATUS_SEND = self::STATUS_ENABLED; + const STATUSES = [ + self::STATUS_SEND => 'Enviado', + ]; + /** * @var integer * @@ -43,13 +49,21 @@ class CounterArgument extends \MapasCulturais\Entity /** * @var \MapasCulturais\Entities\Registration * - * @ORM\OneToOne(targetEntity="MapasCulturais\Entities\Registration", inversedBy="CounterArgument\Entities\CounterArgument", cascade={"persist"}) + * @ORM\OneToOne(targetEntity="MapasCulturais\Entities\Registration", cascade={"persist"}) * @ORM\JoinColumns({ * @ORM\JoinColumn(name="registration_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) */ protected $registration; + /** + * @var \MapasCulturais\Entities\CounterArgumentFile[] Files + * + * @ORM\OneToMany(targetEntity="MapasCulturais\Entities\CounterArgumentFile", fetch="EXTRA_LAZY", mappedBy="owner", cascade="remove", orphanRemoval=true) + * @ORM\JoinColumn(name="id", referencedColumnName="object_id", onDelete="CASCADE") + */ + protected $__files; + /** * @var \DateTime * @@ -63,11 +77,4 @@ class CounterArgument extends \MapasCulturais\Entity * @ORM\Column(name="update_timestamp", type="datetime", nullable=true) */ protected $updateTimestamp; - - public function send(array $data) - { - $this->text = $data['text']; - $this->registration = App::i()->repo('Registration')->find($data['registration']); - $this->save(); - } } diff --git a/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php b/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php new file mode 100644 index 000000000..aa563d850 --- /dev/null +++ b/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php @@ -0,0 +1,21 @@ +em->createQueryBuilder(); + $qb->select('ca') + ->from(CounterArgumentEntity::class, 'ca') + ->innerJoin('ca.registration', 'r') + ->where('r.owner = :agentId') + ->setParameter('agentId', $agentId); + + return $qb->getQuery()->getResult(); + } +} diff --git a/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php b/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php index 8cd492df5..a2e9c76c0 100644 --- a/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php +++ b/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php @@ -33,7 +33,10 @@ public function isCounterArgumentPeriod($opportunity) public function send(array $data) { - $this->counterArgumentEntity->send($data); + $registration = App::i()->repo('Registration')->find($data['registration']); + $this->counterArgumentEntity->text = $data['text']; + $this->counterArgumentEntity->registration = $registration; + $this->counterArgumentEntity->save(); foreach ($_FILES as $file) { App::i()->disableAccessControl(); diff --git a/src/protected/application/lib/modules/CounterArgument/Module.php b/src/protected/application/lib/modules/CounterArgument/Module.php index 594d0ab43..5ae113272 100644 --- a/src/protected/application/lib/modules/CounterArgument/Module.php +++ b/src/protected/application/lib/modules/CounterArgument/Module.php @@ -27,6 +27,10 @@ public function _init() 'registration' => $registration, ]); }); + + App::i()->hook('template(panel.counterArguments.view):before', function () { + App::i()->view->enqueueScript('app', 'counter-argument', 'counter-argument/js/proponent.js'); + }); } public function register() @@ -51,7 +55,7 @@ public function register() ]); App::i()->registerFileGroup( - 'counter-argument', + 'contrarrazao', new \MapasCulturais\Definitions\FileGroup( 'counter-argument-attachment', [ diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js index b1230c106..3068a53c1 100644 --- a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js @@ -44,6 +44,13 @@ const counterArgument = { }) } }) + }, + view(text) { + Swal.fire({ + title: 'Contrarrazão', + html: text, + width: 700, + }) } } @@ -89,4 +96,9 @@ $(() => { } }) }) + + $('[btn-view-counter-argument]').on('click', function (event) { + const text = event.currentTarget.dataset.text + counterArgument.view(text) + }) }) diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php new file mode 100644 index 000000000..ad6dd975a --- /dev/null +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php @@ -0,0 +1,67 @@ + + +
    +

    Minhas Contrarrazões

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OportunidadeInscrição/AgenteContrarrazãoSituaçãoData do envioRespostaAções
    + + registration->opportunity->name ?> + + + + registration->number ?> + +
    + + registration->owner->name ?> + +
    + + getFiles('counter-argument-attachment')) : ?> +
    + getFiles('counter-argument-attachment') as $file) : ?> +
    + name ?> +
    + +
    + +
    + status] ?> + + createTimestamp->format('d/m/Y H:i') ?> +
    + +
    Você ainda não enviou nenhuma contrarrazão.
    + +
    diff --git a/src/protected/application/themes/BaseV1/assets/css/sass/components/_all-components.scss b/src/protected/application/themes/BaseV1/assets/css/sass/components/_all-components.scss index 8394b535b..4f8eb286c 100644 --- a/src/protected/application/themes/BaseV1/assets/css/sass/components/_all-components.scss +++ b/src/protected/application/themes/BaseV1/assets/css/sass/components/_all-components.scss @@ -40,3 +40,4 @@ @import "opportunities-projets"; @import "chats"; @import "opportunities-accountability"; +@import "tables"; diff --git a/src/protected/application/themes/BaseV1/assets/css/sass/components/_tables.scss b/src/protected/application/themes/BaseV1/assets/css/sass/components/_tables.scss new file mode 100644 index 000000000..9229a9a2f --- /dev/null +++ b/src/protected/application/themes/BaseV1/assets/css/sass/components/_tables.scss @@ -0,0 +1,17 @@ +.table { + width: 100%; + margin-bottom: 1rem; + color: #212529; +} + +.table-bordered { + + thead th { + border-bottom-width: 2px; + } + + th, + td { + border: 1px solid #dee2e6; + } +} diff --git a/src/protected/application/themes/BaseV1/layouts/parts/panel-nav.php b/src/protected/application/themes/BaseV1/layouts/parts/panel-nav.php index 8b936bf4c..4761a9e59 100644 --- a/src/protected/application/themes/BaseV1/layouts/parts/panel-nav.php +++ b/src/protected/application/themes/BaseV1/layouts/parts/panel-nav.php @@ -48,6 +48,14 @@
  • template == 'panel/registrations') echo 'class="active"'; ?> href="createUrl('panel', 'registrations') ?>">
  • applyTemplateHook('nav.panel.registrations','after'); ?> + applyTemplateHook('nav.panel.counterArguments','before'); ?> +
  • + template == 'panel/counter-arguments') echo 'class="active"'; ?> href="createUrl('panel', 'counterArguments') ?>"> + Minhas Contrarrazões + +
  • + applyTemplateHook('nav.panel.counterArguments','after'); ?> + applyTemplateHook('nav.panel.accountability', 'before'); ?>
  • template == 'panel/accountability') echo 'class="active"'; ?> href="createUrl('panel', 'accountability') ?>"> diff --git a/src/protected/application/themes/BaseV1/views/panel/counter-arguments.php b/src/protected/application/themes/BaseV1/views/panel/counter-arguments.php new file mode 100644 index 000000000..c128b761c --- /dev/null +++ b/src/protected/application/themes/BaseV1/views/panel/counter-arguments.php @@ -0,0 +1,7 @@ +layout = 'panel'; + +$this->applyTemplateHook('view', 'before'); +$this->part('counter-argument/view', ['counterArguments' => $counterArguments]); +$this->applyTemplateHook('view', 'after'); From f41629f8f6dd2da0a10d8fab9238f64248d4518c Mon Sep 17 00:00:00 2001 From: Gabriel Moreira Date: Wed, 17 Dec 2025 14:32:07 -0300 Subject: [PATCH 06/16] removendo logica desnecessaria --- .../application/themes/BaseV1/layouts/parts/history.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protected/application/themes/BaseV1/layouts/parts/history.php b/src/protected/application/themes/BaseV1/layouts/parts/history.php index cb2d2459c..9b014e50e 100644 --- a/src/protected/application/themes/BaseV1/layouts/parts/history.php +++ b/src/protected/application/themes/BaseV1/layouts/parts/history.php @@ -7,7 +7,7 @@ $entityRevisions = $app->repo("EntityRevision")->findEntityRevisions($entity); $currentDate = null; ?> -user->is('superAdmin') || $app->user->is('saasAdmin')) && is_array($entityRevisions) && count($entityRevisions) > 0): ?> +user->is('superAdmin') && is_array($entityRevisions) && count($entityRevisions) > 0): ?>

      From 505df08ccfffd7d3a28faba76c53e8b8f9836795 Mon Sep 17 00:00:00 2001 From: Jefferson Oliveira Date: Tue, 30 Dec 2025 10:35:51 -0300 Subject: [PATCH 07/16] =?UTF-8?q?feat:=20editar=20contrarraz=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/CounterArgumentService.php | 35 ++++- .../Controllers/Controller.php | 28 +++- .../lib/modules/CounterArgument/Module.php | 3 + .../assets/counter-argument/css/panel.css | 4 + .../assets/counter-argument/js/proponent.js | 132 ++++++++++++++++++ .../parts/counter-argument/send-btn.php | 4 +- .../layouts/parts/counter-argument/view.php | 13 +- 7 files changed, 209 insertions(+), 10 deletions(-) create mode 100644 src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css diff --git a/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php b/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php index a2e9c76c0..053af46fb 100644 --- a/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php +++ b/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php @@ -6,6 +6,7 @@ use MapasCulturais\App; use MapasCulturais\Entities\CounterArgument; use MapasCulturais\Entities\CounterArgumentFile; +use MapasCulturais\Entities\Registration; class CounterArgumentService { @@ -31,25 +32,47 @@ public function isCounterArgumentPeriod($opportunity) return false; } - public function send(array $data) + public function send(string $text, Registration $registration) { - $registration = App::i()->repo('Registration')->find($data['registration']); - $this->counterArgumentEntity->text = $data['text']; + $this->counterArgumentEntity->text = $text; $this->counterArgumentEntity->registration = $registration; $this->counterArgumentEntity->save(); - foreach ($_FILES as $file) { + $this->saveFiles($_FILES, $this->counterArgumentEntity); + + App::i()->em->flush(); + } + + public function update(array $data) + { + $counterArgument = App::i()->repo('CounterArgument')->find($data['id']); + $counterArgument->text = $data['text']; + $counterArgument->updateTimestamp = new DateTime(); + + $this->saveFiles($_FILES, $counterArgument); + + $counterArgument->save(true); + App::i()->em->flush(); + } + + private function saveFiles($files, $counterArgument) + { + foreach ($files as $file) { App::i()->disableAccessControl(); $counterArgumentFile = new CounterArgumentFile($file); $counterArgumentFile->setGroup('counter-argument-attachment'); - $counterArgumentFile->owner = $this->counterArgumentEntity; + $counterArgumentFile->owner = $counterArgument; $counterArgumentFile->private = true; $counterArgumentFile->save(); App::i()->enableAccessControl(); } + } - App::i()->em->flush(); + public function removeFile(int $fileId) + { + $counterArgumentFile = App::i()->repo('CounterArgumentFile')->find($fileId); + $counterArgumentFile->delete(true); } } diff --git a/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php b/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php index 2bf3083c2..5aa7485b4 100644 --- a/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php +++ b/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php @@ -2,6 +2,7 @@ namespace CounterArgument\Controllers; +use MapasCulturais\App; use MapasCulturais\Services\CounterArgumentService; use MapasCulturais\Services\SentryService; @@ -17,12 +18,37 @@ public function __construct() public function POST_send() { $data = $this->getPostData(); + $registration = App::i()->repo('Registration')->find($data['registration']); try { - $this->counterArgumentService->send($data); + $this->counterArgumentService->send($data['text'], $registration); $this->json(['message' => 'Contrarrazão enviada com sucesso. Aguarde a resposta.'], 201); } catch (\Throwable $th) { SentryService::captureExceptions($th); } } + + public function POST_update() + { + $data = $this->getPostData(); + + try { + $this->counterArgumentService->update($data); + $this->json(['message' => 'Contrarrazão atualizada com sucesso. Aguarde a resposta.']); + } catch (\Throwable $th) { + SentryService::captureExceptions($th); + } + } + + public function POST_removeFile() + { + $data = $this->getPostData(); + + try { + $this->counterArgumentService->removeFile((int)$data['fileId']); + $this->json(['message' => 'O arquivo foi removido da contrarrazão']); + } catch (\Throwable $th) { + SentryService::captureExceptions($th); + } + } } diff --git a/src/protected/application/lib/modules/CounterArgument/Module.php b/src/protected/application/lib/modules/CounterArgument/Module.php index 5ae113272..5288764dd 100644 --- a/src/protected/application/lib/modules/CounterArgument/Module.php +++ b/src/protected/application/lib/modules/CounterArgument/Module.php @@ -21,15 +21,18 @@ public function _init() $counterArgumentService = new CounterArgumentService(); $isCounterArgumentPeriod = $counterArgumentService->isCounterArgumentPeriod($registration->opportunity); + $hasCounterArgument = App::i()->repo('CounterArgument')->findOneBy(['registration' => $registration]); $this->part('counter-argument/send-btn', [ 'isCounterArgumentPeriod' => $isCounterArgumentPeriod, 'registration' => $registration, + 'hasCounterArgument' => $hasCounterArgument ]); }); App::i()->hook('template(panel.counterArguments.view):before', function () { App::i()->view->enqueueScript('app', 'counter-argument', 'counter-argument/js/proponent.js'); + App::i()->view->enqueueStyle('app', 'counter-argument', 'counter-argument/css/panel.css'); }); } diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css new file mode 100644 index 000000000..8f6673db1 --- /dev/null +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css @@ -0,0 +1,4 @@ +.icon-remove-counter-argument-file { + margin-left: 5px; + cursor: pointer; +} diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js index 3068a53c1..368bcb6bc 100644 --- a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js @@ -34,6 +34,12 @@ const counterArgument = { title: 'Contrarrazão enviada', text: res.message, icon: 'success', + confirmButtonText: 'Ir para o painel', + allowOutsideClick: false, + }).then(res => { + if (res.isConfirmed) { + window.location.href = MapasCulturais.createUrl('panel', 'counterArguments') + } }) }, error(err) { @@ -51,6 +57,70 @@ const counterArgument = { html: text, width: 700, }) + }, + update(id) { + const formData = new FormData() + formData.append('id', id) + formData.append('text', this.getText()) + + Array.from(this.getFiles()).forEach((file, index) => { + formData.append(index, file) + }) + + $.ajax({ + type: "POST", + url: MapasCulturais.createUrl('contrarrazao', 'update'), + data: formData, + contentType: false, + processData: false, + dataType: "json", + success(res) { + Swal.fire({ + title: 'Contrarrazão atualizada', + text: res.message, + icon: 'success', + allowOutsideClick: false, + }).then(res => { + if (res.isConfirmed) { + window.location.reload() + } + }) + }, + error(err) { + Swal.fire({ + title: 'Contrarrazão não atualizada', + text: 'Erro ao atualizar contrarrazão. Tente novamente.', + icon: 'error', + }) + } + }) + }, + removeFile(fileId) { + $.ajax({ + type: "POST", + url: MapasCulturais.createUrl('contrarrazao', 'removeFile'), + data: { fileId }, + dataType: "json", + success(res) { + Swal.fire({ + title: 'Arquivo removido', + text: res.message, + icon: 'success', + allowOutsideClick: false, + }).then(res => { + if (res.isConfirmed) { + window.location.reload() + } + }) + }, + error(err) { + Swal.fire({ + title: 'Arquivo não removido', + text: 'Erro ao remover arquivo da contrarrazão. Tente novamente.', + icon: 'error', + }) + } + }) } } @@ -101,4 +171,66 @@ $(() => { const text = event.currentTarget.dataset.text counterArgument.view(text) }) + + $('[edit-counter-argument-btn]').on('click', function (event) { + const id = event.currentTarget.dataset.id + const text = event.currentTarget.dataset.text + + let quillEditor + + Swal.fire({ + title: 'Editar Contrarrazão', + html: ` +

      Você pode editar o texto da sua contrarrazão e anexar mais arquivos

      +
      +
      ${text}
      + +
      `, + width: 700, + confirmButtonText: 'Atualizar', + cancelButtonText: 'Cancelar', + showCancelButton: true, + allowOutsideClick: false, + didOpen() { + quillEditor = new Quill('[counter-argument-text]', { + theme: 'snow' + }) + }, + willClose() { + counterArgument.setText(quillEditor.getSemanticHTML()) + counterArgument.setFiles($('[counter-argument-attachments]')[0].files) + }, + }).then(res => { + if (res.isConfirmed) { + if (!quillEditor.getText().trim()) { + Swal.fire({ + title: 'Sua contrarrazão não foi atualizada', + text: 'O texto não pode estar vazio', + icon: 'warning', + }) + return + } + + counterArgument.update(id) + } + }) + }) + + $('[remove-counter-argument-file]').on('click', function (event) { + const fileId = event.currentTarget.dataset.fileId + + Swal.fire({ + title: 'Remover arquivo da contrarrazão', + text: 'Deseja realmente remover este arquivo da contrarrazão?', + icon: 'warning', + confirmButtonText: 'Remover', + cancelButtonText: 'Cancelar', + showCancelButton: true, + allowOutsideClick: false, + }).then(res => { + if (res.isConfirmed) { + counterArgument.removeFile(fileId) + } + }) + }) }) diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/send-btn.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/send-btn.php index bc956efa6..374600bdb 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/send-btn.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/send-btn.php @@ -1,5 +1,7 @@ - +
      Abrir Contrarrazão + + Contrarrazão enviada diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php index ad6dd975a..708f26d7f 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php @@ -38,12 +38,17 @@ - + getFiles('counter-argument-attachment')) : ?>
      getFiles('counter-argument-attachment') as $file) : ?>
      name ?> + + +
      @@ -56,7 +61,11 @@ createTimestamp->format('d/m/Y H:i') ?> - + + + From 794347010a51fa7951dc00b4350a96aee2dcdf0c Mon Sep 17 00:00:00 2001 From: Jefferson Oliveira Date: Tue, 6 Jan 2026 12:35:47 -0300 Subject: [PATCH 08/16] =?UTF-8?q?feat:=20visualizar=20contrarraz=C3=A3o=20?= =?UTF-8?q?(admin)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/CounterArgument.php | 12 ++++ .../lib/modules/CounterArgument/Module.php | 14 +++++ .../assets/counter-argument/js/common.js | 16 +++++ .../assets/counter-argument/js/proponent.js | 12 ---- .../counter-argument/opportunity--tab.php | 5 ++ .../parts/counter-argument/opportunity.php | 61 +++++++++++++++++++ 6 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/common.js create mode 100644 src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity--tab.php create mode 100644 src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php diff --git a/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php b/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php index aa563d850..a8cedb2a4 100644 --- a/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php +++ b/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php @@ -18,4 +18,16 @@ public function getAllByAgentId($agentId): array return $qb->getQuery()->getResult(); } + + public function getAllByOpportunityId($opportunityId): array + { + $qb = App::i()->em->createQueryBuilder(); + $qb->select('ca') + ->from(CounterArgumentEntity::class, 'ca') + ->innerJoin('ca.registration', 'r') + ->where('r.opportunity = :opportunityId') + ->setParameter('opportunityId', $opportunityId); + + return $qb->getQuery()->getResult(); + } } diff --git a/src/protected/application/lib/modules/CounterArgument/Module.php b/src/protected/application/lib/modules/CounterArgument/Module.php index 5288764dd..1946dabfe 100644 --- a/src/protected/application/lib/modules/CounterArgument/Module.php +++ b/src/protected/application/lib/modules/CounterArgument/Module.php @@ -31,9 +31,23 @@ public function _init() }); App::i()->hook('template(panel.counterArguments.view):before', function () { + App::i()->view->enqueueScript('app', 'counter-argument-common', 'counter-argument/js/common.js'); App::i()->view->enqueueScript('app', 'counter-argument', 'counter-argument/js/proponent.js'); App::i()->view->enqueueStyle('app', 'counter-argument', 'counter-argument/css/panel.css'); }); + + App::i()->hook('template(opportunity.single.opportunity-recourse--tab):after', function () { + $this->part('counter-argument/opportunity--tab'); + }); + + App::i()->hook('template(opportunity.single.tabs-content):end', function () { + App::i()->view->enqueueScript('app', 'counter-argument', 'counter-argument/js/common.js'); + + $opportunity = $this->controller->requestedEntity; + $counterArguments = App::i()->repo('CounterArgument')->getAllByOpportunityId($opportunity->id); + + $this->part('counter-argument/opportunity', ['counterArguments' => $counterArguments]); + }); } public function register() diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/common.js b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/common.js new file mode 100644 index 000000000..6c52185b8 --- /dev/null +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/common.js @@ -0,0 +1,16 @@ +const counterArgumentCommon = { + view(text) { + Swal.fire({ + title: 'Contrarrazão', + html: text, + width: 700, + }) + }, +} + +$(() => { + $('[btn-view-counter-argument]').on('click', function (event) { + const text = event.currentTarget.dataset.text + counterArgumentCommon.view(text) + }) +}) diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js index 368bcb6bc..cb92cb120 100644 --- a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js @@ -51,13 +51,6 @@ const counterArgument = { } }) }, - view(text) { - Swal.fire({ - title: 'Contrarrazão', - html: text, - width: 700, - }) - }, update(id) { const formData = new FormData() formData.append('id', id) @@ -167,11 +160,6 @@ $(() => { }) }) - $('[btn-view-counter-argument]').on('click', function (event) { - const text = event.currentTarget.dataset.text - counterArgument.view(text) - }) - $('[edit-counter-argument-btn]').on('click', function (event) { const id = event.currentTarget.dataset.id const text = event.currentTarget.dataset.text diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity--tab.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity--tab.php new file mode 100644 index 000000000..85af1598c --- /dev/null +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity--tab.php @@ -0,0 +1,5 @@ +applyTemplateHook('counter-argument--tab', 'before'); ?> +
    • + Contrarrazão +
    • +applyTemplateHook('counter-argument--tab', 'after'); ?> diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php new file mode 100644 index 000000000..a67f2a7c2 --- /dev/null +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php @@ -0,0 +1,61 @@ + + +
      +

      Nesta seção são listadas todas as contrarrazões enviadas pelos agentes para esta oportunidade.

      + + + + + + + + + + + + + + + + + + + + + + + +
      InscriçãoAgenteContrarrazãoSituaçãoData do envio
      + + registration->number ?> + + + + registration->owner->name ?> + + + + getFiles('counter-argument-attachment')) : ?> +
      + getFiles('counter-argument-attachment') as $file) : ?> +
      + name ?> +
      + +
      + +
      + status] ?> + + createTimestamp->format('d/m/Y H:i') ?> +
      + +
      Ainda não foram enviadas contrarrazões nesta oportunidade.
      + +
      From ee5cede7ae26f28a5f570dbf4ace0c6d7793801a Mon Sep 17 00:00:00 2001 From: Gabriel Moreira Date: Tue, 6 Jan 2026 14:26:15 -0300 Subject: [PATCH 09/16] =?UTF-8?q?refatora=C3=A7=C3=A3o=20das=20condi=C3=A7?= =?UTF-8?q?=C3=B5es=20de=20valida=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../themes/BaseV1/assets/js/editable.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/protected/application/themes/BaseV1/assets/js/editable.js b/src/protected/application/themes/BaseV1/assets/js/editable.js index 47830c71c..566070c64 100644 --- a/src/protected/application/themes/BaseV1/assets/js/editable.js +++ b/src/protected/application/themes/BaseV1/assets/js/editable.js @@ -899,11 +899,12 @@ MapasCulturais.MetalistManager = { const url = $.trim($linkField.val()); if (group === 'videos') { - if (!McValidations.requireHttps(url, 'insertVideoUrl', $errorTag, labels)) return false; - if (!McValidations.requireField(url, 'insertVideoUrl', $errorTag, labels)) return false; - if (!McValidations.requireField(title, 'insertVideoTitle', $errorTag, labels)) return false; - if (!McValidations.isValidUrl(url, 'insertVideoUrl', $errorTag, labels)) return false; - + if ( + !McValidations.requireHttps(url, 'insertVideoUrl', $errorTag, labels) || + !McValidations.requireField(url, 'insertVideoUrl', $errorTag, labels) || + !McValidations.requireField(title, 'insertVideoTitle', $errorTag, labels) || + !McValidations.isValidUrl(url, 'insertVideoUrl', $errorTag, labels) + ) return false; const isValidYouTube = McValidations.isValidYouTube(url, 'insertVideoUrl', $errorTag, labels); const isValidVimeo = McValidations.isValidVimeo(url, 'insertVideoUrl', $errorTag, labels); @@ -912,9 +913,11 @@ MapasCulturais.MetalistManager = { return false; } }else if (group === 'links'){ - if (!McValidations.requireHttps(url, 'insertLinkUrl', $errorTag, labels)) return false; - if (!McValidations.requireField(url, 'insertLinkUrl', $errorTag, labels)) return false; - if (!McValidations.requireField(title, 'insertLinkTitle', $errorTag, labels)) return false; + if ( + !McValidations.requireHttps(url, 'insertLinkUrl', $errorTag, labels) || + !McValidations.requireField(url, 'insertLinkUrl', $errorTag, labels) || + !McValidations.requireField(title, 'insertLinkTitle', $errorTag, labels) + ) return false; } }, success: function (response, statusText, xhr, $form) { From 0240db52e27b333d2dea6b7fdc803540d1d791de Mon Sep 17 00:00:00 2001 From: Gabriel Moreira Date: Fri, 9 Jan 2026 14:21:47 -0300 Subject: [PATCH 10/16] =?UTF-8?q?truncando=20arquivos=20longos=20e=20ajust?= =?UTF-8?q?ando=20bot=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/counter-argument/css/panel.css | 30 +++++++++++++++++++ .../layouts/parts/counter-argument/view.php | 14 +++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css index 8f6673db1..3b9df5b8f 100644 --- a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css @@ -2,3 +2,33 @@ margin-left: 5px; cursor: pointer; } + +.btn-counter-arguments { + border: 1px solid #c3c3c3; + border-radius: 5px; + margin: 2px; + background-color: transparent; + color:black; + cursor: pointer; +} + +.truncate-file { + display: inline-block; + max-width: 10em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + vertical-align: middle; +} + +.file-row { + display: flex; + align-items: center; + gap: 8px; + margin: 0; +} + +.icon-remove-counter-argument-file { + flex-shrink: 0; + cursor: pointer; +} \ No newline at end of file diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php index 708f26d7f..0821dfd7d 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php @@ -38,17 +38,19 @@ - getFiles('counter-argument-attachment')) : ?>
      getFiles('counter-argument-attachment') as $file) : ?>
      - name ?> - - - +

      + name ?> + + + +

      @@ -62,7 +64,7 @@ - From bf794eb85ffd59acfe7379d988ec306d82a2bf80 Mon Sep 17 00:00:00 2001 From: Jefferson Oliveira Date: Mon, 12 Jan 2026 14:17:38 -0300 Subject: [PATCH 11/16] =?UTF-8?q?feat:=20responder=20contrarraz=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entities/CounterArgument.php | 17 ++- .../Entities/CounterArgumentResponse.php | 73 +++++++++++++ .../Services/CounterArgumentService.php | 23 ++++ .../Controllers/Controller.php | 12 +++ .../lib/modules/CounterArgument/Module.php | 3 +- .../assets/counter-argument/js/admin.js | 101 ++++++++++++++++++ .../parts/counter-argument/opportunity.php | 11 ++ .../layouts/parts/counter-argument/view.php | 6 +- src/protected/db-updates.php | 18 ++++ 9 files changed, 259 insertions(+), 5 deletions(-) create mode 100644 src/protected/application/lib/MapasCulturais/Entities/CounterArgumentResponse.php create mode 100644 src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/admin.js diff --git a/src/protected/application/lib/MapasCulturais/Entities/CounterArgument.php b/src/protected/application/lib/MapasCulturais/Entities/CounterArgument.php index f7c3e7c2c..1f2fb079a 100644 --- a/src/protected/application/lib/MapasCulturais/Entities/CounterArgument.php +++ b/src/protected/application/lib/MapasCulturais/Entities/CounterArgument.php @@ -16,10 +16,14 @@ class CounterArgument extends \MapasCulturais\Entity { use Traits\EntityFiles; - const STATUS_SEND = self::STATUS_ENABLED; + const STATUS_WAITING = self::STATUS_ENABLED; + const STATUS_DEFERRED = 10; + const STATUS_REJECTED = 3; const STATUSES = [ - self::STATUS_SEND => 'Enviado', + self::STATUS_WAITING => 'Aguardando resposta', + self::STATUS_DEFERRED => 'Deferida', + self::STATUS_REJECTED => 'Indeferida', ]; /** @@ -44,7 +48,7 @@ class CounterArgument extends \MapasCulturais\Entity * * @ORM\Column(name="status", type="smallint", nullable=false) */ - protected $status = self::STATUS_SEND; + protected $status = self::STATUS_WAITING; /** * @var \MapasCulturais\Entities\Registration @@ -64,6 +68,13 @@ class CounterArgument extends \MapasCulturais\Entity */ protected $__files; + /** + * @var \MapasCulturais\Entities\CounterArgumentResponse|null + * + * @ORM\OneToOne(targetEntity="MapasCulturais\Entities\CounterArgumentResponse", mappedBy="counterArgument", fetch="LAZY") + */ + protected $response; + /** * @var \DateTime * diff --git a/src/protected/application/lib/MapasCulturais/Entities/CounterArgumentResponse.php b/src/protected/application/lib/MapasCulturais/Entities/CounterArgumentResponse.php new file mode 100644 index 000000000..568ec7f1b --- /dev/null +++ b/src/protected/application/lib/MapasCulturais/Entities/CounterArgumentResponse.php @@ -0,0 +1,73 @@ +counterArgumentEntity = new CounterArgument(); + $this->counterArgumentResponseEntity = new CounterArgumentResponse(); } public function isCounterArgumentPeriod($opportunity) @@ -75,4 +78,24 @@ public function removeFile(int $fileId) $counterArgumentFile = App::i()->repo('CounterArgumentFile')->find($fileId); $counterArgumentFile->delete(true); } + + public function saveResponse(array $data) + { + $counterArgument = App::i()->repo('CounterArgument')->find($data['counterArgumentId']); + $counterArgumentResponse = App::i()->repo('CounterArgumentResponse')->findOneBy(['counterArgument' => $counterArgument->id]); + + if ($counterArgumentResponse) { + $counterArgumentResponse->text = $data['text']; + $counterArgumentResponse->updateTimestamp = new DateTime(); + $counterArgumentResponse->save(true); + } else { + $this->counterArgumentResponseEntity->text = $data['text']; + $this->counterArgumentResponseEntity->owner = App::i()->getUser()->profile; + $this->counterArgumentResponseEntity->counterArgument = $counterArgument; + $this->counterArgumentResponseEntity->save(true); + } + + $counterArgument->status = (int)$data['status']; + $counterArgument->save(true); + } } diff --git a/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php b/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php index 5aa7485b4..60a5cea1a 100644 --- a/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php +++ b/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php @@ -51,4 +51,16 @@ public function POST_removeFile() SentryService::captureExceptions($th); } } + + public function POST_respond() + { + $data = $this->getPostData(); + + try { + $this->counterArgumentService->saveResponse($data); + $this->json(['message' => 'Sua resposta para a contrarrazão foi salva com sucesso.']); + } catch (\Throwable $th) { + SentryService::captureExceptions($th); + } + } } diff --git a/src/protected/application/lib/modules/CounterArgument/Module.php b/src/protected/application/lib/modules/CounterArgument/Module.php index 1946dabfe..d2ebe6515 100644 --- a/src/protected/application/lib/modules/CounterArgument/Module.php +++ b/src/protected/application/lib/modules/CounterArgument/Module.php @@ -41,7 +41,8 @@ public function _init() }); App::i()->hook('template(opportunity.single.tabs-content):end', function () { - App::i()->view->enqueueScript('app', 'counter-argument', 'counter-argument/js/common.js'); + App::i()->view->enqueueScript('app', 'counter-argument-common', 'counter-argument/js/common.js'); + App::i()->view->enqueueScript('app', 'counter-argument-admin', 'counter-argument/js/admin.js'); $opportunity = $this->controller->requestedEntity; $counterArguments = App::i()->repo('CounterArgument')->getAllByOpportunityId($opportunity->id); diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/admin.js b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/admin.js new file mode 100644 index 000000000..c9d2653c7 --- /dev/null +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/admin.js @@ -0,0 +1,101 @@ +const counterArgumentAdmin = { + text: '', + status: null, + getText() { + return this.text + }, + setText(text) { + this.text = text + }, + getStatus() { + return this.status + }, + setStatus(status) { + this.status = status + }, + respond(counterArgumentId) { + $.ajax({ + type: "POST", + url: MapasCulturais.createUrl('contrarrazao', 'respond'), + data: { + counterArgumentId, + text: this.getText(), + status: this.getStatus(), + }, + dataType: "json", + success(res) { + Swal.fire({ + title: 'Resposta salva', + text: res.message, + icon: 'success', + allowOutsideClick: false, + }).then(res => { + if (res.isConfirmed) { + window.location.reload() + } + }) + }, + error(err) { + Swal.fire({ + title: 'Sua resposta não foi salva', + text: 'Erro ao salvar resposta da contrarrazão. Tente novamente.', + icon: 'error', + }) + } + }) + }, +} + +$(() => { + $('[btn-view-counter-argument-response]').on('click', function (event) { + const counterArgumentId = event.currentTarget.dataset.id + const text = event.currentTarget.dataset.text + const status = event.currentTarget.dataset.status + + let quillEditor + + Swal.fire({ + title: 'Responder Contrarrazão', + html: ` +

      Digite sua resposta para esta contrarrazão

      +
      +
      ${text}
      +
      + + +
      +
      `, + width: 700, + confirmButtonText: 'Salvar', + cancelButtonText: 'Cancelar', + showCancelButton: true, + allowOutsideClick: false, + didOpen() { + quillEditor = new Quill('[counter-argument-response-text]', { + theme: 'snow' + }) + }, + willClose() { + counterArgumentAdmin.setText(quillEditor.getSemanticHTML()) + counterArgumentAdmin.setStatus($('#counter-argument-status').val()) + }, + }).then(res => { + if (res.isConfirmed) { + if (!quillEditor.getText().trim() || counterArgumentAdmin.getStatus() === null) { + Swal.fire({ + title: 'Sua resposta não foi salva', + text: 'Digite o texto da resposta e selecione uma situação', + icon: 'warning', + }) + return + } + + counterArgumentAdmin.respond(counterArgumentId) + } + }) + }) +}) diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php index a67f2a7c2..13821e1be 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php @@ -16,6 +16,7 @@ Contrarrazão Situação Data do envio + Resposta @@ -51,6 +52,16 @@ createTimestamp->format('d/m/Y H:i') ?> + + + diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php index 708f26d7f..a22e4ebb0 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php @@ -60,7 +60,11 @@ createTimestamp->format('d/m/Y H:i') ?> - + + + getFiles('counter-argument-attachment')) : ?>
      - getFiles('counter-argument-attachment') as $file) : ?> -
      - name ?> -
      - +

      + getFiles('counter-argument-attachment') as $file) : ?> +

      + name ?> + + + +
      + +

      @@ -56,9 +61,11 @@ diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php index 6085e88bc..f5f67f95e 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php @@ -63,7 +63,7 @@ createTimestamp->format('d/m/Y H:i') ?> - From 3b1a1f9e031733d3acb87ed11c7a45feba19199f Mon Sep 17 00:00:00 2001 From: Gabriel Moreira Date: Wed, 14 Jan 2026 16:53:48 -0300 Subject: [PATCH 13/16] =?UTF-8?q?removendo=20fun=C3=A7=C3=A3o=20de=20exclu?= =?UTF-8?q?ir=20da=20tela=20da=20oportunidade?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layouts/parts/counter-argument/opportunity.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php index 932f69ec9..87aaae623 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php @@ -42,9 +42,6 @@ getFiles('counter-argument-attachment') as $file) : ?>
      name ?> - - -

      From fc55ebe17a727151d9b0367559ce7fe1eacd86e0 Mon Sep 17 00:00:00 2001 From: Jefferson Oliveira Date: Fri, 16 Jan 2026 14:03:12 -0300 Subject: [PATCH 14/16] =?UTF-8?q?feat:=20enviar=20contrarraz=C3=A3o=20(val?= =?UTF-8?q?ida=C3=A7=C3=B5es)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/MapasCulturais/Controllers/Panel.php | 4 +- .../Repositories/CounterArgument.php | 7 ++- .../Services/CounterArgumentService.php | 21 +++++-- .../Controllers/Controller.php | 47 ++++++++++++++-- .../lib/modules/CounterArgument/Module.php | 8 ++- .../assets/counter-argument/css/panel.css | 40 ++++++++------ .../assets/counter-argument/js/proponent.js | 55 ++++++++++++++++--- .../parts/counter-argument/opportunity.php | 24 ++++---- .../layouts/parts/counter-argument/view.php | 31 ++++++++--- 9 files changed, 176 insertions(+), 61 deletions(-) diff --git a/src/protected/application/lib/MapasCulturais/Controllers/Panel.php b/src/protected/application/lib/MapasCulturais/Controllers/Panel.php index 998e5b91d..ee305309d 100644 --- a/src/protected/application/lib/MapasCulturais/Controllers/Panel.php +++ b/src/protected/application/lib/MapasCulturais/Controllers/Panel.php @@ -434,8 +434,8 @@ public function GET_counterArguments() { $this->requireAuthentication(); - $agentId = App::i()->getUser()->profile->id; - $counterArguments = App::i()->repo('CounterArgument')->getAllByAgentId($agentId); + $userId = App::i()->getUser()->id; + $counterArguments = App::i()->repo('CounterArgument')->getAllByUserId($userId); $this->render('counter-arguments', ['counterArguments' => $counterArguments]); } diff --git a/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php b/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php index a8cedb2a4..da26e79fd 100644 --- a/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php +++ b/src/protected/application/lib/MapasCulturais/Repositories/CounterArgument.php @@ -7,14 +7,15 @@ class CounterArgument extends \MapasCulturais\Repository { - public function getAllByAgentId($agentId): array + public function getAllByUserId(int $userId): array { $qb = App::i()->em->createQueryBuilder(); $qb->select('ca') ->from(CounterArgumentEntity::class, 'ca') ->innerJoin('ca.registration', 'r') - ->where('r.owner = :agentId') - ->setParameter('agentId', $agentId); + ->innerJoin('r.owner', 'a') + ->where('a.user = :userId') + ->setParameter('userId', $userId); return $qb->getQuery()->getResult(); } diff --git a/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php b/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php index 27d5fd941..01f50cc98 100644 --- a/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php +++ b/src/protected/application/lib/MapasCulturais/Services/CounterArgumentService.php @@ -35,6 +35,19 @@ public function isCounterArgumentPeriod($opportunity) return false; } + public function isResponsePeriod($opportunity) + { + $finalStr = $opportunity->finalDateCounterArgument . ' ' . $opportunity->finalTimeCounterArgument; + $final = new DateTime($finalStr); + $now = new DateTime(); + + $appealEnabled = $opportunity->appealEnabled === 'Sim' ? true : false; + + if ($appealEnabled && $now > $final) return true; + + return false; + } + public function send(string $text, Registration $registration) { $this->counterArgumentEntity->text = $text; @@ -46,10 +59,9 @@ public function send(string $text, Registration $registration) App::i()->em->flush(); } - public function update(array $data) + public function update(string $text, CounterArgument $counterArgument) { - $counterArgument = App::i()->repo('CounterArgument')->find($data['id']); - $counterArgument->text = $data['text']; + $counterArgument->text = $text; $counterArgument->updateTimestamp = new DateTime(); $this->saveFiles($_FILES, $counterArgument); @@ -73,9 +85,8 @@ private function saveFiles($files, $counterArgument) } } - public function removeFile(int $fileId) + public function removeFile(CounterArgumentFile $counterArgumentFile) { - $counterArgumentFile = App::i()->repo('CounterArgumentFile')->find($fileId); $counterArgumentFile->delete(true); } diff --git a/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php b/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php index 60a5cea1a..5213cc3fc 100644 --- a/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php +++ b/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php @@ -3,6 +3,7 @@ namespace CounterArgument\Controllers; use MapasCulturais\App; +use MapasCulturais\Exceptions\PermissionDenied; use MapasCulturais\Services\CounterArgumentService; use MapasCulturais\Services\SentryService; @@ -17,39 +18,62 @@ public function __construct() public function POST_send() { + $this->requireAuthentication(); + $data = $this->getPostData(); $registration = App::i()->repo('Registration')->find($data['registration']); + $this->validateRegistrationOwner($registration); + $this->validatePeriod($registration->opportunity, 'O período para envio de contrarrazões está encerrado.'); + try { $this->counterArgumentService->send($data['text'], $registration); - $this->json(['message' => 'Contrarrazão enviada com sucesso. Aguarde a resposta.'], 201); } catch (\Throwable $th) { SentryService::captureExceptions($th); + return; } + + $this->json(['message' => 'Contrarrazão enviada com sucesso. Aguarde a resposta.'], 201); } public function POST_update() { + $this->requireAuthentication(); + $data = $this->getPostData(); + $counterArgument = App::i()->repo('CounterArgument')->find($data['id']); + + $this->validateRegistrationOwner($counterArgument->registration); + $this->validatePeriod($counterArgument->registration->opportunity, 'O período para editar a contrarrazão está encerrado.'); try { - $this->counterArgumentService->update($data); - $this->json(['message' => 'Contrarrazão atualizada com sucesso. Aguarde a resposta.']); + $this->counterArgumentService->update($data['text'], $counterArgument); } catch (\Throwable $th) { SentryService::captureExceptions($th); + return; } + + $this->json(['message' => 'Contrarrazão atualizada com sucesso. Aguarde a resposta.']); } public function POST_removeFile() { + $this->requireAuthentication(); + $data = $this->getPostData(); + $counterArgumentFile = App::i()->repo('CounterArgumentFile')->find($data['fileId']); + + $this->validateRegistrationOwner($counterArgumentFile->owner->registration); + $this->validatePeriod($counterArgumentFile->owner->registration->opportunity, 'O período para remover arquivos da contrarrazão está encerrado.'); try { - $this->counterArgumentService->removeFile((int)$data['fileId']); - $this->json(['message' => 'O arquivo foi removido da contrarrazão']); + $this->counterArgumentService->removeFile($counterArgumentFile); } catch (\Throwable $th) { SentryService::captureExceptions($th); + return; } + + $this->json(['message' => 'O arquivo foi removido da contrarrazão']); } public function POST_respond() @@ -63,4 +87,17 @@ public function POST_respond() SentryService::captureExceptions($th); } } + + private function validateRegistrationOwner($registration) + { + if (!$registration->owner->canUser('@control')) throw new PermissionDenied(App::i()->getUser(), $registration, 'sendCounterArgument'); + } + + private function validatePeriod($opportunity, $message) + { + if (!$this->counterArgumentService->isCounterArgumentPeriod($opportunity)) { + $this->json(['message' => $message], 403); + return; + } + } } diff --git a/src/protected/application/lib/modules/CounterArgument/Module.php b/src/protected/application/lib/modules/CounterArgument/Module.php index d255034fe..89b08f426 100644 --- a/src/protected/application/lib/modules/CounterArgument/Module.php +++ b/src/protected/application/lib/modules/CounterArgument/Module.php @@ -48,7 +48,13 @@ public function _init() $opportunity = $this->controller->requestedEntity; $counterArguments = App::i()->repo('CounterArgument')->getAllByOpportunityId($opportunity->id); - $this->part('counter-argument/opportunity', ['counterArguments' => $counterArguments]); + $counterArgumentService = new CounterArgumentService(); + $isResponsePeriod = $counterArgumentService->isResponsePeriod($opportunity); + + $this->part('counter-argument/opportunity', [ + 'isResponsePeriod' => $isResponsePeriod, + 'counterArguments' => $counterArguments + ]); }); } diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css index 3b9df5b8f..2e76b1cbe 100644 --- a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/css/panel.css @@ -1,34 +1,42 @@ -.icon-remove-counter-argument-file { - margin-left: 5px; - cursor: pointer; +.info-text { + margin-bottom: 30px; } -.btn-counter-arguments { +.counter-argument-btn { border: 1px solid #c3c3c3; border-radius: 5px; margin: 2px; background-color: transparent; - color:black; + color: black; cursor: pointer; } -.truncate-file { +.counter-argument-btn:disabled { + border: 1px solid #e0e0e0; + color: #a0a0a0; + cursor: not-allowed; +} + +.counter-argument-file-wrapper { + margin-top: 10px; +} + +.counter-argument-file { + margin-bottom: 5px; + display: flex; + justify-content: center; +} + +.counter-argument-file a { display: inline-block; - max-width: 10em; + max-width: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; -} - -.file-row { - display: flex; - align-items: center; - gap: 8px; - margin: 0; + margin: 0 5px; } .icon-remove-counter-argument-file { - flex-shrink: 0; cursor: pointer; -} \ No newline at end of file +} diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js index cb92cb120..830e15e69 100644 --- a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/proponent.js @@ -43,9 +43,21 @@ const counterArgument = { }) }, error(err) { + if (err.status === 403) { + Swal.fire({ + title: 'Contrarrazão não enviada', + text: err.responseJSON.message, + icon: 'warning', + allowOutsideClick: false, + }).then(res => { + if (res.isConfirmed) window.location.reload() + }) + return + } + Swal.fire({ - title: 'Contrarrazão não enviada', - text: 'Erro ao enviar contrarrazão. Tente novamente.', + title: 'Erro ao enviar contrarrazão', + text: 'Entre em contato com o suporte ou tente novamente mais tarde.', icon: 'error', }) } @@ -80,9 +92,21 @@ const counterArgument = { }) }, error(err) { + if (err.status === 403) { + Swal.fire({ + title: 'Contrarrazão não atualizada', + text: err.responseJSON.message, + icon: 'warning', + allowOutsideClick: false, + }).then(res => { + if (res.isConfirmed) window.location.reload() + }) + return + } + Swal.fire({ - title: 'Contrarrazão não atualizada', - text: 'Erro ao atualizar contrarrazão. Tente novamente.', + title: 'Erro ao atualizar contrarrazão', + text: 'Entre em contato com o suporte ou tente novamente mais tarde.', icon: 'error', }) } @@ -101,15 +125,25 @@ const counterArgument = { icon: 'success', allowOutsideClick: false, }).then(res => { - if (res.isConfirmed) { - window.location.reload() - } + if (res.isConfirmed) window.location.reload() }) }, error(err) { + if (err.status === 403) { + Swal.fire({ + title: 'Arquivo não removido', + text: err.responseJSON.message, + icon: 'warning', + allowOutsideClick: false, + }).then(res => { + if (res.isConfirmed) window.location.reload() + }) + return + } + Swal.fire({ - title: 'Arquivo não removido', - text: 'Erro ao remover arquivo da contrarrazão. Tente novamente.', + title: 'Erro ao remover arquivo da contrarrazão', + text: 'Entre em contato com o suporte ou tente novamente mais tarde.', icon: 'error', }) } @@ -170,6 +204,9 @@ $(() => { title: 'Editar Contrarrazão', html: `

      Você pode editar o texto da sua contrarrazão e anexar mais arquivos

      +

      + Você poderá editar até o final do período de envio de contrarrazões +

      ${text}
      diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php index 87aaae623..da32fda2b 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php @@ -5,7 +5,7 @@ ?>
      -

      Nesta seção são listadas todas as contrarrazões enviadas pelos agentes para esta oportunidade.

      +

      Nesta seção são listadas todas as contrarrazões enviadas pelos agentes para esta oportunidade.

      @@ -33,18 +33,17 @@ @@ -60,9 +59,10 @@ data-id="id ?>" data-text="response->text ?? '', ENT_QUOTES, 'UTF-8') ?>" data-status="status ?>" - class="btn-counter-arguments" + class="counter-argument-btn" btn-view-counter-argument-response - > + + title=""> diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php index f5f67f95e..a644e29bb 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php @@ -1,11 +1,15 @@

      Minhas Contrarrazões

      +

      Aqui você pode visualizar todas as contrarrazões que você enviou.

      - getFiles('counter-argument-attachment')) : ?> -
      -

      - getFiles('counter-argument-attachment') as $file) : ?> -

      - name ?> -
      - -

      +
      + getFiles('counter-argument-attachment') as $file) : ?> +
      + + name ?> +
      +
      @@ -22,6 +26,9 @@ + isCounterArgumentPeriod($counterArgument->registration->opportunity) + ?> From 262a62031752bce7e15847906d86302ca4ba4c53 Mon Sep 17 00:00:00 2001 From: Jefferson Oliveira Date: Tue, 20 Jan 2026 15:08:13 -0300 Subject: [PATCH 15/16] =?UTF-8?q?feat:=20responder=20contrarraz=C3=A3o=20(?= =?UTF-8?q?valida=C3=A7=C3=B5es)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Controller.php | 42 ++++++++++++- .../assets/counter-argument/js/admin.js | 60 +++++++++++++++++-- .../parts/counter-argument/opportunity.php | 51 ++++++++++++---- .../layouts/parts/counter-argument/view.php | 2 +- 4 files changed, 136 insertions(+), 19 deletions(-) diff --git a/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php b/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php index 5213cc3fc..0edb500b5 100644 --- a/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php +++ b/src/protected/application/lib/modules/CounterArgument/Controllers/Controller.php @@ -3,6 +3,7 @@ namespace CounterArgument\Controllers; use MapasCulturais\App; +use MapasCulturais\Entities\CounterArgument; use MapasCulturais\Exceptions\PermissionDenied; use MapasCulturais\Services\CounterArgumentService; use MapasCulturais\Services\SentryService; @@ -78,14 +79,30 @@ public function POST_removeFile() public function POST_respond() { + $this->requireAuthentication(); + $data = $this->getPostData(); + $counterArgument = App::i()->repo('CounterArgument')->find($data['counterArgumentId']); + + $this->verifyResponsePermission($counterArgument->registration); + $this->validateResponsePeriod($counterArgument->registration->opportunity); + $this->verifyResponseOwner($counterArgument->response); try { $this->counterArgumentService->saveResponse($data); - $this->json(['message' => 'Sua resposta para a contrarrazão foi salva com sucesso.']); } catch (\Throwable $th) { SentryService::captureExceptions($th); + return; } + + $this->json(['message' => 'Sua resposta para a contrarrazão foi salva com sucesso.']); + } + + public function GET_getStatuses() + { + $this->requireAuthentication(); + + $this->json(['statuses' => CounterArgument::STATUSES]); } private function validateRegistrationOwner($registration) @@ -100,4 +117,27 @@ private function validatePeriod($opportunity, $message) return; } } + + private function verifyResponsePermission($registration) + { + if (!$registration->canUser('evaluate') && !$registration->opportunity->canUser('@control')) { + throw new PermissionDenied(App::i()->getUser(), $registration, 'respondCounterArgument'); + } + } + + private function validateResponsePeriod($opportunity) + { + if (!$this->counterArgumentService->isResponsePeriod($opportunity)) { + $this->json(['message' => 'Fora do período de resposta. Aguarde o fim do período de envio das contrarrazões.'], 403); + return; + } + } + + private function verifyResponseOwner($response) + { + if ($response && !$response->owner->canUser('@control')) { + $this->json(['message' => "Essa contrarrazão já foi respondida por {$response->owner->name}"], 403); + return; + } + } } diff --git a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/admin.js b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/admin.js index c9d2653c7..df99b91ee 100644 --- a/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/admin.js +++ b/src/protected/application/lib/modules/CounterArgument/assets/counter-argument/js/admin.js @@ -1,6 +1,7 @@ const counterArgumentAdmin = { text: '', status: null, + statuses: null, getText() { return this.text }, @@ -13,6 +14,22 @@ const counterArgumentAdmin = { setStatus(status) { this.status = status }, + getStatuses() { + $.ajax({ + type: "GET", + url: MapasCulturais.createUrl('contrarrazao', 'getStatuses'), + dataType: "json", + success(res) { + counterArgumentAdmin.setStatuses(res.statuses) + }, + error(err) { + console.log(err) + } + }) + }, + setStatuses(statuses) { + this.statuses = statuses + }, respond(counterArgumentId) { $.ajax({ type: "POST", @@ -36,9 +53,21 @@ const counterArgumentAdmin = { }) }, error(err) { + if (err.status === 403) { + Swal.fire({ + title: 'Sua resposta não foi salva', + text: err.responseJSON.message, + icon: 'warning', + allowOutsideClick: false, + }).then(res => { + if (res.isConfirmed) window.location.reload() + }) + return + } + Swal.fire({ - title: 'Sua resposta não foi salva', - text: 'Erro ao salvar resposta da contrarrazão. Tente novamente.', + title: 'Erro ao responder contrarrazão', + text: 'Entre em contato com o suporte ou tente novamente mais tarde.', icon: 'error', }) } @@ -47,7 +76,9 @@ const counterArgumentAdmin = { } $(() => { - $('[btn-view-counter-argument-response]').on('click', function (event) { + counterArgumentAdmin.getStatuses() + + $('[btn-counter-argument-response]').on('click', function (event) { const counterArgumentId = event.currentTarget.dataset.id const text = event.currentTarget.dataset.text const status = event.currentTarget.dataset.status @@ -57,7 +88,7 @@ $(() => { Swal.fire({ title: 'Responder Contrarrazão', html: ` -

      Digite sua resposta para esta contrarrazão

      +

      Digite sua resposta para esta contrarrazão e selecione sua situação

      ${text}
      @@ -68,7 +99,10 @@ $(() => {
      -
      `, + +

      + Atenção! Ao salvar a resposta, somente você poderá editá-la. +

      `, width: 700, confirmButtonText: 'Salvar', cancelButtonText: 'Cancelar', @@ -98,4 +132,20 @@ $(() => { } }) }) + + $('[btn-view-counter-argument-response]').on('click', function (event) { + const text = event.currentTarget.dataset.text + const status = event.currentTarget.dataset.status + + Swal.fire({ + title: 'Resposta da Contrarrazão', + html: ` +
      ${text}
      +
      +
      + Situação: ${counterArgumentAdmin.statuses[status]} +
      `, + width: 700, + }) + }) }) diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php index da32fda2b..79dc4978f 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/opportunity.php @@ -21,6 +21,9 @@
      + response; + ?> diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php index a644e29bb..b6ea91428 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php @@ -68,7 +68,7 @@ status] ?>
      @@ -38,19 +45,20 @@ - getFiles('counter-argument-attachment')) : ?> -
      +
      getFiles('counter-argument-attachment') as $file) : ?> -
      -

      - name ?> +

      + + name ?> + -

      +
      @@ -63,12 +71,19 @@ createTimestamp->format('d/m/Y H:i') ?>
      - -
      @@ -51,20 +54,44 @@ status] ?> - createTimestamp->format('d/m/Y H:i') ?> + updateTimestamp ?? $counterArgument->createTimestamp)->format('d/m/Y H:i') ?> - +
      + owner->canUser('@control')) || !$response) : ?> + + owner->canUser('@control')) : ?> + + + +
      +
      + owner->name ?> +
      +
      + updateTimestamp ?? $response->createTimestamp)->format('d/m/Y H:i') ?> +
      +
      + +
      - createTimestamp->format('d/m/Y H:i') ?> + updateTimestamp ?? $counterArgument->createTimestamp)->format('d/m/Y H:i') ?>
      @@ -58,27 +64,26 @@
      - owner->canUser('@control')) || !$response) : ?> + owner->canUser('@control') || $response->published)) : ?> - owner->canUser('@control')) : ?> + owner->canUser('@control')) || !$response) : ?> @@ -97,6 +102,18 @@ class="counter-argument-btn"
      + + canUser('@control')) : ?> + +
      Ainda não foram enviadas contrarrazões nesta oportunidade.
      diff --git a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php index b6ea91428..0f596ea09 100644 --- a/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php +++ b/src/protected/application/lib/modules/CounterArgument/layouts/parts/counter-argument/view.php @@ -27,7 +27,9 @@ isCounterArgumentPeriod($counterArgument->registration->opportunity) + $isCounterArgumentPeriod = $counterArgumentService->isCounterArgumentPeriod($counterArgument->registration->opportunity); + $response = $counterArgument->response; + $publishedResponse = $response && $response->published; ?> @@ -55,7 +57,7 @@ name ?> - + @@ -65,13 +67,19 @@ - status] ?> + status : CounterArgument::STATUS_WAITING] ?> updateTimestamp ?? $counterArgument->createTimestamp)->format('d/m/Y H:i') ?> -