add support for opening hours that automatically change over time

This commit is contained in:
2024-07-08 02:42:02 +02:00
parent ada7d25083
commit 355887518b
23 changed files with 834 additions and 18 deletions

View File

@ -169,6 +169,13 @@ class NeufAddressSectionBlock(blocks.StaticBlock):
admin_text = "Viser adressen og Google-kart."
class OpeningHoursSectionBlock(blocks.StaticBlock):
class Meta:
icon = "time"
label = "Chateau Neuf: Åpningstider"
admin_text = "Viser gjeldende åpningstider."
BASE_BLOCKS = [
("paragraph", blocks.RichTextBlock(label="Rik tekst")),
("image", ImageWithTextBlock(label="Bilde")),
@ -199,6 +206,7 @@ class PageSectionBlock(blocks.StructBlock):
[block for block in BASE_BLOCKS if block[0] != "page_section_navigation"]
+ [
("neuf_address", NeufAddressSectionBlock()),
("opening_hours", OpeningHoursSectionBlock()),
]
)

View File

@ -34,6 +34,7 @@ INSTALLED_APPS = [
"events",
"venues",
"news",
"openinghours",
# end cms apps
"grapple",
"graphene_django",
@ -51,6 +52,7 @@ INSTALLED_APPS = [
"wagtail",
"modelcluster",
"taggit",
"django_extensions",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
@ -195,6 +197,7 @@ GRAPPLE = {
"events",
"venues",
"news",
"openinghours",
],
"EXPOSE_GRAPHIQL": True,
}

File diff suppressed because one or more lines are too long

View File

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class OpeninghoursConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "openinghours"

View File

@ -0,0 +1,47 @@
# Generated by Django 5.0.6 on 2024-07-07 19:27
import django.db.models.deletion
import modelcluster.fields
import wagtail.blocks
import wagtail.fields
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='OpeningHoursSet',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(help_text='Enkel beskrivelse av hvilken periode disse åpningstidene dekker, f.eks. <em>Vanlige åpningstider</em> eller <em>Sommer 2032</em>.', max_length=256)),
('effective_from', models.DateField()),
('effective_to', models.DateField(blank=True, null=True)),
('announcement', models.TextField(blank=True, help_text='En kort notis som vil vises i forbindelse med åpningstidene, f.eks. <em>Huset er stengt i perioden A til B.</em>. Kan være blank.')),
],
options={
'verbose_name': 'Opening hours set',
'verbose_name_plural': 'Opening hours sets',
'ordering': ['effective_from'],
},
),
migrations.CreateModel(
name='OpeningHoursItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
('function', models.CharField(choices=[('glassbaren', 'Glassbaren'), ('bokcafeen', 'Bokcaféen'), ('ekspedisjonen', 'Ekspedisjonen')], default='', help_text='Hvilket lokale/funksjon?', max_length=32)),
('week', wagtail.fields.StreamField([('monday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Mandag')), ('tuesday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Tirsdag')), ('wednesday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Onsdag')), ('thursday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Torsdag')), ('friday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Fredag')), ('saturday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Lørdag')), ('sunday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Søndag'))])),
('opening_hours_set', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='openinghours.openinghoursset')),
],
options={
'ordering': ['sort_order'],
'abstract': False,
},
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 5.0.6 on 2024-07-07 19:34
import wagtail.blocks
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('openinghours', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='openinghoursitem',
name='week',
field=wagtail.fields.StreamField([('days', wagtail.blocks.StructBlock([('monday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Mandag')), ('tuesday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Tirsdag')), ('wednesday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Onsdag')), ('thursday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Torsdag')), ('friday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Fredag')), ('saturday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Lørdag')), ('sunday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Søndag'))]))]),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 5.0.6 on 2024-07-08 00:21
import wagtail.blocks
import wagtail.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('openinghours', '0002_alter_openinghoursitem_week'),
]
operations = [
migrations.AlterField(
model_name='openinghoursitem',
name='week',
field=wagtail.fields.StreamField([('week', wagtail.blocks.StructBlock([('monday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Mandag')), ('tuesday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Tirsdag')), ('wednesday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Onsdag')), ('thursday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Torsdag')), ('friday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Fredag')), ('saturday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Lørdag')), ('sunday', wagtail.blocks.StructBlock([('time_from', wagtail.blocks.TimeBlock(label='Åpner', required=False)), ('time_to', wagtail.blocks.TimeBlock(label='Stenger', required=False)), ('custom', wagtail.blocks.CharBlock(help_text='Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>', label='Fritekst', required=False))], label='Søndag'))]))]),
),
]

View File

@ -0,0 +1,149 @@
from django.db import models
from django.utils.safestring import mark_safe
from grapple.helpers import register_query_field, register_streamfield_block
from grapple.models import GraphQLForeignKey, GraphQLStreamfield, GraphQLString
from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel
from wagtail import blocks
from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel, TitleFieldPanel
from wagtail.models import Orderable, StreamField
from wagtail.snippets.models import register_snippet
@register_streamfield_block
class OpeningHoursRangeBlock(blocks.StructBlock):
# closed = blocks.BooleanBlock(required=False, help_text="Kryss av her om lokalet er stengt.")
# blocks.RegexBlock(regex=r'^\d\d:\d\d$', error_messages={'invalid': 'Må være på formatet HH:MM'}, help_text="Tidspunkt på formatet HH:MM")
time_from = blocks.TimeBlock(required=False, label="Åpner")
time_to = blocks.TimeBlock(required=False, label="Stenger")
custom = blocks.CharBlock(
required=False,
label="Fritekst",
help_text=mark_safe(
"Tekst som vises istedenfor tidspunkter. F.eks. <em>Åpent ved arrangement</em>"
),
)
graphql_fields = [
GraphQLString("time_from", required=False),
GraphQLString("time_to", required=False),
GraphQLString("custom", required=False),
]
@register_streamfield_block
class OpeningHoursWeekBlock(blocks.StructBlock):
monday = OpeningHoursRangeBlock(label="Mandag")
tuesday = OpeningHoursRangeBlock(label="Tirsdag")
wednesday = OpeningHoursRangeBlock(label="Onsdag")
thursday = OpeningHoursRangeBlock(label="Torsdag")
friday = OpeningHoursRangeBlock(label="Fredag")
saturday = OpeningHoursRangeBlock(label="Lørdag")
sunday = OpeningHoursRangeBlock(label="Søndag")
graphql_fields = [
GraphQLStreamfield("monday", required=False, is_list=False),
GraphQLStreamfield("tuesday", required=False, is_list=False),
GraphQLStreamfield("wednesday", required=False, is_list=False),
GraphQLStreamfield("thursday", required=False, is_list=False),
GraphQLStreamfield("friday", required=False, is_list=False),
GraphQLStreamfield("saturday", required=False, is_list=False),
GraphQLStreamfield("sunday", required=False, is_list=False),
]
class OpeningHoursItem(Orderable):
FUNCTION_CHOICES = [
("glassbaren", "Glassbaren"),
("bokcafeen", "Bokcaféen"),
("ekspedisjonen", "Ekspedisjonen"),
]
WEEKDAYS = (
("monday", "Mandag"),
("tuesday", "Tirsdag"),
("wednesday", "Onsdag"),
("thursday", "Torsdag"),
("friday", "Fredag"),
("saturday", "Lørdag"),
("sunday", "Søndag"),
)
opening_hours_set = ParentalKey(
"openinghours.OpeningHoursSet", on_delete=models.CASCADE, related_name="items"
)
function = models.CharField(
max_length=32,
default="",
choices=FUNCTION_CHOICES,
blank=False,
help_text="Hvilket lokale/funksjon?",
)
week = StreamField(
[("week", OpeningHoursWeekBlock())],
min_num=1,
max_num=1,
)
panels = [
FieldPanel("function"),
FieldPanel("week"),
]
graphql_fields = [
GraphQLString("function", required=True),
GraphQLStreamfield("week", required=False),
]
@register_snippet
@register_query_field("openingHoursSet", "openingHoursSets")
class OpeningHoursSet(ClusterableModel):
name = models.CharField(
max_length=256,
null=False,
blank=False,
help_text=mark_safe(
"Enkel beskrivelse av hvilken periode disse åpningstidene dekker, "
"f.eks. <em>Vanlige åpningstider</em> eller <em>Sommer 2032</em>."
),
)
effective_from = models.DateField(null=False, blank=False)
effective_to = models.DateField(null=True, blank=True)
announcement = models.TextField(
blank=True,
help_text=mark_safe(
"En kort notis som vil vises i forbindelse med åpningstidene, "
"f.eks. <em>Huset er stengt i perioden A til B.</em>. Kan være blank."
),
)
panels = [
TitleFieldPanel("name"),
FieldPanel("announcement"),
MultiFieldPanel(
heading="Gyldighet",
children=[
FieldPanel("effective_from", heading="Fra"),
FieldPanel("effective_to", heading="Til"),
],
),
InlinePanel("items", label="Lokaler/funksjoner"),
]
graphql_fields = [
GraphQLString("name", required=True),
GraphQLString("announcement", required=False),
GraphQLString("effective_from", required=True),
GraphQLString("effective_to", required=False),
GraphQLForeignKey("items", "openinghours.OpeningHoursItem", required=False, is_list=True),
]
class Meta:
verbose_name = "Opening hours set"
verbose_name_plural = "Opening hours sets"
ordering = ["effective_from"]
def __str__(self):
return f"{self.name} ({self.effective_from} - {self.effective_to or ''})"

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

16
dnscms/poetry.lock generated
View File

@ -201,6 +201,20 @@ tzdata = {version = "*", markers = "sys_platform == \"win32\""}
argon2 = ["argon2-cffi (>=19.1.0)"]
bcrypt = ["bcrypt"]
[[package]]
name = "django-extensions"
version = "3.2.3"
description = "Extensions for Django"
optional = false
python-versions = ">=3.6"
files = [
{file = "django-extensions-3.2.3.tar.gz", hash = "sha256:44d27919d04e23b3f40231c4ab7af4e61ce832ef46d610cc650d53e68328410a"},
{file = "django_extensions-3.2.3-py3-none-any.whl", hash = "sha256:9600b7562f79a92cbf1fde6403c04fee314608fefbb595502e34383ae8203401"},
]
[package.dependencies]
Django = ">=3.2"
[[package]]
name = "django-filter"
version = "24.2"
@ -960,4 +974,4 @@ wand = ["Wand (>=0.6,<1.0)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
content-hash = "24cb4c360211d1c02576389f51d3ba863b0da6ef2800e39e716ff4bf1f8f8a16"
content-hash = "2e3e69272f994e66fb5e9e8b50e9925e99a11e0ca45d6a60814e499c3bdd9229"

View File

@ -11,6 +11,7 @@ wagtail = "^6.0.1"
django = "^5.0.4"
wagtail-grapple = "^0.25.1"
psycopg2-binary = "^2.9.9"
django-extensions = "^3.2.3"
[tool.poetry.group.dev.dependencies]
ruff = "*"