From 447e1bd3ff351e8881415fb4085b616031c664c6 Mon Sep 17 00:00:00 2001 From: Jonas Braathen Date: Tue, 19 May 2026 22:00:11 +0200 Subject: [PATCH] dnscms: improve news app --- dnscms/dnscms/wagtail_hooks.py | 14 --- dnscms/locale/nb/LC_MESSAGES/django.mo | Bin 6505 -> 7434 bytes dnscms/locale/nb/LC_MESSAGES/django.po | 84 ++++++++++++++---- dnscms/news/admin.py | 35 ++++++++ .../migrations/0019_alter_news_options.py | 28 ++++++ dnscms/news/models.py | 30 +++++-- dnscms/news/wagtail_hooks.py | 8 ++ dnscms/tests/test_news.py | 6 ++ 8 files changed, 164 insertions(+), 41 deletions(-) create mode 100644 dnscms/news/admin.py create mode 100644 dnscms/news/migrations/0019_alter_news_options.py create mode 100644 dnscms/news/wagtail_hooks.py diff --git a/dnscms/dnscms/wagtail_hooks.py b/dnscms/dnscms/wagtail_hooks.py index 7ab829d..a71a06c 100644 --- a/dnscms/dnscms/wagtail_hooks.py +++ b/dnscms/dnscms/wagtail_hooks.py @@ -1,11 +1,6 @@ -from django.contrib.admin.utils import quote from django.templatetags.static import static -from django.urls import reverse from django.utils.html import format_html from wagtail import hooks -from wagtail.admin.menu import MenuItem - -from news.models import NewsIndex @hooks.register("register_rich_text_features") @@ -13,15 +8,6 @@ def enable_additional_rich_text_features(features): features.default_features.extend(["h5", "h6", "blockquote"]) -@hooks.register("register_admin_menu_item") -def register_news_menu_item(): - page = NewsIndex.objects.first() - news_url = "#" - if page: - news_url = reverse("wagtailadmin_explore", args=(quote(page.pk),)) - return MenuItem("Nyheter", news_url, icon_name="info-circle", order=3) - - @hooks.register("construct_page_action_menu") def make_publish_default_action(menu_items, request, context): for index, item in enumerate(menu_items): diff --git a/dnscms/locale/nb/LC_MESSAGES/django.mo b/dnscms/locale/nb/LC_MESSAGES/django.mo index b2952ed080647040aeb287fe6662c1637f7f0e2e..335f88a2245783457d35427e96b2373401360296 100644 GIT binary patch delta 2509 zcmZwITWl0n9LMp~meR_tv|1@D_8?#>Eeiq`EGm?15hypg6o|U*&bDK>vt@RQ(3ee& z2?U5QD{90FbI$)< zW_xkoq2}z*Rilm?%1+`Q;!?3OS^T7w56VYn#>~Qxu@W!fM*Iu=ado*dar_ipu=X}% z#$p`DVK4G$2KcDP=kQH@1@~*HmNCZMPQxj@3%|x1`~x*$3B9RBT#fIc2EL9Or-H0Xa2k%*RO_gy;}}+96OP9U;}GADBcHKCVut)(8MqKw`~W%@2^fODvfzeoPeWjrdZiQS?PCYDVp-2cC+q zlc@j!NVtYKcFL+Rvb7{1u+XZ?GO;tYZDCo6}6U4Zp>`IF8Fk@XxDN-=vXAQb7~YBR;3PbYy8lPiL@#HlXlbvZG8{rJ zT@g>kuo@e21%peA$%mEbwlnfevU*<3{u&6+WM ztJkXr)!`0Q=1-tHa&R8*!TERs)A${#!&ZJYbpI~YfE}oWy6_P0iM}5~t!&BN1t(#- z-v0(FQ}|*5K8c%A3B4cQV9cMWCA@*^U_3vQIs;Qt2{xi;vgjTmuSbrUw2I4+q2eE)q(VpE)XwP{m!lE}rKUiA{9X?jx%pvY4v{fpL3jFUU z|6Iep*MVM3lxmrm5luup(Mr@3Docqqg!W!#J291*PD~^8dWI!;dGzwO4&QZ>jn?%7 zKb`3B4ATC7+ZXraU4Fc;+Xmh7z-Ib;d*i-4;AFUVY;WB4Y-idF951lxWY`w>1Gh8f z#B#ICax0>Xy3FuhF}pS6By8FX?@jtV%NSjbje7}39@&FUxtYNAy7I4=#fozEYtaOHXlXWxiwzOSOGXnkON(tePP z2Z0l43A~h(aJbXP_hvjdVCLywo9^q=0yw_o+wSyUC&7K)=~TiAtQ!v5)8nKZFP1wo zad6>HEq0mT-@~Hyeg1|`ru~dd=QiCn;xW3TxhKfiRK|*?1h&JaUmLh7+rgtZJ(xRH uxs7Qrsk&Y~x@~{A6FB*%>YBa&H;w>V=3KJ{RL}&+TiL_0s zlQdQa3z4o6L?R;MvCvqQNF=l(q!#u4O>Yw?{m9shNGB-{M!-uE||u?D$yp?inrl; z-0pn;36;PX45>3lM<;qxW6#8L@G#>t^y76TH+zqIRKuue`5T$rQqm?S&ck%Z1;|&n z6!|m1bG!w$pk1g$_oY#P9XP@PmF@&;qO+(HwmHYIpjOn4kFXC*@F24(p)j7pTiA&C z98|>)pzeFz@iZ#I^BBR-4C+tcHc*CK4B~V=h&u5cD!~p^g}P9Q^r9-zk7f7(7voo4 zg1LOzgw@C{w|1O?1E`fhLW*wBLv%F3J5(Y=sM3u%$Ms;>F;2j(Sc6LJ8ZN{LDzTTi z0^edOde~{2XcelGe#d%Lg@dStgm%(VW_yt2?F_0Cmr)r;P;bRO)D3^368?+2k(-l! zn2O~Xz+-q4b-!WM`F~Ioj-wKar_617|5NGcgf3*!*5h~=^$eflYX{Fs5`2ctX>X9?*f&%HE>@kQ_dkV>RyrNELN6+zMW_>fs2f!|<9cTt zL`}34U06h@wGbt--o%H_QG)Y{&BQ9AnBX!?WBypvGgQ-x)T#(gKG|l`X(r|orIQCy zD_cQmPv}QUt%hhMf*R1YF)3QC&E<2A(_f7ty}#RtWrS9#wuMkd77^Nf`n^`ks|i&` zjVjtELcb5%h?8w2o#li!u{LZiq1Hgu5i1EjhB*XpPRJ_hR1n%kO9?$g_LkKXY8wb` zq(UM<{NENZ(5CYe`sbxrZn9~!scG-%=eIxu8voy7k9mm(-tdD2f4Cv>a&&D{x-0rP ndC(ob;2DmK_GFa1!t=7aquy+nE83eg>W<#X8;c9S&aeCjiu#t= diff --git a/dnscms/locale/nb/LC_MESSAGES/django.po b/dnscms/locale/nb/LC_MESSAGES/django.po index ad3c85e..173340d 100644 --- a/dnscms/locale/nb/LC_MESSAGES/django.po +++ b/dnscms/locale/nb/LC_MESSAGES/django.po @@ -7,38 +7,39 @@ msgid "" msgstr "" "Project-Id-Version: dnscms\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-19 21:36+0200\n" +"POT-Creation-Date: 2026-05-19 21:55+0200\n" "Language: nb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: associations/admin.py:40 +#: associations/admin.py:23 msgid "Associations" msgstr "Foreninger" -#: associations/admin.py:46 events/admin.py:76 +#: associations/admin.py:29 events/admin.py:59 news/admin.py:24 msgid "Title" msgstr "Tittel" -#: associations/admin.py:49 associations/models.py:81 +#: associations/admin.py:32 associations/models.py:79 msgid "Type" msgstr "Type" -#: associations/admin.py:55 events/admin.py:81 +#: associations/admin.py:38 events/admin.py:64 news/admin.py:27 msgid "Updated" msgstr "Oppdatert" -#: associations/admin.py:59 events/admin.py:85 +#: associations/admin.py:42 events/admin.py:68 news/admin.py:31 msgid "Status" msgstr "Status" -#: associations/models.py:30 associations/models.py:78 events/models.py:327 +#: associations/models.py:30 associations/models.py:76 events/models.py:327 +#: news/models.py:23 news/models.py:69 msgid "Lead" msgstr "Ingress" -#: associations/models.py:31 associations/models.py:79 +#: associations/models.py:31 associations/models.py:77 msgid "Content" msgstr "Innhold" @@ -58,23 +59,24 @@ msgstr "Forening" msgid "Committee" msgstr "Utvalg" -#: associations/models.py:73 +#: associations/models.py:73 news/models.py:60 msgid "Excerpt" msgstr "Utdrag" -#: associations/models.py:75 +#: associations/models.py:74 msgid "A very short summary of the content below. Used in listing views." -msgstr "En veldig kort oppsummering av innholdet nedenfor. Brukes i listevisninger." +msgstr "" +"En veldig kort oppsummering av innholdet nedenfor. Brukes i listevisninger." -#: associations/models.py:82 events/models.py:189 +#: associations/models.py:80 events/models.py:189 msgid "Website" msgstr "Nettsted" -#: associations/models.py:100 +#: associations/models.py:98 msgid "association" msgstr "forening" -#: associations/models.py:101 +#: associations/models.py:99 msgid "associations" msgstr "foreninger" @@ -90,26 +92,26 @@ msgstr "Velg en annen forening" msgid "Edit this association" msgstr "Rediger denne foreningen" -#: events/admin.py:23 +#: events/admin.py:20 msgid "%Y-%m-%d at %H:%M" msgstr "%Y-%m-%d kl %H:%M" -#: events/admin.py:25 +#: events/admin.py:22 #, python-format msgid "%(count)d occurrence" msgid_plural "%(count)d occurrences" msgstr[0] "%(count)d forekomst" msgstr[1] "%(count)d forekomster" -#: events/admin.py:70 +#: events/admin.py:53 msgid "Events" msgstr "Arrangementer" -#: events/admin.py:77 +#: events/admin.py:60 msgid "Date" msgstr "Dato" -#: events/admin.py:78 events/models.py:331 +#: events/admin.py:61 events/models.py:331 msgid "Organizers" msgstr "Arrangører" @@ -365,3 +367,47 @@ msgstr "bilde" #: images/models.py:41 msgid "images" msgstr "bilder" + +#: news/admin.py:18 +msgid "News" +msgstr "Nyheter" + +#: news/models.py:33 +msgid "news index" +msgstr "nyhetsoversikt" + +#: news/models.py:34 +msgid "news indexes" +msgstr "nyhetsoversikter" + +#: news/models.py:52 +msgid "" +"Choose an image for use on the front page and other surfaces. Should be a " +"photo or an illustration without too much text." +msgstr "" +"Velg et bilde til bruk på forsiden og andre visningsflater. Bør være et " +"bilde eller en illustrasjon uten for mye tekst." + +#: news/models.py:62 +msgid "" +"A very short summary of the article's content. Used on the front page and in " +"the article listing." +msgstr "" +"En veldig kort oppsummering av innholdet i artikkelen. Brukes på forsiden " +"og i artikkeloversikten." + +#: news/models.py:71 +msgid "" +"A brief, introductory paragraph that summarizes the main content of the " +"article." +msgstr "" +"Et kortfattet, innledende avsnitt som oppsummerer hovedinnholdet i " +"artikkelen." + +#: news/models.py:92 +msgid "news article" +msgstr "nyhetsartikkel" + +#: news/models.py:93 +msgid "news articles" +msgstr "nyhetsartikler" diff --git a/dnscms/news/admin.py b/dnscms/news/admin.py new file mode 100644 index 0000000..d7ef908 --- /dev/null +++ b/dnscms/news/admin.py @@ -0,0 +1,35 @@ +from django.utils.translation import gettext_lazy as _ +from wagtail.admin.ui.tables import DateColumn +from wagtail.admin.ui.tables.pages import PageStatusColumn, PageTitleColumn +from wagtail.admin.viewsets.pages import PageListingViewSet + +from dnscms.admin import ListingRedirectChooseParentView +from news.models import NewsPage + + +class NewsChooseParentView(ListingRedirectChooseParentView): + listing_url_name = "news:index" + + +class NewsPageListingViewSet(PageListingViewSet): + model = NewsPage + choose_parent_view_class = NewsChooseParentView + icon = "info-circle" + menu_label = _("News") + menu_order = 3 + add_to_admin_menu = True + ordering = "-latest_revision_created_at" + + columns = [ + PageTitleColumn("title", label=_("Title"), sort_key="title", classname="title"), + DateColumn( + "latest_revision_created_at", + label=_("Updated"), + sort_key="latest_revision_created_at", + width="10%", + ), + PageStatusColumn("status", label=_("Status"), sort_key="live", width="10%"), + ] + + +news_page_listing_viewset = NewsPageListingViewSet("news") diff --git a/dnscms/news/migrations/0019_alter_news_options.py b/dnscms/news/migrations/0019_alter_news_options.py new file mode 100644 index 0000000..3726ef1 --- /dev/null +++ b/dnscms/news/migrations/0019_alter_news_options.py @@ -0,0 +1,28 @@ +# Generated by Django 6.0.5 on 2026-05-19 19:55 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('images', '0005_customimage_description'), + ('news', '0018_newspage_wp_block_json_newspage_wp_link_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='newsindex', + options={'verbose_name': 'news index', 'verbose_name_plural': 'news indexes'}, + ), + migrations.AlterModelOptions( + name='newspage', + options={'verbose_name': 'news article', 'verbose_name_plural': 'news articles'}, + ), + migrations.AlterField( + model_name='newspage', + name='featured_image', + field=models.ForeignKey(blank=True, help_text='Choose an image for use on the front page and other surfaces. Should be a photo or an illustration without too much text.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.customimage'), + ), + ] diff --git a/dnscms/news/models.py b/dnscms/news/models.py index bd252f1..d226b87 100644 --- a/dnscms/news/models.py +++ b/dnscms/news/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.utils.translation import gettext_lazy as _ from grapple.helpers import register_singular_query_field from grapple.models import GraphQLImage, GraphQLRichText, GraphQLStreamfield, GraphQLString from wagtail.admin.panels import FieldPanel @@ -19,7 +20,7 @@ class NewsIndex(HeadlessMixin, Page): lead = RichTextField(features=["italic", "link"], blank=True) content_panels = Page.content_panels + [ - FieldPanel("lead", heading="Ingress"), + FieldPanel("lead", heading=_("Lead")), ] graphql_fields = [ @@ -28,6 +29,10 @@ class NewsIndex(HeadlessMixin, Page): search_fields = [] + class Meta: + verbose_name = _("news index") + verbose_name_plural = _("news indexes") + class NewsPage(HeadlessMixin, WPImportedPageMixin, Page): subpage_types = [] @@ -43,23 +48,28 @@ class NewsPage(HeadlessMixin, WPImportedPageMixin, Page): blank=True, on_delete=models.SET_NULL, related_name="+", - help_text=( - "Velg et bilde til bruk i på forsiden og andre visningsflater. " - "Bør være et bilde eller en illustrasjon uten tekst." + help_text=_( + "Choose an image for use on the front page and other surfaces. " + "Should be a photo or an illustration without too much text." ), ) content_panels = Page.content_panels + [ FieldPanel( "excerpt", - heading="Utdrag", - help_text="En veldig kort oppsummering av innholdet i artikkelen. Brukes på forsiden og i artikkeloversikten.", + heading=_("Excerpt"), + help_text=_( + "A very short summary of the article's content. " + "Used on the front page and in the article listing." + ), ), FieldPanel("featured_image"), FieldPanel( "lead", - heading="Ingress", - help_text="Et kortfattet, innledende avsnitt som oppsummerer hovedinnholdet i artikkelen.", + heading=_("Lead"), + help_text=_( + "A brief, introductory paragraph that summarizes the main content of the article." + ), ), FieldPanel("body"), ] @@ -77,6 +87,10 @@ class NewsPage(HeadlessMixin, WPImportedPageMixin, Page): index.SearchField("body"), ] + class Meta: + verbose_name = _("news article") + verbose_name_plural = _("news articles") + def import_wordpress_data(self, data): import html diff --git a/dnscms/news/wagtail_hooks.py b/dnscms/news/wagtail_hooks.py new file mode 100644 index 0000000..c9c7b76 --- /dev/null +++ b/dnscms/news/wagtail_hooks.py @@ -0,0 +1,8 @@ +from wagtail import hooks + +from .admin import news_page_listing_viewset + + +@hooks.register("register_admin_viewset") +def register_news_page_listing_viewset(): + return news_page_listing_viewset diff --git a/dnscms/tests/test_news.py b/dnscms/tests/test_news.py index 1594fd3..4dda665 100644 --- a/dnscms/tests/test_news.py +++ b/dnscms/tests/test_news.py @@ -1,3 +1,4 @@ +from news.admin import NewsPageListingViewSet from news.models import NewsPage from tests.conftest import NewsPageFactory @@ -10,6 +11,11 @@ def test_news_page_persists_via_factory(news_index): assert reloaded.excerpt == "Short summary" +def test_news_listing_viewset_wired_to_newspage(): + assert NewsPageListingViewSet.model is NewsPage + assert NewsPageListingViewSet.add_to_admin_menu is True + + def test_graphql_news_index_query(news_index, graphql_post): response, body = graphql_post( """