diff --git a/app/Resources/translations/messages.fr.yml b/app/Resources/translations/messages.fr.yml index f0aa70291..12c75800a 100644 --- a/app/Resources/translations/messages.fr.yml +++ b/app/Resources/translations/messages.fr.yml @@ -151,6 +151,9 @@ role: ROLE_ARGENTIQUE_ADMIN: Voir la documentation pour ajouter des photos au site ROLE_ARGENTIQUE_READ: Voir les photos du site + ROLE_NEWS_ADMIN: Peut modérer les news + ROLE_NEWS_EDIT: Peut modifier les news d'une asso s'il est autorisé + ROLE_NEWS_READ: Peut lire les news d'une asso ROLE_ASSOS_MEMBERS: Voir la liste des membres d'une association diff --git a/app/config/modules.yml.dist b/app/config/modules.yml.dist index 20b21126e..46f706f63 100644 --- a/app/config/modules.yml.dist +++ b/app/config/modules.yml.dist @@ -14,3 +14,4 @@ modules: - Etu\Module\UploadBundle\EtuModuleUploadBundle - Etu\Module\SIABundle\EtuModuleSIABundle - Etu\Module\BadgesBundle\EtuModuleBadgesBundle + - Etu\Module\NewsBundle\EtuModuleNewsBundle diff --git a/app/config/security.yml b/app/config/security.yml index 765505212..b6c2ba9c5 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -12,6 +12,7 @@ security: - ROLE_EVENTS_INTERNAL # can read Private/internal calendar and events ROLE_USER: + - ROLE_NEWS_READ # Read orga's news ROLE_STUDENT: - ROLE_CORE_SUBSCRIBE # User can receive and use subscriptions @@ -30,6 +31,7 @@ security: - ROLE_COVOIT_EDIT # Can answer, post and set alerts on covoit bundle - ROLE_CUMUL # Can cumul timetables - ROLE_DAYMAIL_EDIT # Can edit daymail of his organization if authorized + - ROLE_NEWS_EDIT # Can edit news of his organization if authorized - ROLE_EVENTS_INTERNAL # can read Private/internal calendar and events - ROLE_EVENTS_ANSWER # Can see answer list - ROLE_EVENTS_ANSWER_POST # Can post an answer @@ -59,6 +61,7 @@ security: - ROLE_COVOIT_EDIT # Can answer, post and set alerts on covoit bundle - ROLE_CUMUL # Can cumul timetables - ROLE_DAYMAIL_EDIT # Can edit daymail of his organization if authorized + - ROLE_NEWS_EDIT # Can edit news of his organization if authorized - ROLE_EVENTS_INTERNAL # can read Private/internal calendar and events - ROLE_EVENTS_EDIT # Can edit event of his organization if authorized - ROLE_TROMBI # Can search on trombi @@ -79,6 +82,7 @@ security: - ROLE_COVOIT # Can read covoit bundle - ROLE_COVOIT_EDIT # Can answer, post and set alerts on covoit bundle - ROLE_DAYMAIL_EDIT # Can edit daymail of his organization if authorized + - ROLE_NEWS_EDIT # Can edit news of his organization if authorized - ROLE_EVENTS_INTERNAL # can read Private/internal calendar and events - ROLE_EVENTS_EDIT # Can edit event of his organization if authorized - ROLE_TROMBI # Can search on trombi @@ -104,6 +108,7 @@ security: - ROLE_UV_REVIEW_ADMIN # Can moderate and remove UV review and old exams - ROLE_BADGE_ADMIN # Can create and attribute badges - ROLE_WIKI_ADMIN # Can lock, read and write on every admin page on the wiki + - ROLE_NEWS_ADMIN # Edit news ROLE_SUPERADMIN: - ROLE_ADMIN @@ -120,6 +125,7 @@ security: - ROLE_CORE_ADMIN_HOME # Can see admin homepage - ROLE_FORUM_ADMIN # Can moderate forum - ROLE_UV_REVIEW_ADMIN # Can moderate and remove UV review and old exams + - ROLE_NEWS_ADMIN # Edit news blog ROLE_ARGENTIQUE: - ROLE_CORE_ADMIN_HOME # Can see admin homepage @@ -141,6 +147,7 @@ security: - ROLE_CORE_SCHEDULE_OWN # Can read his own schedule - ROLE_CORE_HOMEPAGE # Can see the private homepage - ROLE_ARGENTIQUE_READ # View pictures + - ROLE_NEWS_READ # View news - ROLE_ASSOS_MEMBERS # Read assos member list - ROLE_BUGS # read bugs list - ROLE_COVOIT # Can read covoit bundle diff --git a/doc/1. Introduction et installation/4. Bonnes pratiques et conventions.md b/doc/1. Introduction et installation/4. Bonnes pratiques et conventions.md index d72f0755b..3c75db8e4 100644 --- a/doc/1. Introduction et installation/4. Bonnes pratiques et conventions.md +++ b/doc/1. Introduction et installation/4. Bonnes pratiques et conventions.md @@ -61,7 +61,6 @@ pour cela, il faut suivre cette convention. - La configuration est stockée dans `Resources/config` - Les traductions sont stockées dans `Resources/translations` - Les extensions Twig sont stockées dans `Twig` et sont suffixées de `Extension` - - Les traductions sont stockées dans `Resources/translations` - Les commandes sont stockées dans `Command` - Les types de champs de formulaires sont stockés dans `Form` - Les classes outils (classes généralistes utiles partout) sont stockés dans `Util` diff --git a/src/Etu/Core/UserBundle/Resources/translations/messages.fr.yml b/src/Etu/Core/UserBundle/Resources/translations/messages.fr.yml index 566745129..2e9c91a3b 100644 --- a/src/Etu/Core/UserBundle/Resources/translations/messages.fr.yml +++ b/src/Etu/Core/UserBundle/Resources/translations/messages.fr.yml @@ -171,6 +171,7 @@ user: notifications: Notifications event: Evènements daymail: Daymail + news: News wiki: Wiki public: Page publique sia: Gestionnaire SIA diff --git a/src/Etu/Core/UserBundle/Resources/views/Memberships/layout.html.twig b/src/Etu/Core/UserBundle/Resources/views/Memberships/layout.html.twig index a0c5963a3..058ecb97b 100644 --- a/src/Etu/Core/UserBundle/Resources/views/Memberships/layout.html.twig +++ b/src/Etu/Core/UserBundle/Resources/views/Memberships/layout.html.twig @@ -74,6 +74,13 @@ {% endif %} + {% if membership.hasPermission('news') and etu.modules.isEnabled('news') %} +
  • + + {{ 'user.memberships.menu.news'|trans }} + +
  • + {% endif %} {% if etu.modules.isEnabled('wiki') %}
  • diff --git a/src/Etu/Module/EventsBundle/Resources/views/Memberships/delete.html.twig b/src/Etu/Module/EventsBundle/Resources/views/Memberships/delete.html.twig index e100962eb..38bd11694 100644 --- a/src/Etu/Module/EventsBundle/Resources/views/Memberships/delete.html.twig +++ b/src/Etu/Module/EventsBundle/Resources/views/Memberships/delete.html.twig @@ -82,6 +82,14 @@
  • {% endif %} + {% if membership.hasPermission('news') and etu.modules.isEnabled('news') %} +
  • + + {{ 'user.memberships.menu.news'|trans }} + +
  • + {% endif %} + {% if etu.modules.isEnabled('assos') %}
  • diff --git a/src/Etu/Module/NewsBundle/Controller/MainController.php b/src/Etu/Module/NewsBundle/Controller/MainController.php new file mode 100644 index 000000000..7086c525e --- /dev/null +++ b/src/Etu/Module/NewsBundle/Controller/MainController.php @@ -0,0 +1,217 @@ +denyAccessUnlessGranted('ROLE_NEWS_READ'); + /** @var $em EntityManager */ + $em = $this->getDoctrine()->getManager(); + + $query = $em->createQueryBuilder() + ->select('a, o') + ->from('EtuModuleNewsBundle:Article', 'a') + ->leftJoin('a.orga', 'o') + ->where('a.publishedAt is not NULL') + ->andWhere('a.validatedAt is not NULL'); + /** @var $articles Article[] */ + $articles = $query + ->orderBy('a.createdAt', 'DESC') + ->getQuery() + ->getResult(); + return ['articles' => $articles]; + } + + /** + * @Route("/moderate", name="news_moderate") + * @Template() + */ + public function moderateAction() + { + $this->denyAccessUnlessGranted('ROLE_NEWS_ADMIN'); + /** @var $em EntityManager */ + $em = $this->getDoctrine()->getManager(); + + $query = $em->createQueryBuilder() + ->select('a, o') + ->from('EtuModuleNewsBundle:Article', 'a') + ->leftJoin('a.orga', 'o') + ->where('a.validatedAt is NULL') + ->andWhere('a.publishedAt is not NULL'); + /** @var $articles Article[] */ + $articles = $query + ->orderBy('a.createdAt', 'DESC') + ->getQuery() + ->getResult(); + return ['articles' => $articles]; + } + /** + * @Route("/articles/{id}", name="news_view") + * @Template() + * + * @param mixed $id + */ + public function viewAction($id) + { + $this->denyAccessUnlessGranted('ROLE_NEWS_READ'); + + + /** @var $em EntityManager */ + $em = $this->getDoctrine()->getManager(); + $query = $em->createQueryBuilder() + ->select('a, au, o') + ->from('EtuModuleNewsBundle:Article', 'a') + ->leftJoin('a.author', 'au') + ->leftJoin('a.orga', 'o') + ->where('a.id = :id') + ->setParameter('id', $id); + + /** @var $article Article */ + $article = $query + ->getQuery() + ->setMaxResults(1) + ->getOneOrNullResult(); + + if(!$article){ + $this->get('session')->getFlashBag()->set('message', [ + 'type' => 'error', + 'message' => 'news.main.article.notFound', + ]); + return $this->redirect($this->generateUrl('news_index')); + } + /** @var $memberships Member[] */ + $memberships = $em->createQueryBuilder() + ->select('m, o') + ->from('EtuUserBundle:Member', 'm') + ->leftJoin('m.organization', 'o') + ->andWhere('m.user = :user') + ->setParameter('user', $this->getUser()->getId()) + ->orderBy('m.role', 'DESC') + ->addOrderBy('o.name', 'ASC') + ->getQuery() + ->getResult(); + + $membership = null; + + foreach ($memberships as $m) { + if ($m->getOrganization()->getLogin() == $article->getOrga()->getLogin()) { + $membership = $m; + break; + } + } + $canEdit = false; + if($this->isGranted('ROLE_NEWS_EDIT') && $membership != null) { + $canEdit = $membership->hasPermission('news'); + } + if(!$this->isGranted('ROLE_NEWS_ADMIN') && !$canEdit && $article->getValidatedAt() == null) { + $this->get('session')->getFlashBag()->set('message', [ + 'type' => 'error', + 'message' => 'news.main.article.notFound', + ]); + return $this->redirect($this->generateUrl('news_index')); + } + return [ + 'article' => $article, + 'canEdit' => $canEdit, + ]; + } + + + /** + * @Route( + * "/article/{id}/validate", + * name="news_validate" + * ) + * @Template() + * + * @param mixed $id + */ + public function validateAction($id) + { + $this->denyAccessUnlessGranted('ROLE_NEWS_ADMIN'); + + /** @var $em EntityManager */ + $em = $this->getDoctrine()->getManager(); + + /** @var $article Article */ + $article = $em->createQueryBuilder() + ->select('a') + ->from('EtuModuleNewsBundle:Article', 'a') + ->where('a.id = :id') + ->setParameter('id', $id) + ->getQuery() + ->setMaxResults(1) + ->getOneOrNullResult(); + + if (!$article) { + throw $this->createNotFoundException('Article not found'); + } + $article->setValidatedAt(new \DateTime()); + $this->get('session')->getFlashBag()->set('message', [ + 'type' => 'success', + 'message' => 'news.main.article.confirmValidate', + ]); + + $em->persist($article); + $em->flush(); + + return $this->redirect($this->generateUrl('news_view', ['id' => $id])); + } + + /** + * @Route( + * "/article/{id}/unvalidate", + * name="news_unvalidate" + * ) + * @Template() + * + * @param mixed $id + */ + public function unvalidateAction($id) + { + $this->denyAccessUnlessGranted('ROLE_NEWS_ADMIN'); + + /** @var $em EntityManager */ + $em = $this->getDoctrine()->getManager(); + + /** @var $article Article */ + $article = $em->createQueryBuilder() + ->select('a') + ->from('EtuModuleNewsBundle:Article', 'a') + ->where('a.id = :id') + ->setParameter('id', $id) + ->getQuery() + ->setMaxResults(1) + ->getOneOrNullResult(); + + if (!$article) { + throw $this->createNotFoundException('Article not found'); + } + $article->setValidatedAt(null); + $this->get('session')->getFlashBag()->set('message', [ + 'type' => 'warning', + 'message' => 'news.main.article.confirmUnvalidate', + ]); + + $em->persist($article); + $em->flush(); + + return $this->redirect($this->generateUrl('news_view', ['id' => $id])); + } +} diff --git a/src/Etu/Module/NewsBundle/Controller/MembershipsController.php b/src/Etu/Module/NewsBundle/Controller/MembershipsController.php new file mode 100644 index 000000000..844d7d37e --- /dev/null +++ b/src/Etu/Module/NewsBundle/Controller/MembershipsController.php @@ -0,0 +1,239 @@ +denyAccessUnlessGranted('ROLE_NEWS_EDIT'); + + /** @var $em EntityManager */ + $em = $this->getDoctrine()->getManager(); + + /** @var $memberships Member[] */ + $memberships = $em->createQueryBuilder() + ->select('m, o') + ->from('EtuUserBundle:Member', 'm') + ->leftJoin('m.organization', 'o') + ->andWhere('m.user = :user') + ->setParameter('user', $this->getUser()->getId()) + ->orderBy('m.role', 'DESC') + ->addOrderBy('o.name', 'ASC') + ->getQuery() + ->getResult(); + + $membership = null; + + foreach ($memberships as $m) { + if ($m->getOrganization()->getLogin() == $login) { + $membership = $m; + break; + } + } + + if (!$membership) { + throw $this->createNotFoundException('Membership or organization not found for login '.$login); + } + + if (!$membership->hasPermission('news')) { + return $this->createAccessDeniedResponse(); + } + + $orga = $membership->getOrganization(); + + /** @var $unpublishedArticles Article[] */ + $unpublishedArticles = $em->createQueryBuilder() + ->select('a') + ->from('EtuModuleNewsBundle:Article', 'a') + ->where('a.validatedAt is NULL') + ->andWhere('a.id != :id') + ->andWhere('a.orga = :orga') + ->setParameter('id', $id) + ->setParameter('orga', $orga->getId()) + ->orderBy('a.createdAt', 'DESC') + ->getQuery() + ->setMaxResults(10) + ->getResult(); + + $available = []; + $future = []; + if($id != '0') { + $future['new'] = 'new'; + } + /** @var $article Article */ + $article = $em->createQueryBuilder() + ->select('a') + ->from('EtuModuleNewsBundle:Article', 'a') + ->where('a.id = :id') + ->setParameter('id', $id) + ->andWhere('a.orga = :orga') + ->setParameter('orga', $orga->getId()) + ->getQuery() + ->setMaxResults(1) + ->getOneOrNullResult(); + $day = new \DateTime(); + + foreach ($unpublishedArticles as $unpublishedArticle) { + $available[$unpublishedArticle->getId()] = ['id' => $unpublishedArticle->getId(), 'name' => $unpublishedArticle->getTitle()]; + } + + $available = array_merge($future, $available); + + if (!$article) { + $article = new Article($orga, $this->getUser()); + } + + $form = $this->createFormBuilder($article) + ->add('title', TextType::class, ['required' => true, 'label' => 'news.main.article.labels.title', 'attr' => ['maxlength' => 100]]) + ->add('body', EditorEmailType::class, ['required' => true, 'label' => 'news.main.article.labels.body']) + ->getForm(); + + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + + + if ($request->request->has('_publish')) { + $article->setPublishedAt(new \DateTime()); + $this->get('session')->getFlashBag()->set('message', [ + 'type' => 'success', + 'message' => 'news.main.article.confirmPublish', + ]); + } + elseif ($request->request->has('_unpublish')) { + $article->setPublishedAt(null); + $this->get('session')->getFlashBag()->set('message', [ + 'type' => 'warning', + 'message' => 'news.main.article.confirmUnpublish', + ]); + } + else { + if($article->getPublishedAt() != null) { + $this->get('session')->getFlashBag()->set('message', [ + 'type' => 'success', + 'message' => 'news.main.article.confirm', + ]); + } else { + $this->get('session')->getFlashBag()->set('message', [ + 'type' => 'warning', + 'message' => 'news.main.article.confirmWarning', + ]); + } + } + $em->persist($article); + $em->flush(); + + if ($request->request->has('_saveandsee') || $request->request->has('_publish')) { + return $this->redirect($this->generateUrl('news_view', [ + 'id' => $article->getId(), + ])); + } + + return $this->redirect($this->generateUrl('memberships_orga_news', [ + 'login' => $login, + 'id' => $article->getId(), + ])); + } + return [ + 'memberships' => $memberships, + 'membership' => $membership, + 'orga' => $orga, + 'form' => $form->createView(), + 'article' => $article, + 'available' => $available, + 'currentDay' => $day, + 'day' => $day->format('d-m-Y'), + ]; + } + + + /** + * @Route( + * "/user/membership/{login}/news/{id}/remove", + * name="news_remove" + * ) + * @Template() + * + * @param mixed $login + * @param mixed $id + */ + public function removeAction($login, $id) + { + $this->denyAccessUnlessGranted('ROLE_NEWS_EDIT'); + + /** @var $em EntityManager */ + $em = $this->getDoctrine()->getManager(); + + /** @var $memberships Member[] */ + $memberships = $em->createQueryBuilder() + ->select('m, o') + ->from('EtuUserBundle:Member', 'm') + ->leftJoin('m.organization', 'o') + ->andWhere('m.user = :user') + ->setParameter('user', $this->getUser()->getId()) + ->orderBy('m.role', 'DESC') + ->addOrderBy('o.name', 'ASC') + ->getQuery() + ->getResult(); + + $membership = null; + + foreach ($memberships as $m) { + if ($m->getOrganization()->getLogin() == $login) { + $membership = $m; + break; + } + } + + if (!$membership) { + throw $this->createNotFoundException('Membership or organization not found for login '.$login); + } + + if (!$membership->hasPermission('news')) { + return $this->createAccessDeniedResponse(); + } + + $orga = $membership->getOrganization(); + + /** @var $article Article */ + $article = $em->createQueryBuilder() + ->select('a') + ->from('EtuModuleNewsBundle:Article', 'a') + ->where('a.id = :id') + ->andWhere('a.orga = :orga') + ->setParameter('orga', $orga->getId()) + ->setParameter('id', $id) + ->getQuery() + ->setMaxResults(1) + ->getOneOrNullResult(); + + if (!$article) { + throw $this->createNotFoundException('Article not found'); + } + + $em->remove($article); + $em->flush(); + + return $this->redirect($this->generateUrl('news_index')); + } +} diff --git a/src/Etu/Module/NewsBundle/DependencyInjection/Configuration.php b/src/Etu/Module/NewsBundle/DependencyInjection/Configuration.php new file mode 100644 index 000000000..1167e8f7c --- /dev/null +++ b/src/Etu/Module/NewsBundle/DependencyInjection/Configuration.php @@ -0,0 +1,19 @@ +root('etu_news'); + return $treeBuilder; + } +} diff --git a/src/Etu/Module/NewsBundle/DependencyInjection/EtuModuleNewsExtension.php b/src/Etu/Module/NewsBundle/DependencyInjection/EtuModuleNewsExtension.php new file mode 100644 index 000000000..621628b50 --- /dev/null +++ b/src/Etu/Module/NewsBundle/DependencyInjection/EtuModuleNewsExtension.php @@ -0,0 +1,28 @@ +processConfiguration($configuration, $configs); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.yml'); + } +} diff --git a/src/Etu/Module/NewsBundle/Entity/Article.php b/src/Etu/Module/NewsBundle/Entity/Article.php new file mode 100644 index 000000000..1b31f1432 --- /dev/null +++ b/src/Etu/Module/NewsBundle/Entity/Article.php @@ -0,0 +1,309 @@ +setOrga($orga); + $this->setAuthor($author); + } + /** + * @param \DateTime $createdAt + * + * @return Article + */ + public function setCreatedAt($createdAt) + { + $this->createdAt = $createdAt; + + return $this; + } + + /** + * @return \DateTime + */ + public function getCreatedAt() + { + return $this->createdAt; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param \Etu\Core\UserBundle\Entity\Organization $orga + * + * @return Article + */ + public function setOrga($orga) + { + $this->orga = $orga; + + return $this; + } + + /** + * @return \Etu\Core\UserBundle\Entity\Organization + */ + public function getOrga() + { + return $this->orga; + } + + /** + * @param string $title + * + * @return Article + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $body + * + * @return Article + */ + public function setBody($body) + { + $this->body = $body; + + return $this; + } + + /** + * @return string + */ + public function getBody() + { + return $this->body; + } + + /** + * @param \DateTime $updatedAt + * + * @return Article + */ + public function setUpdatedAt($updatedAt) + { + $this->updatedAt = $updatedAt; + + return $this; + } + + /** + * @return \DateTime + */ + public function getUpdatedAt() + { + return $this->updatedAt; + } + + /** + * @param \Etu\Core\UserBundle\Entity\User $author + * + * @return Article + */ + public function setAuthor($author) + { + $this->author = $author; + + return $this; + } + + /** + * @return \Etu\Core\UserBundle\Entity\User + */ + public function getAuthor() + { + return $this->author; + } + + /** + * Set deletedAt. + * + * @param \DateTime $deletedAt + * + * @return Article + */ + public function setDeletedAt($deletedAt) + { + $this->deletedAt = $deletedAt; + + return $this; + } + + /** + * Get deletedAt. + * + * @return \DateTime + */ + public function getDeletedAt() + { + return $this->deletedAt; + } + + /** + * Set publishedAt. + * + * @param \DateTime $publishedAt + * + * @return Article + */ + public function setPublishedAt($publishedAt) + { + $this->publishedAt = $publishedAt; + + return $this; + } + + /** + * Get publishedAt. + * + * @return \DateTime + */ + public function getPublishedAt() + { + return $this->publishedAt; + } + + /** + * Set validatedAt. + * + * @param \DateTime $validatedAt + * + * @return Article + */ + public function setValidatedAt($validatedAt) + { + $this->validatedAt = $validatedAt; + + return $this; + } + + /** + * Get validatedAt. + * + * @return \DateTime + */ + public function getValidatedAt() + { + return $this->validatedAt; + } +} diff --git a/src/Etu/Module/NewsBundle/EtuModuleNewsBundle.php b/src/Etu/Module/NewsBundle/EtuModuleNewsBundle.php new file mode 100644 index 000000000..62ec54b1e --- /dev/null +++ b/src/Etu/Module/NewsBundle/EtuModuleNewsBundle.php @@ -0,0 +1,96 @@ +getAdminMenuBuilder() + ->getBlock('base.admin_menu.title') + ->add('news.admin.menu_item') + ->setIcon('briefcase.png') + ->setUrl($this->getRouter()->generate('news_index')) + ->setPosition(7) + ->setRole('ROLE_NEWS_ADMIN') + ->end(); + + $this->getSidebarBuilder() + ->getBlock('base.sidebar.services.title') + ->add('news.sidebar.service') + ->setPosition(100) + ->setIcon('briefcase.png') + ->setUrl($this->router->generate('news_index')) + ->setRole('ROLE_NEWS_READ') + ->end(); + } + + /** + * Module identifier (to be required by other modules) + * + * @return string + */ + public function getIdentifier() + { + return 'news'; + } + + /** + * Module title (describe shortly its aim) + * + * @return string + */ + public function getTitle() + { + return 'News'; + } + + /** + * Module author + * + * @return string + */ + public function getAuthor() + { + return 'Arnaud Dufour'; + } + + /** + * Module description + * + * @return string + */ + public function getDescription() + { + return 'Module to handle news'; + } + + /** + * @return array + */ + public function getAvailablePermissions() + { + return [ + new OrgaPermission('news', 'Peut modifier les news de l\'association'), + ]; + } + + /** + * Define the modules requirements (the other required modules) using their identifiers + * + * @return array + */ + public function getRequirements() + { + return array( + // Insert your requirements here + ); + } +} diff --git a/src/Etu/Module/NewsBundle/Resources/config/services.yml b/src/Etu/Module/NewsBundle/Resources/config/services.yml new file mode 100644 index 000000000..83135b738 --- /dev/null +++ b/src/Etu/Module/NewsBundle/Resources/config/services.yml @@ -0,0 +1,4 @@ + +parameters: ~ + +services: ~ diff --git a/src/Etu/Module/NewsBundle/Resources/translations/messages.cn.yml b/src/Etu/Module/NewsBundle/Resources/translations/messages.cn.yml new file mode 100644 index 000000000..e69de29bb diff --git a/src/Etu/Module/NewsBundle/Resources/translations/messages.en.yml b/src/Etu/Module/NewsBundle/Resources/translations/messages.en.yml new file mode 100644 index 000000000..4a68fd75f --- /dev/null +++ b/src/Etu/Module/NewsBundle/Resources/translations/messages.en.yml @@ -0,0 +1,48 @@ + +news: + admin: + menu_item: Moderate News + sidebar: + service: News + main: + article: + confirm: The article has been saved + confirmWarning: The article has been saved, do not forget to publish it ! + confirmPublish: The article has been published ! + confirmUnpublish: The article has been withdrawn ! + confirmValidate: The article has been validated, it is now visible to all ! + confirmUnvalidate: The article has been invalidated, it is now hidden to all ! + dropdown: Other unpublished articles + delete: Delete article + edit: Edit article + labels: + title: Title + body: Content + new: Create an article + notFound: The article you're trying to get doesn't exist or doesn't exist anymore. + publish: Publish this article + unpublish: Withdraw this publication + saveandsee: Save and see + index: + head: Organizations latest news + moderate: Moderate + new: Add an article + noResult: No articles + notPublished: NOT PUBLISHED + moderate: + head: News moderation + back: Back + body: You can here moderate articles written by all associations. Please check if the content is decent, everybody can read those articles. If there's incorrect spelling, tell them. + noResult: No articles to moderate + subtitle: Articles to moderate + logo: + alt: Associations' news + title: Associations' news + title: Associations' news + view: + back: Back to the liste + edit: Edit article + notPublished: This article is not visible, you must publish it + notValidated: This article is not validated, wait until a moderator check it + unvalidate: Invalidate + validate: Validate \ No newline at end of file diff --git a/src/Etu/Module/NewsBundle/Resources/translations/messages.es.yml b/src/Etu/Module/NewsBundle/Resources/translations/messages.es.yml new file mode 100644 index 000000000..e69de29bb diff --git a/src/Etu/Module/NewsBundle/Resources/translations/messages.fr.yml b/src/Etu/Module/NewsBundle/Resources/translations/messages.fr.yml new file mode 100644 index 000000000..b9fc446c8 --- /dev/null +++ b/src/Etu/Module/NewsBundle/Resources/translations/messages.fr.yml @@ -0,0 +1,48 @@ + +news: + admin: + menu_item: Modérer les News + sidebar: + service: News + main: + article: + confirm: L'article a été sauvegardé + confirmWarning: L'article a été sauvegardé, n'oubliez pas de le publier ! + confirmPublish: L'article a été publié ! + confirmUnpublish: L'article a été retiré ! + confirmValidate: L'article a été validé, il est maintenant visible de tous ! + confirmUnvalidate: L'article a été invalidé, il n'est maintenant plus visble de tous ! + dropdown: Autre articles non publiés + delete: Supprimer l'article + edit: Modifier l'article + labels: + title: Titre + body: Contenu + new: Créer un article + notFound: L'article que vous souhaitez consulter n'existe pas ou n'existe plus. + publish: Publier cet article + unpublish: Retirer la publication + saveandsee: Sauvegarder et visualiser + index: + head: Voici les dernières news des assos + moderate: Modération + new: Ajouter un article + noResult: Aucun article pour le moment + notPublished: NON PUBLIÉ + moderate: + head: Modération des news + back: Retour + body: Vous pouvez ici modérer les articles écrits par les associations. Vérifiez bien que le contenu est décent, tout le monde peut lire ces articles. S'il y a des fautes, signalez le leur. + noResult: Aucun article à modérer pour le moment + subtitle: Articles à modérer + logo: + alt: News des Associations + title: News des Associations + title: News des Associations + view: + back: Retourner à la liste + edit: Modifier l'article + notPublished: Cet article n'est pas visible, vous devez le publier + notValidated: Cet article n'est pas validé, vous devez attendre qu'un modérateur le valide + unvalidate: Invalider + validate: Valider \ No newline at end of file diff --git a/src/Etu/Module/NewsBundle/Resources/views/Main/index.html.twig b/src/Etu/Module/NewsBundle/Resources/views/Main/index.html.twig new file mode 100644 index 000000000..6efb18eb3 --- /dev/null +++ b/src/Etu/Module/NewsBundle/Resources/views/Main/index.html.twig @@ -0,0 +1,43 @@ +{% extends '::page-2cols.html.twig' %} + +{% block title %}{{ 'news.main.title'|trans }}{% endblock %} + +{% block titleIcon %} + {{ 'news.main.logo.alt'|trans }} +{% endblock %} + +{% block content %} + {% if is_granted('ROLE_NEWS_ADMIN') %} + + {% endif %} +
    +

    {{ 'news.main.index.head'|trans }}

    + +
    +

    Derniers articles :

    + + +
    +{% endblock %} diff --git a/src/Etu/Module/NewsBundle/Resources/views/Main/moderate.html.twig b/src/Etu/Module/NewsBundle/Resources/views/Main/moderate.html.twig new file mode 100644 index 000000000..28cb56012 --- /dev/null +++ b/src/Etu/Module/NewsBundle/Resources/views/Main/moderate.html.twig @@ -0,0 +1,40 @@ +{% extends '::page-2cols.html.twig' %} + +{% block title %}{{ 'news.main.title'|trans }}{% endblock %} + +{% block titleIcon %} + {{ 'news.main.logo.alt'|trans }} +{% endblock %} + +{% block content %} + +
    +

    {{ 'news.main.moderate.head'|trans }}

    +

    {{ 'news.main.moderate.body'|trans }}

    + +
    +

    {{ 'news.main.moderate.subtitle'|trans }} :

    + + +
    +{% endblock %} diff --git a/src/Etu/Module/NewsBundle/Resources/views/Main/view.html.twig b/src/Etu/Module/NewsBundle/Resources/views/Main/view.html.twig new file mode 100644 index 000000000..dbe54aa3c --- /dev/null +++ b/src/Etu/Module/NewsBundle/Resources/views/Main/view.html.twig @@ -0,0 +1,64 @@ +{% extends '::page-2cols.html.twig' %} + +{% block title %}{{ article.title }}{% endblock %} + +{% block titleIcon %} + {{ 'news.main.logo.alt'|trans }} +{% endblock %} + +{% block content %} + + + {% if article.publishedAt == null %} + + {% elseif article.validatedAt == null %} + + {% endif %} +
    + {{ article.body|raw }} +
    +
    +
    + {% if article.publishedAt == null %} +

    Créé le {{ article.createdAt|date('d/m/Y H:i') }} par {{ article.author.fullname }}

    + {% else %} +

    Publié le {{ article.publishedAt|date('d/m/Y H:i') }} par {{ article.author.fullname }}

    + {% endif %} +
    +{% endblock %} diff --git a/src/Etu/Module/NewsBundle/Resources/views/Memberships/news.html.twig b/src/Etu/Module/NewsBundle/Resources/views/Memberships/news.html.twig new file mode 100644 index 000000000..a9459dae8 --- /dev/null +++ b/src/Etu/Module/NewsBundle/Resources/views/Memberships/news.html.twig @@ -0,0 +1,82 @@ +{% extends '@EtuUser/Memberships/layout.html.twig' %} +{% set tab = 'memberships_orga_news' %} + +{% block title %}{{ membership.organization.name }}{% endblock %} + +{% block titleIcon %} + {{ 'base.logo.alt'|trans }} +{% endblock %} + +{% block membership_content %} + + {{ form_start(form) }} + {% if available|count > 0 %} +
    + +
    +
    + + Modifier une autre news + + + +
    +
    +
    + {% endif %} + {{ form_row(form.title) }} + {{ form_row(form.body) }} + +
    +
    + {{ form_rest(form) }} + + {% if article.id > 0 %} + + + {% if article.publishedAt != null %} + + {% else %} + + {% endif %} + + {{ 'news.main.article.delete'|trans }} + + {% else %} + + {% endif %} +
    +
    + + {{ form_end(form) }} +{% endblock %} diff --git a/web/assets/scss/bundles/uvs.scss b/web/assets/scss/bundles/uvs.scss index 245ae1f63..9390fb207 100644 --- a/web/assets/scss/bundles/uvs.scss +++ b/web/assets/scss/bundles/uvs.scss @@ -1,4 +1,26 @@ +.article-list { + margin: 0; + padding: 0; + list-style-type: none; + + li { + list-style-type: none; + margin: 0 0 10px 0; + padding: 0; + } + a { + display: flex; + justify-content: space-between; + background: #f5f5f5; + padding: 10px 5px; + } + a:hover { + background: #e5e5e5; + text-decoration: none; + } +} + .uvs-category { display: block; float: left;