diff --git a/activitystream/serializers.py b/activitystream/serializers.py index 31ef207a5c..0d5881cadd 100644 --- a/activitystream/serializers.py +++ b/activitystream/serializers.py @@ -30,7 +30,7 @@ def _prep_richtext_for_indexing(self, rich_text_value: str) -> str: def to_representation(self, obj): return { - 'id': ('dit:greatCms:Article:' + str(obj.id) + ':Update'), + 'id': 'dit:greatCms:Article:' + str(obj.id) + ':Update', 'type': 'Update', 'published': obj.last_published_at.isoformat('T'), 'object': { @@ -77,7 +77,7 @@ def _get_article_body_content_for_search(self, obj: ArticlePage) -> str: def to_representation(self, obj): return { - 'id': ('dit:greatCms:Article:' + str(obj.id) + ':Update'), + 'id': 'dit:greatCms:Article:' + str(obj.id) + ':Update', 'type': 'Update', 'published': obj.last_published_at.isoformat('T'), 'object': { @@ -134,7 +134,7 @@ def _get_microsite_body_content_for_search(self, obj: MicrositePage) -> str: def to_representation(self, obj): return { - 'id': ('dit:greatCms:Microsite:' + str(obj.id) + ':Update'), + 'id': 'dit:greatCms:Microsite:' + str(obj.id) + ':Update', 'type': 'Update', 'published': obj.last_published_at.isoformat('T'), 'object': { @@ -144,7 +144,7 @@ def to_representation(self, obj): 'summary': obj.page_teaser, 'content': self._get_microsite_body_content_for_search(obj), 'url': f'https://www.great.gov.uk{obj.get_url()}', - 'locale_id': obj.locale_id + 'locale_id': obj.locale_id, # 'keywords': ' '.join(obj.tags.all().values_list('name', flat=True)), }, } diff --git a/config/wsgi.py b/config/wsgi.py index 98730e9605..a544518541 100644 --- a/config/wsgi.py +++ b/config/wsgi.py @@ -6,6 +6,7 @@ For more information on this file, see https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ """ + import os from django.core.wsgi import get_wsgi_application diff --git a/contact/models.py b/contact/models.py index 319b9b4889..040dcdc81b 100644 --- a/contact/models.py +++ b/contact/models.py @@ -22,44 +22,44 @@ class ContactUsGuidanceSnippet( # if we need to trace through where content goes) snippet_slugs.HELP_EXOPP_ALERTS_IRRELEVANT: { 'title': 'Guidance - Daily alerts are not relevant', - 'page_path': ('/contact/triage/export-opportunities/alerts-not-relevant/'), + 'page_path': '/contact/triage/export-opportunities/alerts-not-relevant/', }, snippet_slugs.HELP_EXOPPS_NO_RESPONSE: { 'title': 'Guidance - Export Opportunity application no response', - 'page_path': ('/contact/triage/export-opportunities/opportunity-no-response/'), + 'page_path': '/contact/triage/export-opportunities/opportunity-no-response/', }, snippet_slugs.HELP_MISSING_VERIFY_EMAIL: { 'title': 'Guidance - Email verification missing', - 'page_path': ('/contact/triage/great-account/no-verification-email/'), + 'page_path': '/contact/triage/great-account/no-verification-email/', }, snippet_slugs.HELP_PASSWORD_RESET: { 'title': 'Guidance - Missing password reset link', - 'page_path': ('/contact/triage/great-account/password-reset/'), + 'page_path': '/contact/triage/great-account/password-reset/', }, snippet_slugs.HELP_COMPANIES_HOUSE_LOGIN: { 'title': 'Guidance - Companies House login not working', - 'page_path': ('/contact/triage/great-account/companies-house-login/'), + 'page_path': '/contact/triage/great-account/companies-house-login/', }, snippet_slugs.HELP_VERIFICATION_CODE_ENTER: { 'title': 'Guidance - Where to enter letter verification code', - 'page_path': ('/contact/triage/great-account/verification-letter-code/'), + 'page_path': '/contact/triage/great-account/verification-letter-code/', }, snippet_slugs.HELP_VERIFICATION_CODE_LETTER: { 'title': 'Guidance - Verification letter not delivered', - 'page_path': ('/contact/triage/great-account/no-verification-letter/'), + 'page_path': '/contact/triage/great-account/no-verification-letter/', }, snippet_slugs.HELP_VERIFICATION_CODE_MISSING: { 'title': 'Guidance - Verification code not delivered', - 'page_path': ('/contact/triage/great-account/verification-missing/'), + 'page_path': '/contact/triage/great-account/verification-missing/', }, snippet_slugs.HELP_ACCOUNT_COMPANY_NOT_FOUND: { 'title': 'Guidance - Company not found', - 'page_path': ('/contact/triage/great-account/company-not-found/'), + 'page_path': '/contact/triage/great-account/company-not-found/', }, snippet_slugs.HELP_EXPORTING_TO_UK: { # NB snippet_slugs.HELP_EXPORTING_TO_UK is NOT bootstrapped via data migration 'title': 'Guidance - Exporting to the UK', - 'page_path': ('contact/triage/international/exporting-to-the-uk/'), + 'page_path': 'contact/triage/international/exporting-to-the-uk/', }, } @@ -119,7 +119,7 @@ class ContactSuccessSnippet( }, snippet_slugs.HELP_FORM_SUCCESS_DSO: { 'title': 'Contact Defence and Security Organisation form success page content', - 'page_path': ('/contact/defence-and-security-organisation/success/'), + 'page_path': '/contact/defence-and-security-organisation/success/', }, snippet_slugs.HELP_FORM_SUCCESS_EXPORT_ADVICE: { 'title': 'Contact exporting from the UK form success page content', diff --git a/core/components/static/icons/event-icon.jpeg b/core/components/static/icons/event-icon.jpeg new file mode 100644 index 0000000000..85cc7e57c7 Binary files /dev/null and b/core/components/static/icons/event-icon.jpeg differ diff --git a/core/components/static/icons/series-icon.jpeg b/core/components/static/icons/series-icon.jpeg new file mode 100644 index 0000000000..16a8aad406 Binary files /dev/null and b/core/components/static/icons/series-icon.jpeg differ diff --git a/core/migrations/0130_ukeacta_detailpage_call_to_action_eventorderable.py b/core/migrations/0130_ukeacta_detailpage_call_to_action_eventorderable.py new file mode 100644 index 0000000000..a210cf73a7 --- /dev/null +++ b/core/migrations/0130_ukeacta_detailpage_call_to_action_eventorderable.py @@ -0,0 +1,99 @@ +# Generated by Django 4.1.13 on 2024-01-12 17:57 + +import django.db.models.deletion +import modelcluster.fields +import wagtail.blocks +import wagtail.fields +import wagtail.snippets.blocks +from django.db import migrations, models + +import core.blocks + + +class Migration(migrations.Migration): + + dependencies = [ + ('export_academy', '0033_alter_coursepage_metadata_alter_coursepage_reviews'), + ('core', '0129_alter_greatmedia_subtitles_en_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='UKEACTA', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + 'image', + wagtail.fields.StreamField( + [ + ( + 'media', + wagtail.blocks.StreamBlock([('image', core.blocks.ImageBlock())], max_num=1, min_num=1), + ) + ], + blank=True, + null=True, + use_json_field=True, + ), + ), + ('name', models.CharField(help_text='Snippet name', max_length=50)), + ], + options={ + 'verbose_name': 'UKEA CTA', + 'verbose_name_plural': "UKEA CTA's", + }, + ), + migrations.AddField( + model_name='detailpage', + name='call_to_action', + field=wagtail.fields.StreamField( + [ + ( + 'ukea_article_cta', + wagtail.blocks.ListBlock( + wagtail.snippets.blocks.SnippetChooserBlock('core.UKEACTA'), + icon='link', + label='UKEA Call to action', + max_num=1, + template='learn/includes/article_page_cta.html', + ), + ) + ], + blank=True, + null=True, + use_json_field=True, + ), + ), + migrations.CreateModel( + name='EventOrderable', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sort_order', models.IntegerField(blank=True, editable=False, null=True)), + ( + 'event', + models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='export_academy.event' + ), + ), + ( + 'page', + modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, related_name='ukea_cta_links', to='core.ukeacta' + ), + ), + ( + 'series', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to='export_academy.coursepage', + ), + ), + ], + options={ + 'ordering': ['sort_order'], + 'abstract': False, + }, + ), + ] diff --git a/core/models.py b/core/models.py index 1fb80f81a7..ae3bbc89d9 100644 --- a/core/models.py +++ b/core/models.py @@ -723,7 +723,6 @@ def is_lesson_page(self, page): class LessonPlaceholderPage(Page, mixins.AuthenticatedUserRequired if not settings.FEATURE_DEA_V2 else object): - """Structural page to allow for configuring and representing very simple to modules (`CuratedListPage`s). @@ -906,6 +905,24 @@ class Meta: use_json_field=True, ) + call_to_action = StreamField( + [ + ( + 'ukea_article_cta', + blocks.ListBlock( + SnippetChooserBlock('core.UKEACTA'), + template='learn/includes/article_page_cta.html', + label='UKEA Call to action', + max_num=1, + icon='link', + ), + ) + ], + use_json_field=True, + null=True, + blank=True, + ) + def get_steps(self): topics = CuratedListPage.objects.live() return [{'text': page.title, 'url': page.url} for page in topics] @@ -929,6 +946,7 @@ def get_current_module(self): FieldPanel('objective'), FieldPanel('body'), FieldPanel('recap'), + FieldPanel('call_to_action'), ] @cached_classmethod @@ -1042,6 +1060,56 @@ def get_context(self, request, *args, **kwargs): return context +class EventOrderable(Orderable): + """ + This allows us to either series or multiple events + """ + + page = ParentalKey('core.UKEACTA', related_name='ukea_cta_links') + event = models.ForeignKey('export_academy.Event', on_delete=models.SET_NULL, null=True, blank=True) + series = models.ForeignKey('export_academy.CoursePage', on_delete=models.SET_NULL, null=True, blank=True) + + panels = [FieldPanel('event'), FieldPanel('series')] + + +@register_snippet +class UKEACTA(ClusterableModel): + image = StreamField( + [ + ( + 'media', + blocks.StreamBlock( + [ + ('image', core_blocks.ImageBlock()), + ], + min_num=1, + max_num=1, + ), + ), + ], + use_json_field=True, + blank=True, + null=True, + ) + name = models.CharField(max_length=50, help_text='Snippet name') + panels = [ + FieldPanel('image'), + FieldPanel('name'), + MultiFieldPanel( + [InlinePanel('ukea_cta_links', label='Link')], + heading='Link(s)', + icon='link', + ), + ] + + class Meta: + verbose_name = 'UKEA CTA' + verbose_name_plural = "UKEA CTA's" + + def __str__(self): + return self.name + + @register_snippet class RelatedContentCTA(models.Model): type_choices = [ diff --git a/export_academy/helpers.py b/export_academy/helpers.py index f7c4606ba8..82b9a6f413 100644 --- a/export_academy/helpers.py +++ b/export_academy/helpers.py @@ -140,9 +140,11 @@ def get_ics_button(event, on_confirmation): f'Add to calendar{event.name}', 'value': 'Confirmed', 'type': 'submit', - 'classname': 'govuk-button ukea-ga-tracking govuk-!-margin-bottom-0' - if on_confirmation - else 'govuk-button govuk-button--secondary ukea-ga-tracking govuk-!-margin-bottom-0', + 'classname': ( + 'govuk-button ukea-ga-tracking govuk-!-margin-bottom-0' + if on_confirmation + else 'govuk-button govuk-button--secondary ukea-ga-tracking govuk-!-margin-bottom-0' + ), } diff --git a/exportplan/forms.py b/exportplan/forms.py index a7c858a70a..bfdc35093d 100644 --- a/exportplan/forms.py +++ b/exportplan/forms.py @@ -30,7 +30,7 @@ class ExportPlanAdaptingYourProductForm(forms.Form): 'research what the requirements are so your products have the correct labels for your ' 'target market.' ), - 'placeholder': ('Describe alterations'), + 'placeholder': 'Describe alterations', } ), ) @@ -45,7 +45,7 @@ class ExportPlanAdaptingYourProductForm(forms.Form): 'on the market.You will have to research packaging requirements for your target market to avoid ' 'your products becoming damaged, lost or rejected.' ), - 'placeholder': ('Describe alterations'), + 'placeholder': 'Describe alterations', } ), ) @@ -60,7 +60,7 @@ class ExportPlanAdaptingYourProductForm(forms.Form): 'shopping trips. You will have to research the size of products sold in this market so ' 'you meet customer needs for your target market.' ), - 'placeholder': ('Describe alterations'), + 'placeholder': 'Describe alterations', } ), ) @@ -75,39 +75,39 @@ class ExportPlanAdaptingYourProductForm(forms.Form): 'in order to comply with safety regulations in that market. You will have to research ' 'standards relevant to your product to make sure they are compliant.' ), - 'placeholder': ('Describe alterations'), + 'placeholder': 'Describe alterations', } ), ) translations = forms.CharField( label='Translations', required=False, - widget=Textarea(attrs={'tooltip': ('Translations'), 'placeholder': ('Describe alterations')}), + widget=Textarea(attrs={'tooltip': 'Translations', 'placeholder': 'Describe alterations'}), ) other_changes = forms.CharField( label='Other changes', required=False, - widget=Textarea(attrs={'tooltip': ('Other changes'), 'placeholder': ('Describe alterations')}), + widget=Textarea(attrs={'tooltip': 'Other changes', 'placeholder': 'Describe alterations'}), ) certificate_of_origin = forms.CharField( label='Certificate of origin', required=False, - widget=Textarea(attrs={'tooltip': ('Certificate of origin'), 'placeholder': ('Add notes')}), + widget=Textarea(attrs={'tooltip': 'Certificate of origin', 'placeholder': 'Add notes'}), ) insurance_certificate = forms.CharField( label='Insurance certificate', required=False, - widget=Textarea(attrs={'tooltip': ('Insurance certificate'), 'placeholder': ('Add note')}), + widget=Textarea(attrs={'tooltip': 'Insurance certificate', 'placeholder': 'Add note'}), ) commercial_invoice = forms.CharField( label='Commercial invoice', required=False, - widget=Textarea(attrs={'tooltip': ('Commercial invoice'), 'placeholder': ('Add note')}), + widget=Textarea(attrs={'tooltip': 'Commercial invoice', 'placeholder': 'Add note'}), ) uk_customs_declaration = forms.CharField( label='UK customs declaration', required=False, - widget=Textarea(attrs={'tooltip': ('UK customs declaration'), 'placeholder': ('Add note')}), + widget=Textarea(attrs={'tooltip': 'UK customs declaration', 'placeholder': 'Add note'}), ) @@ -203,7 +203,7 @@ def set_country_specific_text(self, country_name): average_price = forms.CharField( required=False, widget=NumberInput( - attrs={'placeholder': ('0.00'), 'currency': ('GBP')}, + attrs={'placeholder': '0.00', 'currency': 'GBP'}, ), ) diff --git a/learn/templates/learn/includes/article_page_cta.html b/learn/templates/learn/includes/article_page_cta.html index 330ab14d2a..712cc26c4b 100644 --- a/learn/templates/learn/includes/article_page_cta.html +++ b/learn/templates/learn/includes/article_page_cta.html @@ -1,4 +1,6 @@ +{% load get_article_cta_attributes from helpers %}

Learn more with free training

- {% include 'components/great/card.html' with heading_class="great-card__link--heading--18" heading_level="h3" tag_container_inner_class="article-page-cta-container-inner-container" container_class="article-page-cta-container-title-container" classes="great-card--cta great-card--cta-with-content govuk-!-margin-bottom-8" title="Join the UK Export Academy" content="Free training with Q&A, helping you learn to sell confidently to overseas customers" content_tag="p" image_src="/static/images/ukea-landing.png" is_svg_image=False url="/export-academy" show_title_link=True tag="Service" tag_icon="/static/icons/hand.svg" %} -
+ {% get_article_cta_attributes page.call_to_action.0.value.0 as cta_attrs %} + {% include 'components/great/card.html' with heading_class="great-card__link--heading--18" heading_level="h3" tag_container_inner_class="article-page-cta-container-inner-container" container_class="article-page-cta-container-title-container" classes="great-card--cta great-card--cta-with-content govuk-!-margin-bottom-8" title=cta_attrs.title content=cta_attrs.description content_tag="p" image_src=cta_attrs.image is_svg_image=False url=cta_attrs.link show_title_link=True tag=cta_attrs.type tag_icon=cta_attrs.icon %} + \ No newline at end of file diff --git a/learn/templatetags/helpers.py b/learn/templatetags/helpers.py index 5347a0c65b..73e8a9acfb 100644 --- a/learn/templatetags/helpers.py +++ b/learn/templatetags/helpers.py @@ -1,7 +1,10 @@ from django import template +from django.urls import reverse +from django.utils import timezone from wagtail.models import Page -from core.models import RelatedContentCTA +from core.models import UKEACTA, RelatedContentCTA +from export_academy.models import Event register = template.Library() @@ -18,3 +21,57 @@ def get_cta_attributes(cta: RelatedContentCTA): result['tag_description'] = dict(RelatedContentCTA.type_choices)[cta.type] result['tag_icon'] = '/static/icons/hand.svg' if 'service' in cta.type.lower() else '/static/icons/guidance.svg' return result + + +def get_first_available_event(event_ids: list): + first_available_event = None + for event in Event.objects.filter(id__in=event_ids).order_by('start_date'): + if event.start_date > timezone.now() and event.live and not event.completed: + return event + return first_available_event + + +@register.simple_tag +def get_article_cta_attributes(cta: UKEACTA) -> dict: + default_data = { + 'link': '/export-academy', + 'image': '/static/images/ukea-landing.png', + 'icon': '/static/icons/hand.svg', + 'title': 'Join the UK Export Academy', + 'description': 'Free training with Q&A, helping you learn to sell confidently to overseas customers', + 'type': 'Service', + } + if not cta: + return default_data + + links = cta.ukea_cta_links.all() + series = [ + { + 'title': link.series.title, + 'description': link.series.summary, + 'icon': '/static/icons/series-icon.jpeg', + 'type': 'Series', + 'image': cta.image[0].value[0].value.file.url if cta.image else default_data['image'], + 'link': reverse('export_academy:course', kwargs={'slug': link.series.slug}), + } + for link in links + if link.series + ] + # We want pass through the first available event to the CTA + # The default result will be used if first_available_event is None + first_available_event = get_first_available_event([link.event.id for link in links if link.event]) + + if first_available_event: + return { + 'title': first_available_event.name, + 'description': first_available_event.description, + 'icon': '/static/icons/event-icon.jpeg', + 'type': 'Event', + 'image': cta.image[0].value[0].value.file.url if cta.image else default_data['image'], + 'link': first_available_event.get_absolute_url(), + } + elif series: + return series[0] + else: + # the default CTA will be displayed if series and first available_event are None + return default_data diff --git a/requirements.txt b/requirements.txt index c1b92c5487..106243a93f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -257,7 +257,7 @@ jsonschema==3.2.0 # directory-components # drf-spectacular # great-components -kombu==5.3.4 +kombu==5.3.5 # via celery l18n==2021.3 # via wagtail @@ -418,7 +418,7 @@ soupsieve==2.5 # via beautifulsoup4 sphinx==1.8.6 # via -r requirements.in -sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-serializinghtml==1.1.10 # via sphinxcontrib-websupport sphinxcontrib-websupport==1.2.4 # via sphinx diff --git a/requirements_test.in b/requirements_test.in index 6ab07889c6..0466697af4 100644 --- a/requirements_test.in +++ b/requirements_test.in @@ -25,7 +25,7 @@ browserstack-sdk==1.12.0 # Code quality # ------------- -black +black==23.12.1 blacken-docs==1.6.0 isort==5.12.0 flake8==6.1.0 diff --git a/requirements_test.txt b/requirements_test.txt index 66a0f03d21..66e15bb6a6 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -6,10 +6,6 @@ # --no-binary psycopg2 -aiohttp==3.9.1 - # via black -aiosignal==1.3.1 - # via aiohttp airtable-python-wrapper==0.13.0 # via -r requirements.in alabaster==0.7.16 @@ -36,12 +32,9 @@ astroid==3.0.2 asttokens==2.4.1 # via stack-data async-timeout==4.0.3 - # via - # aiohttp - # redis + # via redis attrs==23.2.0 # via - # aiohttp # allure-python-commons # jsonschema # outcome @@ -59,7 +52,7 @@ beautifulsoup4==4.11.2 # wagtail billiard==3.6.4.0 # via celery -black==24.1a1 +black==23.12.1 # via # -r requirements_test.in # blacken-docs @@ -340,10 +333,6 @@ freetype-py==2.3.0 # rlpycairo freezegun==1.1.0 # via -r requirements_test.in -frozenlist==1.4.1 - # via - # aiohttp - # aiosignal geoip2==2.9.0 # via -r requirements.in gevent==23.9.1 @@ -382,7 +371,6 @@ idna==3.6 # via # requests # trio - # yarl imagesize==1.4.1 # via sphinx importlib-metadata==7.0.1 @@ -426,7 +414,7 @@ jsonschema==3.2.0 # directory-components # drf-spectacular # great-components -kombu==5.3.4 +kombu==5.3.5 # via celery l18n==2021.3 # via wagtail @@ -461,10 +449,6 @@ monotonic==1.6 # directory-client-core msgpack==1.0.7 # via locust -multidict==6.0.4 - # via - # aiohttp - # yarl mypy-extensions==1.0.0 # via black nodeenv==1.8.0 @@ -734,7 +718,7 @@ soupsieve==2.5 # via beautifulsoup4 sphinx==1.8.6 # via -r requirements.in -sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-serializinghtml==1.1.10 # via sphinxcontrib-websupport sphinxcontrib-websupport==1.2.4 # via sphinx @@ -880,8 +864,6 @@ wsproto==1.2.0 # via trio-websocket xhtml2pdf==0.2.13 # via -r requirements.in -yarl==1.9.4 - # via aiohttp zipp==3.17.0 # via importlib-metadata zope-event==5.0 diff --git a/sso_profile/business_profile/forms.py b/sso_profile/business_profile/forms.py index e1cfaff375..946da3b5ce 100644 --- a/sso_profile/business_profile/forms.py +++ b/sso_profile/business_profile/forms.py @@ -166,7 +166,7 @@ class CaseStudyRichMediaForm(DynamicHelptextFieldsMixin, forms.Form): 'create_help_text': image_help_text_create, 'update_help_text': image_help_text_update, 'create_label': 'Upload a main image for this case study', - 'update_label': ('Replace the main image for this case study (optional)'), + 'update_label': 'Replace the main image for this case study (optional)', }, { 'field_name': 'image_two', diff --git a/sso_profile/enrolment/views.py b/sso_profile/enrolment/views.py index b81ea929dc..771df99df2 100644 --- a/sso_profile/enrolment/views.py +++ b/sso_profile/enrolment/views.py @@ -279,8 +279,8 @@ def done(self, form_list, form_dict, **kwargs): 'company_name': data['company_name'], 'name': self.request.user.full_name, 'email': self.request.user.email, - 'profile_remove_member_url': ( - self.request.build_absolute_uri(reverse('sso_profile:business-profile-admin-tools')) + 'profile_remove_member_url': self.request.build_absolute_uri( + reverse('sso_profile:business-profile-admin-tools') ), 'report_abuse_url': urls.domestic.FEEDBACK, }, diff --git a/tests/unit/contact/test_helpers.py b/tests/unit/contact/test_helpers.py index 7a5734c0ae..f75a87073f 100644 --- a/tests/unit/contact/test_helpers.py +++ b/tests/unit/contact/test_helpers.py @@ -42,7 +42,7 @@ def all_offices(): 'is_match': True, 'region_id': 'east_midlands', 'name': 'DIT East Midlands', - 'address_street': ('The International Trade Centre, ' '5 Merus Court, ' 'Meridian Business Park'), + 'address_street': 'The International Trade Centre, ' '5 Merus Court, ' 'Meridian Business Park', 'address_city': 'Leicester', 'address_postcode': 'LE19 1RJ', 'email': 'test+east_midlands@examoke.com', diff --git a/tests/unit/contact/test_views.py b/tests/unit/contact/test_views.py index 1dbef940d8..ddfc59bb38 100644 --- a/tests/unit/contact/test_views.py +++ b/tests/unit/contact/test_views.py @@ -679,7 +679,7 @@ def test_office_finder_valid(all_office_details, client): 'is_match': True, 'region_id': 'east_midlands', 'name': 'DIT East Midlands', - 'address_street': ('The International Trade Centre, ' '5 Merus Court, ' 'Meridian Business Park'), + 'address_street': 'The International Trade Centre, ' '5 Merus Court, ' 'Meridian Business Park', 'address_city': 'Leicester', 'address_postcode': 'LE19 1RJ', 'email': 'test+east_midlands@examoke.com', @@ -697,7 +697,7 @@ def test_office_finder_valid(all_office_details, client): 'is_match': False, 'region_id': 'west_midlands', 'name': 'DIT West Midlands', - 'address_street': ('The International Trade Centre, ' '10 New Street, ' 'Midlands Business Park'), + 'address_street': 'The International Trade Centre, ' '10 New Street, ' 'Midlands Business Park', 'address_city': 'Birmingham', 'address_postcode': 'B20 1RJ', 'email': 'test+west_midlands@examoke.com', @@ -1844,7 +1844,7 @@ def test_regional_office_not_displayed_on_confirmation_page( 'is_match': True, 'region_id': 'east_midlands', 'name': 'DIT East Midlands', - 'address_street': ('The International Trade Centre, ' '5 Merus Court, ' 'Meridian Business Park'), + 'address_street': 'The International Trade Centre, ' '5 Merus Court, ' 'Meridian Business Park', 'address_city': 'Leicester', 'address_postcode': 'LE19 1RJ', 'email': 'test+east_midlands@examoke.com', diff --git a/tests/unit/domestic/management/commands/test_organise_country_guide_ctas.py b/tests/unit/domestic/management/commands/test_organise_country_guide_ctas.py index e7bad06ab3..b3a945d40d 100644 --- a/tests/unit/domestic/management/commands/test_organise_country_guide_ctas.py +++ b/tests/unit/domestic/management/commands/test_organise_country_guide_ctas.py @@ -11,11 +11,14 @@ def test_organise_ctas(domestic_homepage): ctas = { 'intro_cta_one_title': 'View live export opportunities for Antigua and Barbuda', - 'intro_cta_one_link': 'https://www.great.gov.uk/export-opportunities/opportunities?s=&areas%5B%5D=antigua-and' - '-barbuda&commit=Find+opportunities', + 'intro_cta_one_link': ( + 'https://www.great.gov.uk/export-opportunities/opportunities?s=&areas%5B%5D=antigua-and' + '-barbuda&commit=Find+opportunities' + ), 'intro_cta_two_title': 'Find an online marketplace in Antigua and Barbuda', - 'intro_cta_two_link': 'https://www.great.gov.uk/selling-online-overseas/markets/results/?category_id' - '=&country_id=344&commit=', + 'intro_cta_two_link': ( + 'https://www.great.gov.uk/selling-online-overseas/markets/results/?category_id' '=&country_id=344&commit=' + ), 'intro_cta_three_title': 'Find export events for Antigua and Barbuda', 'intro_cta_three_link': 'https://www.events.great.gov.uk/ehome/index.php?eventid=200183029&', 'intro_cta_four_title': '', diff --git a/tests/unit/domestic/management/commands/test_update_factsheets_cta_links.py b/tests/unit/domestic/management/commands/test_update_factsheets_cta_links.py index 421f9c6b5a..f53c1f708a 100644 --- a/tests/unit/domestic/management/commands/test_update_factsheets_cta_links.py +++ b/tests/unit/domestic/management/commands/test_update_factsheets_cta_links.py @@ -37,8 +37,10 @@ 'title': 'Trade and investment factsheets: Ivory Coast', }, { - 'url': 'https://assets.publishing.service.gov.uk/127' - '/british-indian-ocean-territory-factsheet-2022-02-18.pdf', + 'url': ( + 'https://assets.publishing.service.gov.uk/127' + '/british-indian-ocean-territory-factsheet-2022-02-18.pdf' + ), 'title': 'Trade and investment factsheets: British Indian Ocean Territory', }, { diff --git a/tests/unit/domestic/test_models.py b/tests/unit/domestic/test_models.py index 3820aaff2c..eb4998bbb6 100644 --- a/tests/unit/domestic/test_models.py +++ b/tests/unit/domestic/test_models.py @@ -371,8 +371,10 @@ def test_fact_sheet_columns( }, { 'title': 'Check for trade barriers', - 'link': 'https://www.check-international-trade-barriers.service.gov.uk/barriers/' - '?resolved=0&location=fr', + 'link': ( + 'https://www.check-international-trade-barriers.service.gov.uk/barriers/' + '?resolved=0&location=fr' + ), }, ], ), @@ -768,7 +770,7 @@ def test_base_content_page__get_breadcrumbs( { 'title': article_page.title, 'url': article_page.url, - } + }, # NB: article_page IS in this list ] diff --git a/tests/unit/learn/factories.py b/tests/unit/learn/factories.py index b33dbc0d3b..ae3e778ab2 100644 --- a/tests/unit/learn/factories.py +++ b/tests/unit/learn/factories.py @@ -15,3 +15,13 @@ class Meta: class RelatedContentCTASnippetFactory(DjangoModelFactory): class Meta: model = models.RelatedContentCTA + + +class UKEACTASnippetFactory(DjangoModelFactory): + class Meta: + model = models.UKEACTA + + +class EventOrderableFactory(DjangoModelFactory): + class Meta: + model = models.EventOrderable diff --git a/tests/unit/learn/test_templatetags.py b/tests/unit/learn/test_templatetags.py index 28b8f7db16..29f039d339 100644 --- a/tests/unit/learn/test_templatetags.py +++ b/tests/unit/learn/test_templatetags.py @@ -1,9 +1,15 @@ import pytest +from django.utils import timezone from wagtail.models import Page from wagtail_factories import PageChooserBlockFactory -from learn.templatetags.helpers import get_cta_attributes -from .factories import RelatedContentCTASnippetFactory +from learn.templatetags.helpers import get_article_cta_attributes, get_cta_attributes +from tests.unit.export_academy.factories import EventFactory +from .factories import ( + EventOrderableFactory, + RelatedContentCTASnippetFactory, + UKEACTASnippetFactory, +) @pytest.mark.parametrize( @@ -67,3 +73,52 @@ def test_get_cta_attributes(domestic_site, link_text, type, url, expected): cta_attrs = get_cta_attributes(cta) assert cta_attrs == expected + + +@pytest.mark.parametrize( + 'name, events, expected', + ( + ( + 'test', + None, + { + 'image': '/static/images/ukea-landing.png', + 'icon': '/static/icons/hand.svg', + 'type': 'Service', + }, + ), + ( + 'test', + 1, + { + 'image': '/static/images/ukea-landing.png', + 'icon': '/static/icons/event-icon.jpeg', + 'type': 'Event', + }, + ), + ( + 'test', + 2, + { + 'image': '/static/images/ukea-landing.png', + 'icon': '/static/icons/event-icon.jpeg', + 'type': 'Event', + }, + ), + ), +) +@pytest.mark.django_db +def test_get_article_cta_attributes(root_page, name, events, expected): + cta = UKEACTASnippetFactory(name=name) + + if events: + for loop in range(events): + delta = timezone.now() + timezone.timedelta(days=1 + loop) + event_obj = EventFactory(start_date=delta, live=delta, completed=None) + EventOrderableFactory(page=cta, event=event_obj) + + cta_attrs = get_article_cta_attributes(cta) + + assert cta_attrs['image'] == expected['image'] + assert cta_attrs['icon'] == expected['icon'] + assert cta_attrs['type'] == expected['type'] diff --git a/tests/unit/sso_profile/enrolment/test_helpers.py b/tests/unit/sso_profile/enrolment/test_helpers.py index bc308391c1..8a34d2d342 100644 --- a/tests/unit/sso_profile/enrolment/test_helpers.py +++ b/tests/unit/sso_profile/enrolment/test_helpers.py @@ -145,7 +145,7 @@ def test_notify_company_admins_member_joined_ok(mock_submit): 'form_url': 'the/form/url', 'sender': {}, 'spam_control': {}, - 'template_id': (settings.GOV_NOTIFY_NEW_MEMBER_REGISTERED_TEMPLATE_ID), + 'template_id': settings.GOV_NOTIFY_NEW_MEMBER_REGISTERED_TEMPLATE_ID, 'email_address': 'admin@xyzcorp.com', }, }