diff --git a/VERSION b/VERSION index fbcbf7380658d02bca7addb53878f58b4c5d89db..e5b820341fb19d0f8eef91cb42b76b8eea7c3ef7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.4.0 \ No newline at end of file +3.5.0 \ No newline at end of file diff --git a/app/dependencies.php b/app/dependencies.php index 35494ad35f058513b89462435491a17882133e03..2d7634e868662bb8d2a8e9fa536a835f69e6bb3a 100644 --- a/app/dependencies.php +++ b/app/dependencies.php @@ -76,6 +76,22 @@ $container->set('App\Action\ProjectAction', function (ContainerInterface $c) { return new App\Action\ProjectAction($c->get('em')); }); +$container->set('App\Action\UserListAction', function (ContainerInterface $c) { + return new App\Action\UserListAction($c->get('em')); +}); + +$container->set('App\Action\UserAction', function (ContainerInterface $c) { + return new App\Action\UserAction($c->get('em')); +}); + +$container->set('App\Action\GroupListAction', function (ContainerInterface $c) { + return new App\Action\GroupListAction($c->get('em')); +}); + +$container->set('App\Action\GroupAction', function (ContainerInterface $c) { + return new App\Action\GroupAction($c->get('em')); +}); + $container->set('App\Action\FamilyListAction', function (ContainerInterface $c) { return new App\Action\FamilyListAction($c->get('em')); }); diff --git a/app/routes.php b/app/routes.php index c0e3b18abbd2e10a5151070bf84925acd27694b1..5b255b7ce9583ae2a50df9e0b220aea74e24b130 100644 --- a/app/routes.php +++ b/app/routes.php @@ -18,6 +18,10 @@ $app->map([OPTIONS, GET, PUT, DELETE], '/database/{id}', App\Action\DatabaseActi $app->map([OPTIONS, GET], '/database/{id}/table', App\Action\TableListAction::class); $app->map([OPTIONS, GET, POST], '/project', App\Action\ProjectListAction::class); $app->map([OPTIONS, GET, PUT, DELETE], '/project/{name}', App\Action\ProjectAction::class); +$app->map([OPTIONS, GET, POST], '/user', App\Action\UserListAction::class); +$app->map([OPTIONS, GET, PUT, DELETE], '/user/{email}', App\Action\UserAction::class); +$app->map([OPTIONS, GET, POST], '/group', App\Action\GroupListAction::class); +$app->map([OPTIONS, GET, PUT, DELETE], '/group/{id}', App\Action\GroupAction::class); $app->map([OPTIONS, GET, POST], '/instance', App\Action\InstanceListAction::class); $app->map([OPTIONS, GET, PUT, DELETE], '/instance/{name}', App\Action\InstanceAction::class); $app->map([OPTIONS, GET, POST], '/instance/{name}/dataset-family', App\Action\DatasetFamilyListAction::class); diff --git a/conf-dev/create-db.sh b/conf-dev/create-db.sh index 46ac523219e8a02674750ef5a6db8a0d76d33b05..3bb8a5088525bdcc10eb989ea318c9e890858e10 100644 --- a/conf-dev/create-db.sh +++ b/conf-dev/create-db.sh @@ -17,10 +17,10 @@ curl -d '{"name":"colibri","label":"Colibri Project Test","description":"Project # Add default dataset family and ANIS datasets curl -d '{"label":"Default dataset family","display":10}' -H "Content-Type: application/json" -X POST http://localhost/instance/default/dataset-family -curl -d '{"name":"obs_cat","table_ref":"obs_cat","label":"ObsCat dataset","description":"ObsCat","display":10,"count":10000,"vo":false,"data_path":"/mnt/mount","config":{"cone_search":{"enabled":true,"column_ra":2,"column_dec":3},"selectable_row":true},"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset -curl -d '{"name":"observations","table_ref":"observations_info","label":"Observations dataset","description":"Observations","display":20,"count":177454,"vo":false,"data_path":"/mnt/mount","config":{"selectable_row":false},"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset -curl -d '{"name":"vipers_dr2_w1","table_ref":"aspic_vipers_dr2_w1","label":"VIPERS-W1 (DR2)","description":"VIPERS W1 dataset","display":30,"count":1000,"vo":false,"data_path":"/mnt/mount","config":{"selectable_row":false},"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset -curl -d '{"name":"gama_g02_dr3","table_ref":"aspic_gama_g02","label":"GAMA G02 (DR3)","description":"GAMA G02 dataset","display":40,"count":8,"vo":false,"data_path":"/mnt/mount","config":{"selectable_row":false},"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset +curl -d '{"name":"obs_cat","table_ref":"obs_cat","label":"ObsCat dataset","description":"ObsCat","display":10,"count":10000,"vo":false,"data_path":"/mnt/mount","config":{"cone_search":{"enabled":true,"column_ra":2,"column_dec":3},"selectable_row":true},"public":true,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset +curl -d '{"name":"observations","table_ref":"observations_info","label":"Observations dataset","description":"Observations","display":20,"count":177454,"vo":false,"data_path":"/mnt/mount","config":{"selectable_row":false},"public":true,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset +curl -d '{"name":"vipers_dr2_w1","table_ref":"aspic_vipers_dr2_w1","label":"VIPERS-W1 (DR2)","description":"VIPERS W1 dataset","display":30,"count":1000,"vo":false,"data_path":"/mnt/mount","config":{"selectable_row":false},"public":true,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset +curl -d '{"name":"gama_g02_dr3","table_ref":"aspic_gama_g02","label":"GAMA G02 (DR3)","description":"GAMA G02 dataset","display":40,"count":8,"vo":false,"data_path":"/mnt/mount","config":{"selectable_row":false},"public":true,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset # Add ANIS obs_cat default criteria family, default output family and default output category curl -d '{"label":"Default criteria family","display":10}' -H "Content-Type: application/json" -X POST http://localhost/dataset/obs_cat/criteria-family @@ -29,9 +29,9 @@ curl -d '{"label":"Default output category","display":10}' -H "Content-Type: app # Add SVOM dataset family and SVOM datasets curl -d '{"label":"Svom dataset family","display":20}' -H "Content-Type: application/json" -X POST http://localhost/instance/default/dataset-family -curl -d '{"name":"l1","table_ref":"public.v_rawproducts","label":"L0 & L1","description":"L0 & L1 products list","display":10,"count":0,"vo":false,"data_path":"/mnt/mount","config":{"results_server_link":{"enabled":true},"selectable_row":false},"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset -curl -d '{"name":"products","table_ref":"public.v_products","label":"Scientific Products","description":"SR3 & SR4 products list","display":20,"count":0,"vo":false,"data_path":"/mnt/mount","config":{"results_server_link":{"enabled":true},"selectable_row":false},"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset -curl -d '{"name":"sp_cards","table_ref":"sp_cards","label":"SP Metadata","description":"Contains metadata of scientific products (Core Program & General Program)","display":30,"count":100,"vo":false,"data_path":"/mnt/mount","config":{"results_server_link":{"enabled":true},"selectable_row":false},"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset +curl -d '{"name":"l1","table_ref":"public.v_rawproducts","label":"L0 & L1","description":"L0 & L1 products list","display":10,"count":0,"vo":false,"data_path":"/mnt/mount","config":{"results_server_link":{"enabled":true},"selectable_row":false},"public":true,"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset +curl -d '{"name":"products","table_ref":"public.v_products","label":"Scientific Products","description":"SR3 & SR4 products list","display":20,"count":0,"vo":false,"data_path":"/mnt/mount","config":{"results_server_link":{"enabled":true},"selectable_row":false},"public":true,"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset +curl -d '{"name":"sp_cards","table_ref":"sp_cards","label":"SP Metadata","description":"Contains metadata of scientific products (Core Program & General Program)","display":30,"count":100,"vo":false,"data_path":"/mnt/mount","config":{"results_server_link":{"enabled":true},"selectable_row":false},"public":true,"project_name":"svom"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/2/dataset # Add SVOM l1 criteria families, default output family and default output category curl -d '{"label":"Obs","display":10}' -H "Content-Type: application/json" -X POST http://localhost/dataset/l1/criteria-family @@ -100,7 +100,7 @@ curl -d '{"id":9,"name":"json_schema_uploaded","table_name":"sp_cards","label":" # Add COLIBRI dataset family and COLIBRI dataset curl -d '{"label":"Colibri dataset family","display":30}' -H "Content-Type: application/json" -X POST http://localhost/instance/default/dataset-family -curl -d '{"name":"anis_observation","table_ref":"anis_observation","label":"COLIBRI OBS","description":"colibri observations","display":10,"count":0,"vo":true,"data_path":"/mnt/mount","config":{"cone_search":{"enabled":true,"column_ra":2,"column_dec":3},"selectable_row":true},"project_name":"colibri"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/3/dataset +curl -d '{"name":"anis_observation","table_ref":"anis_observation","label":"COLIBRI OBS","description":"colibri observations","display":10,"count":0,"vo":true,"data_path":"/mnt/mount","config":{"cone_search":{"enabled":true,"column_ra":2,"column_dec":3},"selectable_row":true},"public":true,"project_name":"colibri"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/3/dataset # Add COLIBRI anis_observation default criteria family, output families and output categories curl -d '{"label":"Default criteria family","display":10}' -H "Content-Type: application/json" -X POST http://localhost/dataset/anis_observation/criteria-family @@ -140,3 +140,11 @@ curl -d '{"id":9,"name":"zflg","table_name":"aspic_vipers_dr2_w1","label":"zflg" curl -d '{"id":56,"name":"spec1d","table_name":"aspic_vipers_dr2_w1","label":"spec1d","form_label":"spec1d","description":null,"output_display":560,"criteria_display":560,"search_flag":"SPECTRUM_1D","search_type":null,"type":"text","operator":null,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"display_detail":560,"selected":true,"order_by":false,"order_display":560,"detail":true,"renderer_detail":"spectra_graph","options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":8}' -H "Content-Type: application/json" -X PUT http://localhost/dataset/vipers_dr2_w1/attribute/56 curl -d '{"id":57,"name":"spec1dnoise","table_name":"aspic_vipers_dr2_w1","label":"spec1dnoise","form_label":"spec1dnoise","description":null,"output_display":570,"criteria_display":570,"search_flag":null,"search_type":null,"type":"text","operator":null,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"display_detail":570,"selected":true,"order_by":false,"order_display":570,"detail":true,"renderer_detail":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":8}' -H "Content-Type: application/json" -X PUT http://localhost/dataset/vipers_dr2_w1/attribute/57 curl -d '{"id":58,"name":"spec1dsky","table_name":"aspic_vipers_dr2_w1","label":"spec1dsky","form_label":"spec1dsky","description":null,"output_display":580,"criteria_display":580,"search_flag":null,"search_type":null,"type":"text","operator":null,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"display_detail":580,"selected":true,"order_by":false,"order_display":580,"detail":true,"renderer_detail":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":8}' -H "Content-Type: application/json" -X PUT http://localhost/dataset/vipers_dr2_w1/attribute/58 + +# Add users +curl -d '{"email":"charles.degaulle@lam.fr"}' -H "Content-Type: application/json" -X POST http://localhost/user +curl -d '{"email":"georges.pompidou@lam.fr"}' -H "Content-Type: application/json" -X POST http://localhost/user + +# Add groups +curl -d '{"label":"SVOM","users":["charles.degaulle@lam.fr"],"datasets":["obs_cat","observations"]}' -H "Content-Type: application/json" -X POST http://localhost/group +curl -d '{"label":"ASPIC","users":[],"datasets":[]}' -H "Content-Type: application/json" -X POST http://localhost/group diff --git a/src/Action/DatasetAction.php b/src/Action/DatasetAction.php index 052fb8baa32c452babc6a5408d9a1644fa715b8d..466a3d5eb74d46bb33076610a474dd6202d89730 100644 --- a/src/Action/DatasetAction.php +++ b/src/Action/DatasetAction.php @@ -48,7 +48,7 @@ final class DatasetAction extends AbstractAction 'Dataset with name ' . $args['name'] . ' is not found' ); } - + if ($request->getMethod() === GET) { $payload = json_encode($dataset, JSON_UNESCAPED_SLASHES); } @@ -65,6 +65,7 @@ final class DatasetAction extends AbstractAction 'vo', 'data_path', 'config', + 'public', 'id_dataset_family' ); foreach ($fields as $a) { @@ -84,7 +85,7 @@ final class DatasetAction extends AbstractAction 'Dataset family with id ' . $parsedBody['id_dataset_family'] . ' is not found' ); } - + $this->editDataset($dataset, $parsedBody, $family); $payload = json_encode($dataset, JSON_UNESCAPED_SLASHES); } @@ -117,6 +118,7 @@ final class DatasetAction extends AbstractAction $dataset->setVo($parsedBody['vo']); $dataset->setDataPath($parsedBody['data_path']); $dataset->setConfig($parsedBody['config']); + $dataset->setPublic($parsedBody['public']); $this->em->flush(); } } diff --git a/src/Action/DatasetListAction.php b/src/Action/DatasetListAction.php index 7d721011431123aa16c44265cc544e8e76a2bf5b..071def9300bed2668dae7204223f0dd13965d0b6 100644 --- a/src/Action/DatasetListAction.php +++ b/src/Action/DatasetListAction.php @@ -84,6 +84,7 @@ final class DatasetListAction extends AbstractAction 'vo', 'data_path', 'config', + 'public', 'project_name' ); foreach ($fields as $a) { @@ -136,6 +137,7 @@ final class DatasetListAction extends AbstractAction $dataset->setVo($parsedBody['vo']); $dataset->setDataPath($parsedBody['data_path']); $dataset->setConfig($parsedBody['config']); + $dataset->setPublic($parsedBody['public']); $dataset->setProject($project); $dataset->setDatasetFamily($datasetFamily); diff --git a/src/Action/GroupAction.php b/src/Action/GroupAction.php new file mode 100644 index 0000000000000000000000000000000000000000..0d9f21f480ae5905fd03a16dd0d96a5b7eb52a45 --- /dev/null +++ b/src/Action/GroupAction.php @@ -0,0 +1,122 @@ +getMethod() === OPTIONS) { + return $response->withHeader('Access-Control-Allow-Methods', 'GET, PUT, DELETE, OPTIONS'); + } + + // Search the correct group with primary key + $group = $this->em->find('App\Entity\Group', $args['id']); + + // If group is not found 404 + if (is_null($group)) { + throw new HttpNotFoundException( + $request, + 'Group with id ' . $args['id'] . ' is not found' + ); + } + + if ($request->getMethod() === GET) { + $payload = json_encode($group); + } + + if ($request->getMethod() === PUT) { + $parsedBody = $request->getParsedBody(); + + // If mandatories empty fields 400 + foreach (array('label') as $a) { + if ($this->isEmptyField($a, $parsedBody)) { + throw new HttpBadRequestException( + $request, + 'Param ' . $a . ' needed to edit the group' + ); + } + } + + $this->editGroup($group, $parsedBody); + $payload = json_encode($group); + } + + if ($request->getMethod() === DELETE) { + $id = $group->getId(); + $this->em->remove($group); + $this->em->flush(); + $payload = json_encode(array('message' => 'Group with id ' . $id . ' is removed!')); + } + + $response->getBody()->write($payload); + return $response; + } + + /** + * Update group object with setters + * + * @param Group $group The group to update + * @param array $parsedBody Contains the new values ​​of the group sent by the user + */ + private function editGroup(Group $group, array $parsedBody): void + { + $group->setLabel($parsedBody['label']); + $group->setUsers($this->getUsers($parsedBody['users'])); + $group->setDatasets($this->getDatasets($parsedBody['datasets'])); + $this->em->flush(); + } + + private function getUsers(array $listOfUsersIds) + { + if (count($listOfUsersIds) < 1) { + return array(); + } + + $dql = 'SELECT u FROM App\Entity\User u WHERE u.id IN (' . implode(',', $listOfUsersIds) . ')'; + $query = $this->em->createQuery($dql); + return $query->getResult(); + } + + private function getDatasets(array $listOfDatasetsNames) + { + if (count($listOfDatasetsNames) < 1) { + return array(); + } + + $in = implode(',', array_map(function ($d) { + return "'" . $d . "'"; + }, $listOfDatasetsNames)); + + $dql = 'SELECT d FROM App\Entity\Dataset d WHERE d.name IN (' . $in . ')'; + $query = $this->em->createQuery($dql); + return $query->getResult(); + } +} diff --git a/src/Action/GroupListAction.php b/src/Action/GroupListAction.php new file mode 100644 index 0000000000000000000000000000000000000000..3acf86769eac5e8cba01e0d13ca7e382ca79b593 --- /dev/null +++ b/src/Action/GroupListAction.php @@ -0,0 +1,114 @@ +getMethod() === OPTIONS) { + return $response->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); + } + + if ($request->getMethod() === GET) { + // Retrieve group with id + $groups = $this->em->getRepository('App\Entity\Group')->findAll(); + $payload = json_encode($groups); + } + + if ($request->getMethod() === POST) { + $parsedBody = $request->getParsedBody(); + + // To work this action needs group information + foreach (array('label') as $a) { + if ($this->isEmptyField($a, $parsedBody)) { + throw new HttpBadRequestException( + $request, + 'Param ' . $a . ' needed to add a new group' + ); + } + } + + $group = $this->postGroup($parsedBody); + $payload = json_encode($group); + $response = $response->withStatus(201); + } + + $response->getBody()->write($payload); + return $response; + } + + /** + * Add a new group into the metamodel + * + * @param array $parsedBody Contains the values ​​of the new group sent by the user + */ + private function postGroup(array $parsedBody): Group + { + $group = new Group( + $this->getUsers($parsedBody['users']), + $this->getDatasets($parsedBody['datasets']) + ); + $group->setLabel($parsedBody['label']); + + $this->em->persist($group); + $this->em->flush(); + + return $group; + } + + private function getUsers(array $listOfUsersEmails) + { + if (count($listOfUsersEmails) < 1) { + return array(); + } + + $in = implode(',', array_map(function ($u) { + return "'" . $u . "'"; + }, $listOfUsersEmails)); + + $dql = 'SELECT u FROM App\Entity\User u WHERE u.email IN (' . $in . ')'; + $query = $this->em->createQuery($dql); + return $query->getResult(); + } + + private function getDatasets(array $listOfDatasetsNames) + { + if (count($listOfDatasetsNames) < 1) { + return array(); + } + + $in = implode(',', array_map(function ($d) { + return "'" . $d . "'"; + }, $listOfDatasetsNames)); + + $dql = 'SELECT d FROM App\Entity\Dataset d WHERE d.name IN (' . $in . ')'; + $query = $this->em->createQuery($dql); + return $query->getResult(); + } +} diff --git a/src/Action/ProjectAction.php b/src/Action/ProjectAction.php index 138b1cd49ef499bc4aaffcabc864d50d846b6e98..6c55379c08d5a8b021ea0fade59188af7e4fa6bc 100644 --- a/src/Action/ProjectAction.php +++ b/src/Action/ProjectAction.php @@ -55,7 +55,7 @@ final class ProjectAction extends AbstractAction if ($request->getMethod() === PUT) { $parsedBody = $request->getParsedBody(); - + // If mandatories empty fields 400 foreach (array('label', 'description', 'link', 'manager', 'id_database') as $a) { if ($this->isEmptyField($a, $parsedBody)) { diff --git a/src/Action/SearchAction.php b/src/Action/SearchAction.php index b15d43cce8014dca805567a6bfcc172195ebc539..35ed1b459bcfe50f9e00a75de60e25d023cbc332 100644 --- a/src/Action/SearchAction.php +++ b/src/Action/SearchAction.php @@ -83,7 +83,7 @@ final class SearchAction extends AbstractAction $connection = $this->connectionFactory->create($dataset->getProject()->getDatabase()); $queryBuilder = $connection->createQueryBuilder(); $queryBuilder->from($dataset->getTableRef()); - + $queryParams = $request->getQueryParams(); // The parameter "a" is mandatory diff --git a/src/Action/UserAction.php b/src/Action/UserAction.php new file mode 100644 index 0000000000000000000000000000000000000000..0d7cb8c1c3cf4218a95d8666ac17fcde92c5e8c4 --- /dev/null +++ b/src/Action/UserAction.php @@ -0,0 +1,94 @@ +getMethod() === OPTIONS) { + return $response->withHeader('Access-Control-Allow-Methods', 'GET, PUT, DELETE, OPTIONS'); + } + + // Search the correct user with primary key + $user = $this->em->find('App\Entity\User', $args['email']); + + // If user is not found 404 + if (is_null($user)) { + throw new HttpNotFoundException( + $request, + 'User with email ' . $args['email'] . ' is not found' + ); + } + + if ($request->getMethod() === GET) { + $payload = json_encode($user); + } + + if ($request->getMethod() === PUT) { + $parsedBody = $request->getParsedBody(); + + // If mandatories empty fields 400 + foreach (array('role') as $a) { + if ($this->isEmptyField($a, $parsedBody)) { + throw new HttpBadRequestException( + $request, + 'Param ' . $a . ' needed to edit the user' + ); + } + } + + $this->editUser($user, $parsedBody); + $payload = json_encode($user); + } + + if ($request->getMethod() === DELETE) { + $email = $user->getEmail(); + $this->em->remove($user); + $this->em->flush(); + $payload = json_encode(array('message' => 'User with email ' . $email . ' is removed!')); + } + + $response->getBody()->write($payload); + return $response; + } + + /** + * Update user object with setters + * + * @param User $user The user to update + * @param array $parsedBody Contains the new values ​​of the user + */ + private function editUser(User $user, array $parsedBody): void + { + $user->setRole($parsedBody['role']); + $this->em->flush(); + } +} diff --git a/src/Action/UserListAction.php b/src/Action/UserListAction.php new file mode 100644 index 0000000000000000000000000000000000000000..d5c921a7801ed1986ff775049de84bb44000cc55 --- /dev/null +++ b/src/Action/UserListAction.php @@ -0,0 +1,80 @@ +getMethod() === OPTIONS) { + return $response->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); + } + + if ($request->getMethod() === GET) { + $users = $this->em->getRepository('App\Entity\User')->findAll(); + $payload = json_encode($users); + } + + if ($request->getMethod() === POST) { + $parsedBody = $request->getParsedBody(); + + // To work this action needs user information + foreach (array('email') as $a) { + if ($this->isEmptyField($a, $parsedBody)) { + throw new HttpBadRequestException( + $request, + 'Param ' . $a . ' needed to add a new user' + ); + } + } + + $user = $this->postUser($parsedBody); + $payload = json_encode($user); + $response = $response->withStatus(201); + } + + $response->getBody()->write($payload); + return $response; + } + + /** + * Add a new user into the metamodel + * + * @param array $parsedBody Contains the values ​​of the new user + */ + private function postUser(array $parsedBody): User + { + $user = new User($parsedBody['email']); + $user->setRole('user'); + + $this->em->persist($user); + $this->em->flush(); + + return $user; + } +} diff --git a/src/Entity/Attribute.php b/src/Entity/Attribute.php index 8eddc35f1516ce7c58067a5b7db2a6f78f28b6c6..cec28a29d1c6c0a49239bb34d3884fb9bd47a3d6 100644 --- a/src/Entity/Attribute.php +++ b/src/Entity/Attribute.php @@ -134,7 +134,7 @@ class Attribute implements \JsonSerializable * @Column(type="string", name="placeholder_min", nullable=true) */ protected $placeholderMin; - + /** * @var string * diff --git a/src/Entity/CriteriaFamily.php b/src/Entity/CriteriaFamily.php index 3317abc9a9f4c6e5b9efe30c88327ea4c2f769ae..00fda78c8e31891622c5679d0604c950173b423e 100644 --- a/src/Entity/CriteriaFamily.php +++ b/src/Entity/CriteriaFamily.php @@ -26,7 +26,7 @@ class CriteriaFamily implements \JsonSerializable * @GeneratedValue */ protected $id; - + /** * @var string * @@ -58,12 +58,12 @@ class CriteriaFamily implements \JsonSerializable { return $this->id; } - + public function getLabel() { return $this->label; } - + public function setLabel($label) { $this->label = $label; diff --git a/src/Entity/Dataset.php b/src/Entity/Dataset.php index c9261420190ce3766536d6334db91f666f7f7cf1..4038240b4e19f40e9f6542258a51b32d7e5dd668 100644 --- a/src/Entity/Dataset.php +++ b/src/Entity/Dataset.php @@ -27,42 +27,42 @@ class Dataset implements \JsonSerializable * @Column(type="string", nullable=false) */ protected $name; - + /** * @var string * * @Column(type="string", name="table_ref", nullable=false) */ protected $tableRef; - + /** * @var string * * @Column(type="string", nullable=false) */ protected $label; - + /** * @var string * * @Column(type="text", nullable=true) */ protected $description; - + /** * @var int * * @Column(type="integer", nullable=false) */ protected $display; - + /** * @var int * * @Column(type="integer", nullable=true) */ protected $count; - + /** * @var bool * @@ -83,7 +83,14 @@ class Dataset implements \JsonSerializable * @Column(type="json", nullable=true) */ protected $config; - + + /** + * @var bool + * + * @Column(type="boolean", nullable=false) + */ + protected $public; + /** * @var Anis\Entity\Project * @@ -99,7 +106,7 @@ class Dataset implements \JsonSerializable * @JoinColumn(name="id_dataset_family", referencedColumnName="id", nullable=false) */ protected $datasetFamily; - + /** * @var Anis\Entity\Attribute[] * @@ -112,72 +119,72 @@ class Dataset implements \JsonSerializable $this->name = $name; $this->attributes = new ArrayCollection(); } - + public function getName() { return $this->name; } - + public function getTableRef() { return $this->tableRef; } - + public function setTableRef($tableRef) { $this->tableRef = $tableRef; } - + public function getLabel() { return $this->label; } - + public function setLabel($label) { $this->label = $label; } - + public function getDescription() { return $this->description; } - + public function setDescription($description) { $this->description = $description; } - + public function getDisplay() { return $this->display; } - + public function setDisplay($display) { $this->display = $display; } - + public function getCount() { return $this->count; } - + public function setCount($count) { $this->count = $count; } - + public function getVo() { return $this->vo; } - + public function setVo($vo) { $this->vo = $vo; } - + public function getDataPath() { return $this->dataPath; @@ -198,11 +205,21 @@ class Dataset implements \JsonSerializable $this->config = $config; } + public function getPublic() + { + return $this->public; + } + + public function setPublic($public) + { + $this->public = $public; + } + public function getProject() { return $this->project; } - + public function setProject($project) { $this->project = $project; @@ -235,6 +252,7 @@ class Dataset implements \JsonSerializable 'vo' => $this->getVo(), 'data_path' => $this->getDataPath(), 'config' => $this->getConfig(), + 'public' => $this->getPublic(), 'project_name' => $this->getProject()->getName(), 'id_dataset_family' => $this->getDatasetFamily()->getId() ]; diff --git a/src/Entity/DatasetFamily.php b/src/Entity/DatasetFamily.php index d0da25d977fa8a22f535f4bd41ca3a18a89088f1..a05357808ef2fc0aa5b7478d88cfccc24729d1cd 100644 --- a/src/Entity/DatasetFamily.php +++ b/src/Entity/DatasetFamily.php @@ -28,7 +28,7 @@ class DatasetFamily implements \JsonSerializable * @GeneratedValue */ protected $id; - + /** * @var string * diff --git a/src/Entity/DatasetPrivileges.php b/src/Entity/DatasetPrivileges.php deleted file mode 100644 index 8fbc8d0a1234a8d23c10eaeddebc04a8c7651b0c..0000000000000000000000000000000000000000 --- a/src/Entity/DatasetPrivileges.php +++ /dev/null @@ -1,54 +0,0 @@ -dataset = $dataset; - $this->group = $group; - } - - public function getDataset() - { - return $this->dataset; - } - - public function getGroup() - { - return $this->group; - } -} diff --git a/src/Entity/Group.php b/src/Entity/Group.php index 4391206d865201ebf0db9cfe83f3ae26cb1d8fd4..c3b48aa6dce469056f596a45a4c303313e638d8c 100644 --- a/src/Entity/Group.php +++ b/src/Entity/Group.php @@ -12,6 +12,9 @@ declare(strict_types=1); namespace App\Entity; +use Doctrine\Common\Collections\Collection; +use Doctrine\Common\Collections\ArrayCollection; + /** * @Entity * @Table(name="anis_group") @@ -35,11 +38,34 @@ class Group implements \JsonSerializable protected $label; /** - * @var Anis\Entity\DatasetPrivileges + * Many Groups have Many Users. + * + * @ManyToMany(targetEntity="User", inversedBy="groups") + * @JoinTable( + * name="groups_users", + * joinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}, + * inverseJoinColumns={@JoinColumn(name="user_email", referencedColumnName="email")} + * ) + */ + protected $users; + + /** + * Many Groups have Many Datasets privileges. * - * @OneToMany(targetEntity="DatasetPrivileges", mappedBy="group") + * @ManyToMany(targetEntity="Dataset") + * @JoinTable( + * name="groups_datasets", + * joinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}, + * inverseJoinColumns={@JoinColumn(name="dataset_name", referencedColumnName="name")} + * ) */ - protected $datasetPrivileges; + protected $datasets; + + public function __construct(array $users, array $datasets) + { + $this->users = new ArrayCollection($users); + $this->datasets = new ArrayCollection($datasets); + } public function getId() { @@ -56,16 +82,43 @@ class Group implements \JsonSerializable $this->label = $label; } - public function getDatasetPrivileges() + public function getUsers() { - return $this->datasetPrivileges; + return $this->users; + } + + public function setUsers($users) + { + $this->users = $users; + } + + public function getDatasets() + { + return $this->datasets; + } + + public function setDatasets($datasets) + { + $this->datasets = $datasets; } public function jsonSerialize() { + $users = array(); + foreach ($this->getUsers() as $user) { + $users[] = $user->getEmail(); + } + + $datasets = array(); + foreach ($this->getDatasets() as $dataset) { + $datasets[] = $dataset->getName(); + } + return [ 'id' => $this->getId(), - 'label' => $this->getLabel() + 'label' => $this->getLabel(), + 'users' => $users, + 'datasets' => $datasets ]; } } diff --git a/src/Entity/OutputCategory.php b/src/Entity/OutputCategory.php index 877bd4dcef6d890cb9ee4dadc5d656fcedd48499..0fddfd58626eebe0cd91456e3dc58b24d00ebac9 100644 --- a/src/Entity/OutputCategory.php +++ b/src/Entity/OutputCategory.php @@ -48,7 +48,7 @@ class OutputCategory implements \JsonSerializable * @JoinColumn(name="output_family", referencedColumnName="id", nullable=false) */ protected $outputFamily; - + public function getId() { return $this->id; @@ -78,7 +78,7 @@ class OutputCategory implements \JsonSerializable { $this->outputFamily = $outputFamily; } - + public function getOutputFamily() { return $this->outputFamily; diff --git a/src/Entity/OutputFamily.php b/src/Entity/OutputFamily.php index ee5ef98fe96d032e3961bb7cf87e47b39fbd28b8..740c19b9ed4370b0fc7b6062d0660f593840d503 100644 --- a/src/Entity/OutputFamily.php +++ b/src/Entity/OutputFamily.php @@ -26,7 +26,7 @@ class OutputFamily implements \JsonSerializable * @GeneratedValue */ protected $id; - + /** * @var string * @@ -58,12 +58,12 @@ class OutputFamily implements \JsonSerializable { return $this->id; } - + public function getLabel() { return $this->label; } - + public function setLabel($label) { $this->label = $label; diff --git a/src/Entity/User.php b/src/Entity/User.php index f130bbfb3150ba6c72d1ba1b40d0174822b34461..5a867a88590dfb61ccd4ea56f456e28d577d281f 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -12,6 +12,9 @@ declare(strict_types=1); namespace App\Entity; +use Doctrine\Common\Collections\Collection; +use Doctrine\Common\Collections\ArrayCollection; + /** * @Entity * @Table(name="anis_user") @@ -27,16 +30,23 @@ class User implements \JsonSerializable protected $email; /** - * @var Anis\Entity\Group + * @var string * - * @ManyToOne(targetEntity="Group") - * @JoinColumn(name="group_id", referencedColumnName="id", nullable=true) + * @Column(type="string", nullable=false) */ - protected $group; + protected $role; - public function __construct(string $email) + /** + * Many Users have Many Groups. + * + * @ManyToMany(targetEntity="Group", mappedBy="users") + */ + protected $groups; + + public function __construct($email) { - return $this->email = $email; + $this->email = $email; + $this->groups = new ArrayCollection(); } public function getEmail() @@ -44,21 +54,32 @@ class User implements \JsonSerializable return $this->email; } - public function getGroup() + public function getRole() { - return $this->group; + return $this->role; } - public function setGroup($group) + public function setRole($role) { - $this->group = $group; + $this->role = $role; + } + + public function getGroups() + { + return $this->groups; } public function jsonSerialize() { + $groups = array(); + foreach ($this->getGroups() as $group) { + $groups[] = $group->getId(); + } + return [ 'email' => $this->getEmail(), - 'id_group' => $this->getGroup()->getId() + 'role' => $this->getRole(), + 'groups' => $groups ]; } } diff --git a/src/Utils/Operator/JsonPostgres.php b/src/Utils/Operator/JsonPostgres.php index 94adbb01263ca7495e31c2287e36dbd8f86a2465..c5dbe7dc8d0d82338582bba752b5bcf6048edd65 100644 --- a/src/Utils/Operator/JsonPostgres.php +++ b/src/Utils/Operator/JsonPostgres.php @@ -72,7 +72,7 @@ class JsonPostgres extends Operator } else { $newValue = $this->value; } - + return $this->getSqlValue(json_encode($newValue)); } } diff --git a/src/Utils/Operator/OperatorFactory.php b/src/Utils/Operator/OperatorFactory.php index 7a80e6926c96f5685ea3d4b8ddcccb4c0bae65a1..c854a8f0019313ac7ac8019220e943d765bdb88b 100644 --- a/src/Utils/Operator/OperatorFactory.php +++ b/src/Utils/Operator/OperatorFactory.php @@ -100,7 +100,7 @@ class OperatorFactory implements IOperatorFactory throw OperatorException::operatorBadNumberOfParameters($type, 1); } return new NotLike($expr, $column, $columnType, $parameters[0]); - + case 'in': if (count($parameters) < 1) { throw OperatorException::inBadNumberOfParameters($type); diff --git a/tests/Action/AttributeActionTest.php b/tests/Action/AttributeActionTest.php index 55e33f1b2d66bbf7aaee6588a724f6cff692e7cb..5ba59710c813c206746727da921dda9ae8d947b3 100644 --- a/tests/Action/AttributeActionTest.php +++ b/tests/Action/AttributeActionTest.php @@ -228,6 +228,7 @@ final class AttributeActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); @@ -256,7 +257,7 @@ final class AttributeActionTest extends TestCase $attribute->setSelected(true); $this->entityManager->persist($attribute); $this->entityManager->flush(); - + return $attribute; } } diff --git a/tests/Action/AttributeListActionTest.php b/tests/Action/AttributeListActionTest.php index 15decb8329c9cc7dc92c1751efe7fc461f8d86c7..0cda65f54a9f7508376ccce361c3d46151f1de3c 100644 --- a/tests/Action/AttributeListActionTest.php +++ b/tests/Action/AttributeListActionTest.php @@ -132,6 +132,7 @@ final class AttributeListActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); diff --git a/tests/Action/CriteriaFamilyActionTest.php b/tests/Action/CriteriaFamilyActionTest.php index b17941694ec7f3112725884ab71e03eec7fd0a99..87cf07acfec6004a0428411c5138a7e06cdf8513 100644 --- a/tests/Action/CriteriaFamilyActionTest.php +++ b/tests/Action/CriteriaFamilyActionTest.php @@ -178,6 +178,7 @@ final class CriteriaFamilyActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); diff --git a/tests/Action/CriteriaFamilyListActionTest.php b/tests/Action/CriteriaFamilyListActionTest.php index d5ffdd194d6fe2807e85ddefcc1d6e747b72c82f..f749e0156543707337ad4037e9680e87750c09bf 100644 --- a/tests/Action/CriteriaFamilyListActionTest.php +++ b/tests/Action/CriteriaFamilyListActionTest.php @@ -179,6 +179,7 @@ final class CriteriaFamilyListActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); diff --git a/tests/Action/DatasetActionTest.php b/tests/Action/DatasetActionTest.php index ff6e15f2654ba9c4332639c54396c0bd75c83f34..45dd902803aab9515164c0beab1ea3ec316699b2 100644 --- a/tests/Action/DatasetActionTest.php +++ b/tests/Action/DatasetActionTest.php @@ -135,6 +135,7 @@ final class DatasetActionTest extends TestCase 'vo' => false, 'data_path' => '/mnt/dataset1', 'config' => '{}', + 'public' => true, 'id_dataset_family' => 1 ); } @@ -198,6 +199,7 @@ final class DatasetActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); diff --git a/tests/Action/DatasetListActionTest.php b/tests/Action/DatasetListActionTest.php index 5629542a1cff02c2a02688085e23d3856189afc0..acd412234df4e210f9739df6c1520beaf26bf514 100644 --- a/tests/Action/DatasetListActionTest.php +++ b/tests/Action/DatasetListActionTest.php @@ -126,6 +126,7 @@ final class DatasetListActionTest extends TestCase 'vo' => false, 'data_path' => '/mnt/dataset1', 'config' => '{}', + 'public' => true, 'project_name' => 'anis_project', 'id_dataset_family' => 1 ); @@ -190,6 +191,7 @@ final class DatasetListActionTest extends TestCase $dataset1->setCount(10000); $dataset1->setVo(false); $dataset1->setDataPath('/mnt/dataset1'); + $dataset1->setPublic(true); $dataset1->setProject($project); $dataset1->setDatasetFamily($family); $this->entityManager->persist($dataset1); @@ -202,6 +204,7 @@ final class DatasetListActionTest extends TestCase $dataset2->setCount(5000); $dataset2->setVo(false); $dataset2->setDataPath('/mnt/dataset2'); + $dataset2->setPublic(true); $dataset2->setProject($project); $dataset2->setDatasetFamily($family); $this->entityManager->persist($dataset2); diff --git a/tests/Action/DatasetListByInstanceActionTest.php b/tests/Action/DatasetListByInstanceActionTest.php index 48a498a8069f646a54373afa3154424c69ac785f..9594892d5c5df6b4b60ec1e70cc1d48ab51f504b 100644 --- a/tests/Action/DatasetListByInstanceActionTest.php +++ b/tests/Action/DatasetListByInstanceActionTest.php @@ -130,6 +130,7 @@ final class DatasetListByInstanceActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); @@ -142,6 +143,7 @@ final class DatasetListByInstanceActionTest extends TestCase $dataset2->setCount(5000); $dataset2->setVo(false); $dataset2->setDataPath('/mnt/observations'); + $dataset2->setPublic(true); $dataset2->setProject($project); $dataset2->setDatasetFamily($family); $this->entityManager->persist($dataset2); diff --git a/tests/Action/OutputCategoryActionTest.php b/tests/Action/OutputCategoryActionTest.php index 4d6777e432297377464049ce52219aa68399a188..fc4d8db2f8080dc48d0e0130e4bc488e35bb7757 100644 --- a/tests/Action/OutputCategoryActionTest.php +++ b/tests/Action/OutputCategoryActionTest.php @@ -197,6 +197,7 @@ final class OutputCategoryActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); diff --git a/tests/Action/OutputCategoryListActionTest.php b/tests/Action/OutputCategoryListActionTest.php index 07903d15bdcf978050e8ab5829771c45286340bd..1d2f976377e34183d16b68dab1aa08d1e866cd88 100644 --- a/tests/Action/OutputCategoryListActionTest.php +++ b/tests/Action/OutputCategoryListActionTest.php @@ -173,6 +173,7 @@ final class OutputCategoryListActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); diff --git a/tests/Action/OutputCategoryListByDatasetActionTest.php b/tests/Action/OutputCategoryListByDatasetActionTest.php index cbb719f315419ee14c41a3f2d433c618371730b9..990ebf0c252ac6e272204258aed6270672693f4c 100644 --- a/tests/Action/OutputCategoryListByDatasetActionTest.php +++ b/tests/Action/OutputCategoryListByDatasetActionTest.php @@ -147,6 +147,7 @@ final class OutputCategoryListByDatasetActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); diff --git a/tests/Action/OutputFamilyActionTest.php b/tests/Action/OutputFamilyActionTest.php index aa1874d86569431e56b7948190f3039f858f34bd..90bfcabfcc318e70bcc3ac939bb2de7db32f2ac4 100644 --- a/tests/Action/OutputFamilyActionTest.php +++ b/tests/Action/OutputFamilyActionTest.php @@ -178,6 +178,7 @@ final class OutputFamilyActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); diff --git a/tests/Action/OutputFamilyListActionTest.php b/tests/Action/OutputFamilyListActionTest.php index 2da33a686429b949f10713a4b0b82513b1cad135..b7e20c24a47fd839680cd850926e8934e4e0337c 100644 --- a/tests/Action/OutputFamilyListActionTest.php +++ b/tests/Action/OutputFamilyListActionTest.php @@ -179,6 +179,7 @@ final class OutputFamilyListActionTest extends TestCase $dataset->setCount(10000); $dataset->setVo(false); $dataset->setDataPath('/mnt/obs_cat'); + $dataset->setPublic(true); $dataset->setProject($project); $dataset->setDatasetFamily($family); $this->entityManager->persist($dataset); diff --git a/tests/Middleware/CorsMiddlewareTest.php b/tests/Middleware/CorsMiddlewareTest.php index 7e76f2394d971bded23dfbcf2caa762509e6e51d..42649183f08720e22a3674e80359bb6c9779df50 100644 --- a/tests/Middleware/CorsMiddlewareTest.php +++ b/tests/Middleware/CorsMiddlewareTest.php @@ -40,7 +40,7 @@ final class CorsMiddlewareTest extends TestCase (string) $response->getHeaderLine('Access-Control-Allow-Headers') ); } - + public function testCorsHeadersForGetMethod() { $request = new ServerRequest('GET', '/');