diff --git a/app/contrib/ds/cms_plugins.py b/app/contrib/ds/cms_plugins.py index 9773586d..a1c1ab8f 100644 --- a/app/contrib/ds/cms_plugins.py +++ b/app/contrib/ds/cms_plugins.py @@ -1,9 +1,12 @@ +from django.contrib import admin from django.utils.translation import gettext_lazy as _ from cms.plugin_base import CMSPluginBase from cms.plugin_pool import plugin_pool +from cms.models import Page -from .models import Navbar, Menu +from .models import Navbar, Menu, MenuExtraLink +from .forms import MenuExtraLinkForm @plugin_pool.register_plugin @@ -37,11 +40,17 @@ class FooterPlugin(CMSPluginBase): allow_children = True +class LinkInlineAdmin(admin.StackedInline): + model = MenuExtraLink + form = MenuExtraLinkForm + + @plugin_pool.register_plugin class MenuPlugin(CMSPluginBase): name = _("Menu") model = Menu render_template = "ds/plugins/menu.html" + inlines = (LinkInlineAdmin,) def render(self, context, instance, placeholder): context = super().render(context, instance, placeholder) @@ -59,5 +68,19 @@ def render(self, context, instance, placeholder): css_styles.append(f"--bs-navbar-active-color:{rgba},.75)") context["css_styles"] = ";".join(css_styles) + + request = context.get('request', None) + if request: + edit_mode = request.toolbar.edit_mode_active + + if edit_mode: + extra_links = MenuExtraLink.objects.filter(menu_plugin=instance) + else: + extra_links = [] + for link in MenuExtraLink.objects.filter(menu_plugin=instance): + if link.internal_link.publisher_public and link.internal_link.publisher_public.is_published("pt-br"): + extra_links.append(link) + context["extra_links"] = extra_links return context + diff --git a/app/contrib/ds/forms.py b/app/contrib/ds/forms.py new file mode 100644 index 00000000..a25a618a --- /dev/null +++ b/app/contrib/ds/forms.py @@ -0,0 +1,13 @@ +from django import forms +from cms.models.pagemodel import Page +from .models import MenuExtraLink + +class MenuExtraLinkForm(forms.ModelForm): + class Meta: + model = MenuExtraLink + fields = '__all__' + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + default_menu_pages = Page.objects.filter(in_navigation=True) + self.fields['internal_link'].queryset = Page.objects.exclude(pk__in=default_menu_pages) diff --git a/app/contrib/ds/migrations/0012_menuextralink.py b/app/contrib/ds/migrations/0012_menuextralink.py new file mode 100644 index 00000000..e0fef619 --- /dev/null +++ b/app/contrib/ds/migrations/0012_menuextralink.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2 on 2024-06-05 14:23 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('cms', '0022_auto_20180620_1551'), + ('ds', '0011_theme_favicon'), + ] + + operations = [ + migrations.CreateModel( + name='MenuExtraLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('internal_link', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='cms.page', verbose_name='Link interno')), + ('menu_plugin', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='associated_link', to='ds.menu')), + ], + ), + ] diff --git a/app/contrib/ds/models.py b/app/contrib/ds/models.py index 02b38997..2584df49 100644 --- a/app/contrib/ds/models.py +++ b/app/contrib/ds/models.py @@ -3,7 +3,7 @@ from django.contrib.sites.models import Site from django.utils.html import mark_safe -from cms.models import CMSPlugin +from cms.models import CMSPlugin, Page from colorfield.fields import ColorField from django_jsonform.models.fields import JSONField from filer.fields.image import FilerImageField @@ -285,6 +285,33 @@ class ActiveStyled(models.TextChoices): class Menu(CMSPlugin): color = ColorField(null=True, blank=True) - active_styled = models.CharField( - max_length=30, choices=ActiveStyled.choices, null=True, blank=True + active_styled = models.CharField(max_length=30, choices=ActiveStyled.choices, null=True, blank=True) + + def copy_relations(self, oldinstance): + # Before copying related objects from the old instance, the ones + # on the current one need to be deleted. Otherwise, duplicates may + # appear on the public version of the page + self.associated_link.all().delete() + + for associated_link in oldinstance.associated_link.all(): + # instance.pk = None; instance.pk.save() is the slightly odd but + # standard Django way of copying a saved model instance + associated_link.pk = None + associated_link.menu_plugin = self + associated_link.save() + + +class MenuExtraLink(models.Model): + internal_link = models.ForeignKey( + Page, + verbose_name=_("Link interno"), + blank=True, + null=True, + on_delete=models.SET_NULL, ) + menu_plugin = models.ForeignKey( + Menu, + related_name="associated_link", + null=True, + on_delete=models.SET_NULL + ) \ No newline at end of file diff --git a/app/contrib/ds/templates/ds/plugins/menu.html b/app/contrib/ds/templates/ds/plugins/menu.html index 4e0e708e..0ef17f34 100644 --- a/app/contrib/ds/templates/ds/plugins/menu.html +++ b/app/contrib/ds/templates/ds/plugins/menu.html @@ -1,4 +1,4 @@ -{% load menu_tags sekizai_tags %} +{% load menu_tags sekizai_tags cms_tags %} {% if instance.active_styled %} {% addtoblock 'css' %} @@ -15,4 +15,11 @@
\ No newline at end of file diff --git a/app/contrib/ds/tests/test_menu_plugin.py b/app/contrib/ds/tests/test_menu_plugin.py index 3a609aa3..046df59d 100644 --- a/app/contrib/ds/tests/test_menu_plugin.py +++ b/app/contrib/ds/tests/test_menu_plugin.py @@ -1,13 +1,12 @@ from django.test.client import RequestFactory -from django.template import Context, Template -from django.contrib.auth.models import AnonymousUser - +from django.contrib.sessions.middleware import SessionMiddleware from cms.api import add_plugin, create_page from cms.plugin_rendering import ContentRenderer from cms.test_utils.testcases import CMSTestCase +from cms.toolbar.toolbar import CMSToolbar +from cms.toolbar.utils import get_toolbar_from_request +from ..models import MenuExtraLink - -# Create your tests here. class MenuPluginTestCase(CMSTestCase): def setUp(self): @@ -24,11 +23,27 @@ def setUp(self): self.home.publish(self.language) self.placeholder = self.home.placeholders.get(slot="content") self.superuser = self.get_superuser() + self.request_factory = RequestFactory() def tearDown(self): self.home.delete() self.superuser.delete() + def get_request(self): + request = self.request_factory.get('/') + request.user = self.superuser + request.current_page = self.home + + # Adiciona a sessão ao request + middleware = SessionMiddleware(lambda req: None) + middleware.process_request(request) + request.session.save() + + # Configura a barra de ferramentas do CMS + toolbar = CMSToolbar(request) + request.toolbar = toolbar + return request + def test_settings_color_menu(self): plugin = add_plugin( placeholder=self.placeholder, @@ -38,9 +53,47 @@ def test_settings_color_menu(self): ) plugin.full_clean() - renderer = ContentRenderer(request=RequestFactory()) + request = self.get_request() + renderer = ContentRenderer(request=request) html = renderer.render_plugin(plugin, {}) expected_html = ' ' self.assertInHTML(expected_html, html) + + def test_render_menu_with_internal_links(self): + plugin = add_plugin( + placeholder=self.placeholder, + plugin_type="MenuPlugin", + language=self.language, + color="#ffffff", + ) + + self.home.in_navigation = False + self.home.save() + + internal_link = self.home + MenuExtraLink.objects.create(internal_link=internal_link, menu_plugin=plugin) + + request = self.get_request() + renderer = ContentRenderer(request=request) + html = renderer.render_plugin(plugin, {}) + + self.assertIn(internal_link.get_absolute_url(), html) + + def test_render_menu_without_internal_links(self): + plugin = add_plugin( + placeholder=self.placeholder, + plugin_type="MenuPlugin", + language=self.language, + color="#ffffff", + ) + + self.home.in_navigation = True + self.home.save() + + request = self.get_request() + renderer = ContentRenderer(request=request) + html = renderer.render_plugin(plugin, {}) + + self.assertNotIn('