Compare commits
19 Commits
feat/add-e
...
feat/add-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
1d0fd27e04
|
|||
|
ac31336acc
|
|||
|
82514a9418
|
|||
|
b599ac6fa3
|
|||
|
fd6209470b
|
|||
|
de48747884
|
|||
|
684871833a
|
|||
|
ef69b99068
|
|||
|
88c797e4b0
|
|||
|
a0819a6552
|
|||
|
e4add89ba8
|
|||
|
7cbec4fc9c
|
|||
|
899ed539c4
|
|||
|
c22ef183f8
|
|||
|
f95a4915bd
|
|||
|
42830dbc45
|
|||
|
fd537c82fc
|
|||
|
a2a38dbc6d
|
|||
|
a44002b714
|
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-03-16 12:38+0000\n"
|
"POT-Creation-Date: 2026-03-17 11:46+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -18,6 +18,14 @@ msgstr ""
|
|||||||
"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"
|
||||||
|
|
||||||
|
#: home/templates/home/course_module_page.html:21
|
||||||
|
msgid "Lessons"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/course_module_page.html:28
|
||||||
|
msgid "No lessons yet."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: home/templates/home/course_page.html:26
|
#: home/templates/home/course_page.html:26
|
||||||
msgid "Modules"
|
msgid "Modules"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-03-16 12:38+0000\n"
|
"POT-Creation-Date: 2026-03-17 11:46+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -20,6 +20,16 @@ msgstr ""
|
|||||||
"(n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && "
|
"(n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && "
|
||||||
"n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
|
"n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
|
||||||
|
|
||||||
|
#: home/templates/home/course_module_page.html:21
|
||||||
|
msgid "Lessons"
|
||||||
|
msgstr "Lekcje"
|
||||||
|
|
||||||
|
#: home/templates/home/course_module_page.html:28
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "No modules yet."
|
||||||
|
msgid "No lessons yet."
|
||||||
|
msgstr "Brak lekcji."
|
||||||
|
|
||||||
#: home/templates/home/course_page.html:26
|
#: home/templates/home/course_page.html:26
|
||||||
msgid "Modules"
|
msgid "Modules"
|
||||||
msgstr "Moduły"
|
msgstr "Moduły"
|
||||||
@@ -32,7 +42,9 @@ msgstr "Brak modułów."
|
|||||||
msgid ""
|
msgid ""
|
||||||
"You need to be logged in to access this course. Please log in or sign up to "
|
"You need to be logged in to access this course. Please log in or sign up to "
|
||||||
"view the modules."
|
"view the modules."
|
||||||
msgstr "Musisz być zalogowany, aby uzyskać dostęp do tego kursu. Zaloguj się lub zarejestruj, aby zobaczyć moduły."
|
msgstr ""
|
||||||
|
"Musisz być zalogowany, aby uzyskać dostęp do tego kursu. Zaloguj się lub "
|
||||||
|
"zarejestruj, aby zobaczyć moduły."
|
||||||
|
|
||||||
#: home/templates/home/course_page.html:40
|
#: home/templates/home/course_page.html:40
|
||||||
#: home/templates/home/event_page.html:40
|
#: home/templates/home/event_page.html:40
|
||||||
@@ -56,7 +68,9 @@ msgstr "Kup kurs"
|
|||||||
#: home/templates/home/event_page.html:25
|
#: home/templates/home/event_page.html:25
|
||||||
msgid ""
|
msgid ""
|
||||||
"This event has already ended. Please check our calendar for upcoming events."
|
"This event has already ended. Please check our calendar for upcoming events."
|
||||||
msgstr "To wydarzenie już się zakończyło. Sprawdź nasz kalendarz, aby zobaczyć nadchodzące wydarzenia."
|
msgstr ""
|
||||||
|
"To wydarzenie już się zakończyło. Sprawdź nasz kalendarz, aby zobaczyć "
|
||||||
|
"nadchodzące wydarzenia."
|
||||||
|
|
||||||
#: home/templates/home/event_page.html:29
|
#: home/templates/home/event_page.html:29
|
||||||
msgid "You are signed up for this event. We look forward to seeing you there!"
|
msgid "You are signed up for this event. We look forward to seeing you there!"
|
||||||
@@ -70,18 +84,67 @@ msgstr "Zrezygnuj"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"You need to be logged in to sign up for this event. Please log in or sign up "
|
"You need to be logged in to sign up for this event. Please log in or sign up "
|
||||||
"to reserve your spot."
|
"to reserve your spot."
|
||||||
msgstr "Musisz być zalogowany, aby zapisać się na to wydarzenie. Zaloguj się lub zarejestruj, aby zarezerwować swoje miejsce."
|
msgstr ""
|
||||||
|
"Musisz być zalogowany, aby zapisać się na to wydarzenie. Zaloguj się lub "
|
||||||
|
"zarejestruj, aby zarezerwować swoje miejsce."
|
||||||
|
|
||||||
#: home/templates/home/event_page.html:48
|
#: home/templates/home/event_page.html:48
|
||||||
msgid ""
|
msgid ""
|
||||||
"This event is fully booked. Please check back later for any cancellations."
|
"This event is fully booked. Please check back later for any cancellations."
|
||||||
msgstr "To wydarzenie jest zarezerwowane w pełni. Sprawdź później w przypadku rezygnacji innych uczestników."
|
msgstr ""
|
||||||
|
"To wydarzenie jest zarezerwowane w pełni. Sprawdź później w przypadku "
|
||||||
|
"rezygnacji innych uczestników."
|
||||||
|
|
||||||
#: home/templates/home/event_page.html:52
|
#: home/templates/home/event_page.html:52
|
||||||
msgid ""
|
msgid ""
|
||||||
"You are not signed up for this event. Please sign up to reserve your spot."
|
"You are not signed up for this event. Please sign up to reserve your spot."
|
||||||
msgstr "Nie jesteś zapisany na to wydarzenie. Zapisz się, aby zarezerwować swoje miejsce!"
|
msgstr ""
|
||||||
|
"Nie jesteś zapisany na to wydarzenie. Zapisz się, aby zarezerwować swoje "
|
||||||
|
"miejsce!"
|
||||||
|
|
||||||
#: home/templates/home/event_page.html:54
|
#: home/templates/home/event_page.html:54
|
||||||
msgid "Sign Up for Event"
|
msgid "Sign Up for Event"
|
||||||
msgstr "Zapisz się"
|
msgstr "Zapisz się"
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:6
|
||||||
|
msgid "Visit the Wagtail website"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:15
|
||||||
|
msgid "View the release notes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:27
|
||||||
|
msgid "Welcome to your new Wagtail site!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:28
|
||||||
|
msgid ""
|
||||||
|
"Please feel free to <a href=\"https://github.com/wagtail/wagtail/wiki/"
|
||||||
|
"Slack\">join our community on Slack</a>, or get started with one of the "
|
||||||
|
"links below."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:35
|
||||||
|
msgid "Wagtail Documentation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:36
|
||||||
|
msgid "Topics, references, & how-tos"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:42
|
||||||
|
msgid "Tutorial"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:43
|
||||||
|
msgid "Build your first Wagtail site"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:49
|
||||||
|
msgid "Admin Interface"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/home/welcome_page.html:50
|
||||||
|
msgid "Create your superuser first!"
|
||||||
|
msgstr ""
|
||||||
|
|||||||
27
home/migrations/0016_modulelessonpage.py
Normal file
27
home/migrations/0016_modulelessonpage.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 6.0.3 on 2026-03-17 11:34
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import wagtail.fields
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('home', '0015_eventpage_end_eventpage_recurrence_endless_and_more'),
|
||||||
|
('wagtailcore', '0096_referenceindex_referenceindex_source_object_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ModuleLessonPage',
|
||||||
|
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')),
|
||||||
|
('body', wagtail.fields.RichTextField(blank=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
bases=('wagtailcore.page',),
|
||||||
|
),
|
||||||
|
]
|
||||||
26
home/migrations/0017_chatmessage.py
Normal file
26
home/migrations/0017_chatmessage.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Generated by Django 6.0.3 on 2026-03-17 14:28
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('home', '0016_modulelessonpage'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ChatMessage',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('content', models.TextField()),
|
||||||
|
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('user', models.ForeignKey(limit_choices_to={'is_staff': False}, on_delete=django.db.models.deletion.CASCADE, related_name='support_chats', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
24
home/models/__init__.py
Normal file
24
home/models/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from .pages import (
|
||||||
|
EmptyPage,
|
||||||
|
HomePage,
|
||||||
|
CoursePage,
|
||||||
|
CourseModulePage,
|
||||||
|
ModuleLessonPage,
|
||||||
|
EventPage,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .event_occurrence import EventOccurrence
|
||||||
|
|
||||||
|
from .chat_message import ChatMessage
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"HomePage",
|
||||||
|
"EmptyPage",
|
||||||
|
"CoursePage",
|
||||||
|
"CourseModulePage",
|
||||||
|
"ModuleLessonPage",
|
||||||
|
"EventPage",
|
||||||
|
"EventOccurrence",
|
||||||
|
"ChatMessage",
|
||||||
|
]
|
||||||
26
home/models/chat_message.py
Normal file
26
home/models/chat_message.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class ChatMessage(models.Model):
|
||||||
|
user = models.ForeignKey(
|
||||||
|
User,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="support_chats",
|
||||||
|
limit_choices_to={"is_staff": False},
|
||||||
|
) # The requester (non-admin)
|
||||||
|
sender = models.ForeignKey(
|
||||||
|
User, on_delete=models.CASCADE, related_name="sent_messages"
|
||||||
|
) # The sender (user or admin)
|
||||||
|
|
||||||
|
content = models.TextField()
|
||||||
|
timestamp = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_support_chat(cls, user):
|
||||||
|
return cls.objects.filter(user=user).order_by("timestamp")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_all_user_senders(cls):
|
||||||
|
user_ids = cls.objects.values_list("user", flat=True).distinct()
|
||||||
|
return User.objects.filter(id__in=user_ids, is_staff=False)
|
||||||
38
home/models/event_occurrence.py
Normal file
38
home/models/event_occurrence.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
|
from modelcluster.fields import ParentalKey
|
||||||
|
|
||||||
|
from .pages import EventPage
|
||||||
|
|
||||||
|
|
||||||
|
class EventOccurrence(models.Model):
|
||||||
|
event = ParentalKey(EventPage, related_name="occurrences", on_delete=models.CASCADE)
|
||||||
|
start = models.DateTimeField()
|
||||||
|
end = models.DateTimeField()
|
||||||
|
signed_up_users = models.ManyToManyField(
|
||||||
|
User,
|
||||||
|
related_name="event_occurrences_signed_up",
|
||||||
|
blank=True,
|
||||||
|
help_text="Users who have signed up for this occurrence.",
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ["start"]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.event.title} ({self.start} - {self.end})"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def attendees_count(self):
|
||||||
|
return self.signed_up_users.count()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_past(self):
|
||||||
|
|
||||||
|
return self.end < timezone.now()
|
||||||
|
|
||||||
|
def user_signed_up(self, user):
|
||||||
|
if not user.is_authenticated:
|
||||||
|
return False
|
||||||
|
return self.signed_up_users.filter(id=user.id).exists()
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
from datetime import date, datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.forms import CheckboxSelectMultiple
|
from django.forms import CheckboxSelectMultiple
|
||||||
@@ -9,7 +8,7 @@ from modelcluster.contrib.taggit import ClusterTaggableManager
|
|||||||
from modelcluster.fields import ParentalKey
|
from modelcluster.fields import ParentalKey
|
||||||
from taggit.models import TaggedItemBase
|
from taggit.models import TaggedItemBase
|
||||||
from wagtail.admin.panels import FieldPanel
|
from wagtail.admin.panels import FieldPanel
|
||||||
from wagtail.fields import RichTextField, StreamField
|
from wagtail.fields import RichTextField
|
||||||
from wagtail.models import Page
|
from wagtail.models import Page
|
||||||
from wagtail.models.copying import ParentalManyToManyField
|
from wagtail.models.copying import ParentalManyToManyField
|
||||||
from wagtail_color_panel.edit_handlers import NativeColorPanel
|
from wagtail_color_panel.edit_handlers import NativeColorPanel
|
||||||
@@ -57,6 +56,7 @@ class CoursePage(Page):
|
|||||||
FieldPanel("body"),
|
FieldPanel("body"),
|
||||||
FieldPanel("allowed_groups", widget=CheckboxSelectMultiple),
|
FieldPanel("allowed_groups", widget=CheckboxSelectMultiple),
|
||||||
]
|
]
|
||||||
|
subpage_types = ["home.CourseModulePage"]
|
||||||
|
|
||||||
|
|
||||||
class CourseModulePage(Page):
|
class CourseModulePage(Page):
|
||||||
@@ -78,6 +78,30 @@ class CourseModulePage(Page):
|
|||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
content_panels = Page.content_panels + ["body"]
|
content_panels = Page.content_panels + ["body"]
|
||||||
|
subpage_types = ["home.ModuleLessonPage"]
|
||||||
|
parent_page_types = ["home.CoursePage"]
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleLessonPage(Page):
|
||||||
|
body = RichTextField(blank=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def module(self):
|
||||||
|
if hasattr(self, "get_parent"):
|
||||||
|
parent = self.get_parent()
|
||||||
|
if parent and hasattr(parent, "specific"):
|
||||||
|
return parent.specific
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_title(self):
|
||||||
|
module = self.module
|
||||||
|
if module:
|
||||||
|
return f"{module.full_title} - {self.title}"
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
content_panels = Page.content_panels + ["body"]
|
||||||
|
parent_page_types = ["home.CourseModulePage"]
|
||||||
|
|
||||||
|
|
||||||
class EventPageTag(TaggedItemBase):
|
class EventPageTag(TaggedItemBase):
|
||||||
@@ -235,36 +259,3 @@ class EventPage(Page):
|
|||||||
FieldPanel("recurrence_repeat_until"),
|
FieldPanel("recurrence_repeat_until"),
|
||||||
FieldPanel("recurrence_endless"),
|
FieldPanel("recurrence_endless"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class EventOccurrence(models.Model):
|
|
||||||
event = ParentalKey(EventPage, related_name="occurrences", on_delete=models.CASCADE)
|
|
||||||
start = models.DateTimeField()
|
|
||||||
end = models.DateTimeField()
|
|
||||||
signed_up_users = models.ManyToManyField(
|
|
||||||
User,
|
|
||||||
related_name="event_occurrences_signed_up",
|
|
||||||
blank=True,
|
|
||||||
help_text="Users who have signed up for this occurrence.",
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ["start"]
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.event.title} ({self.start} - {self.end})"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def attendees_count(self):
|
|
||||||
return self.signed_up_users.count()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_past(self):
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
return self.end < timezone.now()
|
|
||||||
|
|
||||||
def user_signed_up(self, user):
|
|
||||||
if not user.is_authenticated:
|
|
||||||
return False
|
|
||||||
return self.signed_up_users.filter(id=user.id).exists()
|
|
||||||
29
home/templates/chat/admin/admin_chat.html
Normal file
29
home/templates/chat/admin/admin_chat.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends "wagtailadmin/base.html" %}
|
||||||
|
{% load static i18n %}
|
||||||
|
|
||||||
|
{% block titletag %}
|
||||||
|
{% trans "Chat with" %} {{ chat_user.email }}
|
||||||
|
{% endblock titletag %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include "wagtailadmin/shared/header.html" with title="Chat" icon="mail" %}
|
||||||
|
<h1>{% trans "Admin Chat View" %}</h1>
|
||||||
|
<p>{% trans "This is the admin view of the chat. Here you can manage conversations and monitor user interactions." %}</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for message in chat_messages %}
|
||||||
|
<li>
|
||||||
|
<strong>{{ message.sender.email }}:</strong> {{ message.content }}
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li>{% trans "No messages found." %}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<form action="/chat/send/{{ chat_user.id }}/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="text" name="content" placeholder="{% trans "Type your message here..." %}" required>
|
||||||
|
<button type="submit">{% trans "Send" %}</button>
|
||||||
|
</form>
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
|
|
||||||
23
home/templates/chat/admin/admin_chat_dashboard.html
Normal file
23
home/templates/chat/admin/admin_chat_dashboard.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{% extends "wagtailadmin/base.html" %}
|
||||||
|
{% load static i18n %}
|
||||||
|
|
||||||
|
{% block titletag %}
|
||||||
|
{% trans "Chat" %}
|
||||||
|
{% endblock titletag %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include "wagtailadmin/shared/header.html" with title="Chat" icon="mail" %}
|
||||||
|
<h1>{% trans "Admin Chat Dashboard" %}</h1>
|
||||||
|
<ul>
|
||||||
|
{% for user in chats %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'admin_chat' user.id %}">
|
||||||
|
{{ user.email }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li>{% trans "No active chats found." %}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
26
home/templates/chat/user_chat.html
Normal file
26
home/templates/chat/user_chat.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static i18n %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{% trans "Chat" %}
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{% trans "Chat with Support" %}</h1>
|
||||||
|
<p>{% trans "This is the user chat interface. Here you can communicate with our support team for assistance." %}</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for message in chat_messages %}
|
||||||
|
<li>
|
||||||
|
<strong>{{ message.sender.email }}:</strong> {{ message.content }}
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li>{% trans "No messages found." %}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<form action="/chat/send/{{ user.id }}/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<textarea name="content" placeholder="{% trans "Type your message here..." %}"></textarea>
|
||||||
|
<button type="submit">{% trans "Send" %}</button>
|
||||||
|
</form>
|
||||||
|
{% endblock content %}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load static %}
|
{% load static i18n wagtailcore_tags %}
|
||||||
{% load wagtailcore_tags %}
|
|
||||||
|
|
||||||
{% block title %}{{ page.full_title }}{% endblock %}
|
{% block title %}{{ page.full_title }}{% endblock %}
|
||||||
|
|
||||||
@@ -18,4 +17,15 @@
|
|||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{{ page.body|richtext }}
|
{{ page.body|richtext }}
|
||||||
|
|
||||||
|
<h3 class="not-prose text-lg mt-8 mb-4 text-gray-700 font-semibold">{% trans "Lessons" %}</h3>
|
||||||
|
<ul class="list-disc list-inside">
|
||||||
|
{% for lesson in page.get_children.specific.live %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ lesson.url }}" class="text-blue-600 hover:underline">{{ lesson.title }}</a>
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li>{% trans "No lessons yet." %}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
25
home/templates/home/module_lesson_page.html
Normal file
25
home/templates/home/module_lesson_page.html
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static wagtailcore_tags i18n %}
|
||||||
|
|
||||||
|
{% block title %}{{ page.full_title }}{% endblock %}
|
||||||
|
|
||||||
|
{% block body_class %}template-modulelessonpage{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
|
||||||
|
{% endblock extra_css %}
|
||||||
|
|
||||||
|
{% block content_class %}prose{% endblock content_class %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h2 class="not-prose text-xl mb-4 text-gray-700">
|
||||||
|
<a href="{{ page.module.course.url }}" class="font-bold">{{ page.module.course.title }}</a>
|
||||||
|
»
|
||||||
|
<a href="{{ page.module.url }}" class="font-bold">{{ page.module.title }}</a>
|
||||||
|
»
|
||||||
|
<span class="text-gray-500">{{ page.title }}</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{{ page.body|richtext }}
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
7
home/urls.py
Normal file
7
home/urls.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("chat/", views.user_chat, name="user_chat"),
|
||||||
|
path("chat/send/<int:user_id>/", views.user_chat_send, name="user_chat_send"),
|
||||||
|
]
|
||||||
44
home/views.py
Normal file
44
home/views.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.shortcuts import redirect, render
|
||||||
|
|
||||||
|
from home.models import ChatMessage
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def admin_chat_dashboard(request):
|
||||||
|
chats = ChatMessage.get_all_user_senders()
|
||||||
|
return render(request, "chat/admin/admin_chat_dashboard.html", {"chats": chats})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def admin_chat(request, user_id):
|
||||||
|
chat_user = User.objects.filter(id=user_id, is_staff=False).first()
|
||||||
|
print(chat_user)
|
||||||
|
chat_messages = ChatMessage.get_support_chat(chat_user)
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"chat/admin/admin_chat.html",
|
||||||
|
{"chat_user": chat_user, "chat_messages": chat_messages},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def user_chat(request):
|
||||||
|
if request.user.is_staff:
|
||||||
|
return redirect("admin_chat_dashboard")
|
||||||
|
chat_messages = ChatMessage.get_support_chat(request.user)
|
||||||
|
return render(request, "chat/user_chat.html", {"chat_messages": chat_messages})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def user_chat_send(request, user_id):
|
||||||
|
if request.method == "POST":
|
||||||
|
content = request.POST.get("content")
|
||||||
|
content = content.strip() if content else ""
|
||||||
|
if content:
|
||||||
|
user = User.objects.filter(id=user_id).first()
|
||||||
|
ChatMessage.objects.create(user=user, sender=request.user, content=content)
|
||||||
|
if request.user.is_staff:
|
||||||
|
return redirect("admin_chat", user_id=user_id)
|
||||||
|
return redirect("user_chat")
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
|
from wagtail.admin.menu import MenuItem
|
||||||
import wagtail.admin.rich_text.editors.draftail.features as draftail_features
|
import wagtail.admin.rich_text.editors.draftail.features as draftail_features
|
||||||
from wagtail.admin.rich_text.converters.html_to_contentstate import BlockElementHandler
|
from wagtail.admin.rich_text.converters.html_to_contentstate import BlockElementHandler
|
||||||
from wagtail import hooks
|
from wagtail import hooks
|
||||||
|
|
||||||
|
from django.urls import path, reverse
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
@hooks.register("register_rich_text_features")
|
@hooks.register("register_rich_text_features")
|
||||||
def register_code_block_feature(features):
|
def register_code_block_feature(features):
|
||||||
@@ -39,3 +44,20 @@ def register_code_block_feature(features):
|
|||||||
|
|
||||||
# Optional: add to default features
|
# Optional: add to default features
|
||||||
features.default_features.append(feature_name)
|
features.default_features.append(feature_name)
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.register("register_admin_urls")
|
||||||
|
def register_admin_chat_dashboard_url():
|
||||||
|
return [
|
||||||
|
path("chat/", views.admin_chat_dashboard, name="admin_chat_dashboard"),
|
||||||
|
path(
|
||||||
|
"chat/user/<int:user_id>/",
|
||||||
|
views.admin_chat,
|
||||||
|
name="admin_chat",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.register("register_admin_menu_item")
|
||||||
|
def register_admin_chat_menu_item():
|
||||||
|
return MenuItem("Chat", reverse("admin_chat_dashboard"), icon_name="mail")
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-03-16 12:38+0000\n"
|
"POT-Creation-Date: 2026-03-17 11:46+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -38,11 +38,11 @@ msgstr ""
|
|||||||
msgid "Logout"
|
msgid "Logout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kursy/templates/header.html:12
|
#: kursy/templates/header.html:12 kursy/templates/occurrence_detail.html:39
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kursy/templates/header.html:13
|
#: kursy/templates/header.html:13 kursy/templates/occurrence_detail.html:42
|
||||||
msgid "Sign Up"
|
msgid "Sign Up"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -50,6 +50,39 @@ msgstr ""
|
|||||||
msgid "Search courses..."
|
msgid "Search courses..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:24
|
||||||
|
msgid ""
|
||||||
|
"This event has already ended. Please check our calendar for upcoming events."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:28
|
||||||
|
msgid "You are signed up for this event. We look forward to seeing you there!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:31
|
||||||
|
msgid "Cancel Sign Up"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:37
|
||||||
|
msgid ""
|
||||||
|
"You need to be logged in to sign up for this event. Please log in or sign up "
|
||||||
|
"to reserve your spot."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:47
|
||||||
|
msgid ""
|
||||||
|
"This event is fully booked. Please check back later for any cancellations."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:51
|
||||||
|
msgid ""
|
||||||
|
"You are not signed up for this event. Please sign up to reserve your spot."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:53
|
||||||
|
msgid "Sign Up for Event"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: kursy/templates/profile.html:6
|
#: kursy/templates/profile.html:6
|
||||||
msgid "Hello, "
|
msgid "Hello, "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-03-16 12:38+0000\n"
|
"POT-Creation-Date: 2026-03-17 11:46+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -40,11 +40,11 @@ msgstr "Ładowanie..."
|
|||||||
msgid "Logout"
|
msgid "Logout"
|
||||||
msgstr "Wyloguj się"
|
msgstr "Wyloguj się"
|
||||||
|
|
||||||
#: kursy/templates/header.html:12
|
#: kursy/templates/header.html:12 kursy/templates/occurrence_detail.html:39
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr "Zaloguj się"
|
msgstr "Zaloguj się"
|
||||||
|
|
||||||
#: kursy/templates/header.html:13
|
#: kursy/templates/header.html:13 kursy/templates/occurrence_detail.html:42
|
||||||
msgid "Sign Up"
|
msgid "Sign Up"
|
||||||
msgstr "Zarejestruj się"
|
msgstr "Zarejestruj się"
|
||||||
|
|
||||||
@@ -52,6 +52,41 @@ msgstr "Zarejestruj się"
|
|||||||
msgid "Search courses..."
|
msgid "Search courses..."
|
||||||
msgstr "Szukaj kursów..."
|
msgstr "Szukaj kursów..."
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:24
|
||||||
|
msgid ""
|
||||||
|
"This event has already ended. Please check our calendar for upcoming events."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:28
|
||||||
|
msgid "You are signed up for this event. We look forward to seeing you there!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:31
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Sign Up"
|
||||||
|
msgid "Cancel Sign Up"
|
||||||
|
msgstr "Zrezygnuj"
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:37
|
||||||
|
msgid ""
|
||||||
|
"You need to be logged in to sign up for this event. Please log in or sign up "
|
||||||
|
"to reserve your spot."
|
||||||
|
msgstr "Musisz być zalogowany, aby zapisać się na to wydarzenie. Zaloguj się lub zarejestruj, aby zarezerwować swoje miejsce."
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:47
|
||||||
|
msgid ""
|
||||||
|
"This event is fully booked. Please check back later for any cancellations."
|
||||||
|
msgstr "To wydarzenie jest w pełni zarezerwowane. Sprawdź ponownie później w przypadku zwolnienia miejsc."
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:51
|
||||||
|
msgid ""
|
||||||
|
"You are not signed up for this event. Please sign up to reserve your spot."
|
||||||
|
msgstr "Nie jesteś zapisany na to wydarzenie. Zapisz się, aby zarezerwować swoje miejsce."
|
||||||
|
|
||||||
|
#: kursy/templates/occurrence_detail.html:53
|
||||||
|
msgid "Sign Up for Event"
|
||||||
|
msgstr "Zapisz się"
|
||||||
|
|
||||||
#: kursy/templates/profile.html:6
|
#: kursy/templates/profile.html:6
|
||||||
msgid "Hello, "
|
msgid "Hello, "
|
||||||
msgstr "Witaj, "
|
msgstr "Witaj, "
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ urlpatterns = [
|
|||||||
path("accounts/profile/", views.profile, name="profile"),
|
path("accounts/profile/", views.profile, name="profile"),
|
||||||
path("accounts/signup/", views.signup, name="signup"),
|
path("accounts/signup/", views.signup, name="signup"),
|
||||||
path("i18n/", include("django.conf.urls.i18n")),
|
path("i18n/", include("django.conf.urls.i18n")),
|
||||||
|
path("", include("home.urls")),
|
||||||
path("calendar/", views.calendar, name="calendar"),
|
path("calendar/", views.calendar, name="calendar"),
|
||||||
|
# TODO: move occurrence related urls to home app
|
||||||
path(
|
path(
|
||||||
"occurrence/<int:occurrence_id>/",
|
"occurrence/<int:occurrence_id>/",
|
||||||
views.occurrence_detail,
|
views.occurrence_detail,
|
||||||
|
|||||||
11
theme/static_src/package-lock.json
generated
11
theme/static_src/package-lock.json
generated
@@ -12,7 +12,6 @@
|
|||||||
"@tailwindcss/postcss": "^4.1.16",
|
"@tailwindcss/postcss": "^4.1.16",
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
"daisyui": "^5.3.10",
|
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"postcss-cli": "^11.0.1",
|
"postcss-cli": "^11.0.1",
|
||||||
"postcss-nested": "^7.0.2",
|
"postcss-nested": "^7.0.2",
|
||||||
@@ -596,16 +595,6 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/daisyui": {
|
|
||||||
"version": "5.5.19",
|
|
||||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.5.19.tgz",
|
|
||||||
"integrity": "sha512-pbFAkl1VCEh/MPCeclKL61I/MqRIFFhNU7yiXoDDRapXN4/qNCoMxeCCswyxEEhqL5eiTTfwHvucFtOE71C9sA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/saadeghi/daisyui?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/dependency-graph": {
|
"node_modules/dependency-graph": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz",
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
"@tailwindcss/postcss": "^4.1.16",
|
"@tailwindcss/postcss": "^4.1.16",
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
"daisyui": "^5.3.10",
|
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"postcss-cli": "^11.0.1",
|
"postcss-cli": "^11.0.1",
|
||||||
"postcss-nested": "^7.0.2",
|
"postcss-nested": "^7.0.2",
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@plugin "@tailwindcss/typography";
|
@plugin "@tailwindcss/typography";
|
||||||
|
|
||||||
@plugin "daisyui";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A catch-all path to Django template files, JavaScript, and Python files
|
* A catch-all path to Django template files, JavaScript, and Python files
|
||||||
* that contain Tailwind CSS classes and will be scanned by Tailwind to generate the final CSS file.
|
* that contain Tailwind CSS classes and will be scanned by Tailwind to generate the final CSS file.
|
||||||
|
|||||||
Reference in New Issue
Block a user