diff --git a/features/api/general_conventions.feature b/features/api/general_conventions.feature new file mode 100644 index 0000000000..f1018e2167 --- /dev/null +++ b/features/api/general_conventions.feature @@ -0,0 +1,121 @@ +@api +Feature: + In order to display general conventions informations + As an anonymous user + I should be able to list and read general conventions + + Scenario: As an anonymous user, I can list general conventions + And I send a "GET" request to "/api/general_conventions?page_size=10" + Then the response status code should be 200 + And the response should be in JSON + And the JSON should be equal to: + """ + { + "metadata": { + "total_items": 3, + "items_per_page": 10, + "count": 3, + "current_page": 1, + "last_page": 1 + }, + "items": [ + { + "department_zone": { + "uuid": "@uuid@", + "type": "department", + "code": "92", + "name": "Hauts-de-Seine" + }, + "committee_zone": null, + "district_zone": null, + "organizer": "assembly", + "reported_at": "@string@.isDateTime()", + "meeting_type": "on_site", + "members_count": 0, + "participant_quality": "adherent", + "uuid": "c5317499-7130-4255-a7f8-418e72f5dfa5" + }, + { + "department_zone": { + "uuid": "@uuid@", + "type": "department", + "code": "92", + "name": "Hauts-de-Seine" + }, + "committee_zone": { + "uuid": "@uuid@", + "type": "city", + "code": "92024", + "name": "Clichy" + }, + "district_zone": null, + "organizer": "committee", + "reported_at": "@string@.isDateTime()", + "meeting_type": "remote", + "members_count": 20, + "participant_quality": "sympathizer", + "uuid": "b3a2b082-01fc-4306-9fdb-6559ebe765b1" + }, + { + "department_zone": { + "uuid": "@uuid@", + "type": "department", + "code": "92", + "name": "Hauts-de-Seine" + }, + "committee_zone": null, + "district_zone": { + "uuid": "@uuid@", + "type": "district", + "code": "92-4", + "name": "Hauts-de-Seine (4)" + }, + "organizer": "district", + "reported_at": "@string@.isDateTime()", + "meeting_type": "remote", + "members_count": 10, + "participant_quality": "adherent_before", + "uuid": "54c9ae4c-3e2d-475d-8993-54639ec58ea1" + } + ] + } + """ + + Scenario: As an anonymous user, I can get informations of a general convention + And I send a "GET" request to "/api/general_conventions/c5317499-7130-4255-a7f8-418e72f5dfa5" + Then the response status code should be 200 + And the response should be in JSON + And the JSON should be equal to: + """ + { + "department_zone": { + "uuid": "@uuid@", + "type": "department", + "code": "92", + "name": "Hauts-de-Seine" + }, + "committee_zone": null, + "district_zone": null, + "organizer": "assembly", + "reported_at": "@string@.isDateTime()", + "meeting_type": "on_site", + "members_count": 0, + "participant_quality": "adherent", + "general_summary": null, + "party_definition_summary": null, + "unique_party_summary": null, + "progress_since2016": null, + "party_objectives": null, + "governance": null, + "communication": null, + "militant_training": null, + "member_journey": null, + "mobilization": null, + "talent_detection": null, + "election_preparation": null, + "relationship_with_supporters": null, + "work_with_partners": null, + "additional_comments": null, + "uuid": "c5317499-7130-4255-a7f8-418e72f5dfa5" + } + """ diff --git a/migrations/2025/Version20250131104505.php b/migrations/2025/Version20250131111843.php similarity index 97% rename from migrations/2025/Version20250131104505.php rename to migrations/2025/Version20250131111843.php index 7365561f03..983590cfcf 100644 --- a/migrations/2025/Version20250131104505.php +++ b/migrations/2025/Version20250131111843.php @@ -5,13 +5,13 @@ use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; -final class Version20250131104505 extends AbstractMigration +final class Version20250131111843 extends AbstractMigration { public function up(Schema $schema): void { $this->addSql('CREATE TABLE general_convention ( id INT UNSIGNED AUTO_INCREMENT NOT NULL, - department_zone_id INT UNSIGNED DEFAULT NULL, + department_zone_id INT UNSIGNED NOT NULL, committee_zone_id INT UNSIGNED DEFAULT NULL, district_zone_id INT UNSIGNED DEFAULT NULL, reporter_id INT UNSIGNED DEFAULT NULL, diff --git a/src/Admin/GeneralConventionAdmin.php b/src/Admin/GeneralConventionAdmin.php index 0970d375f6..3c476bf115 100644 --- a/src/Admin/GeneralConventionAdmin.php +++ b/src/Admin/GeneralConventionAdmin.php @@ -101,9 +101,10 @@ protected function configureFormFields(FormMapper $form): void ]) ->add('reportedAt', null, [ 'label' => 'Date de la remontée', + 'widget' => 'single_text', ]) ->add('meetingType', EnumType::class, [ - 'label' => 'Instance organisatrice', + 'label' => 'Type de réunion', 'class' => MeetingTypeEnum::class, 'choice_label' => function (MeetingTypeEnum $meetingType) { return 'general_convention.meeting_type.'.$meetingType->value; diff --git a/src/DataFixtures/ORM/LoadGeneralConventionData.php b/src/DataFixtures/ORM/LoadGeneralConventionData.php index fd752f73c3..8da5b6b32f 100644 --- a/src/DataFixtures/ORM/LoadGeneralConventionData.php +++ b/src/DataFixtures/ORM/LoadGeneralConventionData.php @@ -13,9 +13,15 @@ use Doctrine\Persistence\ObjectManager; use Faker\Factory; use Faker\Generator; +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\UuidInterface; class LoadGeneralConventionData extends Fixture implements DependentFixtureInterface { + private const UUID_1 = 'c5317499-7130-4255-a7f8-418e72f5dfa5'; + private const UUID_2 = 'b3a2b082-01fc-4306-9fdb-6559ebe765b1'; + private const UUID_3 = '54c9ae4c-3e2d-475d-8993-54639ec58ea1'; + private Generator $faker; public function __construct() @@ -26,6 +32,7 @@ public function __construct() public function load(ObjectManager $manager): void { $manager->persist($this->createGeneralConvention( + Uuid::fromString(self::UUID_1), LoadGeoZoneData::getZoneReference($manager, 'zone_department_92'), OrganizerEnum::ASSEMBLY, MeetingTypeEnum::ON_SITE, @@ -35,6 +42,7 @@ public function load(ObjectManager $manager): void )); $manager->persist($this->createGeneralConvention( + Uuid::fromString(self::UUID_2), LoadGeoZoneData::getZoneReference($manager, 'zone_department_92'), OrganizerEnum::COMMITTEE, MeetingTypeEnum::REMOTE, @@ -62,6 +70,7 @@ public function load(ObjectManager $manager): void )); $manager->persist($this->createGeneralConvention( + Uuid::fromString(self::UUID_3), LoadGeoZoneData::getZoneReference($manager, 'zone_department_92'), OrganizerEnum::DISTRICT, MeetingTypeEnum::REMOTE, @@ -92,6 +101,7 @@ public function load(ObjectManager $manager): void } private function createGeneralConvention( + UuidInterface $uuid, Zone $departmentZone, OrganizerEnum $organizer, MeetingTypeEnum $meetingType, @@ -117,7 +127,7 @@ private function createGeneralConvention( ?string $workWithPartners = null, ?string $additionalComments = null, ): GeneralConvention { - $generalConvention = new GeneralConvention(); + $generalConvention = new GeneralConvention($uuid); $generalConvention->departmentZone = $departmentZone; $generalConvention->organizer = $organizer; diff --git a/src/Entity/EntityIdentityTrait.php b/src/Entity/EntityIdentityTrait.php index c76ce0f153..2e2a5e257f 100644 --- a/src/Entity/EntityIdentityTrait.php +++ b/src/Entity/EntityIdentityTrait.php @@ -123,6 +123,8 @@ trait EntityIdentityTrait 'event_registration_list', 'zone_based_role_read', 'zone_based_role_write', + 'general_convention_list', + 'general_convention_read', ])] #[ORM\Column(type: 'uuid', unique: true)] protected $uuid; diff --git a/src/Entity/GeneralConvention/GeneralConvention.php b/src/Entity/GeneralConvention/GeneralConvention.php index fe73a37470..a7864c25f1 100644 --- a/src/Entity/GeneralConvention/GeneralConvention.php +++ b/src/Entity/GeneralConvention/GeneralConvention.php @@ -2,6 +2,9 @@ namespace App\Entity\GeneralConvention; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; use App\Entity\Adherent; use App\Entity\EntityAdministratorBlameableTrait; use App\Entity\EntityIdentityTrait; @@ -12,10 +15,23 @@ use App\GeneralConvention\ParticipantQuality; use Doctrine\ORM\Mapping as ORM; use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\UuidInterface; +use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Validator\Constraints as Assert; +#[ApiResource( + operations: [ + new GetCollection( + uriTemplate: '/general_conventions', + normalizationContext: ['groups' => ['general_convention_list']], + ), + new Get( + uriTemplate: '/general_conventions/{uuid}', + normalizationContext: ['groups' => ['general_convention_read']], + ), + ], +)] #[ORM\Entity] -#[ORM\Table(name: 'general_convention')] class GeneralConvention { use EntityIdentityTrait; @@ -23,92 +39,114 @@ class GeneralConvention use EntityAdministratorBlameableTrait; #[Assert\NotBlank] + #[Groups(['general_convention_list', 'general_convention_read'])] + #[ORM\JoinColumn(nullable: false)] #[ORM\ManyToOne(targetEntity: Zone::class)] public ?Zone $departmentZone = null; - #[ORM\JoinColumn(nullable: true)] + #[Groups(['general_convention_list', 'general_convention_read'])] #[ORM\ManyToOne(targetEntity: Zone::class)] public ?Zone $committeeZone = null; - #[ORM\JoinColumn(nullable: true)] + #[Groups(['general_convention_list', 'general_convention_read'])] #[ORM\ManyToOne(targetEntity: Zone::class)] public ?Zone $districtZone = null; #[Assert\NotBlank] #[Assert\Type(type: OrganizerEnum::class)] + #[Groups(['general_convention_list', 'general_convention_read'])] #[ORM\Column(enumType: OrganizerEnum::class)] public ?OrganizerEnum $organizer = null; #[Assert\NotBlank] - #[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')] + #[ORM\JoinColumn(onDelete: 'SET NULL')] #[ORM\ManyToOne(targetEntity: Adherent::class)] public ?Adherent $reporter = null; #[Assert\NotBlank] + #[Groups(['general_convention_list', 'general_convention_read'])] #[ORM\Column(type: 'datetime')] public ?\DateTimeInterface $reportedAt = null; #[Assert\NotBlank] #[Assert\Type(type: MeetingTypeEnum::class)] + #[Groups(['general_convention_list', 'general_convention_read'])] #[ORM\Column(enumType: MeetingTypeEnum::class)] public ?MeetingTypeEnum $meetingType = null; + #[Groups(['general_convention_list', 'general_convention_read'])] #[ORM\Column(type: 'smallint', options: ['unsigned' => true, 'default' => 0])] public int $membersCount = 0; #[Assert\NotBlank] #[Assert\Type(type: ParticipantQuality::class)] + #[Groups(['general_convention_list', 'general_convention_read'])] #[ORM\Column(enumType: ParticipantQuality::class)] public ?ParticipantQuality $participantQuality = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $generalSummary = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $partyDefinitionSummary = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $uniquePartySummary = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $progressSince2016 = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $partyObjectives = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $governance = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $communication = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $militantTraining = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $memberJourney = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $mobilization = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $talentDetection = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $electionPreparation = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $relationshipWithSupporters = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $workWithPartners = null; + #[Groups(['general_convention_read'])] #[ORM\Column(type: 'text', nullable: true)] public ?string $additionalComments = null; - public function __construct() + public function __construct(?UuidInterface $uuid = null) { - $this->uuid = Uuid::uuid4(); + $this->uuid = $uuid ?? Uuid::uuid4(); } public function __toString(): string diff --git a/src/Entity/Geo/GeoTrait.php b/src/Entity/Geo/GeoTrait.php index 18620bd27a..3b12da65b5 100644 --- a/src/Entity/Geo/GeoTrait.php +++ b/src/Entity/Geo/GeoTrait.php @@ -25,14 +25,14 @@ trait GeoTrait /** * @var string */ - #[Groups(['zone_read', 'department_read', 'region_read', 'survey_list', 'survey_list_dc', 'survey_read_dc', 'scopes', 'scope', 'jecoute_news_read_dc', 'audience_read', 'audience_segment_read', 'phoning_campaign_read', 'team_read', 'team_list_read', 'pap_campaign_read', 'pap_campaign_read_after_write', 'phoning_campaign_read', 'phoning_campaign_list', 'read_api', 'department_site_read', 'department_site_read_list', 'elected_representative_read', 'elected_representative_list', 'formation_list_read', 'formation_read', 'elected_mandate_read', 'adherent_elect_read', 'general_meeting_report_list_read', 'general_meeting_report_read', 'committee:read', 'zone:code,type', 'managed_users_list', 'managed_user_read', 'procuration_request_read', 'procuration_request_list', 'procuration_proxy_list', 'procuration_matched_proxy', 'action_read', 'profile_read', 'zone_based_role_read'])] + #[Groups(['zone_read', 'department_read', 'region_read', 'survey_list', 'survey_list_dc', 'survey_read_dc', 'scopes', 'scope', 'jecoute_news_read_dc', 'audience_read', 'audience_segment_read', 'phoning_campaign_read', 'team_read', 'team_list_read', 'pap_campaign_read', 'pap_campaign_read_after_write', 'phoning_campaign_read', 'phoning_campaign_list', 'read_api', 'department_site_read', 'department_site_read_list', 'elected_representative_read', 'elected_representative_list', 'formation_list_read', 'formation_read', 'elected_mandate_read', 'adherent_elect_read', 'general_meeting_report_list_read', 'general_meeting_report_read', 'committee:read', 'zone:code,type', 'managed_users_list', 'managed_user_read', 'procuration_request_read', 'procuration_request_list', 'procuration_proxy_list', 'procuration_matched_proxy', 'action_read', 'profile_read', 'zone_based_role_read', 'general_convention_list', 'general_convention_read'])] #[ORM\Column(unique: true)] private $code; /** * @var string */ - #[Groups(['zone_read', 'department_read', 'region_read', 'survey_list', 'survey_list_dc', 'survey_read_dc', 'scopes', 'scope', 'jecoute_news_read_dc', 'audience_read', 'audience_segment_read', 'phoning_campaign_read', 'team_read', 'team_list_read', 'pap_campaign_read', 'pap_campaign_read_after_write', 'phoning_campaign_read', 'phoning_campaign_list', 'department_site_read', 'department_site_read_list', 'elected_representative_read', 'elected_representative_list', 'formation_list_read', 'formation_read', 'elected_mandate_read', 'adherent_elect_read', 'general_meeting_report_list_read', 'general_meeting_report_read', 'committee:read', 'managed_users_list', 'managed_user_read', 'procuration_request_read', 'procuration_request_list', 'procuration_proxy_list', 'procuration_matched_proxy', 'action_read', 'profile_read', 'zone_based_role_read'])] + #[Groups(['zone_read', 'department_read', 'region_read', 'survey_list', 'survey_list_dc', 'survey_read_dc', 'scopes', 'scope', 'jecoute_news_read_dc', 'audience_read', 'audience_segment_read', 'phoning_campaign_read', 'team_read', 'team_list_read', 'pap_campaign_read', 'pap_campaign_read_after_write', 'phoning_campaign_read', 'phoning_campaign_list', 'department_site_read', 'department_site_read_list', 'elected_representative_read', 'elected_representative_list', 'formation_list_read', 'formation_read', 'elected_mandate_read', 'adherent_elect_read', 'general_meeting_report_list_read', 'general_meeting_report_read', 'committee:read', 'managed_users_list', 'managed_user_read', 'procuration_request_read', 'procuration_request_list', 'procuration_proxy_list', 'procuration_matched_proxy', 'action_read', 'profile_read', 'zone_based_role_read', 'general_convention_list', 'general_convention_read'])] #[ORM\Column] private $name; diff --git a/src/Entity/Geo/Zone.php b/src/Entity/Geo/Zone.php index 20292b71c4..c022f471f1 100644 --- a/src/Entity/Geo/Zone.php +++ b/src/Entity/Geo/Zone.php @@ -95,14 +95,14 @@ class Zone implements GeoInterface, UuidEntityInterface * @var UuidInterface */ #[ApiProperty(identifier: true, openapiContext: ['type' => 'string', 'format' => 'uuid', 'example' => 'b4219d47-3138-5efd-9762-2ef9f9495084'])] - #[Groups(['zone_read', 'survey_write_dc', 'scopes', 'scope', 'jecoute_news_read_dc', 'audience_read', 'audience_segment_read', 'survey_list_dc', 'survey_read_dc', 'team_read', 'team_list_read', 'pap_campaign_read', 'pap_campaign_read_after_write', 'phoning_campaign_read', 'phoning_campaign_list', 'department_site_read', 'department_site_read_list', 'elected_representative_read', 'elected_representative_list', 'formation_list_read', 'formation_read', 'formation_write', 'elected_mandate_read', 'adherent_elect_read', 'general_meeting_report_list_read', 'general_meeting_report_read', 'committee:read', 'managed_users_list', 'managed_user_read', 'procuration_request_read', 'procuration_request_list', 'procuration_proxy_list', 'procuration_matched_proxy', 'general_meeting_report_write', 'elected_mandate_write', 'action_read', 'department_site_write', 'committee:write', 'audience_write', 'profile_read', 'zone_based_role_write', 'zone_based_role_read'])] + #[Groups(['zone_read', 'survey_write_dc', 'scopes', 'scope', 'jecoute_news_read_dc', 'audience_read', 'audience_segment_read', 'survey_list_dc', 'survey_read_dc', 'team_read', 'team_list_read', 'pap_campaign_read', 'pap_campaign_read_after_write', 'phoning_campaign_read', 'phoning_campaign_list', 'department_site_read', 'department_site_read_list', 'elected_representative_read', 'elected_representative_list', 'formation_list_read', 'formation_read', 'formation_write', 'elected_mandate_read', 'adherent_elect_read', 'general_meeting_report_list_read', 'general_meeting_report_read', 'committee:read', 'managed_users_list', 'managed_user_read', 'procuration_request_read', 'procuration_request_list', 'procuration_proxy_list', 'procuration_matched_proxy', 'general_meeting_report_write', 'elected_mandate_write', 'action_read', 'department_site_write', 'committee:write', 'audience_write', 'profile_read', 'zone_based_role_write', 'zone_based_role_read', 'general_convention_list', 'general_convention_read'])] #[ORM\Column(type: 'uuid', unique: true)] protected $uuid; /** * @var string */ - #[Groups(['zone_read', 'scope', 'read_api', 'committee:read', 'zone:code,type', 'managed_users_list', 'managed_user_read', 'procuration_request_read', 'procuration_request_list', 'procuration_proxy_list', 'procuration_matched_proxy', 'action_read', 'profile_read', 'zone_based_role_read'])] + #[Groups(['zone_read', 'scope', 'read_api', 'committee:read', 'zone:code,type', 'managed_users_list', 'managed_user_read', 'procuration_request_read', 'procuration_request_list', 'procuration_proxy_list', 'procuration_matched_proxy', 'action_read', 'profile_read', 'zone_based_role_read', 'general_convention_list', 'general_convention_read'])] #[ORM\Column] private $type;