Changeset View
Changeset View
Standalone View
Standalone View
static_assets/models/static_assets.py
- This file was moved from assets/models/assets.py.
| from typing import Optional | from typing import Optional | ||||
| from django.contrib.auth.models import User | from django.contrib.auth.models import User | ||||
| from django.core.exceptions import ValidationError | from django.core.exceptions import ValidationError | ||||
| from django.core.files.storage import FileSystemStorage | from django.core.files.storage import FileSystemStorage | ||||
| from django.db import models | from django.db import models | ||||
| from django.db.models import FileField | from django.db.models import FileField | ||||
| from django.db.models.fields.files import FieldFile | from django.db.models.fields.files import FieldFile | ||||
| from storages.backends.gcloud import GoogleCloudStorage | from storages.backends.gcloud import GoogleCloudStorage | ||||
| from assets.models import License, StorageLocation, StorageLocationCategoryChoices | from static_assets.models import License, StorageLocation, StorageLocationCategoryChoices | ||||
| from common import mixins | from common import mixins | ||||
| from common.upload_paths import get_upload_to_hashed_path | from common.upload_paths import get_upload_to_hashed_path | ||||
| class AssetFileTypeChoices(models.TextChoices): | class StaticAssetFileTypeChoices(models.TextChoices): | ||||
| file = 'file', 'File' | file = 'file', 'File' | ||||
| image = 'image', 'Image' | image = 'image', 'Image' | ||||
| video = 'video', 'Video' | video = 'video', 'Video' | ||||
| class DynamicStorageFieldFile(FieldFile): | class DynamicStorageFieldFile(FieldFile): | ||||
| def __init__(self, instance: models.Model, field: FileField, name: Optional[str]): | def __init__(self, instance: models.Model, field: FileField, name: Optional[str]): | ||||
| super(DynamicStorageFieldFile, self).__init__(instance, field, name) | super(DynamicStorageFieldFile, self).__init__(instance, field, name) | ||||
| Show All 28 Lines | def pre_save(self, model_instance: models.Model, add: bool) -> FieldFile: | ||||
| storage = FileSystemStorage() | storage = FileSystemStorage() | ||||
| self.storage = storage | self.storage = storage | ||||
| file: FieldFile = super(DynamicStorageFileField, self).pre_save(model_instance, add) | file: FieldFile = super(DynamicStorageFileField, self).pre_save(model_instance, add) | ||||
| return file | return file | ||||
| class StaticAsset(mixins.CreatedUpdatedMixin, models.Model): | class StaticAsset(mixins.CreatedUpdatedMixin, models.Model): | ||||
| source = DynamicStorageFileField(upload_to=get_upload_to_hashed_path) | source = DynamicStorageFileField(upload_to=get_upload_to_hashed_path) | ||||
| source_type = models.CharField(choices=AssetFileTypeChoices.choices, max_length=5) | source_type = models.CharField(choices=StaticAssetFileTypeChoices.choices, max_length=5) | ||||
| # TODO(Natalia): source type validation | # TODO(Natalia): source type validation | ||||
| original_filename = models.CharField(max_length=128, editable=False) | original_filename = models.CharField(max_length=128, editable=False) | ||||
| size_bytes = models.BigIntegerField(editable=False) | size_bytes = models.BigIntegerField(editable=False) | ||||
| user = models.ForeignKey(User, on_delete=models.PROTECT, related_name='uploaded_assets') | user = models.ForeignKey(User, on_delete=models.PROTECT, related_name='uploaded_assets') | ||||
| user.description = "The user who uploaded the asset." | user.description = "The user who uploaded the asset." | ||||
| author = models.ForeignKey( | author = models.ForeignKey( | ||||
| User, blank=True, null=True, on_delete=models.PROTECT, related_name='authored_assets' | User, blank=True, null=True, on_delete=models.PROTECT, related_name='authored_assets' | ||||
| ) | ) | ||||
| author.description = "The actual author of the artwork/learning materials." | author.description = "The actual author of the artwork/learning materials." | ||||
| license = models.ForeignKey( | license = models.ForeignKey( | ||||
| License, null=True, on_delete=models.SET_NULL, related_name='assets' | License, null=True, on_delete=models.SET_NULL, related_name='static_assets' | ||||
| ) | ) | ||||
| storage_location = models.ForeignKey( | storage_location = models.ForeignKey( | ||||
| StorageLocation, on_delete=models.CASCADE, related_name='assets' | StorageLocation, on_delete=models.CASCADE, related_name='static_assets' | ||||
| ) | ) | ||||
| source_preview = DynamicStorageFileField(upload_to=get_upload_to_hashed_path, blank=True) | source_preview = DynamicStorageFileField(upload_to=get_upload_to_hashed_path, blank=True) | ||||
| source_preview.description = ( | source_preview.description = ( | ||||
| "Asset preview is auto-generated for images and videos. Required for other files." | "Asset preview is auto-generated for images and videos. Required for other files." | ||||
| ) | ) | ||||
| # TODO(Natalia): generate preview if source_preview not uploaded. | # TODO(Natalia): generate preview if source_preview not uploaded. | ||||
| @property | @property | ||||
| def preview(self): | def preview(self): | ||||
| if self.source_preview: | if self.source_preview: | ||||
| return self.source_preview | return self.source_preview | ||||
| if self.source_type == AssetFileTypeChoices.image: | if self.source_type == StaticAssetFileTypeChoices.image: | ||||
| return self.source | return self.source | ||||
| # TODO(Natalia): Update this once we have auto-generated previews. | # TODO(Natalia): Update this once we have auto-generated previews. | ||||
| @property | @property | ||||
| def author_name(self) -> str: | def author_name(self) -> str: | ||||
| """Get the asset's author full name. | """Get the asset's author full name. | ||||
| Usually the author of the asset will be the same as the user who uploads the asset.""" | Usually the author of the asset will be the same as the user who uploads the asset.""" | ||||
| if self.author: | if self.author: | ||||
| return self.author.get_full_name() | return self.author.get_full_name() | ||||
| return self.user.get_full_name() | return self.user.get_full_name() | ||||
| def clean(self): | def clean(self): | ||||
| super().clean() | super().clean() | ||||
| if self.source: | if self.source: | ||||
| # The `if` prevents an unhandled exception if one tries to save without a source | # The `if` prevents an unhandled exception if one tries to save without a source | ||||
| self.original_filename = self.source.file.name | self.original_filename = self.source.file.name | ||||
| self.size_bytes = self.source.size | self.size_bytes = self.source.size | ||||
| if self.source_type == AssetFileTypeChoices.file and not self.source_preview: | if self.source_type == StaticAssetFileTypeChoices.file and not self.source_preview: | ||||
| raise ValidationError( | raise ValidationError( | ||||
| f'Source preview has to be provided for `{AssetFileTypeChoices.file}` source type.' | f'Source preview has to be provided for `{StaticAssetFileTypeChoices.file}` source type.' | ||||
| ) | ) | ||||
| def __str__(self): | def __str__(self): | ||||
| return f'{self.source_type} {self.original_filename}' | return f'{self.source_type} {self.original_filename}' | ||||
| class Video(mixins.CreatedUpdatedMixin, models.Model): | class Video(mixins.CreatedUpdatedMixin, models.Model): | ||||
| static_asset = models.OneToOneField(StaticAsset, on_delete=models.CASCADE) | static_asset = models.OneToOneField(StaticAsset, on_delete=models.CASCADE) | ||||
| Show All 20 Lines | |||||