mirror of
https://github.com/ae-utbm/sith.git
synced 2026-04-24 12:13:11 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9c5297473 | |||
| 52117b5a24 | |||
| ae72a2e00f |
+5
-24
@@ -1,22 +1,16 @@
|
|||||||
from pathlib import Path
|
from typing import Any
|
||||||
from typing import TYPE_CHECKING, Any
|
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from PIL import Image
|
|
||||||
|
|
||||||
from core.models import User
|
from core.models import User
|
||||||
from core.utils import resize_image
|
|
||||||
from core.views import MultipleImageField
|
from core.views import MultipleImageField
|
||||||
from core.views.forms import SelectDate
|
from core.views.forms import SelectDate
|
||||||
from core.views.widgets.ajax_select import AutoCompleteSelectMultipleGroup
|
from core.views.widgets.ajax_select import AutoCompleteSelectMultipleGroup
|
||||||
from sas.models import Album, Picture, PictureModerationRequest
|
from sas.models import Album, Picture, PictureModerationRequest
|
||||||
from sas.widgets.ajax_select import AutoCompleteSelectAlbum
|
from sas.widgets.ajax_select import AutoCompleteSelectAlbum
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from django.db.models.fields.files import FieldFile
|
|
||||||
|
|
||||||
|
|
||||||
class AlbumCreateForm(forms.ModelForm):
|
class AlbumCreateForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -55,30 +49,17 @@ class AlbumEditForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Album
|
model = Album
|
||||||
fields = ["name", "date", "file", "parent", "edit_groups"]
|
fields = ["name", "date", "file", "parent", "edit_groups"]
|
||||||
widgets = {"edit_groups": AutoCompleteSelectMultipleGroup, "date": SelectDate}
|
widgets = {
|
||||||
|
"edit_groups": AutoCompleteSelectMultipleGroup,
|
||||||
|
}
|
||||||
|
|
||||||
name = forms.CharField(max_length=Album.NAME_MAX_LENGTH, label=_("file name"))
|
name = forms.CharField(max_length=Album.NAME_MAX_LENGTH, label=_("file name"))
|
||||||
|
date = forms.DateField(label=_("Date"), widget=SelectDate, required=True)
|
||||||
recursive = forms.BooleanField(label=_("Apply rights recursively"), required=False)
|
recursive = forms.BooleanField(label=_("Apply rights recursively"), required=False)
|
||||||
parent = forms.ModelChoiceField(
|
parent = forms.ModelChoiceField(
|
||||||
Album.objects.all(), required=True, widget=AutoCompleteSelectAlbum
|
Album.objects.all(), required=True, widget=AutoCompleteSelectAlbum
|
||||||
)
|
)
|
||||||
|
|
||||||
def clean_file(self):
|
|
||||||
# if a file was given in the form, resize it
|
|
||||||
f: FieldFile = self.cleaned_data["file"]
|
|
||||||
if self.errors or not f or "file" not in self.changed_data:
|
|
||||||
return f
|
|
||||||
f.file = resize_image(Image.open(f.file), 200, "WEBP")
|
|
||||||
return f
|
|
||||||
|
|
||||||
def save(self, commit=True): # noqa: FBT002
|
|
||||||
if self.instance.file:
|
|
||||||
self.instance.file.name = str(Path(self.instance.name) / "thumb.webp")
|
|
||||||
self.instance = super().save(commit=commit)
|
|
||||||
if not self.instance.file:
|
|
||||||
self.instance.generate_thumbnail()
|
|
||||||
return self.instance
|
|
||||||
|
|
||||||
|
|
||||||
class PictureModerationRequestForm(forms.ModelForm):
|
class PictureModerationRequestForm(forms.ModelForm):
|
||||||
"""Form to create a PictureModerationRequest.
|
"""Form to create a PictureModerationRequest.
|
||||||
|
|||||||
+10
-4
@@ -110,7 +110,7 @@ class Picture(SasFile):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("sas:picture", kwargs={"picture_id": self.id})
|
return reverse("sas:picture", kwargs={"picture_id": self.id})
|
||||||
|
|
||||||
def generate_thumbnails(self):
|
def generate_thumbnails(self, *, overwrite=False):
|
||||||
im = Image.open(BytesIO(self.file.read()))
|
im = Image.open(BytesIO(self.file.read()))
|
||||||
with contextlib.suppress(Exception):
|
with contextlib.suppress(Exception):
|
||||||
im = exif_auto_rotate(im)
|
im = exif_auto_rotate(im)
|
||||||
@@ -126,6 +126,10 @@ class Picture(SasFile):
|
|||||||
file = resize_image(im, max(im.size), extension, optimize=False)
|
file = resize_image(im, max(im.size), extension, optimize=False)
|
||||||
thumb = resize_image(im, 200, "webp")
|
thumb = resize_image(im, 200, "webp")
|
||||||
compressed = resize_image(im, 1200, "webp")
|
compressed = resize_image(im, 1200, "webp")
|
||||||
|
if overwrite:
|
||||||
|
self.file.delete()
|
||||||
|
self.thumbnail.delete()
|
||||||
|
self.compressed.delete()
|
||||||
new_extension_name = str(Path(self.name).with_suffix(".webp"))
|
new_extension_name = str(Path(self.name).with_suffix(".webp"))
|
||||||
self.file = file
|
self.file = file
|
||||||
self.file.name = self.name
|
self.file.name = self.name
|
||||||
@@ -241,15 +245,17 @@ class Album(SasFile):
|
|||||||
return reverse("sas:album_preview", kwargs={"album_id": self.id})
|
return reverse("sas:album_preview", kwargs={"album_id": self.id})
|
||||||
|
|
||||||
def generate_thumbnail(self):
|
def generate_thumbnail(self):
|
||||||
p = self.children_pictures.order_by("?").first() or (
|
p = (
|
||||||
self.children_albums.exclude(Q(file=None) | Q(file=""))
|
self.children_pictures.order_by("?").first()
|
||||||
|
or self.children_albums.exclude(file=None)
|
||||||
|
.exclude(file="")
|
||||||
.order_by("?")
|
.order_by("?")
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
if p and p.file:
|
if p and p.file:
|
||||||
image = resize_image(Image.open(BytesIO(p.file.read())), 200, "webp")
|
image = resize_image(Image.open(BytesIO(p.file.read())), 200, "webp")
|
||||||
self.file = image
|
self.file = image
|
||||||
self.file.name = str(Path(self.name) / "thumb.webp")
|
self.file.name = f"{self.name}/thumb.webp"
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@
|
|||||||
--loading-size: 20px
|
--loading-size: 20px
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
@media (min-width: 700px) and (max-width: 1000px) {
|
||||||
max-width: calc(50% - 5px);
|
max-width: calc(50% - 5px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,57 +201,52 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.general {
|
#pict .general {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: 20px;
|
gap: 3em;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
|
gap: 1em;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
>.infos {
|
.infos, .tools {
|
||||||
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 50%;
|
gap: .5em;
|
||||||
|
@media (min-width: 700px) {
|
||||||
|
max-width: 350px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.infos > div, .tools > div > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: .35em;
|
||||||
|
}
|
||||||
|
|
||||||
>div>div {
|
.tools > div, >.infos >div>div {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
>*:first-child {
|
|
||||||
min-width: 150px;
|
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
min-width: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
>.tools {
|
>.tools {
|
||||||
display: flex;
|
flex: 1;
|
||||||
flex-direction: column;
|
|
||||||
width: 50%;
|
|
||||||
|
|
||||||
>div {
|
>div>div {
|
||||||
display: flex;
|
>a.btn {
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
>div {
|
|
||||||
>a.button {
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: $primary-neutral-light-color;
|
background-color: $primary-neutral-light-color;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 10px;
|
padding: 0;
|
||||||
color: black;
|
color: black;
|
||||||
border-radius: 5px;
|
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
font-size: 20px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #aaa;
|
background-color: #aaa;
|
||||||
@@ -268,9 +263,9 @@
|
|||||||
|
|
||||||
&.buttons {
|
&.buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@@ -2,19 +2,19 @@
|
|||||||
<a href="{{ url('sas:album', album_id=a.id) }}">
|
<a href="{{ url('sas:album', album_id=a.id) }}">
|
||||||
{% if a.file %}
|
{% if a.file %}
|
||||||
{% set img = a.get_download_url() %}
|
{% set img = a.get_download_url() %}
|
||||||
{% set alt = a.name %}
|
{% set src = a.name %}
|
||||||
{% elif a.children.filter(is_folder=False, is_moderated=True).exists() %}
|
{% elif a.children.filter(is_folder=False, is_moderated=True).exists() %}
|
||||||
{% set picture = a.children.filter(is_folder=False).first().as_picture %}
|
{% set picture = a.children.filter(is_folder=False).first().as_picture %}
|
||||||
{% set img = picture.get_download_thumb_url() %}
|
{% set img = picture.get_download_thumb_url() %}
|
||||||
{% set alt = picture.name %}
|
{% set src = picture.name %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% set img = static('core/img/sas.jpg') %}
|
{% set img = static('core/img/sas.jpg') %}
|
||||||
{% set alt = "sas.jpg" %}
|
{% set src = "sas.jpg" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div
|
<div
|
||||||
class="album{% if not a.is_moderated %} not_moderated{% endif %}"
|
class="album{% if not a.is_moderated %} not_moderated{% endif %}"
|
||||||
>
|
>
|
||||||
<img src="{{ img }}" alt="{{ alt }}" loading="lazy" />
|
<img src="{{ img }}" alt="{{ src }}" loading="lazy" />
|
||||||
{% if not a.is_moderated %}
|
{% if not a.is_moderated %}
|
||||||
<div class="overlay"> </div>
|
<div class="overlay"> </div>
|
||||||
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
|
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
|
||||||
|
|||||||
@@ -12,6 +12,17 @@
|
|||||||
{% trans %}See all the photos taken during events organised by the AE.{% endtrans %}
|
{% trans %}See all the photos taken during events organised by the AE.{% endtrans %}
|
||||||
{%- endblock %}
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block metatags %}
|
||||||
|
<meta property="og:url" content="{{ request.build_absolute_uri() }}" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content="Stock à souvenirs" />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="Retrouvez toutes les photos prises durant les événements organisés par l'AE."
|
||||||
|
/>
|
||||||
|
<meta property="og:image" content="{{ request.build_absolute_uri(static("core/img/logo_no_text.png")) }}" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% set is_sas_admin = user.is_root or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID) %}
|
{% set is_sas_admin = user.is_root or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID) %}
|
||||||
|
|
||||||
{% from "sas/macros.jinja" import display_album %}
|
{% from "sas/macros.jinja" import display_album %}
|
||||||
|
|||||||
@@ -118,15 +118,20 @@
|
|||||||
<a class="text" :href="currentPicture.full_size_url">
|
<a class="text" :href="currentPicture.full_size_url">
|
||||||
{% trans %}HD version{% endtrans %}
|
{% trans %}HD version{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
<br>
|
|
||||||
<a class="text danger " :href="currentPicture.report_url">
|
<a class="text danger " :href="currentPicture.report_url">
|
||||||
{% trans %}Ask for removal{% endtrans %}
|
{% trans %}Ask for removal{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<a class="button" :href="currentPicture.edit_url"><i class="fa-regular fa-pen-to-square edit-action"></i></a>
|
<a
|
||||||
<a class="button" href="?rotate_left"><i class="fa-solid fa-rotate-left"></i></a>
|
class="btn btn-no-text"
|
||||||
<a class="button" href="?rotate_right"><i class="fa-solid fa-rotate-right"></i></a>
|
:href="currentPicture.edit_url"
|
||||||
|
x-show="{{ user.has_perm("sas.change_sasfile")|tojson }} || currentPicture.owner.id === {{ user.id }}"
|
||||||
|
>
|
||||||
|
<i class="fa-regular fa-pen-to-square edit-action"></i>
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-no-text" href="?rotate_left"><i class="fa-solid fa-rotate-left"></i></a>
|
||||||
|
<a class="btn btn-no-text" href="?rotate_right"><i class="fa-solid fa-rotate-right"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+3
-3
@@ -16,7 +16,6 @@ from typing import Any
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
from django.core.exceptions import PermissionDenied
|
|
||||||
from django.db.models import Count, OuterRef, Subquery
|
from django.db.models import Count, OuterRef, Subquery
|
||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
@@ -153,8 +152,9 @@ class AlbumView(CanViewMixin, UseFragmentsMixin, DetailView):
|
|||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
if not request.user.can_edit(self.object):
|
if not self.object.file:
|
||||||
raise PermissionDenied
|
self.object.generate_thumbnail()
|
||||||
|
if request.user.can_edit(self.object): # Handle the copy-paste functions
|
||||||
FileView.handle_clipboard(request, self.object)
|
FileView.handle_clipboard(request, self.object)
|
||||||
return HttpResponseRedirect(self.request.path)
|
return HttpResponseRedirect(self.request.path)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user