diff --git a/src/api/serializers.py b/src/api/serializers.py index 087a3fc22b3d6710493193198cc3394d31874d75..f6a5ef970628ac7ce536c1bfb077dd660f40aad3 100644 --- a/src/api/serializers.py +++ b/src/api/serializers.py @@ -114,10 +114,16 @@ class ConferenceSerializer(HubModelSerializer): 'is_public', 'start', 'end', + 'publication_date', + 'registration_start', 'registration_deadline', 'tracks', ] - staff_only_fields = ['is_public'] + staff_only_fields = [ + 'is_public', + 'publication_date', + 'registration_start', + ] class ConferenceTrackSerializer(HubModelSerializer): diff --git a/src/backoffice/views/assemblies.py b/src/backoffice/views/assemblies.py index 44fc93eceba29b9c60a4b2d5d429c9242a6b9bc6..b2ca54024d054b3679937bb6d482162fceadd89a 100644 --- a/src/backoffice/views/assemblies.py +++ b/src/backoffice/views/assemblies.py @@ -6,7 +6,7 @@ from rest_framework.authtoken.models import Token from django.conf import settings from django.contrib import messages from django.core.exceptions import PermissionDenied -from django.http import Http404, HttpResponse +from django.http import Http404, HttpRequest, HttpResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils import timezone @@ -20,7 +20,7 @@ from django.views.generic.edit import CreateView, FormView, UpdateView from core.integrations import BigBlueButton, Hangar, IntegrationError, WorkAdventure from core.models.assemblies import Assembly, AssemblyLink, AssemblyMember -from core.models.conference import ConferenceExportCache +from core.models.conference import ConferenceExportCache, ConferenceMember from core.models.events import Event from core.models.rooms import Room, RoomLink from core.models.sso import Application @@ -57,6 +57,13 @@ class CreateAssemblyView(ConferenceLoginRequiredMixin, CreateView): require_conference_open = True template_name = 'backoffice/assembly_create.html' + def dispatch(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: + member = ConferenceMember.objects.get(conference=self.conference, user=request.user) + if (member.is_staff and member.has_perm('core.assembly_team')) or self.conference.is_open: + return super().dispatch(request, *args, **kwargs) + + raise PermissionDenied + def get_context_data(self, *args, **kwargs): return { **super().get_context_data(*args, **kwargs), diff --git a/src/core/locale/de/LC_MESSAGES/django.po b/src/core/locale/de/LC_MESSAGES/django.po index df12d0bb9b1cc503b37d429dfcbd065ffb39c56b..f8d30d14df38b2a2cc43cec052fb73370a02683f 100644 --- a/src/core/locale/de/LC_MESSAGES/django.po +++ b/src/core/locale/de/LC_MESSAGES/django.po @@ -673,6 +673,18 @@ msgstr "Konferenz öffentlich anzeigen" msgid "Conference__is_public" msgstr "veröffentlicht" +msgid "Conference__publication_date__help" +msgstr "Veröffentlichungszeitpunkt für Inhalte für die Öffentlichkeit" + +msgid "Conference__publication_date" +msgstr "Veröffentlichungszeitpunkt" + +msgid "Conference__registration_start__help" +msgstr "Start der Registrierung für Assemblies." + +msgid "Conference__registration_start" +msgstr "Registrierungsstart" + msgid "Conference__registration_deadline__help" msgstr "" diff --git a/src/core/locale/en/LC_MESSAGES/django.po b/src/core/locale/en/LC_MESSAGES/django.po index e6cc0f624812b918b8bf935c680f9aa8ca254e04..dc6c5f67a6bffb415ae8c584ee2124dd4578726a 100644 --- a/src/core/locale/en/LC_MESSAGES/django.po +++ b/src/core/locale/en/LC_MESSAGES/django.po @@ -673,6 +673,18 @@ msgstr "show this conference publically" msgid "Conference__is_public" msgstr "is public" +msgid "Conference__publication_date__help" +msgstr "From this point in time the content will be displayed to the public." + +msgid "Conference__publication_date" +msgstr "publication start" + +msgid "Conference__registration_start__help" +msgstr "from this point in time registration will be available" + +msgid "Conference__registration_start" +msgstr "registration start" + msgid "Conference__registration_deadline__help" msgstr "until this point in time registration will be available" diff --git a/src/core/migrations/0150_conference_registration_start.py b/src/core/migrations/0150_conference_registration_start.py new file mode 100644 index 0000000000000000000000000000000000000000..b35627657f640b2b105ad851b673b30fa8b6a9c9 --- /dev/null +++ b/src/core/migrations/0150_conference_registration_start.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.2 on 2024-10-19 18:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0149_alter_event_additional_data"), + ] + + operations = [ + migrations.AddField( + model_name="conference", + name="registration_start", + field=models.DateTimeField( + blank=True, + help_text="Conference__registration_start__help", + null=True, + verbose_name="Conference__registration_start", + ), + ), + ] diff --git a/src/core/migrations/0151_conference_publication_date.py b/src/core/migrations/0151_conference_publication_date.py new file mode 100644 index 0000000000000000000000000000000000000000..89763a07b6f8e2ba78ba4831d101b3fff67a3197 --- /dev/null +++ b/src/core/migrations/0151_conference_publication_date.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.2 on 2024-10-20 17:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0150_conference_registration_start"), + ] + + operations = [ + migrations.AddField( + model_name="conference", + name="publication_date", + field=models.DateTimeField( + blank=True, + help_text="Conference__publication_date__help", + null=True, + verbose_name="Conference__publication_date", + ), + ), + ] diff --git a/src/core/models/base_managers.py b/src/core/models/base_managers.py index 651ba1c3bf0315b2a57647d3c30a82cb5bf2a8fc..aa2ff05a5a2e27911d2baaf3814e7dc75b484f4c 100644 --- a/src/core/models/base_managers.py +++ b/src/core/models/base_managers.py @@ -157,6 +157,8 @@ class ConferenceManagerMixin(models.Manager, Generic[_ModelType]): Returns: QuerySet[_ModelType]: A Queryset of objects that are accessible for the given conference. """ + if not conference.is_published: + return self.get_queryset().none() if isinstance(member, ConferenceMember): return self.apply_public_filter(self.get_conference_queryset(conference), member) return self.apply_public_filter(self.get_conference_queryset(conference)) diff --git a/src/core/models/conference.py b/src/core/models/conference.py index f604e69bc59a3a580d1b017482b6b523361bbb75..0b8be5714120146fe5d6d130bfbb1d53cdcc2abd 100644 --- a/src/core/models/conference.py +++ b/src/core/models/conference.py @@ -230,6 +230,12 @@ class Conference(models.Model): name = models.CharField(max_length=200, help_text=_('Conference__name__help'), verbose_name=_('Conference__name')) is_public = models.BooleanField(default=False, help_text=_('Conference__is_public__help'), verbose_name=_('Conference__is_public')) + publication_date = models.DateTimeField( + blank=True, null=True, help_text=_('Conference__publication_date__help'), verbose_name=_('Conference__publication_date') + ) + registration_start = models.DateTimeField( + blank=True, null=True, help_text=_('Conference__registration_start__help'), verbose_name=_('Conference__registration_start') + ) registration_deadline = models.DateTimeField( blank=True, null=True, help_text=_('Conference__registration_deadline__help'), verbose_name=_('Conference__registration_deadline') ) @@ -360,7 +366,11 @@ class Conference(models.Model): @cached_property def is_open(self): - return self.is_public and (self.registration_deadline is None or self.registration_deadline > timezone.now()) + return ( + self.is_public + and (self.registration_start is None or self.registration_start < timezone.now()) + and (self.registration_deadline is None or self.registration_deadline > timezone.now()) + ) @cached_property def is_running(self): @@ -371,6 +381,10 @@ class Conference(models.Model): return self.start <= timezone.now() return self.start <= timezone.now() <= self.end + @cached_property + def is_published(self): + return self.is_public and (self.publication_date is None or self.publication_date < timezone.now()) + @cached_property def has_ended(self): return self.end is not None and timezone.now() > self.end diff --git a/src/core/tests/assemblies.py b/src/core/tests/assemblies.py index 3150f0ef24c39295ac73c28555c7798bfd3f9e9f..052e0e1934dc967143472ca9695bc829a7d99f8b 100644 --- a/src/core/tests/assemblies.py +++ b/src/core/tests/assemblies.py @@ -9,7 +9,7 @@ from core.models.users import PlatformUser, UserCommunicationChannel class AssembliesTestsMixin(TestCase): def setUp(self): - self.conference = Conference(slug='foo', name='Foo Conference', mail_footer='This is serious business w/ legal stuff.') + self.conference = Conference(slug='foo', name='Foo Conference', mail_footer='This is serious business w/ legal stuff.', is_public=True) self.conference.save() self.user_mgmt = PlatformUser(username='manager')