dnscms: improve news app
This commit is contained in:
@@ -1,11 +1,6 @@
|
|||||||
from django.contrib.admin.utils import quote
|
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from wagtail import hooks
|
from wagtail import hooks
|
||||||
from wagtail.admin.menu import MenuItem
|
|
||||||
|
|
||||||
from news.models import NewsIndex
|
|
||||||
|
|
||||||
|
|
||||||
@hooks.register("register_rich_text_features")
|
@hooks.register("register_rich_text_features")
|
||||||
@@ -13,15 +8,6 @@ def enable_additional_rich_text_features(features):
|
|||||||
features.default_features.extend(["h5", "h6", "blockquote"])
|
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")
|
@hooks.register("construct_page_action_menu")
|
||||||
def make_publish_default_action(menu_items, request, context):
|
def make_publish_default_action(menu_items, request, context):
|
||||||
for index, item in enumerate(menu_items):
|
for index, item in enumerate(menu_items):
|
||||||
|
|||||||
Binary file not shown.
@@ -7,38 +7,39 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: dnscms\n"
|
"Project-Id-Version: dnscms\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"Language: nb\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: associations/admin.py:40
|
#: associations/admin.py:23
|
||||||
msgid "Associations"
|
msgid "Associations"
|
||||||
msgstr "Foreninger"
|
msgstr "Foreninger"
|
||||||
|
|
||||||
#: associations/admin.py:46 events/admin.py:76
|
#: associations/admin.py:29 events/admin.py:59 news/admin.py:24
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
msgstr "Tittel"
|
msgstr "Tittel"
|
||||||
|
|
||||||
#: associations/admin.py:49 associations/models.py:81
|
#: associations/admin.py:32 associations/models.py:79
|
||||||
msgid "Type"
|
msgid "Type"
|
||||||
msgstr "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"
|
msgid "Updated"
|
||||||
msgstr "Oppdatert"
|
msgstr "Oppdatert"
|
||||||
|
|
||||||
#: associations/admin.py:59 events/admin.py:85
|
#: associations/admin.py:42 events/admin.py:68 news/admin.py:31
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "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"
|
msgid "Lead"
|
||||||
msgstr "Ingress"
|
msgstr "Ingress"
|
||||||
|
|
||||||
#: associations/models.py:31 associations/models.py:79
|
#: associations/models.py:31 associations/models.py:77
|
||||||
msgid "Content"
|
msgid "Content"
|
||||||
msgstr "Innhold"
|
msgstr "Innhold"
|
||||||
|
|
||||||
@@ -58,23 +59,24 @@ msgstr "Forening"
|
|||||||
msgid "Committee"
|
msgid "Committee"
|
||||||
msgstr "Utvalg"
|
msgstr "Utvalg"
|
||||||
|
|
||||||
#: associations/models.py:73
|
#: associations/models.py:73 news/models.py:60
|
||||||
msgid "Excerpt"
|
msgid "Excerpt"
|
||||||
msgstr "Utdrag"
|
msgstr "Utdrag"
|
||||||
|
|
||||||
#: associations/models.py:75
|
#: associations/models.py:74
|
||||||
msgid "A very short summary of the content below. Used in listing views."
|
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"
|
msgid "Website"
|
||||||
msgstr "Nettsted"
|
msgstr "Nettsted"
|
||||||
|
|
||||||
#: associations/models.py:100
|
#: associations/models.py:98
|
||||||
msgid "association"
|
msgid "association"
|
||||||
msgstr "forening"
|
msgstr "forening"
|
||||||
|
|
||||||
#: associations/models.py:101
|
#: associations/models.py:99
|
||||||
msgid "associations"
|
msgid "associations"
|
||||||
msgstr "foreninger"
|
msgstr "foreninger"
|
||||||
|
|
||||||
@@ -90,26 +92,26 @@ msgstr "Velg en annen forening"
|
|||||||
msgid "Edit this association"
|
msgid "Edit this association"
|
||||||
msgstr "Rediger denne foreningen"
|
msgstr "Rediger denne foreningen"
|
||||||
|
|
||||||
#: events/admin.py:23
|
#: events/admin.py:20
|
||||||
msgid "%Y-%m-%d at %H:%M"
|
msgid "%Y-%m-%d at %H:%M"
|
||||||
msgstr "%Y-%m-%d kl %H:%M"
|
msgstr "%Y-%m-%d kl %H:%M"
|
||||||
|
|
||||||
#: events/admin.py:25
|
#: events/admin.py:22
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(count)d occurrence"
|
msgid "%(count)d occurrence"
|
||||||
msgid_plural "%(count)d occurrences"
|
msgid_plural "%(count)d occurrences"
|
||||||
msgstr[0] "%(count)d forekomst"
|
msgstr[0] "%(count)d forekomst"
|
||||||
msgstr[1] "%(count)d forekomster"
|
msgstr[1] "%(count)d forekomster"
|
||||||
|
|
||||||
#: events/admin.py:70
|
#: events/admin.py:53
|
||||||
msgid "Events"
|
msgid "Events"
|
||||||
msgstr "Arrangementer"
|
msgstr "Arrangementer"
|
||||||
|
|
||||||
#: events/admin.py:77
|
#: events/admin.py:60
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Dato"
|
msgstr "Dato"
|
||||||
|
|
||||||
#: events/admin.py:78 events/models.py:331
|
#: events/admin.py:61 events/models.py:331
|
||||||
msgid "Organizers"
|
msgid "Organizers"
|
||||||
msgstr "Arrangører"
|
msgstr "Arrangører"
|
||||||
|
|
||||||
@@ -365,3 +367,47 @@ msgstr "bilde"
|
|||||||
#: images/models.py:41
|
#: images/models.py:41
|
||||||
msgid "images"
|
msgid "images"
|
||||||
msgstr "bilder"
|
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"
|
||||||
|
|||||||
@@ -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")
|
||||||
@@ -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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+22
-8
@@ -1,4 +1,5 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from grapple.helpers import register_singular_query_field
|
from grapple.helpers import register_singular_query_field
|
||||||
from grapple.models import GraphQLImage, GraphQLRichText, GraphQLStreamfield, GraphQLString
|
from grapple.models import GraphQLImage, GraphQLRichText, GraphQLStreamfield, GraphQLString
|
||||||
from wagtail.admin.panels import FieldPanel
|
from wagtail.admin.panels import FieldPanel
|
||||||
@@ -19,7 +20,7 @@ class NewsIndex(HeadlessMixin, Page):
|
|||||||
lead = RichTextField(features=["italic", "link"], blank=True)
|
lead = RichTextField(features=["italic", "link"], blank=True)
|
||||||
|
|
||||||
content_panels = Page.content_panels + [
|
content_panels = Page.content_panels + [
|
||||||
FieldPanel("lead", heading="Ingress"),
|
FieldPanel("lead", heading=_("Lead")),
|
||||||
]
|
]
|
||||||
|
|
||||||
graphql_fields = [
|
graphql_fields = [
|
||||||
@@ -28,6 +29,10 @@ class NewsIndex(HeadlessMixin, Page):
|
|||||||
|
|
||||||
search_fields = []
|
search_fields = []
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("news index")
|
||||||
|
verbose_name_plural = _("news indexes")
|
||||||
|
|
||||||
|
|
||||||
class NewsPage(HeadlessMixin, WPImportedPageMixin, Page):
|
class NewsPage(HeadlessMixin, WPImportedPageMixin, Page):
|
||||||
subpage_types = []
|
subpage_types = []
|
||||||
@@ -43,23 +48,28 @@ class NewsPage(HeadlessMixin, WPImportedPageMixin, Page):
|
|||||||
blank=True,
|
blank=True,
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
related_name="+",
|
related_name="+",
|
||||||
help_text=(
|
help_text=_(
|
||||||
"Velg et bilde til bruk i på forsiden og andre visningsflater. "
|
"Choose an image for use on the front page and other surfaces. "
|
||||||
"Bør være et bilde eller en illustrasjon uten tekst."
|
"Should be a photo or an illustration without too much text."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
content_panels = Page.content_panels + [
|
content_panels = Page.content_panels + [
|
||||||
FieldPanel(
|
FieldPanel(
|
||||||
"excerpt",
|
"excerpt",
|
||||||
heading="Utdrag",
|
heading=_("Excerpt"),
|
||||||
help_text="En veldig kort oppsummering av innholdet i artikkelen. Brukes på forsiden og i artikkeloversikten.",
|
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("featured_image"),
|
||||||
FieldPanel(
|
FieldPanel(
|
||||||
"lead",
|
"lead",
|
||||||
heading="Ingress",
|
heading=_("Lead"),
|
||||||
help_text="Et kortfattet, innledende avsnitt som oppsummerer hovedinnholdet i artikkelen.",
|
help_text=_(
|
||||||
|
"A brief, introductory paragraph that summarizes the main content of the article."
|
||||||
|
),
|
||||||
),
|
),
|
||||||
FieldPanel("body"),
|
FieldPanel("body"),
|
||||||
]
|
]
|
||||||
@@ -77,6 +87,10 @@ class NewsPage(HeadlessMixin, WPImportedPageMixin, Page):
|
|||||||
index.SearchField("body"),
|
index.SearchField("body"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("news article")
|
||||||
|
verbose_name_plural = _("news articles")
|
||||||
|
|
||||||
def import_wordpress_data(self, data):
|
def import_wordpress_data(self, data):
|
||||||
import html
|
import html
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from news.admin import NewsPageListingViewSet
|
||||||
from news.models import NewsPage
|
from news.models import NewsPage
|
||||||
from tests.conftest import NewsPageFactory
|
from tests.conftest import NewsPageFactory
|
||||||
|
|
||||||
@@ -10,6 +11,11 @@ def test_news_page_persists_via_factory(news_index):
|
|||||||
assert reloaded.excerpt == "Short summary"
|
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):
|
def test_graphql_news_index_query(news_index, graphql_post):
|
||||||
response, body = graphql_post(
|
response, body = graphql_post(
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user