def freeze( self, name: str, user=None, notify_speakers: bool = True, comment: str = None ): """Releases the current WIP schedule as a fixed schedule version. :param name: The new schedule name. May not be in use in this event, and cannot be 'wip' or 'latest'. :param user: The :class:`~pretalx.person.models.user.User` initiating the freeze. :param notify_speakers: Should notification emails for speakers with changed slots be generated? :param comment: Public comment for the release :rtype: Schedule """ from pretalx.schedule.models import TalkSlot if name in ["wip", "latest"]: raise Exception(f'Cannot use reserved name "{name}" for schedule version.') if self.version: raise Exception( f'Cannot freeze schedule version: already versioned as "{self.version}".' ) if not name: raise Exception("Cannot create schedule version without a version name.") self.version = name self.comment = comment self.published = now() self.save(update_fields=["published", "version", "comment"]) self.log_action("pretalx.schedule.release", person=user, orga=True) wip_schedule = Schedule.objects.create(event=self.event) # Set visibility self.talks.all().update(is_visible=False) self.talks.filter( models.Q(submission__state=SubmissionStates.CONFIRMED) | models.Q(submission__isnull=True), start__isnull=False, ).update(is_visible=True) talks = [] for talk in self.talks.select_related("submission", "room").all(): talks.append(talk.copy_to_schedule(wip_schedule, save=False)) TalkSlot.objects.bulk_create(talks) if notify_speakers: self.generate_notifications(save=True) with suppress(AttributeError): del wip_schedule.event.wip_schedule with suppress(AttributeError): del wip_schedule.event.current_schedule if self.event.settings.export_html_on_schedule_release: if settings.HAS_CELERY: export_schedule_html.apply_async(kwargs={"event_id": self.event.id}) else: self.event.cache.set("rebuild_schedule_export", True, None) return self, wip_schedule
def post(self, request, event): export_schedule_html.apply_async( kwargs={'event_id': self.request.event.id}) messages.success( self.request, _('A new export is being generated and will be available soon.')) return redirect(self.request.event.orga_urls.schedule_export)
def test_schedule_export_schedule_html_task(mocker, event, slot): mocker.patch('django.core.management.call_command') from django.core.management import call_command # Import here to avoid overriding mocks export_schedule_html.apply_async(kwargs={'event_id': event.id}) call_command.assert_called_with('export_schedule_html', event.slug, '--zip')
def test_schedule_export_schedule_html_task_nozip(mocker, orga_client, event): mocker.patch('django.core.management.call_command') from pretalx.agenda.tasks import export_schedule_html export_schedule_html.apply_async(kwargs={'event_id': event.id, 'make_zip': False}) from django.core.management import call_command call_command.assert_called_with('export_schedule_html', event.slug)
def test_schedule_export_schedule_html_task_nozip(mocker, event, slot): mocker.patch("django.core.management.call_command") from django.core.management import ( call_command, ) # Import here to avoid overriding mocks export_schedule_html.apply_async(kwargs={"event_id": event.id, "make_zip": False}) call_command.assert_called_with("export_schedule_html", event.slug)
def test_schedule_orga_download_export(mocker, orga_client, event): from pretalx.agenda.tasks import export_schedule_html export_schedule_html.apply_async(kwargs={ 'event_id': event.id, 'make_zip': True }) response = orga_client.get(event.orga_urls.schedule_export_download, follow=True) assert len(b"".join(response.streaming_content)) > 1000000 # 1MB
def freeze(self, name: str, user=None, notify_speakers: bool=True): """Releases the current WIP schedule as a fixed schedule version. :param name: The new schedule name. May not be in use in this event, and cannot be 'wip' or 'latest'. :param user: The :class:`~pretalx.person.models.user.User` initiating the freeze. :param notify_speakers: Should notification emails for speakers with changed slots be generated? :rtype: Schedule """ from pretalx.schedule.models import TalkSlot if name in ['wip', 'latest']: raise Exception(f'Cannot use reserved name "{name}" for schedule version.') if self.version: raise Exception( f'Cannot freeze schedule version: already versioned as "{self.version}".' ) if not name: raise Exception('Cannot create schedule version without a version name.') self.version = name self.published = now() self.save(update_fields=['published', 'version']) self.log_action('pretalx.schedule.release', person=user, orga=True) wip_schedule = Schedule.objects.create(event=self.event) # Set visibility self.talks.filter( start__isnull=False, submission__state=SubmissionStates.CONFIRMED, is_visible=False, ).update(is_visible=True) self.talks.filter(is_visible=True).exclude( start__isnull=False, submission__state=SubmissionStates.CONFIRMED ).update(is_visible=False) talks = [] for talk in self.talks.select_related('submission', 'room').all(): talks.append(talk.copy_to_schedule(wip_schedule, save=False)) TalkSlot.objects.bulk_create(talks) if notify_speakers: self.notify_speakers() with suppress(AttributeError): del wip_schedule.event.wip_schedule with suppress(AttributeError): del wip_schedule.event.current_schedule if self.event.settings.export_html_on_schedule_release: export_schedule_html.apply_async(kwargs={'event_id': self.event.id}) return self, wip_schedule
def test_schedule_export_schedule_html_task(mocker, event, slot): mocker.patch('django.core.management.call_command') from pretalx.agenda.tasks import export_schedule_html export_schedule_html.apply_async(kwargs={'event_id': event.id}) from django.core.management import call_command call_command.assert_called_with('export_schedule_html', event.slug, '--zip')
def test_schedule_orga_download_export( mocker, orga_client, django_assert_max_num_queries, event, slot ): export_schedule_html.apply_async(kwargs={'event_id': event.id, 'make_zip': True}) with django_assert_max_num_queries(45): response = orga_client.get( event.orga_urls.schedule_export_download, follow=True ) assert response.status_code == 200 if hasattr(response, 'streaming_content'): assert len(b"".join(response.streaming_content)) > 100_000 # 100 KB
def freeze(self, name, user=None, notify_speakers=True): from pretalx.schedule.models import TalkSlot if name in ['wip', 'latest']: raise Exception( f'Cannot use reserved name "{name}" for schedule version.') if self.version: raise Exception( f'Cannot freeze schedule version: already versioned as "{self.version}".' ) if not name: raise Exception( 'Cannot create schedule version without a version name.') self.version = name self.published = now() self.save(update_fields=['published', 'version']) self.log_action('pretalx.schedule.release', person=user, orga=True) wip_schedule = Schedule.objects.create(event=self.event) # Set visibility self.talks.filter( start__isnull=False, submission__state=SubmissionStates.CONFIRMED, is_visible=False, ).update(is_visible=True) self.talks.filter(is_visible=True).exclude( start__isnull=False, submission__state=SubmissionStates.CONFIRMED).update( is_visible=False) talks = [] for talk in self.talks.select_related('submission', 'room').all(): talks.append(talk.copy_to_schedule(wip_schedule, save=False)) TalkSlot.objects.bulk_create(talks) if notify_speakers: self.notify_speakers() with suppress(AttributeError): del wip_schedule.event.wip_schedule with suppress(AttributeError): del wip_schedule.event.current_schedule if self.event.settings.export_html_on_schedule_release: export_schedule_html.apply_async( kwargs={'event_id': self.event.id}) return self, wip_schedule
def task_periodic_schedule_export(event_slug): event = (Event.objects.filter(slug=event_slug).prefetch_related( '_settings_objects', 'submissions__slots').first()) zip_path = ExportScheduleHtml.get_output_zip_path(event) last_time = event.cache.get('last_schedule_rebuild') _now = now() should_rebuild_schedule = ( event.cache.get('rebuild_schedule_export') or (event.settings.export_html_on_schedule_release and not zip_path.exists() and (not last_time or now() - last_time > timedelta(days=1)))) if should_rebuild_schedule: event.cache.delete('rebuild_schedule_export') event.cache.set('last_schedule_rebuild', _now, None) export_schedule_html.apply_async(kwargs={'event_id': event.id})
def post(self, request, event): if settings.HAS_CELERY: export_schedule_html.apply_async(kwargs={"event_id": self.request.event.id}) messages.success( self.request, _("A new export is being generated and will be available soon."), ) else: self.request.event.cache.set("rebuild_schedule_export", True, None) messages.success( self.request, _( "A new export will be generated on the next scheduled opportunity – please contact your administrator for details." ), ) return redirect(self.request.event.orga_urls.schedule_export)
def task_periodic_schedule_export(event_slug): with scopes_disabled(): event = (Event.objects.filter(slug=event_slug).prefetch_related( '_settings_objects', 'submissions__slots').first()) with scope(event=event): zip_path = get_export_zip_path(event) last_time = event.cache.get('last_schedule_rebuild') _now = now() if not event.settings.export_html_on_schedule_release: event.cache.delete('rebuild_schedule_export') return if last_time and _now - last_time < timedelta(hours=1): return should_rebuild_schedule = event.cache.get( 'rebuild_schedule_export') or not zip_path.exists() if should_rebuild_schedule: event.cache.delete('rebuild_schedule_export') event.cache.set('last_schedule_rebuild', _now, None) export_schedule_html.apply_async(kwargs={'event_id': event.id})
def task_periodic_schedule_export(event_slug): from pretalx.agenda.management.commands.export_schedule_html import ( get_export_zip_path, ) with scopes_disabled(): event = (Event.objects.filter(slug=event_slug).prefetch_related( "_settings_objects", "submissions__slots").first()) with scope(event=event): zip_path = get_export_zip_path(event) last_time = event.cache.get("last_schedule_rebuild") _now = now() if not event.settings.export_html_on_schedule_release: event.cache.delete("rebuild_schedule_export") return if last_time and _now - last_time < dt.timedelta(hours=1): return should_rebuild_schedule = (event.cache.get("rebuild_schedule_export") or not zip_path.exists()) if should_rebuild_schedule: event.cache.delete("rebuild_schedule_export") event.cache.set("last_schedule_rebuild", _now, None) export_schedule_html.apply_async(kwargs={"event_id": event.id})