Esempio n. 1
0
class Room(LogMixin, models.Model):
    """A Room is an actual place where talks will be scheduled.

    The Room object stores some meta information. Most, like capacity,
    are not in use right now.
    """

    event = models.ForeignKey(to="event.Event",
                              on_delete=models.PROTECT,
                              related_name="rooms")
    name = I18nCharField(max_length=100, verbose_name=_("Name"))
    description = I18nCharField(
        max_length=1000,
        null=True,
        blank=True,
        verbose_name=_("Description"),
        help_text=_("A description for attendees, for example directions."),
    )
    speaker_info = I18nCharField(
        max_length=1000,
        null=True,
        blank=True,
        verbose_name=_("Speaker Information"),
        help_text=
        _("Information relevant for speakers scheduled in this room, for example room size, special directions, available adaptors for video input …"
          ),
    )
    capacity = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_("Capacity"),
        help_text=_("How many people can fit in the room?"),
    )
    position = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_("Position"),
        help_text=
        _("This is the order that rooms are displayed in in the schedule (lower = left)."
          ),
    )

    objects = ScopedManager(event="event")

    class Meta:
        ordering = ("position", )

    class urls(EventUrls):
        settings_base = edit = "{self.event.orga_urls.room_settings}{self.pk}/"
        delete = "{settings_base}delete"
        up = "{settings_base}up"
        down = "{settings_base}down"

    def __str__(self) -> str:
        return str(self.name)
Esempio n. 2
0
class Room(LogMixin, models.Model):
    """A Room is an actual place where talks will be scheduled.

    The Room object stores some meta information. Most, like capacity, are not
    in use right now.
    """
    event = models.ForeignKey(to='event.Event',
                              on_delete=models.PROTECT,
                              related_name='rooms')
    name = I18nCharField(max_length=100, verbose_name=_('Name'))
    description = I18nCharField(
        max_length=1000,
        null=True,
        blank=True,
        verbose_name=_('Description'),
        help_text=_('A description for attendees, for example directions.'),
    )
    speaker_info = I18nCharField(
        max_length=1000,
        null=True,
        blank=True,
        verbose_name=_('Speaker Information'),
        help_text=
        _('Information relevant for speakers scheduled in this room, for example room size, special directions, available adapters for video input …'
          ),
    )
    capacity = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_('Capacity'),
        help_text=_('How many people can fit in the room?'),
    )
    position = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_('Position'),
        help_text=
        _('This is the order that rooms are displayed in in the schedule (lower = left).'
          ),
    )

    class Meta:
        ordering = ('position', )

    class urls(EventUrls):
        settings_base = edit = '{self.event.orga_urls.room_settings}{self.pk}/'
        delete = '{settings_base}delete'
        up = '{settings_base}up'
        down = '{settings_base}down'

    def __str__(self) -> str:
        return str(self.name)
Esempio n. 3
0
class Room(LogMixin, models.Model):
    event = models.ForeignKey(
        to='event.Event',
        on_delete=models.PROTECT,
        related_name='rooms',
    )
    name = I18nCharField(
        max_length=100,
        verbose_name=_('Name'),
    )
    description = I18nCharField(
        max_length=1000,
        null=True,
        blank=True,
        verbose_name=_('Description'),
        help_text=_('A description for attendees, for example directions.'),
    )
    speaker_info = I18nCharField(
        max_length=1000,
        null=True,
        blank=True,
        verbose_name=_('Speaker Information'),
        help_text=
        _('Information relevant for speakers scheduled in this room, for example room size, special directions, available adapters for video input …'
          ),
    )
    capacity = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_('Capacity'),
        help_text=_('How many people can fit in the room?'))
    position = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_('Position'),
        help_text=
        _('This is the order that rooms are displayed in in the schedule (lower = left).'
          ),
    )

    class Meta:
        ordering = ('position', )

    class urls(EventUrls):
        settings_base = edit = '{self.event.orga_urls.room_settings}/{self.pk}'
        delete = '{settings_base}/delete'

    def __str__(self) -> str:
        return f'Room(event={self.event.slug}, name={self.name})'
Esempio n. 4
0
class SpeakerInformation(LogMixin, FileCleanupMixin, models.Model):
    """Represents any information organisers want to show all or some
    submitters or speakers."""

    event = models.ForeignKey(
        to="event.Event", related_name="information", on_delete=models.CASCADE
    )
    include_submitters = models.BooleanField(
        verbose_name=_("Include all submitters"),
        help_text=_("Show to every submitter regardless of their proposals' status"),
        default=False,
    )
    exclude_unconfirmed = models.BooleanField(
        verbose_name=_("Exclude unconfirmed speakers"),
        help_text=_("Show to speakers only once they have confirmed attendance"),
        default=False,
    )
    title = I18nCharField(verbose_name=_("Subject"), max_length=200)
    text = I18nTextField(verbose_name=_("Text"), help_text=phrases.base.use_markdown)
    resource = models.FileField(
        verbose_name=_("file"),
        null=True,
        blank=True,
        help_text=_("Please try to keep your upload small, preferably below 16 MB."),
        upload_to=resource_path,
    )

    objects = ScopedManager(event="event")

    class orga_urls(EventUrls):
        base = edit = "{self.event.orga_urls.information}{self.pk}/"
        delete = "{base}delete"
Esempio n. 5
0
class CfP(LogMixin, models.Model):
    event = models.OneToOneField(
        to='event.Event',
        on_delete=models.PROTECT,
    )
    headline = I18nCharField(
        max_length=300,
        null=True,
        blank=True,
    )
    text = I18nTextField(null=True, blank=True)
    default_type = models.ForeignKey(
        to='submission.SubmissionType',
        on_delete=models.PROTECT,
        related_name='+',
    )
    deadline = models.DateTimeField(null=True, blank=True)

    class urls(Urls):
        base = '{self.event.orga_urls.cfp}'
        questions = '{base}/questions'
        new_question = '{questions}/new'
        text = '{base}/text'
        edit_text = '{text}/edit'
        types = '{base}/types'
        new_type = '{types}/new'

    @property
    def is_open(self):
        if self.deadline is not None:
            return now() <= self.deadline
        return True

    def __str__(self) -> str:
        return str(self.headline)
Esempio n. 6
0
class ReviewScoreCategory(models.Model):
    event = models.ForeignKey(
        to="event.Event", related_name="score_categories", on_delete=models.CASCADE
    )
    name = I18nCharField()
    weight = models.DecimalField(max_digits=4, decimal_places=1, default=1)
    required = models.BooleanField(default=False)
    active = models.BooleanField(default=True)
    limit_tracks = models.ManyToManyField(
        to="submission.Track",
        verbose_name=_("Limit to tracks"),
        blank=True,
        help_text=_("Leave empty to use this category for all tracks."),
    )

    objects = ScopedManager(event="event")

    class urls(EventUrls):
        base = "{self.event.orga_urls.review_settings}category/{self.pk}/"
        delete = "{base}delete"

    @classmethod
    def recalculate_scores(cls, event):
        for review in event.reviews.all():
            review.save(update_score=True)
Esempio n. 7
0
class Question(LogMixin, models.Model):
    event = models.ForeignKey(
        to='event.Event',
        on_delete=models.PROTECT,
        related_name='questions',
    )
    variant = models.CharField(
        max_length=QuestionVariant.get_max_length(),
        choices=QuestionVariant.get_choices(),
        default=QuestionVariant.STRING,
    )
    question = I18nCharField(max_length=200, )
    default_answer = models.TextField(
        null=True,
        blank=True,
    )
    required = models.BooleanField(default=False, )
    position = models.IntegerField(default=0, )

    class urls(Urls):
        base = '{self.event.cfp.urls.questions}/{self.pk}'
        edit = '{base}/edit'
        delete = '{base}/delete'

    def __str__(self):
        return str(self.question)

    class Meta:
        ordering = ['position']
Esempio n. 8
0
class QuestionOption(models.Model):
    question = models.ForeignKey('Question', related_name='options', on_delete=models.CASCADE)
    identifier = models.CharField(max_length=190)
    answer = I18nCharField(verbose_name=_('Answer'))
    position = models.IntegerField(default=0)

    def __str__(self):
        return str(self.answer)

    def save(self, *args, **kwargs):
        if not self.identifier:
            charset = list('ABCDEFGHJKLMNPQRSTUVWXYZ3789')
            while True:
                code = get_random_string(length=8, allowed_chars=charset)
                if not QuestionOption.objects.filter(question__event=self.question.event, identifier=code).exists():
                    self.identifier = code
                    break
        super().save(*args, **kwargs)

    @staticmethod
    def clean_identifier(event, code, instance=None, known=[]):
        qs = QuestionOption.objects.filter(question__event=event, identifier=code)
        if instance:
            qs = qs.exclude(pk=instance.pk)
        if qs.exists() or code in known:
            raise ValidationError(_('The identifier "{}" is already used for a different option.').format(code))

    class Meta:
        verbose_name = _("Question option")
        verbose_name_plural = _("Question options")
        ordering = ('position', 'id')
Esempio n. 9
0
class Page(models.Model):
    # TODO: find the table for the foreign key
    event = models.ForeignKey(Event, on_delete=models.CASCADE)
    slug = models.CharField(
        max_length=150,
        db_index=True,
        verbose_name=_('URL to static page'),
        validators=[
            RegexValidator(
                regex="^[a-zA-Z0-9.-]+$",
                message=
                _("The slug may only contain letters, numbers, dots and dashes."
                  )),
        ],
        help_text=_(
            "This will be used to generate the URL of the page. Please only use latin letters, "
            "numbers, dots and dashes. You cannot change this afterwards."))
    position = models.IntegerField(default=0)
    title = I18nCharField(verbose_name=_('Page title'))
    text = I18nTextField(verbose_name=_('Page content'))
    link_on_frontpage = models.BooleanField(
        default=False, verbose_name=_('Show link on the event start page'))
    link_in_footer = models.BooleanField(
        default=False, verbose_name=_('Show link in the event footer'))
    require_confirmation = models.BooleanField(
        default=False,
        verbose_name=_('Require the user to acknowledge this page before the '
                       'user action (e.g. for code of conduct).'))

    class Meta:
        ordering = ['position', 'title']
Esempio n. 10
0
class Track(LogMixin, models.Model):
    """A track groups :class:`~pretalx.submission.models.submission.Submission`
    objects within an :class:`~pretalx.event.models.event.Event`, e.g. by
    topic.
    """
    event = models.ForeignKey(to='event.Event',
                              on_delete=models.PROTECT,
                              related_name='tracks')
    name = I18nCharField(
        max_length=200,
        verbose_name=_('Name'),
    )
    color = models.CharField(
        max_length=7,
        verbose_name=_('Color'),
        validators=[
            RegexValidator(r'#([0-9A-Fa-f]{3}){1,2}'),
        ],
    )

    class urls(EventUrls):
        base = edit = '{self.event.cfp.urls.tracks}{self.pk}/'
        delete = '{base}delete'
        prefilled_cfp = '{self.event.cfp.urls.public}?track={self.slug}'

    def __str__(self) -> str:
        return str(self.name)

    @property
    def slug(self) -> str:
        """The slug makes tracks more readable in URLs.

        It consists of the ID, followed by a slugified (and, in lookups, optional) form of the track name."""
        return f'{self.id}-{slugify(self.name)}'
Esempio n. 11
0
class FAQ(models.Model):
    category = models.ForeignKey(
        to=FAQCategory,
        on_delete=models.CASCADE,
        related_name='questions',
        verbose_name=_('Category'),
    )
    question = I18nCharField(verbose_name=_('Question'))
    answer = I18nTextField(verbose_name=_('Answer'))
    tags = models.CharField(
        null=True,
        blank=True,
        max_length=180,
        verbose_name=_('Tags'),
        help_text=(
            'Tags can help people find related questions. Please enter the tags separated by commas.'
        ),
    )
    position = models.PositiveIntegerField(verbose_name=_('Position'))

    objects = ScopedManager(event='category__event')

    def __str__(self):
        return str(self.question)

    class Meta:
        ordering = ('category__position', 'position', 'id')
Esempio n. 12
0
class SubmissionType(LogMixin, models.Model):
    event = models.ForeignKey(
        to='event.Event',
        related_name='submission_types',
        on_delete=models.CASCADE,
    )
    name = I18nCharField(max_length=100, )
    default_duration = models.PositiveIntegerField(
        default=30,
        help_text='Default duration in minutes',
    )
    max_duration = models.PositiveIntegerField(
        default=60,
        help_text='Maximum duration in minutes',
    )

    class urls(Urls):
        base = '{self.event.cfp.urls.types}/{self.pk}'
        default = '{base}/default'
        edit = '{base}/edit'
        delete = '{base}/delete'

    def __str__(self) -> str:
        return _('{name} ({duration} minutes)').format(
            name=self.name,
            duration=self.default_duration,
        )
Esempio n. 13
0
class Page(LogMixin, models.Model):
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="pages")
    slug = models.CharField(
        max_length=150,
        db_index=True,
        verbose_name=_("URL to static page"),
        validators=[
            RegexValidator(
                regex="^[a-zA-Z0-9.-]+$",
                message=_(
                    "The slug may only contain letters, numbers, dots and dashes."
                ),
            )
        ],
        help_text=_(
            "This will be used to generate the URL of the page. Please only use latin letters, "
            "numbers, dots and dashes. You cannot change this afterwards."
        ),
    )
    position = models.IntegerField(default=0)
    title = I18nCharField(verbose_name=_("Page title"))
    text = I18nTextField(
        verbose_name=_("Page content"), help_text=phrases.base.use_markdown
    )
    link_in_footer = models.BooleanField(
        default=False, verbose_name=_("Show link in the event footer")
    )

    class Meta:
        ordering = ["position", "title"]
Esempio n. 14
0
class Book(models.Model):
    title = I18nCharField(verbose_name='Book title', max_length=190)
    abstract = I18nTextField(verbose_name='Abstract')
    author = models.ForeignKey(Author, verbose_name='Author')

    def __str__(self):
        return str(self.title)
Esempio n. 15
0
class SpeakerInformation(LogMixin, models.Model):
    event = models.ForeignKey(
        to='event.Event', related_name='information', on_delete=models.CASCADE
    )
    include_submitters = models.BooleanField(
        verbose_name=_('Include all submitters'),
        help_text=_('Show to every submitter regardless of their submissions\' status'),
        default=False,
    )
    exclude_unconfirmed = models.BooleanField(
        verbose_name=_('Exclude unconfirmed speakers'),
        help_text=_('Show to speakers only once they have confirmed attendance'),
        default=False,
    )
    title = I18nCharField(verbose_name=_('Subject'), max_length=200)
    text = I18nTextField(verbose_name=_('Text'), help_text=phrases.base.use_markdown)
    resource = models.FileField(
        verbose_name=_('file'),
        null=True,
        blank=True,
        help_text=_('Please try to keep your upload small, preferably below 16 MB.'),
    )

    class orga_urls(EventUrls):
        base = edit = '{self.event.orga_urls.information}/{self.pk}'
        delete = '{base}/delete/'
Esempio n. 16
0
class Organiser(LogMixin, models.Model):
    """The Organiser model represents the entity responsible for one or several events."""

    name = I18nCharField(
        max_length=190,
        verbose_name=_('Name'),
    )
    slug = models.SlugField(
        max_length=50,
        db_index=True,
        unique=True,
        validators=[
            RegexValidator(
                regex=f"^[{SLUG_CHARS}]+$",
                message=
                _('The slug may only contain letters, numbers, dots and dashes.'
                  ),
            ),
        ],
        verbose_name=_('Short form'),
        help_text=
        _('Should be short, only contain lowercase letters and numbers, and must be unique, as it is used in URLs.'
          ),
    )

    def __str__(self) -> str:
        """Used in generated forms."""
        return str(self.name)

    class orga_urls(EventUrls):
        base = '/orga/organiser/{self.slug}'
        teams = '{base}/teams'
        new_team = '{teams}/new'
Esempio n. 17
0
class ItemCategory(LoggedModel):
    """
    Items can be sorted into these categories.

    :param event: The event this category belongs to
    :type event: Event
    :param name: The name of this category
    :type name: str
    :param position: An integer, used for sorting
    :type position: int
    """
    event = models.ForeignKey(
        Event,
        on_delete=models.CASCADE,
        related_name='categories',
    )
    name = I18nCharField(
        max_length=255,
        verbose_name=_("Category name"),
    )
    description = I18nTextField(
        blank=True, verbose_name=_("Category description")
    )
    position = models.IntegerField(
        default=0
    )
    is_addon = models.BooleanField(
        default=False,
        verbose_name=_('Products in this category are add-on products'),
        help_text=_('If selected, the products belonging to this category are not for sale on their own. They can '
                    'only be bought in combination with a product that has this category configured as a possible '
                    'source for add-ons.')
    )

    class Meta:
        verbose_name = _("Product category")
        verbose_name_plural = _("Product categories")
        ordering = ('position', 'id')

    def __str__(self):
        if self.is_addon:
            return _('{category} (Add-On products)').format(category=str(self.name))
        return str(self.name)

    def delete(self, *args, **kwargs):
        super().delete(*args, **kwargs)
        if self.event:
            self.event.get_cache().clear()

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if self.event:
            self.event.get_cache().clear()

    @property
    def sortkey(self):
        return self.position, self.id

    def __lt__(self, other) -> bool:
        return self.sortkey < other.sortkey
Esempio n. 18
0
class MembershipType(LoggedModel):
    id = models.BigAutoField(primary_key=True)
    organizer = models.ForeignKey(Organizer, related_name='membership_types', on_delete=models.CASCADE)
    name = I18nCharField(
        verbose_name=_('Name'),
    )
    transferable = models.BooleanField(
        verbose_name=_('Membership is transferable'),
        help_text=_('If this is selected, the membership can be used to purchase tickets for multiple persons. If not, '
                    'the attendee name always needs to stay the same.'),
        default=False
    )
    allow_parallel_usage = models.BooleanField(
        verbose_name=_('Parallel usage is allowed'),
        help_text=_('If this is selected, the membership can be used to purchase tickets for events happening at the same time. Note '
                    'that this will only check for an identical start time of the events, not for any overlap between events.'),
        default=False
    )
    max_usages = models.PositiveIntegerField(
        verbose_name=_("Maximum usages"),
        help_text=_("Number of times this membership can be used in a purchase."),
        null=True, blank=True,
    )

    class Meta:
        ordering = ('id',)

    def __str__(self):
        return str(self.name)

    def allow_delete(self):
        return not self.memberships.exists() and not self.granted_by.exists()
Esempio n. 19
0
class CfP(LogMixin, models.Model):
    event = models.OneToOneField(
        to='event.Event',
        on_delete=models.PROTECT,
    )
    headline = I18nCharField(
        max_length=300,
        null=True, blank=True,
    )
    text = I18nTextField(null=True, blank=True)
    default_type = models.ForeignKey(
        to='submission.SubmissionType',
        on_delete=models.PROTECT,
        related_name='+',
    )
    deadline = models.DateTimeField(null=True, blank=True)

    @property
    def is_open(self):
        if self.deadline is not None:
            return now() <= self.deadline
        return True

    def __str__(self) -> str:
        return str(self.headline)
Esempio n. 20
0
class CfP(LogMixin, models.Model):
    event = models.OneToOneField(
        to='event.Event',
        on_delete=models.PROTECT,
    )
    headline = I18nCharField(
        max_length=300,
        null=True,
        blank=True,
        verbose_name=_('headline'),
    )
    text = I18nTextField(
        null=True,
        blank=True,
        verbose_name=_('text'),
        help_text=_('You can use markdown here.'),
    )
    default_type = models.ForeignKey(
        to='submission.SubmissionType',
        on_delete=models.PROTECT,
        related_name='+',
        verbose_name=_('Default submission type'),
    )
    deadline = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_('deadline'),
        help_text=
        _('Please put in the last date you want to accept submissions from users.'
          ),
    )

    class urls(EventUrls):
        base = '{self.event.orga_urls.cfp}'
        questions = '{base}/questions'
        new_question = '{questions}/new'
        remind_questions = '{questions}/remind'
        text = edit_text = '{base}/text'
        types = '{base}/types'
        new_type = '{types}/new'
        public = '{self.event.urls.base}/cfp'

    def __str__(self) -> str:
        return f'CfP(event={self.event.slug})'

    @cached_property
    def is_open(self):
        if self.deadline is None:
            return True
        return self.max_deadline >= now()

    @cached_property
    def max_deadline(self):
        deadlines = list(
            self.event.submission_types.filter(
                deadline__isnull=False).values_list('deadline', flat=True))
        if self.deadline:
            deadlines += [self.deadline]
        return max(deadlines)
Esempio n. 21
0
class MailTemplate(Auditable, models.Model):

    subject = I18nCharField(
        max_length=200,
        verbose_name=_('Subject'),
    )
    text = I18nTextField(
        verbose_name=_('Text'),
    )
    reply_to = models.EmailField(
        max_length=200,
        blank=True, null=True,
        verbose_name=_('Reply-To'),
        help_text=_('Change the Reply-To address if you do not want to use the default orga address'),
    )
    bcc = models.CharField(
        max_length=1000,
        blank=True, null=True,
        verbose_name=_('BCC'),
        help_text=_('Enter comma separated addresses. Will receive a blind copy of every mail sent from this template. This may be a LOT!'),
    )

    def __str__(self):
        return '{self.subject}'.format(self=self)

    def to_mail(self, email, locale=None, context=None, skip_queue=False, attachments=None, save=True):
        from byro.common.models import Configuration
        config = Configuration.get_solo()
        locale = locale or config.language
        with override(locale):
            context = context or dict()
            try:
                subject = str(self.subject).format(**context)
                text = str(self.text).format(**context)
            except KeyError as e:
                raise SendMailException('Experienced KeyError when rendering Text: {e}'.format(e=e))

            mail = EMail(
                to=email,
                reply_to=self.reply_to,
                bcc=self.bcc,
                subject=subject,
                text=text,
                template=self,
            )
            if save:
                mail.save()
                if attachments:
                    for a in attachments:
                        mail.attachments.add(a)
                if skip_queue:
                    mail.send()
        return mail

    def get_absolute_url(self):
        return reverse('office:mails.templates.view', kwargs={'pk': self.pk})

    def get_object_icon(self):
        return mark_safe('<i class="fa fa-envelope-o"></i> ')
Esempio n. 22
0
class CfP(LogMixin, models.Model):
    event = models.OneToOneField(to='event.Event', on_delete=models.PROTECT)
    headline = I18nCharField(max_length=300,
                             null=True,
                             blank=True,
                             verbose_name=_('headline'))
    text = I18nTextField(
        null=True,
        blank=True,
        verbose_name=_('text'),
        help_text=phrases.base.use_markdown,
    )
    default_type = models.ForeignKey(
        to='submission.SubmissionType',
        on_delete=models.PROTECT,
        related_name='+',
        verbose_name=_('Default submission type'),
    )
    deadline = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_('deadline'),
        help_text=
        _('Please put in the last date you want to accept submissions from users.'
          ),
    )

    class urls(EventUrls):
        base = '{self.event.orga_urls.cfp}'
        questions = '{base}questions/'
        new_question = '{questions}new'
        remind_questions = '{questions}remind'
        text = edit_text = '{base}text'
        types = '{base}types/'
        new_type = '{types}new'
        tracks = '{base}tracks/'
        new_track = '{tracks}new'
        public = '{self.event.urls.base}cfp'
        submit = '{self.event.urls.base}submit/'

    def __str__(self) -> str:
        """Help with debugging."""
        return f'CfP(event={self.event.slug})'

    @cached_property
    def is_open(self):
        if self.deadline is None:
            return True
        return self.max_deadline >= now() if self.max_deadline else True

    @cached_property
    def max_deadline(self):
        deadlines = list(
            self.event.submission_types.filter(
                deadline__isnull=False).values_list('deadline', flat=True))
        if self.deadline:
            deadlines.append(self.deadline)
        return max(deadlines) if deadlines else None
Esempio n. 23
0
class RadioOption(django_models.Model):
    name = I18nCharField(max_length=60)

    related_filter = django_models.ForeignKey(RadioFilter,
                                              related_name='options',
                                              on_delete=django_models.CASCADE)

    def __str__(self):
        return f'{self.name} option id: {self.id}'
Esempio n. 24
0
class EmailTemplate(models.Model):
    title = I18nCharField(max_length=255)
    subject = I18nCharField(max_length=255)
    plain_text = I18nTextField()
    html_body = I18nRichTextField(blank=True)

    panels = [
        FieldPanel('title', heading=_('Title')),
        FieldPanel('subject', heading=_('Subject')),
        FieldPanel('plain_text', heading=_('Plain Text Body')),
        FieldPanel('html_body', heading=_('HTML Body')),
    ]

    def __str__(self):
        return str(self.title)

    class Meta:
        verbose_name = _('Email Template')
        verbose_name_plural = _('Email Templates')
Esempio n. 25
0
class Track(LogMixin, models.Model):
    event = models.ForeignKey(
        to='event.Event',
        on_delete=models.PROTECT,
        related_name='tracks',
    )
    name = I18nCharField(max_length=200, )
    color = models.CharField(max_length=7, )

    def __str__(self) -> str:
        return str(self.name)
Esempio n. 26
0
class MailTemplate(LogMixin, models.Model):
    event = models.ForeignKey(
        to='event.Event',
        on_delete=models.PROTECT,
        related_name='mail_templates',
    )
    subject = I18nCharField(max_length=200)
    text = I18nTextField()
    reply_to = models.EmailField(
        max_length=200,
        blank=True,
        null=True,
        verbose_name=_('Reply-To'),
        help_text=
        _('Change the Reply-To address if you do not want to use the default orga address'
          ),
    )
    bcc = models.CharField(
        max_length=1000,
        blank=True,
        null=True,
        verbose_name=_('BCC'),
        help_text=
        _('Enter comma separated addresses. Will receive a blind copy of every mail sent from this template. This may be a LOT!'
          ))

    class urls(Urls):
        base = '{self.event.orga_urls.mail_templates}/{self.pk}'
        edit = '{base}/edit'
        delete = '{base}/delete'

    def bulk_mail(self):
        # TODO: call to_mail
        pass

    def to_mail(self,
                user,
                event,
                locale=None,
                context=None,
                skip_queue=False):
        with override(locale):
            context = TolerantDict(context or dict())
            mail = QueuedMail(event=self.event,
                              to=user.email,
                              reply_to=self.reply_to or event.email,
                              bcc=self.bcc,
                              subject=str(self.subject).format(**context),
                              text=str(self.text).format(**context))
            if skip_queue:
                mail.send()
            else:
                mail.save()
        return mail
Esempio n. 27
0
class Filter(PolymorphicModel):
    name = I18nCharField(max_length=60)
    order = django_models.PositiveIntegerField(default=0)

    objects = PolymorphicManager.from_queryset(FilterQuerySet)()

    def __str__(self):
        return f'{self.name} filter'

    class Meta:
        ordering = ['order']
Esempio n. 28
0
class Track(LogMixin, models.Model):
    event = models.ForeignKey(
        to='event.Event',
        on_delete=models.PROTECT,
        related_name='tracks',
    )
    name = I18nCharField(max_length=200, )
    color = models.CharField(max_length=7, )

    def __str__(self) -> str:
        """Help when debugging."""
        return f'Track(event={self.event.slug}, name={self.name})'
Esempio n. 29
0
class QuestionOption(models.Model):
    question = models.ForeignKey('Question', related_name='options')
    answer = I18nCharField(verbose_name=_('Answer'))
    position = models.IntegerField(default=0)

    def __str__(self):
        return str(self.answer)

    class Meta:
        verbose_name = _("Question option")
        verbose_name_plural = _("Question options")
        ordering = ('position', 'id')
Esempio n. 30
0
class Track(LogMixin, models.Model):
    """A track groups :class:`~pretalx.submission.models.submission.Submission`
    objects within an :class:`~pretalx.event.models.event.Event`, e.g. by
    topic.

    :param color: The track colour, in the format #012345.
    """

    event = models.ForeignKey(
        to="event.Event", on_delete=models.PROTECT, related_name="tracks"
    )
    name = I18nCharField(
        max_length=200,
        verbose_name=_("Name"),
    )
    description = I18nTextField(
        verbose_name=_("Description"),
        blank=True,
    )
    color = models.CharField(
        max_length=7,
        verbose_name=_("Color"),
        validators=[
            RegexValidator(r"#([0-9A-Fa-f]{3}){1,2}"),
        ],
    )
    requires_access_code = models.BooleanField(
        verbose_name=_("Requires access code"),
        help_text=_(
            "This track will only be shown to submitters with a matching access code."
        ),
        default=False,
    )

    objects = ScopedManager(event="event")

    class urls(EventUrls):
        base = edit = "{self.event.cfp.urls.tracks}{self.pk}/"
        delete = "{base}delete"
        prefilled_cfp = "{self.event.cfp.urls.public}?track={self.slug}"

    def __str__(self) -> str:
        return str(self.name)

    @property
    def slug(self) -> str:
        """The slug makes tracks more readable in URLs.

        It consists of the ID, followed by a slugified (and, in lookups,
        optional) form of the track name.
        """
        return f"{self.id}-{slugify(self.name)}"