예제 #1
0
    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
예제 #2
0
 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)
예제 #3
0
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')
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
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
예제 #7
0
    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
예제 #8
0
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')
예제 #9
0
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
예제 #10
0
    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
예제 #11
0
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})
예제 #12
0
    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)
예제 #13
0
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})
예제 #14
0
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})