class Medium(CreateModifyOn):
    project = models.ForeignKey(
        Project,
        help_text='Project that this medium belongs to',
        on_delete=models.PROTECT)
    received_date = models.DateField(
        help_text='Date that the medium was received')
    photographer = models.ForeignKey(
        PhysicalPerson,
        help_text='Person who took the photo/video',
        on_delete=models.PROTECT)
    license = models.ForeignKey(License,
                                help_text='License',
                                on_delete=models.PROTECT,
                                null=True,
                                blank=True)
    copyright = models.CharField(
        max_length=1024,
        help_text=
        'Owner of copyright if it is not the photographer (e.g. institution)',
        null=True,
        blank=True)
    file = models.FileField(storage=S3Boto3Storage(),
                            upload_to=medium_file_rename,
                            validators=[*management_file_validator()])
    file_md5 = models.CharField(max_length=32, null=True, blank=True)

    blog_posts = models.ManyToManyField(
        BlogPost,
        help_text='Which blog posts this image belongs to',
        blank=True)
    descriptive_text = models.TextField(
        help_text=
        'Description of this media, if provided. Where was it taken, context, etc.',
        null=True,
        blank=True)

    class Meta:
        verbose_name_plural = 'Media'

    def __str__(self):
        return f'{self.project}-{self.photographer}'

    def save(self, *args, **kwargs):
        self.file_md5 = calculate_md5_from_file_field(self.file)
        super().save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        with transaction.atomic():
            MediumDeleted.objects.create(**{'original_id': self.id})
            delete_result = super().delete(*args, **kwargs)

        return delete_result
Beispiel #2
0
class ProjectAttachment(AbstractAttachment):
    file = models.FileField(storage=S3Boto3Storage(),
                            upload_to=project_attachment_rename,
                            validators=[*management_file_validator()])
    project = models.ForeignKey(Project,
                                help_text='Project that this attachment belongs to',
                                on_delete=models.PROTECT)
    category = models.ForeignKey(ProjectAttachmentCategory, help_text='Category of the attachment',
                                 on_delete=models.PROTECT)

    def set_parent(self, parent):
        self.project = parent

    @staticmethod
    def category_queryset():
        return ProjectAttachmentCategory.objects.all()
Beispiel #3
0
class CallAttachment(AbstractAttachment):
    file = models.FileField(storage=S3Boto3Storage(),
                            upload_to=call_attachment_rename,
                            validators=[*management_file_validator()])
    call = models.ForeignKey(Call, help_text='Call that this attachment belongs to',
                             on_delete=models.PROTECT)
    category = models.ForeignKey(CallAttachmentCategory, help_text='Category of the attachment',
                                 on_delete=models.PROTECT)

    def __str__(self):
        return f'Call:{self.call.little_name()} Category:{self.category} File: {self.file.name}'

    def set_parent(self, parent):
        self.call = parent

    @staticmethod
    def category_queryset():
        return CallAttachmentCategory.objects.all()
Beispiel #4
0
class GrantAgreementAttachment(AbstractAttachment):
    file = models.FileField(storage=S3Boto3Storage(),
                            upload_to=grant_agreement_attachment_rename,
                            validators=[*management_file_validator()])
    grant_agreement = models.ForeignKey(GrantAgreement,
                                        help_text='GrantAgreement that this attachment belongs to',
                                        on_delete=models.PROTECT)
    category = models.ForeignKey(GrantAgreementAttachmentCategory, help_text='Category of the attachment',
                                 on_delete=models.PROTECT)

    class Meta:
        verbose_name_plural = 'Grant Agreement Attachments'

    def set_parent(self, parent):
        self.grant_agreement = parent

    @staticmethod
    def category_queryset():
        return GrantAgreementAttachmentCategory.objects.all()
class GrantAgreement(CreateModifyOn):
    project = models.OneToOneField(
        Project,
        help_text='Project this Grant Agreement belongs to',
        on_delete=models.PROTECT)
    signed_date = models.DateField(
        help_text='Date the grant agreement was signed', null=True, blank=True)
    signed_by = models.ManyToManyField(
        PhysicalPerson,
        help_text='People who signed the grant agreement',
        blank=True)
    file = models.FileField(storage=S3Boto3Storage(),
                            upload_to=grant_agreement_file_rename,
                            validators=[*management_file_validator()])

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

    def signed_by_string(self):
        return ', '.join([
            f'{person.first_name} {person.surname}'
            for person in self.signed_by.all().order_by('first_name')
        ])

    @staticmethod
    def comment_object():
        from comments.models import GrantAgreementComment
        return GrantAgreementComment

    @staticmethod
    def attachment_object():
        from comments.models import GrantAgreementAttachment
        return GrantAgreementAttachment

    def attachments(self):
        return self.grantagreementattachment_set.all().order_by('created_on')

    def comments(self):
        return self.grantagreementcomment_set.all().order_by('created_on')
class ScientificReport(AbstractProjectReport):
    file = models.FileField(storage=S3Boto3Storage(),
                            upload_to=scientific_report_file_rename,
                            validators=[*management_file_validator()],
                            blank=True,
                            null=True)
class Invoice(AbstractProjectDueReceivedDate):
    sent_for_payment_date = models.DateField(
        help_text='Date the invoice was sent for payment',
        null=True,
        blank=True)

    file = models.FileField(storage=S3Boto3Storage(),
                            upload_to=invoice_file_rename,
                            null=True,
                            validators=[*management_file_validator()],
                            blank=True)
    paid_date = models.DateField(help_text='Date the invoice was paid',
                                 null=True,
                                 blank=True)
    amount = models.DecimalField(max_digits=20,
                                 decimal_places=2,
                                 help_text='Total of the invoice (CHF)',
                                 null=True,
                                 blank=True)
    installment = models.ForeignKey(
        Installment,
        help_text='Installment to which the invoice is assigned',
        null=True,
        blank=True,
        on_delete=models.PROTECT)

    allow_overbudget = models.BooleanField(
        default=False, help_text='This invoice takes a payment overbudget')
    overbudget_allowed_by = models.ForeignKey(
        User,
        null=True,
        blank=True,
        help_text='User that allowed the overbudget',
        on_delete=models.PROTECT)

    def __str__(self):
        return f'Id: {self.id} Amount: {self.amount}'

    @staticmethod
    def comment_object():
        from comments.models import InvoiceComment
        return InvoiceComment

    @staticmethod
    def attachment_object():
        return None

    def installment_number(self):
        # This is not very efficient, but given the number of invoices and installments it's nice to not have to
        # save this in the database

        if self.installment is None:
            return None

        return self.installment.number()

    def due_date_passed(self):
        return self.due_date and self.due_date < datetime.today().date(
        ) and self.paid_date is None

    def comments(self):
        return self.invoicecomment_set.all().order_by('created_on')

    def attachments(self):
        return None
Beispiel #8
0
class Medium(CreateModifyOn):
    project = models.ForeignKey(
        Project,
        help_text='Project that this medium belongs to',
        on_delete=models.PROTECT)
    received_date = models.DateField(
        help_text='Date that the medium was received')
    photographer = models.ForeignKey(
        PhysicalPerson,
        help_text='Person who took the photo/video',
        on_delete=models.PROTECT)
    license = models.ForeignKey(License,
                                help_text='License',
                                on_delete=models.PROTECT,
                                null=True,
                                blank=True)
    copyright = models.CharField(
        max_length=1024,
        help_text=
        'Owner of copyright if it is not the photographer (e.g. institution)',
        null=True,
        blank=True)
    file = models.FileField(storage=S3Boto3Storage(),
                            upload_to=medium_file_rename,
                            validators=[*management_file_validator()])
    file_md5 = models.CharField(max_length=32, null=True, blank=True)
    file_web = models.FileField(storage=S3Boto3Storage(),
                                upload_to=medium_file_rename,
                                null=True)

    blog_posts = models.ManyToManyField(
        BlogPost,
        help_text='Which blog posts this image belongs to',
        blank=True)
    descriptive_text = models.TextField(
        help_text=
        'Description of this media, if provided. Where was it taken, context, etc.',
        null=True,
        blank=True)
    key_image = models.BooleanField(
        default=False,
        help_text="Select as a key image to be displayed on website")
    primary_image = models.BooleanField(
        default=False, help_text="Select as a primary image on website")

    class Meta:
        verbose_name_plural = 'Media'

    def __str__(self):
        return f'{self.project}-{self.photographer}'

    def save(self, *args, **kwargs):
        self.file_md5 = calculate_md5_from_file_field(self.file)
        # Be sure only one primary_image per project
        if self.primary_image:
            with transaction.atomic():
                Medium.objects.filter(
                    Q(primary_image=True)
                    & Q(project=self.project)).update(primary_image=False)
        if self.file.name.lower().endswith(tuple(['jpg', 'jpeg', 'png'])):
            try:
                im = Image.open(self.file)
                if im._getexif():
                    orientation = 0
                    for orientation in ExifTags.TAGS.keys():
                        if ExifTags.TAGS[orientation] == 'Orientation':
                            break
                    exif = dict(im._getexif().items())
                    if orientation in exif.keys():
                        if exif[orientation] == 3:
                            im = im.rotate(180, expand=True)
                        elif exif[orientation] == 6:
                            im = im.rotate(270, expand=True)
                        elif exif[orientation] == 8:
                            im = im.rotate(90, expand=True)
                out = BytesIO()
                if self.file.name.lower().endswith('png'):
                    im = im.convert('RGB')
                im.save(out, format='JPEG', quality=75)
                out.seek(0)
                self.file_web = InMemoryUploadedFile(
                    out, 'ImageField',
                    "%s_web.jpeg" % self.file.name.split('.')[0], 'image/jpeg',
                    sys.getsizeof(out), None)
            except (UnidentifiedImageError) as e:
                logger.warning(
                    f"Error: {e}; Can not save smaller image for web!")
        super().save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        with transaction.atomic():
            MediumDeleted.objects.create(**{'original_id': self.id})
            delete_result = super().delete(*args, **kwargs)

        return delete_result