Skip to content

Commit 3cb35dc

Browse files
committed
5566: Add security contract entity and controller, refactor crud controller and styling
1 parent 06ca1c5 commit 3cb35dc

17 files changed

Lines changed: 564 additions & 72 deletions

assets/styles/app.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,14 @@
1313
--text-color-dark: rgb(66, 66, 66);
1414
--bs-danger-rgb: 228, 73, 48;
1515
}
16+
17+
/* Grouped dropdown group styling for index pages */
18+
.dropdown-menu {
19+
.btn-danger i, .text-danger i {
20+
color: var(--button-invisible-danger-color);
21+
}
22+
23+
a.btn-danger:hover , a.text-danger:hover {
24+
background: var(--button-invisible-danger-hover-hover-bg);
25+
}
26+
}
Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/**
1111
* Auto-generated Migration: Please modify to your needs!
1212
*/
13-
final class Version20251021113753 extends AbstractMigration
13+
final class Version20251023091529 extends AbstractMigration
1414
{
1515
public function getDescription(): string
1616
{
@@ -37,11 +37,39 @@ public function up(Schema $schema): void
3737
PRIMARY KEY (id)
3838
) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci`
3939
SQL);
40+
$this->addSql(<<<'SQL'
41+
CREATE TABLE security_contract (
42+
id BINARY(16) NOT NULL,
43+
created_at DATETIME NOT NULL,
44+
modified_at DATETIME NOT NULL,
45+
created_by VARCHAR(255) DEFAULT '' NOT NULL,
46+
modified_by VARCHAR(255) DEFAULT '' NOT NULL,
47+
economics_report_url VARCHAR(255) DEFAULT NULL,
48+
operational_contract_url LONGTEXT DEFAULT NULL,
49+
monthly_price DOUBLE PRECISION DEFAULT NULL,
50+
quarterly_hours DOUBLE PRECISION DEFAULT NULL,
51+
valid_from DATE NOT NULL,
52+
valid_to DATE NOT NULL,
53+
active TINYINT(1) NOT NULL,
54+
notes LONGTEXT NOT NULL,
55+
project_id BINARY(16) NOT NULL,
56+
UNIQUE INDEX UNIQ_8AE4AF8B166D1F9C (project_id),
57+
PRIMARY KEY (id)
58+
) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci`
59+
SQL);
60+
$this->addSql(<<<'SQL'
61+
ALTER TABLE
62+
security_contract
63+
ADD
64+
CONSTRAINT FK_8AE4AF8B166D1F9C FOREIGN KEY (project_id) REFERENCES project (id)
65+
SQL);
4066
}
4167

4268
public function down(Schema $schema): void
4369
{
4470
// this down() migration is auto-generated, please modify it to your needs
71+
$this->addSql('ALTER TABLE security_contract DROP FOREIGN KEY FK_8AE4AF8B166D1F9C');
4572
$this->addSql('DROP TABLE project');
73+
$this->addSql('DROP TABLE security_contract');
4674
}
4775
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace App\Controller\Admin;
4+
5+
use App\Trait\ExportCrudControllerTrait;
6+
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
7+
use EasyCorp\Bundle\EasyAdminBundle\Config\ActionGroup;
8+
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
9+
use EasyCorp\Bundle\EasyAdminBundle\Config\Assets;
10+
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
11+
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
12+
13+
abstract class AbstractFullCrudController extends AbstractCrudController
14+
{
15+
use ExportCrudControllerTrait;
16+
17+
#[\Override]
18+
public function configureCrud(Crud $crud): Crud
19+
{
20+
return $crud->showEntityActionsInlined();
21+
}
22+
23+
#[\Override]
24+
public function configureActions(Actions $actions): Actions
25+
{
26+
// Remove default actions
27+
$actions
28+
->remove(Crud::PAGE_INDEX, Action::EDIT)
29+
->remove(Crud::PAGE_INDEX, Action::DELETE);
30+
31+
// Re-add default actions as grouped action.
32+
$groupedDefaultActions = ActionGroup::new('default', 'Default')
33+
->addMainAction(
34+
Action::new('show', 'Show')
35+
->linkToCrudAction(Action::DETAIL)
36+
)
37+
->addAction(
38+
Action::new('edit', 'Edit')
39+
->linkToCrudAction(Action::EDIT)
40+
->setIcon('fa fa-edit')
41+
)
42+
->addDivider()
43+
->addAction(
44+
Action::new('delete', 'Delete')
45+
->linkToCrudAction(Action::DELETE)
46+
->setIcon('fa fa-trash')
47+
->setCssClass('btn-danger text-danger')
48+
);
49+
50+
return $actions
51+
->add(Crud::PAGE_INDEX, $groupedDefaultActions)
52+
->add(Crud::PAGE_INDEX, $this->createExportAction())
53+
->update(Crud::PAGE_INDEX, Action::NEW,
54+
static fn (Action $action) => $action->setIcon('fa fa-plus')
55+
)
56+
;
57+
}
58+
59+
#[\Override]
60+
public function configureAssets(Assets $assets): Assets
61+
{
62+
return $assets
63+
->addWebpackEncoreEntry('easyadmin');
64+
}
65+
}

src/Controller/Admin/DashboardController.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace App\Controller\Admin;
66

7+
use App\EasyAdmin\Config\AutoBadgeMenuItem;
78
use App\Entity\Advisory;
89
use App\Entity\DetectionResult;
910
use App\Entity\DockerImage;
@@ -18,10 +19,14 @@
1819
use App\Entity\Package;
1920
use App\Entity\PackageVersion;
2021
use App\Entity\Project;
22+
use App\Entity\SecurityContract;
2123
use App\Entity\Server;
2224
use App\Entity\ServiceCertificate;
2325
use App\Entity\Site;
2426
use App\Repository\AdvisoryRepository;
27+
use App\Repository\OIDCRepository;
28+
use App\Repository\SecurityContractRepository;
29+
use App\Repository\ServiceCertificateRepository;
2530
use EasyCorp\Bundle\EasyAdminBundle\Config\Assets;
2631
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
2732
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
@@ -35,6 +40,9 @@ class DashboardController extends AbstractDashboardController
3540
public function __construct(
3641
private readonly AdminUrlGenerator $adminUrlGenerator,
3742
private readonly AdvisoryRepository $advisoryRepository,
43+
private readonly ServiceCertificateRepository $serviceCertificateRepository,
44+
private readonly OIDCRepository $oidcRepository,
45+
private readonly SecurityContractRepository $securityContractRepository,
3846
) {
3947
}
4048

@@ -62,17 +70,27 @@ public function configureDashboard(): Dashboard
6270
public function configureMenuItems(): iterable
6371
{
6472
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
65-
yield MenuItem::linkToCrud('Servers', 'fas fa-server', Server::class);
73+
74+
yield MenuItem::section('Projects');
6675
yield MenuItem::linkToCrud('Projects', 'fas fa-folder', Project::class);
76+
yield AutoBadgeMenuItem::linkToCrud('Cyber Security', 'fas fa-file-contract', SecurityContract::class)
77+
->setBadge($this->securityContractRepository->countExpiredContracts(), 'danger');
78+
yield AutoBadgeMenuItem::linkToCrud('OIDC', 'fas fa-shield-halved', OIDC::class)
79+
->setBadge($this->oidcRepository->countExpiredCertificates(), 'danger');
80+
yield AutoBadgeMenuItem::linkToCrud('Service certificates', 'fas fa-passport', ServiceCertificate::class)
81+
->setBadge($this->serviceCertificateRepository->countExpiredCertificates(), 'danger');
82+
83+
yield MenuItem::section('Hosting');
84+
yield MenuItem::linkToCrud('Servers', 'fas fa-server', Server::class);
6785
yield MenuItem::linkToCrud('Installations', 'fas fa-folder', Installation::class);
6886
yield MenuItem::linkToCrud('Sites', 'fas fa-bookmark', Site::class);
6987
yield MenuItem::linkToCrud('Domains', 'fas fa-link', Domain::class);
70-
yield MenuItem::linkToCrud('OIDC', 'fas fa-key', OIDC::class);
71-
yield MenuItem::linkToCrud('Service certificates', 'fas fa-lock', ServiceCertificate::class);
88+
7289
yield MenuItem::section('Dependencies');
7390
yield MenuItem::linkToCrud('Packages', 'fas fa-cube', Package::class);
7491
yield MenuItem::linkToCrud('Package Versions', 'fas fa-cubes', PackageVersion::class);
75-
yield MenuItem::linkToCrud('Advisories', 'fas fa-skull-crossbones', Advisory::class)->setBadge($this->advisoryRepository->count([]), 'dark');
92+
yield AutoBadgeMenuItem::linkToCrud('Advisories', 'fas fa-skull-crossbones', Advisory::class)
93+
->setBadge($this->advisoryRepository->count([]), 'danger');
7694
yield MenuItem::linkToCrud('Modules', 'fas fa-cube', Module::class);
7795
yield MenuItem::linkToCrud('Modules Versions', 'fas fa-cubes', ModuleVersion::class);
7896
yield MenuItem::linkToCrud('Docker Images', 'fas fa-cube', DockerImage::class);

src/Controller/Admin/OIDCCrudController.php

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,18 @@
88
use App\Repository\SiteRepository;
99
use App\Trait\ExportCrudControllerTrait;
1010
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
11+
use EasyCorp\Bundle\EasyAdminBundle\Config\ActionGroup;
1112
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
1213
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
13-
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
1414
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
1515
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
1616
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
1717
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
1818
use EasyCorp\Bundle\EasyAdminBundle\Field\UrlField;
1919
use Symfony\Component\Translation\TranslatableMessage;
2020

21-
class OIDCCrudController extends AbstractCrudController
21+
class OIDCCrudController extends AbstractFullCrudController
2222
{
23-
use ExportCrudControllerTrait;
24-
2523
public function __construct(
2624
private readonly SiteRepository $siteRepository)
2725
{
@@ -32,24 +30,6 @@ public static function getEntityFqcn(): string
3230
return OIDC::class;
3331
}
3432

35-
#[\Override]
36-
public function configureCrud(Crud $crud): Crud
37-
{
38-
return $crud->showEntityActionsInlined();
39-
}
40-
41-
#[\Override]
42-
public function configureActions(Actions $actions): Actions
43-
{
44-
return $actions
45-
->add(Crud::PAGE_INDEX, Action::DETAIL)
46-
->add(Crud::PAGE_INDEX, $this->createExportAction())
47-
->update(Crud::PAGE_INDEX, Action::NEW,
48-
static fn (Action $action) => $action->setIcon('fa fa-plus')
49-
)
50-
;
51-
}
52-
5333
#[\Override]
5434
public function configureFields(string $pageName): iterable
5535
{

src/Controller/Admin/ProjectCrudController.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function configureCrud(Crud $crud): Crud
3838
->setDefaultSort(['name' => 'ASC'])
3939
->setSearchFields(['name', 'details'])
4040
->showEntityActionsInlined()
41-
->setPageTitle(Crud::PAGE_INDEX, 'Leantime projects')
41+
->setPageTitle(Crud::PAGE_INDEX, 'Projects')
4242
->setHelp(Crud::PAGE_INDEX, 'Projects are synced from Leantime. Click on the "Sync all" button to update all projects.');
4343
}
4444

@@ -80,7 +80,13 @@ public function createUpdateAllProjectsAction(): Action
8080

8181
public function updateAllProjects(SiteRepository $siteRepository): RedirectResponse
8282
{
83-
$this->projectSyncService->syncAllProjects();
83+
try {
84+
$this->projectSyncService->syncAllProjects();
85+
86+
$this->addFlash('info', 'All projects have been synced.', );
87+
} catch (\Throwable $e) {
88+
$this->addFlash('error', 'An error occurred while syncing projects. Check the log for details.');
89+
}
8490

8591
return $this->redirectToRoute('admin_project_index');
8692
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace App\Controller\Admin;
4+
5+
use App\Entity\SecurityContract;
6+
use App\Repository\SecurityContractRepository;
7+
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
8+
use EasyCorp\Bundle\EasyAdminBundle\Config\KeyValueStore;
9+
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
10+
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
11+
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
12+
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
13+
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
14+
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField;
15+
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
16+
use EasyCorp\Bundle\EasyAdminBundle\Field\UrlField;
17+
use Symfony\Component\HttpFoundation\RedirectResponse;
18+
use Symfony\Component\HttpFoundation\Response;
19+
20+
class SecurityContractCrudController extends AbstractFullCrudController
21+
{
22+
public function __construct(
23+
private readonly SecurityContractRepository $securityContractRepository,
24+
)
25+
{
26+
}
27+
28+
public static function getEntityFqcn(): string
29+
{
30+
return SecurityContract::class;
31+
}
32+
33+
#[\Override]
34+
public function configureCrud(Crud $crud): Crud
35+
{
36+
return $crud
37+
->setDefaultSort(['project.name' => 'ASC'])
38+
//->setSearchFields(['name', 'details'])
39+
->showEntityActionsInlined()
40+
->setPageTitle(Crud::PAGE_INDEX, 'Cyber Security Contracts');
41+
}
42+
43+
#[\Override]
44+
public function configureFields(string $pageName): iterable
45+
{
46+
yield FormField::addFieldset('Project');
47+
yield BooleanField::new('active')->renderAsSwitch(false)->setColumns(2);
48+
yield AssociationField::new('project')->setColumns(10);
49+
50+
yield FormField::addFieldset('Links');
51+
yield UrlField::new('project.leantimeUrl')->setLabel('Leantime URL')->setDisabled()->hideOnIndex()->hideWhenCreating();
52+
yield UrlField::new('economicsReportUrl')->setLabel('Economics URL')->hideOnIndex()->setColumns(12);
53+
yield UrlField::new('operationalContractUrl')->setLabel('Contract URL')->hideOnIndex()->setColumns(12);
54+
55+
yield FormField::addFieldset('Budget');
56+
yield NumberField::new('monthlyPrice')->setTextAlign('right')->setColumns(6);
57+
yield NumberField::new('quarterlyHours')->setTextAlign('right')->setColumns(6);
58+
59+
yield FormField::addFieldset('Validity');
60+
yield DateField::new('validFrom')->setColumns(6);
61+
yield DateField::new('validTo')->setColumns(6);
62+
63+
yield FormField::addFieldset('Notes');
64+
yield TextareaField::new('notes')->hideOnIndex()->setColumns(12);
65+
}
66+
}

src/Controller/Admin/ServerCrudController.php

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@
2828
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
2929
use Symfony\Component\HttpFoundation\RequestStack;
3030

31-
class ServerCrudController extends AbstractCrudController
31+
class ServerCrudController extends AbstractFullCrudController
3232
{
33-
use ExportCrudControllerTrait;
34-
3533
public function __construct(
3634
private readonly RequestStack $requestStack,
3735
) {
@@ -54,20 +52,6 @@ public function configureCrud(Crud $crud): Crud
5452
return $crud;
5553
}
5654

57-
#[\Override]
58-
public function configureActions(Actions $actions): Actions
59-
{
60-
return $actions
61-
->remove(Crud::PAGE_INDEX, Action::EDIT)
62-
->remove(Crud::PAGE_INDEX, Action::DELETE)
63-
->add(Crud::PAGE_INDEX, Action::DETAIL)
64-
->add(Crud::PAGE_INDEX, $this->createExportAction())
65-
->update(Crud::PAGE_INDEX, Action::NEW,
66-
static fn (Action $action) => $action->setIcon('fa fa-plus')
67-
)
68-
;
69-
}
70-
7155
#[\Override]
7256
public function configureFields(string $pageName): iterable
7357
{

0 commit comments

Comments
 (0)