Mise à jour de mars (#586)

---------

Co-authored-by: Thomas Girod <thgirod@hotmail.com>
Co-authored-by: Théo DURR <git@theodurr.fr>
This commit is contained in:
Julien Constant
2023-04-04 19:17:44 +02:00
committed by GitHub
parent 982fc09908
commit 4830c3ea2d
125 changed files with 4978 additions and 3243 deletions

View File

@ -1,23 +1,15 @@
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
# You can find the source code of the website at https://github.com/ae-utbm/sith3
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#

View File

@ -1,24 +1,16 @@
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
# You can find the source code of the website at https://github.com/ae-utbm/sith3
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#

View File

@ -1,24 +1,16 @@
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
# You can find the source code of the website at https://github.com/ae-utbm/sith3
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#
@ -69,7 +61,6 @@ class Picture(SithFile):
im = Image.open(BytesIO(f.read()))
(w, h) = im.size
return (w / h) < 1
return False
def can_be_edited_by(self, user):
return user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID)
@ -79,11 +70,20 @@ class Picture(SithFile):
# Result is cached 4s for this user
if user.is_anonymous:
return False
perm = cache.get("%d_can_view_pictures" % (user.id), False)
if perm:
# use cache only when user is in SAS Admins or when picture is moderated
if perm and (self.is_moderated or self.can_be_edited_by(user)):
return perm
perm = self.is_in_sas and self.is_moderated and user.was_subscribed
perm = (
self.is_in_sas
and (self.is_moderated or self.can_be_edited_by(user))
and user.was_subscribed
)
cache.set("%d_can_view_pictures" % (user.id), perm, timeout=4)
return perm
def get_download_url(self):

View File

@ -1,202 +1,248 @@
{% extends "core/base.jinja" %}
{% from "core/macros.jinja" import paginate %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('sas/album.scss') }}">
{%- endblock -%}
{% block title %}
{% trans %}SAS{% endtrans %}
{% trans %}SAS{% endtrans %}
{% endblock %}
{% macro print_path(file) %}
{% if file and file.parent %}
{{ print_path(file.parent) }}
<a href="{{ url('sas:album', album_id=file.id) }}">{{ file.get_display_name() }}</a> >
{% endif %}
{% if file and file.parent %}
{{ print_path(file.parent) }}
<a href="{{ url('sas:album', album_id=file.id) }}">{{ file.get_display_name() }}</a> /
{% endif %}
{% endmacro %}
{% block content %}
<a href="{{ url('sas:main') }}">SAS</a> > {{ print_path(album.parent) }} {{ album.get_display_name() }}
<h3>{{ album.get_display_name() }}</h3>
<a href="{{ url('sas:album_edit', album_id=album.id) }}">{% trans %}Edit{% endtrans %}</a><br>
{% set start = timezone.now() %}
<hr>
{% set edit_mode = user.can_edit(album) %}
{% if edit_mode %}
<form action="" method="post" enctype="multipart/form-data" style="width: 100%;">
{% csrf_token %}
<p>
<input name="delete" type="submit" value="{% trans %}Delete{% endtrans %}"> |
<input name="clear" type="submit" value="{% trans %}Clear clipboard{% endtrans %}"> |
<input name="cut" type="submit" value="{% trans %}Cut{% endtrans %}"> |
<input name="paste" type="submit" value="{% trans %}Paste{% endtrans %}">
</p>
{% if clipboard %}
<p>{% trans %}Clipboard: {% endtrans %}
<ul>
{% for f in clipboard %}
<li>{{ f.get_full_path() }}</li>
{% endfor %}
</ul>
</p>
{% endif %}
{% endif %}
<div>
{% for a in album.children_albums.order_by('-date') %}
<div style="display: inline-block;">
{% if edit_mode %}
<input type="checkbox" name="file_list" value="{{ a.id }}">
{% endif %}
{% if user.can_view(a) %}
<a href="{{ url("sas:album", album_id=a.id) }}" style="display: inline-block">
<div class="album{% if not a.is_moderated %} not_moderated{% endif %}">
<div>
{% if a.file %}
<img src="{{ a.get_download_url() }}" alt="{% trans %}preview{% endtrans %}">
{% else %}
<img src="{{ static('core/img/sas.jpg') }}" alt="{% trans %}preview{% endtrans %}">
{% endif %}
<code>
<a href="{{ url('sas:main') }}">SAS</a> / {{ print_path(album.parent) }} {{ album.get_display_name() }}
</code>
{% set edit_mode = user.can_edit(album) %}
{% set start = timezone.now() %}
{% if edit_mode %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="navbar">
<h3>{{ album.get_display_name() }}</h3>
<div class="toolbar">
<a href="{{ url('sas:album_edit', album_id=album.id) }}">{% trans %}Edit{% endtrans %}</a>
<input name="delete" type="submit" value="{% trans %}Delete{% endtrans %}">
<input name="cut" type="submit" value="{% trans %}Cut{% endtrans %}">
<input {% if not clipboard %}disabled{% endif %} name="paste" type="submit" value="{% trans %}Paste{% endtrans %}">
</div>
</div>
{{ a.name }}
{% if clipboard %}
<div class="clipboard">
{% trans %}Clipboard: {% endtrans %}
<ul>
{% for f in clipboard %}
<li>{{ f.get_full_path() }}</li>
{% endfor %}
</ul>
<input name="clear" type="submit" value="{% trans %}Clear clipboard{% endtrans %}">
</div>
{% endif %}
{% endif %}
{% if album.children_albums.count() > 0 %}
<h4>{% trans %}Albums{% endtrans %}</h4>
<div class="albums">
{% for a in album.children_albums.order_by('-date') %}
{% if a.can_be_viewed_by(user) %}
<a href="{{ url('sas:album', album_id=a.id) }}">
<div
class="album{% if not a.is_moderated %} not_moderated{% endif %}"
style="background-image: url('{% if a.file %}{{ a.get_download_url() }}{% else %}{{ static('core/img/sas.jpg') }}{% endif %}');"
>
{% if not a.is_moderated %}
<div class="overlay">&nbsp;</div>
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
{% else %}
<div class="text">{{ a.name }}</div>
{% endif %}
</div>
{% if edit_mode %}
<input type="checkbox" name="file_list" value="{{ a.id }}">
{% endif %}
</a>
{% endif %}
{% endfor %}
</div>
</a>
{% endif %}
<br>
{% endif %}
<h4>{% trans %}Pictures{% endtrans %}</h4>
{% if pictures | length != 0 %}
<div class="photos">
{% for p in pictures %}
{% if p.can_be_viewed_by(user) %}
<a href="{{ url('sas:picture', picture_id=p.id) }}#pict">
<div
class="photo"
style="background-image: url('{{ p.get_download_thumb_url() }}')"
>
{% if not p.is_moderated %}
<div class="overlay">&nbsp;</div>
<div class="text">{% trans %}To be moderated{% endtrans %}</div>
{% else %}
<div class="text">&nbsp;</div>
{% endif %}
</div>
{% if edit_mode %}
<input type="checkbox" name="file_list" value="{{ p.id }}">
{% endif %}
</a>
{% endif %}
{% endfor %}
</div>
{% endfor %}
</div>
<div>
{% for p in pictures %}
<div style="display: inline-block;">
{% if edit_mode %}
<input type="checkbox" name="file_list" value="{{ p.id }}">
{% endif %}
{% if user.can_view(p) %}
<div class="picture{% if not p.is_moderated %} not_moderated{% endif %}">
<a href="{{ url("sas:picture", picture_id=p.id) }}#pict">
<img src="{{ p.get_download_thumb_url() }}" alt="{{ p.get_display_name() }}" />
</a>
{% else %}
{% trans %}This album does not contain any photos.{% endtrans %}
{% endif %}
{% if pictures.has_previous() or pictures.has_next() %}
<div class="paginator">
{{ paginate(pictures, paginator) }}
</div>
{% endif %}
</div>
{% endfor %}
</div>
<br>
{{ paginate(pictures, paginator) }}
{% if edit_mode %}
</form>
{% endif %}
<form id="upload_form" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p() }}
<p><input type="submit" value="{% trans %}Upload{% endtrans %}" /></p>
</form>
<p style="font-size: small; color: #444;">{% trans %}Template generation time: {% endtrans %}
{{ timezone.now() - start }}
</p>
{% endif %}
{% if edit_mode %}
</form>
{% endif %}
{% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %}
<form class="add-files" id="upload_form" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="inputs">
{{ form.as_p() }}
<input type="submit" value="{% trans %}Upload{% endtrans %}" />
</div>
</form>
{% endif %}
<hr>
<p style="font-size: small; color: #444;">{% trans %}Template generation time: {% endtrans %}
{{ timezone.now() - start }}
</p>
{% endblock %}
{% block script %}
{{ super() }}
<script>
$("form#upload_form").submit(function (event) {
var formData = new FormData($(this)[0]);
{{ super() }}
<script>
$("form#upload_form").submit(function (event) {
let formData = new FormData($(this)[0]);
if(!formData.get('album_name') && !formData.get('images').name)
return false;
if(!formData.get('album_name') && !formData.get('images').name)
return false;
if(!formData.get('images').name) {
return true;
}
event.preventDefault();
var errorlist;
if((errorlist = this.querySelector('#upload_form ul.errorlist.nonfield')) === null) {
errorlist = document.createElement('ul');
errorlist.classList.add('errorlist', 'nonfield');
this.insertBefore(errorlist, this.firstElementChild);
}
while(errorlist.childElementCount > 0)
errorlist.removeChild(errorlist.firstElementChild);
var progress;
if((progress = this.querySelector('progress')) === null) {
progress = document.createElement('progress');
progress.value = 0;
var p = document.createElement('p');
p.appendChild(progress);
this.insertBefore(p, this.lastElementChild);
}
var dataHolder;
if(formData.get('album_name')) {
dataHolder = new FormData();
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
dataHolder.set('album_name', formData.get('album_name'));
$.ajax({
method: 'POST',
url: "{{ url('sas:album_upload', album_id=object.id) }}",
data: dataHolder,
processData: false,
contentType: false,
success: onSuccess
});
}
var images = formData.getAll('images');
var imagesCount = images.length;
var completeCount = 0;
var poolSize = 1;
var imagePool = [];
while(images.length > 0 && imagePool.length < poolSize) {
var image = images.shift();
imagePool.push(image);
sendImage(image);
}
function sendImage(image) {
dataHolder = new FormData();
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
dataHolder.set('images', image);
$.ajax({
method: 'POST',
url: "{{ url('sas:album_upload', album_id=object.id) }}",
data: dataHolder,
processData: false,
contentType: false,
})
.fail(onSuccess.bind(undefined, image))
.done(onSuccess.bind(undefined, image))
.always(next.bind(undefined, image));
}
function next(image, status, jqXHR) {
var index;
if(index = imagePool.indexOf(image) !== -1) {
imagePool.splice(index, 1);
if(!formData.get('images').name) {
return true;
}
var nextImage;
if(nextImage = images.shift()) {
imagePool.push(nextImage);
sendImage(nextImage);
event.preventDefault();
let errorList;
if((errorList = this.querySelector('#upload_form ul.errorlist.nonfield')) === null) {
errorList = document.createElement('ul');
errorList.classList.add('errorlist', 'nonfield');
this.insertBefore(errorList, this.firstElementChild);
}
}
function onSuccess(image, data, status, jqXHR) {
if ($(data.responseText).find('.errorlist.nonfield')[0])
var errors = Array.from($(data.responseText).find('.errorlist.nonfield')[0].children);
else
var errors = []
while(errors.length > 0)
errorlist.appendChild(errors.shift());
progress.value = ++completeCount / imagesCount;
if(progress.value === 1 && errorlist.children.length === 0)
document.location.reload(true)
}
});
</script>
while(errorList.childElementCount > 0)
errorList.removeChild(errorList.firstElementChild);
let progress;
if((progress = this.querySelector('progress')) === null) {
progress = document.createElement('progress');
progress.value = 0;
let p = document.createElement('p');
p.appendChild(progress);
this.insertBefore(p, this.lastElementChild);
}
let dataHolder;
if(formData.get('album_name')) {
dataHolder = new FormData();
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
dataHolder.set('album_name', formData.get('album_name'));
$.ajax({
method: 'POST',
url: "{{ url('sas:album_upload', album_id=object.id) }}",
data: dataHolder,
processData: false,
contentType: false,
success: onSuccess
});
}
let images = formData.getAll('images');
let imagesCount = images.length;
let completeCount = 0;
let poolSize = 1;
let imagePool = [];
while(images.length > 0 && imagePool.length < poolSize) {
let image = images.shift();
imagePool.push(image);
sendImage(image);
}
function sendImage(image) {
dataHolder = new FormData();
dataHolder.set('csrfmiddlewaretoken', '{{ csrf_token }}');
dataHolder.set('images', image);
$.ajax({
method: 'POST',
url: "{{ url('sas:album_upload', album_id=object.id) }}",
data: dataHolder,
processData: false,
contentType: false,
})
.fail(onSuccess.bind(undefined, image))
.done(onSuccess.bind(undefined, image))
.always(next.bind(undefined, image));
}
function next(image, _, __) {
let index = imagePool.indexOf(image);
let nextImage = images.shift();
if(index !== -1)
imagePool.splice(index, 1);
if(nextImage) {
imagePool.push(nextImage);
sendImage(nextImage);
}
}
function onSuccess(image, data, _, __) {
let errors = [];
if ($(data.responseText).find('.errorlist.nonfield')[0])
errors = Array.from($(data.responseText).find('.errorlist.nonfield')[0].children);
while(errors.length > 0)
errorList.appendChild(errors.shift());
progress.value = ++completeCount / imagesCount;
if(progress.value === 1 && errorList.children.length === 0)
document.location.reload()
}
});
</script>
{% endblock %}

View File

@ -1,56 +1,110 @@
{% extends "core/base.jinja" %}
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('sas/album.scss') }}">
{%- endblock -%}
{% block title %}
{% trans %}SAS{% endtrans %}
{% trans %}SAS{% endtrans %}
{% endblock %}
{% macro display_album(a) %}
{% if a.is_moderated %}
<a href="{{ url("sas:album", album_id=a.id) }}">
<div class="album">
<div>
{% if a.file %}
<img src="{{ a.get_download_url() }}" alt="{% trans %}preview{% endtrans %}">
{% elif a.children.filter(is_folder=False, is_moderated=True).exists() %}
<img src="{{ a.children.filter(is_folder=False).first().as_picture.get_download_thumb_url() }}" alt="{% trans %}preview{% endtrans %}">
{% else %}
<img src="{{ static('core/img/sas.jpg') }}" alt="{% trans %}preview{% endtrans %}">
{% endif %}
</div>
{{ a.name }}
</div>
</a>
{% elif user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %}
<div style="display: inline-block; border: solid 1px red; text-align: center">
<p><a href="{{ url('core:file_moderate', file_id=a.id) }}?next={{ url('sas:moderation') }}">Moderate</a> or <a href="">Delete</a></p>
<a href="{{ url("sas:album", album_id=a.id) }}">{{ a.name }}</a>
</div>
{% endif %}
{% set edit_mode = user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %}
{% macro display_album(a, checkbox) %}
<a href="{{ url('sas:album', album_id=a.id) }}">
{% if a.file %}
{% set img = a.get_download_url() %}
{% elif a.children.filter(is_folder=False, is_moderated=True).exists() %}
{% set img = a.children.filter(is_folder=False).first().as_picture.get_download_thumb_url() %}
{% else %}
{% set img = static('core/img/sas.jpg') %}
{% endif %}
<div
class="album"
style="background-image: url('{{ img }}');"
>
<div class="text">
{{ a.name }}
</div>
</div>
{# {% if edit_mode and checkbox %}
<input type="checkbox" name="file_list" value="{{ a.id }}">
{% endif %} #}
</a>
{% endmacro %}
{% block content %}
<h3>{% trans %}SAS{% endtrans %}</h3>
<hr>
<h4>{% trans %}Latest albums{% endtrans %}</h4>
<div>
{% for a in latest %}
{{ display_album(a) }}
{% endfor %}
</div>
<hr>
<h4>{% trans %}All categories{% endtrans %}</h4>
<div>
{% for a in categories %}
{{ display_album(a) }}
{% endfor %}
</div>
{% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.non_field_errors() }}
<p>{{ form.album_name.errors }}<label for="{{ form.album_name.name }}">{{ form.album_name.label }}</label>
{{ form.album_name }}</p>
<p><input type="submit" value="{% trans %}Create{% endtrans %}" /></p>
</form>
{% endif %}
<main>
<h3>{% trans %}SAS{% endtrans %}</h3>
{% if not user.is_authenticated %}
<p>{% trans %}You must be logged in to see the SAS.{% endtrans %}</p>
{% else %}
<br>
<h4>{% trans %}Latest albums{% endtrans %}</h4>
<div class="albums">
{% for a in latest %}
{{ display_album(a) }}
{% endfor %}
</div>
<br>
{% if edit_mode %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="navbar">
<h4>{% trans %}All categories{% endtrans %}</h4>
{# <div class="toolbar">
<input name="delete" type="submit" value="{% trans %}Delete{% endtrans %}">
</div> #}
</div>
{% if clipboard %}
<div class="clipboard">
{% trans %}Clipboard: {% endtrans %}
<ul>
{% for f in clipboard %}
<li>{{ f.get_full_path() }}</li>
{% endfor %}
</ul>
<input name="clear" type="submit" value="{% trans %}Clear clipboard{% endtrans %}">
</div>
{% endif %}
{% else %}
<h4>{% trans %}All categories{% endtrans %}</h4>
{% endif %}
<div class="albums">
{% for a in categories %}
{{ display_album(a, true) }}
{% endfor %}
</div>
{% if edit_mode %}
</form>
<br>
<form class="add-files" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="inputs">
<div>
<label for="{{ form.album_name.name }}">{{ form.album_name.label }}</label>
{{ form.album_name }}
</div>
<input type="submit" value="{% trans %}Create{% endtrans %}" />
</div>
{{ form.non_field_errors() }}
{{ form.album_name.errors }}
</form>
{% endif %}
{% endif %}
</main>
{% endblock %}

View File

@ -1,150 +1,176 @@
{% extends "core/base.jinja" %}
{% block head %}
{{ super() }}
<style>
#prev, #next {
display: inline-block;
width: 42%;
height: 100px;
margin: 0.5%;
border: solid 1px grey;
overflow: hidden;
background: #aaa;
text-align: center;
}
#prev img, #next img {
display: block;
margin: auto;
max-height: 80%;
max-width: 100%;
}
</style>
{%- block additional_css -%}
<link rel="stylesheet" href="{{ scss('sas/picture.scss') }}">
{%- endblock -%}
{% if picture.get_previous() %}
<link rel="preload" as="image" href="{{ url("sas:download_compressed", picture_id=picture.get_previous().id) }}">
{% endif %}
{% if picture.get_next() %}
<link rel="preload" as="image" href="{{ url("sas:download_compressed", picture_id=picture.get_next().id) }}">
{% endif %}
{% block head %}
{{ super() }}
{% if picture.get_previous() %}
<link rel="preload" as="image" href="{{ url("sas:download_compressed", picture_id=picture.get_previous().id) }}">
{% endif %}
{% if picture.get_next() %}
<link rel="preload" as="image" href="{{ url("sas:download_compressed", picture_id=picture.get_next().id) }}">
{% endif %}
{% endblock %}
{% block title %}
{% trans %}SAS{% endtrans %}
{% trans %}SAS{% endtrans %}
{% endblock %}
{% macro print_path(file) %}
{% if file and file.parent %}
{{ print_path(file.parent) }}
<a href="{{ url('sas:album', album_id=file.id) }}">{{ file.get_display_name() }}</a> >
{% endif %}
{% if file and file.parent %}
{{ print_path(file.parent) }}
<a href="{{ url('sas:album', album_id=file.id) }}">{{ file.get_display_name() }}</a> /
{% endif %}
{% endmacro %}
{% block content %}
<a href="{{ url('sas:main') }}">SAS</a> > {{ print_path(picture.parent) }} {{ picture.get_display_name() }}
({{ picture.parent.children.filter(id__lte=picture.id).count() }} / {{ picture.parent.children.count() }})
<h3> {{ picture.get_display_name() }}</h3>
<div style="display: inline-block; width: 19%; vertical-align: top; overflow: hidden; float: right">
<div>
<div id="prev">
{% if picture.get_previous() %}
<a href="{{ url("sas:picture", picture_id=picture.get_previous().id) }}#pict">
&larr;
<img src="{{ picture.get_previous().as_picture.get_download_thumb_url() }}" alt="{{ picture.get_previous().get_display_name() }}" />
</a>
{% endif %}
</div>
<div id="next">
{% if picture.get_next() %}
<a href="{{ url("sas:picture", picture_id=picture.get_next().id) }}#pict">
&rarr;
<img src="{{ picture.get_next().as_picture.get_download_thumb_url() }}" alt="{{ picture.get_next().get_display_name() }}" />
</a>
{% endif %}
</div>
<code>
<a href="{{ url('sas:main') }}">SAS</a> / {{ print_path(picture.parent) }} {{ picture.get_display_name() }}
</code>
<br>
<div class="title">
<h3>{{ picture.get_display_name() }}</h3>
<h4>{{ picture.parent.children.filter(id__lte=picture.id).count() }} / {{ picture.parent.children.count() }}</h4>
</div>
<div>
<h5>{% trans %}People{% endtrans %}</h5>
<ul>
{% for r in picture.people.all() %}
<li>
<a href="{{ r.user.get_absolute_url() }}">{{ r.user.get_short_name() }}</a>
{% if user == r.user or user.can_edit(picture) %}
<a href="?remove_user={{ r.user.id }}">{% trans %}Delete{% endtrans %}</a>
{% if not picture.is_moderated %}
{% set next = picture.get_next() %}
{% if not next %}
{% set next = url('sas:moderation') %}
{% else %}
{% set next = next.get_absolute_url() + "#pict" %}
{% endif %}
<div class="moderation">
<div>
{% if picture.asked_for_removal %}
<span class="important">{% trans %}Asked for removal{% endtrans %}</span>
{% else %}
&nbsp;
{% endif %}
</li>
{% endfor %}
</ul>
<form action="" method="post" enctype="multipart/form-data" style="margin: 0px;">
{% csrf_token %}
{{ form.as_p() }}
<p><input type="submit" value="{% trans %}Go{% endtrans %}" /></p>
</form>
</div>
<div>
<h5>{% trans %}Infos{% endtrans %}</h5>
<p>{% trans %}Date: {% endtrans %}{{ picture.date|date(DATETIME_FORMAT) }}</p>
<p>{% trans %}Owner: {% endtrans %}<a href="{{ picture.owner.get_absolute_url() }}">{{ picture.owner.get_short_name() }}</a></p>
{% if picture.moderator %}
<p>{% trans %}Moderator: {% endtrans %}<a href="{{ picture.moderator.get_absolute_url() }}">{{ picture.moderator.get_short_name() }}</a></p>
{% endif %}
<p>{{ picture.parent.children.filter(id__lte=picture.id).count() }} / {{ picture.parent.children.count() }}</p>
</div>
<div>
<h5>{% trans %}Tools{% endtrans %}</h5>
<p>
<a href="{{ picture.get_download_url() }}">{% trans %}HD version{% endtrans %}</a>
</p>
<p style="font-size: smaller;">
<a href="{{ url('sas:picture_edit', picture_id=picture.id) }}">{% trans %}Edit{% endtrans %}</a><br>
<a href="?rotate_left">{% trans %}Rotate left{% endtrans %}</a><br>
<a href="?rotate_right">{% trans %}Rotate right{% endtrans %}</a><br>
<a href="?ask_removal">{% trans %}Ask for removal{% endtrans %}</a><br>
</p>
</div>
</div>
{% if picture.is_moderated %}
<div id="pict">
{% else %}
<div id="pict" style="border: solid #f00 2px; box-shadow: red 0px 0px 5px">
{% set next = picture.get_next() %}
{% if not next %}
{% set next = url('sas:moderation') %}
{% else %}
{% set next = next.get_absolute_url() + "#pict" %}
{% endif %}
<div style="background: lightgrey; padding: 2px;">
{% if picture.asked_for_removal %}
<span class="important">{% trans %}Asked for removal{% endtrans %}</span>
</div>
<div>
<a href="{{ url('core:file_moderate', file_id=picture.id) }}?next={{ next }}">
{% trans %}Moderate{% endtrans %}
</a>
<a href="{{ url('core:file_delete', file_id=picture.id) }}?next={{ next }}">
{% trans %}Delete{% endtrans %}
</a>
</div>
</div>
{% endif %}
<a href="{{ url('core:file_moderate', file_id=picture.id) }}?next={{ next }}">
{% trans %}Moderate{% endtrans %}</a> |
<a href="{{ url('core:file_delete', file_id=picture.id) }}?next={{ next }}">
{% trans %}Delete{% endtrans %}</a>
</div>
{% endif %}
{% if picture.is_vertical %}
<img src="{{ picture.get_download_compressed_url() }}" alt="{{ picture.get_display_name() }}" style="width: 60%; display: block; margin: auto"/>
{% else %}
<img src="{{ picture.get_download_compressed_url() }}" alt="{{ picture.get_display_name() }}" style="width: 100%; display: block; margin: auto"/>
{% endif %}
</div>
<div class="container">
<div class="main">
<div class="photo">
<img src="{{ picture.get_download_compressed_url() }}" alt="{{ picture.get_display_name() }}"/>
</div>
<div class="general">
<div class="infos">
<h5>{% trans %}Infos{% endtrans %}</h5>
<div>
<div>
<span>{% trans %}Date: {% endtrans %}</span>
<span>{{ picture.date|date(DATETIME_FORMAT) }}</span>
</div>
<div>
<span>{% trans %}Owner: {% endtrans %}</span>
<a href="{{ picture.owner.get_absolute_url() }}">{{ picture.owner.get_short_name() }}</a>
</div>
{% if picture.moderator %}
<div>
<span>{% trans %}Moderator: {% endtrans %}</span>
<a href="{{ picture.moderator.get_absolute_url() }}">{{ picture.moderator.get_short_name() }}</a>
</div>
{% endif %}
</div>
</div>
<div class="tools">
<h5>{% trans %}Tools{% endtrans %}</h5>
<div>
<div>
<a class="text" href="{{ picture.get_download_url() }}">{% trans %}HD version{% endtrans %}</a>
<br>
<a class="text danger" href="?ask_removal">{% trans %}Ask for removal{% endtrans %}</a>
</div>
<div class="buttons">
<a class="button" href="{{ url('sas:picture_edit', picture_id=picture.id) }}">✏️</a>
<a class="button" href="?rotate_left">↺</a>
<a class="button" href="?rotate_right">↻</a>
</div>
</div>
</div>
</div>
</div>
<div class="subsection">
<div class="navigation">
<div id="prev">
{% if picture.get_previous() %}
<a href="{{ url( 'sas:picture', picture_id=picture.get_previous().id) }}#pict">
<div style="background-image: url('{{ picture.get_previous().as_picture.get_download_thumb_url() }}');"></div>
</a>
{% endif %}
</div>
<div id="next">
{% if picture.get_next() %}
<a href="{{ url( 'sas:picture', picture_id=picture.get_next().id) }}#pict">
<div style="background-image: url('{{ picture.get_next().as_picture.get_download_thumb_url() }}');"></div>
</a>
{% endif %}
</div>
</div>
<div class="tags">
<h5>{% trans %}People{% endtrans %}</h5>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p() }}
<input type="submit" value="{% trans %}Go{% endtrans %}" />
</form>
<ul>
{% for r in picture.people.all() %}
<li>
<a class="user" href="{{ r.user.get_absolute_url() }}">
{% if r.user.profile_pict %}
<img src="{{ r.user.profile_pict.get_download_url() }}">
{% endif %}
<span>{{ r.user.get_short_name() }}</span>
</a>
{% if user == r.user or user.can_edit(picture) %}
<a class="delete" href="?remove_user={{ r.user.id }}">❌</a>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endblock %}
{% block script %}
{{ super() }}
<script>
$( function() {
$(document).keydown(function (e) {
if (e.keyCode == 37) {
console.log("prev");
$('#prev a')[0].click();
} else if (e.keyCode == 39) {
console.log("next");
$('#next a')[0].click();
}
{{ super() }}
<script>
$(() => {
$(document).keydown((e) => {
switch (e.keyCode) {
case 37:
$('#prev a')[0].click();
case 39:
$('#next a')[0].click();
}
});
});
} );
</script>
</script>
{% endblock %}

View File

@ -1,24 +1,16 @@
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
# You can find the source code of the website at https://github.com/ae-utbm/sith3
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#

View File

@ -1,24 +1,16 @@
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
# You can find the source code of the website at https://github.com/ae-utbm/sith3
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#

View File

@ -1,24 +1,16 @@
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
# You can find the source code of the website at https://github.com/ae-utbm/sith3
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#