class DeveloperApplication(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) email = models.EmailField(unique=True, validators=[validate_email]) phone_number = models.CharField(max_length=15) country = CountryField() city = models.CharField(max_length=50) stack = models.TextField() experience = models.TextField() discovery_story = models.TextField() status = models.PositiveSmallIntegerField( choices=APPLICATION_STATUS_CHOICES, help_text=','.join(['%s - %s' % (item[0], item[1]) for item in APPLICATION_STATUS_CHOICES]), default=REQUEST_STATUS_INITIAL ) created_at = models.DateTimeField(auto_now_add=True) confirmation_key = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) confirmation_sent_at = models.DateTimeField(blank=True, null=True, editable=False) used = models.BooleanField(default=False) used_at = models.DateTimeField(blank=True, null=True, editable=False) def __str__(self): return self.display_name @property def display_name(self): return '%s %s' % (self.first_name, self.last_name) @property def country_name(self): return self.country.name country_name.fget.short_description = 'country'
class BaseModel(TimetrackingBaseModel): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, verbose_name=_('BaseModel.id.verbose_name'), help_text=_('BaseModel.id.help_text')) user = models.ForeignKey( # "Owner" of this entry settings.AUTH_USER_MODEL, related_name='+', on_delete=models.CASCADE, editable=False, # Must be set automatically and never changed verbose_name=_('BaseModel.user.verbose_name'), help_text=_('BaseModel.user.help_text')) name = models.CharField(max_length=255, verbose_name=_('BaseModel.name.verbose_name'), help_text=_('BaseModel.name.help_text')) tags = tagulous.models.TagField( blank=True, case_sensitive=False, force_lowercase=False, space_delimiter=False, max_count=10, verbose_name=_('BaseModel.tags.verbose_name'), help_text=_('BaseModel.tags.help_text')) def __str__(self): return self.name class Meta: abstract = True
class DeveloperInvitation(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) email = models.EmailField(unique=True, validators=[validate_email]) type = models.IntegerField(choices=USER_TYPE_CHOICES, default=USER_TYPE_DEVELOPER) invitation_key = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) invitation_sent_at = models.DateTimeField(blank=True, null=True, editable=False) used = models.BooleanField(default=False) used_at = models.DateTimeField(blank=True, null=True, editable=False) resent = models.BooleanField(default=False) resent_at = models.DateTimeField(blank=True, null=True, editable=False) created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) class Meta: verbose_name = 'user invitation' def __unicode__(self): return self.display_name @property def display_name(self): return '%s %s' % (self.first_name, self.last_name)
class Questionnaire(models.Model): PHASE_CHOICES = ( (1, 'Phase-1'), (2, 'Phase-2'), (3, 'Phase-3'), (4, 'Phase-4'), ) identifier = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) name = models.CharField(max_length=500) phase = models.PositiveSmallIntegerField(choices=PHASE_CHOICES, default=1) root = models.BooleanField( default=False, help_text='Note that you cannot delete the root questionnaire.') def __str__(self): return self.name # TODO needed? (already enforced in forms.py) def save(self, force_insert=False, force_update=False, using=None, update_fields=None, *args, **kwargs): root_field = self.root if Questionnaire.objects.filter(root=True).exists(): invalid = False if self.pk is None: # if new questionnaire is being added if root_field is True: invalid = True else: # if existing questionnaire is being edited if Questionnaire.objects.get(root=True).pk != self.pk: if root_field is True: invalid = True if invalid: raise ValidationError('You already have a root questionnaire!') super(Questionnaire, self).save(force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields, *args, **kwargs) # TODO needed? (already enforced in admin.py) def delete(self, using=None, keep_parents=False): if self.root: raise ValidationError( 'You cannot delete a root question! Consider editing it instead.' ) super(Questionnaire, self).delete(using=using, keep_parents=keep_parents)
class Post(models.Model): POST_TYPE = ( (1, 'Article'), (2, 'Course'), (3, 'Job'), (4, 'Project'), ) identifier = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) slug = models.SlugField(unique=True, null=True, blank=True, max_length=512) type = models.PositiveSmallIntegerField(choices=POST_TYPE, default=1) tags = tagulous.models.TagField(related_name='posts', to=Tag, blank=True) author = models.ForeignKey('users.CustomUser', on_delete=models.CASCADE, related_name='blogs') title = models.CharField(max_length=255) body = BleachField() preview = models.CharField( max_length=300, help_text='A short preview of this post that is shown in list of posts.' ) likes = models.ManyToManyField('users.CustomUser', blank=True) allow_comments = models.BooleanField(default=True) def save(self, *args, **kwargs): self.slug = slugify(f'{self.title} {self.identifier}', allow_unicode=True) super(Post, self).save(*args, **kwargs) def __str__(self): return f'{self.title}, by {self.author.first_name} {self.author.last_name}' @property def likes_count(self): return self.likes.count() @property def relative_url(self): return reverse('blog-post', kwargs={'slug': self.slug}) def get_absolute_url(self): domain = Site.objects.get_current().domain protocol = "https" if settings.PRODUCTION_SERVER else "http" absolute_url = f'{protocol}://{domain}{self.relative_url}' return absolute_url
class Question(models.Model): identifier = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) body = models.CharField(max_length=1000) questionnaire = models.ForeignKey('Questionnaire', related_name='question', on_delete=models.CASCADE) multiselect = models.BooleanField(default=False) position = models.PositiveSmallIntegerField("position", null=True) class Meta: ordering = ['position'] def __str__(self): return self.body
class Option(models.Model): identifier = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) body = models.CharField(max_length=1000) question = models.ForeignKey('Question', related_name='option', on_delete=models.CASCADE) continuation_questionnaire = models.ForeignKey('Questionnaire', related_name='from_options', null=True, blank=True, on_delete=models.SET_NULL) tags = tagulous.models.TagField(related_name='options', to=Tag, blank=True) def clean(self): if self.continuation_questionnaire == self.question.questionnaire: raise ValidationError( 'Continuation questionnaire cannot point to the current one!') def __str__(self): return self.body
class InterestPoll(models.Model): status_choices = ((STATUS_INITIAL, 'Initial'), (STATUS_INTERESTED, 'Interested'), (STATUS_UNINTERESTED, 'Uninterested')) project = models.ForeignKey(Project, on_delete=models.CASCADE) user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='project_interest_polls', on_delete=models.DO_NOTHING) status = models.CharField(max_length=20, choices=status_choices, help_text=','.join([ '%s - %s' % (item[0], item[1]) for item in status_choices ]), default=STATUS_INITIAL) approval_status = models.CharField(max_length=20, choices=REQUEST_STATUS_CHOICES, help_text=','.join([ '%s - %s' % (item[0], item[1]) for item in REQUEST_STATUS_CHOICES ]), default=STATUS_INITIAL) created_by = models.ForeignKey( settings.AUTH_USER_MODEL, related_name='project_interest_polls_created') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) responded_at = models.DateTimeField(blank=True, null=True) sent_at = models.DateTimeField(blank=True, null=True) reminded_at = models.DateTimeField(blank=True, null=True) token = models.UUIDField(default=uuid.uuid4) def __str__(self): return '#{} | {} - {}'.format( self.id, self.user.get_short_name() or self.user.username, self.project.title) class Meta: unique_together = ('user', 'project') ordering = ['-created_at'] verbose_name = 'interest poll' verbose_name_plural = 'interest polls' def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if self.status != STATUS_INITIAL and self.responded_at is None: self.responded_at = datetime.datetime.utcnow() super(InterestPoll, self).save(force_insert=force_insert, force_update=force_update, using=using) @staticmethod @allow_staff_or_superuser def has_read_permission(request): return True @allow_staff_or_superuser def has_object_read_permission(self, request): return self.project.is_participant(request.user, active=False) @staticmethod @allow_staff_or_superuser def has_write_permission(request): return True @allow_staff_or_superuser def has_object_write_permission(self, request): allowed_users = [self.created_by, self.user, self.project.user] for user in [self.project.owner, self.project.pm]: if user: allowed_users.append(user) return request.user in allowed_users