mirror of
https://github.com/ae-utbm/sith.git
synced 2025-03-25 22:57:12 +00:00
Merge e1eb634c623bb6ba275ed4efdc546e9ff5672681 into bb3dfb7e8a87e4c4ca61d2ee095bb6c3f7ffc115
This commit is contained in:
commit
fd05081d6a
@ -880,11 +880,9 @@ class SithFile(models.Model):
|
||||
def save(self, *args, **kwargs):
|
||||
sas = SithFile.objects.filter(id=settings.SITH_SAS_ROOT_DIR_ID).first()
|
||||
self.is_in_sas = sas in self.get_parent_list() or self == sas
|
||||
copy_rights = False
|
||||
if self.id is None:
|
||||
copy_rights = True
|
||||
adding = self._state.adding
|
||||
super().save(*args, **kwargs)
|
||||
if copy_rights:
|
||||
if adding:
|
||||
self.copy_rights()
|
||||
if self.is_in_sas:
|
||||
for user in User.objects.filter(
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { BasketItem } from "#counter:counter/basket";
|
||||
import type { CounterConfig, ErrorMessage } from "#counter:counter/types";
|
||||
import type { CounterProductSelect } from "./components/counter-product-select-index";
|
||||
import type { CounterProductSelect } from "./components/counter-product-select-index.ts";
|
||||
|
||||
document.addEventListener("alpine:init", () => {
|
||||
Alpine.data("counter", (config: CounterConfig) => ({
|
||||
|
@ -23,7 +23,7 @@ from typing import ClassVar, Self
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.db import models
|
||||
from django.db.models import Exists, OuterRef
|
||||
from django.db.models import Exists, OuterRef, Q
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -73,7 +73,7 @@ class PictureQuerySet(models.QuerySet):
|
||||
if user.is_root or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID):
|
||||
return self.all()
|
||||
if user.was_subscribed:
|
||||
return self.filter(is_moderated=True)
|
||||
return self.filter(Q(is_moderated=True) | Q(owner=user))
|
||||
return self.filter(people__user_id=user.id, is_moderated=True)
|
||||
|
||||
|
||||
@ -187,7 +187,7 @@ class AlbumQuerySet(models.QuerySet):
|
||||
if user.is_root or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID):
|
||||
return self.all()
|
||||
if user.was_subscribed:
|
||||
return self.filter(is_moderated=True)
|
||||
return self.filter(Q(is_moderated=True) | Q(owner=user))
|
||||
# known bug : if all children of an album are also albums
|
||||
# then this album is excluded, even if one of the sub-albums should be visible.
|
||||
# The fs-like navigation is likely to be half-broken for non-subscribers,
|
||||
|
@ -4,9 +4,9 @@ import { History } from "#core:utils/history";
|
||||
import type TomSelect from "tom-select";
|
||||
import {
|
||||
type IdentifiedUserSchema,
|
||||
type ModerationRequestSchema,
|
||||
type PictureSchema,
|
||||
type PicturesFetchIdentificationsResponse,
|
||||
type PicturesFetchModerationRequestsResponse,
|
||||
type PicturesFetchPicturesData,
|
||||
type UserProfileSchema,
|
||||
picturesDeletePicture,
|
||||
@ -30,7 +30,7 @@ class PictureWithIdentifications {
|
||||
id: number;
|
||||
// biome-ignore lint/style/useNamingConvention: api is in snake_case
|
||||
compressed_url: string;
|
||||
moderationRequests: PicturesFetchModerationRequestsResponse = null;
|
||||
moderationRequests: ModerationRequestSchema[] = null;
|
||||
|
||||
constructor(picture: PictureSchema) {
|
||||
Object.assign(this, picture);
|
||||
@ -156,9 +156,6 @@ exportToHtml("loadViewer", (config: ViewerConfig) => {
|
||||
* The select2 component used to identify users
|
||||
**/
|
||||
selector: undefined,
|
||||
/**
|
||||
* true if the page is in a loading state, else false
|
||||
**/
|
||||
/**
|
||||
* Error message when a moderation operation fails
|
||||
**/
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
{% from "sas/macros.jinja" import print_path %}
|
||||
|
||||
{% set user_is_sas_admin = user.is_root or user.is_in_group(pk = settings.SITH_GROUP_SAS_ADMIN_ID) %}
|
||||
|
||||
{% block content %}
|
||||
<main x-data="picture_viewer">
|
||||
<code>
|
||||
@ -31,8 +33,13 @@
|
||||
</div>
|
||||
<br>
|
||||
|
||||
{# Non-moderated pictures (hence, this moderation alert too)
|
||||
should be shown only to admins and to the picture owner.
|
||||
Admins should see all infos and have access to all actions.
|
||||
Non-admin picture owners should only see the message warning them that
|
||||
the picture isn't moderated yet. #}
|
||||
<template x-if="!currentPicture.is_moderated">
|
||||
<div class="alert alert-red" @click="console.log(currentPicture)">
|
||||
<div id="picture-moderation-alert" class="alert alert-red">
|
||||
<div class="alert-main">
|
||||
<template x-if="currentPicture.asked_for_removal">
|
||||
<h3 class="alert-title">{% trans %}Asked for removal{% endtrans %}</h3>
|
||||
@ -43,35 +50,37 @@
|
||||
It will be hidden to other users until it has been moderated.
|
||||
{% endtrans %}
|
||||
</p>
|
||||
<template x-if="currentPicture.asked_for_removal">
|
||||
<div>
|
||||
<h5 @click="console.log(currentPicture.moderationRequests)">
|
||||
{% trans %}The following issues have been raised:{% endtrans %}
|
||||
</h5>
|
||||
<template x-for="req in (currentPicture.moderationRequests ?? [])" :key="req.id">
|
||||
<div>
|
||||
<h6
|
||||
x-text="`${req.author.first_name} ${req.author.last_name}`"
|
||||
></h6>
|
||||
<i x-text="Intl.DateTimeFormat(
|
||||
'{{ LANGUAGE_CODE }}',
|
||||
{dateStyle: 'long', timeStyle: 'short'}
|
||||
).format(new Date(req.created_at))"></i>
|
||||
<blockquote x-text="`> ${req.reason}`"></blockquote>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="alert-aside">
|
||||
<button class="btn btn-blue" @click="moderatePicture()">
|
||||
{% trans %}Moderate{% endtrans %}
|
||||
</button>
|
||||
<button class="btn btn-red" @click.prevent="deletePicture()">
|
||||
{% trans %}Delete{% endtrans %}
|
||||
</button>
|
||||
<p x-show="!!moderationError" x-text="moderationError"></p>
|
||||
{% if user_is_sas_admin %}
|
||||
<template x-if="currentPicture.asked_for_removal">
|
||||
<div>
|
||||
<h5>{% trans %}The following issues have been raised:{% endtrans %}</h5>
|
||||
<template x-for="req in (currentPicture.moderationRequests ?? [])" :key="req.id">
|
||||
<div>
|
||||
<h6
|
||||
x-text="`${req.author.first_name} ${req.author.last_name}`"
|
||||
></h6>
|
||||
<i x-text="Intl.DateTimeFormat(
|
||||
'{{ LANGUAGE_CODE }}',
|
||||
{dateStyle: 'long', timeStyle: 'short'}
|
||||
).format(new Date(req.created_at))"></i>
|
||||
<blockquote x-text="`${req.reason}`"></blockquote>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if user_is_sas_admin %}
|
||||
<div class="alert-aside">
|
||||
<button class="btn btn-blue" @click="moderatePicture()">
|
||||
{% trans %}Moderate{% endtrans %}
|
||||
</button>
|
||||
<button class="btn btn-red" @click.prevent="deletePicture()">
|
||||
{% trans %}Delete{% endtrans %}
|
||||
</button>
|
||||
<p x-show="!!moderationError" x-text="moderationError"></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -203,7 +212,7 @@
|
||||
albumUrl: "{{ album.get_absolute_url() }}",
|
||||
firstPictureId: {{ picture.id }}, {# id of the first picture to show after page load #}
|
||||
userId: {{ user.id }},
|
||||
userIsSasAdmin: {{ (user.is_root or user.is_in_group(pk = settings.SITH_GROUP_SAS_ADMIN_ID))|tojson }}
|
||||
userIsSasAdmin: {{ user_is_sas_admin|tojson }}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
@ -16,17 +16,22 @@ class TestPictureQuerySet(TestCase):
|
||||
|
||||
def test_root(self):
|
||||
root = baker.make(User, is_superuser=True)
|
||||
pictures = list(Picture.objects.viewable_by(root))
|
||||
self.assertCountEqual(pictures, self.pictures)
|
||||
pictures = list(Picture.objects.viewable_by(root).order_by("id"))
|
||||
assert pictures == self.pictures
|
||||
|
||||
def test_subscriber(self):
|
||||
"""Test that subscribed users see moderated pictures and pictures they own."""
|
||||
subscriber = subscriber_user.make()
|
||||
old_subcriber = old_subscriber_user.make()
|
||||
qs = Picture.objects.filter(pk=self.pictures[1].id)
|
||||
qs.update(is_moderated=False)
|
||||
for user in (subscriber, old_subcriber):
|
||||
pictures = list(Picture.objects.viewable_by(user))
|
||||
self.assertCountEqual(pictures, self.pictures[1:])
|
||||
qs.update(owner=user)
|
||||
pictures = list(Picture.objects.viewable_by(user).order_by("id"))
|
||||
assert pictures == self.pictures[1:]
|
||||
|
||||
def test_not_subscribed_identified(self):
|
||||
"""Public users should only see moderated photos on which they are identified."""
|
||||
user = baker.make(
|
||||
# This is the guy who asked the feature of making pictures
|
||||
# available for tagged users, even if not subscribed
|
||||
@ -35,7 +40,7 @@ class TestPictureQuerySet(TestCase):
|
||||
last_name="Dheilly",
|
||||
nick_name="Sahmer",
|
||||
)
|
||||
user.pictures.create(picture=self.pictures[0])
|
||||
user.pictures.create(picture=self.pictures[1])
|
||||
user.pictures.create(picture=self.pictures[0]) # non-moderated
|
||||
user.pictures.create(picture=self.pictures[1]) # moderated
|
||||
pictures = list(Picture.objects.viewable_by(user))
|
||||
assert pictures == [self.pictures[1]]
|
||||
|
Loading…
x
Reference in New Issue
Block a user