diff --git a/api/src/Entity/Activity.php b/api/src/Entity/Activity.php index 3ca1837966..81291e5351 100644 --- a/api/src/Entity/Activity.php +++ b/api/src/Entity/Activity.php @@ -16,6 +16,7 @@ use App\Repository\ActivityRepository; use App\State\ActivityCreateProcessor; use App\State\ActivityRemoveProcessor; +use App\State\ActivityResetProcessor; use App\Validator\AssertBelongsToSameCamp; use App\Validator\AssertLastCollectionItemIsNotDeleted; use Doctrine\Common\Collections\ArrayCollection; @@ -24,6 +25,7 @@ use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\SerializedName; use Symfony\Component\Validator\Constraints as Assert; +use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation; /** * A piece of programme that will be carried out once or multiple times in a camp. @@ -39,6 +41,14 @@ security: 'is_granted("CAMP_MEMBER", object) or is_granted("CAMP_MANAGER", object)', validationContext: ['groups' => ['Default', 'update']] ), + new Patch( + processor: ActivityResetProcessor::class, + security: 'is_granted("CAMP_MANAGER", object)', + uriTemplate: 'activities/{id}/reset_contents', + denormalizationContext: ['groups' => ['reset_contents']], + openapi: new OpenApiOperation(summary: 'Delete all programme content from this activity and replace it with a copy of the content of the connected category.'), + validationContext: ['groups' => ['Default', 'reset_contents']] + ), new Delete( processor: ActivityRemoveProcessor::class, security: 'is_granted("CAMP_MEMBER", object) or is_granted("CAMP_MANAGER", object)' diff --git a/api/src/State/ActivityResetProcessor.php b/api/src/State/ActivityResetProcessor.php new file mode 100644 index 0000000000..d2ed6d1027 --- /dev/null +++ b/api/src/State/ActivityResetProcessor.php @@ -0,0 +1,60 @@ + + */ +class ActivityResetProcessor extends AbstractPersistProcessor { + public function __construct( + ProcessorInterface $decorated, + private EntityManagerInterface $em + ) { + parent::__construct($decorated); + } + + /** + * @param Activity $data + */ + public function onBefore($data, Operation $operation, array $uriVariables = [], array $context = []): Activity { + // @phpstan-ignore nullsafe.neverNull + if (!isset($data->category?->rootContentNode)) { + throw new \UnexpectedValueException('Property rootContentNode of provided category is null. Object of type '.ColumnLayout::class.' expected.'); + } + if (!$data->category->rootContentNode instanceof ColumnLayout) { + throw new \UnexpectedValueException('Property rootContentNode of provided category is of wrong type. Object of type '.ColumnLayout::class.' expected.'); + } + + // Delete the old content + $this->em->remove($data->rootContentNode); + + // Copy content from the category + $targetCamp = $data->category->camp; + $rootContentNodePrototype = $data->category->rootContentNode; + + $rootContentNode = new ColumnLayout(); + $rootContentNode->contentType = $this->em + ->getRepository(ContentType::class) + ->findOneBy(['name' => 'ColumnLayout']) + ; + $data->setRootContentNode($rootContentNode); + + $entityMap = new EntityMap($targetCamp); + $rootContentNode->copyFromPrototype($rootContentNodePrototype, $entityMap); + + return $data; + } + + private function deleteContent(Activity $activity): void { + + } +} diff --git a/frontend/src/components/category/CategoryTemplate.vue b/frontend/src/components/category/CategoryTemplate.vue index f453a21c59..068c36a443 100644 --- a/frontend/src/components/category/CategoryTemplate.vue +++ b/frontend/src/components/category/CategoryTemplate.vue @@ -4,6 +4,9 @@ + diff --git a/frontend/src/components/category/DialogApplyCategoryLayoutToActivities.vue b/frontend/src/components/category/DialogApplyCategoryLayoutToActivities.vue new file mode 100644 index 0000000000..85a6c8c08b --- /dev/null +++ b/frontend/src/components/category/DialogApplyCategoryLayoutToActivities.vue @@ -0,0 +1,224 @@ + + + diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 4c0834874f..38ca910df9 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -211,9 +211,20 @@ "category": { "categoryTemplate": { "contents": "Inhalte", - "createLayoutHelp": "Hier kannst du die Vorlage für neue {categoryShort}-Blöcke definieren.{br}Blockinhalt & Layout bereits erstellter {categoryShort}-Blöcke, werden nicht angepasst.", + "createLayoutHelp": "Hier kannst du die Vorlage für neue {categoryShort}-Blöcke definieren.{br}Blockinhalt & Layout bereits erstellter {categoryShort}-Blöcke, werden nicht automatisch angepasst. {applyToActivities}", "layout": "Layout", "noTemplate": "Keine Vorlage" + }, + "dialogApplyCategoryLayoutToActivities": { + "applyToActivities": "Layout und Inhalte der folgenden Aktivitäten überschreiben", + "confirmApply": "Aktivitäten überschreiben | 1 Aktivität überschreiben | {count} Aktivitäten überschreiben", + "description": "Du kannst das Layout und die Inhalte von {categoryShort} auf Aktivitäten übertragen.", + "lastChanged": "Zuletzt geändert", + "noContent": "Kein Inhalt", + "replaceActivityContents": "Aktivitäten überschreiben", + "risk": "Jegliche bereits erfasste Inhalte in der Aktivität gehen dabei unwiderruflich verloren. Fahre nur fort wenn du dir sicher bist.", + "templateForNewActivities": "Vorlage für neue {categoryShort}-Blöcke", + "title": "Auf Aktivitäten übertragen" } }, "checklist": { diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 26c2e8c2eb..1e3caa9fc4 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -211,7 +211,7 @@ "category": { "categoryTemplate": { "contents": "Contents", - "createLayoutHelp": "Here you can define the template for new {categoryShort} activities.{br}The content & layout of already created {categoryShort} activities will not be adjusted.", + "createLayoutHelp": "Here you can define the template for new {categoryShort} activities.{br}The content & layout of already created {categoryShort} activities will not be automatically adjusted. {applyToActivities}", "layout": "Layout", "noTemplate": "No template" } diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index a51ca2d1e2..cb0e3c19cf 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -211,7 +211,7 @@ "category": { "categoryTemplate": { "contents": "Contenus", - "createLayoutHelp": "Ici, vous pouvez définir le modèle pour de nouvelles activités {categoryShort}.{br}Le contenu et la mise en page des activités {categoryShort} déjà créées ne seront pas ajustés.", + "createLayoutHelp": "Ici, vous pouvez définir le modèle pour de nouvelles activités {categoryShort}.{br}Le contenu et la mise en page des activités {categoryShort} déjà créées ne seront pas ajustés. {applyToActivities}", "layout": "Layout", "noTemplate": "Pas de modèle" } diff --git a/frontend/src/locales/it.json b/frontend/src/locales/it.json index 0abde0d6eb..26eeea9351 100644 --- a/frontend/src/locales/it.json +++ b/frontend/src/locales/it.json @@ -176,7 +176,7 @@ "category": { "categoryTemplate": { "contents": "Contenuti", - "createLayoutHelp": "Qui puoi definire il modello per le nuove attività {categoryShort}.{br}Il contenuto e il layout delle attività {categoryShort} già create non verranno modificati.", + "createLayoutHelp": "Qui puoi definire il modello per le nuove attività {categoryShort}.{br}Il contenuto e il layout delle attività {categoryShort} già create non verranno modificati. {applyToActivities}", "layout": "Layout", "noTemplate": "Nessun modello" } diff --git a/frontend/src/locales/rm.json b/frontend/src/locales/rm.json index 10f235f61b..d614c6164f 100644 --- a/frontend/src/locales/rm.json +++ b/frontend/src/locales/rm.json @@ -135,7 +135,7 @@ "category": { "categoryTemplate": { "contents": "Cuntegns", - "createLayoutHelp": "Qua pudais vus definir il project per novas activitads da {categoryShort}.{br}Il cuntegn ed il layout ch'èn gia vegnidas fatgas da {categoryShort} na vegnan betg adattads.", + "createLayoutHelp": "Qua pudais vus definir il project per novas activitads da {categoryShort}.{br}Il cuntegn ed il layout ch'èn gia vegnidas fatgas da {categoryShort} na vegnan betg adattads. {applyToActivities}", "layout": "Layout", "noTemplate": "Nagin model" } diff --git a/frontend/src/views/camp/category/Category.vue b/frontend/src/views/camp/category/Category.vue index 8373e97118..44f82c170e 100644 --- a/frontend/src/views/camp/category/Category.vue +++ b/frontend/src/views/camp/category/Category.vue @@ -71,7 +71,7 @@