Exemple #1
0
class EventWizardDisplayForm(forms.Form):
    show_on_dashboard = forms.BooleanField(
        initial=True,
        required=False,
        label=_('Show on dashboard'),
        help_text=_(
            'Show this event on this website\'s dashboard, once it is public?'
        ),
    )
    primary_color = forms.CharField(
        max_length=7,
        label=_('Main event colour'),
        help_text=
        _('Provide a hex value like #00ff00 if you want to style pretalx in your event\'s colour scheme.'
          ),
        required=False,
    )
    logo = ExtensionFileField(
        required=False,
        extension_whitelist=IMAGE_EXTENSIONS,
        label=_('Logo'),
        help_text=
        _('If you provide a logo image, we will by default not show your events name and date in the page header. '
          'We will show your logo in its full size if possible, scaled down to the full header width otherwise.'
          ),
    )
    display_header_pattern = forms.ChoiceField(
        label=_('Frontpage header pattern'),
        help_text=
        _('Choose how the frontpage header banner will be styled. Pattern source: <a href="http://www.heropatterns.com/">heropatterns.com</a>, CC BY 4.0.'
          ),
        choices=(
            ('', _('Plain')),
            ('pcb', _('Circuits')),
            ('bubbles', _('Circles')),
            ('signal', _('Signal')),
            ('topo', _('Topography')),
            ('graph', _('Graph Paper')),
        ),
        required=False,
        widget=HeaderSelect,
    )

    def __init__(self,
                 *args,
                 user=None,
                 locales=None,
                 organiser=None,
                 **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['primary_color'].widget.attrs['class'] = 'colorpickerfield'
Exemple #2
0
class EventWizardDisplayForm(forms.Form):
    show_on_dashboard = forms.BooleanField(
        initial=True,
        required=False,
        label=_("Show on dashboard"),
        help_text=_(
            "Show this event on this website's dashboard, once it is public?"),
    )
    primary_color = forms.CharField(
        max_length=7,
        label=_("Main event colour"),
        help_text=
        _("Provide a hex value like #00ff00 if you want to style pretalx in your event's colour scheme."
          ),
        required=False,
    )
    logo = ExtensionFileField(
        required=False,
        extensions=IMAGE_EXTENSIONS,
        label=_("Logo"),
        help_text=
        _("If you provide a logo image, we will by default not show your event's name and date in the page header. "
          "We will show your logo in its full size if possible, scaled down to the full header width otherwise."
          ),
    )
    display_header_pattern = forms.ChoiceField(
        label=_("Frontpage header pattern"),
        help_text=
        _('Choose how the frontpage header banner will be styled. Pattern source: <a href="http://www.heropatterns.com/">heropatterns.com</a>, CC BY 4.0.'
          ),
        choices=(
            ("", _("Plain")),
            ("pcb", _("Circuits")),
            ("bubbles", _("Circles")),
            ("signal", _("Signal")),
            ("topo", _("Topography")),
            ("graph", _("Graph Paper")),
        ),
        required=False,
        widget=HeaderSelect,
    )

    def __init__(self,
                 *args,
                 user=None,
                 locales=None,
                 organiser=None,
                 **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["primary_color"].widget.attrs["class"] = "colorpickerfield"
Exemple #3
0
class EventForm(ReadOnlyFlag, I18nModelForm):
    locales = forms.MultipleChoiceField(
        label=_("Active languages"),
        choices=settings.LANGUAGES,
        widget=MultipleLanguagesWidget,
        help_text=_(
            "Users will be able to use pretalx in these languages, and you will be able to provide all texts in these"
            " languages. If you don't provide a text in the language a user selects, it will be shown in your event's"
            " default language instead."
        ),
    )
    logo = ExtensionFileField(
        required=False,
        extensions=IMAGE_EXTENSIONS,
        label=_("Header image"),
        help_text=_(
            "If you provide a header image, it will be displayed instead of your event's color and/or header pattern "
            "on top of all event pages. It will be center-aligned, so when the window shrinks, the center parts will "
            "continue to be displayed, and not stretched."
        ),
    )
    header_image = ExtensionFileField(
        required=False,
        extensions=IMAGE_EXTENSIONS,
        label=_("Header image"),
        help_text=_(
            "If you provide a logo image, we will by default not show your event's name and date in the page header. "
            "We will show your logo in its full size if possible, scaled down to the full header width otherwise."
        ),
    )
    custom_css_text = forms.CharField(
        required=False,
        widget=forms.Textarea(),
        label="",
        help_text=_("You can type in your CSS instead of uploading it, too."),
    )

    def __init__(self, *args, **kwargs):
        self.is_administrator = kwargs.pop("is_administrator", False)
        super().__init__(*args, **kwargs)
        self.initial["locales"] = self.instance.locale_array.split(",")
        year = str(now().year)
        self.fields["name"].widget.attrs["placeholder"] = (
            _("The name of your conference, e.g. My Conference") + " " + year
        )
        self.fields["slug"].help_text = _(
            "Please contact your administrator if you need to change the short name of your event."
        )
        self.fields["primary_color"].widget.attrs["placeholder"] = _(
            "A color hex value, e.g. #ab01de"
        )
        self.fields["primary_color"].widget.attrs["class"] = "colorpickerfield"
        self.fields["slug"].disabled = True
        self.fields["date_to"].help_text = _(
            "Any talks you have scheduled already will be moved if you change the event dates. You will have to release a new schedule version to notify all speakers."
        )

    def clean_custom_css(self):
        if self.cleaned_data.get("custom_css") or self.files.get("custom_css"):
            css = self.cleaned_data["custom_css"] or self.files["custom_css"]
            if self.is_administrator:
                return css
            try:
                validate_css(css.read())
                return css
            except IsADirectoryError:
                self.instance.custom_css = None
                self.instance.save(update_fields=["custom_css"])
        else:
            self.instance.custom_css = None
            self.instance.save(update_fields=["custom_css"])
        return None

    def clean_custom_css_text(self):
        css = self.cleaned_data.get("custom_css_text").strip()
        if not css or self.is_administrator:
            return css
        validate_css(css)
        return css

    def clean(self):
        data = super().clean()
        if data.get("locale") not in data.get("locales", []):
            error = forms.ValidationError(
                _("Your default language needs to be one of your active languages."),
            )
            self.add_error("locale", error)
        return data

    def save(self, *args, **kwargs):
        self.instance.locale_array = ",".join(self.cleaned_data["locales"])
        if any(key in self.changed_data for key in ("date_from", "date_to")):
            self.change_dates()
        result = super().save(*args, **kwargs)
        css_text = self.cleaned_data["custom_css_text"]
        if css_text:
            self.instance.custom_css.save(
                self.instance.slug + ".css", ContentFile(css_text)
            )
        return result

    def change_dates(self):
        """Changes dates of current WIP slots, or deschedules them."""
        from pretalx.schedule.models import Availability

        old_instance = Event.objects.get(pk=self.instance.pk)
        if not self.instance.wip_schedule.talks.filter(start__isnull=False).exists():
            return
        new_date_from = self.cleaned_data["date_from"]
        new_date_to = self.cleaned_data["date_to"]
        start_delta = new_date_from - old_instance.date_from
        end_delta = new_date_to - old_instance.date_to
        shortened = (new_date_to - new_date_from) < (
            old_instance.date_to - old_instance.date_from
        )

        if start_delta and end_delta:
            # The event was moved, and we will move all talks with it.
            for key in ("start", "end"):
                filt = {f"{key}__isnull": False, "event": self.instance.event}
                update = {key: F(key) + start_delta}
                self.instance.wip_schedule.talks.filter(**filt).update(**update)
                Availability.objects.filter(event=self.instance).filter(**filt).update(
                    **update
                )

        # Otherwise, the event got longer, no need to do anything.
        # We *could* move all talks towards the new start date, but I'm
        # not convinced that this is the actual use case.
        # I think it's more likely that people add a new day to the start.
        if shortened:
            # The event was shortened, de-schedule all talks outside the range
            self.instance.wip_schedule.talks.filter(
                Q(start__date__gt=new_date_to) | Q(start__date__lt=new_date_from),
            ).update(start=None, end=None, room=None)
            Availability.objects.filter(
                Q(end__date__gt=new_date_to) | Q(start__date__lt=new_date_from),
                event=self.instance.event,
            ).delete()

    class Meta:
        model = Event
        fields = [
            "name",
            "slug",
            "date_from",
            "date_to",
            "timezone",
            "email",
            "locale",
            "primary_color",
            "custom_css",
            "logo",
            "header_image",
            "landing_page_text",
        ]
        widgets = {
            "date_from": forms.DateInput(attrs={"class": "datepickerfield"}),
            "date_to": forms.DateInput(
                attrs={"class": "datepickerfield", "data-date-after": "#id_date_from"}
            ),
        }
Exemple #4
0
class EventForm(ReadOnlyFlag, I18nModelForm):
    locales = forms.MultipleChoiceField(
        label=_('Active languages'),
        choices=settings.LANGUAGES,
        widget=MultipleLanguagesWidget,
    )
    logo = ExtensionFileField(
        required=False,
        extension_whitelist=IMAGE_EXTENSIONS,
        label=_('Logo'),
        help_text=_(
            'If you provide a logo image, we will by default not show your event\'s name and date in the page header. '
            'We will show your logo in its full size if possible, scaled down to the full header width otherwise.'
        ),
    )

    def __init__(self, *args, **kwargs):
        self.is_administrator = kwargs.pop('is_administrator', False)
        super().__init__(*args, **kwargs)
        self.initial['locales'] = self.instance.locale_array.split(',')
        year = str(now().year)
        self.fields['name'].widget.attrs['placeholder'] = (
            _('The name of your conference, e.g. My Conference') + ' ' + year
        )
        self.fields['slug'].widget.attrs['placeholder'] = (
            _('A short version of your conference name, e.g. mycon') + year[2:]
        )
        self.fields['primary_color'].widget.attrs['placeholder'] = _(
            'A color hex value, e.g. #ab01de'
        )
        self.fields['primary_color'].widget.attrs['class'] = 'colorpickerfield'
        self.fields['slug'].disabled = True

    def clean_custom_css(self):

        if self.cleaned_data.get('custom_css') or self.files.get('custom_css'):
            css = self.cleaned_data['custom_css'] or self.files['custom_css']
            if self.is_administrator:
                return css
            try:
                validate_css(css.read())
                return css
            except IsADirectoryError:
                self.instance.custom_css = None
                self.instance.save(update_fields=['custom_css'])
        else:
            self.instance.custom_css = None
            self.instance.save(update_fields=['custom_css'])
        return None

    def clean(self):
        data = super().clean()
        if data.get('locale') not in data.get('locales', []):
            raise forms.ValidationError(
                _('Your default language needs to be one of your active languages.')
            )
        if not data.get('email'):
            raise forms.ValidationError(
                _(
                    'Please provide a contact address – your speakers and participants should be able to reach you easily.'
                )
            )
        return data

    def save(self, *args, **kwargs):
        self.instance.locale_array = ','.join(self.cleaned_data['locales'])
        return super().save(*args, **kwargs)

    class Meta:
        model = Event
        fields = [
            'name',
            'slug',
            'date_from',
            'date_to',
            'timezone',
            'email',
            'locale',
            'primary_color',
            'custom_css',
            'logo',
            'landing_page_text',
        ]
        widgets = {
            'date_from': forms.DateInput(attrs={'class': 'datepickerfield'}),
            'date_to': forms.DateInput(
                attrs={'class': 'datepickerfield', 'data-date-after': '#id_date_from'}
            ),
        }
Exemple #5
0
class EventForm(ReadOnlyFlag, I18nModelForm):
    locales = forms.MultipleChoiceField(
        label=_("Active languages"),
        choices=settings.LANGUAGES,
        widget=MultipleLanguagesWidget,
        help_text=_(
            "Users will be able to use pretalx in these languages, and you will be able to provide all texts in these"
            " languages. If you don't provide a text in the language a user selects, it will be shown in your event's"
            " default language instead."
        ),
    )
    logo = ExtensionFileField(
        required=False,
        extensions=IMAGE_EXTENSIONS,
        label=_("Header image"),
        help_text=_(
            "If you provide a header image, it will be displayed instead of your event's color and/or header pattern "
            "on top of all event pages. It will be center-aligned, so when the window shrinks, the center parts will "
            "continue to be displayed, and not stretched."
        ),
    )
    header_image = ExtensionFileField(
        required=False,
        extensions=IMAGE_EXTENSIONS,
        label=_("Header image"),
        help_text=_(
            "If you provide a logo image, we will by default not show your event's name and date in the page header. "
            "We will show your logo in its full size if possible, scaled down to the full header width otherwise."
        ),
    )
    custom_css_text = forms.CharField(
        required=False,
        widget=forms.Textarea(),
        label="",
        help_text=_("You can type in your CSS instead of uploading it, too."),
    )

    def __init__(self, *args, **kwargs):
        self.is_administrator = kwargs.pop("is_administrator", False)
        super().__init__(*args, **kwargs)
        self.initial["locales"] = self.instance.locale_array.split(",")
        year = str(now().year)
        self.fields["name"].widget.attrs["placeholder"] = (
            _("The name of your conference, e.g. My Conference") + " " + year
        )
        self.fields["slug"].help_text = _(
            "Please contact your administrator if you need to change the short name of your event."
        )
        self.fields["primary_color"].widget.attrs["placeholder"] = _(
            "A color hex value, e.g. #ab01de"
        )
        self.fields["primary_color"].widget.attrs["class"] = "colorpickerfield"
        self.fields["slug"].disabled = True

    def clean_custom_css(self):
        if self.cleaned_data.get("custom_css") or self.files.get("custom_css"):
            css = self.cleaned_data["custom_css"] or self.files["custom_css"]
            if self.is_administrator:
                return css
            try:
                validate_css(css.read())
                return css
            except IsADirectoryError:
                self.instance.custom_css = None
                self.instance.save(update_fields=["custom_css"])
        else:
            self.instance.custom_css = None
            self.instance.save(update_fields=["custom_css"])
        return None

    def clean_custom_css_text(self):
        css = self.cleaned_data.get("custom_css_text").strip()
        if not css or self.is_administrator:
            return css
        validate_css(css)
        return css

    def clean(self):
        data = super().clean()
        if data.get("locale") not in data.get("locales", []):
            error = forms.ValidationError(
                _("Your default language needs to be one of your active languages."),
            )
            self.add_error("locale", error)
        return data

    def save(self, *args, **kwargs):
        self.instance.locale_array = ",".join(self.cleaned_data["locales"])
        result = super().save(*args, **kwargs)
        css_text = self.cleaned_data["custom_css_text"]
        if css_text:
            self.instance.custom_css.save(
                self.instance.slug + ".css", ContentFile(css_text)
            )
        return result

    class Meta:
        model = Event
        fields = [
            "name",
            "slug",
            "date_from",
            "date_to",
            "timezone",
            "email",
            "locale",
            "primary_color",
            "custom_css",
            "logo",
            "header_image",
            "landing_page_text",
        ]
        widgets = {
            "date_from": forms.DateInput(attrs={"class": "datepickerfield"}),
            "date_to": forms.DateInput(
                attrs={"class": "datepickerfield", "data-date-after": "#id_date_from"}
            ),
        }
Exemple #6
0
class EventForm(ReadOnlyFlag, I18nModelForm):
    locales = forms.MultipleChoiceField(
        label=_('Active languages'),
        choices=settings.LANGUAGES,
        widget=MultipleLanguagesWidget,
    )
    logo = ExtensionFileField(
        required=False,
        extension_whitelist=IMAGE_EXTENSIONS,
        label=_('Header image'),
        help_text=
        _('If you provide a header image, it will be displayed instead of your event\'s color and/or header pattern '
          'on top of all event pages. It will be center-aligned, so when the window shrinks, the center parts will '
          'continue to be displayed, and not stretched.'),
    )
    header_image = ExtensionFileField(
        required=False,
        extension_whitelist=IMAGE_EXTENSIONS,
        label=_('Header image'),
        help_text=
        _('If you provide a logo image, we will by default not show your event\'s name and date in the page header. '
          'We will show your logo in its full size if possible, scaled down to the full header width otherwise.'
          ),
    )
    custom_css_text = forms.CharField(
        required=False,
        widget=forms.Textarea(),
        label='',
        help_text=_('You can type in your CSS instead of uploading it, too.'))

    def __init__(self, *args, **kwargs):
        self.is_administrator = kwargs.pop('is_administrator', False)
        super().__init__(*args, **kwargs)
        self.initial['locales'] = self.instance.locale_array.split(',')
        year = str(now().year)
        self.fields['name'].widget.attrs['placeholder'] = (
            _('The name of your conference, e.g. My Conference') + ' ' + year)
        self.fields['slug'].widget.attrs['placeholder'] = (
            _('A short version of your conference name, e.g. mycon') +
            year[2:])
        self.fields['primary_color'].widget.attrs['placeholder'] = _(
            'A color hex value, e.g. #ab01de')
        self.fields['primary_color'].widget.attrs['class'] = 'colorpickerfield'
        self.fields['slug'].disabled = True

    def clean_custom_css(self):
        if self.cleaned_data.get('custom_css') or self.files.get('custom_css'):
            css = self.cleaned_data['custom_css'] or self.files['custom_css']
            if self.is_administrator:
                return css
            try:
                validate_css(css.read())
                return css
            except IsADirectoryError:
                self.instance.custom_css = None
                self.instance.save(update_fields=['custom_css'])
        else:
            self.instance.custom_css = None
            self.instance.save(update_fields=['custom_css'])
        return None

    def clean_custom_css_text(self):
        css = self.cleaned_data.get('custom_css_text').strip()
        if not css or self.is_administrator:
            return css
        validate_css(css)
        return css

    def clean(self):
        data = super().clean()
        if data.get('locale') not in data.get('locales', []):
            error = forms.ValidationError(
                _('Your default language needs to be one of your active languages.'
                  ), )
            self.add_error('locale', error)
        return data

    def save(self, *args, **kwargs):
        self.instance.locale_array = ','.join(self.cleaned_data['locales'])
        result = super().save(*args, **kwargs)
        css_text = self.cleaned_data['custom_css_text']
        if css_text:
            self.instance.custom_css.save(self.instance.slug + '.css',
                                          ContentFile(css_text))
        return result

    class Meta:
        model = Event
        fields = [
            'name',
            'slug',
            'date_from',
            'date_to',
            'timezone',
            'email',
            'locale',
            'primary_color',
            'custom_css',
            'logo',
            'header_image',
            'landing_page_text',
        ]
        widgets = {
            'date_from':
            forms.DateInput(attrs={'class': 'datepickerfield'}),
            'date_to':
            forms.DateInput(attrs={
                'class': 'datepickerfield',
                'data-date-after': '#id_date_from'
            }),
        }
Exemple #7
0
class InfoForm(CfPFormMixin, RequestRequire, PublicContent, forms.ModelForm):
    additional_speaker = forms.EmailField(
        label=_("Additional Speaker"),
        help_text=_(
            "If you have a co-speaker, please add their email address here, and we will invite them to create an account. If you have more than one co-speaker, you can add more speakers after finishing the proposal process."
        ),
        required=False,
    )
    image = ExtensionFileField(
        required=False,
        extensions=IMAGE_EXTENSIONS,
        label=_("Session image"),
        help_text=_("Use this if you want an illustration to go with your proposal."),
    )

    def __init__(self, event, **kwargs):
        self.event = event
        self.readonly = kwargs.pop("readonly", False)
        self.access_code = kwargs.pop("access_code", None)
        instance = kwargs.get("instance")
        initial = kwargs.pop("initial", {}) or {}
        if not instance or not instance.submission_type:
            initial["submission_type"] = (
                getattr(self.access_code, "submission_type", None)
                or initial.get("submission_type")
                or self.event.cfp.default_type
            )
        if not instance and self.access_code:
            initial["track"] = self.access_code.track
        if not instance or not instance.content_locale:
            initial["content_locale"] = self.event.locale

        super().__init__(initial=initial, **kwargs)

        self.fields["title"].label = _("Proposal title")
        if "abstract" in self.fields:
            self.fields["abstract"].widget.attrs["rows"] = 2
        if instance and instance.pk:
            self.fields.pop("additional_speaker")

        self._set_track(instance=instance)
        self._set_submission_types(instance=instance)
        self._set_locales()
        self._set_slot_count(instance=instance)

        if self.readonly:
            for f in self.fields.values():
                f.disabled = True

    def _set_track(self, instance=None):
        if "track" in self.fields:
            if (
                not self.event.settings.use_tracks
                or instance
                and instance.state != SubmissionStates.SUBMITTED
            ):
                self.fields.pop("track")
                return

            access_code = self.access_code or getattr(instance, "access_code", None)
            if not access_code or not access_code.track:
                self.fields["track"].queryset = self.event.tracks.filter(
                    requires_access_code=False
                )
            else:
                self.fields["track"].queryset = self.event.tracks.filter(
                    pk=access_code.track.pk
                )
            if len(self.fields["track"].queryset) == 1:
                self.fields["track"].initial = self.fields["track"].queryset.first()
                self.fields["track"].widget = forms.HiddenInput()

    def _set_submission_types(self, instance=None):
        _now = now()
        if (
            instance
            and instance.pk
            and (
                instance.state != SubmissionStates.SUBMITTED
                or not self.event.cfp.is_open
            )
        ):
            self.fields[
                "submission_type"
            ].queryset = self.event.submission_types.filter(
                pk=instance.submission_type_id
            )
            self.fields["submission_type"].disabled = True
            return
        access_code = self.access_code or getattr(instance, "access_code", None)
        if access_code and not access_code.submission_type:
            pks = set(self.event.submission_types.values_list("pk", flat=True))
        elif access_code:
            pks = {access_code.submission_type.pk}
        else:
            queryset = self.event.submission_types.filter(requires_access_code=False)
            if (
                not self.event.cfp.deadline or self.event.cfp.deadline >= _now
            ):  # No global deadline or still open
                types = queryset.exclude(deadline__lt=_now)
            else:
                types = queryset.filter(deadline__gte=_now)
            pks = set(types.values_list("pk", flat=True))
        if instance and instance.pk:
            pks |= {instance.submission_type.pk}
        self.fields["submission_type"].queryset = self.event.submission_types.filter(
            pk__in=pks
        )
        if len(pks) == 1:
            self.fields["submission_type"].initial = self.event.submission_types.get(
                pk=pks.pop()
            )
            self.fields["submission_type"].widget = forms.HiddenInput()

    def _set_locales(self):
        if len(self.event.locales) == 1:
            self.fields["content_locale"].initial = self.event.locales[0]
            self.fields["content_locale"].widget = forms.HiddenInput()
        else:
            locale_names = dict(settings.LANGUAGES)
            self.fields["content_locale"].choices = [
                (a, locale_names[a]) for a in self.event.locales
            ]

    def _set_slot_count(self, instance=None):
        if not self.event.settings.present_multiple_times:
            self.fields.pop("slot_count", None)
        elif (
            "slot_count" in self.fields
            and instance
            and instance.state
            in [SubmissionStates.ACCEPTED, SubmissionStates.CONFIRMED]
        ):
            self.fields["slot_count"].disabled = True
            self.fields["slot_count"].help_text += " " + str(
                _(
                    "Please contact the organisers if you want to change how often you're presenting this proposal."
                )
            )

    class Meta:
        model = Submission
        fields = [
            "title",
            "submission_type",
            "track",
            "content_locale",
            "abstract",
            "description",
            "notes",
            "slot_count",
            "do_not_record",
            "image",
            "duration",
        ]
        request_require = [
            "title",
            "abstract",
            "description",
            "notes",
            "image",
            "do_not_record",
            "track",
            "duration",
        ]
        public_fields = ["title", "abstract", "description", "image"]
        widgets = {
            "abstract": MarkdownWidget,
            "description": MarkdownWidget,
            "notes": MarkdownWidget,
            "track": TrackSelectWidget,
        }
        field_classes = {
            "submission_type": SafeModelChoiceField,
            "track": SafeModelChoiceField,
        }