Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DONE] Feature dressing video #1006

Merged
merged 56 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
e1d96cd
feature_dressing_video
vsabatie Nov 23, 2023
2d86e0a
make lang
vsabatie Nov 23, 2023
4e3fd61
flake
vsabatie Nov 23, 2023
02a598a
unit test + pydoc
vsabatie Nov 27, 2023
3f8b4fd
Unit tests
vsabatie Nov 27, 2023
3548cfb
fix dark theme
vsabatie Nov 28, 2023
64cf9d9
some fixes
vsabatie Nov 30, 2023
5e8c259
Create migrations/__init__.py
vsabatie Dec 1, 2023
754b6d4
fix encode when add watermark only
vsabatie Dec 1, 2023
9487421
fix
vsabatie Dec 4, 2023
830e479
Remove field site
vsabatie Dec 4, 2023
c2094cc
add tests for dressing utilities
vsabatie Dec 4, 2023
817369d
fix
vsabatie Dec 4, 2023
4d17b82
Replace css by bootstrap classes
vsabatie Dec 5, 2023
8068b2c
add table-sm
vsabatie Dec 5, 2023
32d2005
Use path instead url
vsabatie Dec 5, 2023
a973973
fix
vsabatie Dec 5, 2023
3578ad7
fix flake
vsabatie Dec 5, 2023
b4ae3c4
remove id watermark
vsabatie Dec 5, 2023
5f4a163
fix
vsabatie Dec 12, 2023
e2a9e2b
fix flake
vsabatie Dec 12, 2023
0ca9f5a
fix
vsabatie Jan 8, 2024
07dc9e5
fix panel admin
vsabatie Jan 9, 2024
6a514b7
fix flake
vsabatie Jan 9, 2024
d01d349
[DONE] Patch elasticsearch options (#1009)
CartierPierre Dec 18, 2023
5c5153d
Auto-update configuration files
invalid-email-address Dec 18, 2023
36bef46
[DONE] Feature import external video, add mediacad platform (#1014)
LoicBonavent Dec 18, 2023
660234c
Fixup. Format code with Black
invalid-email-address Dec 18, 2023
b8e837e
[DONE] Fix jsi18n (#1011)
Badatos Jan 4, 2024
016d562
[WIP] Fix CSS z-index for audio enrichment slide to keep them over th…
gcondess Jan 9, 2024
f9e21c9
Fixup. Format code with Prettier
invalid-email-address Jan 9, 2024
1188c8b
make lang
vsabatie Nov 23, 2023
ae8bfe5
some fixes
vsabatie Nov 30, 2023
b13a8c4
fix lang
vsabatie Jan 9, 2024
72931d0
Merge branch 'develop' into feature_dressing_video
vsabatie Jan 9, 2024
26d8632
improve test settigns to add use docker setting - default to true (#1…
ptitloup Jan 11, 2024
dbf4d8d
Fixup. Format code with Black
invalid-email-address Jan 11, 2024
7d3aa29
[DONE] WebTV - Add private field (#1016)
vsabatie Jan 15, 2024
c3dc7db
make lang
vsabatie Nov 23, 2023
cb0cf0c
some fixes
vsabatie Nov 30, 2023
6042cfb
fix
vsabatie Dec 4, 2023
4be42d0
fix
vsabatie Dec 4, 2023
7e52579
[DONE] Feature import external video, add mediacad platform (#1014)
LoicBonavent Dec 18, 2023
d0ea93d
Fixup. Format code with Black
invalid-email-address Dec 18, 2023
80f1de3
make lang
vsabatie Nov 23, 2023
2f69514
some fixes
vsabatie Nov 30, 2023
b247c4a
fix lang
vsabatie Jan 9, 2024
1403439
conflits lang
vsabatie Jan 16, 2024
cfee71d
compilemessages
vsabatie Jan 16, 2024
070e4ea
Squashed commit of the following:
vsabatie Jan 16, 2024
9deb2d2
fix
vsabatie Jan 16, 2024
7567780
fix completion
vsabatie Jan 16, 2024
873b6cb
fix
vsabatie Jan 16, 2024
3477fa1
lang
vsabatie Jan 16, 2024
1837a16
fix
vsabatie Jan 17, 2024
21c7d4e
change Agreement required
vsabatie Jan 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added pod/dressing/__init__.py
Empty file.
34 changes: 34 additions & 0 deletions pod/dressing/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from django.contrib import admin
from .models import Dressing
from .forms import DressingForm


class DressingAdmin(admin.ModelAdmin):
"""Dressing admin page."""
form = DressingForm
list_display = ("title", "watermark", "opacity", "position",
"opening_credits", "ending_credits")
autocomplete_fields = [
"owners",
"users",
"allow_to_groups",
"opening_credits",
"ending_credits",
]

class Media:
css = {
"all": (
# "bootstrap/dist/css/bootstrap.min.css",
# "bootstrap/dist/css/bootstrap-grid.min.css",
# "css/pod.css",
vsabatie marked this conversation as resolved.
Show resolved Hide resolved
)
}
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'
vsabatie marked this conversation as resolved.
Show resolved Hide resolved
verbose_name = _("Video dressings")
114 changes: 114 additions & 0 deletions pod/dressing/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
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 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()
)

# 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'})
vsabatie marked this conversation as resolved.
Show resolved Hide resolved
self.fields["owners"].initial = self.user

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()

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)
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 upload video to this channel."),
vsabatie marked this conversation as resolved.
Show resolved Hide resolved
)

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

position = models.CharField(
verbose_name=_("position"),
max_length=200,
vsabatie marked this conversation as resolved.
Show resolved Hide resolved
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,
}
31 changes: 31 additions & 0 deletions pod/dressing/static/css/video_dressing.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
margin-bottom: 10px;
text-align: center;
}

th, td {
padding: 10px;
border: 1px solid #ccc;
}

th {
background-color: #f2f2f2;
}

tr:nth-child(even) {
background-color: #f9f9f9;
}

[data-theme="dark"] tr:nth-child(even), [data-theme="dark"] th {
background-color: var(--pod-background-neutre1-bloc-dark)
}

#watermark {
max-width: 50px;
height: auto;
display: block;
margin: auto;
}
55 changes: 55 additions & 0 deletions pod/dressing/static/js/video_dressing.js
vsabatie marked this conversation as resolved.
Show resolved Hide resolved
vsabatie marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @file Esup-Pod functions for the dressing form.
vsabatie marked this conversation as resolved.
Show resolved Hide resolved
* @since 3.5.0
*/

/**
* Get the opacity and position fields
*/
let opacityField = document.getElementById('id_opacity');
let positionField = document.getElementById('id_position');
let watermarkField = document.getElementById('id_watermark');

/**
* Manage field state when modifying watermark field
*/
function handleWatermarkChange() {
if (watermarkField.value !== '') {
opacityField.disabled = false;
positionField.disabled = false;
} else {
opacityField.disabled = true;
positionField.disabled = true;
}
};

/**
* Disable opacity and position fields on page load
*/
handleWatermarkChange();

/**
* Create a mutation observer
*/
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName === 'value') {
handleWatermarkChange();
}
});
});

/**
* Observe the mutations of the "value" attribute of the watermark field
*/
observer.observe(watermarkField, { attributes: true });

/**
* Deselect all radio input buttons
*/
function resetRadioButtons() {
const radioButtons = document.querySelectorAll('#apply_dressing input[type="radio"]');
radioButtons.forEach(button => {
button.checked = false;
});
}
Loading