Ejemplo n.º 1
0
 class Meta:
     model = Appliance
     fields = [
         'name', 'short_description', 'description', 'documentation',
         'appliance_icon', 'chi_tacc_appliance_id', 'chi_uc_appliance_id',
         'kvm_tacc_appliance_id', 'template', 'author_name', 'author_url',
         'support_contact_name', 'support_contact_url', 'keywords',
         'new_keywords', 'version', 'project_supported'
     ]
     labels = {
         'short_description': 'Short description (140 characters)',
         'chi_tacc_appliance_id': 'Appliance ID for '
         '<a href="https://chi.tacc.chameleoncloud.org">CHI@TACC</a>',
         'chi_uc_appliance_id': 'Appliance ID for '
         '<a href="https://chi.uc.chameleoncloud.org">CHI@UC</a>',
         'kvm_tacc_appliance_id': 'Appliance ID for '
         '<a href="https://openstack.tacc.chameleoncloud.org">KVM@TACC</a>',
         'template': 'Template (Complex Appliances Only)',
         'author_url': 'Author: Contact URL or Email',
         'support_contact_name': 'Support: Contact Name',
         'support_contact_url': 'Support: Contact URL or Email',
     }
     widgets = {
         'chi_tacc_appliance_id':
         forms.TextInput(attrs={'placeholder': ''}),
         'chi_uc_appliance_id': forms.TextInput(attrs={'placeholder': ''}),
         'kvm_tacc_appliance_id':
         forms.TextInput(attrs={'placeholder': ''}),
     }
     help_texts = {
         'description': markdown_allowed(),
         'documentation': markdown_allowed()
     }
Ejemplo n.º 2
0
class AdminRevokeForm(forms.Form):
    user_reason = forms.CharField(label='Reason for rejection (user)',
                                  required=False,
                                  widget=forms.Textarea(attrs={'rows': 5}),
                                  help_text=markdown_allowed())
    internal_reason = forms.CharField(label='Reason for rejection (internal)',
                                      required=False,
                                      widget=forms.Textarea(attrs={'rows': 5}),
                                      help_text=markdown_allowed())
Ejemplo n.º 3
0
class Election(ExtraInfoMixin, models.Model):
    name = models.CharField(max_length=255)
    slug = AutoSlugField(populate_from='name', unique=True)
    description = models.TextField(blank=True)
    tags = TaggableManager(blank=True)
    searchable = models.BooleanField(default=True)
    highlighted = models.BooleanField(default=False)
    extra_info_title = models.CharField(max_length=50, blank=True, null=True)
    extra_info_content = models.TextField(max_length=3000, blank=True, null=True, help_text=_("Puedes usar Markdown. <br/> ")
            + markdown_allowed())
    uses_preguntales = models.BooleanField(default=False, help_text=_(u"Esta elección debe usar preguntales?"))
    uses_ranking = models.BooleanField(default=False, help_text=_(u"Esta elección debe usar ranking"))
    uses_face_to_face = models.BooleanField(default=True, help_text=_(u"Esta elección debe usar frente a frente"))
    uses_soul_mate = models.BooleanField(default=True, help_text=_(u"Esta elección debe usar 1/2 naranja"))
    uses_questionary = models.BooleanField(default=True, help_text=_(u"Esta elección debe usar cuestionario"))

    default_extra_info = settings.DEFAULT_ELECTION_EXTRA_INFO
    area = models.ForeignKey(Area, null=True, related_name="elections")

    def __unicode__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('election_view', kwargs={'slug': self.slug})

    def get_extra_info_url(self):
            return reverse('election_extra_info', kwargs={'slug': self.slug})

    class Meta:
            verbose_name = _(u'Mi Elección')
            verbose_name_plural = _(u'Mis Elecciones')
Ejemplo n.º 4
0
class Tournament(models.Model):
    id = models.IntegerField(primary_key=True)

    # Tournament display information
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True, help_text=markdown_allowed())
    start = models.DateTimeField(default=timezone.now)
    end = models.DateTimeField(default=timezone.now)

    # TODO: handle signups through warwick.gg itself rather than an external signup form.
    signup_form = models.URLField()
    signup_start = models.DateTimeField(default=timezone.now)
    signup_end = models.DateTimeField(default=timezone.now)

    # Associated event
    for_event = models.ForeignKey(Event, on_delete=models.CASCADE, blank=True, null=True)
    requires_attendance = models.BooleanField(default=False)

    # Routing
    slug = models.SlugField(max_length=40, unique=True)

    @property
    def signups_open(self):
        return self.signup_start < timezone.now() <= self.signup_end

    def get_absolute_url(self):
        return '/events/tournament/{slug}'.format(slug=self.slug)
Ejemplo n.º 5
0
class Election(ExtraInfoMixin, models.Model, OGPMixin):
    name = models.CharField(max_length=255)
    slug = AutoSlugField(populate_from='name', unique=True)
    description = models.TextField(blank=True)
    tags = TaggableManager(blank=True)
    searchable = models.BooleanField(default=True)
    highlighted = models.BooleanField(default=False)
    extra_info_title = models.CharField(max_length=50, blank=True, null=True)
    extra_info_content = models.TextField(
        max_length=3000,
        blank=True,
        null=True,
        help_text=_("Puedes usar Markdown. <br/> ") + markdown_allowed())
    uses_preguntales = models.BooleanField(
        default=False, help_text=_(u"Esta elección debe usar preguntales?"))
    uses_ranking = models.BooleanField(
        default=False, help_text=_(u"Esta elección debe usar ranking"))
    uses_face_to_face = models.BooleanField(
        default=True, help_text=_(u"Esta elección debe usar frente a frente"))
    uses_soul_mate = models.BooleanField(
        default=True, help_text=_(u"Esta elección debe usar 1/2 naranja"))
    uses_questionary = models.BooleanField(
        default=True, help_text=_(u"Esta elección debe usar cuestionario"))
    position = models.CharField(default='',
                                null=True,
                                blank=True,
                                max_length=255,
                                help_text=_(u'A qué cargo está postulando?'))

    default_extra_info = settings.DEFAULT_ELECTION_EXTRA_INFO
    area = models.ForeignKey(Area,
                             blank=True,
                             null=True,
                             related_name="elections")

    ogp_enabled = True

    def __unicode__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('election_view', kwargs={'slug': self.slug})

    def ranking(self):
        return Candidate.ranking.filter(elections=self)

    def position_in_ranking(self, candidate):
        qs = self.ranking()
        return get_position_in_(qs, candidate)

    def get_extra_info_url(self):
        return reverse('election_extra_info', kwargs={'slug': self.slug})

    def has_anyone_answered(self):
        return TakenPosition.objects.filter(
            person__in=self.candidates.all()).exists()

    class Meta:
        verbose_name = _(u'Mi Elección')
        verbose_name_plural = _(u'Mis Elecciones')
Ejemplo n.º 6
0
class Election(models.Model):
    name = models.CharField(max_length=255)
    slug = AutoSlugField(populate_from='name', unique=True)
    description = models.TextField(blank=True)
    tags = TaggableManager(blank=True)
    can_election = models.OneToOneField(CanElection, null=True, blank=True)
    searchable = models.BooleanField(default=True)
    highlighted = models.BooleanField(default=False)
    popit_api_instance = models.ForeignKey(PopitApiInstance, null=True, blank=True)
    writeitinstance = models.ForeignKey(WriteItInstance, null=True, blank=True)
    extra_info_title = models.CharField(max_length=50, blank=True, null=True)
    extra_info_content = models.TextField(max_length=3000, blank=True, null=True,
                                          help_text=_("Puedes usar Markdown. <br/> ")
                                                    + markdown_allowed())
    uses_preguntales = models.BooleanField(default=True, help_text=_(u"Esta elección debe usar preguntales?"))
    uses_ranking = models.BooleanField(default=True, help_text=_(u"Esta elección debe usar ranking"))
    uses_face_to_face = models.BooleanField(default=True, help_text=_(u"Esta elección debe usar frente a frente"))
    uses_soul_mate = models.BooleanField(default=True, help_text=_(u"Esta elección debe usar 1/2 naranja"))
    uses_questionary = models.BooleanField(default=True, help_text=_(u"Esta elección debe usar cuestionario"))

    def __unicode__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('election_view', kwargs={'slug': self.slug})

    def get_extra_info_url(self):
        return reverse('election_extra_info', kwargs={'slug': self.slug})

    class Meta:
        verbose_name = _(u'Mi Elección')
        verbose_name_plural = _(u'Mis Elecciones')
Ejemplo n.º 7
0
class Post(models.Model):
    """
    Database model for individual posts.
    """
    contentHelpText = markdown_allowed() + " <a id='ref'>Quick reference</a>"

    title = models.CharField(max_length=100)
    content = models.TextField(help_text=contentHelpText)
    date_posted = models.DateTimeField(auto_now_add=True)
    author = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    view_count = models.PositiveIntegerField(default=0)

    tags = TaggableManager()
    TAGGIT_CASE_INSENSITIVE = True

    class Meta:
        ordering = ['-date_posted']

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post-detail', kwargs={'pk': self.pk})

    def getContent(self):
        return markdown(self.content)
Ejemplo n.º 8
0
class Bio(models.Model):

    artist = models.OneToOneField(Artist, on_delete=models.CASCADE)
    bio = models.TextField(help_text="Short biography of artist. " +
                           markdown_allowed())

    def __str__(self):
        return str(self.artist)
Ejemplo n.º 9
0
class AlbumBio(models.Model):

    album = models.OneToOneField(Album, on_delete=models.CASCADE)
    bio = models.TextField(
        help_text="Tracklisting and other info about the album. " +
        markdown_allowed())

    def __str__(self):
        return str(self.album)
Ejemplo n.º 10
0
class PostForm(forms.ModelForm):
    title = forms.CharField()
    body = forms.CharField(
        widget=PagedownWidget(),
        help_text=markdown_allowed()
    )

    class Meta:
        model = Post
        fields = ['title', 'body']
Ejemplo n.º 11
0
class Update(models.Model):

    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    created_datetime = models.DateTimeField(db_index=True, auto_now_add=True)
    title = models.CharField(max_length=75)
    text = models.TextField(help_text="The content of the update. " +
                            markdown_allowed())

    def __str__(self):
        return self.title
Ejemplo n.º 12
0
class Tournament(models.Model):
    id = models.IntegerField(primary_key=True)

    # Tournament display information
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True, help_text=markdown_allowed())
    start = models.DateTimeField(default=timezone.now)
    end = models.DateTimeField(default=timezone.now)

    # TODO: handle signups through warwick.gg itself rather than an external signup form.
    signup_form = models.URLField()
    signup_start = models.DateTimeField(default=timezone.now)
    signup_end = models.DateTimeField(default=timezone.now)

    # Associated event
    for_event = models.ForeignKey(Event,
                                  on_delete=models.CASCADE,
                                  blank=True,
                                  null=True)
    requires_attendance = models.BooleanField(default=False)

    # Routing
    slug = models.SlugField(max_length=40, unique=True)

    objects = TournamentManager()

    def __str__(self):
        return self.title

    @property
    def signups_open(self):
        return self.signup_start < timezone.now() <= self.signup_end

    @property
    def is_onging(self):
        return timezone.now() < self.end

    def get_absolute_url(self):
        return '/events/tournament/{slug}'.format(slug=self.slug)


# class TournamentSignupManager(models.Manager):
#     pass
#
#
# class TournamentSignup(models.Model):
#     user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
#     tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
#     created_at = models.DateTimeField(default=timezone.now)
#     comment = models.TextField(blank=True, max_length=255)
#
#     # Stripe transaction tokens in case of refund
#     ticket = models.OneToOneField(Ticket, related_name='signup', on_delete=models.CASCADE, blank=True, null=True)
#
#     objects = TournamentSignupManager()
Ejemplo n.º 13
0
class Eleccion(models.Model):
    nombre = models.CharField(max_length=255)
    popit_api_instance = models.OneToOneField(ApiInstance)
    write_it_instance = models.OneToOneField(WriteItInstance, null=True)
    slug = models.CharField(max_length=255)
    main_embedded = models.CharField(max_length=512, blank=True, null=True)
    messaging_extra_app_url = models.CharField(max_length=512,
                                               blank=True,
                                               null=True)
    mapping_extra_app_url = models.CharField(max_length=512,
                                             blank=True,
                                             null=True)
    featured = models.BooleanField(default=False)
    searchable = models.BooleanField(default=True)
    featured_caption = models.CharField(max_length=100, blank=True, null=True)
    extra_info_title = models.CharField(max_length=50, blank=True, null=True)
    extra_info_content = models.TextField(
        max_length=3000,
        blank=True,
        null=True,
        help_text="Puedes usar Markdown. <br/> " + markdown_allowed())

    def __unicode__(self):
        return self.nombre

    def preguntas(self):
        #solo preguntas aprobadas
        candidatos_eleccion = Candidato.objects.filter(eleccion=self)
        preguntas_candidatos_eleccion = Pregunta.objects.filter(
            aprobada=True).filter(
                candidato__in=candidatos_eleccion).distinct()
        return preguntas_candidatos_eleccion

    def numero_preguntas(self):
        preg = self.preguntas()
        return preg.count()

    def numero_respuestas(self):
        resp = Respuesta.objects.filter(pregunta__in=self.preguntas()).exclude(
            texto_respuesta=settings.NO_ANSWER_DEFAULT_MESSAGE).distinct()
        return resp.count()
Ejemplo n.º 14
0
class Request(HasMetadata):
    """
    Represents a request to grant a user a role.

    There may be many requests for each access(role/user combination). A request
    is considered 'active' if:

      1. It is the most recent request for the role/user combination
      2. It was requested after the active grant for the role/user combination

    A can be in one of three states: PENDING, REJECTED or APPROVED. A rejected
    request will have a reason to present to the user, and an approved request
    will have an associated grant.

    A request can have arbitrary metadata associated with it. That metadata is
    defined by the service.
    """
    class Meta:
        ordering = (
            'access__role__service__category__position',
            'access__role__service__category__long_name',
            'access__role__service__position',
            'access__role__service__name',
            'access__role__position',
            'access__role__name',
            '-requested_at',
        )
        get_latest_by = 'requested_at'
        permissions = (('decide_request', 'Can make decisions on requests'), )

    objects = RequestQuerySet.as_manager()

    #: The role/user combination that the request is for
    access = models.ForeignKey(Access,
                               models.CASCADE,
                               related_name='requests',
                               related_query_name='request')
    #: Username of the user who requested the role
    requested_by = models.CharField(max_length=200)
    #: The datetime at which the service request was created
    requested_at = models.DateTimeField(auto_now_add=True)
    #: The current state of the request
    state = RequestState.model_field(default=RequestState.PENDING)
    #: True if request requires more information
    incomplete = models.BooleanField(default=False)
    #: If approved, this is the resulting access grant
    resulting_grant = models.OneToOneField(Grant,
                                           models.SET_NULL,
                                           null=True,
                                           blank=True,
                                           related_name='request')
    #: If approved, this is the access grant being superceeded
    previous_grant = models.ForeignKey(Grant,
                                       models.SET_NULL,
                                       null=True,
                                       blank=True,
                                       related_name='next_requests')
    #: Request that this request superceeds
    previous_request = models.OneToOneField('self',
                                            models.SET_NULL,
                                            null=True,
                                            blank=True,
                                            related_name='next_request')
    #: If rejected, this is a reason for the user
    user_reason = models.TextField(blank=True,
                                   verbose_name='Reason for rejection (user)',
                                   help_text=markdown_allowed())
    #: Optional internal reason, for sensitive details
    internal_reason = models.TextField(
        blank=True,
        verbose_name='Reason for rejection (internal)',
        help_text=markdown_allowed())

    def __str__(self):
        return '{} : {}'.format(self.access,
                                'INCOMPETE' if self.incomplete else self.state)

    @property
    def active(self):
        """
        Returns ``True`` if this request is the active request for the
        service/role/user combination.
        """
        if not hasattr(self, '_active'):
            if self.resulting_grant or hasattr(self, 'next_request'):
                # Unsaved requests won't have a resulting grant
                self._active = False
            else:
                self._active = True
        return self._active

    @active.setter
    def active(self, value):
        self._active = value

    @property
    def pending(self):
        """
        ``True`` if the request is in the PENDING state, ``False`` otherwise.
        """
        return self.state == RequestState.PENDING

    @property
    def approved(self):
        """
        ``True`` if the request is in the APPROVED state, ``False`` otherwise.
        """
        return self.state == RequestState.APPROVED

    @property
    def rejected(self):
        """
        ``True`` if the request is in the REJECTED state, ``False`` otherwise.
        """
        return self.state == RequestState.REJECTED

    def clean(self):
        errors = {}
        # If we are approved, we need a grant
        if self.state == RequestState.APPROVED and not self.resulting_grant:
            errors['grant'] = 'Required for state {}'.format(self.state)
        # If we have a grant, we must be approved
        if self.resulting_grant and not self.state == RequestState.APPROVED:
            errors['grant'] = 'Not allowed for state {}'.format(self.state)
        # If the state is rejected, we need a user reason
        if self.state == RequestState.REJECTED and not self.user_reason:
            errors['user_reason'] = 'Please give a reason for rejection'
        # If the request is incomplete, it must be rejected
        if self.incomplete and not self.state == RequestState.REJECTED:
            errors[
                'state'] = 'Incomplete requests must be in the REJECTED state'
        try:
            user = self.access.user
            # Ensure that the user is active
            if not user.is_active:
                errors['user'] = '******'
            #
            if not settings.MULTIPLE_REQUESTS_ALLOWED:
                active_grant = Grant.objects.filter(access=self.access,
                                                    next_grant__isnull=True)
                active_request = Request.objects.filter(
                    access=self.access,
                    resulting_grant__isnull=True,
                    next_request__isnull=True)
                if self.active and active_grant and self.previous_grant != active_grant[
                        0]:
                    errors = 'There is already an existing active grant for this access'
                if self.active and active_request and self != active_request[0]:
                    errors = 'There is already an existing active request for this access'
        except ObjectDoesNotExist:
            pass
        # Check that the grant is for the same service/role/user combination
        if self.resulting_grant:
            try:
                if self.resulting_grant.access != self.access:
                    errors[
                        'grant'] = 'Grant must be for same access as request'
            except ObjectDoesNotExist:
                pass
        if errors:
            raise ValidationError(errors)
Ejemplo n.º 15
0
class DecisionForm(forms.Form):
    """
    Form for making a decision on a request.
    """
    # Constants defining options for the quick expiry selection
    EXPIRES_SIX_MONTHS = 1
    EXPIRES_ONE_YEAR = 2
    EXPIRES_TWO_YEARS = 3
    EXPIRES_THREE_YEARS = 4
    EXPIRES_FIVE_YEARS = 5
    EXPIRES_TEN_YEARS = 6
    EXPIRES_CUSTOM = 7

    state = forms.TypedChoiceField(label='Decision',
                                   choices=[(None, '---------'),
                                            ('APPROVED', 'APPROVED'),
                                            ('INCOMPLETE', 'INCOMPLETE'),
                                            ('REJECTED', 'REJECTED')],
                                   coerce=str,
                                   empty_value=None)
    expires = forms.TypedChoiceField(
        label='Expiry date',
        help_text=
        'Pick a duration from the dropdown list, or pick a custom expiry date',
        required=False,
        choices=[
            (0, '---------'),
            (EXPIRES_SIX_MONTHS, 'Six months from now'),
            (EXPIRES_ONE_YEAR, 'One year from now'),
            (EXPIRES_TWO_YEARS, 'Two years from now'),
            (EXPIRES_THREE_YEARS, 'Three years from now'),
            (EXPIRES_FIVE_YEARS, 'Five years from now'),
            (EXPIRES_TEN_YEARS, 'Ten years from now'),
            (EXPIRES_CUSTOM, 'Custom expiry date'),
        ],
        coerce=int,
        empty_value=0)
    expires_custom = forms.DateField(label='Custom expiry date',
                                     required=False,
                                     input_formats=['%Y-%m-%d', '%d/%m/%Y'],
                                     widget=forms.DateInput(
                                         format='%Y-%m-%d',
                                         attrs={'type': 'date'}))
    user_reason = forms.CharField(label='Reason for rejection (user)',
                                  required=False,
                                  widget=forms.Textarea(attrs={'rows': 5}),
                                  help_text=mark_safe(markdown_allowed()))
    internal_reason = forms.CharField(label='Reason for rejection (internal)',
                                      required=False,
                                      widget=forms.Textarea(attrs={'rows': 5}),
                                      help_text=mark_safe(markdown_allowed()))

    def __init__(self, request, approver, *args, **kwargs):
        self._request = request
        self._approver = approver
        super().__init__(*args, **kwargs)

    def clean_state(self):
        state = self.cleaned_data.get('state')
        if state is None:
            raise ValidationError('This field is required')
        return state

    def clean_expires(self):
        state = self.cleaned_data.get('state')
        expires = self.cleaned_data.get('expires')
        if state == 'APPROVED' and not expires:
            raise ValidationError('Please give an expiry date for access')
        return expires

    def clean_expires_custom(self):
        state = self.cleaned_data.get('state')
        expires = self.cleaned_data.get('expires')
        expires_custom = self.cleaned_data.get('expires_custom')
        if state == 'APPROVED' and expires == self.EXPIRES_CUSTOM and not expires_custom:
            raise ValidationError('Please give an expiry date for access')
        if expires_custom and expires_custom < date.today():
            raise ValidationError('Expiry date must be in the future')
        return expires_custom

    def clean_user_reason(self):
        state = self.cleaned_data.get('state')
        user_reason = self.cleaned_data.get('user_reason')
        if state != 'APPROVED' and not user_reason:
            raise ValidationError(
                'Please give a reason for rejection or incompletion')
        return user_reason

    def save(self):
        # Update the request from the form
        if self.cleaned_data['state'] == 'APPROVED':
            # Get the expiry date
            expires = self.cleaned_data['expires']
            if expires == self.EXPIRES_SIX_MONTHS:
                expires_date = date.today() + relativedelta(months=6)
            elif expires == self.EXPIRES_ONE_YEAR:
                expires_date = date.today() + relativedelta(years=1)
            elif expires == self.EXPIRES_TWO_YEARS:
                expires_date = date.today() + relativedelta(years=2)
            elif expires == self.EXPIRES_THREE_YEARS:
                expires_date = date.today() + relativedelta(years=3)
            elif expires == self.EXPIRES_FIVE_YEARS:
                expires_date = date.today() + relativedelta(years=5)
            elif expires == self.EXPIRES_TEN_YEARS:
                expires_date = date.today() + relativedelta(years=10)
            else:
                expires_date = self.cleaned_data['expires_custom']
            self._request.state = RequestState.APPROVED
            # If the request has a previous_grant create a new grant
            # and link with the old grant
            previous_grant = self._request.previous_grant
            if previous_grant:
                self._request.resulting_grant = Grant.objects.create(
                    access=self._request.access,
                    granted_by=self._approver.username,
                    expires=expires_date,
                    previous_grant=previous_grant)
            else:
                # Else create the access if it does not already exist and
                # then create the new grant
                access, _ = Access.objects.get_or_create(
                    user=self._request.access.user,
                    role=self._request.access.role)
                self._request.resulting_grant = Grant.objects.create(
                    access=access,
                    granted_by=self._approver.username,
                    expires=expires_date)
            # Copy the metadata from the request to the grant
            self._request.copy_metadata_to(self._request.resulting_grant)
        else:
            self._request.state = RequestState.REJECTED
            self._request.incomplete = True if self.cleaned_data[
                'state'] == 'INCOMPLETE' else False
            self._request.user_reason = self.cleaned_data['user_reason']
            self._request.internal_reason = self.cleaned_data[
                'internal_reason']
        self._request.save()
        return self._request
Ejemplo n.º 16
0
class Tournament(models.Model):
    PLATFORM_STEAM = 'S'
    PLATFORM_BNET = 'B'
    PLATFORM_LEAGUE = 'L'
    PLATFORM_SWITCH = 'N'
    PLATFORM_XBOX = 'X'
    PLATFORM_PLAYSTATION = 'P'
    PLATFORM_OTHER = 'O'

    PLATFORM_CHOICES = ((PLATFORM_STEAM, 'Steam'),
                        (PLATFORM_BNET, 'Battle.NET'), (PLATFORM_LEAGUE,
                                                        'League of Legends'),
                        (PLATFORM_SWITCH, 'Nintendo Switch'), (PLATFORM_XBOX,
                                                               'Xbox Live'),
                        (PLATFORM_PLAYSTATION,
                         'Playstation Network'), (PLATFORM_OTHER, 'Other'))

    id = models.AutoField(primary_key=True)

    # Tournament display information
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True, help_text=markdown_allowed())
    start = models.DateTimeField(default=timezone.now)
    end = models.DateTimeField(default=timezone.now)

    platform = models.CharField(max_length=1,
                                choices=PLATFORM_CHOICES,
                                help_text='If \"other\" please specify')
    platform_other = models.CharField(max_length=64, blank=True)
    games = models.CharField(
        max_length=1024,
        blank=True,
        help_text=
        'A comma separated list of the game(s) played in this tournament')

    signup_start = models.DateTimeField(default=timezone.now)
    signup_end = models.DateTimeField(default=timezone.now)
    signup_limit = models.IntegerField(blank=True, null=True)

    # Associated event
    for_event = models.ForeignKey(Event,
                                  on_delete=models.CASCADE,
                                  blank=True,
                                  null=True)
    requires_attendance = models.BooleanField(default=False)

    # Routing
    slug = models.SlugField(max_length=40, unique=True)

    objects = TournamentManager()

    def __str__(self):
        return self.title

    @property
    def signups_open(self):
        return self.signup_start < timezone.now() <= self.signup_end

    @property
    def is_onging(self):
        return self.start <= timezone.now() < self.end

    @property
    def platform_verbose(self):
        return dict(Tournament.PLATFORM_CHOICES).get(self.platform).replace(
            'Other', self.platform_other)

    @property
    def platform_icon(self):
        return {
            Tournament.PLATFORM_STEAM: 'steam',
            Tournament.PLATFORM_BNET: 'battle-net',
            Tournament.PLATFORM_XBOX: 'xbox',
            Tournament.PLATFORM_PLAYSTATION: 'playstation',
            Tournament.PLATFORM_SWITCH: 'nintendo-switch'
        }.get(self.platform, None)

    @property
    def signup_count(self):
        return len(TournamentSignup.objects.all_for_tournament(self).all())

    @property
    def games_list(self):
        return list(map(lambda x: x.strip(), self.games.split(',')))

    @property
    def signups_remaining(self):
        return self.signup_limit - len(TournamentSignup.objects.all_for_tournament(self)) if self.signup_limit else \
            sys.maxsize

    @property
    def signups(self):
        signups = TournamentSignup.objects.filter(tournament=self, is_unsigned_up=False).exclude(comment__exact='')\
            .order_by('commented_at', '-created_at').all()

        return signups

    def user_signed_up(self, user):
        return TournamentSignup.objects.for_tournament(self, user).exists()

    def get_absolute_url(self):
        return '/events/tournament/{slug}'.format(slug=self.slug)
Ejemplo n.º 17
0
class Grant(HasMetadata):
    """
    Represents the granting of a role to a user.

    There may be many grants for each role/user combination. However, when
    determining whether a user is approved for a role, only the most recent
    grant for the role/user combination is considered. This is referred to as
    the 'active' grant.

    A grant can have arbitrary metadata associated with it. That metadata is
    defined by the service.
    """
    class Meta:
        ordering = (
            'role__service__category__position',
            'role__service__category__long_name',
            'role__service__position',
            'role__service__name',
            'role__position',
            'role__name',
            '-granted_at',
        )
        get_latest_by = 'granted_at'

    objects = GrantQuerySet.as_manager()

    #: The role that the grant is for
    role = models.ForeignKey(Role,
                             models.CASCADE,
                             related_name='grants',
                             related_query_name='grant')
    #: The user for whom the role is granted
    user = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)
    #: Username of the user who granted the role
    granted_by = models.CharField(max_length=200)
    #: The datetime at which the role was granted
    granted_at = models.DateTimeField(auto_now_add=True)
    #: The date that the the grant expires
    #:   * Access is assumed to expire at the **end** of the given day
    #:   * Default expiry is one year from now
    expires = models.DateField(default=_default_expiry,
                               verbose_name='expiry date')
    #: Indicates whether the grant has been revoked
    #: This overrides any expiry date
    revoked = models.BooleanField(default=False)
    #: If revoked, this is a reason for the user
    user_reason = models.TextField(blank=True,
                                   verbose_name='Reason for revocation (user)',
                                   help_text=markdown_allowed())
    #: Optional internal reason, for sensitive details
    internal_reason = models.TextField(
        blank=True,
        verbose_name='Reason for revocation (internal)',
        help_text=markdown_allowed())

    def __str__(self):
        return '{} : {}'.format(self.role, self.user)

    @property
    def active(self):
        """
        Returns ``True`` if this grant is the active grant for the
        service/role/user combination.
        """
        if not hasattr(self, '_active'):
            if self.pk:
                self._active = self.__class__.objects  \
                    .filter_active()  \
                    .filter(pk = self.pk)  \
                    .exists()
            else:
                # Unsaved grants are never active
                self._active = False
        return self._active

    @active.setter
    def active(self, value):
        self._active = value

    @property
    def expired(self):
        """
        Shortcut to check if a grant has expired.
        """
        return self.expires < date.today()

    @property
    def expiring(self):
        """
        Shortcut to check if a grant is expiring in the next 2 months.
        """
        today = date.today()
        return today <= self.expires < (today + relativedelta(months=2))

    def clean(self):
        errors = {}
        try:
            user = self.user
            # Ensure that the user is active
            if not user.is_active:
                errors['user'] = '******'
        except ObjectDoesNotExist:
            pass
        # Ensure that at least a user reason is given if the grant is revoked
        if self.revoked and not self.user_reason:
            errors['user_reason'] = 'Please give a reason'
        # Ensure that expires is in the future
        if self.expires < date.today():
            errors['expires'] = 'Expiry date must be in the future'
        if errors:
            raise ValidationError(errors)
Ejemplo n.º 18
0
class Request(HasMetadata):
    """
    Represents a request to grant a user a role.

    There may be many requests for each role/user combination. A request
    is considered 'active' if:

      1. It is the most recent request for the role/user combination
      2. It was requested after the active grant for the role/user combination

    A can be in one of three states: PENDING, REJECTED or APPROVED. A rejected
    request will have a reason to present to the user, and an approved request
    will have an associated grant.

    A request can have arbitrary metadata associated with it. That metadata is
    defined by the service.
    """
    class Meta:
        ordering = (
            'role__service__category__position',
            'role__service__category__long_name',
            'role__service__position',
            'role__service__name',
            'role__position',
            'role__name',
            '-requested_at',
        )
        get_latest_by = 'requested_at'
        permissions = (('decide_request', 'Can make decisions on requests'), )

    objects = RequestQuerySet.as_manager()

    #: The role that the request is for
    role = models.ForeignKey(Role,
                             models.CASCADE,
                             related_name='requests',
                             related_query_name='request')
    #: User for whom the role is being requested
    user = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE)
    #: Username of the user who requested the role
    requested_by = models.CharField(max_length=200)
    #: The datetime at which the service request was created
    requested_at = models.DateTimeField(auto_now_add=True)

    #: The current state of the request
    state = RequestState.model_field(default=RequestState.PENDING)
    #: If approved, this is the resulting access grant
    grant = models.OneToOneField(Grant,
                                 models.SET_NULL,
                                 null=True,
                                 blank=True,
                                 related_name='request')
    #: If rejected, this is a reason for the user
    user_reason = models.TextField(blank=True,
                                   verbose_name='Reason for rejection (user)',
                                   help_text=markdown_allowed())
    #: Optional internal reason, for sensitive details
    internal_reason = models.TextField(
        blank=True,
        verbose_name='Reason for rejection (internal)',
        help_text=markdown_allowed())

    def __str__(self):
        return '{} : {} : {}'.format(self.role, self.user, self.state)

    @property
    def active(self):
        """
        Returns ``True`` if this request is the active request for the
        service/role/user combination.
        """
        if not hasattr(self, '_active'):
            if self.pk:
                self._active = self.__class__.objects  \
                    .filter_active()  \
                    .filter(pk = self.pk)  \
                    .exists()
            else:
                # Unsaved grants are never active
                self._active = False
        return self._active

    @active.setter
    def active(self, value):
        self._active = value

    @property
    def pending(self):
        """
        ``True`` if the request is in the PENDING state, ``False`` otherwise.
        """
        return self.state == RequestState.PENDING

    @property
    def approved(self):
        """
        ``True`` if the request is in the APPROVED state, ``False`` otherwise.
        """
        return self.state == RequestState.APPROVED

    @property
    def rejected(self):
        """
        ``True`` if the request is in the REJECTED state, ``False`` otherwise.
        """
        return self.state == RequestState.REJECTED

    def clean(self):
        errors = {}
        # If we are approved, we need a grant
        if self.state == RequestState.APPROVED and not self.grant:
            errors['grant'] = 'Required for state {}'.format(self.state)
        # If we have a grant, we must be approved
        if self.grant and not self.state == RequestState.APPROVED:
            errors['grant'] = 'Not allowed for state {}'.format(self.state)
        # If the state is rejected, we need a user reason
        if self.state == RequestState.REJECTED and not self.user_reason:
            errors['user_reason'] = 'Please give a reason for rejection'
        try:
            user = self.user
            # Ensure that the user is active
            if not user.is_active:
                errors['user'] = '******'
        except ObjectDoesNotExist:
            pass
        # Check that the grant is for the same service/role/user combination
        if self.grant:
            if self.grant.role != self.role:
                errors['grant'] = 'Grant must be for same role as request'
            try:
                if self.grant.service != self.service:
                    errors[
                        'grant'] = 'Grant must be for same service as request'
                if self.grant.user != self.user:
                    errors['grant'] = 'Grant must be for same user as request'
            except ObjectDoesNotExist:
                pass
        if errors:
            raise ValidationError(errors)
Ejemplo n.º 19
0
class DecisionForm(forms.Form):
    """
    Form for making a decision on a request.
    """
    # Constants defining options for the quick expiry selection
    EXPIRES_SIX_MONTHS = 1
    EXPIRES_ONE_YEAR = 2
    EXPIRES_TWO_YEARS = 3
    EXPIRES_THREE_YEARS = 4
    EXPIRES_FIVE_YEARS = 5
    EXPIRES_TEN_YEARS = 6
    EXPIRES_CUSTOM = 7

    approved = forms.NullBooleanField(
        label='Decision',
        widget=forms.Select(
            choices=[(None, '---------'), (True,
                                           'APPROVED'), (False, 'REJECTED')]))
    expires = forms.TypedChoiceField(
        label='Expiry date',
        help_text=
        'Pick a duration from the dropdown list, or pick a custom expiry date',
        required=False,
        choices=[
            (0, '---------'),
            (EXPIRES_SIX_MONTHS, 'Six months from now'),
            (EXPIRES_ONE_YEAR, 'One year from now'),
            (EXPIRES_TWO_YEARS, 'Two years from now'),
            (EXPIRES_THREE_YEARS, 'Three years from now'),
            (EXPIRES_FIVE_YEARS, 'Five years from now'),
            (EXPIRES_TEN_YEARS, 'Ten years from now'),
            (EXPIRES_CUSTOM, 'Custom expiry date'),
        ],
        coerce=int,
        empty_value=0)
    expires_custom = forms.DateField(label='Custom expiry date',
                                     required=False,
                                     input_formats=['%Y-%m-%d', '%d/%m/%Y'],
                                     widget=forms.DateInput(
                                         format='%Y-%m-%d',
                                         attrs={'type': 'date'}))
    user_reason = forms.CharField(label='Reason for rejection (user)',
                                  required=False,
                                  widget=forms.Textarea(attrs={'rows': 5}),
                                  help_text=markdown_allowed())
    internal_reason = forms.CharField(label='Reason for rejection (internal)',
                                      required=False,
                                      widget=forms.Textarea(attrs={'rows': 5}),
                                      help_text=markdown_allowed())

    def __init__(self, request, approver, *args, **kwargs):
        self._request = request
        self._approver = approver
        super().__init__(*args, **kwargs)

    def clean_approved(self):
        approved = self.cleaned_data.get('approved')
        if approved is None:
            raise ValidationError('This field is required')
        return approved

    def clean_expires(self):
        approved = self.cleaned_data.get('approved')
        expires = self.cleaned_data.get('expires')
        if approved and not expires:
            raise ValidationError('Please give an expiry date for access')
        return expires

    def clean_expires_custom(self):
        approved = self.cleaned_data.get('approved')
        expires = self.cleaned_data.get('expires')
        expires_custom = self.cleaned_data.get('expires_custom')
        if approved and expires == self.EXPIRES_CUSTOM and not expires_custom:
            raise ValidationError('Please give an expiry date for access')
        if expires_custom and expires_custom < date.today():
            raise ValidationError('Expiry date must be in the future')
        return expires_custom

    def clean_user_reason(self):
        approved = self.cleaned_data.get('approved')
        user_reason = self.cleaned_data.get('user_reason')
        if approved is False and not user_reason:
            raise ValidationError('Please give a reason for rejection')
        return user_reason

    def save(self):
        # Update the request from the form
        if self.cleaned_data['approved']:
            # Get the expiry date
            expires = self.cleaned_data['expires']
            if expires == self.EXPIRES_SIX_MONTHS:
                expires_date = date.today() + relativedelta(months=6)
            elif expires == self.EXPIRES_ONE_YEAR:
                expires_date = date.today() + relativedelta(years=1)
            elif expires == self.EXPIRES_TWO_YEARS:
                expires_date = date.today() + relativedelta(years=2)
            elif expires == self.EXPIRES_THREE_YEARS:
                expires_date = date.today() + relativedelta(years=3)
            elif expires == self.EXPIRES_FIVE_YEARS:
                expires_date = date.today() + relativedelta(years=5)
            elif expires == self.EXPIRES_TEN_YEARS:
                expires_date = date.today() + relativedelta(years=10)
            else:
                expires_date = self.cleaned_data['expires_custom']
            self._request.state = RequestState.APPROVED
            # If the request was approved, create the grant
            self._request.grant = Grant.objects.create(
                role=self._request.role,
                user=self._request.user,
                granted_by=self._approver.username,
                expires=expires_date)
            # Copy the metadata from the request to the grant
            self._request.copy_metadata_to(self._request.grant)
        else:
            self._request.state = RequestState.REJECTED
            self._request.user_reason = self.cleaned_data['user_reason']
            self._request.internal_reason = self.cleaned_data[
                'internal_reason']
        self._request.save()
        return self._request
Ejemplo n.º 20
0
class Event(models.Model):
    SOCIETY_CHOICES = (
        ('UWCS', 'Uni of Warwick Computing Society'),
        ('WE', 'Warwick Esports'),
    )

    id = models.IntegerField(primary_key=True)

    # Event display information
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True, help_text=markdown_allowed())
    start = models.DateTimeField(default=timezone.now)
    end = models.DateTimeField(default=timezone.now)
    location = models.CharField(max_length=100)

    # Signup information
    signup_start = models.DateTimeField(default=timezone.now)
    signup_end = models.DateTimeField(default=timezone.now)
    signup_start_fresher = models.DateTimeField(blank=True, null=True)
    signup_limit = models.IntegerField(default=70)

    # Society eligibility criteria
    hosted_by = MultiSelectField(blank=True,
                                 choices=SOCIETY_CHOICES,
                                 max_choices=2)
    cost_member = models.DecimalField(default=0,
                                      decimal_places=2,
                                      max_digits=3)
    cost_non_member = models.DecimalField(default=5,
                                          decimal_places=2,
                                          max_digits=3)

    # Routing
    slug = models.SlugField(max_length=40, unique=True)

    # Seating plan
    has_seating = models.BooleanField(default=True)
    seating_location = models.ForeignKey(SeatingRoom,
                                         on_delete=models.PROTECT,
                                         blank=True,
                                         null=True)

    # Signup options
    has_photography = models.BooleanField(default=False)
    has_livestream = models.BooleanField(default=False)

    def __str__(self):
        return self.title

    def __bytes__(self):
        return bytes(self.title.encode()) + bytes(self.id) + bytes(
            str(self.start).encode())

    def get_absolute_url(self):
        return '/events/{slug}'.format(slug=self.slug)

    @property
    def signups(self):
        signups = EventSignup.objects.filter(
            event=self,
            is_unsigned_up=False).exclude(comment__exact='').order_by(
                'commented_at', '-created_at').all()

        return signups

    @property
    def signups_all(self):
        signups = EventSignup.objects.filter(
            event=self, is_unsigned_up=False).order_by('-created_at').all()

        return signups

    @property
    def signup_count(self):
        return len(self.signups_all)

    @property
    def signups_left(self):
        return self.signup_limit - self.signup_count

    def signup_start_for_user(self, user):
        if self.signup_start_fresher:
            if not user.is_authenticated:
                return self.signup_start
            else:
                profile = WarwickGGUser.objects.get(user=user)

                return self.signup_start_fresher if profile.is_fresher else self.signup_start
        else:
            return self.signup_start

    def signups_open(self, user):
        return self.signup_start_for_user(user) < timezone.now(
        ) <= self.signup_end and self.signup_count < self.signup_limit

    @property
    def is_ongoing(self):
        if self.start < timezone.now() <= self.end:
            return True
        else:
            return False
Ejemplo n.º 21
0
class Grant(HasMetadata):
    """
    Represents the granting of a role to a user.

    There may be many grants for each role/user combination. However, when
    determining whether a user is approved for a role, only grants the head of a
    grant chain (one without a next_grant) for the role/user combination is considered. 
    These are referred to as the 'active' grants.

    A grant can have arbitrary metadata associated with it. That metadata is
    defined by the service.
    """
    class Meta:
        ordering = (
            'access__role__service__category__position',
            'access__role__service__category__long_name',
            'access__role__service__position',
            'access__role__service__name',
            'access__role__position',
            'access__role__name',
            '-granted_at',
        )
        get_latest_by = 'granted_at'
        indexes = [models.Index(fields=['access', 'granted_at'])]

    objects = GrantQuerySet.as_manager()

    #: The role/user combination that the grant is for
    access = models.ForeignKey(Access,
                               models.CASCADE,
                               related_name='grants',
                               related_query_name='grant')
    #: Username of the user who granted the role
    granted_by = models.CharField(max_length=200)
    #: The datetime at which the role was granted
    granted_at = models.DateTimeField(auto_now_add=True)
    #: The date that the the grant expires
    #:   * Access is assumed to expire at the **end** of the given day
    #:   * Default expiry is one year from now
    expires = models.DateField(default=_default_expiry,
                               verbose_name='expiry date')
    #: Indicates whether the grant has been revoked
    #: This overrides any expiry date
    revoked = models.BooleanField(default=False)
    #: If revoked, this is a reason for the user
    user_reason = models.TextField(blank=True,
                                   verbose_name='Reason for revocation (user)',
                                   help_text=markdown_allowed())
    #: Optional internal reason, for sensitive details
    internal_reason = models.TextField(
        blank=True,
        verbose_name='Reason for revocation (internal)',
        help_text=markdown_allowed())
    #: Grant that this grant superceeds
    previous_grant = models.OneToOneField('self',
                                          models.SET_NULL,
                                          null=True,
                                          blank=True,
                                          related_name='next_grant')

    def __str__(self):
        if hasattr(self, 'next_grant'):
            return '{} : old'.format(self.access)
        else:
            return '{} : active'.format(self.access)

    @property
    def active(self):
        """
        Returns ``True`` if this grant is the active grant for the
        service/role/user combination.
        """
        if not hasattr(self, '_active'):
            if not hasattr(self, 'next_grant'):
                self._active = True
            else:
                # Unsaved grants are never active
                self._active = False
        return self._active

    @active.setter
    def active(self, value):
        self._active = value

    @property
    def expired(self):
        """
        Shortcut to check if a grant has expired.
        """
        return self.expires < date.today()

    @property
    def expiring(self):
        """
        Shortcut to check if a grant is expiring in the next 2 months.
        """
        today = date.today()
        return today <= self.expires < (today + relativedelta(months=2))

    def clean(self):
        errors = {}
        try:
            user = self.access.user
            # Ensure that the user is active
            if not user.is_active:
                errors['user'] = '******'
            if not settings.MULTIPLE_REQUESTS_ALLOWED:
                active_grant = Grant.objects.filter(access=self.access,
                                                    next_grant__isnull=True)
                active_request = Request.objects.filter(
                    access=self.access,
                    resulting_grant__isnull=True,
                    next_request__isnull=True)
                if self.active and active_grant and self.previous_grant != active_grant[
                        0] and self != active_grant[0]:
                    errors = 'There is already an existing active grant for this access'
                if self.active and active_request:
                    errors = 'There is already an existing active request for this access'

        except ObjectDoesNotExist:
            pass
        # Ensure that at least a user reason is given if the grant is revoked
        if self.revoked and not self.user_reason:
            errors['user_reason'] = 'Please give a reason'
        # Ensure that expires is in the future
        if self.expires < date.today():
            errors['expires'] = 'Expiry date must be in the future'
        if errors:
            raise ValidationError(errors)