Files
Investidor-V2/app/Services/ContentManagement.php
T
2026-11-14 12:25:27 +02:00

139 lines
7.1 KiB
PHP

<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Support\Facades\DB;
/** Navigation over existing authorisations; never grants a role or publishes content. */
final class ContentManagement
{
/**
* @return array<array-key, mixed>
*/
public function access(?User $actor): array
{
if (! $actor || ! $actor->hasVerifiedEmail()) {
return [];
}
$profiles = app(PortalProfileAccess::class);
$navigation = $profiles->navigation($actor);
$legacy = $profiles->legacyWriteAllowed($actor);
$documents = app(DocumentManagementAccess::class);
$editor = $documents->full($actor) || $documents->editorial($actor);
$upload = $editor || $documents->limited($actor);
$result = [];
if (app(PortalEditorialWorkflow::class)->demographyAccess($actor)) {
$result['demography'] = ['index' => '/management/demography'];
}
if (app(PortalEditorialWorkflow::class)->portfolioAvailable() && $actor->can('manage-portal') && ! $profiles->has($actor, 'auditor')) {
$result['portfolio'] = ['index' => '/management/portfolio'];
}
if (app(ClusterCompetitiveness::class)->editorialEnabled() && $actor->can('manage-portal') && ! $profiles->has($actor, 'auditor')) {
$result['clusters'] = ['index' => '/management/clusters'];
}
if (app(Procurement::class)->available() && app(Procurement::class)->access($actor)) {
$result['procurement'] = ['index' => '/management/concursos', 'create' => '/management/concursos/novo'];
}
if ($legacy || ($navigation['mine'] ?? null) || ($navigation['review'] ?? null)) {
$result['opportunities'] = ['index' => $legacy ? '/management/opportunities' : '/minhas-oportunidades',
'create' => $legacy ? '/management/opportunities/create' : ($navigation['create'] ?? null), 'profileWorkflow' => ! $legacy];
}
if ($upload) {
$result['documents'] = ['index' => '/management/portal-services', 'edit' => $editor];
}
if (($editor || isset($result['opportunities'])) && ! $profiles->has($actor, 'auditor') && app(PortalEditorialWorkflow::class)->available()) {
$result['editorial'] = ['index' => '/management/editorial'];
}
return $result;
}
/** @param array<array-key,mixed> $access
* @return list<array{label:string,href:string}>
*/
public function administrationNavigation(?User $actor, array $access): array
{
if (! $actor || ! $actor->hasVerifiedEmail()) {
return [];
}
$items = [];
foreach (['documents' => 'Biblioteca e documentos', 'opportunities' => 'Oportunidades', 'clusters' => 'Competitividade', 'portfolio' => 'Carteira', 'demography' => 'Demografia', 'procurement' => 'Concursos e anúncios'] as $key => $label) {
if (isset($access[$key]['index'])) {
$items[] = ['label' => $label, 'href' => $access[$key]['index']];
}
}
if (app(PortalEditorialSubjects::class)->available() && $actor->can('manage-portal') && ! app(PortalProfileAccess::class)->has($actor, 'auditor')) {
$items[] = ['label' => 'Estruturas e relações', 'href' => '/management/editorial/subjects'];
}
$native = app(PortalEditorialNativeNotices::class);
if ($native->access($actor, 'territorial-editorial-v1')) {
$items[] = ['label' => 'Conteúdos territoriais', 'href' => '/management/territorial/editorial'];
}
if ($native->access($actor, 'investment-zones')) {
$items[] = ['label' => 'Zonas e indicadores', 'href' => '/management/investment/zones'];
}
return $items;
}
/** @param array<array-key,mixed> $access
* @return list<array{label:string,href:string}>
*/
public function dashboardNavigation(?User $actor, array $access): array
{
if (! $actor || ! $actor->hasVerifiedEmail() || (! $actor->can('manage-portal') && $access === [] && ! app(ScopedPortalAdministration::class)->administrative($actor))) {
return [];
}
$items = [['label' => 'Visão geral', 'href' => '/dashboard'], ['label' => 'O meu trabalho', 'href' => '/dashboard#meu-trabalho']];
if ($actor->can('manage-portal') && ! app(PortalProfileAccess::class)->has($actor, 'auditor')) {
foreach (['manifestacoes' => 'Manifestações de interesse', 'indicadores-oportunidades' => 'Indicadores de oportunidades', 'pedidos-recentes' => 'Pedidos recentes', 'accoes-rapidas' => 'Acções rápidas'] as $anchor => $label) {
$items[] = ['label' => $label, 'href' => '/dashboard#'.$anchor];
}
$items[] = ['label' => 'Indicadores de utilização', 'href' => '/management/product-usage'];
}
if (! $actor->can('manage-portal') && app(InvestorPath::class)->available()) {
$items[] = ['label' => 'Os meus investimentos', 'href' => '/dashboard#meus-investimentos'];
}
$workflow = app(PortalEditorialWorkflow::class);
if ($workflow->available() && $workflow->canEnter($actor)) {
$items[] = ['label' => 'Circuito editorial', 'href' => '/management/editorial'];
$documents = app(DocumentManagementAccess::class);
if ($documents->full($actor) || $documents->editorial($actor)) {
foreach (['article' => 'Revisão de artigos', 'legislation' => 'Revisão de legislação', 'document' => 'Revisão de documentos'] as $kind => $label) {
$items[] = ['label' => $label, 'href' => '/management/editorial?kind='.$kind];
}
}
$items[] = ['label' => 'Notificações editoriais', 'href' => '/management/editorial#notificacoes'];
}
return $items;
}
/**
* @return array<array-key, mixed>
*/
public function view(User $actor): array
{
$access = $this->access($actor);
abort_unless($access !== [], 403);
$counts = [];
if (isset($access['opportunities'])) {
$counts['opportunities'] = app(PortalProfileAccess::class)->scope(Opportunity::query(), $actor)
->selectRaw("COALESCE(workflow_context->>'working_state',status) as state, count(*) as total")
->groupByRaw("COALESCE(workflow_context->>'working_state',status)")->pluck('total', 'state');
}
if (isset($access['documents'])) {
$documents = app(DocumentManagementAccess::class);
$query = $documents->full($actor) ? DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->whereNull('d.deleted_at')
: ($access['documents']['edit'] ? $documents->editorialResources($actor) : null);
$counts['documents'] = $query ? $query->select('r.published', DB::raw('count(*) as total'))->groupBy('r.published')->get()
->mapWithKeys(fn ($row) => [$row->published ? 'published' : 'unpublished' => (int) $row->total]) : [];
}
return ['access' => $access, 'counts' => $counts];
}
}