Skip to content

Commit

Permalink
[DONE] Feature dressing video (#1006)
Browse files Browse the repository at this point in the history
* feature_dressing_video

* make lang

* flake

* unit test + pydoc

* Unit tests

* fix dark theme

* some fixes

* Create migrations/__init__.py

* fix encode when add watermark only

* fix

* Remove field site

* add tests for dressing utilities

* fix

* Replace css by bootstrap classes

* add table-sm

* Use path instead url

* fix

* fix flake

* remove id watermark

* fix

* fix flake

* fix

* fix panel admin

* fix flake

* [DONE] Patch elasticsearch options (#1009)

* Update configuration.json

* Update views.py

* Update utils.py

* Auto-update configuration files

* [DONE] Feature import external video, add mediacad platform (#1014)

* Add documentation about video platforms

* Add tests

* Add functions to manage import videos from Mediacad platform, and refactor some code

* Add functions to manage import videos from Mediacad platform; improved error message handling

* Add translations about Pod informations and Mediacad platform

* Modification of a test due to improved error message handling

* Add translations about Pod informations and Mediacad platform

* Add translations about Pod informations and Mediacad platform

* Change translation : Impossible to upload to Pod the video => Unable to upload the video to Pod; and remove fuzzy translations

* Add role='alert' to one error message

* Fixup. Format code with Black

* [DONE] Fix jsi18n (#1011)

* * Replace every `<script src="/admin/jsi18n/"></script>` by `<script id="jsi18n" src="{% url 'javascript-catalog' %}"></script>`
* Add js-catalog in theme_edit.html

* Add jsi18n in more scripts

* Add JS catalog in caption maker

* Remove every `javascript-catalog` as it is already in base.html

* rename i18njs as jsi18n

* Remove the "version" number in base html, as webpush also load it without version number and we do not want it to be downloaded twice.

* [WIP] Fix CSS z-index for audio enrichment slide to keep them over the sound wave element (#1013)

* Update views.py

* 🐛 Fix z-index in audio enrichment to keep enrichement slides over the sound wave element

---------

Co-authored-by: Ptitloup <nicolas.can@univ-lille.fr>

* Fixup. Format code with Prettier

* make lang

* some fixes

* fix lang

* improve test settigns to add use docker setting - default to true (#1019)

* Fixup. Format code with Black

* [DONE] WebTV - Add private field (#1016)

* init

* trad

* compil trad

* fix

* make lang

* some fixes

* fix

* fix

* [DONE] Feature import external video, add mediacad platform (#1014)

* Add documentation about video platforms

* Add tests

* Add functions to manage import videos from Mediacad platform, and refactor some code

* Add functions to manage import videos from Mediacad platform; improved error message handling

* Add translations about Pod informations and Mediacad platform

* Modification of a test due to improved error message handling

* Add translations about Pod informations and Mediacad platform

* Add translations about Pod informations and Mediacad platform

* Change translation : Impossible to upload to Pod the video => Unable to upload the video to Pod; and remove fuzzy translations

* Add role='alert' to one error message

* Fixup. Format code with Black

* make lang

* some fixes

* fix lang

* conflits lang

* compilemessages

* fix

* fix completion

* fix

* lang

* fix

* change Agreement required

---------

Co-authored-by: PierreC <heraknoshsdj@hotmail.fr>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Loïc Bonavent <56730254+LoicBonavent@users.noreply.github.com>
Co-authored-by: Olivier Bado-Faustin <bado@unice.fr>
Co-authored-by: gcondess <guillaume.condesse@u-bordeaux.fr>
Co-authored-by: Ptitloup <nicolas.can@univ-lille.fr>
  • Loading branch information
7 people authored Jan 17, 2024
1 parent 6eda22a commit e205b21
Show file tree
Hide file tree
Showing 38 changed files with 1,836 additions and 143 deletions.
16 changes: 12 additions & 4 deletions pod/completion/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,21 @@


class Contributor(models.Model):
"""Class for Contributor object."""

video = models.ForeignKey(Video, verbose_name=_("video"), on_delete=models.CASCADE)
name = models.CharField(_("lastname / firstname"), max_length=200)
email_address = models.EmailField(_("mail"), null=True, blank=True, default="")
name = models.CharField(
verbose_name=_("lastname / firstname"), max_length=200, default=""
)
email_address = models.EmailField(
verbose_name=_("mail"), null=True, blank=True, default=""
)
role = models.CharField(
_("role"), max_length=200, choices=ROLE_CHOICES, default="author"
verbose_name=_("role"), max_length=200, choices=ROLE_CHOICES, default="author"
)
weblink = models.URLField(
verbose_name=_("Web link"), max_length=200, null=True, blank=True
)
weblink = models.URLField(_("Web link"), max_length=200, null=True, blank=True)

class Meta:
verbose_name = _("Contributor")
Expand Down
Empty file added pod/dressing/__init__.py
Empty file.
50 changes: 50 additions & 0 deletions pod/dressing/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from django.contrib import admin
from .models import Dressing
from .forms import DressingAdminForm


class DressingAdmin(admin.ModelAdmin):
"""Dressing admin page."""

def get_form(self, request, obj=None, **kwargs):
ModelForm = super(DressingAdmin, self).get_form(request, obj, **kwargs)

class ModelFormMetaClass(ModelForm):
def __new__(cls, *args, **kwargs):
kwargs["request"] = request
return ModelForm(*args, **kwargs)

return ModelFormMetaClass

form = DressingAdminForm

list_display = (
"title",
"watermark",
"opacity",
"position",
"opening_credits",
"ending_credits"
)

autocomplete_fields = [
"opening_credits",
"ending_credits",
]

class Media:
css = {
"all": (
# "bootstrap/dist/css/bootstrap.min.css",
# "bootstrap/dist/css/bootstrap-grid.min.css",
# "css/pod.css",
)
}
js = (
"js/main.js",
"podfile/js/filewidget.js",
"bootstrap/dist/js/bootstrap.min.js",
)


admin.site.register(Dressing, DressingAdmin)
8 changes: 8 additions & 0 deletions pod/dressing/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _


class DressingConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'pod.dressing'
verbose_name = _("Video dressings")
150 changes: 150 additions & 0 deletions pod/dressing/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
from django import forms
from django.conf import settings
from pod.main.forms_utils import add_placeholder_and_asterisk
from django.contrib.sites.models import Site
from django_select2 import forms as s2forms
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _

from django.contrib import admin
from django.contrib.admin import widgets

from pod.video.models import Video
from .models import Dressing

__FILEPICKER__ = False
if getattr(settings, "USE_PODFILE", False):
__FILEPICKER__ = True
from pod.podfile.widgets import CustomFileWidget


class AddOwnerWidget(s2forms.ModelSelect2MultipleWidget):
"""Class AddOwnerWidget."""
search_fields = [
"username__icontains",
"email__icontains",
]


class AddAccessGroupWidget(s2forms.ModelSelect2MultipleWidget):
"""Class AddAccessGroupWidget."""
search_fields = [
"display_name__icontains",
"code_name__icontains",
]


class AddVideoHoldWidget(s2forms.ModelSelect2Widget):
"""Class AddVideoHoldWidget."""
search_fields = [
"slug__icontains",
"title__icontains"
]


class DressingForm(forms.ModelForm):
"""Form to add or edit a dressing."""
is_staff = True
is_superuser = False
admin_form = True

def __init__(self, *args, **kwargs):
"""Init method."""
self.is_staff = (
kwargs.pop("is_staff") if "is_staff" in kwargs.keys() else self.is_staff
)
self.is_superuser = (
kwargs.pop("is_superuser")
if ("is_superuser" in kwargs.keys())
else self.is_superuser
)
self.user = kwargs.pop("user", None)

super(DressingForm, self).__init__(*args, **kwargs)
if __FILEPICKER__:
self.fields["watermark"].widget = CustomFileWidget(type="image")
if not self.is_superuser or not hasattr(self, "admin_form"):
self.fields["owners"].queryset = self.fields["owners"].queryset.filter(
owner__sites=Site.objects.get_current()
)
self.fields["users"].queryset = self.fields["users"].queryset.filter(
owner__sites=Site.objects.get_current()
)
query_videos = Video.objects.filter(is_video=True).filter(
Q(owner=self.user) | Q(additional_owners__in=[self.user])
)
self.fields["opening_credits"].queryset = query_videos.all()
self.fields["ending_credits"].queryset = query_videos.all()

# change ckeditor config for no staff user
if not hasattr(self, "admin_form") and (
self.is_staff is False and self.is_superuser is False
):
del self.fields["watermark"]
# hide default langage
if self.fields.get("title_%s" % settings.LANGUAGE_CODE):
self.fields["title_%s" % settings.LANGUAGE_CODE].widget = forms.HiddenInput()

self.fields = add_placeholder_and_asterisk(self.fields)
self.fields["opacity"].widget.attrs.update({'max': '100'})
self.fields["owners"].initial = self.user

class Meta(object):
"""Meta class."""
model = Dressing
fields = "__all__"
exclude = ['videos']
widgets = {
"owners": AddOwnerWidget,
"users": AddOwnerWidget,
"allow_to_groups": AddAccessGroupWidget,
"opening_credits": AddVideoHoldWidget,
"ending_credits": AddVideoHoldWidget,
}


class DressingDeleteForm(forms.Form):
"""Form to delete a dressing."""
agree = forms.BooleanField(
label=_("I agree"),
help_text=_("Delete video dressing cannot be undone"),
widget=forms.CheckboxInput(),
)

def __init__(self, *args, **kwargs):
super(DressingDeleteForm, self).__init__(*args, **kwargs)
self.fields = add_placeholder_and_asterisk(self.fields)


class DressingAdminForm(forms.ModelForm):
"""Form for admin panel."""
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request", None)
super(DressingAdminForm, self).__init__(*args, **kwargs)
if __FILEPICKER__ and self.fields.get("watermark"):
self.fields["watermark"].widget = CustomFileWidget(type="image")

def clean(self):
super(DressingAdminForm, self).clean()

class Meta(object):
model = Dressing
fields = "__all__"
exclude = ['videos']
widgets = {
"owners": widgets.AutocompleteSelectMultiple(
Dressing._meta.get_field("owners"),
admin.site,
attrs={"style": "width: 20em"},
),
"users": widgets.AutocompleteSelectMultiple(
Dressing._meta.get_field("users"),
admin.site,
attrs={"style": "width: 20em"},
),
"allow_to_groups": widgets.AutocompleteSelectMultiple(
Dressing._meta.get_field("allow_to_groups"),
admin.site,
attrs={"style": "width: 20em"},
),
}
1 change: 1 addition & 0 deletions pod/dressing/migrations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

125 changes: 125 additions & 0 deletions pod/dressing/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"""Esup-Pod dressing models."""
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator

from django.contrib.auth.models import User
from pod.authentication.models import AccessGroup
from pod.podfile.models import CustomImageModel
from django.utils.translation import ugettext_lazy as _
from pod.video.models import Video


class Dressing(models.Model):
"""Class describing Dressing objects."""
TOP_RIGHT = 'top_right'
TOP_LEFT = 'top_left'
BOTTOM_RIGHT = 'bottom_right'
BOTTOM_LEFT = 'bottom_left'
POSITIONS = (
(TOP_RIGHT, _('Top right')),
(TOP_LEFT, _('Top left')),
(BOTTOM_RIGHT, _('Bottom right')),
(BOTTOM_LEFT, _('Bottom left')),
)

title = models.CharField(
_("Title"),
max_length=100,
unique=True,
help_text=_(
"Please choose a title as short and accurate as "
"possible, reflecting the main subject / context "
"of the content.(max length: 100 characters)"
),
)

owners = models.ManyToManyField(
User,
related_name="owners_dressing",
verbose_name=_("Owners"),
blank=True,
)

users = models.ManyToManyField(
User,
related_name="users_dressing",
verbose_name=_("Users"),
blank=True,
)

allow_to_groups = models.ManyToManyField(
AccessGroup,
blank=True,
verbose_name=_("Groups"),
help_text=_("Select one or more groups who can manage and use this video dressing."),
)

watermark = models.ForeignKey(
CustomImageModel,
models.SET_NULL,
blank=True,
null=True,
verbose_name=_("Watermark"),
)

position = models.CharField(
verbose_name=_("Position"),
max_length=200,
choices=POSITIONS,
default=TOP_RIGHT,
blank=True,
null=True,
)

opacity = models.PositiveIntegerField(
default=100,
validators=[MinValueValidator(1), MaxValueValidator(100)],
blank=True,
null=True,
verbose_name=_("Opacity"),
)

opening_credits = models.ForeignKey(
Video,
verbose_name=_("Opening credits"),
related_name="opening_credits",
on_delete=models.CASCADE,
null=True,
blank=True,
)

ending_credits = models.ForeignKey(
Video,
verbose_name=_("Ending credits"),
related_name="ending_credits",
on_delete=models.CASCADE,
null=True,
blank=True,
)

videos = models.ManyToManyField(
Video,
related_name="videos_dressing",
verbose_name=_("Videos"),
blank=True,
)

class Meta:
"""Metadata for Dressing model."""
verbose_name = _("Video dressing")
verbose_name_plural = _("Video dressings")

def to_json(self):
"""Convert to json format for encoding logs"""
return {
"id": self.id,
"title": self.title,
"owners": list(self.owners.values_list('id', flat=True)),
"users": list(self.users.values_list('id', flat=True)),
"allow_to_groups": list(self.allow_to_groups.values_list('id', flat=True)),
"watermark": self.watermark.file.url if self.watermark else None,
"position": self.get_position_display(),
"opacity": self.opacity,
"opening_credits": self.opening_credits.slug if self.opening_credits else None,
"ending_credits": self.ending_credits.slug if self.ending_credits else None,
}
Loading

0 comments on commit e205b21

Please sign in to comment.