5 Commits

3 changed files with 118 additions and 4 deletions

View File

@@ -0,0 +1,23 @@
# Generated by Django 6.0.3 on 2026-03-30 07:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0020_coursepage_repository_url_and_more'),
]
operations = [
migrations.AddField(
model_name='modulelessonpage',
name='create_gitea_repo',
field=models.BooleanField(default=False, help_text='If enabled, a Gitea repository will be automatically created for this module when the module is published.'),
),
migrations.AddField(
model_name='modulelessonpage',
name='gitea_repo_url',
field=models.URLField(blank=True, help_text="URL of the Gitea repository for this lesson (auto-generated if 'create_gitea_repo' is enabled)", null=True),
),
]

View File

@@ -0,0 +1,40 @@
# Generated by Django 6.0.3 on 2026-03-30 07:53
import django.db.models.deletion
import wagtail.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0021_modulelessonpage_create_gitea_repo_and_more'),
('wagtailcore', '0096_referenceindex_referenceindex_source_object_and_more'),
('wagtailimages', '0027_image_description'),
]
operations = [
migrations.CreateModel(
name='BlogIndexPage',
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
migrations.CreateModel(
name='BlogPage',
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
('author', models.CharField(max_length=255)),
('body', wagtail.fields.StreamField([('heading', 0), ('paragraph', 1), ('image', 2)], block_lookup={0: ('wagtail.blocks.CharBlock', (), {'form_classname': 'title'}), 1: ('wagtail.blocks.RichTextBlock', (), {}), 2: ('wagtail.images.blocks.ImageBlock', [], {})})),
('image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
]

View File

@@ -1,15 +1,17 @@
from datetime import datetime, timedelta
from django.contrib.auth.models import Group, User
from django.conf import settings
from django.contrib.auth.models import Group, User
from django.db import models
from django.forms import CheckboxSelectMultiple
from django.utils import timezone
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey
from taggit.models import TaggedItemBase
from wagtail import blocks
from wagtail.admin.panels import FieldPanel
from wagtail.fields import RichTextField
from wagtail.fields import RichTextField, StreamField
from wagtail.images.blocks import ImageBlock
from wagtail.models import Page
from wagtail.models.copying import ParentalManyToManyField
from wagtail_color_panel.edit_handlers import NativeColorPanel
@@ -28,6 +30,10 @@ class HomePage(Page):
content_panels = Page.content_panels + ["body"]
class BlogIndexPage(Page):
subpage_types = ["home.BlogPage"]
class CourseIndexPage(Page):
subpage_types = ["home.CoursePage"]
@@ -50,6 +56,31 @@ class CourseIndexPage(Page):
return context
class BlogPage(Page):
author = models.CharField(max_length=255)
image = models.ForeignKey(
"wagtailimages.Image",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
body = StreamField(
[
("heading", blocks.CharBlock(classname="title")),
("paragraph", blocks.RichTextBlock()),
("image", ImageBlock()),
]
)
content_panels = Page.content_panels + [
FieldPanel("author"),
FieldPanel("image"),
FieldPanel("body"),
]
parent_page_types = ["home.BlogIndexPage"]
class CoursePage(Page):
course_image = models.ForeignKey(
"wagtailimages.Image",
@@ -164,6 +195,15 @@ class CourseModulePage(Page):
class ModuleLessonPage(Page):
body = RichTextField(blank=True)
create_gitea_repo = models.BooleanField(
default=False,
help_text="If enabled, a Gitea repository will be automatically created for this module when the module is published.",
)
gitea_repo_url = models.URLField(
null=True,
blank=True,
help_text="URL of the Gitea repository for this lesson (auto-generated if 'create_gitea_repo' is enabled)",
)
@property
def module(self):
@@ -180,7 +220,15 @@ class ModuleLessonPage(Page):
return f"{module.full_title} - {self.title}"
return self.title
content_panels = Page.content_panels + ["body"]
content_panels = Page.content_panels + [
FieldPanel("body"),
FieldPanel("create_gitea_repo"),
FieldPanel(
"gitea_repo_url",
read_only=True,
heading="Gitea Repository URL (auto-generated if 'create_gitea_repo' is enabled)",
),
]
parent_page_types = ["home.CourseModulePage"]
@@ -271,6 +319,8 @@ class EventPage(Page):
Generate EventOccurrence objects for this event based on recurrence settings.
For endless recurrence, generate up to days_ahead into the future.
"""
from .event_occurrence import EventOccurrence
now = timezone.now()
if not self.recurrence_enabled:
# if recurrence is not enabled, ensure there's at least one occurrence for the specified start/end
@@ -320,7 +370,8 @@ class EventPage(Page):
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.generate_occurrences()
if self.live:
self.generate_occurrences()
content_panels = Page.content_panels + [
FieldPanel("tags"),