diff --git a/api/config/packages/framework.yaml b/api/config/packages/framework.yaml index 23c913ea2..7be339232 100644 --- a/api/config/packages/framework.yaml +++ b/api/config/packages/framework.yaml @@ -22,6 +22,12 @@ framework: app: cache.adapter.redis system: cache.adapter.redis default_redis_provider: "redis://%env(REDIS_HOST)%:%env(int:REDIS_PORT)%" + + + trusted_hosts: "%env(TRUSTED_HOSTS)%" + trusted_proxies: "%env(TRUSTED_PROXIES)%" + trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix'] + parameters: samesite: none when@test: diff --git a/api/migrations/Version20231219151046.php b/api/migrations/Version20231219151046.php new file mode 100644 index 000000000..464b3d7e2 --- /dev/null +++ b/api/migrations/Version20231219151046.php @@ -0,0 +1,51 @@ +addSql('ALTER TABLE action ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE application ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE collection_entity ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE cronjob ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE endpoint ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE entity ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE gateway ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE mapping ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE organization ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE security_group ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE template ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE "user" ALTER version SET DEFAULT \'0.0.1\''); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE action ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE application ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE collection_entity ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE cronjob ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE endpoint ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE entity ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE gateway ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE mapping ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE organization ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE security_group ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE template ALTER version SET DEFAULT NULL'); + $this->addSql('ALTER TABLE "user" ALTER version SET DEFAULT NULL'); + } +} diff --git a/api/migrations/Version20240109135300.php b/api/migrations/Version20240109135300.php new file mode 100644 index 000000000..b0b86a715 --- /dev/null +++ b/api/migrations/Version20240109135300.php @@ -0,0 +1,63 @@ +addSql('UPDATE action SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE action ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE application SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE application ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE collection_entity SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE collection_entity ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE cronjob SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE cronjob ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE endpoint SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE endpoint ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE entity SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE entity ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE gateway SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE gateway ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE mapping SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE mapping ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE organization SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE organization ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE security_group SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE security_group ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE template SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE template ALTER version SET DEFAULT \'0.0.0\''); + $this->addSql('UPDATE "user" SET version = \'0.0.0\' WHERE version IS NULL'); + $this->addSql('ALTER TABLE "user" ALTER version SET DEFAULT \'0.0.0\''); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE action ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE application ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE collection_entity ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE cronjob ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE endpoint ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE entity ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE gateway ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE mapping ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE organization ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE security_group ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE template ALTER version SET DEFAULT \'0.0.1\''); + $this->addSql('ALTER TABLE "user" ALTER version SET DEFAULT \'0.0.1\''); + } +} diff --git a/api/src/ActionHandler/EmailHandler.php b/api/src/ActionHandler/EmailHandler.php deleted file mode 100644 index f21e338e5..000000000 --- a/api/src/ActionHandler/EmailHandler.php +++ /dev/null @@ -1,109 +0,0 @@ -emailService = $emailService; - } - - /** - * This function returns the requered configuration as a [json-schema](https://json-schema.org/) array. - * - * @throws array a [json-schema](https://json-schema.org/) that this action should comply to - */ - public function getConfiguration(): array - { - return [ - '$id' => 'https://commongateway.nl/ActionHandler/EmailHandler.ActionHandler.json', - '$schema' => 'https://docs.commongateway.nl/schemas/ActionHandler.schema.json', - 'title' => 'EmailHandler', - 'required' => ['ServiceDNS', 'template', 'sender', 'receiver', 'subject'], - 'properties' => [ - 'serviceDNS' => [ - 'type' => 'string', - 'description' => 'The DNS of the mail provider, see https://symfony.com/doc/6.2/mailer.html for details', - 'example' => 'native://default', - 'required' => true, - ], - 'template' => [ - 'type' => 'string', - 'description' => 'The actual email template, should be a base64 encoded twig template', - 'example' => 'eyMgdG9kbzogbW92ZSB0aGlzIHRvIGFuIGVtYWlsIHBsdWdpbiAoc2VlIEVtYWlsU2VydmljZS5waHApICN9CjwhRE9DVFlQRSBodG1sIFBVQkxJQyAiLS8vVzNDLy9EVEQgWEhUTUwgMS4wIFRyYW5zaXRpb25hbC8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9UUi94aHRtbDEvRFREL3hodG1sMS10cmFuc2l0aW9uYWwuZHRkIj4KPGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPgo8aGVhZD4KICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCIgLz4KICA8bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD1VVEYtOCIgLz4KICA8dGl0bGU+e3sgc3ViamVjdCB9fTwvdGl0bGU+CgogIDxsaW5rIHJlbD0icHJlY29ubmVjdCIgaHJlZj0iaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbSIgLz4KICA8bGluawogICAgICAgICAgaHJlZj0iaHR0cHM6Ly9mb250cy5nb29nbGVhcGlzLmNvbS9jc3MyP2ZhbWlseT1GYXVzdGluYTp3Z2h0QDYwMCZkaXNwbGF5PXN3YXAiCiAgICAgICAgICByZWw9InN0eWxlc2hlZXQiCiAgLz4KICA8bGluawogICAgICAgICAgaHJlZj0iaHR0cHM6Ly9mb250cy5nb29nbGVhcGlzLmNvbS9jc3MyP2ZhbWlseT1Tb3VyY2UrU2FucytQcm8mZGlzcGxheT1zd2FwIgogICAgICAgICAgcmVsPSJzdHlsZXNoZWV0IgogIC8+CgogIDxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyIgcmVsPSJzdHlsZXNoZWV0IiBtZWRpYT0iYWxsIj4KICAgIC8qIEJhc2UgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCgogICAgYm9keSB7CiAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7CiAgICAgIGhlaWdodDogMTAwJTsKICAgICAgbWFyZ2luOiAwOwogICAgICBtc28tbGluZS1oZWlnaHQtcnVsZTogZXhhY3RseTsKICAgICAgbGluZS1oZWlnaHQ6IDEuNDsKICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZmZmZjsKICAgICAgY29sb3I6ICM3NDc4N2U7CiAgICAgIC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogbm9uZTsKICAgIH0KCiAgICBwLAogICAgdWwsCiAgICBvbCwKICAgIGJsb2NrcXVvdGUgewogICAgICBtc28tbGluZS1oZWlnaHQtcnVsZTogZXhhY3RseTsKICAgICAgbGluZS1oZWlnaHQ6IDEuNDsKICAgICAgdGV4dC1hbGlnbjogbGVmdDsKICAgIH0KCiAgICBhIHsKICAgICAgY29sb3I6ICMxZDU1ZmY7CiAgICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKICAgIH0KCiAgICBhOmhvdmVyIHsKICAgICAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7CiAgICB9CgogICAgcCBhIHsKICAgICAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7CiAgICB9CgogICAgYSBpbWcgewogICAgICBib3JkZXI6IG5vbmU7CiAgICB9CgogICAgdGQgewogICAgICB3b3JkLWJyZWFrOiBicmVhay13b3JkOwogICAgfQogICAgLyogTGF5b3V0IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqLwoKICAgIC5oZWFkZXIgewogICAgICBiYWNrZ3JvdW5kOiAjMWQ1NWZmOwogICAgICB3aWR0aDogMTAwJTsKICAgICAgaGVpZ2h0OiAyMzZweDsKICAgICAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsKICAgICAgYmFja2dyb3VuZC1wb3NpdGlvbjogY2VudGVyOwogICAgfQoKICAgIC5oZWFkZXItY2VsbCB7CiAgICAgIHBhZGRpbmc6IDE2cHggMjRweDsKICAgIH0KCiAgICAuZW1haWwtd3JhcHBlciB7CiAgICAgIHdpZHRoOiAxMDAlOwogICAgICBtYXJnaW46IDA7CiAgICAgIHBhZGRpbmc6IDA7CiAgICAgIC1wcmVtYWlsZXItd2lkdGg6IDEwMCU7CiAgICAgIC1wcmVtYWlsZXItY2VsbHBhZGRpbmc6IDA7CiAgICAgIC1wcmVtYWlsZXItY2VsbHNwYWNpbmc6IDA7CiAgICAgIGJhY2tncm91bmQtY29sb3I6ICNmZmZmZmY7CiAgICB9CgogICAgLmVtYWlsLWNvbnRlbnQgewogICAgICB3aWR0aDogMTAwJTsKICAgICAgbWFyZ2luOiAwOwogICAgICBwYWRkaW5nOiAwOwogICAgICAtcHJlbWFpbGVyLXdpZHRoOiAxMDAlOwogICAgICAtcHJlbWFpbGVyLWNlbGxwYWRkaW5nOiAwOwogICAgICAtcHJlbWFpbGVyLWNlbGxzcGFjaW5nOiAwOwogICAgfQogICAgLyogTWFzdGhlYWQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi8KCiAgICAuZW1haWwtbWFzdGhlYWQgewogICAgICBwYWRkaW5nOiAyNXB4IDA7CiAgICAgIHRleHQtYWxpZ246IGNlbnRlcjsKICAgIH0KCiAgICAuZW1haWwtbWFzdGhlYWRfbG9nbyB7CiAgICAgIHdpZHRoOiA5NHB4OwogICAgfQoKICAgIC5lbWFpbC1tYXN0aGVhZF9uYW1lIHsKICAgICAgZm9udC1zaXplOiAxNnB4OwogICAgICBmb250LXdlaWdodDogNjAwOwogICAgICBjb2xvcjogI2JiYmZjMzsKICAgICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwogICAgICB0ZXh0LXNoYWRvdzogMCAxcHggMCB3aGl0ZTsKICAgIH0KICAgIC8qIEJvZHkgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCgogICAgLmVtYWlsLWJvZHkgewogICAgICB3aWR0aDogMTAwJTsKICAgICAgbWFyZ2luOiAwOwogICAgICBwYWRkaW5nOiAwOwogICAgICAtcHJlbWFpbGVyLXdpZHRoOiAxMDAlOwogICAgICAtcHJlbWFpbGVyLWNlbGxwYWRkaW5nOiAwOwogICAgICAtcHJlbWFpbGVyLWNlbGxzcGFjaW5nOiAwOwogICAgICBiYWNrZ3JvdW5kOiBub25lOwogICAgfQoKICAgIC5lbWFpbC1ib2R5X2lubmVyIHsKICAgICAgd2lkdGg6IDY0MHB4OwogICAgICBtYXJnaW46IDAgYXV0bzsKICAgICAgcGFkZGluZzogMDsKICAgICAgLXByZW1haWxlci13aWR0aDogNTcwcHg7CiAgICAgIC1wcmVtYWlsZXItY2VsbHBhZGRpbmc6IDA7CiAgICAgIC1wcmVtYWlsZXItY2VsbHNwYWNpbmc6IDA7CiAgICAgIGJhY2tncm91bmQtY29sb3I6ICNmZmZmZmY7CiAgICB9CgogICAgLmVtYWlsLWZvb3RlciB7CiAgICAgIHdpZHRoOiA2NDBweDsKICAgICAgbWFyZ2luOiAwIGF1dG87CiAgICAgIHBhZGRpbmc6IDA7CiAgICAgIC1wcmVtYWlsZXItd2lkdGg6IDU3MHB4OwogICAgICAtcHJlbWFpbGVyLWNlbGxwYWRkaW5nOiAwOwogICAgICAtcHJlbWFpbGVyLWNlbGxzcGFjaW5nOiAwOwogICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgICB9CgogICAgLmVtYWlsLWZvb3RlciBwIHsKICAgICAgY29sb3I6ICNhZWFlYWU7CiAgICB9CgogICAgLmJvZHktYWN0aW9uIHsKICAgICAgd2lkdGg6IDEwMCU7CiAgICAgIG1hcmdpbjogNDBweCBhdXRvOwogICAgICBwYWRkaW5nOiAwOwogICAgICAtcHJlbWFpbGVyLXdpZHRoOiAxMDAlOwogICAgICAtcHJlbWFpbGVyLWNlbGxwYWRkaW5nOiAwOwogICAgICAtcHJlbWFpbGVyLWNlbGxzcGFjaW5nOiAwOwogICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgICB9CgogICAgLmJvZHktc3ViIHsKICAgICAgbWFyZ2luLXRvcDogMjVweDsKICAgICAgcGFkZGluZy10b3A6IDI1cHg7CiAgICAgIGJvcmRlci10b3A6IDFweCBzb2xpZCAjZWRlZmYyOwogICAgfQoKICAgIC5jb250ZW50LWNlbGwgewogICAgICBwYWRkaW5nOiAzNnB4IDE2cHg7CiAgICB9CgogICAgLnByZWhlYWRlciB7CiAgICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDsKICAgICAgdmlzaWJpbGl0eTogaGlkZGVuOwogICAgICBtc28taGlkZTogYWxsOwogICAgICBmb250LXNpemU6IDFweDsKICAgICAgbXNvLWxpbmUtaGVpZ2h0LXJ1bGU6IGV4YWN0bHk7CiAgICAgIGxpbmUtaGVpZ2h0OiAxcHg7CiAgICAgIG1heC1oZWlnaHQ6IDA7CiAgICAgIG1heC13aWR0aDogMDsKICAgICAgb3BhY2l0eTogMDsKICAgICAgb3ZlcmZsb3c6IGhpZGRlbjsKICAgIH0KICAgIC8qIEF0dHJpYnV0ZSBsaXN0IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqLwoKICAgIC5hdHRyaWJ1dGVzIHsKICAgICAgbWFyZ2luOiAwIDAgMjFweDsKICAgIH0KCiAgICAuYXR0cmlidXRlc19jb250ZW50IHsKICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2VkZWZmMjsKICAgICAgcGFkZGluZzogMTZweDsKICAgIH0KCiAgICAuYXR0cmlidXRlc19pdGVtIHsKICAgICAgcGFkZGluZzogMDsKICAgIH0KICAgIC8qIFJlbGF0ZWQgSXRlbXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCgogICAgLnJlbGF0ZWQgewogICAgICB3aWR0aDogMTAwJTsKICAgICAgbWFyZ2luOiAwOwogICAgICBwYWRkaW5nOiAyNXB4IDAgMCAwOwogICAgICAtcHJlbWFpbGVyLXdpZHRoOiAxMDAlOwogICAgICAtcHJlbWFpbGVyLWNlbGxwYWRkaW5nOiAwOwogICAgICAtcHJlbWFpbGVyLWNlbGxzcGFjaW5nOiAwOwogICAgfQoKICAgIC5yZWxhdGVkX2l0ZW0gewogICAgICBwYWRkaW5nOiAxMHB4IDA7CiAgICAgIGNvbG9yOiAjNzQ3ODdlOwogICAgICBmb250LXNpemU6IDE1cHg7CiAgICAgIG1zby1saW5lLWhlaWdodC1ydWxlOiBleGFjdGx5OwogICAgICBsaW5lLWhlaWdodDogMThweDsKICAgIH0KCiAgICAucmVsYXRlZF9pdGVtLXRpdGxlIHsKICAgICAgZGlzcGxheTogYmxvY2s7CiAgICAgIG1hcmdpbjogMC41ZW0gMCAwOwogICAgfQoKICAgIC5yZWxhdGVkX2l0ZW0tdGh1bWIgewogICAgICBkaXNwbGF5OiBibG9jazsKICAgICAgcGFkZGluZy1ib3R0b206IDEwcHg7CiAgICB9CgogICAgLnJlbGF0ZWRfaGVhZGluZyB7CiAgICAgIGJvcmRlci10b3A6IDFweCBzb2xpZCAjZWRlZmYyOwogICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgICAgIHBhZGRpbmc6IDI1cHggMCAxMHB4OwogICAgfQoKICAgIC8qIFV0aWxpdGllcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi8KCiAgICAubm8tbWFyZ2luIHsKICAgICAgbWFyZ2luOiAwOwogICAgfQoKICAgIC5tYXJnaW4tdG9wIHsKICAgICAgbWFyZ2luLXRvcDogOHB4OwogICAgfQoKICAgIC5hbGlnbi1yaWdodCB7CiAgICAgIHRleHQtYWxpZ246IHJpZ2h0OwogICAgfQoKICAgIC5hbGlnbi1sZWZ0IHsKICAgICAgdGV4dC1hbGlnbjogbGVmdDsKICAgIH0KCiAgICAuYWxpZ24tY2VudGVyIHsKICAgICAgdGV4dC1hbGlnbjogY2VudGVyOwogICAgfQogICAgLypNZWRpYSBRdWVyaWVzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqLwoKICAgIEBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDogNjAwcHgpIHsKICAgICAgLmVtYWlsLWJvZHlfaW5uZXIsCiAgICAgIC5lbWFpbC1mb290ZXIgewogICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7CiAgICAgIH0KICAgIH0KCiAgICBAbWVkaWEgb25seSBzY3JlZW4gYW5kIChtYXgtd2lkdGg6IDUwMHB4KSB7CiAgICAgIC5idXR0b24gewogICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7CiAgICAgIH0KICAgIH0KCiAgICAvKiBDYXJkcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi8KICAgIC5jYXJkIHsKICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZjsKICAgICAgYm9yZGVyLXRvcDogMXB4IHNvbGlkICNlMGUxZTU7CiAgICAgIGJvcmRlci1yaWdodDogMXB4IHNvbGlkICNlMGUxZTU7CiAgICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjZTBlMWU1OwogICAgICBib3JkZXItbGVmdDogMXB4IHNvbGlkICNlMGUxZTU7CiAgICAgIHBhZGRpbmc6IDI0cHg7CiAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jazsKICAgICAgY29sb3I6ICMzOTM5M2E7CiAgICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKICAgICAgd2lkdGg6IDEwMCU7CiAgICAgIGJvcmRlci1yYWRpdXM6IDNweDsKICAgICAgYm94LXNoYWRvdzogMCA0cHggM3B4IC0zcHggcmdiYSgwLCAwLCAwLCAwLjA4KTsKICAgICAgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiBub25lOwogICAgICBtc28tbGluZS1oZWlnaHQtcnVsZTogZXhhY3RseTsKICAgICAgbGluZS1oZWlnaHQ6IDEuNzU7CiAgICAgIGxldHRlci1zcGFjaW5nOiAwLjhweDsKICAgIH0KCiAgICAvKiBCdXR0b25zIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqLwoKICAgIC5idXR0b24gewogICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMWRiNGVkOwogICAgICBib3JkZXItdG9wOiAxMHB4IHNvbGlkICMxZGI0ZWQ7CiAgICAgIGJvcmRlci1yaWdodDogMThweCBzb2xpZCAjMWRiNGVkOwogICAgICBib3JkZXItYm90dG9tOiAxMHB4IHNvbGlkICMxZGI0ZWQ7CiAgICAgIGJvcmRlci1sZWZ0OiAxOHB4IHNvbGlkICMxZGI0ZWQ7CiAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jazsKICAgICAgY29sb3I6ICNmZmY7CiAgICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKICAgICAgYm9yZGVyLXJhZGl1czogNHB4OwogICAgICBib3gtc2hhZG93OiAwIDJweCAzcHggcmdiYSgwLCAwLCAwLCAwLjE2KTsKICAgICAgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiBub25lOwogICAgICBtc28tbGluZS1oZWlnaHQtcnVsZTogZXhhY3RseTsKICAgICAgd2lkdGg6IDEwMCU7CiAgICAgIHRleHQtYWxpZ246IGNlbnRlcjsKICAgICAgZm9udC1zaXplOiAxNHB4OwogICAgICBmb250LXdlaWdodDogNjAwOwogICAgfQoKICAgIC5zbWFsbC1sb2dvIHsKICAgICAgd2lkdGg6IDI0cHg7CiAgICAgIGhlaWdodDogMjRweDsKICAgIH0KCiAgICAuaW5saW5lIHsKICAgICAgZGlzcGxheTogaW5saW5lOwogICAgfQogICAgLyogVHlwZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi8KCiAgICBwIHsKICAgICAgbWFyZ2luOiAwOwogICAgICBjb2xvcjogIzM5MzkzYTsKICAgICAgZm9udC1zaXplOiAxNXB4OwogICAgICBtc28tbGluZS1oZWlnaHQtcnVsZTogZXhhY3RseTsKICAgICAgbGV0dGVyLXNwYWNpbmc6IG5vcm1hbDsKICAgICAgdGV4dC1hbGlnbjogbGVmdDsKICAgICAgbGluZS1oZWlnaHQ6IDIwcHg7CiAgICB9CgogICAgcCArIHAgewogICAgICBtYXJnaW4tdG9wOiAyMHB4OwogICAgfQoKICAgIHAuc3VmZml4IHsKICAgICAgZm9udC1zaXplOiAxNHB4OwogICAgfQoKICAgIHAuc3ViIHsKICAgICAgZm9udC1zaXplOiAxMnB4OwogICAgfQoKICAgIHAuY2VudGVyIHsKICAgICAgdGV4dC1hbGlnbjogY2VudGVyOwogICAgfQoKICAgIC5zdWJ0bGUgewogICAgICBjb2xvcjogI2IxYjFiMTsKICAgIH0KCiAgICAvKiBGb290ZXIgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCgogICAgLmxvZ28tbGFiZWwgewogICAgICB2ZXJ0aWNhbC1hbGlnbjogdG9wOwogICAgICBmb250LXNpemU6IDE0cHg7CiAgICAgIG1hcmdpbi1sZWZ0OiA0cHg7CiAgICB9CgogICAgLmZvb3Rlci1jZWxsIHsKICAgICAgcGFkZGluZzogOHB4IDI0cHg7CiAgICB9CgogICAgLmZvb3Rlci1uYXYgewogICAgICBtYXJnaW4tbGVmdDogOHB4OwogICAgICBmb250LXNpemU6IDE0cHg7CiAgICAgIGNvbG9yOiAjMzkzOTNhOwogICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7CiAgICB9CgogICAgLmhlYWRlci1saW5rIHsKICAgICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwogICAgICBmb250LXNpemU6IDE0cHg7CiAgICAgIGNvbG9yOiAjMWQ1NWZmOwogICAgICBmb250LXdlaWdodDogNTAwOwogICAgfQoKICAgIC5tYXJnaW4tdG9wIHsKICAgICAgbWFyZ2luLXRvcDogMTZweDsKICAgIH0KCiAgICAubG9nby1jb250YWluZXIgewogICAgICB3aWR0aDogMTAwJTsKICAgICAgbWFyZ2luLWJvdHRvbTogNTZweDsKICAgIH0KCiAgICAubG9nbyB7CiAgICAgIGRpc3BsYXk6IGJsb2NrOwogICAgfQoKICAgIC8qIEN1c3RvbSBzdHlsZXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovCiAgICBociB7CiAgICAgIGJvcmRlci10b3A6IDFweCBzb2xpZCAjZDlkOWRlOwogICAgICBjb2xvcjogI2Q5ZDlkZTsKICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2Q5ZDlkZTsKICAgICAgbWFyZ2luLXRvcDogMzJweDsKICAgICAgbWFyZ2luLWJvdHRvbTogNDBweDsKICAgIH0KCiAgICBoMSB7CiAgICAgIGZvbnQtZmFtaWx5OiAiRmF1c3RpbmEiLCBzZXJpZjsKICAgICAgZm9udC1zaXplOiAzMnB4OwogICAgICBmb250LXdlaWdodDogNjAwOwogICAgICBjb2xvcjogIzIzMjMyNjsKICAgICAgbWFyZ2luLWJvdHRvbTogMjJweDsKICAgIH0KCiAgICBwIHsKICAgICAgZm9udC1mYW1pbHk6ICJTb3VyY2UgU2FucyBQcm8iLCBzYW5zLXNlcmlmOwogICAgICBmb250LXNpemU6IDE4cHg7CiAgICAgIGxpbmUtaGVpZ2h0OiAxLjY7CiAgICAgIGNvbG9yOiAjMjMyMzI2OwogICAgfQoKICAgIC5idXR0b24gewogICAgICBmb250LWZhbWlseTogIlNvdXJjZSBTYW5zIFBybyIsIHNhbnMtc2VyaWY7CiAgICB9CgogICAgLmNvbnRlbnQtY2VsbCB7CiAgICAgIHBhZGRpbmc6IDQwcHggNDBweDsKICAgIH0KCiAgICAuYnV0dG9uIHsKICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2ZmNWEyNjsKICAgICAgYm9yZGVyLXRvcDogMTBweCBzb2xpZCAjZmY1YTI2OwogICAgICBib3JkZXItcmlnaHQ6IDE4cHggc29saWQgI2ZmNWEyNjsKICAgICAgYm9yZGVyLWJvdHRvbTogMTBweCBzb2xpZCAjZmY1YTI2OwogICAgICBib3JkZXItbGVmdDogMThweCBzb2xpZCAjZmY1YTI2OwogICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7CiAgICAgIGNvbG9yOiAjZmZmOwogICAgICB3aWR0aDogYXV0bzsKICAgICAgYm94LXNoYWRvdzogbm9uZTsKICAgICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwogICAgICBib3JkZXItcmFkaXVzOiA4cHg7CiAgICAgIC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogbm9uZTsKICAgICAgbXNvLWxpbmUtaGVpZ2h0LXJ1bGU6IGV4YWN0bHk7CiAgICAgIHRleHQtYWxpZ246IGNlbnRlcjsKICAgICAgZm9udC1zaXplOiAxNHB4OwogICAgICBmb250LXdlaWdodDogNjAwOwogICAgfQogIDwvc3R5bGU+CjwvaGVhZD4KPGJvZHk+Cjx0YWJsZSBjbGFzcz0iZW1haWwtd3JhcHBlciIgd2lkdGg9IjEwMCUiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+CiAgPHRyPgogICAgPHRkIGFsaWduPSJjZW50ZXIiPgogICAgICA8dGFibGUKICAgICAgICAgICAgICBjbGFzcz0iZW1haWwtY29udGVudCIKICAgICAgICAgICAgICB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICBjZWxscGFkZGluZz0iMCIKICAgICAgICAgICAgICBjZWxsc3BhY2luZz0iMCIKICAgICAgPgogICAgICAgIDx0cj4KICAgICAgICAgIDx0ZCBjbGFzcz0iZW1haWwtbWFzdGhlYWQiPjwvdGQ+CiAgICAgICAgPC90cj4KICAgICAgICA8IS0tIEVtYWlsIEJvZHkgLS0+CiAgICAgICAgPHRyPgogICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgIGNsYXNzPSJlbWFpbC1ib2R5IgogICAgICAgICAgICAgICAgICB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgY2VsbHBhZGRpbmc9IjAiCiAgICAgICAgICAgICAgICAgIGNlbGxzcGFjaW5nPSIwIgogICAgICAgICAgPgogICAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgICBjbGFzcz0iZW1haWwtYm9keV9pbm5lciIKICAgICAgICAgICAgICAgICAgICBhbGlnbj0iY2VudGVyIgogICAgICAgICAgICAgICAgICAgIHdpZHRoPSIxMDAlIgogICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I9IiNlZGVmZjIiCiAgICAgICAgICAgICAgICAgICAgY2VsbHBhZGRpbmc9IjAiCiAgICAgICAgICAgICAgICAgICAgY2VsbHNwYWNpbmc9IjAiCiAgICAgICAgICAgID4KICAgICAgICAgICAgICA8IS0tIEJvZHkgY29udGVudCAtLT4KICAgICAgICAgICAgICA8dHI+PC90cj4KICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9ImNvbnRlbnQtY2VsbCIgd2lkdGg9IjEwMCUiPgogICAgICAgICAgICAgICAgICA8cD4KICAgICAgICAgICAgICAgICAgICAgIHt7IGF1dGhvciB9fSBoZWVmdCBmZWVkYmFjayBnZWdldmVuIG9wOiB7eyB0b3BpYyB9fQogICAgICAgICAgICAgICAgICA8L3A+CiAgICAgICAgICAgICAgICAgIDxici8+CiAgICAgICAgICAgICAgICAgIDxwPgogICAgICAgICAgICAgICAgICAgICAge3sgZGVzY3JpcHRpb24gfCBubDJiciB9fQogICAgICAgICAgICAgICAgICA8L3A+CiAgICAgICAgICAgICAgICAgIDxociAvPgogICAgICAgICAgICAgICAgICA8cD5NZXQgdnJpZW5kZWxpamtlIGdyb2V0LDwvcD4KICAgICAgICAgICAgICAgICAgPHA+S0lTUzwvcD4KICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICA8dHI+PC90cj4KICAgICAgICAgICAgPC90YWJsZT4KICAgICAgICAgIDwvdGQ+CiAgICAgICAgPC90cj4KICAgICAgPC90YWJsZT4KICAgIDwvdGQ+CiAgPC90cj4KPC90YWJsZT4KPC9ib2R5Pgo8L2h0bWw+Cg==', - 'required' => true, - ], - 'variables' => [ - 'type' => 'array', - 'description' => 'The variables supported by this template (might contain default vallues)', - 'nullable' => true, - ], - 'sender' => [ - 'type' => 'string', - 'description' => 'The sender of the email', - 'example' => 'info@conduction.nl', - 'required' => true, - ], - 'receiver' => [ - 'type' => 'string', - 'description' => 'The receiver of the email', - 'example' => 'j.do@conduction.nl', - 'required' => true, - ], - 'subject' => [ - 'type' => 'string', - 'description' => 'The subject of the email', - 'example' => 'Your weekly update', - 'required' => true, - ], - 'cc' => [ - 'type' => 'string', - 'description' => 'Carbon copy, email boxes that should receive a copy of this mail', - 'example' => 'archive@conduction.nl', - 'nullable' => true, - ], - 'bcc' => [ - 'type' => 'string', - 'description' => 'Blind carbon copy, people that should receive a copy without other recipient knowing', - 'example' => 'b.brother@conduction.nl', - 'nullable' => true, - ], - 'replyTo' => [ - 'type' => 'string', - 'description' => 'The address the receiver should reply to, only provide this if it differs from the sender address', - 'example' => 'no-reply@conduction.nl', - 'nullable' => true, - ], - 'priority' => [ - 'type' => 'int', - 'description' => 'An optional priority for the email', - 'nullable' => true, - ], - ], - ]; - } - - /** - * This function runs the email service plugin. - * - * @param array $data The data from the call - * @param array $configuration The configuration of the action - * - * @throws TransportExceptionInterface|LoaderError|RuntimeError|SyntaxError - * - * @return array - */ - public function run(array $data, array $configuration): array - { - return $this->emailService->emailHandler($data, $configuration); - } -} diff --git a/api/src/Command/InitializationCommand.php b/api/src/Command/InitializationCommand.php index 6d4ac71ba..71707915a 100644 --- a/api/src/Command/InitializationCommand.php +++ b/api/src/Command/InitializationCommand.php @@ -91,7 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $config['unsafe'] = $input->getOption('unsafe'); // Throw the event - $io->info('Trowing commongateway.pre.initialization event'); + $io->info('Throwing commongateway.pre.initialization event'); $event = new ActionEvent('commongateway.pre.initialization', []); $this->eventDispatcher->dispatch($event, 'commongateway.pre.initialization'); @@ -249,7 +249,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int // Handling users $io->section('Looking for an user'); if (!$user = $this->entityManager->getRepository('App:User')->findOneBy([])) { - $io->info('No User found, creating a new one'); + $io->info('No User found, creating a default and APIKEY one'); + $user = new User(); $user->setName('Default User'); $user->setReference('https://docs.commongateway.nl/user/default.user.json'); @@ -261,6 +262,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int $user->setOrganization($organization); $this->entityManager->persist($user); + + $apikeyUser = new User(); + $apikeyUser->setName('APIKEY_USER'); + $apikeyUser->setReference('https://docs.commongateway.nl/user/default.apikey.user.json'); + $apikeyUser->setDescription('Created during auto configuration'); + $apikeyUser->setEmail('apikey@test.com'); + $apikeyUser->setPassword($this->hasher->hashPassword($apikeyUser, '!ChangeMe!')); + $apikeyUser->addSecurityGroup($securityGroupAdmin); + $apikeyUser->addApplication($application); + $apikeyUser->setOrganization($organization); + + $this->entityManager->persist($apikeyUser); } else { $io->info('User found, continuing....'); } @@ -280,7 +293,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io->success('Successfully finished setting basic configuration'); // todo: actualy throw it - $io->info('Trowing commongateway.post.initialization event'); + $io->info('Throwing commongateway.post.initialization event'); // Throw the event $event = new ActionEvent('commongateway.post.initialization', []); diff --git a/api/src/Controller/ConvenienceController.php b/api/src/Controller/ConvenienceController.php index 32f7f46c6..f4d642310 100755 --- a/api/src/Controller/ConvenienceController.php +++ b/api/src/Controller/ConvenienceController.php @@ -40,7 +40,6 @@ class ConvenienceController extends AbstractController private ActionSubscriber $actionSubscriber; private ObjectEntityService $objectEntityService; private MappingService $mappingService; - private Environment $twig; public function __construct( EntityManagerInterface $entityManager, @@ -50,7 +49,7 @@ public function __construct( HandlerService $handlerService, ActionSubscriber $actionSubscriber, ObjectEntityService $objectEntityService, - Environment $twig + MappingService $mappingService ) { $this->entityManager = $entityManager; $this->serializer = $serializer; @@ -60,8 +59,7 @@ public function __construct( $this->handlerService = $handlerService; $this->actionSubscriber = $actionSubscriber; $this->objectEntityService = $objectEntityService; - $this->twig = $twig; - $this->mappingService = new MappingService($twig); + $this->mappingService = $mappingService; } /** diff --git a/api/src/Entity/Action.php b/api/src/Entity/Action.php index 17c9e6cb4..64f8c0a41 100644 --- a/api/src/Entity/Action.php +++ b/api/src/Entity/Action.php @@ -15,6 +15,7 @@ use Gedmo\Mapping\Annotation as Gedmo; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -32,7 +33,7 @@ * collectionOperations={ * "get"={"path"="/admin/actions"}, * "post"={"path"="/admin/actions"} - * }) + * } * ) * * @ORM\HasLifecycleCallbacks @@ -48,6 +49,8 @@ * "name": "exact", * "reference": "exact" * }) + * + * @UniqueEntity("reference") */ class Action { @@ -73,16 +76,20 @@ class Action /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true) */ - private $reference; + private ?string $reference; /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private $version; + private string $version = '0.0.0'; /** * @var string The name of the action diff --git a/api/src/Entity/ActionHandler.php b/api/src/Entity/ActionHandler.php index 7c531ba14..50d3a301e 100644 --- a/api/src/Entity/ActionHandler.php +++ b/api/src/Entity/ActionHandler.php @@ -28,7 +28,7 @@ * collectionOperations={ * "get"={"path"="/admin/actionHandlers"}, * "post"={"path"="/admin/actionHandlers"} - * }) + * } * ) * * @ORM\Entity(repositoryClass=ActionHandlerRepository::class) diff --git a/api/src/Entity/Application.php b/api/src/Entity/Application.php index 2afb2f2fd..3d3a52989 100644 --- a/api/src/Entity/Application.php +++ b/api/src/Entity/Application.php @@ -16,6 +16,7 @@ use Gedmo\Mapping\Annotation as Gedmo; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\MaxDepth; use Symfony\Component\Validator\Constraints as Assert; @@ -34,7 +35,7 @@ * collectionOperations={ * "get"={"path"="/admin/applications"}, * "post"={"path"="/admin/applications"} - * }) + * } * ) * * @ORM\HasLifecycleCallbacks @@ -50,6 +51,8 @@ * "name": "exact", * "reference": "exact" * }) + * + * @UniqueEntity("reference") */ class Application { @@ -101,6 +104,8 @@ class Application /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) */ private ?string $reference = null; @@ -108,9 +113,11 @@ class Application /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * The hosts that this applications uses, keep in ind that a host is exluding a trailing slach / and https:// ot http://. diff --git a/api/src/Entity/Attribute.php b/api/src/Entity/Attribute.php index 1bcd2d559..8d899ac4d 100644 --- a/api/src/Entity/Attribute.php +++ b/api/src/Entity/Attribute.php @@ -24,7 +24,7 @@ use Symfony\Component\Validator\Constraints as Assert; /** - * An possible attribute on an Entity. + * A possible attribute on an Entity. * * @category Entity * @@ -39,7 +39,8 @@ * collectionOperations={ * "get"={"path"="/admin/attributes"}, * "post"={"path"="/admin/attributes"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass=AttributeRepository::class) * diff --git a/api/src/Entity/AuditTrail.php b/api/src/Entity/AuditTrail.php index 17e0f1517..313136ae5 100644 --- a/api/src/Entity/AuditTrail.php +++ b/api/src/Entity/AuditTrail.php @@ -33,7 +33,8 @@ * "get"={"path"="/admin/audit_trails"}, * "post"={"path"="/admin/audit_trails"} * }, - * attributes={"order"={"creationDate": "DESC"}}) + * attributes={"order"={"creationDate": "DESC"}} + * ) * * @ORM\Entity(repositoryClass=AuditTrailRepository::class) * diff --git a/api/src/Entity/CollectionEntity.php b/api/src/Entity/CollectionEntity.php index 97823f723..c34e1a7eb 100644 --- a/api/src/Entity/CollectionEntity.php +++ b/api/src/Entity/CollectionEntity.php @@ -36,7 +36,8 @@ * collectionOperations={ * "get"={"path"="/admin/collections"}, * "post"={"path"="/admin/collections"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass=CollectionEntityRepository::class) * @@ -51,6 +52,7 @@ * }) * * @UniqueEntity("name") + * @UniqueEntity("reference") */ class CollectionEntity { @@ -100,6 +102,8 @@ class CollectionEntity /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) */ private ?string $reference = null; @@ -107,9 +111,11 @@ class CollectionEntity /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * @var ?string The location where the OAS can be loaded from diff --git a/api/src/Entity/Contract.php b/api/src/Entity/Contract.php index 5184262c4..f32d81283 100644 --- a/api/src/Entity/Contract.php +++ b/api/src/Entity/Contract.php @@ -33,7 +33,8 @@ * collectionOperations={ * "get"={"path"="/admin/contracts"}, * "post"={"path"="/admin/contracts"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass=ContractRepository::class) * diff --git a/api/src/Entity/Cronjob.php b/api/src/Entity/Cronjob.php index 862ba6b03..cc220c227 100644 --- a/api/src/Entity/Cronjob.php +++ b/api/src/Entity/Cronjob.php @@ -13,6 +13,7 @@ use Doctrine\ORM\Mapping as ORM; use Gedmo\Mapping\Annotation as Gedmo; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -30,7 +31,8 @@ * collectionOperations={ * "get"={"path"="/admin/cronjobs"}, * "post"={"path"="/admin/cronjobs"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass=CronjobRepository::class) * @@ -43,6 +45,8 @@ * "name": "exact", * "reference": "exact" * }) + * + * @UniqueEntity("reference") */ class Cronjob { @@ -94,6 +98,8 @@ class Cronjob /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) */ private ?string $reference = null; @@ -101,9 +107,11 @@ class Cronjob /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * @var string The crontab that determines the interval https://crontab.guru/ diff --git a/api/src/Entity/DashboardCard.php b/api/src/Entity/DashboardCard.php index 777cb6c4e..8e78148ce 100644 --- a/api/src/Entity/DashboardCard.php +++ b/api/src/Entity/DashboardCard.php @@ -27,7 +27,8 @@ * collectionOperations={ * "get"={"path"="/admin/dashboardCards"}, * "post"={"path"="/admin/dashboardCards"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass=DashboardCardRepository::class) * diff --git a/api/src/Entity/Endpoint.php b/api/src/Entity/Endpoint.php index 567c865c4..1eb7c2772 100644 --- a/api/src/Entity/Endpoint.php +++ b/api/src/Entity/Endpoint.php @@ -18,6 +18,7 @@ use Gedmo\Mapping\Annotation as Gedmo; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\MaxDepth; use Symfony\Component\Validator\Constraints as Assert; @@ -36,7 +37,8 @@ * collectionOperations={ * "get"={"path"="/admin/endpoints"}, * "post"={"path"="/admin/endpoints"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass="App\Repository\EndpointRepository") * @@ -57,6 +59,8 @@ * "entities", * "proxy" * }) + * + * @UniqueEntity("reference") */ class Endpoint { @@ -321,6 +325,8 @@ class Endpoint /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true) */ private ?string $reference = null; @@ -328,9 +334,11 @@ class Endpoint /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * Constructor for creating an Endpoint. Use $entity to create an Endpoint for an Entity or diff --git a/api/src/Entity/Entity.php b/api/src/Entity/Entity.php index a3091daed..2185064a3 100644 --- a/api/src/Entity/Entity.php +++ b/api/src/Entity/Entity.php @@ -19,6 +19,7 @@ use Gedmo\Mapping\Annotation as Gedmo; use phpDocumentor\Reflection\Types\This; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\MaxDepth; use Symfony\Component\Validator\Constraints as Assert; @@ -50,7 +51,8 @@ * "description"="Deletes all objects that belong to this schema" * } * }, - * }) + * } + * ) * * @ORM\Entity(repositoryClass="App\Repository\EntityRepository") * @@ -63,6 +65,8 @@ * "name": "exact", * "reference": "exact" * }) + * + * @UniqueEntity("reference") */ class Entity { @@ -411,6 +415,8 @@ class Entity /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) */ private ?string $reference = null; @@ -418,9 +424,11 @@ class Entity /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; //todo: do we want read/write groups here? /** diff --git a/api/src/Entity/Gateway.php b/api/src/Entity/Gateway.php index 9ff175dff..e3251a52c 100644 --- a/api/src/Entity/Gateway.php +++ b/api/src/Entity/Gateway.php @@ -149,6 +149,7 @@ * }) * * @UniqueEntity("name") + * @UniqueEntity("reference") */ class Gateway { @@ -216,6 +217,8 @@ class Gateway /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) */ private ?string $reference = null; @@ -223,9 +226,11 @@ class Gateway /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * @var string The location where the Gateway needs to be accessed @@ -559,8 +564,7 @@ class Gateway private ?string $documentation = null; /** - * Configuration for logging, when an api call is made on the source we can log some information for this call. - * With this array you can enable/disable what will be logged. + * @var array Configuration for logging, when an api call is made on the source we can log some information for this call. With this array you can enable/disable what will be logged. * * @Assert\NotNull * @@ -633,7 +637,9 @@ class Gateway * * @ORM\Column(type="array", nullable=true) */ - private ?array $configuration = []; + private ?array $configuration = [ + "verify" => true + ]; /** * @var array|null The configuration for endpoints on this source, mostly mapping for now. @@ -812,7 +818,12 @@ public function fromSchema(array $schema): self array_key_exists('headers', $schema) ? $this->setHeaders($schema['headers']) : ''; array_key_exists('translationConfig', $schema) ? $this->setTranslationConfig($schema['translationConfig']) : ''; array_key_exists('type', $schema) ? $this->setType($schema['type']) : ''; - array_key_exists('configuration', $schema) ? $this->setConfiguration($schema['configuration']) : ''; + if (isset($schema['configuration']) === true) { + if (isset($schema['configuration']['verify']) === false) { + $schema['configuration']['verify'] = true; + } + $this->setConfiguration($schema['configuration']); + } array_key_exists('endpointsConfig', $schema) ? $this->setEndpointsConfig($schema['endpointsConfig']) : ''; array_key_exists('isEnabled', $schema) ? $this->setIsEnabled($schema['isEnabled']) : ''; diff --git a/api/src/Entity/Mapping.php b/api/src/Entity/Mapping.php index 6187d7fd4..5e7a2a952 100644 --- a/api/src/Entity/Mapping.php +++ b/api/src/Entity/Mapping.php @@ -15,6 +15,7 @@ use Doctrine\ORM\Mapping as ORM; use Gedmo\Mapping\Annotation as Gedmo; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -30,7 +31,7 @@ * collectionOperations={ * "get"={"path"="/admin/mappings"}, * "post"={"path"="/admin/mappings"} - * }) + * } * ) * * @ORM\Entity(repositoryClass=MappingRepository::class) @@ -44,6 +45,8 @@ * "name": "exact", * "reference": "exact" * }) + * + * @UniqueEntity("reference") */ class Mapping { @@ -69,6 +72,8 @@ class Mapping /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) */ private ?string $reference = null; @@ -76,9 +81,11 @@ class Mapping /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * @var string The name of the mapping diff --git a/api/src/Entity/ObjectEntity.php b/api/src/Entity/ObjectEntity.php index fb6eb4e43..8f9095279 100644 --- a/api/src/Entity/ObjectEntity.php +++ b/api/src/Entity/ObjectEntity.php @@ -19,7 +19,7 @@ use function Symfony\Component\Translation\t; /** - * An (data) object that resides within the datalayer of the gateway. + * A (data) object that resides within the datalayer of the gateway. * * @category Entity * @@ -1184,6 +1184,12 @@ public function toArray(array $configuration = []): array $config['maxDepth'] = $attribute->getObject()->getMaxDepth() + $config['level']; } $config['level'] = $config['level'] + 1; + + //TODO: This is a very hacky solution that has to be changed back ASAP + if ($attribute->getObject() === $this->getEntity()) { + $config['maxDepth'] = $config['level']; + } + $objectToArray = $object->toArray($config); // Check if we want an embedded array @@ -1251,6 +1257,11 @@ public function toArray(array $configuration = []): array $config['maxDepth'] = $attribute->getObject()->getMaxDepth() + $config['level']; } $config['level'] = $config['level'] + 1; + + //TODO: This is a very hacky solution that has to be changed back ASAP + if ($attribute->getObject() === $this->getEntity()) { + $config['maxDepth'] = $config['level']; + } $objectToArray = $object->toArray($config); // Check if we want an embedded array diff --git a/api/src/Entity/Organization.php b/api/src/Entity/Organization.php index cd231688b..7043caac4 100644 --- a/api/src/Entity/Organization.php +++ b/api/src/Entity/Organization.php @@ -16,6 +16,7 @@ use Gedmo\Mapping\Annotation as Gedmo; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\MaxDepth; use Symfony\Component\Validator\Constraints as Assert; @@ -34,7 +35,8 @@ * collectionOperations={ * "get"={"path"="/admin/organizations"}, * "post"={"path"="/admin/organizations"} - * }) + * } + * ) * * @ORM\HasLifecycleCallbacks * @@ -49,6 +51,8 @@ * "name": "exact", * "reference": "exact" * }) + * + * @UniqueEntity("reference") */ class Organization { @@ -100,6 +104,8 @@ class Organization /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) */ private ?string $reference = null; @@ -107,9 +113,11 @@ class Organization /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * @Groups({"read", "write"}) diff --git a/api/src/Entity/Property.php b/api/src/Entity/Property.php index f50b8da07..eaeadb576 100644 --- a/api/src/Entity/Property.php +++ b/api/src/Entity/Property.php @@ -28,7 +28,7 @@ * collectionOperations={ * "get"={"path"="/admin/properties"}, * "post"={"path"="/admin/properties"} - * }) + * } * ) * * @ORM\Entity(repositoryClass=PropertyRepository::class) diff --git a/api/src/Entity/Purpose.php b/api/src/Entity/Purpose.php index 23c26c033..71af172b7 100644 --- a/api/src/Entity/Purpose.php +++ b/api/src/Entity/Purpose.php @@ -28,7 +28,8 @@ * collectionOperations={ * "get"={"path"="/admin/purposes"}, * "post"={"path"="/admin/purposes"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass=PurposeRepository::class) * diff --git a/api/src/Entity/SecurityGroup.php b/api/src/Entity/SecurityGroup.php index ded4d2b26..0203a7cab 100644 --- a/api/src/Entity/SecurityGroup.php +++ b/api/src/Entity/SecurityGroup.php @@ -16,6 +16,7 @@ use Gedmo\Mapping\Annotation as Gedmo; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\MaxDepth; use Symfony\Component\Validator\Constraints as Assert; @@ -34,7 +35,7 @@ * collectionOperations={ * "get"={"path"="/admin/user_groups"}, * "post"={"path"="/admin/user_groups"} - * }) + * } * ) * * @ORM\HasLifecycleCallbacks @@ -50,6 +51,8 @@ * "name": "exact", * "reference": "exact" * }) + * + * @UniqueEntity("reference") */ class SecurityGroup { @@ -101,6 +104,8 @@ class SecurityGroup /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) */ private ?string $reference = null; @@ -108,9 +113,11 @@ class SecurityGroup /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * @Groups({"read", "write"}) diff --git a/api/src/Entity/Synchronization.php b/api/src/Entity/Synchronization.php index 678594050..6fc019997 100644 --- a/api/src/Entity/Synchronization.php +++ b/api/src/Entity/Synchronization.php @@ -32,7 +32,8 @@ * collectionOperations={ * "get"={"path"="/admin/synchronizations"}, * "post"={"path"="/admin/synchronizations"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass=SynchronizationRepository::class) * diff --git a/api/src/Entity/Template.php b/api/src/Entity/Template.php index a400d7a1a..4fa1edd19 100644 --- a/api/src/Entity/Template.php +++ b/api/src/Entity/Template.php @@ -13,6 +13,7 @@ use Doctrine\ORM\Mapping as ORM; use Gedmo\Mapping\Annotation as Gedmo; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -30,7 +31,8 @@ * collectionOperations={ * "get"={"path"="/admin/templates"}, * "post"={"path"="/admin/templates"} - * })) + * } + * ) * * @ORM\Entity(repositoryClass=TemplateRepository::class) * @@ -41,8 +43,11 @@ * @ApiFilter(DateFilter::class, strategy=DateFilter::EXCLUDE_NULL) * @ApiFilter(SearchFilter::class, properties={ * "supportedSchemas": "exact", - * "name": "exact" + * "name": "exact", + * "reference": "exact" * }) + * + * @UniqueEntity("reference") */ class Template { @@ -127,6 +132,8 @@ class Template /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true) */ private ?string $reference = null; @@ -134,9 +141,11 @@ class Template /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * @var Datetime|null The moment this resource was created diff --git a/api/src/Entity/Translation.php b/api/src/Entity/Translation.php index c5f7561a0..731ade771 100644 --- a/api/src/Entity/Translation.php +++ b/api/src/Entity/Translation.php @@ -35,7 +35,8 @@ * "path"="/admin/table_names" * }, * "post"={"path"="/admin/translations"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass=TranslationRepository::class) * diff --git a/api/src/Entity/Unread.php b/api/src/Entity/Unread.php index 836f1a822..2f96e9a2b 100644 --- a/api/src/Entity/Unread.php +++ b/api/src/Entity/Unread.php @@ -30,7 +30,7 @@ * collectionOperations={ * "get"={"path"="/admin/unreads"}, * "post"={"path"="/admin/unreads"} - * }) + * } * ) * * @ORM\Entity(repositoryClass="App\Repository\UnreadRepository") diff --git a/api/src/Entity/User.php b/api/src/Entity/User.php index 845610de9..7d2797e63 100644 --- a/api/src/Entity/User.php +++ b/api/src/Entity/User.php @@ -16,6 +16,7 @@ use Gedmo\Mapping\Annotation as Gedmo; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\MaxDepth; @@ -35,7 +36,8 @@ * collectionOperations={ * "get"={"path"="/admin/users"}, * "post"={"path"="/admin/users"} - * }) + * } + * ) * * @ORM\HasLifecycleCallbacks * @@ -50,6 +52,8 @@ * "reference": "exact" * }) * + * @UniqueEntity("reference") + * * @ORM\Table(name="`user`") */ class User implements PasswordAuthenticatedUserInterface @@ -102,6 +106,8 @@ class User implements PasswordAuthenticatedUserInterface /** * @Groups({"read", "write"}) * + * @Assert\NotNull + * * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) */ private ?string $reference = null; @@ -109,9 +115,11 @@ class User implements PasswordAuthenticatedUserInterface /** * @Groups({"read", "write"}) * - * @ORM\Column(type="string", length=255, nullable=true, options={"default": null}) + * @Assert\NotNull + * + * @ORM\Column(type="string", length=255, options={"default": "0.0.0"}) */ - private ?string $version = null; + private string $version = '0.0.0'; /** * @Groups({"write"}) diff --git a/api/src/Entity/Value.php b/api/src/Entity/Value.php index 91154a87d..89a6c4cae 100644 --- a/api/src/Entity/Value.php +++ b/api/src/Entity/Value.php @@ -40,7 +40,8 @@ * collectionOperations={ * "get"={"path"="/admin/values"}, * "post"={"path"="/admin/values"} - * }) + * } + * ) * * @ORM\Entity(repositoryClass="App\Repository\ValueRepository") * diff --git a/api/src/Repository/ActionRepository.php b/api/src/Repository/ActionRepository.php index 2a883d429..7d7e5746a 100644 --- a/api/src/Repository/ActionRepository.php +++ b/api/src/Repository/ActionRepository.php @@ -26,6 +26,8 @@ public function __construct(ManagerRegistry $registry) */ public function findByListens(string $listen): array { + // Todo: maybe add actions to MongoDB as well, so we can use better queries for this: + // Todo: %$listen% will sometimes find actions it shouldn't find, example: action listening to test.test.123 will be found if action test.test is thrown. $query = $this->createQueryBuilder('a') ->andWhere('a.listens LIKE :listen') ->setParameter('listen', "%$listen%") diff --git a/api/src/Security/ApiKeyAuthenticator.php b/api/src/Security/ApiKeyAuthenticator.php index c7af2224d..4bf905852 100644 --- a/api/src/Security/ApiKeyAuthenticator.php +++ b/api/src/Security/ApiKeyAuthenticator.php @@ -152,13 +152,22 @@ public function authenticate(Request $request): PassportInterface } try { - $user = $application->getOrganization()->getUsers()[0]; + $user = $application->getOrganization()->getUsers()->first(); + + $userCollection = $application->getOrganization()->getUsers(); + $users = $userCollection->filter(function (User $user) { + return $user->getName() === 'APIKEY_USER'; + }); + + if (count($users) > 0) { + $user = $users->first(); + } } catch (\Exception $exception) { - throw new AuthenticationException('An invalid User is configured for this ApiKey'); + throw new AuthenticationException('An invalid User (or no user) is configured for this ApiKey'); } if ($user instanceof User === false) { - throw new AuthenticationException('An invalid User is configured for this ApiKey'); + throw new AuthenticationException('An invalid User (or no user) is configured for this ApiKey'); } // Set apiKey Application id in session diff --git a/api/src/Service/EavService.php b/api/src/Service/EavService.php index c5e68a4a1..1a5dad5a9 100644 --- a/api/src/Service/EavService.php +++ b/api/src/Service/EavService.php @@ -1291,7 +1291,8 @@ public function handleDelete(ObjectEntity $object, ArrayCollection $maxDepth = n } // Remove this object from cache - $this->functionService->removeResultFromCache($object); + //todo: deprecated function +// $this->functionService->removeResultFromCache($object); $this->em->remove($object); $this->em->flush(); diff --git a/api/src/Service/EmailService.php b/api/src/Service/EmailService.php deleted file mode 100644 index 7625caabc..000000000 --- a/api/src/Service/EmailService.php +++ /dev/null @@ -1,133 +0,0 @@ -, Ruben van der Linde , Sarai Misidjan - * - * @license EUPL - * - * @category Service - */ -class EmailService -{ - private Environment $twig; - private array $data; - private array $configuration; - - public function __construct( - Environment $twig - ) { - $this->twig = $twig; - } - - /** - * Handles the sending of an email based on an event. - * - * @param array $data - * @param array $configuration - * - * @throws LoaderError|RuntimeError|SyntaxError|TransportExceptionInterface - * - * @return array - */ - public function EmailHandler(array $data, array $configuration): array - { - $this->data = $data; - $this->configuration = $configuration; - - $this->sendEmail(); - - return $data; - } - - /** - * Sends and email using an EmailTemplate with configuration for it. It is possible to use $object data in the email if configured right. - * - * @throws LoaderError - * @throws SyntaxError - * @throws TransportExceptionInterface - * - * @return bool - */ - private function sendEmail(): bool - { - // Create mailer with mailgun url - $transport = Transport::fromDsn($this->configuration['serviceDNS']); - $mailer = new Mailer($transport); - - // Ready the email template with configured variables - $variables = []; - - foreach ($this->configuration['variables'] as $key => $variable) { - // Response is the default used for creating emails after an /api endpoint has been called and returned a response. - if (isset($this->data['response']) === true && array_key_exists($variable, $this->data['response'])) { - $variables[$key] = $this->data['response'][$variable]; - } elseif (array_key_exists($variable, $this->data)) { - $variables[$key] = $this->data[$variable]; - } - } - - // Render the template - $html = $this->twig->createTemplate(base64_decode($this->configuration['template']))->render($variables); - $text = strip_tags(preg_replace('##i', "\n", $html), '\n'); - - // Lets allow the use of values from the object Created/Updated with {attributeName.attributeName} in the these^ strings. - $subject = $this->twig->createTemplate($this->configuration['subject'])->render($variables); - $receiver = $this->twig->createTemplate($this->configuration['receiver'])->render($variables); - $sender = $this->twig->createTemplate($this->configuration['sender'])->render($variables); - - // If we have no sender, set sender to receiver - if (!$sender) { - $sender = $receiver; - } - - // Create the email - $email = (new Email()) - ->from($sender) - ->to($receiver) - //->cc('cc@example.com') - //->bcc('bcc@example.com') - //->replyTo('fabien@example.com') - //->priority(Email::PRIORITY_HIGH) - ->subject($subject) - ->html($html) - ->text($text); - - // Then we can handle some optional configuration - if (array_key_exists('cc', $this->configuration)) { - $email->cc($this->configuration['cc']); - } - - if (array_key_exists('bcc', $this->configuration)) { - $email->bcc($this->configuration['bcc']); - } - - if (array_key_exists('replyTo', $this->configuration)) { - $email->replyTo($this->configuration['replyTo']); - } - - if (array_key_exists('priority', $this->configuration)) { - $email->priority($this->configuration['priority']); - } - - // todo: attachments - - // Send the email - /** @var Symfony\Component\Mailer\SentMessage $sentEmail */ - $mailer->send($email); - - return true; - } -} diff --git a/api/src/Service/FunctionService.php b/api/src/Service/FunctionService.php index 4ac569b10..d36564fc2 100644 --- a/api/src/Service/FunctionService.php +++ b/api/src/Service/FunctionService.php @@ -196,6 +196,7 @@ public function isResource($url) * @throws InvalidArgumentException * * @return bool + * @deprecated */ public function removeResultFromCache(ObjectEntity $objectEntity, ?SymfonyStyle $io = null): bool { @@ -225,6 +226,7 @@ public function removeResultFromCache(ObjectEntity $objectEntity, ?SymfonyStyle * @throws InvalidArgumentException * * @return void + * @deprecated */ private function removeParentResultsFromCache(ObjectEntity $objectEntity, ?SymfonyStyle $io) { @@ -248,6 +250,7 @@ private function removeParentResultsFromCache(ObjectEntity $objectEntity, ?Symfo * @throws InvalidArgumentException * * @return void + * @deprecated */ private function removeChildResultsFromCache(ObjectEntity $objectEntity, ?SymfonyStyle $io) { diff --git a/api/src/Service/SynchronizationService.php b/api/src/Service/SynchronizationService.php index b70a62ee0..b3ef73c37 100644 --- a/api/src/Service/SynchronizationService.php +++ b/api/src/Service/SynchronizationService.php @@ -14,6 +14,7 @@ use App\Exception\GatewayException; use CommonGateway\CoreBundle\Service\CallService; use CommonGateway\CoreBundle\Service\FileSystemHandleService; +use CommonGateway\CoreBundle\Service\GatewayResourceService; use CommonGateway\CoreBundle\Service\MappingService; use DateInterval; use DateTime; @@ -23,6 +24,7 @@ use Monolog\Logger; use Psr\Cache\CacheException; use Psr\Cache\InvalidArgumentException; +use Ramsey\Uuid\Uuid; use Safe\Exceptions\UrlException; use Symfony\Component\Console\Helper\TableSeparator; use Symfony\Component\Console\Style\SymfonyStyle; @@ -60,6 +62,7 @@ class SynchronizationService private SymfonyStyle $io; private Environment $twig; private MappingService $mappingService; + private GatewayResourceService $resourceService; private ActionEvent $event; private EventDispatcherInterface $eventDispatcher; @@ -83,6 +86,7 @@ class SynchronizationService * @param EventDispatcherInterface $eventDispatcher * @param MappingService $mappingService * @param FileSystemHandleService $fileSystemService + * @param GatewayResourceService $resourceService */ public function __construct( CallService $callService, @@ -98,7 +102,8 @@ public function __construct( Environment $twig, EventDispatcherInterface $eventDispatcher, MappingService $mappingService, - FileSystemHandleService $fileSystemService + FileSystemHandleService $fileSystemService, + GatewayResourceService $resourceService ) { $this->callService = $callService; $this->entityManager = $entityManager; @@ -119,6 +124,7 @@ public function __construct( $this->logger = new Logger('installation'); $this->mappingService = $mappingService; $this->fileSystemService = $fileSystemService; + $this->resourceService = $resourceService; } /** @@ -303,7 +309,7 @@ private function loopThroughCollectionResults(array $results, array $config): ar array_key_exists('object', $this->configuration['apiSource']['location']) && $result = $dot->get($this->configuration['apiSource']['location']['object'], $result); // Lets grab the sync object, if we don't find an existing one, this will create a new one: - $synchronization = $this->findSyncBySource($config['source'], $config['entity'], $id); + $synchronization = $this->findSyncBySource($config['source'], $config['entity'], $id, $this->configuration['location'] ?? null); // todo: Another search function for sync object. If no sync object is found, look for matching properties... // todo: ...in $result and an ObjectEntity in db. And then create sync for an ObjectEntity if we find one this way. (nice to have) // Other option to find a sync object, currently not used: @@ -670,13 +676,22 @@ public function getSingleFromSource(Synchronization $synchronization): ?array $url = \Safe\parse_url($synchronization->getSource()->getLocation()); + $endpoint = $synchronization->getEndpoint().'/'.$synchronization->getSourceId(); + if (str_contains('http', $synchronization->getSourceId()) === true) { + $endpoint = $synchronization->getEndpoint(); + } + if (isset($this->configuration['location']) === true) { + $endpoint = $this->configuration['location']; + $synchronization->setEndpoint($endpoint); + } + if ($url['scheme'] === 'http' || $url['scheme'] === 'https') { // Get object form source with callservice try { $this->logger->info("getSingleFromSource with Synchronization->sourceId = {$synchronization->getSourceId()}"); $response = $this->callService->call( $callServiceConfig['source'], - $synchronization->getEndpoint() ?? $callServiceConfig['endpoint'], + $endpoint, $callServiceConfig['method'] ?? 'GET', [ 'body' => '', @@ -694,7 +709,7 @@ public function getSingleFromSource(Synchronization $synchronization): ?array $result = $this->callService->decodeResponse($callServiceConfig['source'], $response); } elseif ($url['scheme'] === 'ftp') { // This only works if a file data equals a single Object(Entity). Or if the mapping on the Source or Synchronization results in data for just a single Object. - $result = $this->fileSystemService->call($synchronization->getSource(), $synchronization->getEndpoint() ?? $callServiceConfig['endpoint']); + $result = $this->fileSystemService->call($synchronization->getSource(), isset($this->configuration['location']) === true ? $callServiceConfig['endpoint'] : $endpoint); } $dot = new Dot($result); // The place where we can find the id field when looping through the list of objects, from $result root, by object (dot notation) @@ -711,15 +726,20 @@ public function getSingleFromSource(Synchronization $synchronization): ?array /** * Finds a synchronization object if it exists for the current object in the source, or creates one if it doesn't exist. * - * @param Source $source The source that is requested - * @param Entity $entity The entity that is requested - * @param string $sourceId The id of the object in the source + * @param Source $source The source that is requested + * @param Entity $entity The entity that is requested + * @param string $sourceId The id of the object in the source + * @param string|null $endpoint The endpoint of the synchronization. * * @return Synchronization|null A synchronization object related to the object in the source */ - public function findSyncBySource(Source $source, Entity $entity, string $sourceId): ?Synchronization + public function findSyncBySource(Source $source, Entity $entity, string $sourceId, ?string $endpoint = null): ?Synchronization { - $synchronization = $this->entityManager->getRepository('App:Synchronization')->findOneBy(['gateway' => $source, 'entity' => $entity, 'sourceId' => $sourceId]); + $criteria = ['gateway' => $source, 'entity' => $entity, 'sourceId' => $sourceId]; + if (empty($endpoint) === false) { + $criteria['endpoint'] = $endpoint; + } + $synchronization = $this->entityManager->getRepository('App:Synchronization')->findOneBy($criteria); if ($synchronization instanceof Synchronization) { if (isset($this->io)) { @@ -731,6 +751,7 @@ public function findSyncBySource(Source $source, Entity $entity, string $sourceI } $synchronization = new Synchronization($source, $entity); + $synchronization->setEndpoint($endpoint); $synchronization->setSourceId($sourceId); $this->entityManager->persist($synchronization); // We flush later @@ -1326,15 +1347,27 @@ private function syncToSource(Synchronization $synchronization, bool $existsInSo // $objectArray = $this->objectEntityService->checkGetObjectExceptions($data, $object, [], ['all' => true], 'application/ld+json'); // todo: maybe move this to foreach in getAllFromSource() (nice to have) - $callServiceConfig = $this->getCallServiceConfig($synchronization->getSource(), null, $objectArray); + $callServiceConfig = $this->getCallServiceConfig($synchronization->getSource(), $existsInSource ? $synchronization->getSourceId() : null, $objectArray); $objectArray = $this->mapOutput($objectArray); + $endpoint = $synchronization->getEndpoint(); + if ($existsInSource === true) { + $endpoint = $endpoint.'/'.$synchronization->getSourceId(); + } + if (str_contains('http', $synchronization->getSourceId()) === true) { + $endpoint = $synchronization->getEndpoint(); + } + if (isset($this->configuration['location']) === true) { + $endpoint = $this->configuration['location']; + $synchronization->setEndpoint($endpoint); + } + $objectString = $this->getObjectString($objectArray); try { $result = $this->callService->call( $callServiceConfig['source'], - $synchronization->getEndpoint() ?? $callServiceConfig['endpoint'], + $endpoint, $callServiceConfig['method'] ?? ($existsInSource ? 'PUT' : 'POST'), [ 'body' => $objectString, @@ -1469,41 +1502,39 @@ private function syncThroughComparing(Synchronization $synchronization): Synchro */ public function aquireObject(string $url, Entity $entity): ?ObjectEntity { - // 1. Get the domain from the url - $parse = \Safe\parse_url($url); - $location = $parse['scheme'].'://'.$parse['host']; - - // 2.c Try to establish a source for the domain - $source = $this->entityManager->getRepository('App:Gateway')->findOneBy(['location'=>$location]); - - // 2.b The source might be on a path e.g. /v1 so if whe cant find a source let try to cycle - if ($source instanceof Source === false && isset($parse['path']) === true) { - foreach (explode('/', $parse['path']) as $pathPart) { - if ($pathPart !== '') { - $location = $location.'/'.$pathPart; - } - $source = $this->entityManager->getRepository('App:Gateway')->findOneBy(['location'=>$location]); - if ($source !== null) { - break; - } - } - } - if ($source instanceof Source === false) { - return null; - } + $source = $this->resourceService->findSourceForUrl($url, 'conduction-nl/commonground-gateway', $endpoint); + $sourceId = $this->getSourceId($endpoint, $url); - // 3 If we have a source we can establish an endpoint. - $endpoint = str_replace($location, '', $url); - - // 4 Create sync - $synchronization = new Synchronization($source, $entity); - $synchronization->setSourceId($url); - $synchronization->setEndpoint($endpoint); - - $this->entityManager->persist($synchronization); + $synchronization = $this->findSyncBySource($source, $entity, $sourceId, $endpoint); $this->synchronize($synchronization); return $synchronization->getObject(); } + + /** + * A function best used after resourceService->findSourceForUrl and/or before $this->findSyncBySource. + * This function will get the uuid / int id from the end of an endpoint. This is the sourceId for a Synchronization. + * + * @param string|null $endpoint The endpoint to get the SourceId from. + * @param string|null $url The url used as back-up for SourceId if no proper SourceId can be found. + * + * @return string|null The sourceId, will be equal to $url if end part of the endpoint isn't an uuid or integer. And will return null if $endpoint & $url ar both null. + */ + public function getSourceId(?string &$endpoint, ?string $url = null): ?string + { + if ($endpoint === null) { + return $url; + } + + $explodedEndpoint = explode('/', $endpoint); + $sourceId = end($explodedEndpoint); + if (Uuid::isValid($sourceId) === true || is_int((int) $sourceId) === true) { + $endpoint = str_replace("/$sourceId", '', $endpoint); + } else { + $sourceId = $url; + } + + return $sourceId; + } } diff --git a/api/src/Twig/MappingExtension.php b/api/src/Twig/MappingExtension.php index d2df0d88d..6145279a4 100644 --- a/api/src/Twig/MappingExtension.php +++ b/api/src/Twig/MappingExtension.php @@ -12,6 +12,8 @@ public function getFunctions() return [ new TwigFunction('map', [MappingRuntime::class, 'map']), new TwigFunction('dotToObject', [MappingRuntime::class, 'dotToArray']), + new TwigFunction('arrayValues', [MappingRuntime::class, 'arrayValues']), + new TwigFunction('getObject', [MappingRuntime::class, 'getObject']), ]; } } diff --git a/api/src/Twig/MappingRuntime.php b/api/src/Twig/MappingRuntime.php index 850832aa2..95700abeb 100644 --- a/api/src/Twig/MappingRuntime.php +++ b/api/src/Twig/MappingRuntime.php @@ -4,6 +4,7 @@ use Adbar\Dot; use CommonGateway\CoreBundle\Service\MappingService; +use CommonGateway\CoreBundle\Service\CacheService; use Doctrine\ORM\EntityManagerInterface; use Twig\Extension\RuntimeExtensionInterface; @@ -11,13 +12,29 @@ class MappingRuntime implements RuntimeExtensionInterface { private MappingService $mappingService; private EntityManagerInterface $entityManager; + private CacheService $cacheService; - public function __construct(MappingService $mappingService, EntityManagerInterface $entityManager) + public function __construct(MappingService $mappingService, EntityManagerInterface $entityManager, CacheService $cacheService) { $this->entityManager = $entityManager; $this->mappingService = $mappingService; + $this->cacheService = $cacheService; } + /** + * Uses CoreBundle MappingService to map data. + * If $list is set to true you could use the key 'listInput' in the $data array to pass along the list of items to map. + * This makes it possible to also pass along other key+value pairs to use in mapping besides just one array of items to map. + * + * @param string $mappingString The reference of a Mapping object. + * @param array $data The data to map. Or one list of items to map. + * @param bool $list False by default, if set to true mapping will be done for each item in the $data array. + * + * @return array The mapped result. + * + * @throws \Twig\Error\LoaderError + * @throws \Twig\Error\SyntaxError + */ public function map(string $mappingString, array $data, bool $list = false): array { $mapping = $this->entityManager->getRepository('App:Mapping')->findOneBy(['reference' => $mappingString]); @@ -27,10 +44,41 @@ public function map(string $mappingString, array $data, bool $list = false): arr return $value; } + /** + * Turns given array into an Adbar\Dot (dot notation). + * + * @param array $array The array to turn into a dot array. + * + * @return array The dot aray. + */ public function dotToArray(array $array): array { $dotArray = new Dot($array, true); return $dotArray->all(); } + + /** + * Makes it possible to use the php function array_values in twig. + * + * @param array $array The array to use array_values on. + * + * @return array The updated array. + */ + public function arrayValues(array $array): array + { + return array_values($array); + } + + /** + * Makes it possible to get a object with the cacheService in twig. + * + * @param string $id The id of the object to fetch. + * + * @return array The fetched object. + */ + public function getObject(string $id): array + { + return $this->cacheService->getObject($id); + } } diff --git a/api/templates/emails/bisc/password-forgot-e-mail.html.twig b/api/templates/emails/bisc/password-forgot-e-mail.html.twig deleted file mode 100644 index a19fcbc74..000000000 --- a/api/templates/emails/bisc/password-forgot-e-mail.html.twig +++ /dev/null @@ -1,525 +0,0 @@ - - - - - - {{ subject }} - - - - - - - - - - - - - - - diff --git a/api/templates/emails/gateway/new-log-e-mail.html.twig b/api/templates/emails/gateway/new-log-e-mail.html.twig deleted file mode 100644 index 672102e69..000000000 --- a/api/templates/emails/gateway/new-log-e-mail.html.twig +++ /dev/null @@ -1,503 +0,0 @@ -{# todo: move this to an email plugin (see EmailService.php) #} - - - - - - {{ subject }} - - - - - - - - - - - - - - - diff --git a/api/templates/emails/kiss/new-review-e-mail.html.twig b/api/templates/emails/kiss/new-review-e-mail.html.twig deleted file mode 100644 index 2b3720643..000000000 --- a/api/templates/emails/kiss/new-review-e-mail.html.twig +++ /dev/null @@ -1,491 +0,0 @@ -{# todo: move this to an email plugin (see EmailService.php) #} - - - - - - {{ subject }} - - - - - - - - - - - - - - -