From 96ec41ece98b9bbf59e1b0a0289249be7fe9e3a0 Mon Sep 17 00:00:00 2001 From: Quentin RIBAC <quentin.ribac@xelians.fr> Date: Wed, 9 Jun 2021 19:08:45 +0200 Subject: [PATCH] FEAT #17150 TIME 3:30 WIP back CRUD for NotificationsSchedule (Controller and Model) --- composer.json | 3 +- rest/index.php | 7 + sql/structure.sql | 24 +++ .../group/controllers/PrivilegeController.php | 3 +- .../NotificationsScheduleController.php | 186 ++++++++++++++++++ .../models/NotificationsScheduleModel.php | 110 +++++++++++ vendor/composer/LICENSE | 2 - vendor/composer/autoload_psr4.php | 1 + vendor/composer/autoload_static.php | 8 + 9 files changed, 340 insertions(+), 4 deletions(-) create mode 100644 src/app/notifications/controllers/NotificationsScheduleController.php create mode 100644 src/app/notifications/models/NotificationsScheduleModel.php diff --git a/composer.json b/composer.json index 61d16f6dc0..a6eb2d676f 100755 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "History\\" : "src/app/history/", "Search\\" : "src/app/search/", "User\\" : "src/app/user/", - "Workflow\\" : "src/app/workflow/" + "Workflow\\" : "src/app/workflow/", + "Notifications\\" : "src/app/notifications/" } }, "require": { diff --git a/rest/index.php b/rest/index.php index c55c79b7a5..3b49bd3ac8 100755 --- a/rest/index.php +++ b/rest/index.php @@ -161,4 +161,11 @@ $app->get('/workflowTemplates', \Workflow\controllers\WorkflowTemplateController $app->get('/workflowTemplates/{id}', \Workflow\controllers\WorkflowTemplateController::class . ':getById'); $app->delete('/workflowTemplates/{id}', \Workflow\controllers\WorkflowTemplateController::class . ':delete'); +//NotificationsSchedule +$app->post('/schedule', \Notifications\controllers\NotificationsScheduleController::class.':create'); +$app->get('/schedule', \Notifications\controllers\NotificationsScheduleController::class.':get'); +$app->get('/schedule/{id}', \Notifications\controllers\NotificationsScheduleController::class.':getById'); +$app->put('/schedule', \Notifications\controllers\NotificationsScheduleController::class.':update'); +$app->delete('/schedule', \Notifications\controllers\NotificationsScheduleController::class.':delete'); + $app->run(); diff --git a/sql/structure.sql b/sql/structure.sql index 7e64bba36c..29f7f0dffe 100755 --- a/sql/structure.sql +++ b/sql/structure.sql @@ -301,3 +301,27 @@ CREATE TABLE workflow_templates_items CONSTRAINT workflow_templates_items_pkey PRIMARY KEY (id) ) WITH (OIDS=FALSE); + +CREATE TABLE notifications_stack +( + id serial NOT NULL, + main_document_id int NOT NULL, + type character varying(256) NOT NULL, + sender_id int, + recipient_id int, + CONSTRAINT external_signatory_book_pkey PRIMARY KEY (id) +) +WITH (OIDS=FALSE); + +CREATE TABLE notifications_schedule +( + id serial NOT NULL, + type character varying(256) NOT NULL, + month character varying(16), -- -> 1 - 12 + day_of_month character varying(16), -- -> null -> *, 1-31 + day_of_week character varying(16), -- -> null -> *, 0-6 (0-Sunday, 6-Saturday) + hour character varying(16), -- 0 - 23 + minute character varying(16), -- 0 - 59 + CONSTRAINT notifications_schedule_pkey PRIMARY KEY (id) +) +WITH (OIDS=FALSE); diff --git a/src/app/group/controllers/PrivilegeController.php b/src/app/group/controllers/PrivilegeController.php index c322fd4dd5..a430426b4a 100755 --- a/src/app/group/controllers/PrivilegeController.php +++ b/src/app/group/controllers/PrivilegeController.php @@ -20,7 +20,7 @@ use Group\models\GroupPrivilegeModel; class PrivilegeController { - const PRIVILEGES = [ + public const PRIVILEGES = [ ['id' => 'manage_users', 'type' => 'admin', 'icon' => 'person-sharp', 'route' => '/administration/users'], ['id' => 'manage_groups', 'type' => 'admin', 'icon' => 'people-sharp', 'route' => '/administration/groups'], ['id' => 'manage_connections', 'type' => 'admin', 'icon' => 'server-sharp', 'route' => '/administration/connections'], @@ -29,6 +29,7 @@ class PrivilegeController ['id' => 'manage_history', 'type' => 'admin', 'icon' => 'timer-outline', 'route' => '/administration/history'], ['id' => 'manage_otp_connectors', 'type' => 'admin', 'icon' => 'people-circle-outline', 'route' => '/administration/otps'], ['id' => 'manage_customization', 'type' => 'admin', 'icon' => 'color-wand-outline', 'route' => '/administration/customization'], + ['id' => 'manage_notifications', 'type' => 'admin', 'icon' => 'notifications', 'route' => '/administration/notifications'], ['id' => 'manage_documents', 'type' => 'simple'], ['id' => 'indexation', 'type' => 'simple'] ]; diff --git a/src/app/notifications/controllers/NotificationsScheduleController.php b/src/app/notifications/controllers/NotificationsScheduleController.php new file mode 100644 index 0000000000..705008611f --- /dev/null +++ b/src/app/notifications/controllers/NotificationsScheduleController.php @@ -0,0 +1,186 @@ +<?php + +/** +* Copyright Maarch since 2008 under license. +* See LICENSE.txt file at the root folder for more details. +* This file is part of Maarch software. +* +*/ + +/** +* @brief Notifications Schedule Controller +* @author dev@maarch.org +*/ + +namespace Notifications\controllers; + +use Notifications\models\NotificationsScheduleModel; +use Group\controllers\PrivilegeController; +use History\controllers\HistoryController; +use Respect\Validation\Validator; +use Slim\Http\Request; +use Slim\Http\Response; + +class NotificationsScheduleController +{ + public function create(Request $request, Response $response) + { + if (!PrivilegeController::hasPrivilege(['userId' => $GLOBALS['id'], 'privilege' => 'manage_notifications'])) { + return $response->withStatus(403)->withJson(['errors' => 'Privilege forbidden']); + } + + $body = $request->getParsedBody(); + // type, month, dayOfMonth, dayOfWeek, hour, minute + + if (empty($body)) { + return $response->withStatus(400)->withJson(['errors' => 'Body is not set or empty']); + } elseif (!Validator::stringType()->in(NotificationsScheduleModel::TYPES)->validate($body['type'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body type does not exist']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(1, 12))->validate($body['month'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body month is not a number or is not between 1 and 12']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(1, 31))->validate($body['dayOfMonth'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body dayOfMonth is not a number or is not between 1 and 31']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(0, 6))->validate($body['dayOfWeek'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body dayOfWeek is not a number or is not between 0 and 6']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(0, 23))->validate($body['hour'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body hour is not a number or is not between 0 and 23']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(0, 59))->validate($body['minute'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body minute is not a number or is not between 0 and 59']); + } elseif ($body['month'] !== 'ANY' && $body['dayOfMonth'] !== 'ANY' && !Validator::date('n-j')->validate($body['month'].'-'.$body['dayOfMonth'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body month and dayOfMonth do not form a valid date']); + } + + $id = NotificationsScheduleModel::create([ + 'type' => $body['type'], + 'month' => (string) $body['month'], + 'day_of_month' => (string) $body['dayOfMonth'], + 'day_of_week' => (string) $body['dayOfWeek'], + 'hour' => (string) $body['hour'], + 'minute' => (string) $body['minute'], + ]); + + HistoryController::add([ + 'code' => 'OK', + 'objectType' => 'notifications_schedule', + 'objectId' => $id, + 'type' => 'CREATION', + 'message' => "{notificationScheduleAdded} : {$body['type']} on {$body['month']} {$body['dayOfMonth']} {$body['dayOfWeek']} {$body['hour']} {$body['minute']}" + ]); + + return $response->withJson(['id' => $id]); + } + + public function get(Request $request, Response $response) + { + if (!PrivilegeController::hasPrivilege(['userId' => $GLOBALS['id'], 'privilege' => 'manage_notifications'])) { + return $response->withStatus(403)->withJson(['errors' => 'Privilege forbidden']); + } + + $notificationsSchedule = NotificationsScheduleModel::get(); + + return $response->withJson(['notifications_schedule' => $notificationsSchedule]); + } + + public function getById(Request $request, Response $response, array $args) + { + if (!PrivilegeController::hasPrivilege(['userId' => $GLOBALS['id'], 'privilege' => 'manage_notifications'])) { + return $response->withStatus(403)->withJson(['errors' => 'Privilege forbidden']); + } + + if (!Validator::intVal()->notEmpty()->validate($args['id'])) { + return $response->withStatus(400)->withJson(['errors' => 'Route id must be an integer']); + } + + $notificationsScheduleItem = NotificationsScheduleModel::getById(['id' => $args['id']]); + if (empty($notificationsScheduleItem)) { + return $response->withStatus(400)->withJson(['errors' => 'Notifications schedule item not found']); + } + + return $response->withJson(['notificationsScheduleItem' => $notificationsScheduleItem]); + } + + public function update(Request $request, Response $response, array $aArgs) + { + if (!PrivilegeController::hasPrivilege(['userId' => $GLOBALS['id'], 'privilege' => 'manage_notifications'])) { + return $response->withStatus(403)->withJson(['errors' => 'Privilege forbidden']); + } + + $body = $request->getParsedBody(); + + if (empty($body)) { + return $response->withStatus(400)->withJson(['errors' => 'Body is not set or empty']); + } elseif (!Validator::intVal()->notEmpty()->validate($aArgs['id'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body id is not set or empty']); + } elseif (!Validator::stringType()->in(self::TYPES)->validate($body['type'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body type does not exist']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(1, 12))->validate($body['month'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body month is not a number or is not between 1 and 12']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(1, 31))->validate($body['dayOfMonth'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body dayOfMonth is not a number or is not between 1 and 31']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(0, 6))->validate($body['dayOfWeek'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body dayOfWeek is not a number or is not between 0 and 6']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(0, 23))->validate($body['hour'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body hour is not a number or is not between 0 and 23']); + } elseif (!Validator::oneOf(Validator::equals('ANY'), Validator::intVal()->between(0, 59))->validate($body['minute'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body minute is not a number or is not between 0 and 59']); + } elseif ($body['month'] !== 'ANY' && $body['dayOfMonth'] !== 'ANY' && !Validator::date('n-j')->validate($body['month'].'-'.$body['dayOfMonth'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body month and dayOfMonth do not form a valid date']); + } + + $notificationsScheduleItem::getById(['id' => $aArgs['id']]); + if (empty($notificationsScheduleItem)) { + return $response->withStatus(400)->withJson(['errors' => 'Notifications schedule item not found']); + } + + NotificationsScheduleModel::update([ + 'set' => [ + 'type' => $body['type'], + 'month' => (string) $body['month'], + 'day_of_month' => (string) $body['dayOfMonth'], + 'day_of_week' => (string) $body['dayOfWeek'], + 'hour' => (string) $body['hour'], + 'minute' => (string) $body['minute'], + ], + 'where' => ['id = ?'], + 'data' => [$aArgs['id']] + ]); + + HistoryController::add([ + 'code' => 'OK', + 'objectType' => 'notifications_schedule', + 'objectId' => $aArgs['id'], + 'type' => 'MODIFICATION', + 'message' => "{notificationsScheduleItemUpdated} : {$body['type']}" + ]); + + return $response->withStatus(204); + } + + public function delete(Request $request, Response $response, array $aArgs) + { + if (!PrivilegeController::hasPrivilege(['userId' => $GLOBALS['id'], 'privilege' => 'manage_notifications'])) { + return $response->withStatus(403)->withJson(['errors' => 'Privilege forbidden']); + } + + if (!Validator::intVal()->notEmpty()->validate($aArgs['id'])) { + return $response->withStatus(400)->withJson(['errors' => 'Id must be an integer']); + } + + $notificationsScheduleItem = NotificationsScheduleModel::getById(['id' => $aArgs['id']]); + if (empty($notificationsScheduleItem)) { + return $response->withStatus(400)->withJson(['errors' => 'Notifications schedule item not found']); + } + + NotificationsScheduleModel::delete(['where' => ['id = ?'], 'data' => [$aArgs['id']]]); + + HistoryController::add([ + 'code' => 'OK', + 'objectType' => 'notifications_schedule', + 'objectId' => $aArgs['id'], + 'type' => 'SUPPRESSION', + 'message' => "{notificationsScheduleItemDeleted} : {$notificationsScheduleItem['type']}" + ]); + + return $response->withStatus(204); + } +} diff --git a/src/app/notifications/models/NotificationsScheduleModel.php b/src/app/notifications/models/NotificationsScheduleModel.php new file mode 100644 index 0000000000..3e8c133df1 --- /dev/null +++ b/src/app/notifications/models/NotificationsScheduleModel.php @@ -0,0 +1,110 @@ +<?php + +/** +* Copyright Maarch since 2008 under license. +* See LICENSE.txt file at the root folder for more details. +* This file is part of Maarch software. +* +*/ + +/** +* @brief Notifications Schedule Model +* @author dev@maarch.org +*/ + +namespace Notifications\models; + +use SrcCore\models\DatabaseModel; +use SrcCore\models\ValidatorModel; + +class NotificationsScheduleModel +{ + public const TYPES = ['next_user', 'typist_END', 'typist_INT', 'typist_DEL', 'typist_REF']; + + public static function get(array $aArgs = []) + { + ValidatorModel::arrayType($aArgs, ['select', 'where', 'data', 'orderBy']); + ValidatorModel::intType($aArgs, ['limit']); + + $notificationsSchedule = DatabaseModel::select([ + 'select' => empty($aArgs['select']) ? ['*'] : $aArgs['select'], + 'table' => ['notifications_schedule'], + 'where' => empty($aArgs['where']) ? [] : $aArgs['where'], + 'data' => empty($aArgs['data']) ? [] : $aArgs['data'], + 'orderBy' => empty($aArgs['orderBy']) ? [] : $aArgs['orderBy'], + 'limit' => empty($aArgs['limit']) ? 0 : $aArgs['limit'] + ]); + + return $notificationsSchedule; + } + + public static function getById(array $aArgs) + { + ValidatorModel::notEmpty($aArgs, ['id']); + ValidatorModel::intVal($aArgs, ['id']); + ValidatorModel::arrayType($aArgs, ['select']); + + $notificationsScheduleItem = NotificationsScheduleModel::get([ + 'select' => empty($aArgs['select']) ? ['*'] : $aArgs['select'], + 'where' => ['id = ?'], + 'data' => [$aArgs['id']] + ]); + + if (!empty($notificationsScheduleItem)) { + return $notificationsScheduleItem[0]; + } + + return []; + } + + public static function create(array $aArgs) + { + ValidatorModel::notEmpty($aArgs, ['label']); + ValidatorModel::stringType($aArgs, ['type', 'month', 'day_of_month', 'day_of_week', 'hour', 'minute']); + + $nextSequenceId = DatabaseModel::getNextSequenceValue(['sequenceId' => 'notifications_schedule_id_seq']); + DatabaseModel::insert([ + 'table' => 'notifications_schedule', + 'columnsValues' => [ + 'id' => $nextSequenceId, + 'type' => $aArgs['type'], + 'month' => $aArgs['month'], + 'day_of_month' => $aArgs['day_of_month'], + 'day_of_week' => $aArgs['day_of_week'], + 'hour' => $aArgs['hour'], + 'minute' => $aArgs['minute'], + ] + ]); + + return $nextSequenceId; + } + + public static function update(array $args) + { + ValidatorModel::notEmpty($args, ['set', 'where', 'data']); + ValidatorModel::arrayType($args, ['set', 'where', 'data']); + + DatabaseModel::update([ + 'table' => 'notifications_schedule', + 'set' => $args['set'], + 'where' => $args['where'], + 'data' => $args['data'] + ]); + + return true; + } + + public static function delete(array $args) + { + ValidatorModel::notEmpty($args, ['where', 'data']); + ValidatorModel::arrayType($args, ['where', 'data']); + + DatabaseModel::delete([ + 'table' => 'notifications_schedule', + 'where' => $args['where'], + 'data' => $args['data'] + ]); + + return true; + } +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE index f27399a042..62ecfd8d00 100644 --- a/vendor/composer/LICENSE +++ b/vendor/composer/LICENSE @@ -1,4 +1,3 @@ - Copyright (c) Nils Adermann, Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy @@ -18,4 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 3c823bd1dd..1b2f5d9351 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -26,6 +26,7 @@ return array( 'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'), 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), 'Otp\\' => array($vendorDir . '/christian-riesen/otp/src'), + 'Notifications\\' => array($baseDir . '/src/app/notifications'), 'History\\' => array($baseDir . '/src/app/history'), 'Group\\' => array($baseDir . '/src/app/group'), 'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index ea707cfbbd..c1322e0a73 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -60,6 +60,10 @@ class ComposerStaticInit637514d10f1ed5d4c55a005a428a3656 array ( 'Otp\\' => 4, ), + 'N' => + array ( + 'Notifications\\' => 14, + ), 'H' => array ( 'History\\' => 8, @@ -179,6 +183,10 @@ class ComposerStaticInit637514d10f1ed5d4c55a005a428a3656 array ( 0 => __DIR__ . '/..' . '/christian-riesen/otp/src', ), + 'Notifications\\' => + array ( + 0 => __DIR__ . '/../..' . '/src/app/notifications', + ), 'History\\' => array ( 0 => __DIR__ . '/../..' . '/src/app/history', -- GitLab