Skip to content
Open
12 changes: 12 additions & 0 deletions config/module.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
Service\ObjectCategoryService::class => AutowireFactory::class,
Service\ObjectObjectService::class => AutowireFactory::class,
Service\PasswordService::class => AutowireFactory::class,
Service\RiskSourceService::class => AutowireFactory::class,
Service\ScaleService::class => AutowireFactory::class,
Service\ScaleCommentService::class => AutowireFactory::class,
Service\ScaleImpactTypeService::class => AutowireFactory::class,
Expand Down Expand Up @@ -208,7 +209,9 @@
Table\OperationalRiskScaleCommentTable::class => Table\Factory\CoreEntityManagerFactory::class,
Table\OperationalInstanceRiskScaleTable::class => Table\Factory\CoreEntityManagerFactory::class,
Table\PasswordTokenTable::class => Table\Factory\ClientEntityManagerFactory::class,
Table\ReassessmentTriggerTable::class => Table\Factory\CoreEntityManagerFactory::class,
Table\ReferentialTable::class => Table\Factory\CoreEntityManagerFactory::class,
Table\RiskSourceTable::class => Table\Factory\CoreEntityManagerFactory::class,
Table\RolfTagTable::class => Table\Factory\CoreEntityManagerFactory::class,
Table\RolfRiskTable::class => Table\Factory\CoreEntityManagerFactory::class,
Table\ScaleTable::class => Table\Factory\CoreEntityManagerFactory::class,
Expand All @@ -228,6 +231,7 @@
Service\ConnectedUserService::class => AutowireFactory::class,
/* Translation */
Service\TranslateService::class => Service\TranslateServiceFactory::class,
Service\ReassessmentTriggerService::class => AutowireFactory::class,

/* Validators */
InputValidator\InputValidationTranslator::class => ReflectionBasedAbstractFactory::class,
Expand Down Expand Up @@ -307,6 +311,14 @@
ReflectionBasedAbstractFactory::class,
InputValidator\Referential\PostReferentialDataInputValidator::class =>
ReflectionBasedAbstractFactory::class,
InputValidator\ReassessmentTrigger\PostReassessmentTriggerDataInputValidator::class =>
ReflectionBasedAbstractFactory::class,
InputValidator\ReassessmentTrigger\PatchReassessmentTriggerDataInputValidator::class =>
ReflectionBasedAbstractFactory::class,
InputValidator\RiskSource\PostRiskSourceDataInputValidator::class =>
ReflectionBasedAbstractFactory::class,
InputValidator\RiskSource\PatchRiskSourceDataInputValidator::class =>
ReflectionBasedAbstractFactory::class,
InputValidator\RolfTag\PostRolfTagDataInputValidator::class => static function (
Containerinterface $container
) {
Expand Down
25 changes: 24 additions & 1 deletion migrations/db/20210521090000_changeable_operational_impact.php
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ public function change()
private function createTranslations(array $data, string $type, string $fieldName, string $translationKey): void
{
$translations = [];
foreach ([1 => 'fr', 2 => 'en', 3 => 'de', 4 => 'nl'] as $langKey => $langLabel) {
foreach ($this->getLanguageIndexToCodeMap() as $langKey => $langLabel) {
if (!empty($data[$fieldName . $langKey])) {
$translations[] = [
'anr_id' => $data['anr_id'],
Expand All @@ -281,6 +281,29 @@ private function createTranslations(array $data, string $type, string $fieldName
$this->table('translations')->insert($translations)->save();
}

private function getLanguageIndexToCodeMap(): array
{
$config = [];
$base = getcwd() . '/config/autoload/';
foreach (['global.php', 'local.php'] as $file) {
$path = $base . $file;
if (file_exists($path)) {
$config = array_replace_recursive($config, require $path);
}
}

if (!empty($config['languages']) && is_array($config['languages'])) {
$map = [];
foreach ($config['languages'] as $code => $langData) {
$map[(int)$langData['index']] = $code;
}
ksort($map);
return $map;
}

return [1 => 'fr', 2 => 'en', 3 => 'de', 4 => 'nl'];
}

private function createOperationalInstanceRisksScales(array $currentScaleTypesByAnr): void
{
$operationalInstanceRisksScalesTable = $this->table('operational_instance_risks_scales');
Expand Down
27 changes: 23 additions & 4 deletions migrations/db/20211129110500_fix_op_scales_translations.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ public function change()
group by st.label_translation_key, st.anr_id'
);
$translationsTable = $this->table('translations');
$languages = $this->getLanguageCodes();
foreach ($scalesTypesQuery->fetchAll() as $scaleTypeData) {
if ((int)$scaleTypeData['langs_cnt'] < 4) {
foreach (['fr', 'en', 'de', 'nl'] as $lang) {
if ((int)$scaleTypeData['langs_cnt'] < count($languages)) {
foreach ($languages as $lang) {
$existsForTheLang = $this->fetchRow(
'select count(*) cnt from `translations`
where translation_key = "' . $scaleTypeData['label_translation_key'] . '"
Expand Down Expand Up @@ -51,8 +52,8 @@ public function change()
);
$translationsTable = $this->table('translations');
foreach ($scalesCommentsQuery->fetchAll() as $scaleCommentData) {
if ((int)$scaleCommentData['langs_cnt'] < 4) {
foreach (['fr', 'en', 'de', 'nl'] as $lang) {
if ((int)$scaleCommentData['langs_cnt'] < count($languages)) {
foreach ($languages as $lang) {
$existsForTheLang = $this->fetchRow(
'select count(*) cnt from `translations`
where translation_key = "' . $scaleCommentData['comment_translation_key'] . '"
Expand All @@ -73,4 +74,22 @@ public function change()
}
}
}

private function getLanguageCodes(): array
{
$config = [];
$base = getcwd() . '/config/autoload/';
foreach (['global.php', 'local.php'] as $file) {
$path = $base . $file;
if (file_exists($path)) {
$config = array_replace_recursive($config, require $path);
}
}

if (!empty($config['languages']) && is_array($config['languages'])) {
return array_keys($config['languages']);
}

return ['fr', 'en', 'de', 'nl'];
}
}
52 changes: 40 additions & 12 deletions migrations/db/20230901112005_fix_positions_cleanup_db.php
Original file line number Diff line number Diff line change
Expand Up @@ -295,18 +295,28 @@ public function change()
->removeIndex(['anr_id', 'code'])
->removeColumn('anr_id')
->save();
$this->table('rolf_tags')
->dropForeignKey('anr_id')
->removeIndex(['anr_id', 'code'])
->removeColumn('anr_id')
->save();
$this->table('rolf_tags')->addIndex(['code'], ['unique' => true])->save();
$this->table('rolf_risks')
->dropForeignKey('anr_id')
->removeIndex(['anr_id', 'code'])
->removeColumn('anr_id')
->save();
$this->table('rolf_risks')->addIndex(['code'], ['unique' => true])->save();
$rolfTagsTable = $this->table('rolf_tags');
if ($rolfTagsTable->hasColumn('anr_id')) {
if ($rolfTagsTable->hasForeignKey('anr_id')) {
$rolfTagsTable->dropForeignKey('anr_id')->save();
}
$this->dropIndexesOnColumn('rolf_tags', 'anr_id');
$rolfTagsTable->removeColumn('anr_id')->save();
}
if (!$rolfTagsTable->hasIndex(['code'])) {
$rolfTagsTable->addIndex(['code'], ['unique' => true])->save();
}
$rolfRisksTable = $this->table('rolf_risks');
if ($rolfRisksTable->hasColumn('anr_id')) {
if ($rolfRisksTable->hasForeignKey('anr_id')) {
$rolfRisksTable->dropForeignKey('anr_id')->save();
}
$this->dropIndexesOnColumn('rolf_risks', 'anr_id');
$rolfRisksTable->removeColumn('anr_id')->save();
}
if (!$rolfRisksTable->hasIndex(['code'])) {
$rolfRisksTable->addIndex(['code'], ['unique' => true])->save();
}
$this->table('rolf_risks_tags')
->removeColumn('creator')
->removeColumn('created_at')
Expand All @@ -329,4 +339,22 @@ public function change()
->removeColumn('updated_at')
->save();
}

/**
* Drops all non-PRIMARY indexes that include the given column.
* Uses SHOW INDEX which only requires SELECT privilege on the table (no information_schema access needed).
*/
private function dropIndexesOnColumn(string $tableName, string $columnName): void
{
$rows = $this->fetchAll("SHOW INDEX FROM `{$tableName}`");
$namesToDrop = [];
foreach ($rows as $row) {
if ($row['Column_name'] === $columnName && $row['Key_name'] !== 'PRIMARY') {
$namesToDrop[$row['Key_name']] = true;
}
}
foreach (array_keys($namesToDrop) as $indexName) {
$this->execute("ALTER TABLE `{$tableName}` DROP INDEX `{$indexName}`");
}
}
}
119 changes: 119 additions & 0 deletions migrations/db/20260505100000_add_risk_sources.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php declare(strict_types=1);
/**
* @link https://github.com/monarc-project for the canonical source repository
* @copyright Copyright (c) 2016-2026 Luxembourg House of Cybersecurity LHC.lu - Licensed under GNU Affero GPL v3
* @license MONARC is licensed under GNU Affero General Public License version 3
*/

use Phinx\Migration\AbstractMigration;

class AddRiskSources extends AbstractMigration
{
public function up(): void
{
$this->execute(
'CREATE TABLE IF NOT EXISTS `risk_sources` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`label` text NOT NULL,
`is_default` tinyint(1) NOT NULL DEFAULT 0,
`is_active` tinyint(1) NOT NULL DEFAULT 1,
`creator` varchar(255) DEFAULT NULL,
`created_at` datetime DEFAULT CURRENT_TIMESTAMP,
`updater` varchar(255) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `risk_sources_is_active_indx` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'
);

$defaultRiskSources = [
[
'fr' => 'Attaquant externe',
'en' => 'External attacker',
'de' => 'Externer Angreifer',
'nl' => 'Externe aanvaller',
'pt' => 'Atacante externo',
],
[
'fr' => 'Utilisateur interne malveillant',
'en' => 'Internal malicious user',
'de' => 'Interner böswilliger Benutzer',
'nl' => 'Interne kwaadwillende gebruiker',
'pt' => 'Utilizador interno malicioso',
],
[
'fr' => 'Utilisateur interne accidentel',
'en' => 'Internal accidental user',
'de' => 'Interner versehentlicher Benutzer',
'nl' => 'Interne onbedoelde gebruiker',
'pt' => 'Utilizador interno acidental',
],
[
'fr' => 'Fournisseur / tiers',
'en' => 'Supplier / third party',
'de' => 'Lieferant / Drittpartei',
'nl' => 'Leverancier / derde partij',
'pt' => 'Fornecedor / terceiro',
],
[
'fr' => 'Défaillance système',
'en' => 'System failure',
'de' => 'Systemausfall',
'nl' => 'Systeemstoring',
'pt' => 'Falha do sistema',
],
[
'fr' => 'Défaut logiciel',
'en' => 'Software defect',
'de' => 'Softwarefehler',
'nl' => 'Softwaredefect',
'pt' => 'Defeito de software',
],
[
'fr' => 'Événement naturel',
'en' => 'Natural event',
'de' => 'Naturereignis',
'nl' => 'Natuurgebeurtenis',
'pt' => 'Evento natural',
],
[
'fr' => 'Faiblesse organisationnelle ou processuelle',
'en' => 'Organizational or process weakness',
'de' => 'Organisatorische oder prozessuale Schwäche',
'nl' => 'Organisatorische of procesmatige zwakte',
'pt' => 'Fraqueza organizacional ou de processo',
],
[
'fr' => 'Autre',
'en' => 'Other',
'de' => 'Sonstige',
'nl' => 'Overige',
'pt' => 'Outro',
],
];
foreach ($defaultRiskSources as $labels) {
$escapedLabel = addslashes(json_encode($labels, JSON_THROW_ON_ERROR));
$this->execute(
"INSERT INTO `risk_sources` (`label`, `is_default`, `is_active`, `creator`, `created_at`) VALUES
('{$escapedLabel}', 1, 1, 'Migration script', NOW());"
);
}

$this->table('instances_risks')
->addColumn('risk_source_id', 'integer', ['null' => true, 'signed' => false, 'after' => 'asset_id'])
->addIndex(['risk_source_id'], ['name' => 'risk_source_id'])
->addForeignKey('risk_source_id', 'risk_sources', 'id', ['delete' => 'SET_NULL', 'update' => 'RESTRICT'])
->update();
}

public function down(): void
{
$this->table('instances_risks')
->dropForeignKey('risk_source_id')
->removeIndexByName('risk_source_id')
->removeColumn('risk_source_id')
->update();

$this->table('risk_sources')->drop()->save();
}
}
Loading
Loading