From 4286a51bf4c7103c96d635a25818ccc41aab8663 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 26 Oct 2023 11:23:47 +0200 Subject: [PATCH 01/60] create news item entity + migration --- .../ChillMainBundle/Entity/NewsItem.php | 188 ++++++++++++++++++ .../migrations/Version20231026091847.php | 48 +++++ 2 files changed, 236 insertions(+) create mode 100644 src/Bundle/ChillMainBundle/Entity/NewsItem.php create mode 100644 src/Bundle/ChillMainBundle/migrations/Version20231026091847.php diff --git a/src/Bundle/ChillMainBundle/Entity/NewsItem.php b/src/Bundle/ChillMainBundle/Entity/NewsItem.php new file mode 100644 index 000000000..375390bb5 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Entity/NewsItem.php @@ -0,0 +1,188 @@ +createdAt; + } + + public function getCreatedBy(): ?User + { + return $this->createdBy; + } + + public function getUpdatedAt(): ?\DateTimeInterface + { + return $this->updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; + } + + public function setCreatedAt(\DateTimeInterface $datetime): self + { + $this->createdAt = $datetime; + + return $this; + } + + public function setCreatedBy(User $user): self + { + $this->createdBy = $user; + + return $this; + } + + public function setUpdatedAt(\DateTimeInterface $datetime): self + { + $this->updatedAt = $datetime; + + return $this; + } + + public function setUpdatedBy(User $user): self + { + $this->updatedBy = $user; + + return $this; + } + + public function getTitle(): string + { + return $this->title; + } + + public function setTitle(string $title): void + { + $this->title = $title; + } + + public function getContent(): string + { + return $this->content; + } + + public function setContent(string $content): void + { + $this->content = $content; + } + + public function getStartDate(): ?\DateTimeImmutable + { + return $this->startDate; + } + + public function setStartDate(?\DateTimeImmutable $startDate): void + { + $this->startDate = $startDate; + } + + public function getEndDate(): ?\DateTimeImmutable + { + return $this->endDate; + } + + public function setEndDate(?\DateTimeImmutable $endDate): void + { + $this->endDate = $endDate; + } + + public function getId(): ?int + { + return $this->id; + } +} diff --git a/src/Bundle/ChillMainBundle/migrations/Version20231026091847.php b/src/Bundle/ChillMainBundle/migrations/Version20231026091847.php new file mode 100644 index 000000000..1c1b3138e --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20231026091847.php @@ -0,0 +1,48 @@ +addSql('CREATE SEQUENCE chill_main_news_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_main_news (id INT NOT NULL, title TEXT NOT NULL, content TEXT NOT NULL, startDate DATE NOT NULL, endDate DATE DEFAULT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, createdBy_id INT DEFAULT NULL, updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_96922AFB3174800F ON chill_main_news (createdBy_id)'); + $this->addSql('CREATE INDEX IDX_96922AFB65FF1AEC ON chill_main_news (updatedBy_id)'); + $this->addSql('COMMENT ON COLUMN chill_main_news.startDate IS \'(DC2Type:date_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_main_news.endDate IS \'(DC2Type:date_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_main_news.createdAt IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_main_news.updatedAt IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('ALTER TABLE chill_main_news ADD CONSTRAINT FK_96922AFB3174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_main_news ADD CONSTRAINT FK_96922AFB65FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema): void + { + $this->addSql('DROP SEQUENCE chill_main_news_id_seq CASCADE'); + $this->addSql('ALTER TABLE chill_main_news DROP CONSTRAINT FK_96922AFB3174800F'); + $this->addSql('ALTER TABLE chill_main_news DROP CONSTRAINT FK_96922AFB65FF1AEC'); + $this->addSql('DROP TABLE chill_main_news'); + } +} From a542d319f7d1a8441aec422eac0a70a51b659c6a Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 1 Nov 2023 16:25:14 +0100 Subject: [PATCH 02/60] create news item entity and the admin for it --- .../Controller/AdminController.php | 8 +++ .../Controller/NewsItemController.php | 26 ++++++++ .../ChillMainExtension.php | 46 +++++++++++++++ .../ChillMainBundle/Entity/NewsItem.php | 4 +- .../ChillMainBundle/Form/NewsItemType.php | 53 +++++++++++++++++ .../Repository/NewsItemRepository.php | 59 +++++++++++++++++++ .../views/Admin/indexDashboard.html.twig | 13 ++++ .../Resources/views/NewsItem/edit.html.twig | 11 ++++ .../Resources/views/NewsItem/index.html.twig | 33 +++++++++++ .../Resources/views/NewsItem/new.html.twig | 11 ++++ .../MenuBuilder/AdminNewsMenuBuilder.php | 45 ++++++++++++++ 11 files changed, 306 insertions(+), 3 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Controller/NewsItemController.php create mode 100644 src/Bundle/ChillMainBundle/Form/NewsItemType.php create mode 100644 src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php create mode 100644 src/Bundle/ChillMainBundle/Resources/views/Admin/indexDashboard.html.twig create mode 100644 src/Bundle/ChillMainBundle/Resources/views/NewsItem/edit.html.twig create mode 100644 src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig create mode 100644 src/Bundle/ChillMainBundle/Resources/views/NewsItem/new.html.twig create mode 100644 src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminNewsMenuBuilder.php diff --git a/src/Bundle/ChillMainBundle/Controller/AdminController.php b/src/Bundle/ChillMainBundle/Controller/AdminController.php index 7d3826823..46fbfb351 100644 --- a/src/Bundle/ChillMainBundle/Controller/AdminController.php +++ b/src/Bundle/ChillMainBundle/Controller/AdminController.php @@ -47,4 +47,12 @@ class AdminController extends AbstractController { return $this->render('@ChillMain/Admin/indexUser.html.twig'); } + + /** + * @Route("/{_locale}/admin/dashboard", name="chill_main_dashboard_admin") + */ + public function indexDashboardAction() + { + return $this->render('@ChillMain/Admin/indexDashboard.html.twig'); + } } diff --git a/src/Bundle/ChillMainBundle/Controller/NewsItemController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemController.php new file mode 100644 index 000000000..af36be9fc --- /dev/null +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemController.php @@ -0,0 +1,26 @@ +addOrderBy('e.id', 'ASC'); + + return parent::orderQuery($action, $query, $request, $paginator); + } +} diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 2590b549b..bc4929dfb 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -19,6 +19,8 @@ use Chill\MainBundle\Controller\CountryController; use Chill\MainBundle\Controller\LanguageController; use Chill\MainBundle\Controller\LocationController; use Chill\MainBundle\Controller\LocationTypeController; +use Chill\MainBundle\Controller\NewsItemApiController; +use Chill\MainBundle\Controller\NewsItemController; use Chill\MainBundle\Controller\RegroupmentController; use Chill\MainBundle\Controller\UserController; use Chill\MainBundle\Controller\UserJobApiController; @@ -53,6 +55,7 @@ use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Entity\Language; use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Entity\LocationType; +use Chill\MainBundle\Entity\NewsItem; use Chill\MainBundle\Entity\Regroupment; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\UserJob; @@ -62,6 +65,7 @@ use Chill\MainBundle\Form\CountryType; use Chill\MainBundle\Form\LanguageType; use Chill\MainBundle\Form\LocationFormType; use Chill\MainBundle\Form\LocationTypeType; +use Chill\MainBundle\Form\NewsItemType; use Chill\MainBundle\Form\RegroupmentType; use Chill\MainBundle\Form\UserJobType; use Chill\MainBundle\Form\UserType; @@ -544,6 +548,27 @@ class ChillMainExtension extends Extension implements ], ], ], + [ + 'class' => NewsItem::class, + 'name' => 'news_item', + 'base_path' => '/admin/news_item', + 'form_class' => NewsItemType::class, + 'controller' => NewsItemController::class, + 'actions' => [ + 'index' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillMain/NewsItem/index.html.twig', + ], + 'new' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillMain/NewsItem/new.html.twig', + ], + 'edit' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillMain/NewsItem/edit.html.twig', + ], + ], + ], ], 'apis' => [ [ @@ -767,6 +792,27 @@ class ChillMainExtension extends Extension implements ], ], ], + [ + 'class' => \Chill\MainBundle\Entity\NewsItem::class, + 'controller' => \Chill\MainBundle\Controller\NewsItemApiController::class, + 'name' => 'news-item', + 'base_path' => '/api/1.0/main/news', + 'base_role' => 'ROLE_USER', + 'actions' => [ + '_index' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + ], + '_entity' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + ], + ], + ], ], ]); } diff --git a/src/Bundle/ChillMainBundle/Entity/NewsItem.php b/src/Bundle/ChillMainBundle/Entity/NewsItem.php index 375390bb5..aa3ded5b0 100644 --- a/src/Bundle/ChillMainBundle/Entity/NewsItem.php +++ b/src/Bundle/ChillMainBundle/Entity/NewsItem.php @@ -20,9 +20,7 @@ use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Entity * - * @ORM\Table( - * name="chill_main_news", - * ) + * @ORM\Table(name="chill_main_news") */ class NewsItem implements TrackCreationInterface, TrackUpdateInterface { diff --git a/src/Bundle/ChillMainBundle/Form/NewsItemType.php b/src/Bundle/ChillMainBundle/Form/NewsItemType.php new file mode 100644 index 000000000..0318387ea --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/NewsItemType.php @@ -0,0 +1,53 @@ +add('title', TextType::class, [ + 'required' => true, + ]) + ->add('content', ChillTextareaType::class, [ + 'required' => true, + ]) + ->add( + 'startDate', + ChillDateType::class, + [ + 'required' => true, + ] + ) + ->add('endDate', ChillDateType::class, [ + 'required' => false, + ]); + } + + /** + * @return void + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefault('class', NewsItem::class); + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php new file mode 100644 index 000000000..09334a483 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -0,0 +1,59 @@ +repository = $entityManager->getRepository(NewsItem::class); + } + + /** + * @inheritDoc + */ + public function find($id) + { + $this->repository->find($id); + } + + /** + * @inheritDoc + */ + public function findAll() + { + return $this->repository->findAll(); + } + + /** + * @inheritDoc + */ + public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null) + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + /** + * @inheritDoc + */ + public function findOneBy(array $criteria) + { + return $this->repository->findOneBy($criteria); + } + + /** + * @inheritDoc + */ + public function getClassName() + { + return NewsItem::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Resources/views/Admin/indexDashboard.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Admin/indexDashboard.html.twig new file mode 100644 index 000000000..6f79e3d2a --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/Admin/indexDashboard.html.twig @@ -0,0 +1,13 @@ +{% extends "@ChillMain/Admin/layoutWithVerticalMenu.html.twig" %} + +{% block vertical_menu_content %} + {{ chill_menu('admin_news_item', { + 'layout': '@ChillMain/Admin/menu_admin_section.html.twig', + }) }} +{% endblock %} + +{% block layout_wvm_content %} + {% block admin_content %} +

{{ 'News configuration' |trans }}

+ {% endblock %} +{% endblock %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/edit.html.twig b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/edit.html.twig new file mode 100644 index 000000000..4d55c480c --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/edit.html.twig @@ -0,0 +1,11 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block title %} + {% include('@ChillMain/CRUD/_edit_title.html.twig') %} +{% endblock %} + +{% block admin_content %} + {% embed '@ChillMain/CRUD/_edit_content.html.twig' %} + {% block content_form_actions_save_and_show %}{% endblock %} + {% endembed %} +{% endblock admin_content %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig new file mode 100644 index 000000000..d5b2ea6cd --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig @@ -0,0 +1,33 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block admin_content %} + {% embed '@ChillMain/CRUD/_index.html.twig' %} + {% block table_entities_thead_tr %} + {{ 'Title'|trans }} + {{ 'news.startdate'|trans }} + {{ 'news.enddate'|trans }} + {% endblock %} + {% block table_entities_tbody %} + {% for entity in entities %} + + {{ entity.title }} + {{ entity.startDate }} + {{ entity.endDate }} + + + + + {% endfor %} + {% endblock %} + + {% block actions_before %} +
  • + {{'Back to the admin'|trans}} +
  • + {% endblock %} + {% endembed %} +{% endblock %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/new.html.twig b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/new.html.twig new file mode 100644 index 000000000..7c204dddd --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/new.html.twig @@ -0,0 +1,11 @@ +{% extends '@ChillMain/CRUD/Admin/index.html.twig' %} + +{% block title %} + {% include('@ChillMain/CRUD/_new_title.html.twig') %} +{% endblock %} + +{% block admin_content %} + {% embed '@ChillMain/CRUD/_new_content.html.twig' %} + {% block content_form_actions_save_and_show %}{% endblock %} + {% endembed %} +{% endblock admin_content %} diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminNewsMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminNewsMenuBuilder.php new file mode 100644 index 000000000..7d89d59f1 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminNewsMenuBuilder.php @@ -0,0 +1,45 @@ +authorizationChecker->isGranted('ROLE_ADMIN')) { + return; + } + + $menu->addChild('News', [ + 'route' => 'chill_main_dashboard_admin', + ]) + ->setAttribute('class', 'list-group-item-header') + ->setExtras([ + 'order' => 9000, + ]); + + $menu->addChild('NewsItem', [ + 'route' => 'chill_crud_news_item_index', + ])->setExtras(['order' => 9000]); + } + + public static function getMenuIds(): array + { + return ['admin_section', 'admin_news_item']; + } +} From 3a6d5fc22afc13995930565a3f0ae859eabe4d3c Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 1 Nov 2023 16:26:19 +0100 Subject: [PATCH 03/60] create API for news item + testing if fetch works : to be generalized to accomodate other types of dashboard items --- .../Controller/NewsItemApiController.php | 24 +++++++++++ .../public/vuejs/HomepageWidget/MyCustoms.vue | 6 +-- .../public/vuejs/HomepageWidget/js/store.js | 19 +++++++- .../Normalizer/NewsItemNormalizer.php | 43 +++++++++++++++++++ .../ChillMainBundle/chill.api.specs.yaml | 38 ++++++++++++++++ 5 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php create mode 100644 src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php diff --git a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php new file mode 100644 index 000000000..aa2bcb8bc --- /dev/null +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php @@ -0,0 +1,24 @@ +addOrderBy('e.startDate', 'ASC'); + } +} diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue index 5e9cb79df..1fe4dfd7c 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue @@ -1,7 +1,7 @@ @@ -70,7 +65,7 @@ export default { return { counterClass: { counter: true //hack to pass class 'counter' in i18n-t - } + }, } }, computed: { diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js index ab2e44b1d..1f9527b4f 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js @@ -24,7 +24,7 @@ const store = createStore({ workflows: {}, workflowsCc: {}, errorMsg: [], - newsItems: {}, + dashboardItems: {}, loading: false }, getters: { @@ -98,26 +98,26 @@ const store = createStore({ catchError(state, error) { state.errorMsg.push(error); }, - addNewsItems(state, newsItems) { - state.newsItems = newsItems; + addDashboardItems(state, dashboardItems) { + state.dashboardItems = dashboardItems; } }, actions: { + getDashboardItems({commit, getters}, { userId }) { + const url = `/api/1.0/main/dashboard-item/${userId}.json`; + makeFetch('GET', url) + .then((response) => { + console.log('dashboardItems', response.results) + commit('addDashboardItems', response); + }) + .catch((error) => { + commit('catchError', error); + throw error; + }) + ; + }, getByTab({ commit, getters }, { tab, param }) { switch (tab) { - case 'MyCustoms': - const url = `/api/1.0/main/news.json`; - makeFetch('GET', url) - .then((response) => { - console.log('news', response.results) - commit('addNewsItems', response); - }) - .catch((error) => { - commit('catchError', error); - throw error; - }) - ; - break; // case 'MyWorks': // if (!getters.isWorksLoaded) { // commit('setLoading', true); From 4646cd1cf03bf9475594d91a2d06b36523b65350 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 8 Nov 2023 12:59:01 +0100 Subject: [PATCH 10/60] create dashboard item entity --- .../ChillMainExtension.php | 6 +-- .../ChillMainBundle/Entity/DashboardItem.php | 53 +++++++++++++++++++ .../ChillMainBundle/Entity/NewsItem.php | 4 +- .../migrations/Version20231108115104.php | 39 ++++++++++++++ 4 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Entity/DashboardItem.php create mode 100644 src/Bundle/ChillMainBundle/migrations/Version20231108115104.php diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 6db465cc1..4355e0f56 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -792,10 +792,10 @@ class ChillMainExtension extends Extension implements ], ], ], -/* [ + [ 'class' => \Chill\MainBundle\Entity\DashboardItem::class, 'controller' => \Chill\MainBundle\Controller\DashboardApiController::class, - 'name' => 'news-item', + 'name' => 'dashboard-item', 'base_path' => '/api/1.0/main/dashboard-item', 'base_role' => 'ROLE_USER', 'actions' => [ @@ -812,7 +812,7 @@ class ChillMainExtension extends Extension implements ], ], ], - ],*/ + ], ], ]); } diff --git a/src/Bundle/ChillMainBundle/Entity/DashboardItem.php b/src/Bundle/ChillMainBundle/Entity/DashboardItem.php new file mode 100644 index 000000000..d849407bc --- /dev/null +++ b/src/Bundle/ChillMainBundle/Entity/DashboardItem.php @@ -0,0 +1,53 @@ +id; + } + + public function getType(): string + { + return $this->type; + } + + public function setType(string $type): self + { + $this->type = $type; + + return $this; + } +} diff --git a/src/Bundle/ChillMainBundle/Entity/NewsItem.php b/src/Bundle/ChillMainBundle/Entity/NewsItem.php index b35076101..c58acf48e 100644 --- a/src/Bundle/ChillMainBundle/Entity/NewsItem.php +++ b/src/Bundle/ChillMainBundle/Entity/NewsItem.php @@ -58,13 +58,13 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface private string $content = ''; /** - * @ORM\Column(type="string") + * @ORM\OneToOne (targetEntity="DashboardItem", inversedBy="newsItem") * * @groups({"write", "read"}) * * @Assert\NotNull */ - private string $type = 'news'; + private ?DashboardItem $dashboardItem = null; /** * @ORM\Column(type="date_immutable", nullable=false) diff --git a/src/Bundle/ChillMainBundle/migrations/Version20231108115104.php b/src/Bundle/ChillMainBundle/migrations/Version20231108115104.php new file mode 100644 index 000000000..d33001598 --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20231108115104.php @@ -0,0 +1,39 @@ +addSql('CREATE SEQUENCE chill_main_dashboard_item_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_main_dashboard_item (id INT NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); + $this->addSql('ALTER TABLE chill_main_news ADD dashboardItem_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_main_news DROP type'); + $this->addSql('ALTER TABLE chill_main_news ADD CONSTRAINT FK_96922AFBCBDA857A FOREIGN KEY (dashboardItem_id) REFERENCES chill_main_dashboard_item (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_96922AFBCBDA857A ON chill_main_news (dashboardItem_id)'); + $this->addSql('ALTER TABLE chill_main_notification ALTER addressesemails DROP DEFAULT'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_main_news DROP CONSTRAINT FK_96922AFBCBDA857A'); + $this->addSql('DROP SEQUENCE chill_main_dashboard_item_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_main_dashboard_item'); + $this->addSql('ALTER TABLE chill_main_news ADD type VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE chill_main_news DROP dashboardItem_id'); + } +} From 01a5c291e0f10f49df3065c853dc2af0d2c80d74 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 8 Nov 2023 14:00:53 +0100 Subject: [PATCH 11/60] fix admin form for news item --- src/Bundle/ChillMainBundle/Form/NewsItemType.php | 4 +++- .../Resources/views/NewsItem/index.html.twig | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Form/NewsItemType.php b/src/Bundle/ChillMainBundle/Form/NewsItemType.php index b29ea8801..0080acf1c 100644 --- a/src/Bundle/ChillMainBundle/Form/NewsItemType.php +++ b/src/Bundle/ChillMainBundle/Form/NewsItemType.php @@ -29,17 +29,19 @@ class NewsItemType extends AbstractType 'required' => true, ]) ->add('content', ChillTextareaType::class, [ - 'required' => true, + 'required' => false, ]) ->add( 'startDate', ChillDateType::class, [ 'required' => true, + 'input' => 'datetime_immutable' ] ) ->add('endDate', ChillDateType::class, [ 'required' => false, + 'input' => 'datetime_immutable' ]); } diff --git a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig index d5b2ea6cd..25c1555fb 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig @@ -11,12 +11,16 @@ {% for entity in entities %} {{ entity.title }} - {{ entity.startDate }} - {{ entity.endDate }} + {{ entity.startDate|date }} + {% if entity.endDate is not null %} + {{ entity.endDate|date }} + {% else %} + Pas de date de fin + {% endif %}
    • - +
    From 5a400fd1627349cd82eb8f3b9d26cafee6af7a48 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 8 Nov 2023 15:40:58 +0100 Subject: [PATCH 12/60] change logic of dashboard item to return user config, reinstate news items api --- .../Controller/DashboardApiController.php | 65 +++++------ .../ChillMainExtension.php | 27 ++++- .../Entity/DashboardConfigItem.php | 106 ++++++++++++++++++ .../ChillMainBundle/Entity/DashboardItem.php | 53 --------- .../ChillMainBundle/Entity/NewsItem.php | 20 ---- .../DashboardWidget/News/News.vue | 0 .../Normalizer/NewsItemNormalizer.php | 15 +-- .../ChillMainBundle/chill.api.specs.yaml | 53 ++++++--- .../migrations/Version20231108115104.php | 39 ------- ...08103723.php => Version20231108141141.php} | 15 ++- 10 files changed, 210 insertions(+), 183 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php delete mode 100644 src/Bundle/ChillMainBundle/Entity/DashboardItem.php create mode 100644 src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidget/News/News.vue delete mode 100644 src/Bundle/ChillMainBundle/migrations/Version20231108115104.php rename src/Bundle/ChillMainBundle/migrations/{Version20231108103723.php => Version20231108141141.php} (56%) diff --git a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php index ed0f55cfd..bc045a596 100644 --- a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php @@ -11,55 +11,40 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Core\Security; -class DashboardApiController extends ApiController +class DashboardApiController { - public function __construct(private readonly EntityManagerInterface $em) + public function __construct(private readonly Security $security) { } - /** - * Give an answer to a calendar invite. - * - * @Route("/api/1.0/main/dashboard-item/{user_id}.json", methods={"get"}) - */ - public function getDataForDashboard(int $userId): JsonResponse + public function setCrudConfig() { + return null; + } - //with the userId get the dashboard config for that user? - $user = $this->security->getUser(); - if (!$user instanceof User) { - throw new AccessDeniedHttpException('You must be an authenticated user'); - } + /** + * Give the user dashboard configuration + * + * @Route("/api/1.0/main/dashboard-config-item.json", methods={"post"}) + */ + public function getDashboardConfiguration(): JsonResponse + { + $data = [ + [ + 'position' => 'top-left', + 'id' => 1, + 'type' => 'news', + 'metadata' => [ + // arbitrary data that will be store "some time" + 'only_unread' => false, + ] + ] + ]; - $config = ['types' => ['news']]; - - //based on the user dashboard config fetch the items to be displayed - - $data = []; - - foreach ($config['types'] as $type) - { - switch ($type) { - case 'news': - $qb = $this->em->createQueryBuilder(); - $qb->select('n') - ->from(NewsItem::class) - ->where( - $qb->expr()->lt('n.endDate', ':today') - ); - - $qb->setParameter('today', new \DateTimeImmutable('now')); - - $newsItems = $qb->getQuery()->getResult(); - $data[] = $newsItems; - - break; - } - } - - return new JsonResponse($data, Response::HTTP_ACCEPTED, [], true); + return new JsonResponse($data); } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 4355e0f56..7e44ceb6b 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -793,10 +793,31 @@ class ChillMainExtension extends Extension implements ], ], [ - 'class' => \Chill\MainBundle\Entity\DashboardItem::class, + 'class' => \Chill\MainBundle\Entity\DashboardConfigItem::class, 'controller' => \Chill\MainBundle\Controller\DashboardApiController::class, - 'name' => 'dashboard-item', - 'base_path' => '/api/1.0/main/dashboard-item', + 'name' => 'dashboard-config-item', + 'base_path' => '/api/1.0/main/dashboard-config-item', + 'base_role' => 'ROLE_USER', + 'actions' => [ + '_index' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + ], + '_entity' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + ], + ], + ], + [ + 'class' => \Chill\MainBundle\Entity\NewsItem::class, + 'controller' => \Chill\MainBundle\Controller\NewsItemApiController::class, + 'name' => 'news-items', + 'base_path' => '/api/1.0/main/news', 'base_role' => 'ROLE_USER', 'actions' => [ '_index' => [ diff --git a/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php new file mode 100644 index 000000000..208c864e7 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php @@ -0,0 +1,106 @@ +id; + } + + public function getType(): string + { + return $this->type; + } + + public function setType(string $type): self + { + $this->type = $type; + + return $this; + } + + public function getPosition(): string + { + return $this->position; + } + + public function setPosition(string $position): void + { + $this->position = $position; + } + + public function getUser(): User + { + return $this->user; + } + + public function setUser(User $user): void + { + $this->user = $user; + } + + public function getMetadata(): array + { + return $this->metadata; + } + + public function setMetadata(array $metadata): void + { + $this->metadata = $metadata; + } +} diff --git a/src/Bundle/ChillMainBundle/Entity/DashboardItem.php b/src/Bundle/ChillMainBundle/Entity/DashboardItem.php deleted file mode 100644 index d849407bc..000000000 --- a/src/Bundle/ChillMainBundle/Entity/DashboardItem.php +++ /dev/null @@ -1,53 +0,0 @@ -id; - } - - public function getType(): string - { - return $this->type; - } - - public function setType(string $type): self - { - $this->type = $type; - - return $this; - } -} diff --git a/src/Bundle/ChillMainBundle/Entity/NewsItem.php b/src/Bundle/ChillMainBundle/Entity/NewsItem.php index c58acf48e..4febb9d98 100644 --- a/src/Bundle/ChillMainBundle/Entity/NewsItem.php +++ b/src/Bundle/ChillMainBundle/Entity/NewsItem.php @@ -57,15 +57,6 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface */ private string $content = ''; - /** - * @ORM\OneToOne (targetEntity="DashboardItem", inversedBy="newsItem") - * - * @groups({"write", "read"}) - * - * @Assert\NotNull - */ - private ?DashboardItem $dashboardItem = null; - /** * @ORM\Column(type="date_immutable", nullable=false) */ @@ -193,15 +184,4 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface return $this->id; } - public function getType(): string - { - return $this->type; - } - - public function setType(string $type): self - { - $this->type = $type; - - return $this; - } } diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidget/News/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidget/News/News.vue new file mode 100644 index 000000000..e69de29bb diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php index 306e8d182..fd3c510b7 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php @@ -24,18 +24,15 @@ class NewsItemNormalizer implements NormalizerInterface { public function __construct(private readonly CenterRepository $repository) {} - public function normalize($dashboardItem, $format = null, array $context = []) + public function normalize($newsItem, $format = null, array $context = []) { - /* @var DashboardItem $dashboardItem */ + /* @var NewsItem $newsItem */ return [ 'id' => $newsItem->getId(), - 'type' => $dashboardItem->getType(), - 'metadata' => [ - 'title' => $newsItem->getTitle(), - 'content' => $newsItem->getContent(), - 'startdate' => $newsItem->getStartDate(), - 'enddate' => $newsItem->getEndDate() - ], + 'title' => $newsItem->getTitle(), + 'content' => $newsItem->getContent(), + 'startdate' => $newsItem->getStartDate(), + 'enddate' => $newsItem->getEndDate() ]; } diff --git a/src/Bundle/ChillMainBundle/chill.api.specs.yaml b/src/Bundle/ChillMainBundle/chill.api.specs.yaml index 936712a11..8edbd93f6 100644 --- a/src/Bundle/ChillMainBundle/chill.api.specs.yaml +++ b/src/Bundle/ChillMainBundle/chill.api.specs.yaml @@ -137,7 +137,7 @@ components: id: type: integer - DashboardItem: + DashboardConfigItem: type: object properties: id: @@ -146,6 +146,24 @@ components: type: string metadata: type: object + userId: + type: integer + position: + type: string + + NewsItem: + type: object + properties: + id: + type: integer + title: + type: string + content: + type: string + startDate: + $ref: "#/components/schemas/Date" + endDate: + $ref: "#/components/schemas/Date" paths: @@ -859,20 +877,26 @@ paths: $ref: '#/components/schemas/Workflow' 403: description: "Unauthorized" - /1.0/main/dashboard-item/{user_id}.json: + /1.0/main/dashboard-config-item.json: get: tags: - - dashboard item - summary: Returns a list of dashboard items for the user in question - parameters: - - name: user_id - in: path - required: true - description: The user id - schema: - type: integer - format: integer - minimum: 1 + - dashboard config item + summary: Returns the dashboard configuration for the current user. + responses: + 200: + description: "ok" + content: + application/json: + schema: + $ref: '#/components/schemas/DashboardConfigItem' + 403: + description: "Unauthorized" + + /1.0/main/news.json: + get: + tags: + - news items + summary: Returns a list of news items responses: 200: description: "ok" @@ -881,7 +905,6 @@ paths: schema: type: array items: - $ref: '#/components/schemas/DashboardItem' + $ref: '#/components/schemas/NewsItem' 403: description: "Unauthorized" - diff --git a/src/Bundle/ChillMainBundle/migrations/Version20231108115104.php b/src/Bundle/ChillMainBundle/migrations/Version20231108115104.php deleted file mode 100644 index d33001598..000000000 --- a/src/Bundle/ChillMainBundle/migrations/Version20231108115104.php +++ /dev/null @@ -1,39 +0,0 @@ -addSql('CREATE SEQUENCE chill_main_dashboard_item_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); - $this->addSql('CREATE TABLE chill_main_dashboard_item (id INT NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); - $this->addSql('ALTER TABLE chill_main_news ADD dashboardItem_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_main_news DROP type'); - $this->addSql('ALTER TABLE chill_main_news ADD CONSTRAINT FK_96922AFBCBDA857A FOREIGN KEY (dashboardItem_id) REFERENCES chill_main_dashboard_item (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('CREATE UNIQUE INDEX UNIQ_96922AFBCBDA857A ON chill_main_news (dashboardItem_id)'); - $this->addSql('ALTER TABLE chill_main_notification ALTER addressesemails DROP DEFAULT'); - } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_main_news DROP CONSTRAINT FK_96922AFBCBDA857A'); - $this->addSql('DROP SEQUENCE chill_main_dashboard_item_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_main_dashboard_item'); - $this->addSql('ALTER TABLE chill_main_news ADD type VARCHAR(255) NOT NULL'); - $this->addSql('ALTER TABLE chill_main_news DROP dashboardItem_id'); - } -} diff --git a/src/Bundle/ChillMainBundle/migrations/Version20231108103723.php b/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php similarity index 56% rename from src/Bundle/ChillMainBundle/migrations/Version20231108103723.php rename to src/Bundle/ChillMainBundle/migrations/Version20231108141141.php index f2f924bc3..ffcc6130b 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20231108103723.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php @@ -8,34 +8,41 @@ use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; /** - * Create news item entity + * Create dashboard config item and news item */ -final class Version20231108103723 extends AbstractMigration +final class Version20231108141141 extends AbstractMigration { public function getDescription(): string { - return 'Create news item entity'; + return 'Create dashboard config item and news item'; } public function up(Schema $schema): void { + $this->addSql('CREATE SEQUENCE chill_main_dashboard_config_item_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE SEQUENCE chill_main_news_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); - $this->addSql('CREATE TABLE chill_main_news (id INT NOT NULL, title TEXT NOT NULL, content TEXT NOT NULL, type VARCHAR(255) NOT NULL, startDate DATE NOT NULL, endDate DATE DEFAULT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, createdBy_id INT DEFAULT NULL, updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE TABLE chill_main_dashboard_config_item (id INT NOT NULL, user_id INT DEFAULT NULL, type VARCHAR(255) NOT NULL, position VARCHAR(255) NOT NULL, metadata JSON NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_CF59DFD6A76ED395 ON chill_main_dashboard_config_item (user_id)'); + $this->addSql('CREATE TABLE chill_main_news (id INT NOT NULL, title TEXT NOT NULL, content TEXT NOT NULL, startDate DATE NOT NULL, endDate DATE DEFAULT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, createdBy_id INT DEFAULT NULL, updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE INDEX IDX_96922AFB3174800F ON chill_main_news (createdBy_id)'); $this->addSql('CREATE INDEX IDX_96922AFB65FF1AEC ON chill_main_news (updatedBy_id)'); $this->addSql('COMMENT ON COLUMN chill_main_news.startDate IS \'(DC2Type:date_immutable)\''); $this->addSql('COMMENT ON COLUMN chill_main_news.endDate IS \'(DC2Type:date_immutable)\''); $this->addSql('COMMENT ON COLUMN chill_main_news.createdAt IS \'(DC2Type:datetime_immutable)\''); $this->addSql('COMMENT ON COLUMN chill_main_news.updatedAt IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('ALTER TABLE chill_main_dashboard_config_item ADD CONSTRAINT FK_CF59DFD6A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_main_news ADD CONSTRAINT FK_96922AFB3174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_main_news ADD CONSTRAINT FK_96922AFB65FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } public function down(Schema $schema): void { + $this->addSql('DROP SEQUENCE chill_main_dashboard_config_item_id_seq CASCADE'); $this->addSql('DROP SEQUENCE chill_main_news_id_seq CASCADE'); + $this->addSql('ALTER TABLE chill_main_dashboard_config_item DROP CONSTRAINT FK_CF59DFD6A76ED395'); $this->addSql('ALTER TABLE chill_main_news DROP CONSTRAINT FK_96922AFB3174800F'); $this->addSql('ALTER TABLE chill_main_news DROP CONSTRAINT FK_96922AFB65FF1AEC'); + $this->addSql('DROP TABLE chill_main_dashboard_config_item'); $this->addSql('DROP TABLE chill_main_news'); } } From 6b966285a63cdcc6e32949796534c4b77b7d36cc Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 13:49:32 +0100 Subject: [PATCH 13/60] make frontend news widget --- .../Controller/DashboardApiController.php | 12 +- .../public/vuejs/HomepageWidget/App.vue | 5 +- .../DashboardWidget/News/News.vue | 0 .../HomepageWidget/DashboardWidgets/News.vue | 106 ++++++++++++++++++ .../public/vuejs/HomepageWidget/MyCustoms.vue | 32 ++++-- .../public/vuejs/HomepageWidget/js/store.js | 17 --- .../Resources/public/vuejs/_js/i18n.ts | 7 +- 7 files changed, 141 insertions(+), 38 deletions(-) delete mode 100644 src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidget/News/News.vue create mode 100644 src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue diff --git a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php index bc045a596..0b618c6f4 100644 --- a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php @@ -19,17 +19,17 @@ class DashboardApiController { } + public function indexApi() + { + return $this->getDashboardConfiguration(); + } + + // I dont understand why this method is needed, but if I do a cache clear without this method present, he gives an error saying it needs to be present. public function setCrudConfig() { return null; } - - /** - * Give the user dashboard configuration - * - * @Route("/api/1.0/main/dashboard-config-item.json", methods={"post"}) - */ public function getDashboardConfiguration(): JsonResponse { $data = [ diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/App.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/App.vue index 908b9eb1c..ea87277d5 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/App.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/App.vue @@ -97,6 +97,8 @@ import MyNotifications from './MyNotifications'; import MyWorkflows from './MyWorkflows.vue'; import TabCounter from './TabCounter'; import { mapState } from "vuex"; +import { makeFetch } from "ChillMainAssets/lib/api/apiMethods"; + export default { name: "App", @@ -112,7 +114,7 @@ export default { }, data() { return { - activeTab: 'MyCustoms' + activeTab: 'MyCustoms', } }, computed: { @@ -131,7 +133,6 @@ export default { } }, mounted() { - this.$store.dispatch('getDashboardItems', {userId: 1}) for (const m of [ 'MyNotifications', 'MyAccompanyingCourses', diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidget/News/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidget/News/News.vue deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue new file mode 100644 index 000000000..d6e607810 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue index 4a79ddd49..5df7fb787 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue @@ -39,18 +39,11 @@ - -
    -
    - News - -
    -
    -
    -
    - Mon dashboard personnalisé -
    -
    +
    +
    + +
    +
    @@ -58,14 +51,20 @@ diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js index 1f9527b4f..1579a3d0c 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js @@ -24,7 +24,6 @@ const store = createStore({ workflows: {}, workflowsCc: {}, errorMsg: [], - dashboardItems: {}, loading: false }, getters: { @@ -98,24 +97,8 @@ const store = createStore({ catchError(state, error) { state.errorMsg.push(error); }, - addDashboardItems(state, dashboardItems) { - state.dashboardItems = dashboardItems; - } }, actions: { - getDashboardItems({commit, getters}, { userId }) { - const url = `/api/1.0/main/dashboard-item/${userId}.json`; - makeFetch('GET', url) - .then((response) => { - console.log('dashboardItems', response.results) - commit('addDashboardItems', response); - }) - .catch((error) => { - commit('catchError', error); - throw error; - }) - ; - }, getByTab({ commit, getters }, { tab, param }) { switch (tab) { // case 'MyWorks': diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.ts b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.ts index c509ac10f..c43586915 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.ts +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.ts @@ -51,7 +51,12 @@ const messages = { years_old: "1 an | {n} an | {n} ans", residential_address: "Adresse de résidence", located_at: "réside chez" - } + }, + widget: { + news: { + title: "Actualités" + } + } } }; From a55cd3b7e97c664b63414ed4c1ee35f7a0f0be7c Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 18:33:07 +0100 Subject: [PATCH 14/60] update controller not to extend apiController and make some changes in repository + serializer --- .../Controller/DashboardApiController.php | 18 +++----- .../Controller/NewsItemApiController.php | 37 ++++++++++++++-- .../ChillMainExtension.php | 4 +- .../Repository/NewsItemRepository.php | 43 ++++++++++++++++++- .../Normalizer/NewsItemNormalizer.php | 2 - 5 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php index 0b618c6f4..e3088e42f 100644 --- a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php @@ -19,17 +19,11 @@ class DashboardApiController { } - public function indexApi() - { - return $this->getDashboardConfiguration(); - } - - // I dont understand why this method is needed, but if I do a cache clear without this method present, he gives an error saying it needs to be present. - public function setCrudConfig() - { - return null; - } - + /** + * Get user dashboard config (not yet based on user id and still hardcoded for now) + * + * @Route("/api/1.0/main/dashboard-config-item.json", methods={"get"}) + */ public function getDashboardConfiguration(): JsonResponse { $data = [ @@ -44,7 +38,7 @@ class DashboardApiController ] ]; - return new JsonResponse($data); + return new JsonResponse($data, JsonResponse::HTTP_OK, []); } } diff --git a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php index aa2bcb8bc..ce304c4ca 100644 --- a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php @@ -12,13 +12,44 @@ declare(strict_types=1); namespace Chill\MainBundle\Controller; use Chill\MainBundle\CRUD\Controller\ApiController; +use Chill\MainBundle\Entity\NewsItem; +use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Pagination\PaginatorInterface; +use Chill\MainBundle\Repository\NewsItemRepository; +use Chill\MainBundle\Serializer\Model\Collection; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; +use Chill\MainBundle\Serializer\NewsItemNormalizer; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; +use Symfony\Component\Serializer\SerializerInterface; -class NewsItemApiController extends ApiController +class NewsItemApiController { - protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format) + public function __construct( + private NewsItemRepository $newsItemRepository, + private SerializerInterface $serializer, + private PaginatorFactory $paginatorFactory) {} + + /** + * Get list of news items filtered on start and end date + * + * @Route("/api/1.0/main/news.json", methods={"get"}) + */ + public function listCurrentNewsItems():JsonResponse { - return $query->addOrderBy('e.startDate', 'ASC'); + $total = $this->newsItemRepository->countWithDateFilter(); + $paginator = $this->paginatorFactory->create($total); + $newsItems = $this->newsItemRepository->findWithDateFilter(); + + return new JsonResponse($this->serializer->serialize( + new Collection(array_values($newsItems), $paginator), + 'json', + [ + AbstractNormalizer::GROUPS => ['read'], + ] + ), JsonResponse::HTTP_OK, [], true); + } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 7e44ceb6b..29b3a9384 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -792,7 +792,7 @@ class ChillMainExtension extends Extension implements ], ], ], - [ +/* [ 'class' => \Chill\MainBundle\Entity\DashboardConfigItem::class, 'controller' => \Chill\MainBundle\Controller\DashboardApiController::class, 'name' => 'dashboard-config-item', @@ -833,7 +833,7 @@ class ChillMainExtension extends Extension implements ], ], ], - ], + ],*/ ], ]); } diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php index 09334a483..27f9b8fcd 100644 --- a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -5,7 +5,9 @@ namespace Chill\MainBundle\Repository; use Chill\MainBundle\Entity\NewsItem; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ObjectRepository; +use Faker\Core\DateTime; class NewsItemRepository implements ObjectRepository { @@ -17,6 +19,11 @@ class NewsItemRepository implements ObjectRepository $this->repository = $entityManager->getRepository(NewsItem::class); } + public function createQueryBuilder(string $alias, string $indexBy = null): QueryBuilder + { + return $this->repository->createQueryBuilder($alias, $indexBy); + } + /** * @inheritDoc */ @@ -40,7 +47,6 @@ class NewsItemRepository implements ObjectRepository { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - /** * @inheritDoc */ @@ -56,4 +62,39 @@ class NewsItemRepository implements ObjectRepository { return NewsItem::class; } + + public function findWithDateFilter() + { + return $this->buildQueryWithDateFilter() + ->getQuery() + ->getResult(); + } + + public function countWithDateFilter() + { + return $this->buildQueryWithDateFilter() + ->select('COUNT(n)') + ->getQuery() + ->getSingleScalarResult(); + } + + public function buildQueryWithDateFilter(): QueryBuilder + { + $now = new \DateTime('now'); + + $qb = $this->createQueryBuilder('n'); + $qb + ->where( + $qb->expr()->andX( + $qb->expr()->gte('n.startDate', ':now'), + $qb->expr()->orX( + $qb->expr()->lt('n.endDate', ':now'), + $qb->expr()->isNull('n.endDate') + ) + ) + ) + ->setParameter('now', $now); + + return $qb; + } } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php index fd3c510b7..de999a5b9 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php @@ -22,8 +22,6 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class NewsItemNormalizer implements NormalizerInterface { - public function __construct(private readonly CenterRepository $repository) {} - public function normalize($newsItem, $format = null, array $context = []) { /* @var NewsItem $newsItem */ From 997a6ea419b76a98992091b50c9f2c47eb28a68a Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:07:35 +0100 Subject: [PATCH 15/60] Convert markdown into html + minor style adjustments --- .../ChillMainBundle/Entity/NewsItem.php | 4 +++ .../HomepageWidget/DashboardWidgets/News.vue | 36 ++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Entity/NewsItem.php b/src/Bundle/ChillMainBundle/Entity/NewsItem.php index 4febb9d98..35a08c0ff 100644 --- a/src/Bundle/ChillMainBundle/Entity/NewsItem.php +++ b/src/Bundle/ChillMainBundle/Entity/NewsItem.php @@ -59,11 +59,15 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface /** * @ORM\Column(type="date_immutable", nullable=false) + * + * @Groups({"read"}) */ private ?\DateTimeImmutable $startDate = null; /** * @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) + * + * @Groups({"read"}) */ private ?\DateTimeImmutable $endDate = null; diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue index d6e607810..679eed8b4 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue @@ -5,15 +5,20 @@
  • {{ item.title }}

    - {{ truncateContent(item.content) }} +
    Read more
    - {{ item.content }} +
    - - + +
  • @@ -24,6 +29,7 @@ import { onMounted, ref } from 'vue' import {makeFetch} from "ChillMainAssets/lib/api/apiMethods"; import Modal from '../../_components/Modal.vue'; // Adjust the import path +import { marked } from 'marked'; const newsItems = ref([]) @@ -52,6 +58,19 @@ const truncateContent = (content, maxLength = 100) => { } }; +const convertMarkdownToHtml = (markdown) => { + return marked(markdown); +}; + +const truncateMarkdownContent = (content, maxLength = 100) => { + const htmlContent = convertMarkdownToHtml(content); + return truncateContent(htmlContent, maxLength); +}; + +const formatDate = (datetime) => { + return new Date(datetime.date).toDateString() +} + onMounted(() => { makeFetch('GET', '/api/1.0/main/news.json') .then((response) => { @@ -103,4 +122,13 @@ button { color: #3498db; /* Adjust the color as needed */ cursor: pointer; } + +.news-date { + font-style: italic; +} + +.news-title { + font-weight: bold; + text-transform: uppercase; +} From fc22bf1194869a3d83402441a14ca51597f86c41 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:21:52 +0100 Subject: [PATCH 16/60] Add use of DOMPurify to sanitize text from possible injection --- .../public/vuejs/HomepageWidget/DashboardWidgets/News.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue index 679eed8b4..366dfa329 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue @@ -30,6 +30,8 @@ import { onMounted, ref } from 'vue' import {makeFetch} from "ChillMainAssets/lib/api/apiMethods"; import Modal from '../../_components/Modal.vue'; // Adjust the import path import { marked } from 'marked'; +import DOMPurify from 'dompurify'; + const newsItems = ref([]) @@ -59,7 +61,11 @@ const truncateContent = (content, maxLength = 100) => { }; const convertMarkdownToHtml = (markdown) => { - return marked(markdown); + const rawHtml = marked(markdown); + return rawHtml; +/* console.log('rawhtml', rawHtml) + console.log('sanitized', DOMPurify.sanitize(rawHtml)) + return DOMPurify.sanitize(rawHtml)*/ }; const truncateMarkdownContent = (content, maxLength = 100) => { From 7b4969e89df757d9071d4719c32ab9bf0a116424 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:23:04 +0100 Subject: [PATCH 17/60] uncomment sanitizing --- .../public/vuejs/HomepageWidget/DashboardWidgets/News.vue | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue index 366dfa329..208025983 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue @@ -62,10 +62,7 @@ const truncateContent = (content, maxLength = 100) => { const convertMarkdownToHtml = (markdown) => { const rawHtml = marked(markdown); - return rawHtml; -/* console.log('rawhtml', rawHtml) - console.log('sanitized', DOMPurify.sanitize(rawHtml)) - return DOMPurify.sanitize(rawHtml)*/ + return DOMPurify.sanitize(rawHtml) }; const truncateMarkdownContent = (content, maxLength = 100) => { From d6641f70c90680a125dc432c110a1ac63520bc70 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:25:18 +0100 Subject: [PATCH 18/60] fix phpstan issues --- .../ChillMainBundle/Controller/DashboardApiController.php | 4 ---- src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php | 2 +- src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php index e3088e42f..86a824d0b 100644 --- a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php @@ -15,10 +15,6 @@ use Symfony\Component\Security\Core\Security; class DashboardApiController { - public function __construct(private readonly Security $security) - { - } - /** * Get user dashboard config (not yet based on user id and still hardcoded for now) * diff --git a/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php index 208c864e7..05ead7f07 100644 --- a/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php +++ b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php @@ -23,7 +23,7 @@ class DashboardConfigItem * * @Serializer\Groups({"dashboardConfigItem:read", "read"}) */ - private ?int $id; + private ?int $id = null; /** * @ORM\Column(type="string") diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php index 27f9b8fcd..f38462d4e 100644 --- a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -29,7 +29,7 @@ class NewsItemRepository implements ObjectRepository */ public function find($id) { - $this->repository->find($id); + return $this->repository->find($id); } /** From d828a6b9e00843e9fc716f8ee8cba38639f48819 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:25:41 +0100 Subject: [PATCH 19/60] php cs fixes --- .../Controller/ActivityController.php | 4 +-- .../Controller/DashboardApiController.php | 23 ++++++++------- .../Controller/NewsItemApiController.php | 14 +++------ .../ChillMainExtension.php | 3 +- .../Entity/DashboardConfigItem.php | 12 ++++++-- .../ChillMainBundle/Entity/NewsItem.php | 1 - .../ChillMainBundle/Form/NewsItemType.php | 5 ++-- .../Repository/NewsItemRepository.php | 29 +++++++------------ .../Normalizer/NewsItemNormalizer.php | 8 +---- .../migrations/Version20231108141141.php | 9 +++++- .../Form/ThirdPartyType.php | 2 +- 11 files changed, 51 insertions(+), 59 deletions(-) diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index 43c0b13bb..06489010c 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -673,8 +673,8 @@ final class ActivityController extends AbstractController throw $this->createNotFoundException('Accompanying Period not found'); } - // TODO Add permission - // $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + // TODO Add permission + // $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); } else { throw $this->createNotFoundException('Person or Accompanying Period not found'); } diff --git a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php index 86a824d0b..e091d2f5a 100644 --- a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php @@ -1,22 +1,24 @@ [ // arbitrary data that will be store "some time" 'only_unread' => false, - ] - ] + ], + ], ]; return new JsonResponse($data, JsonResponse::HTTP_OK, []); } - } diff --git a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php index ce304c4ca..25fe7620f 100644 --- a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php @@ -11,17 +11,11 @@ declare(strict_types=1); namespace Chill\MainBundle\Controller; -use Chill\MainBundle\CRUD\Controller\ApiController; -use Chill\MainBundle\Entity\NewsItem; use Chill\MainBundle\Pagination\PaginatorFactory; -use Chill\MainBundle\Pagination\PaginatorInterface; use Chill\MainBundle\Repository\NewsItemRepository; use Chill\MainBundle\Serializer\Model\Collection; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -use Chill\MainBundle\Serializer\NewsItemNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\SerializerInterface; @@ -30,14 +24,15 @@ class NewsItemApiController public function __construct( private NewsItemRepository $newsItemRepository, private SerializerInterface $serializer, - private PaginatorFactory $paginatorFactory) {} + private PaginatorFactory $paginatorFactory + ) {} /** - * Get list of news items filtered on start and end date + * Get list of news items filtered on start and end date. * * @Route("/api/1.0/main/news.json", methods={"get"}) */ - public function listCurrentNewsItems():JsonResponse + public function listCurrentNewsItems(): JsonResponse { $total = $this->newsItemRepository->countWithDateFilter(); $paginator = $this->paginatorFactory->create($total); @@ -50,6 +45,5 @@ class NewsItemApiController AbstractNormalizer::GROUPS => ['read'], ] ), JsonResponse::HTTP_OK, [], true); - } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 29b3a9384..7cb84b14d 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -19,7 +19,6 @@ use Chill\MainBundle\Controller\CountryController; use Chill\MainBundle\Controller\LanguageController; use Chill\MainBundle\Controller\LocationController; use Chill\MainBundle\Controller\LocationTypeController; -use Chill\MainBundle\Controller\NewsItemApiController; use Chill\MainBundle\Controller\NewsItemController; use Chill\MainBundle\Controller\RegroupmentController; use Chill\MainBundle\Controller\UserController; @@ -792,7 +791,7 @@ class ChillMainExtension extends Extension implements ], ], ], -/* [ + /* [ 'class' => \Chill\MainBundle\Entity\DashboardConfigItem::class, 'controller' => \Chill\MainBundle\Controller\DashboardApiController::class, 'name' => 'dashboard-config-item', diff --git a/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php index 05ead7f07..122202f96 100644 --- a/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php +++ b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php @@ -1,12 +1,20 @@ id; } - } diff --git a/src/Bundle/ChillMainBundle/Form/NewsItemType.php b/src/Bundle/ChillMainBundle/Form/NewsItemType.php index 0080acf1c..01ae63882 100644 --- a/src/Bundle/ChillMainBundle/Form/NewsItemType.php +++ b/src/Bundle/ChillMainBundle/Form/NewsItemType.php @@ -18,7 +18,6 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Contracts\Translation\TranslatorInterface; class NewsItemType extends AbstractType { @@ -36,12 +35,12 @@ class NewsItemType extends AbstractType ChillDateType::class, [ 'required' => true, - 'input' => 'datetime_immutable' + 'input' => 'datetime_immutable', ] ) ->add('endDate', ChillDateType::class, [ 'required' => false, - 'input' => 'datetime_immutable' + 'input' => 'datetime_immutable', ]); } diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php index f38462d4e..bb2128b25 100644 --- a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -1,5 +1,14 @@ repository->createQueryBuilder($alias, $indexBy); } - /** - * @inheritDoc - */ public function find($id) { return $this->repository->find($id); } - /** - * @inheritDoc - */ public function findAll() { return $this->repository->findAll(); } - /** - * @inheritDoc - */ - public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null) + public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null) { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - /** - * @inheritDoc - */ + public function findOneBy(array $criteria) { return $this->repository->findOneBy($criteria); } - /** - * @inheritDoc - */ public function getClassName() { return NewsItem::class; diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php index de999a5b9..77a969752 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php @@ -11,13 +11,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Serializer\Normalizer; -use Chill\MainBundle\Entity\Center; -use Chill\MainBundle\Entity\DashboardItem; use Chill\MainBundle\Entity\NewsItem; -use Chill\MainBundle\Repository\CenterRepository; -use Symfony\Component\Serializer\Exception\InvalidArgumentException; -use Symfony\Component\Serializer\Exception\UnexpectedValueException; -use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class NewsItemNormalizer implements NormalizerInterface @@ -30,7 +24,7 @@ class NewsItemNormalizer implements NormalizerInterface 'title' => $newsItem->getTitle(), 'content' => $newsItem->getContent(), 'startdate' => $newsItem->getStartDate(), - 'enddate' => $newsItem->getEndDate() + 'enddate' => $newsItem->getEndDate(), ]; } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php b/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php index ffcc6130b..d081a9e94 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php @@ -2,13 +2,20 @@ declare(strict_types=1); +/* + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + namespace Chill\Migrations\Main; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; /** - * Create dashboard config item and news item + * Create dashboard config item and news item. */ final class Version20231108141141 extends AbstractMigration { diff --git a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php index 046d553e9..41e0140c8 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php @@ -100,7 +100,7 @@ class ThirdPartyType extends AbstractType 'label' => 'thirdparty.Contact data are confidential', ]); - // Institutional ThirdParty (parent) + // Institutional ThirdParty (parent) } else { $builder ->add('nameCompany', TextType::class, [ From ed2d41c2256d009763b7cf020eb2947c26dee5ec Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 20:22:31 +0100 Subject: [PATCH 20/60] add typing --- .../ChillMainBundle/Resources/public/types.ts | 8 +++++++ .../HomepageWidget/DashboardWidgets/News.vue | 23 +++++++++---------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/types.ts b/src/Bundle/ChillMainBundle/Resources/public/types.ts index b31b70897..2b0112582 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/types.ts +++ b/src/Bundle/ChillMainBundle/Resources/public/types.ts @@ -160,3 +160,11 @@ export interface LocationType { contactData: "optional" | "required"; title: TranslatableString; } + +export interface NewsItem { + id: number; + title: string; + content: string; + startdate: { date: DateTime }; + enddate: { date: DateTime | null} +} diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue index 208025983..272a57e9b 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue @@ -27,18 +27,17 @@ + + diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue index 4a79ddd49..5df7fb787 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue @@ -39,18 +39,11 @@ - -
    -
    - News - -
    -
    -
    -
    - Mon dashboard personnalisé -
    -
    +
    +
    + +
    +
    @@ -58,14 +51,20 @@ diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js index 1f9527b4f..1579a3d0c 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/js/store.js @@ -24,7 +24,6 @@ const store = createStore({ workflows: {}, workflowsCc: {}, errorMsg: [], - dashboardItems: {}, loading: false }, getters: { @@ -98,24 +97,8 @@ const store = createStore({ catchError(state, error) { state.errorMsg.push(error); }, - addDashboardItems(state, dashboardItems) { - state.dashboardItems = dashboardItems; - } }, actions: { - getDashboardItems({commit, getters}, { userId }) { - const url = `/api/1.0/main/dashboard-item/${userId}.json`; - makeFetch('GET', url) - .then((response) => { - console.log('dashboardItems', response.results) - commit('addDashboardItems', response); - }) - .catch((error) => { - commit('catchError', error); - throw error; - }) - ; - }, getByTab({ commit, getters }, { tab, param }) { switch (tab) { // case 'MyWorks': diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.ts b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.ts index c509ac10f..c43586915 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.ts +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.ts @@ -51,7 +51,12 @@ const messages = { years_old: "1 an | {n} an | {n} ans", residential_address: "Adresse de résidence", located_at: "réside chez" - } + }, + widget: { + news: { + title: "Actualités" + } + } } }; From 3ae8e0c406058582968a245bd3591fb98599b870 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 18:33:07 +0100 Subject: [PATCH 34/60] update controller not to extend apiController and make some changes in repository + serializer --- .../Controller/DashboardApiController.php | 18 +++----- .../Controller/NewsItemApiController.php | 37 ++++++++++++++-- .../ChillMainExtension.php | 4 +- .../Repository/NewsItemRepository.php | 43 ++++++++++++++++++- .../Normalizer/NewsItemNormalizer.php | 2 - 5 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php index 0b618c6f4..e3088e42f 100644 --- a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php @@ -19,17 +19,11 @@ class DashboardApiController { } - public function indexApi() - { - return $this->getDashboardConfiguration(); - } - - // I dont understand why this method is needed, but if I do a cache clear without this method present, he gives an error saying it needs to be present. - public function setCrudConfig() - { - return null; - } - + /** + * Get user dashboard config (not yet based on user id and still hardcoded for now) + * + * @Route("/api/1.0/main/dashboard-config-item.json", methods={"get"}) + */ public function getDashboardConfiguration(): JsonResponse { $data = [ @@ -44,7 +38,7 @@ class DashboardApiController ] ]; - return new JsonResponse($data); + return new JsonResponse($data, JsonResponse::HTTP_OK, []); } } diff --git a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php index aa2bcb8bc..ce304c4ca 100644 --- a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php @@ -12,13 +12,44 @@ declare(strict_types=1); namespace Chill\MainBundle\Controller; use Chill\MainBundle\CRUD\Controller\ApiController; +use Chill\MainBundle\Entity\NewsItem; +use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Pagination\PaginatorInterface; +use Chill\MainBundle\Repository\NewsItemRepository; +use Chill\MainBundle\Serializer\Model\Collection; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; +use Chill\MainBundle\Serializer\NewsItemNormalizer; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; +use Symfony\Component\Serializer\SerializerInterface; -class NewsItemApiController extends ApiController +class NewsItemApiController { - protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format) + public function __construct( + private NewsItemRepository $newsItemRepository, + private SerializerInterface $serializer, + private PaginatorFactory $paginatorFactory) {} + + /** + * Get list of news items filtered on start and end date + * + * @Route("/api/1.0/main/news.json", methods={"get"}) + */ + public function listCurrentNewsItems():JsonResponse { - return $query->addOrderBy('e.startDate', 'ASC'); + $total = $this->newsItemRepository->countWithDateFilter(); + $paginator = $this->paginatorFactory->create($total); + $newsItems = $this->newsItemRepository->findWithDateFilter(); + + return new JsonResponse($this->serializer->serialize( + new Collection(array_values($newsItems), $paginator), + 'json', + [ + AbstractNormalizer::GROUPS => ['read'], + ] + ), JsonResponse::HTTP_OK, [], true); + } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 7e44ceb6b..29b3a9384 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -792,7 +792,7 @@ class ChillMainExtension extends Extension implements ], ], ], - [ +/* [ 'class' => \Chill\MainBundle\Entity\DashboardConfigItem::class, 'controller' => \Chill\MainBundle\Controller\DashboardApiController::class, 'name' => 'dashboard-config-item', @@ -833,7 +833,7 @@ class ChillMainExtension extends Extension implements ], ], ], - ], + ],*/ ], ]); } diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php index 09334a483..27f9b8fcd 100644 --- a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -5,7 +5,9 @@ namespace Chill\MainBundle\Repository; use Chill\MainBundle\Entity\NewsItem; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ObjectRepository; +use Faker\Core\DateTime; class NewsItemRepository implements ObjectRepository { @@ -17,6 +19,11 @@ class NewsItemRepository implements ObjectRepository $this->repository = $entityManager->getRepository(NewsItem::class); } + public function createQueryBuilder(string $alias, string $indexBy = null): QueryBuilder + { + return $this->repository->createQueryBuilder($alias, $indexBy); + } + /** * @inheritDoc */ @@ -40,7 +47,6 @@ class NewsItemRepository implements ObjectRepository { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - /** * @inheritDoc */ @@ -56,4 +62,39 @@ class NewsItemRepository implements ObjectRepository { return NewsItem::class; } + + public function findWithDateFilter() + { + return $this->buildQueryWithDateFilter() + ->getQuery() + ->getResult(); + } + + public function countWithDateFilter() + { + return $this->buildQueryWithDateFilter() + ->select('COUNT(n)') + ->getQuery() + ->getSingleScalarResult(); + } + + public function buildQueryWithDateFilter(): QueryBuilder + { + $now = new \DateTime('now'); + + $qb = $this->createQueryBuilder('n'); + $qb + ->where( + $qb->expr()->andX( + $qb->expr()->gte('n.startDate', ':now'), + $qb->expr()->orX( + $qb->expr()->lt('n.endDate', ':now'), + $qb->expr()->isNull('n.endDate') + ) + ) + ) + ->setParameter('now', $now); + + return $qb; + } } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php index fd3c510b7..de999a5b9 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php @@ -22,8 +22,6 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class NewsItemNormalizer implements NormalizerInterface { - public function __construct(private readonly CenterRepository $repository) {} - public function normalize($newsItem, $format = null, array $context = []) { /* @var NewsItem $newsItem */ From cd793d684254a895b2c2b6e9a490034ad331f3fb Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:07:35 +0100 Subject: [PATCH 35/60] Convert markdown into html + minor style adjustments --- .../ChillMainBundle/Entity/NewsItem.php | 4 +++ .../HomepageWidget/DashboardWidgets/News.vue | 36 ++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Entity/NewsItem.php b/src/Bundle/ChillMainBundle/Entity/NewsItem.php index 4febb9d98..35a08c0ff 100644 --- a/src/Bundle/ChillMainBundle/Entity/NewsItem.php +++ b/src/Bundle/ChillMainBundle/Entity/NewsItem.php @@ -59,11 +59,15 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface /** * @ORM\Column(type="date_immutable", nullable=false) + * + * @Groups({"read"}) */ private ?\DateTimeImmutable $startDate = null; /** * @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) + * + * @Groups({"read"}) */ private ?\DateTimeImmutable $endDate = null; diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue index d6e607810..679eed8b4 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue @@ -5,15 +5,20 @@
  • {{ item.title }}

    - {{ truncateContent(item.content) }} +
    Read more
    - {{ item.content }} +
    - - + +
  • @@ -24,6 +29,7 @@ import { onMounted, ref } from 'vue' import {makeFetch} from "ChillMainAssets/lib/api/apiMethods"; import Modal from '../../_components/Modal.vue'; // Adjust the import path +import { marked } from 'marked'; const newsItems = ref([]) @@ -52,6 +58,19 @@ const truncateContent = (content, maxLength = 100) => { } }; +const convertMarkdownToHtml = (markdown) => { + return marked(markdown); +}; + +const truncateMarkdownContent = (content, maxLength = 100) => { + const htmlContent = convertMarkdownToHtml(content); + return truncateContent(htmlContent, maxLength); +}; + +const formatDate = (datetime) => { + return new Date(datetime.date).toDateString() +} + onMounted(() => { makeFetch('GET', '/api/1.0/main/news.json') .then((response) => { @@ -103,4 +122,13 @@ button { color: #3498db; /* Adjust the color as needed */ cursor: pointer; } + +.news-date { + font-style: italic; +} + +.news-title { + font-weight: bold; + text-transform: uppercase; +} From 8363c5c3cf354edf621b43e832298647e4e83b3f Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:21:52 +0100 Subject: [PATCH 36/60] Add use of DOMPurify to sanitize text from possible injection --- .../public/vuejs/HomepageWidget/DashboardWidgets/News.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue index 679eed8b4..366dfa329 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue @@ -30,6 +30,8 @@ import { onMounted, ref } from 'vue' import {makeFetch} from "ChillMainAssets/lib/api/apiMethods"; import Modal from '../../_components/Modal.vue'; // Adjust the import path import { marked } from 'marked'; +import DOMPurify from 'dompurify'; + const newsItems = ref([]) @@ -59,7 +61,11 @@ const truncateContent = (content, maxLength = 100) => { }; const convertMarkdownToHtml = (markdown) => { - return marked(markdown); + const rawHtml = marked(markdown); + return rawHtml; +/* console.log('rawhtml', rawHtml) + console.log('sanitized', DOMPurify.sanitize(rawHtml)) + return DOMPurify.sanitize(rawHtml)*/ }; const truncateMarkdownContent = (content, maxLength = 100) => { From 334d357189d98b160038cdb8a637b7adca7fc565 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:23:04 +0100 Subject: [PATCH 37/60] uncomment sanitizing --- .../public/vuejs/HomepageWidget/DashboardWidgets/News.vue | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue index 366dfa329..208025983 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue @@ -62,10 +62,7 @@ const truncateContent = (content, maxLength = 100) => { const convertMarkdownToHtml = (markdown) => { const rawHtml = marked(markdown); - return rawHtml; -/* console.log('rawhtml', rawHtml) - console.log('sanitized', DOMPurify.sanitize(rawHtml)) - return DOMPurify.sanitize(rawHtml)*/ + return DOMPurify.sanitize(rawHtml) }; const truncateMarkdownContent = (content, maxLength = 100) => { From 6d608ab35ab9f134931504e9a6a4d4a5149c5eeb Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:25:18 +0100 Subject: [PATCH 38/60] fix phpstan issues --- .../ChillMainBundle/Controller/DashboardApiController.php | 4 ---- src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php | 2 +- src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php index e3088e42f..86a824d0b 100644 --- a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php @@ -15,10 +15,6 @@ use Symfony\Component\Security\Core\Security; class DashboardApiController { - public function __construct(private readonly Security $security) - { - } - /** * Get user dashboard config (not yet based on user id and still hardcoded for now) * diff --git a/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php index 208c864e7..05ead7f07 100644 --- a/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php +++ b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php @@ -23,7 +23,7 @@ class DashboardConfigItem * * @Serializer\Groups({"dashboardConfigItem:read", "read"}) */ - private ?int $id; + private ?int $id = null; /** * @ORM\Column(type="string") diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php index 27f9b8fcd..f38462d4e 100644 --- a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -29,7 +29,7 @@ class NewsItemRepository implements ObjectRepository */ public function find($id) { - $this->repository->find($id); + return $this->repository->find($id); } /** From 32a103d86a0b43f39974b5b9b50a75d1fd1bd906 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 19:25:41 +0100 Subject: [PATCH 39/60] php cs fixes --- .../Controller/DashboardApiController.php | 23 ++++++++------- .../Controller/NewsItemApiController.php | 14 +++------ .../ChillMainExtension.php | 3 +- .../Entity/DashboardConfigItem.php | 12 ++++++-- .../ChillMainBundle/Entity/NewsItem.php | 1 - .../ChillMainBundle/Form/NewsItemType.php | 5 ++-- .../Repository/NewsItemRepository.php | 29 +++++++------------ .../Normalizer/NewsItemNormalizer.php | 8 +---- .../migrations/Version20231108141141.php | 9 +++++- 9 files changed, 48 insertions(+), 56 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php index 86a824d0b..e091d2f5a 100644 --- a/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/DashboardApiController.php @@ -1,22 +1,24 @@ [ // arbitrary data that will be store "some time" 'only_unread' => false, - ] - ] + ], + ], ]; return new JsonResponse($data, JsonResponse::HTTP_OK, []); } - } diff --git a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php index ce304c4ca..25fe7620f 100644 --- a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php @@ -11,17 +11,11 @@ declare(strict_types=1); namespace Chill\MainBundle\Controller; -use Chill\MainBundle\CRUD\Controller\ApiController; -use Chill\MainBundle\Entity\NewsItem; use Chill\MainBundle\Pagination\PaginatorFactory; -use Chill\MainBundle\Pagination\PaginatorInterface; use Chill\MainBundle\Repository\NewsItemRepository; use Chill\MainBundle\Serializer\Model\Collection; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -use Chill\MainBundle\Serializer\NewsItemNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\SerializerInterface; @@ -30,14 +24,15 @@ class NewsItemApiController public function __construct( private NewsItemRepository $newsItemRepository, private SerializerInterface $serializer, - private PaginatorFactory $paginatorFactory) {} + private PaginatorFactory $paginatorFactory + ) {} /** - * Get list of news items filtered on start and end date + * Get list of news items filtered on start and end date. * * @Route("/api/1.0/main/news.json", methods={"get"}) */ - public function listCurrentNewsItems():JsonResponse + public function listCurrentNewsItems(): JsonResponse { $total = $this->newsItemRepository->countWithDateFilter(); $paginator = $this->paginatorFactory->create($total); @@ -50,6 +45,5 @@ class NewsItemApiController AbstractNormalizer::GROUPS => ['read'], ] ), JsonResponse::HTTP_OK, [], true); - } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 29b3a9384..7cb84b14d 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -19,7 +19,6 @@ use Chill\MainBundle\Controller\CountryController; use Chill\MainBundle\Controller\LanguageController; use Chill\MainBundle\Controller\LocationController; use Chill\MainBundle\Controller\LocationTypeController; -use Chill\MainBundle\Controller\NewsItemApiController; use Chill\MainBundle\Controller\NewsItemController; use Chill\MainBundle\Controller\RegroupmentController; use Chill\MainBundle\Controller\UserController; @@ -792,7 +791,7 @@ class ChillMainExtension extends Extension implements ], ], ], -/* [ + /* [ 'class' => \Chill\MainBundle\Entity\DashboardConfigItem::class, 'controller' => \Chill\MainBundle\Controller\DashboardApiController::class, 'name' => 'dashboard-config-item', diff --git a/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php index 05ead7f07..122202f96 100644 --- a/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php +++ b/src/Bundle/ChillMainBundle/Entity/DashboardConfigItem.php @@ -1,12 +1,20 @@ id; } - } diff --git a/src/Bundle/ChillMainBundle/Form/NewsItemType.php b/src/Bundle/ChillMainBundle/Form/NewsItemType.php index 0080acf1c..01ae63882 100644 --- a/src/Bundle/ChillMainBundle/Form/NewsItemType.php +++ b/src/Bundle/ChillMainBundle/Form/NewsItemType.php @@ -18,7 +18,6 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Contracts\Translation\TranslatorInterface; class NewsItemType extends AbstractType { @@ -36,12 +35,12 @@ class NewsItemType extends AbstractType ChillDateType::class, [ 'required' => true, - 'input' => 'datetime_immutable' + 'input' => 'datetime_immutable', ] ) ->add('endDate', ChillDateType::class, [ 'required' => false, - 'input' => 'datetime_immutable' + 'input' => 'datetime_immutable', ]); } diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php index f38462d4e..bb2128b25 100644 --- a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -1,5 +1,14 @@ repository->createQueryBuilder($alias, $indexBy); } - /** - * @inheritDoc - */ public function find($id) { return $this->repository->find($id); } - /** - * @inheritDoc - */ public function findAll() { return $this->repository->findAll(); } - /** - * @inheritDoc - */ - public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null) + public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null) { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - /** - * @inheritDoc - */ + public function findOneBy(array $criteria) { return $this->repository->findOneBy($criteria); } - /** - * @inheritDoc - */ public function getClassName() { return NewsItem::class; diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php index de999a5b9..77a969752 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php @@ -11,13 +11,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Serializer\Normalizer; -use Chill\MainBundle\Entity\Center; -use Chill\MainBundle\Entity\DashboardItem; use Chill\MainBundle\Entity\NewsItem; -use Chill\MainBundle\Repository\CenterRepository; -use Symfony\Component\Serializer\Exception\InvalidArgumentException; -use Symfony\Component\Serializer\Exception\UnexpectedValueException; -use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class NewsItemNormalizer implements NormalizerInterface @@ -30,7 +24,7 @@ class NewsItemNormalizer implements NormalizerInterface 'title' => $newsItem->getTitle(), 'content' => $newsItem->getContent(), 'startdate' => $newsItem->getStartDate(), - 'enddate' => $newsItem->getEndDate() + 'enddate' => $newsItem->getEndDate(), ]; } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php b/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php index ffcc6130b..d081a9e94 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20231108141141.php @@ -2,13 +2,20 @@ declare(strict_types=1); +/* + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + namespace Chill\Migrations\Main; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; /** - * Create dashboard config item and news item + * Create dashboard config item and news item. */ final class Version20231108141141 extends AbstractMigration { From eb8dc441b9f637798e29c38f8e5d8f875103e123 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Nov 2023 20:22:31 +0100 Subject: [PATCH 40/60] add typing --- .../ChillMainBundle/Resources/public/types.ts | 8 +++++++ .../HomepageWidget/DashboardWidgets/News.vue | 23 +++++++++---------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/types.ts b/src/Bundle/ChillMainBundle/Resources/public/types.ts index b31b70897..2b0112582 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/types.ts +++ b/src/Bundle/ChillMainBundle/Resources/public/types.ts @@ -160,3 +160,11 @@ export interface LocationType { contactData: "optional" | "required"; title: TranslatableString; } + +export interface NewsItem { + id: number; + title: string; + content: string; + startdate: { date: DateTime }; + enddate: { date: DateTime | null} +} diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue index 208025983..272a57e9b 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/News.vue @@ -27,18 +27,17 @@ + + From 50a6cb5af6462c1a3ba6cc38474be2f2af9f00b1 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 20 Nov 2023 15:51:07 +0100 Subject: [PATCH 50/60] fix: do no display expired news items --- src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php index b7a55c846..be5190873 100644 --- a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -86,7 +86,7 @@ class NewsItemRepository implements ObjectRepository $qb->expr()->andX( $qb->expr()->lte('n.startDate', ':now'), $qb->expr()->orX( - $qb->expr()->lt('n.endDate', ':now'), + $qb->expr()->gt('n.endDate', ':now'), $qb->expr()->isNull('n.endDate') ) ) From caa2bc1f3c6f0085d3b1e73d741896626657a603 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 20 Nov 2023 15:52:08 +0100 Subject: [PATCH 51/60] Add admin translations and order items differently in admin --- src/Bundle/ChillMainBundle/Controller/NewsItemController.php | 3 ++- .../Resources/views/Admin/indexDashboard.html.twig | 2 +- .../Routing/MenuBuilder/AdminNewsMenuBuilder.php | 4 ++-- src/Bundle/ChillMainBundle/translations/messages.fr.yml | 4 ++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/NewsItemController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemController.php index fadaba494..a94dd55b9 100644 --- a/src/Bundle/ChillMainBundle/Controller/NewsItemController.php +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemController.php @@ -19,7 +19,8 @@ class NewsItemController extends CRUDController { protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator) { - $query->addOrderBy('e.startDate', 'ASC'); + $query->addOrderBy('e.startDate', 'DESC'); + $query->addOrderBy('e.id', 'DESC'); return parent::orderQuery($action, $query, $request, $paginator); } diff --git a/src/Bundle/ChillMainBundle/Resources/views/Admin/indexDashboard.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Admin/indexDashboard.html.twig index 8049f3430..9c7513d4c 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Admin/indexDashboard.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Admin/indexDashboard.html.twig @@ -8,6 +8,6 @@ {% block layout_wvm_content %} {% block admin_content %} -

    {{ 'News configuration' | trans }}

    +

    {{ 'admin.dashboard.description' | trans }}

    {% endblock %} {% endblock %} diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminNewsMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminNewsMenuBuilder.php index 7d89d59f1..08e72884f 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminNewsMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminNewsMenuBuilder.php @@ -25,7 +25,7 @@ class AdminNewsMenuBuilder implements LocalMenuBuilderInterface return; } - $menu->addChild('News', [ + $menu->addChild('admin.dashboard.title', [ 'route' => 'chill_main_dashboard_admin', ]) ->setAttribute('class', 'list-group-item-header') @@ -33,7 +33,7 @@ class AdminNewsMenuBuilder implements LocalMenuBuilderInterface 'order' => 9000, ]); - $menu->addChild('NewsItem', [ + $menu->addChild('admin.dashboard.news', [ 'route' => 'chill_crud_news_item_index', ])->setExtras(['order' => 9000]); } diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index a3b772081..cd220de37 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -678,6 +678,10 @@ admin: undefined: non défini user: Utilisateur scope: Service + dashboard: + title: Tableau de bord + news: Actualités + description: Configuration du tableau de bord dashboard: news: From e8b8f30e3c6e78c2cfa750920530d8d87353f0cc Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 20 Nov 2023 15:52:30 +0100 Subject: [PATCH 52/60] add validation on start- and enddate of news item --- src/Bundle/ChillMainBundle/Entity/NewsItem.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Bundle/ChillMainBundle/Entity/NewsItem.php b/src/Bundle/ChillMainBundle/Entity/NewsItem.php index 6ca58afd1..7989d5545 100644 --- a/src/Bundle/ChillMainBundle/Entity/NewsItem.php +++ b/src/Bundle/ChillMainBundle/Entity/NewsItem.php @@ -66,6 +66,8 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface /** * @ORM\Column(type="date_immutable", nullable=false) * + * @Assert\NotNull + * * @Groups({"read"}) */ private ?\DateTimeImmutable $startDate = null; @@ -73,6 +75,8 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface /** * @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) * + * @Assert\GreaterThanOrEqual(propertyPath="startDate") + * * @Groups({"read"}) */ private ?\DateTimeImmutable $endDate = null; From c185c35c44071905a50f60cbb95d9fff0c9cebac Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 20 Nov 2023 17:13:04 +0100 Subject: [PATCH 53/60] Add history page for all news items with a search filter on the basis of the title or content --- .../Controller/UserNewsItemsController.php | 57 +++++++++++++++ .../Repository/NewsItemRepository.php | 37 ++++++++-- .../NewsItem/news_items_history.html.twig | 71 +++++++++++++++++++ .../MenuBuilder/SectionMenuBuilder.php | 8 +++ .../translations/messages.fr.yml | 5 ++ 5 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Controller/UserNewsItemsController.php create mode 100644 src/Bundle/ChillMainBundle/Resources/views/NewsItem/news_items_history.html.twig diff --git a/src/Bundle/ChillMainBundle/Controller/UserNewsItemsController.php b/src/Bundle/ChillMainBundle/Controller/UserNewsItemsController.php new file mode 100644 index 000000000..08074f346 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Controller/UserNewsItemsController.php @@ -0,0 +1,57 @@ +buildFilterOrder(false); + $total = $this->newsItemRepository->countAllFilteredByUser($filter->getQueryString()); + $newsItems = $this->newsItemRepository->findAllFilteredByUser($filter->getQueryString()); + + $pagination = $this->paginatorFactory->create($total); + + return $this->render('@ChillMain/NewsItem/news_items_history.html.twig', [ + 'entities' => $newsItems, + 'paginator' => $pagination, + 'filter_order' => $filter, + ]); + } + + private function buildFilterOrder($includeFilterByUser = true, $includeMissionType = false): FilterOrderHelper + { + $filterBuilder = $this->filterOrderHelperFactory + ->create(self::class) + ->addSearchBox(); + + return $filterBuilder->build(); + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php index be5190873..b9b0f8727 100644 --- a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -57,17 +57,46 @@ class NewsItemRepository implements ObjectRepository return NewsItem::class; } + public function buildBaseQuery( + string $pattern = null + ): QueryBuilder { + $qb = $this->createQueryBuilder('n'); + + if (null !== $pattern && '' !== $pattern) { + $qb->andWhere($qb->expr()->like('LOWER(UNACCENT(n.title))', 'LOWER(UNACCENT(:pattern))')) + ->orWhere($qb->expr()->like('LOWER(UNACCENT(n.content))', 'LOWER(UNACCENT(:pattern))')) + ->setParameter('pattern', '%'.$pattern.'%'); + } + + return $qb; + } + + public function findAllFilteredByUser(string $pattern = null) + { + $qb = $this->buildBaseQuery($pattern); + $qb->addOrderBy('n.startDate', 'DESC') + ->addOrderBy('n.id', 'DESC'); + + return $qb->getQuery()->getResult(); + } + public function findWithDateFilter() { - dump($this->buildQueryWithDateFilter() - ->getQuery() - ->getResult()); - return $this->buildQueryWithDateFilter() ->getQuery() ->getResult(); } + public function countAllFilteredByUser(string $pattern = null) + { + $qb = $this->buildBaseQuery($pattern); + + return $qb + ->select('COUNT(n)') + ->getQuery() + ->getSingleScalarResult(); + } + public function countWithDateFilter() { return $this->buildQueryWithDateFilter() diff --git a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/news_items_history.html.twig b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/news_items_history.html.twig new file mode 100644 index 000000000..fe5c70828 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/news_items_history.html.twig @@ -0,0 +1,71 @@ +{% extends "@ChillMain/layout.html.twig" %} + +{% block title %} + {{ 'news_history.title'|trans }} +{% endblock title %} + +{% block content %} +
    +

    {{ 'news_history.title'|trans }}

    + + {{ filter_order|chill_render_filter_order_helper }} + + {% if entities|length == 0 %} +

    + {{ "news_history.no_data"|trans }} +

    + {% else %} + +
    + + {% for entity in entities %} + +
    +
    + +
    +

    + {{ entity.title }} +

    +
    + {% if entity.startDate %} + {{ entity.startDate|format_date('long') }} + {% endif %} + {% if entity.endDate %} + - {{ entity.endDate|format_date('long') }} + {% endif %} +
    +
    +
    +
    +
    + {% apply markdown_to_html %} + {{ entity.content }} + {% endapply %} +
    +{#
    #} +{#
      #} +{#
    • #} +{# #} +{#
    • #} +{#
    #} +{#
    #} +
    +
    +
    +
    + {% endfor %} +
    + + {{ chill_pagination(paginator) }} + + + {% endif %} +
    +{% endblock %} diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php index 37c47e1bd..88007a074 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php @@ -58,6 +58,14 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface 'order' => 20, ]); } + + $menu->addChild($this->translator->trans('news_history.menu'), [ + 'route' => 'chill_main_news_items_history', + ]) + ->setExtras([ + 'icons' => ['newspaper-o'], + 'order' => 5, + ]); } public static function getMenuIds(): array diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index cd220de37..98933f614 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -688,3 +688,8 @@ dashboard: noDate: Pas de date de fin startDate: Date de début endDate: Date de fin + +news_history: + title: Historique des actualités + menu: Actualités + no_data: Aucune actualité From 502894eceab32409dd1d9200fd0e216c03d1c12a Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 21 Nov 2023 09:19:57 +0100 Subject: [PATCH 54/60] add limit and offset for apicontroller --- .../Controller/NewsItemApiController.php | 5 ++++- .../Repository/NewsItemRepository.php | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php index 25fe7620f..5224228a8 100644 --- a/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemApiController.php @@ -36,7 +36,10 @@ class NewsItemApiController { $total = $this->newsItemRepository->countWithDateFilter(); $paginator = $this->paginatorFactory->create($total); - $newsItems = $this->newsItemRepository->findWithDateFilter(); + $newsItems = $this->newsItemRepository->findWithDateFilter( + $limit = $paginator->getItemsPerPage(), + $offset = $paginator->getCurrentPage()->getFirstItemNumber() + ); return new JsonResponse($this->serializer->serialize( new Collection(array_values($newsItems), $paginator), diff --git a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php index b9b0f8727..88b597647 100644 --- a/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/NewsItemRepository.php @@ -80,9 +80,19 @@ class NewsItemRepository implements ObjectRepository return $qb->getQuery()->getResult(); } - public function findWithDateFilter() + public function findWithDateFilter($limit = null, $offset = null) { - return $this->buildQueryWithDateFilter() + $qb = $this->buildQueryWithDateFilter(); + + if ($limit) { + $qb->setMaxResults($limit); + } + + if ($offset) { + $qb->setFirstResult($offset); + } + + return $qb ->getQuery() ->getResult(); } From ed271bed314eb1388c2348788dfe80f8c569f8df Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 21 Nov 2023 09:20:21 +0100 Subject: [PATCH 55/60] fix truncating of text to avoid cutting into link --- .../DashboardWidgets/NewsItem.vue | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/NewsItem.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/NewsItem.vue index 173d0cda9..345545fe9 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/NewsItem.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/DashboardWidgets/NewsItem.vue @@ -58,14 +58,41 @@ const shouldTruncate = (content: string, maxLength = 100): boolean => { const truncateContent = (content: string, maxLength = 100): string => { if (shouldTruncate(content, maxLength)) { - const lastSpaceIndex = content.lastIndexOf(' ', maxLength); - console.log(lastSpaceIndex) + let truncatedContent = content.slice(0, maxLength); + let linkDepth = 0; + let linkStartIndex = -1; - if (lastSpaceIndex !== -1) { - return content.slice(0, lastSpaceIndex) + '...'; - } else { - return content.slice(0, maxLength) + '...'; + for (let i = 0; i < truncatedContent.length; i++) { + const char = truncatedContent[i]; + + if (char === '[') { + linkDepth++; + if (linkDepth === 1) { + linkStartIndex = i; + } + } else if (char === ']') { + linkDepth = Math.max(0, linkDepth - 1); + } else if (char === '(' && linkDepth === 0) { + truncatedContent = truncatedContent.slice(0, i); + break; + } } + + while (linkDepth > 0) { + truncatedContent += ']'; + linkDepth--; + } + + // If a link was found, append the URL inside the parentheses + if (linkStartIndex !== -1) { + const linkEndIndex = content.indexOf(')', linkStartIndex); + const url = content.slice(linkStartIndex + 1, linkEndIndex); + truncatedContent = truncatedContent.slice(0, linkStartIndex) + `(${url})`; + } + + truncatedContent += '...'; + + return truncatedContent; } else { return content; } @@ -76,9 +103,9 @@ const convertMarkdownToHtml = (markdown: string): string => { return DOMPurify.sanitize(rawHtml) }; -const prepareContent = (content: string, maxLength = 100): string => { - const truncatedContent = truncateContent(content, maxLength); - return convertMarkdownToHtml(truncatedContent); +const prepareContent = (content: string, maxLength = 200): string => { + const htmlContent = convertMarkdownToHtml(content); + return truncateContent(htmlContent, maxLength); }; const formatDate = (datetime: DateTime): string|null => { From 6dd463a7b027986e909d113f3f8746b2c910be9a Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 21 Nov 2023 09:20:45 +0100 Subject: [PATCH 56/60] let news tile stretch over entire dashboard --- .../Resources/public/vuejs/HomepageWidget/MyCustoms.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue index 65bed73ef..58120e5cf 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyCustoms.vue @@ -39,7 +39,7 @@ -
    +
    From f7de5fe1ed860a4ff6029b4783812eddccef0914 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 21 Nov 2023 09:28:19 +0100 Subject: [PATCH 57/60] remove custom serializer and adjust annotations of news item entity --- .../ChillMainBundle/Entity/NewsItem.php | 4 +-- .../Normalizer/NewsItemNormalizer.php | 35 ------------------- 2 files changed, 2 insertions(+), 37 deletions(-) delete mode 100644 src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php diff --git a/src/Bundle/ChillMainBundle/Entity/NewsItem.php b/src/Bundle/ChillMainBundle/Entity/NewsItem.php index 7989d5545..604c58c5f 100644 --- a/src/Bundle/ChillMainBundle/Entity/NewsItem.php +++ b/src/Bundle/ChillMainBundle/Entity/NewsItem.php @@ -44,7 +44,7 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface /** * @ORM\Column(type="text") * - * @Groups({"read", "write"}) + * @Groups({"read"}) * * @Assert\NotBlank * @@ -55,7 +55,7 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface /** * @ORM\Column(type="text") * - * @Groups({"read", "write"}) + * @Groups({"read"}) * * @Assert\NotBlank * diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php deleted file mode 100644 index 77a969752..000000000 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/NewsItemNormalizer.php +++ /dev/null @@ -1,35 +0,0 @@ - $newsItem->getId(), - 'title' => $newsItem->getTitle(), - 'content' => $newsItem->getContent(), - 'startdate' => $newsItem->getStartDate(), - 'enddate' => $newsItem->getEndDate(), - ]; - } - - public function supportsNormalization($data, $format = null): bool - { - return $data instanceof NewsItem && 'json' === $format; - } -} From 8f3256e46ed62544f5c06cabca5f1b144b7c25f4 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 21 Nov 2023 09:39:59 +0100 Subject: [PATCH 58/60] rename news item history controller --- ...serNewsItemsController.php => NewsItemHistoryController.php} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/Bundle/ChillMainBundle/Controller/{UserNewsItemsController.php => NewsItemHistoryController.php} (97%) diff --git a/src/Bundle/ChillMainBundle/Controller/UserNewsItemsController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemHistoryController.php similarity index 97% rename from src/Bundle/ChillMainBundle/Controller/UserNewsItemsController.php rename to src/Bundle/ChillMainBundle/Controller/NewsItemHistoryController.php index 08074f346..d92cd3a6f 100644 --- a/src/Bundle/ChillMainBundle/Controller/UserNewsItemsController.php +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemHistoryController.php @@ -20,7 +20,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -class UserNewsItemsController extends AbstractController +class NewsItemHistoryController extends AbstractController { public function __construct( private readonly NewsItemRepository $newsItemRepository, From 693bf657214c9a16d539edb03351f21b76c4d918 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 21 Nov 2023 10:18:16 +0100 Subject: [PATCH 59/60] Add single detail page to view entire article from within news item history page --- .../Controller/NewsItemHistoryController.php | 15 ++++++++++ .../Resources/views/NewsItem/index.html.twig | 6 ++-- .../NewsItem/news_items_history.html.twig | 29 ++++++++++--------- .../Resources/views/NewsItem/show.html.twig | 21 ++++++++++++++ .../translations/messages.fr.yml | 14 ++++----- 5 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Resources/views/NewsItem/show.html.twig diff --git a/src/Bundle/ChillMainBundle/Controller/NewsItemHistoryController.php b/src/Bundle/ChillMainBundle/Controller/NewsItemHistoryController.php index d92cd3a6f..8c645828b 100644 --- a/src/Bundle/ChillMainBundle/Controller/NewsItemHistoryController.php +++ b/src/Bundle/ChillMainBundle/Controller/NewsItemHistoryController.php @@ -46,6 +46,21 @@ class NewsItemHistoryController extends AbstractController ]); } + /** + * @Route("/{_locale}/news-items/{id}", name="chill_main_single_news_item") + */ + public function showSingleItem(int $id, Request $request): Response + { + $newsItem = $this->newsItemRepository->findOneBy(['id' => $id]); + + return $this->render( + '@ChillMain/NewsItem/show.html.twig', + [ + 'entity' => $newsItem, + ] + ); + } + private function buildFilterOrder($includeFilterByUser = true, $includeMissionType = false): FilterOrderHelper { $filterBuilder = $this->filterOrderHelperFactory diff --git a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig index 307073496..4eb02945b 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/index.html.twig @@ -4,8 +4,8 @@ {% embed '@ChillMain/CRUD/_index.html.twig' %} {% block table_entities_thead_tr %} {{ 'Title'|trans }} - {{ 'dashboard.news.startDate'|trans }} - {{ 'dashboard.news.endDate'|trans }} + {{ 'news.startDate'|trans }} + {{ 'news.endDate'|trans }} {% endblock %} {% block table_entities_tbody %} {% for entity in entities %} @@ -15,7 +15,7 @@ {% if entity.endDate is not null %} {{ entity.endDate|date }} {% else %} - {{ 'dashboard.news.noDate'|trans }} + {{ 'news.noDate'|trans }} {% endif %}
      diff --git a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/news_items_history.html.twig b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/news_items_history.html.twig index fe5c70828..e462c3302 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/news_items_history.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/news_items_history.html.twig @@ -1,18 +1,18 @@ {% extends "@ChillMain/layout.html.twig" %} {% block title %} - {{ 'news_history.title'|trans }} + {{ 'news.title'|trans }} {% endblock title %} {% block content %}
      -

      {{ 'news_history.title'|trans }}

      +

      {{ 'news.title'|trans }}

      {{ filter_order|chill_render_filter_order_helper }} {% if entities|length == 0 %}

      - {{ "news_history.no_data"|trans }} + {{ "news.no_data"|trans }}

      {% else %} @@ -39,17 +39,20 @@
      - {% apply markdown_to_html %} - {{ entity.content }} - {% endapply %} +{#
      #} + {{ entity.content|u.truncate(350, '…', false)|chill_markdown_to_html }} +{# {% if entity.content|length > 350 %}#} +{# {{ 'news.read_more'|trans }}#} +{# {% endif %}#} +{#
      #} +
      +
        +
      • + +
      • +
      +
      -{#
      #} -{#
        #} -{#
      • #} -{# #} -{#
      • #} -{#
      #} -{#
      #}
      diff --git a/src/Bundle/ChillMainBundle/Resources/views/NewsItem/show.html.twig b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/show.html.twig new file mode 100644 index 000000000..b86408183 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/NewsItem/show.html.twig @@ -0,0 +1,21 @@ +{% extends '@ChillMain/layout.html.twig' %} + +{% block title 'news.show_details'|trans %} + +{% block content %} +

      {{ entity.title }}

      + +
      +
      +
      + {{ entity.startDate|format_date('long') }} + {% if entity.endDate is not null %} + - {{ entity.endDate|format_date('long') }} + {% endif %} +
      +
      +
      + {{ entity.content|chill_markdown_to_html }} +
      +
      +{% endblock %} diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 98933f614..5d500f48e 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -75,7 +75,6 @@ Comment: Commentaire Comments: Commentaires Pinned comment: Commentaire épinglé Any comment: Aucun commentaire -Read more: Lire la suite (more...): (suite...) # comment embeddable @@ -683,13 +682,14 @@ admin: news: Actualités description: Configuration du tableau de bord -dashboard: - news: - noDate: Pas de date de fin - startDate: Date de début - endDate: Date de fin -news_history: +news: + noDate: Pas de date de fin + startDate: Date de début + endDate: Date de fin title: Historique des actualités menu: Actualités no_data: Aucune actualité + read_more: Lire la suite + + From dadde29bc21d04d239f6c41f29950f1e3fdbc2b7 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 21 Nov 2023 11:53:16 +0100 Subject: [PATCH 60/60] Fix navigation back to MyCustoms tab --- .../Resources/public/vuejs/HomepageWidget/App.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/App.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/App.vue index ea87277d5..02763221a 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/App.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/App.vue @@ -128,8 +128,11 @@ export default { }, methods: { selectTab(tab) { - this.$store.dispatch('getByTab', { tab: tab }); + if (tab !== 'MyCustoms') { + this.$store.dispatch('getByTab', { tab: tab }); + } this.activeTab = tab; + console.log(this.activeTab) } }, mounted() {