mirror of
https://github.com/ae-utbm/sith.git
synced 2026-05-02 11:26:08 +00:00
add update date to SithFile model
This commit is contained in:
@@ -7,7 +7,7 @@ from model_bakery import baker
|
|||||||
|
|
||||||
from com.models import News, NewsDate
|
from com.models import News, NewsDate
|
||||||
from core.baker_recipes import subscriber_user
|
from core.baker_recipes import subscriber_user
|
||||||
from core.models import Group, Notification, User
|
from core.models import Group, Notification, SithFile, User
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@@ -18,6 +18,7 @@ def test_notification_created():
|
|||||||
past_news = baker.make(News, is_published=False)
|
past_news = baker.make(News, is_published=False)
|
||||||
baker.make(NewsDate, news=past_news, start_date=now() - timedelta(days=1))
|
baker.make(NewsDate, news=past_news, start_date=now() - timedelta(days=1))
|
||||||
com_admin_group = Group.objects.get(pk=settings.SITH_GROUP_COM_ADMIN_ID)
|
com_admin_group = Group.objects.get(pk=settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
|
SithFile.objects.filter(owner__in=com_admin_group.users.all()).delete()
|
||||||
com_admin_group.users.all().delete()
|
com_admin_group.users.all().delete()
|
||||||
Notification.objects.all().delete()
|
Notification.objects.all().delete()
|
||||||
com_admin = baker.make(User, groups=[com_admin_group])
|
com_admin = baker.make(User, groups=[com_admin_group])
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Generated by Django 5.2.12 on 2026-05-01 08:59
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.db.migrations.state import StateApps
|
||||||
|
from django.db.models import F
|
||||||
|
|
||||||
|
|
||||||
|
def set_updated_at(apps: StateApps, schema_editor):
|
||||||
|
SithFile = apps.get_model("core", "SithFile")
|
||||||
|
SithFile.objects.update(updated_at=F("date"))
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [("core", "0049_user_whitelisted_users")]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="sithfile",
|
||||||
|
name="moderator",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="moderated_files",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
verbose_name="owner",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="sithfile",
|
||||||
|
name="owner",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="owned_files",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
verbose_name="owner",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="sithfile",
|
||||||
|
name="updated_at",
|
||||||
|
field=models.DateTimeField(auto_now=True, verbose_name="updated at"),
|
||||||
|
),
|
||||||
|
migrations.RunPython(set_updated_at, reverse_code=migrations.RunPython.noop),
|
||||||
|
]
|
||||||
+3
-2
@@ -853,7 +853,7 @@ class SithFile(models.Model):
|
|||||||
User,
|
User,
|
||||||
related_name="owned_files",
|
related_name="owned_files",
|
||||||
verbose_name=_("owner"),
|
verbose_name=_("owner"),
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.PROTECT,
|
||||||
)
|
)
|
||||||
edit_groups = models.ManyToManyField(
|
edit_groups = models.ManyToManyField(
|
||||||
Group, related_name="editable_files", verbose_name=_("edit group"), blank=True
|
Group, related_name="editable_files", verbose_name=_("edit group"), blank=True
|
||||||
@@ -865,6 +865,7 @@ class SithFile(models.Model):
|
|||||||
mime_type = models.CharField(_("mime type"), max_length=30)
|
mime_type = models.CharField(_("mime type"), max_length=30)
|
||||||
size = models.IntegerField(_("size"), default=0)
|
size = models.IntegerField(_("size"), default=0)
|
||||||
date = models.DateTimeField(_("date"), default=timezone.now)
|
date = models.DateTimeField(_("date"), default=timezone.now)
|
||||||
|
updated_at = models.DateTimeField(_("updated at"), auto_now=True)
|
||||||
is_moderated = models.BooleanField(_("is moderated"), default=False)
|
is_moderated = models.BooleanField(_("is moderated"), default=False)
|
||||||
moderator = models.ForeignKey(
|
moderator = models.ForeignKey(
|
||||||
User,
|
User,
|
||||||
@@ -872,7 +873,7 @@ class SithFile(models.Model):
|
|||||||
verbose_name=_("owner"),
|
verbose_name=_("owner"),
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.SET_NULL,
|
||||||
)
|
)
|
||||||
asked_for_removal = models.BooleanField(_("asked for removal"), default=False)
|
asked_for_removal = models.BooleanField(_("asked for removal"), default=False)
|
||||||
is_in_sas = models.BooleanField(
|
is_in_sas = models.BooleanField(
|
||||||
|
|||||||
@@ -33,7 +33,8 @@
|
|||||||
<a href="{{ url("core:file_detail", file_id=f.id) }}">{{ f.name }}</a><br/>
|
<a href="{{ url("core:file_detail", file_id=f.id) }}">{{ f.name }}</a><br/>
|
||||||
{% trans %}Full name: {% endtrans %}{{ f.get_parent_path()+'/'+f.name }}<br/>
|
{% trans %}Full name: {% endtrans %}{{ f.get_parent_path()+'/'+f.name }}<br/>
|
||||||
{% trans %}Owner: {% endtrans %}{{ f.owner.get_display_name() }}<br/>
|
{% trans %}Owner: {% endtrans %}{{ f.owner.get_display_name() }}<br/>
|
||||||
{% trans %}Date: {% endtrans %}{{ f.date|date(DATE_FORMAT) }} {{ f.date|time(TIME_FORMAT) }}<br/>
|
{% trans %}Date: {% endtrans %}
|
||||||
|
{{ f.date|date(DATE_FORMAT) }} {{ f.date|time(TIME_FORMAT) }}<br/>
|
||||||
</p>
|
</p>
|
||||||
<p><button
|
<p><button
|
||||||
hx-get="{{ url('core:file_moderate', file_id=f.id) }}"
|
hx-get="{{ url('core:file_moderate', file_id=f.id) }}"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from core.baker_recipes import (
|
|||||||
subscriber_user,
|
subscriber_user,
|
||||||
very_old_subscriber_user,
|
very_old_subscriber_user,
|
||||||
)
|
)
|
||||||
from core.models import AnonymousUser, Group, User
|
from core.models import AnonymousUser, Group, SithFile, User
|
||||||
from core.views import UserTabsMixin
|
from core.views import UserTabsMixin
|
||||||
from counter.baker_recipes import sale_recipe
|
from counter.baker_recipes import sale_recipe
|
||||||
from counter.models import Counter, Customer, Permanency, Refilling, Selling
|
from counter.models import Counter, Customer, Permanency, Refilling, Selling
|
||||||
@@ -34,6 +34,7 @@ class TestSearchUsers(TestCase):
|
|||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
# News.author has on_delete=PROTECT, so news must be deleted beforehand
|
# News.author has on_delete=PROTECT, so news must be deleted beforehand
|
||||||
News.objects.all().delete()
|
News.objects.all().delete()
|
||||||
|
SithFile.objects.all().delete()
|
||||||
User.objects.all().delete()
|
User.objects.all().delete()
|
||||||
user_recipe = Recipe(
|
user_recipe = Recipe(
|
||||||
User,
|
User,
|
||||||
|
|||||||
+2
-1
@@ -7,13 +7,14 @@ from model_bakery import baker
|
|||||||
|
|
||||||
from com.models import News
|
from com.models import News
|
||||||
from core.baker_recipes import subscriber_user
|
from core.baker_recipes import subscriber_user
|
||||||
from core.models import User
|
from core.models import SithFile, User
|
||||||
|
|
||||||
|
|
||||||
class TestMatmatronch(TestCase):
|
class TestMatmatronch(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
News.objects.all().delete()
|
News.objects.all().delete()
|
||||||
|
SithFile.objects.all().delete()
|
||||||
User.objects.all().delete()
|
User.objects.all().delete()
|
||||||
users = [
|
users = [
|
||||||
baker.prepare(User, promo=17),
|
baker.prepare(User, promo=17),
|
||||||
|
|||||||
+20
-4
@@ -100,13 +100,25 @@ class Picture(SasFile):
|
|||||||
return (w / h) < 1
|
return (w / h) < 1
|
||||||
|
|
||||||
def get_download_url(self):
|
def get_download_url(self):
|
||||||
return reverse("sas:download", kwargs={"picture_id": self.id})
|
return reverse(
|
||||||
|
"sas:download",
|
||||||
|
kwargs={"picture_id": self.id},
|
||||||
|
query={"date": int(self.updated_at.timestamp())},
|
||||||
|
)
|
||||||
|
|
||||||
def get_download_compressed_url(self):
|
def get_download_compressed_url(self):
|
||||||
return reverse("sas:download_compressed", kwargs={"picture_id": self.id})
|
return reverse(
|
||||||
|
"sas:download_compressed",
|
||||||
|
kwargs={"picture_id": self.id},
|
||||||
|
query={"date": int(self.updated_at.timestamp())},
|
||||||
|
)
|
||||||
|
|
||||||
def get_download_thumb_url(self):
|
def get_download_thumb_url(self):
|
||||||
return reverse("sas:download_thumb", kwargs={"picture_id": self.id})
|
return reverse(
|
||||||
|
"sas:download_thumb",
|
||||||
|
kwargs={"picture_id": self.id},
|
||||||
|
query={"date": int(self.updated_at.timestamp())},
|
||||||
|
)
|
||||||
|
|
||||||
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})
|
||||||
@@ -239,7 +251,11 @@ class Album(SasFile):
|
|||||||
return reverse("sas:album", kwargs={"album_id": self.id})
|
return reverse("sas:album", kwargs={"album_id": self.id})
|
||||||
|
|
||||||
def get_download_url(self):
|
def get_download_url(self):
|
||||||
return reverse("sas:album_preview", kwargs={"album_id": self.id})
|
return reverse(
|
||||||
|
"sas:album_preview",
|
||||||
|
kwargs={"album_id": self.id},
|
||||||
|
query={"date": int(self.updated_at.timestamp())},
|
||||||
|
)
|
||||||
|
|
||||||
def generate_thumbnail(self):
|
def generate_thumbnail(self):
|
||||||
p = self.children_pictures.order_by("?").first()
|
p = self.children_pictures.order_by("?").first()
|
||||||
|
|||||||
+9
-1
@@ -70,7 +70,15 @@ class PictureFilterSchema(FilterSchema):
|
|||||||
class PictureSchema(ModelSchema):
|
class PictureSchema(ModelSchema):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Picture
|
model = Picture
|
||||||
fields = ["id", "name", "date", "size", "is_moderated", "asked_for_removal"]
|
fields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"date",
|
||||||
|
"updated_at",
|
||||||
|
"size",
|
||||||
|
"is_moderated",
|
||||||
|
"asked_for_removal",
|
||||||
|
]
|
||||||
|
|
||||||
owner: UserProfileSchema
|
owner: UserProfileSchema
|
||||||
sas_url: str
|
sas_url: str
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{% extends "core/base.jinja" %}
|
{% extends "core/base.jinja" %}
|
||||||
|
|
||||||
{%- block additional_css -%}
|
{%- block additional_css -%}
|
||||||
<link defer rel="stylesheet" href="{{ static('bundled/core/components/ajax-select-index.css') }}">
|
<link rel="stylesheet" href="{{ static('bundled/core/components/ajax-select-index.css') }}">
|
||||||
<link defer rel="stylesheet" href="{{ static('core/components/ajax-select.scss') }}">
|
<link rel="stylesheet" href="{{ static('core/components/ajax-select.scss') }}">
|
||||||
<link defer rel="stylesheet" href="{{ static('sas/css/picture.scss') }}">
|
<link rel="stylesheet" href="{{ static('sas/css/picture.scss') }}">
|
||||||
{%- endblock -%}
|
{%- endblock -%}
|
||||||
|
|
||||||
{%- block additional_js -%}
|
{%- block additional_js -%}
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="photo" :aria-busy="currentPicture.imageLoading">
|
<div class="photo" :aria-busy="currentPicture.imageLoading">
|
||||||
<img
|
<img
|
||||||
:src="currentPicture.compressed_url"
|
:src="currentPicture.compressedUrl"
|
||||||
:alt="currentPicture.name"
|
:alt="currentPicture.name"
|
||||||
id="main-picture"
|
id="main-picture"
|
||||||
x-ref="mainPicture"
|
x-ref="mainPicture"
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
<span
|
<span
|
||||||
x-text="Intl.DateTimeFormat(
|
x-text="Intl.DateTimeFormat(
|
||||||
'{{ LANGUAGE_CODE }}', {dateStyle: 'long'}
|
'{{ LANGUAGE_CODE }}', {dateStyle: 'long'}
|
||||||
).format(new Date(currentPicture.date))"
|
).format(Date.parse(currentPicture.date))"
|
||||||
>
|
>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,23 +115,38 @@
|
|||||||
<h5>{% trans %}Tools{% endtrans %}</h5>
|
<h5>{% trans %}Tools{% endtrans %}</h5>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<a class="text" :href="currentPicture.full_size_url">
|
<a class="text" :href="currentPicture.fullSizeUrl">
|
||||||
{% trans %}HD version{% endtrans %}
|
{% trans %}HD version{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
<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"
|
||||||
|
x-show="{{ user.has_perm("sas.change_sasfile")|tojson }} || currentPicture.owner.id === {{ user.id }}"
|
||||||
|
>
|
||||||
<a
|
<a
|
||||||
class="btn btn-no-text"
|
class="btn btn-no-text"
|
||||||
:href="currentPicture.edit_url"
|
:href="currentPicture.edit_url"
|
||||||
x-show="{{ user.has_perm("sas.change_sasfile")|tojson }} || currentPicture.owner.id === {{ user.id }}"
|
:disabled="currentPicture.imageLoading"
|
||||||
>
|
>
|
||||||
<i class="fa-regular fa-pen-to-square edit-action"></i>
|
<i class="fa-regular fa-pen-to-square edit-action"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-no-text" href="?rotate_left"><i class="fa-solid fa-rotate-left"></i></a>
|
<button
|
||||||
<a class="btn btn-no-text" href="?rotate_right"><i class="fa-solid fa-rotate-right"></i></a>
|
class="btn btn-no-text"
|
||||||
|
@click="currentPicture.rotate('left')"
|
||||||
|
:disabled="currentPicture.imageLoading"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-rotate-left"></i>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-no-text"
|
||||||
|
@click="currentPicture.rotate('right')"
|
||||||
|
:disabled="currentPicture.imageLoading"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-rotate-right"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -146,7 +161,7 @@
|
|||||||
@keyup.left.window="currentPicture = previousPicture"
|
@keyup.left.window="currentPicture = previousPicture"
|
||||||
@click="currentPicture = previousPicture"
|
@click="currentPicture = previousPicture"
|
||||||
>
|
>
|
||||||
<img :src="previousPicture.thumb_url" alt="{% trans %}Previous picture{% endtrans %}"/>
|
<img :src="previousPicture.thumbUrl" alt="{% trans %}Previous picture{% endtrans %}"/>
|
||||||
<div class="overlay">←</div>
|
<div class="overlay">←</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -157,7 +172,7 @@
|
|||||||
@keyup.right.window="currentPicture = nextPicture"
|
@keyup.right.window="currentPicture = nextPicture"
|
||||||
@click="currentPicture = nextPicture"
|
@click="currentPicture = nextPicture"
|
||||||
>
|
>
|
||||||
<img :src="nextPicture.thumb_url" alt="{% trans %}Previous picture{% endtrans %}"/>
|
<img :src="nextPicture.thumbUrl" alt="{% trans %}Previous picture{% endtrans %}"/>
|
||||||
<div class="overlay">→</div>
|
<div class="overlay">→</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user