diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index 7850bbee4..4a4e59f4b 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -16,6 +16,7 @@ use Chill\ThirdPartyBundle\Entity\ThirdParty; use Symfony\Component\Serializer\Exception\RuntimeException; use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; +use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\MainBundle\Entity\Scope; class AccompanyingCourseApiController extends ApiController @@ -83,6 +84,11 @@ class AccompanyingCourseApiController extends ApiController return $this->addRemoveSomething('comment', $id, $request, $_format, 'comment', Comment::class); } + public function socialIssueApi($id, Request $request, string $_format): Response + { + return $this->addRemoveSomething('socialissue', $id, $request, $_format, 'socialIssue', SocialIssue::class, [ 'groups' => [ 'read' ] ]); + } + public function requestorApi($id, Request $request, string $_format): Response { /** @var AccompanyingPeriod $accompanyingPeriod */ diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index dabe009c9..26cff4f55 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -389,7 +389,20 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, Request::METHOD_DELETE=> \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE ] - ] + ], + 'socialissue' => [ + 'methods' => [ + Request::METHOD_POST => true, + Request::METHOD_DELETE => true, + Request::METHOD_GET => false, + Request::METHOD_HEAD => false, + ], + 'controller_action' => 'socialIssueApi', + 'roles' => [ + Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, + Request::METHOD_DELETE=> \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE + ] + ], ] ], diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index fbe90b312..e7f8385e1 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -249,6 +249,7 @@ class AccompanyingPeriod * @ORM\JoinTable( * name="chill_person_accompanying_period_social_issues" * ) + * @Groups({"read"}) */ private Collection $socialIssues; @@ -727,14 +728,14 @@ class AccompanyingPeriod return $this->socialIssues; } - public function addSocialIssues(SocialIssue $socialIssue): self + public function addSocialIssue(SocialIssue $socialIssue): self { $this->socialIssues[] = $socialIssue; return $this; } - public function removeSocialIssue(SocialIssue $socialissue): void + public function removeSocialIssue(SocialIssue $socialIssue): void { $this->socialIssues->removeElement($socialIssue); } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php index cdbbd0afc..716048966 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php @@ -27,6 +27,7 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\ThirdPartyBundle\Entity\ThirdParty; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Center; @@ -87,6 +88,41 @@ class AccompanyingCourseApiControllerTest extends WebTestCase $this->assertEquals(404, $response->getStatusCode(), "Test that the response of rest api has a status code 'not found' (404)"); } + /** + * + * @dataProvider dataGenerateRandomAccompanyingCourseWithSocialIssue + */ + public function testAccompanyingCourseAddRemoveSocialIssue(AccompanyingPeriod $period, SocialIssue $si) + { + $this->client->request( + Request::METHOD_POST, + sprintf('/api/1.0/person/accompanying-course/%d/socialissue.json', $period->getId()), + [], + [], + [], + \json_encode([ 'type' => 'social_issue', 'id' => $si->getId() ]) + ); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + + $data = \json_decode($this->client->getResponse()->getContent(), true); + $this->assertArrayHasKey('id', $data); + $this->assertArrayHasKey('type', $data); + $this->assertEquals('social_issue', $data['type']); + + + $this->client->request( + Request::METHOD_DELETE, + sprintf('/api/1.0/person/accompanying-course/%d/socialissue.json', $period->getId()), + [], + [], + [], + \json_encode([ 'type' => 'social_issue', 'id' => $si->getId() ]) + ); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + } + /** * @dataProvider dataGenerateRandomRequestorValidData */ @@ -425,6 +461,53 @@ class AccompanyingCourseApiControllerTest extends WebTestCase } } + public function dataGenerateRandomAccompanyingCourseWithSocialIssue() + { + // note about max result for person query, and maxGenerated: + // + // in the final loop, an id is popped out of the personIds array twice: + // + // * one for getting the person, which will in turn provide his accompanying period; + // * one for getting the personId to populate to the data manager + // + // Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :) + $maxGenerated = 3; + $maxResults = $maxGenerated * 8; + + static::bootKernel(); + $em = static::$container->get(EntityManagerInterface::class); + $center = $em->getRepository(Center::class) + ->findOneBy(array('name' => 'Center A')); + + $personIds = $em->createQuery("SELECT p.id FROM ". + Person::class." p ". + " WHERE p.center = :center") + ->setParameter('center', $center) + ->setMaxResults($maxResults) + ->getScalarResult(); + + // create a random order + shuffle($personIds); + + $socialIssues = $em->createQuery("SELECT s FROM ". + SocialIssue::class." s ") + ->setMaxResults(10) + ->getResult(); + + $nbGenerated = 0; + while ($nbGenerated < $maxGenerated) { + $id = \array_pop($personIds)["id"]; + + $person = $em->getRepository(Person::class) + ->find($id); + $periods = $person->getAccompanyingPeriods(); + + yield [$periods[\array_rand($periods)], $socialIssues[\array_rand($socialIssues)] ]; + + $nbGenerated++; + } + } + public function dataGenerateRandomAccompanyingCourse() { // note about max result for person query, and maxGenerated: diff --git a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml index bfbd025e0..9010686e8 100644 --- a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml +++ b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml @@ -84,6 +84,8 @@ components: required: - id - type + + # ok to stay here AccompanyingPeriod: type: object properties: @@ -147,6 +149,33 @@ components: required: - id - type + SocialIssue: + type: object + properties: + id: + type: integer + type: + type: string + enum: + - 'social_issue' + parent_id: + type: integer + readOnly: true + children_ids: + type: array + items: + type: integer + readOnly: true + title: + type: object + additionalProperties: + type: string + example: + fr: Accompagnement Social Adulte + readOnly: true + text: + type: string + readOnly: true paths: /1.0/person/accompanying-course/{id}.json: @@ -534,3 +563,68 @@ paths: description: "OK" 422: description: "object with validation errors" + + /1.0/person/accompanying-course/{id}/socialissue.json: + post: + tags: + - person + summary: "Add a social issue to the accompanying course" + parameters: + - name: id + in: path + required: true + description: The accompanying period's id + schema: + type: integer + format: integer + minimum: 1 + requestBody: + description: "A social issue by id" + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SocialIssue' + examples: + add a social issue: + value: + type: social_issue + id: 5 + responses: + 401: + description: "Unauthorized" + 404: + description: "Not found" + 200: + description: "OK" + 422: + description: "object with validation errors" + delete: + tags: + - person + summary: "Remove the social issue" + parameters: + - name: id + in: path + required: true + description: The accompanying period's id + schema: + type: integer + format: integer + minimum: 1 + requestBody: + description: "A social issue with his id" + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SocialIssue' + responses: + 401: + description: "Unauthorized" + 404: + description: "Not found" + 200: + description: "OK" + 422: + description: "object with validation errors"