diff --git a/src/cms/api/tests/test_page_contact.py b/src/cms/api/tests/test_page_contact.py new file mode 100644 index 0000000..d85db87 --- /dev/null +++ b/src/cms/api/tests/test_page_contact.py @@ -0,0 +1,170 @@ +import logging + +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ObjectDoesNotExist +from django.test import Client, TestCase +from django.urls import reverse + +from cms.contacts.tests import ContactUnitTest + +from cms.contexts.tests import ContextUnitTest + +from cms.pages.models import PageContact +from cms.pages.tests import PageUnitTest + + +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + + +class PageContactAPIUnitTest(TestCase): + + def setUp(self): + pass + + def test_page_contact(self): + """ + Page Contact API + """ + req = Client() + user2 = ContextUnitTest.create_user(username='staff', + is_staff=True) + + ebu = ContextUnitTest.create_editorialboard_user() + user = ebu.user + webpath = ebu.webpath + site = webpath.site + + page = PageUnitTest.create_page() + page.webpath = webpath + page.save() + + # page contacts list + url = reverse('unicms_api:editorial-board-site-webpath-page-contacts', + kwargs={'site_id': site.pk, + 'webpath_id': webpath.pk, + 'page_id': page.pk}) + + # accessible to staff users only + res = req.get(url) + assert res.status_code == 403 + # site is not managed by user2 + req.force_login(user2) + res = req.get(url) + assert res.status_code == 403 + # user is staff + user.is_staff = True + user.is_superuser = True + user.save() + req.force_login(user) + res = req.get(url) + assert isinstance(res.json(), dict) + + # POST + contact = ContactUnitTest.create_contact() + data = {'page': page.pk, + 'contact': contact.pk, + 'is_active': True + } + # user hasn't permission + req.force_login(user2) + res = req.post(url, data=data, follow=1, + content_type='application/json') + assert res.status_code == 403 + # user has permission + req.force_login(user) + res = req.post(url, data=data, follow=1, + content_type='application/json') + page_contact = PageContact.objects.filter(contact=contact).last() + assert page_contact + + # GET LOGS + url = reverse('unicms_api:editorial-board-site-webpath-page-contact-logs', + kwargs={'site_id': site.pk, + 'webpath_id': webpath.pk, + 'page_id': page.pk, + 'pk': contact.pk}) + res = req.get(url, content_type='application/json',) + assert isinstance(res.json(), dict) + + # redis lock set + ct = ContentType.objects.get_for_model(page_contact) + data = {'content_type_id': ct.pk, + 'object_id': page_contact.pk} + res = req.post(url, data, + content_type='application/json', follow=1) + assert isinstance(res.json(), dict) + + + # GET, patch, put, delete + url = reverse('unicms_api:editorial-board-site-webpath-page-contact', + kwargs={'site_id': site.pk, + 'webpath_id': webpath.pk, + 'page_id': page.pk, + 'pk': page_contact.pk}) + + # GET + res = req.get(url, content_type='application/json',) + assert isinstance(res.json(), dict) + + # PATCH + data = {'is_active': False} + # user hasn't permission + req.force_login(user2) + res = req.patch(url, data, + content_type='application/json', + follow=1) + assert res.status_code == 403 + # user has permission on page + page.created_by = user2 + page.save() + ebu3 = ContextUnitTest.create_editorialboard_user(user=user2, + webpath=webpath, + permission=3) + user2.refresh_from_db() + req.force_login(user2) + res = req.patch(url, data, + content_type='application/json', + follow=1) + page_contact.refresh_from_db() + assert not page_contact.is_active + + # PUT + page.created_by = None + page.save() + data = {'page': page.pk, + 'contact': page_contact.pk, + 'is_active': True + } + # user hasn't permission + req.force_login(user2) + res = req.put(url, data, follow=1, + content_type='application/json') + assert res.status_code == 403 + # user has permission + req.force_login(user) + res = req.put(url, data, follow=1, + content_type='application/json') + page_contact.refresh_from_db() + assert page_contact.is_active + + # DELETE + # user hasn't permission + req.force_login(user2) + res = req.delete(url) + assert res.status_code == 403 + # user has permission + req.force_login(user) + res = req.delete(url) + try: + page_contact.refresh_from_db() + except ObjectDoesNotExist: + assert True + + # form + url = reverse('unicms_api:editorial-board-site-webpath-page-contact-form', + kwargs={'site_id': site.pk, + 'webpath_id': webpath.pk, + 'page_id': page.pk}) + res = req.get(url) + assert isinstance(res.json(), list) diff --git a/src/cms/api/urls.py b/src/cms/api/urls.py index b1fc5ec..a702303 100644 --- a/src/cms/api/urls.py +++ b/src/cms/api/urls.py @@ -12,8 +12,8 @@ publication_media_collection, publication_block, publication_related, website, webpath, webpath_pub_context, - page, page_block, page_carousel, page_link, - page_media, page_media_collection, + page, page_block, page_carousel, page_contact, + page_link, page_media, page_media_collection, page_menu, page_publication, page_heading, page_heading_localization, page_related, page_localization, page_template, @@ -230,6 +230,14 @@ name='editorial-board-site-webpath-page-carousel-logs'), urlpatterns += path(f'{pac_prefix}/form/', page_carousel.PageCarouselFormView.as_view(), name='editorial-board-site-webpath-page-carousel-form'), +# page contacts +paco_prefix = f'{pa_prefix}//contacts' +urlpatterns += path(f'{paco_prefix}/', page_contact.PageContactList.as_view(), name='editorial-board-site-webpath-page-contacts'), +urlpatterns += path(f'{paco_prefix}//', page_contact.PageContactView.as_view(), name='editorial-board-site-webpath-page-contact'), +urlpatterns += path(f'{paco_prefix}//logs/', page_contact.PageContactLogsView.as_view(), + name='editorial-board-site-webpath-page-contact-logs'), +urlpatterns += path(f'{paco_prefix}/form/', page_contact.PageContactFormView.as_view(), name='editorial-board-site-webpath-page-contact-form'), + # page localizations palo_prefix = f'{pa_prefix}//localizations' urlpatterns += path(f'{palo_prefix}/', page_localization.PageLocalizationList.as_view(), name='editorial-board-site-webpath-page-localizations'), diff --git a/src/cms/api/views/page_contact.py b/src/cms/api/views/page_contact.py new file mode 100644 index 0000000..7748690 --- /dev/null +++ b/src/cms/api/views/page_contact.py @@ -0,0 +1,73 @@ +from django.contrib.contenttypes.models import ContentType +from django.shortcuts import get_object_or_404 + +from cms.pages.forms import PageContactForm +from cms.pages.models import * +from cms.pages.serializers import * + +from rest_framework.response import Response +from rest_framework.schemas.openapi import AutoSchema +from rest_framework.views import APIView + +from .. serializers import UniCMSFormSerializer +from .. views.page import PageRelatedObject, PageRelatedObjectList, PageRelatedObjectLogsView + + +class PageContactList(PageRelatedObjectList): + """ + """ + description = "" + search_fields = ['contact__name', 'contact__description', + 'contact__contact_type'] + ordering_fields = ['id', 'contact__name', 'contact__contact_type', + 'is_active', 'order'] + serializer_class = PageContactSerializer + + def get_queryset(self): + """ + """ + super().get_data() + if self.page: + return PageContact.objects.filter(page=self.page) + return PageContact.objects.none() # pragma: no cover + + +class PageContactView(PageRelatedObject): + """ + """ + description = "" + serializer_class = PageContactSerializer + + def get_queryset(self): + """ + """ + super().get_data() + items = PageContact.objects.filter(pk=self.pk, page=self.page) + return items + + +class PageContactFormView(APIView): + + def get(self, *args, **kwargs): + form = PageContactForm(page_id=kwargs.get('page_id')) + form_fields = UniCMSFormSerializer.serialize(form) + return Response(form_fields) + + +class PageContactLogsSchema(AutoSchema): + def get_operation_id(self, path, method):# pragma: no cover + return 'listPageContactLogs' + + +class PageContactLogsView(PageRelatedObjectLogsView): + + schema = PageContactLogsSchema() + + def get_queryset(self): + """ + """ + super().get_data() + item = get_object_or_404(PageContact.objects.select_related('page'), + pk=self.pk, page=self.page) + content_type_id = ContentType.objects.get_for_model(item).pk + return super().get_queryset(self.pk, content_type_id) diff --git a/src/cms/contacts/migrations/0003_auto_20210910_0855.py b/src/cms/contacts/migrations/0003_auto_20210910_0855.py new file mode 100644 index 0000000..a7d1f94 --- /dev/null +++ b/src/cms/contacts/migrations/0003_auto_20210910_0855.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.5 on 2021-09-10 06:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cmscontacts', '0002_auto_20210909_0951'), + ] + + operations = [ + migrations.AlterField( + model_name='contactinfo', + name='label', + field=models.CharField(max_length=160), + ), + migrations.AlterField( + model_name='contactinfolocalization', + name='label', + field=models.CharField(max_length=160), + ), + migrations.AlterField( + model_name='contactinfolocalization', + name='value', + field=models.CharField(max_length=160), + ), + ] diff --git a/src/cms/pages/serializers.py b/src/cms/pages/serializers.py index 873c73e..2fd51ee 100644 --- a/src/cms/pages/serializers.py +++ b/src/cms/pages/serializers.py @@ -110,7 +110,7 @@ def to_representation(self, instance): return data class Meta: - model = PageCarousel + model = PageContact fields = '__all__' diff --git a/src/cms/pages/tests.py b/src/cms/pages/tests.py index 10013e0..f82f50c 100644 --- a/src/cms/pages/tests.py +++ b/src/cms/pages/tests.py @@ -411,6 +411,31 @@ def test_load_carousel_placeholder(cls): lm = block.render() assert lm + # placeholders + @classmethod + def test_load_contact_placeholder(cls): + page = cls.create_page() + webpath = page.webpath + req = RequestFactory().get('/') + + block = ContactPlaceholderBlock( + request = req, + webpath = webpath, + page = page, + content = '{"template" :"that_template.html"}' + ) + + template_block = TemplateBlock.objects.create( + name = 'contact test', + type = 'cms.templates.blocks.ContactPlaceholderBlock', + is_active = True + ) + page_block = PageBlock.objects.create(page=page, + block = template_block, + is_active=1) + lm = block.render() + assert lm + # placeholders @classmethod def test_load_link_placeholder(cls): diff --git a/src/cms/templates/blocks.py b/src/cms/templates/blocks.py index b5a0ebc..5d96cf3 100644 --- a/src/cms/templates/blocks.py +++ b/src/cms/templates/blocks.py @@ -3,7 +3,9 @@ from django.template import Context, Template from django.utils.safestring import mark_safe -from cms.templates.placeholders import (SafeString, load_carousel_placeholder, +from cms.templates.placeholders import (SafeString, + load_carousel_placeholder, + load_contact_placeholder, load_heading_placeholder, load_link_placeholder, load_media_placeholder, @@ -65,6 +67,18 @@ def render(self): content=self.content) +class ContactPlaceholderBlock(PlaceHolderBlock): + """ + Contact PlaceHolder + """ + + def render(self): + self.sanitize_template() + context = self.get_context() + return load_contact_placeholder(context=context, + content=self.content) + + class LinkPlaceholderBlock(PlaceHolderBlock): """ Link PlaceHolder diff --git a/src/cms/templates/placeholders.py b/src/cms/templates/placeholders.py index 565e119..21942a8 100644 --- a/src/cms/templates/placeholders.py +++ b/src/cms/templates/placeholders.py @@ -93,6 +93,20 @@ def build_data_dict(self): return {**self.content,**data} +class ContactPlaceHolder(AbstractPlaceholder): + collection_name = 'contacts' + ph_name = 'cms.templates.blocks.ContactPlaceholderBlock' + + def __init__(self, context:dict, content:dict): + super().__init__(context, content) + self.contacts = self.page.get_contacts() + + def build_data_dict(self): + data = {'contact': self.entry.contact.localized(self.language), + 'contact_infos': self.entry.contact.get_infos(self.language)} + return {**self.content,**data} + + class LinkPlaceHolder(AbstractPlaceholder): collection_name = 'links' ph_name = 'cms.templates.blocks.LinkPlaceholderBlock' @@ -200,6 +214,10 @@ def load_carousel_placeholder(*args, **kwargs): return CarouselPlaceHolder(*args, **kwargs)() +def load_contact_placeholder(*args, **kwargs): + return ContactPlaceHolder(*args, **kwargs)() + + def load_link_placeholder(*args, **kwargs): return LinkPlaceHolder(*args, **kwargs)() diff --git a/src/cms/templates/settings.py b/src/cms/templates/settings.py index ac3cac4..7832167 100644 --- a/src/cms/templates/settings.py +++ b/src/cms/templates/settings.py @@ -122,6 +122,7 @@ ('cms.templates.blocks.HtmlBlock', 'HTML Block'), ('cms.templates.blocks.JSONBlock', 'JSON Block'), ('cms.templates.blocks.CarouselPlaceholderBlock', 'Carousel Placeholder Block'), + ('cms.templates.blocks.ContactPlaceholderBlock', 'Contact Placeholder Block'), ('cms.templates.blocks.HeadingPlaceholderBlock', 'Headings Placeholder Block'), ('cms.templates.blocks.LinkPlaceholderBlock', 'Link Placeholder Block'), ('cms.templates.blocks.MediaPlaceholderBlock', 'Media Placeholder Block'),