Initial commit from ZIP
This commit is contained in:
commit
378d4692a9
454 files changed
+40367
No files matched your search
@@ -0,0 +1,11 @@
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class FinalPhotobriefingAppConfig(AppConfig):
|
||||
name = "outbo.apps.final_photobriefing"
|
||||
label = "final_photobriefing"
|
||||
verbose_name = _("Final photo briefing")
|
||||
|
||||
|
||||
default_app_config = "outbo.apps.final_photobriefing.FinalPhotobriefingAppConfig"
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@@ -0,0 +1,9 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class PhotoType(Enum):
|
||||
INVALID = "<invalid>"
|
||||
ARRANGEMENT_PHOTOS = "arrangement"
|
||||
CLIPPING = "clipping"
|
||||
PACKSHOT = "packshot"
|
||||
EXTRA_PHOTO = "extraPhoto"
|
||||
@@ -0,0 +1,49 @@
|
||||
# Generated by Django 2.2.8 on 2019-12-18 13:54
|
||||
|
||||
import rules.contrib.models
|
||||
from django.db import migrations, models
|
||||
|
||||
import outbo.apps.core.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="FinalBrief",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_at",
|
||||
outbo.apps.core.fields.CreationDateTimeField(
|
||||
auto_now_add=True, verbose_name="Created at"
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_at",
|
||||
outbo.apps.core.fields.ModificationDateTimeField(
|
||||
auto_now=True, verbose_name="Updated at"
|
||||
),
|
||||
),
|
||||
(
|
||||
"deleted_at",
|
||||
outbo.apps.core.fields.RemovalDateTimeField(
|
||||
blank=True, editable=False, null=True, verbose_name="Deleted at"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={"abstract": False,},
|
||||
bases=(rules.contrib.models.RulesModelMixin, models.Model),
|
||||
),
|
||||
]
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
# Generated by Django 2.2.8 on 2019-12-18 14:03
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("final_photobriefing", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(model_name="finalbrief", name="id",),
|
||||
]
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# Generated by Django 2.2.8 on 2019-12-18 14:03
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("photobriefing", "0001_initial"),
|
||||
("final_photobriefing", "0002_remove_finalbrief_id"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="finalbrief",
|
||||
name="brief",
|
||||
field=models.ForeignKey(
|
||||
default=0,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="photobriefing.Brief",
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 2.2.8 on 2019-12-18 14:05
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("final_photobriefing", "0003_finalbrief_brief"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="finalbrief",
|
||||
name="brief",
|
||||
field=models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="photobriefing.Brief",
|
||||
),
|
||||
),
|
||||
]
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 2.2.8 on 2019-12-18 14:06
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("final_photobriefing", "0004_auto_20191218_1505"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="finalbrief",
|
||||
name="brief",
|
||||
field=models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
primary_key=True,
|
||||
related_name="final",
|
||||
related_query_name="final",
|
||||
serialize=False,
|
||||
to="photobriefing.Brief",
|
||||
),
|
||||
),
|
||||
]
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# Generated by Django 2.2.8 on 2019-12-19 08:48
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import outbo.apps.core.fields
|
||||
import outbo.apps.final_photobriefing.enums
|
||||
import outbo.apps.final_photobriefing.models
|
||||
import rules.contrib.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("final_photobriefing", "0005_auto_20191218_1506"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="FinalBriefPhoto",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_at",
|
||||
outbo.apps.core.fields.CreationDateTimeField(
|
||||
auto_now_add=True, verbose_name="Created at"
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_at",
|
||||
outbo.apps.core.fields.ModificationDateTimeField(
|
||||
auto_now=True, verbose_name="Updated at"
|
||||
),
|
||||
),
|
||||
(
|
||||
"deleted_at",
|
||||
outbo.apps.core.fields.RemovalDateTimeField(
|
||||
blank=True, editable=False, null=True, verbose_name="Deleted at"
|
||||
),
|
||||
),
|
||||
(
|
||||
"file",
|
||||
models.FileField(
|
||||
upload_to=outbo.apps.final_photobriefing.models.FormatFinalPhotoBriefPhotoFilename()
|
||||
),
|
||||
),
|
||||
(
|
||||
"category",
|
||||
models.CharField(
|
||||
choices=[
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType(
|
||||
"<invalid>"
|
||||
),
|
||||
"<invalid>",
|
||||
),
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType(
|
||||
"arrangement"
|
||||
),
|
||||
"arrangement",
|
||||
),
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType(
|
||||
"clipping"
|
||||
),
|
||||
"clipping",
|
||||
),
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType(
|
||||
"packshot"
|
||||
),
|
||||
"packshot",
|
||||
),
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType(
|
||||
"extraPhoto"
|
||||
),
|
||||
"extraPhoto",
|
||||
),
|
||||
],
|
||||
max_length=30,
|
||||
),
|
||||
),
|
||||
(
|
||||
"brief",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="final_photobriefing.FinalBrief",
|
||||
),
|
||||
),
|
||||
],
|
||||
bases=(rules.contrib.models.RulesModelMixin, models.Model),
|
||||
),
|
||||
]
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Generated by Django 2.2.8 on 2019-12-20 10:14
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import outbo.apps.final_photobriefing.enums
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("final_photobriefing", "0006_finalbriefphoto"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(model_name="finalbriefphoto", name="category",),
|
||||
migrations.AddField(
|
||||
model_name="finalbriefphoto",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType("<invalid>"),
|
||||
"<invalid>",
|
||||
),
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType("arrangement"),
|
||||
"arrangement",
|
||||
),
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType("clipping"),
|
||||
"clipping",
|
||||
),
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType("packshot"),
|
||||
"packshot",
|
||||
),
|
||||
(
|
||||
outbo.apps.final_photobriefing.enums.PhotoType("extraPhoto"),
|
||||
"extraPhoto",
|
||||
),
|
||||
],
|
||||
default=outbo.apps.final_photobriefing.enums.PhotoType("<invalid>"),
|
||||
max_length=30,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="finalbriefphoto",
|
||||
name="brief",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="photos",
|
||||
related_query_name="photo",
|
||||
to="final_photobriefing.FinalBrief",
|
||||
),
|
||||
),
|
||||
]
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 2.2.10 on 2020-05-25 08:25
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("final_photobriefing", "0007_auto_20191220_1114"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="finalbrief",
|
||||
name="brief",
|
||||
field=models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
primary_key=True,
|
||||
related_name="final",
|
||||
related_query_name="final",
|
||||
serialize=False,
|
||||
to="photobriefing.Brief",
|
||||
),
|
||||
),
|
||||
]
|
||||
Whitespace-only changes.
+63
@@ -0,0 +1,63 @@
|
||||
import os
|
||||
|
||||
from django.db import models
|
||||
from django.utils.deconstruct import deconstructible
|
||||
from rules.contrib.models import RulesModel
|
||||
|
||||
from outbo.apps.core.models import TimestampableDeletableMixin
|
||||
from outbo.apps.final_photobriefing import rules
|
||||
from outbo.apps.final_photobriefing.enums import PhotoType
|
||||
|
||||
|
||||
@deconstructible
|
||||
class FormatFinalPhotoBriefPhotoFilename:
|
||||
def __call__(self, instance, filename):
|
||||
obj = instance.brief.brief
|
||||
return "/".join(
|
||||
("projects", obj.product.project.slug[1:], "final-photobriefing", filename)
|
||||
)
|
||||
|
||||
|
||||
class FinalBrief(TimestampableDeletableMixin, RulesModel):
|
||||
class Meta:
|
||||
rules_permissions = {
|
||||
"add": rules.can_create_final_brief,
|
||||
"view": rules.can_read_final_brief,
|
||||
"change": rules.can_update_final_brief,
|
||||
"delete": rules.can_delete_final_brief,
|
||||
}
|
||||
|
||||
brief = models.OneToOneField(
|
||||
to="photobriefing.Brief",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="final",
|
||||
related_query_name="final",
|
||||
primary_key=True,
|
||||
)
|
||||
|
||||
|
||||
class FinalBriefPhoto(TimestampableDeletableMixin, RulesModel):
|
||||
class Meta:
|
||||
rules_permissions = {
|
||||
"add": rules.can_create_final_brief_photo,
|
||||
"view": rules.can_read_final_brief_photo,
|
||||
"change": rules.can_update_final_brief_photo,
|
||||
"delete": rules.can_delete_final_brief_photo,
|
||||
}
|
||||
|
||||
brief = models.ForeignKey(
|
||||
to=FinalBrief,
|
||||
on_delete=models.CASCADE,
|
||||
related_query_name="photo",
|
||||
related_name="photos",
|
||||
)
|
||||
file = models.FileField(upload_to=FormatFinalPhotoBriefPhotoFilename())
|
||||
type = models.CharField(
|
||||
max_length=30,
|
||||
choices=[(type, type.value) for type in PhotoType],
|
||||
default=PhotoType.INVALID,
|
||||
)
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
return os.path.basename(self.file.name)
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
from rules import always_deny, always_allow
|
||||
|
||||
from outbo.apps.core.rules import is_agency
|
||||
|
||||
can_create_final_brief = always_deny
|
||||
can_read_final_brief = always_allow
|
||||
can_update_final_brief = is_agency
|
||||
can_delete_final_brief = always_deny
|
||||
|
||||
can_create_final_brief_photo = always_deny
|
||||
can_read_final_brief_photo = always_allow
|
||||
can_update_final_brief_photo = is_agency
|
||||
can_delete_final_brief_photo = is_agency
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
from rest_framework_extensions.routers import ExtendedSimpleRouter
|
||||
|
||||
from outbo.apps.final_photobriefing.viewsets import (
|
||||
FinalBriefViewSet,
|
||||
FinalBriefPhotoViewSet,
|
||||
)
|
||||
|
||||
app_name = "final_photobriefing"
|
||||
router = ExtendedSimpleRouter()
|
||||
router.register(prefix="final-photobriefing", viewset=FinalBriefViewSet)
|
||||
router.register(prefix="final-photobriefing-photo", viewset=FinalBriefPhotoViewSet)
|
||||
|
||||
urlpatterns = router.urls
|
||||
@@ -0,0 +1,99 @@
|
||||
from django.http import HttpResponseRedirect
|
||||
from rest_framework import serializers
|
||||
from rest_framework.permissions import AllowAny
|
||||
|
||||
from outbo.apps.core.viewsets import (
|
||||
AutoPermissionViewSetMixin,
|
||||
RetrieveModelMixin,
|
||||
MultipleSerializerViewSet,
|
||||
PartialUpdateModelMixin,
|
||||
DestroyModelMixin,
|
||||
)
|
||||
from outbo.apps.final_photobriefing.enums import PhotoType
|
||||
from outbo.apps.final_photobriefing.models import FinalBrief, FinalBriefPhoto
|
||||
|
||||
|
||||
class FinalBriefPhotoSerializer:
|
||||
class List(serializers.ModelSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(
|
||||
view_name="final_photobriefing:finalbriefphoto-detail"
|
||||
)
|
||||
type = serializers.SerializerMethodField()
|
||||
filename = serializers.ReadOnlyField()
|
||||
|
||||
class Meta:
|
||||
model = FinalBriefPhoto
|
||||
fields = ["url", "type", "filename"]
|
||||
|
||||
def get_type(self, instance):
|
||||
t, val = instance.type.split(".", 1)
|
||||
return PhotoType[val].value
|
||||
|
||||
class Create(serializers.ModelSerializer):
|
||||
type = serializers.CharField()
|
||||
|
||||
class Meta:
|
||||
model = FinalBriefPhoto
|
||||
fields = ["type", "file"]
|
||||
|
||||
def validate_type(self, value):
|
||||
try:
|
||||
return PhotoType(value)
|
||||
except ValueError:
|
||||
raise serializers.ValidationError("Invalid photo type value")
|
||||
|
||||
|
||||
class BaseFinalBriefSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = FinalBrief
|
||||
|
||||
|
||||
class FinalBriefSerializer:
|
||||
class Retrieve(BaseFinalBriefSerializer):
|
||||
photos = FinalBriefPhotoSerializer.List(many=True)
|
||||
|
||||
class Meta(BaseFinalBriefSerializer.Meta):
|
||||
fields = ["photos", "created_at", "updated_at"]
|
||||
|
||||
class Update(BaseFinalBriefSerializer):
|
||||
photos = FinalBriefPhotoSerializer.Create(many=True)
|
||||
|
||||
class Meta(BaseFinalBriefSerializer.Meta):
|
||||
fields = ["photos"]
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
photos = validated_data.pop("photos", None)
|
||||
if photos is not None:
|
||||
for photo in photos:
|
||||
FinalBriefPhoto.objects.create(brief=instance, **photo)
|
||||
return instance
|
||||
|
||||
|
||||
class FinalBriefViewSet(
|
||||
AutoPermissionViewSetMixin,
|
||||
RetrieveModelMixin,
|
||||
PartialUpdateModelMixin,
|
||||
MultipleSerializerViewSet,
|
||||
):
|
||||
queryset = FinalBrief.objects.all()
|
||||
serializer_class_set = FinalBriefSerializer
|
||||
|
||||
|
||||
class FinalBriefPhotoViewSet(
|
||||
AutoPermissionViewSetMixin,
|
||||
RetrieveModelMixin,
|
||||
DestroyModelMixin,
|
||||
MultipleSerializerViewSet,
|
||||
):
|
||||
queryset = FinalBriefPhoto.objects.all()
|
||||
serializer_class_set = FinalBriefPhotoSerializer
|
||||
retrieve_permission_classes = [AllowAny]
|
||||
|
||||
def get_permissions(self):
|
||||
if self.action == "retrieve":
|
||||
return [permission() for permission in self.retrieve_permission_classes]
|
||||
return super().get_permissions()
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
photo = self.get_object()
|
||||
return HttpResponseRedirect(redirect_to=photo.file.url)
|
||||
Reference in new issue
Block a user