mirror of
https://github.com/ae-utbm/sith.git
synced 2026-04-28 09:36:07 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1d203ba98 | |||
| 67b859ebda | |||
| ad50085574 | |||
| f9c5297473 | |||
| 52117b5a24 | |||
| ae72a2e00f | |||
| fdf89ea716 | |||
| 3954f2f170 | |||
| d36d672d0b | |||
| da3602329c | |||
|
8b18999514
|
|||
| 1d525ca6d4 | |||
|
4dea60ac66
|
@@ -26,10 +26,9 @@
|
|||||||
{% if club.logo %}
|
{% if club.logo %}
|
||||||
<div class="club_logo"><img src="{{ club.logo.url }}" alt="{{ club.name }}"></div>
|
<div class="club_logo"><img src="{{ club.logo.url }}" alt="{{ club.name }}"></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<h3>{{ club.name }}</h3>
|
||||||
{% if page_revision %}
|
{% if page_revision %}
|
||||||
{{ page_revision|markdown }}
|
{{ page_revision|markdown }}
|
||||||
{% else %}
|
|
||||||
<h3>{{ club.name }}</h3>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#news {
|
#news {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
gap: 1em;
|
||||||
|
|
||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -26,12 +27,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
background: $second-color;
|
--box-shadow: rgb(60 64 67 / 30%) 0 1px 3px 0, rgb(60 64 67 / 15%) 0 3px 7px 2px;
|
||||||
box-shadow: $shadow-color 1px 1px 1px;
|
background: lighten($second-color, 5%);
|
||||||
padding: 0.4em;
|
box-shadow: var(--box-shadow);
|
||||||
|
padding: .75rem;
|
||||||
margin: 0 0 0.5em 0;
|
margin: 0 0 0.5em 0;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
&:not(:first-of-type) {
|
&:not(:first-of-type) {
|
||||||
margin: 2em 0 1em 0;
|
margin: 2em 0 1em 0;
|
||||||
@@ -39,12 +42,11 @@
|
|||||||
|
|
||||||
.feed {
|
.feed {
|
||||||
float: right;
|
float: right;
|
||||||
color: #f26522;
|
color: #e25512;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: $small-devices) {
|
@media screen and (max-width: $small-devices) {
|
||||||
|
|
||||||
#left_column,
|
#left_column,
|
||||||
#right_column {
|
#right_column {
|
||||||
flex: 100%;
|
flex: 100%;
|
||||||
@@ -57,6 +59,7 @@
|
|||||||
max-height: 600px;
|
max-height: 600px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overflow-x: clip;
|
overflow-x: clip;
|
||||||
|
margin-top: 1em;
|
||||||
|
|
||||||
#load-more-news-button {
|
#load-more-news-button {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -76,15 +79,11 @@
|
|||||||
font-size: 70%;
|
font-size: 70%;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#links_content {
|
#links_content {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
box-shadow: $shadow-color 1px 1px 1px;
|
box-shadow: $shadow-color 1px 1px 1px;
|
||||||
min-height: 20em;
|
min-height: 20em;
|
||||||
padding-bottom: 1em;
|
padding: 1em;
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
@@ -121,6 +120,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#birthdays_content {
|
#birthdays_content {
|
||||||
|
box-shadow: $shadow-color 1px 1px 1px;
|
||||||
|
padding: 1em;
|
||||||
ul.birthdays_year {
|
ul.birthdays_year {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
@@ -135,8 +136,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
margin: 0;
|
margin: .5em 0 0 1em;
|
||||||
margin-left: 1em;
|
|
||||||
list-style-type: square;
|
list-style-type: square;
|
||||||
list-style-position: inside;
|
list-style-position: inside;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
@@ -150,9 +150,13 @@
|
|||||||
/* EVENTS TODAY AND NEXT FEW DAYS */
|
/* EVENTS TODAY AND NEXT FEW DAYS */
|
||||||
.news_events_group {
|
.news_events_group {
|
||||||
box-shadow: $shadow-color 1px 1px 1px;
|
box-shadow: $shadow-color 1px 1px 1px;
|
||||||
margin-left: 1em;
|
margin-left: 0;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
|
|
||||||
|
@media screen and (max-width: $small-devices) {
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.news_events_group_date {
|
.news_events_group_date {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
padding: 0.6em;
|
padding: 0.6em;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<a target="#" href="{{ url("com:news_feed") }}"><i class="fa fa-rss feed"></i></a>
|
<a target="#" href="{{ url("com:news_feed") }}"><i class="fa fa-rss feed"></i></a>
|
||||||
</h3>
|
</h3>
|
||||||
{% if user.is_authenticated and (user.is_com_admin or user.memberships.board().ongoing().exists()) %}
|
{% if user.is_authenticated and (user.is_com_admin or user.memberships.board().ongoing().exists()) %}
|
||||||
<a class="btn btn-blue margin-bottom" href="{{ url("com:news_new") }}">
|
<a class="btn btn-blue" href="{{ url("com:news_new") }}">
|
||||||
<i class="fa fa-plus"></i>
|
<i class="fa fa-plus"></i>
|
||||||
{% trans %}Create news{% endtrans %}
|
{% trans %}Create news{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
# details.
|
# details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License along with
|
# 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
|
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
@@ -110,7 +110,9 @@ class Command(BaseCommand):
|
|||||||
p.save(force_lock=True)
|
p.save(force_lock=True)
|
||||||
|
|
||||||
club_root = SithFile.objects.create(name="clubs", owner=root)
|
club_root = SithFile.objects.create(name="clubs", owner=root)
|
||||||
sas = SithFile.objects.create(name="SAS", owner=root)
|
sas = SithFile.objects.create(
|
||||||
|
name="SAS", owner=root, id=settings.SITH_SAS_ROOT_DIR_ID
|
||||||
|
)
|
||||||
main_club = Club.objects.create(
|
main_club = Club.objects.create(
|
||||||
id=1, name="AE", address="6 Boulevard Anatole France, 90000 Belfort"
|
id=1, name="AE", address="6 Boulevard Anatole France, 90000 Belfort"
|
||||||
)
|
)
|
||||||
|
|||||||
+7
-3
@@ -131,7 +131,9 @@ class UserQuerySet(models.QuerySet):
|
|||||||
if user.has_perm("core.view_hidden_user"):
|
if user.has_perm("core.view_hidden_user"):
|
||||||
return self
|
return self
|
||||||
if user.has_perm("core.view_user"):
|
if user.has_perm("core.view_user"):
|
||||||
return self.filter(Q(is_viewable=True) | Q(whitelisted_users=user))
|
return self.filter(
|
||||||
|
Q(is_viewable=True) | Q(whitelisted_users=user) | Q(pk=user.pk)
|
||||||
|
)
|
||||||
if user.is_anonymous:
|
if user.is_anonymous:
|
||||||
return self.none()
|
return self.none()
|
||||||
return self.filter(id=user.id)
|
return self.filter(id=user.id)
|
||||||
@@ -884,8 +886,10 @@ class SithFile(models.Model):
|
|||||||
return self.get_parent_path() + "/" + self.name
|
return self.get_parent_path() + "/" + self.name
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
sas = SithFile.objects.filter(id=settings.SITH_SAS_ROOT_DIR_ID).first()
|
sas_id = settings.SITH_SAS_ROOT_DIR_ID
|
||||||
self.is_in_sas = sas in self.get_parent_list() or self == sas
|
self.is_in_sas = self.id == sas_id or any(
|
||||||
|
p.id == sas_id for p in self.get_parent_list()
|
||||||
|
)
|
||||||
adding = self._state.adding
|
adding = self._state.adding
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
if adding:
|
if adding:
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ body {
|
|||||||
|
|
||||||
/*--------------------------------CONTENT------------------------------*/
|
/*--------------------------------CONTENT------------------------------*/
|
||||||
#content {
|
#content {
|
||||||
padding: 1em 1%;
|
padding: 1.5em 3%;
|
||||||
box-shadow: $shadow-color 0 5px 10px;
|
box-shadow: $shadow-color 0 5px 10px;
|
||||||
background: $white-color;
|
background: $white-color;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<span class="helptext">{{ form.is_viewable.help_text }}</span>
|
<span class="helptext">{{ form.is_viewable.help_text }}</span>
|
||||||
{{ form.is_viewable.errors }}
|
{{ form.is_viewable.errors }}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="form-group" x-show="!isViewable">
|
<fieldset class="form-group" x-show="!isViewable" x-transition x-cloak>
|
||||||
{{ form.whitelisted_users.as_field_group() }}
|
{{ form.whitelisted_users.as_field_group() }}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
|
|||||||
@@ -344,3 +344,14 @@ def test_quick_upload_image(
|
|||||||
assert (
|
assert (
|
||||||
parsed["name"] == Path(file.name).stem[: QuickUploadImage.IMAGE_NAME_SIZE - 1]
|
parsed["name"] == Path(file.name).stem[: QuickUploadImage.IMAGE_NAME_SIZE - 1]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_populated_sas_is_in_sas():
|
||||||
|
"""Test that, in the data generated by the populate command,
|
||||||
|
the SAS has value is_in_sas=True.
|
||||||
|
|
||||||
|
If it's not the case, it has no incidence in prod, but it's annoying
|
||||||
|
in dev and may cause misunderstandings.
|
||||||
|
"""
|
||||||
|
assert SithFile.objects.get(id=settings.SITH_SAS_ROOT_DIR_ID).is_in_sas
|
||||||
|
|||||||
+12
-4
@@ -410,12 +410,20 @@ class TestUserQuerySetViewableBy:
|
|||||||
assert set(viewable) == set(users)
|
assert set(viewable) == set(users)
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"user_factory", [old_subscriber_user.make, subscriber_user.make]
|
"user_factory",
|
||||||
|
[
|
||||||
|
old_subscriber_user.make,
|
||||||
|
lambda: old_subscriber_user.make(is_viewable=False),
|
||||||
|
subscriber_user.make,
|
||||||
|
lambda: subscriber_user.make(is_viewable=False),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
def test_subscriber(self, users: list[User], user_factory):
|
def test_can_search(self, users: list[User], user_factory):
|
||||||
user = user_factory()
|
user = user_factory()
|
||||||
viewable = User.objects.filter(id__in=[u.id for u in users]).viewable_by(user)
|
viewable = User.objects.filter(
|
||||||
assert set(viewable) == {users[0], users[1]}
|
id__in=[u.id for u in [*users, user]]
|
||||||
|
).viewable_by(user)
|
||||||
|
assert set(viewable) == {user, users[0], users[1]}
|
||||||
|
|
||||||
def test_whitelist(self, users: list[User]):
|
def test_whitelist(self, users: list[User]):
|
||||||
user = subscriber_user.make()
|
user = subscriber_user.make()
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
#eboutic {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
align-items: flex-start;
|
|
||||||
column-gap: 20px;
|
|
||||||
margin: 0 20px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic-title {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic h3 {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#basket {
|
|
||||||
min-width: 300px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow:
|
|
||||||
rgb(60 64 67 / 30%) 0 1px 3px 0,
|
|
||||||
rgb(60 64 67 / 15%) 0 4px 8px 3px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#basket h3 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 765px) {
|
|
||||||
#eboutic {
|
|
||||||
flex-direction: column-reverse;
|
|
||||||
align-items: center;
|
|
||||||
margin: 10px;
|
|
||||||
row-gap: 20px;
|
|
||||||
}
|
|
||||||
#eboutic-title {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
#basket {
|
|
||||||
width: -webkit-fill-available;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .item-list {
|
|
||||||
margin-left: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .item-list li {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .item-row {
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .item-name {
|
|
||||||
word-break: break-word;
|
|
||||||
width: 100%;
|
|
||||||
line-height: 100%;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .fa-plus,
|
|
||||||
#eboutic .fa-minus {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #354a5f;
|
|
||||||
color: white;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 5px;
|
|
||||||
font-size: 10px;
|
|
||||||
line-height: 10px;
|
|
||||||
width: 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .item-quantity {
|
|
||||||
min-width: 65px;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .item-price {
|
|
||||||
min-width: 65px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CSS du catalogue */
|
|
||||||
|
|
||||||
#eboutic #catalog {
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-direction: column;
|
|
||||||
row-gap: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .category-header {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .product-group {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
column-gap: 15px;
|
|
||||||
row-gap: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .card.selected::after {
|
|
||||||
content: "🛒";
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 5px;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 50%;
|
|
||||||
box-shadow: 0 0 12px 2px rgb(0 0 0 / 14%);
|
|
||||||
background-color: white;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .catalog-buttons {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
column-gap: 30px;
|
|
||||||
margin: 30px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic input {
|
|
||||||
all: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .catalog-buttons button {
|
|
||||||
min-width: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .catalog-buttons form {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 765px) {
|
|
||||||
#eboutic #catalog {
|
|
||||||
row-gap: 15px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic section {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#eboutic .product-group {
|
|
||||||
justify-content: space-around;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
#eboutic-title {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#eboutic {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
align-items: flex-start;
|
||||||
|
column-gap: 20px;
|
||||||
|
margin: 0 20px 20px;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#basket {
|
||||||
|
--box-shadow:
|
||||||
|
rgb(60 64 67 / 30%) 0 1px 3px 0,
|
||||||
|
rgb(60 64 67 / 15%) 0 4px 8px 3px;
|
||||||
|
min-width: 300px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: var(--box-shadow);
|
||||||
|
padding: 10px;
|
||||||
|
h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 765px) {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
align-items: center;
|
||||||
|
margin: 10px;
|
||||||
|
row-gap: 20px;
|
||||||
|
|
||||||
|
#eboutic-title {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
#basket {
|
||||||
|
width: -webkit-fill-available;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list {
|
||||||
|
margin-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-row {
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-name {
|
||||||
|
word-break: break-word;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 100%;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-plus,
|
||||||
|
.fa-minus {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #354a5f;
|
||||||
|
color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 10px;
|
||||||
|
width: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-quantity {
|
||||||
|
min-width: 65px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-price {
|
||||||
|
min-width: 65px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CSS du catalogue */
|
||||||
|
|
||||||
|
#catalog {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-header {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-group {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
column-gap: 15px;
|
||||||
|
row-gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.selected::after {
|
||||||
|
--box-shadow: 0 0 12px 2px rgb(0 0 0 / 14%);
|
||||||
|
content: "🛒";
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: var(--box-shadow);
|
||||||
|
background-color: white;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
all: unset;
|
||||||
|
}
|
||||||
|
.catalog-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
column-gap: 30px;
|
||||||
|
margin: 30px 0 0;
|
||||||
|
|
||||||
|
button {
|
||||||
|
min-width: 60px;
|
||||||
|
}
|
||||||
|
form {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media screen and (max-width: 765px) {
|
||||||
|
#catalog {
|
||||||
|
row-gap: 15px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-group {
|
||||||
|
justify-content: space-around;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block additional_css %}
|
{% block additional_css %}
|
||||||
<link rel="stylesheet" href="{{ static("eboutic/css/eboutic.css") }}">
|
<link rel="stylesheet" href="{{ static("eboutic/css/eboutic.scss") }}">
|
||||||
<link rel="stylesheet" href="{{ static("core/components/card.scss") }}">
|
<link rel="stylesheet" href="{{ static("core/components/card.scss") }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -170,8 +170,6 @@
|
|||||||
{% for category, items in priority_groups.list|groupby('category') %}
|
{% for category, items in priority_groups.list|groupby('category') %}
|
||||||
{% if items|count > 0 %}
|
{% if items|count > 0 %}
|
||||||
<section>
|
<section>
|
||||||
{# I would have wholeheartedly directly used the header element instead
|
|
||||||
but it has already been made messy in core/style.scss #}
|
|
||||||
<div class="category-header">
|
<div class="category-header">
|
||||||
<h3>{{ category }}</h3>
|
<h3>{{ category }}</h3>
|
||||||
{% if items[0].category_comment %}
|
{% if items[0].category_comment %}
|
||||||
|
|||||||
+3
-3
@@ -19,7 +19,7 @@ authors = [
|
|||||||
license = { text = "GPL-3.0-only" }
|
license = { text = "GPL-3.0-only" }
|
||||||
requires-python = "<4.0,>=3.12"
|
requires-python = "<4.0,>=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"django>=5.2.13,<6.0.0",
|
"django>=5.2.12,<6.0.0",
|
||||||
"django-ninja>=1.5.3,<6.0.0",
|
"django-ninja>=1.5.3,<6.0.0",
|
||||||
"django-ninja-extra>=0.31.0",
|
"django-ninja-extra>=0.31.0",
|
||||||
"Pillow>=12.1.1,<13.0.0",
|
"Pillow>=12.1.1,<13.0.0",
|
||||||
@@ -30,7 +30,7 @@ dependencies = [
|
|||||||
"phonenumbers>=9.0.25,<10.0.0",
|
"phonenumbers>=9.0.25,<10.0.0",
|
||||||
"reportlab>=4.4.10,<5.0.0",
|
"reportlab>=4.4.10,<5.0.0",
|
||||||
"django-haystack<4.0.0,>=3.3.0",
|
"django-haystack<4.0.0,>=3.3.0",
|
||||||
"xapian-haystack<3.1.0,<5.0.0",
|
"xapian-haystack<4.0.0,>=3.1.0",
|
||||||
"libsass<1.0.0,>=0.23.0",
|
"libsass<1.0.0,>=0.23.0",
|
||||||
"django-ordered-model<4.0.0,>=3.7.4",
|
"django-ordered-model<4.0.0,>=3.7.4",
|
||||||
"django-simple-captcha<1.0.0,>=0.6.3",
|
"django-simple-captcha<1.0.0,>=0.6.3",
|
||||||
@@ -45,7 +45,7 @@ dependencies = [
|
|||||||
"pydantic-extra-types>=2.11.0,<3.0.0",
|
"pydantic-extra-types>=2.11.0,<3.0.0",
|
||||||
"ical>=11.1.0,<12",
|
"ical>=11.1.0,<12",
|
||||||
"redis[hiredis]>=5.3.0,<8.0.0",
|
"redis[hiredis]>=5.3.0,<8.0.0",
|
||||||
"environs[django]>=14.5.0,<16.0.0",
|
"environs[django]>=14.5.0,<15.0.0",
|
||||||
"requests>=2.32.5,<3.0.0",
|
"requests>=2.32.5,<3.0.0",
|
||||||
"honcho>=2.0.0",
|
"honcho>=2.0.0",
|
||||||
"psutil>=7.2.2,<8.0.0",
|
"psutil>=7.2.2,<8.0.0",
|
||||||
|
|||||||
+3
-1
@@ -50,13 +50,15 @@ class AlbumEditForm(forms.ModelForm):
|
|||||||
model = Album
|
model = Album
|
||||||
fields = ["name", "date", "file", "parent", "edit_groups"]
|
fields = ["name", "date", "file", "parent", "edit_groups"]
|
||||||
widgets = {
|
widgets = {
|
||||||
"parent": AutoCompleteSelectAlbum,
|
|
||||||
"edit_groups": AutoCompleteSelectMultipleGroup,
|
"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)
|
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(
|
||||||
|
Album.objects.all(), required=True, widget=AutoCompleteSelectAlbum
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PictureModerationRequestForm(forms.ModelForm):
|
class PictureModerationRequestForm(forms.ModelForm):
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -20,12 +20,14 @@ from django.conf import settings
|
|||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.test import Client, TestCase
|
from django.test import Client, TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils.timezone import localdate
|
||||||
from model_bakery import baker
|
from model_bakery import baker
|
||||||
from pytest_django.asserts import assertHTMLEqual, assertInHTML, assertRedirects
|
from pytest_django.asserts import assertHTMLEqual, assertInHTML, assertRedirects
|
||||||
|
|
||||||
from core.baker_recipes import old_subscriber_user, subscriber_user
|
from core.baker_recipes import old_subscriber_user, subscriber_user
|
||||||
from core.models import Group, User
|
from core.models import Group, User
|
||||||
from sas.baker_recipes import picture_recipe
|
from sas.baker_recipes import picture_recipe
|
||||||
|
from sas.forms import AlbumEditForm
|
||||||
from sas.models import Album, Picture
|
from sas.models import Album, Picture
|
||||||
|
|
||||||
# Create your tests here.
|
# Create your tests here.
|
||||||
@@ -64,6 +66,25 @@ def test_main_page_no_form_for_regular_users(client: Client):
|
|||||||
assert len(forms) == 0
|
assert len(forms) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_main_page_displayed_albums(client: Client):
|
||||||
|
"""Test that the right data is displayed on the SAS main page"""
|
||||||
|
sas = Album.objects.get(id=settings.SITH_SAS_ROOT_DIR_ID)
|
||||||
|
Album.objects.exclude(id=sas.id).delete()
|
||||||
|
album_a = baker.make(Album, parent=sas, is_moderated=True)
|
||||||
|
album_b = baker.make(Album, parent=album_a, is_moderated=True)
|
||||||
|
album_c = baker.make(Album, parent=sas, is_moderated=True)
|
||||||
|
baker.make(Album, parent=sas, is_moderated=False)
|
||||||
|
client.force_login(subscriber_user.make())
|
||||||
|
res = client.get(reverse("sas:main"))
|
||||||
|
# album_b is not a direct child of the SAS, so it shouldn't be displayed
|
||||||
|
# in the categories, but it should appear in the latest albums.
|
||||||
|
# album_d isn't moderated, so it shouldn't appear at all for a simple user.
|
||||||
|
# Also, the SAS itself shouldn't be listed in the albums.
|
||||||
|
assert res.context_data["latest"] == [album_c, album_b, album_a]
|
||||||
|
assert res.context_data["categories"] == [album_a, album_c]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_main_page_content_anonymous(client: Client):
|
def test_main_page_content_anonymous(client: Client):
|
||||||
"""Test that public users see only an incentive to login"""
|
"""Test that public users see only an incentive to login"""
|
||||||
@@ -89,6 +110,15 @@ def test_album_access_non_subscriber(client: Client):
|
|||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_accessing_sas_from_album_view_is_404(client: Client):
|
||||||
|
"""Test that trying to see the SAS with a regular album view isn't allowed."""
|
||||||
|
res = client.get(
|
||||||
|
reverse("sas:album", kwargs={"album_id": settings.SITH_SAS_ROOT_DIR_ID})
|
||||||
|
)
|
||||||
|
assert res.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
class TestAlbumUpload:
|
class TestAlbumUpload:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -133,6 +163,140 @@ class TestAlbumUpload:
|
|||||||
assert not album.children.exists()
|
assert not album.children.exists()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
class TestAlbumEdit:
|
||||||
|
@pytest.fixture
|
||||||
|
def sas_root(self) -> Album:
|
||||||
|
return Album.objects.get(id=settings.SITH_SAS_ROOT_DIR_ID)
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def album(self) -> Album:
|
||||||
|
return baker.make(
|
||||||
|
Album, parent_id=settings.SITH_SAS_ROOT_DIR_ID, is_moderated=True
|
||||||
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"user",
|
||||||
|
[None, lambda: baker.make(User), subscriber_user.make],
|
||||||
|
)
|
||||||
|
def test_permission_denied(
|
||||||
|
self,
|
||||||
|
client: Client,
|
||||||
|
album: Album,
|
||||||
|
user: Callable[[], User] | None,
|
||||||
|
):
|
||||||
|
if user:
|
||||||
|
client.force_login(user())
|
||||||
|
|
||||||
|
url = reverse("sas:album_edit", kwargs={"album_id": album.pk})
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 403
|
||||||
|
response = client.post(url)
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
def test_sas_root_read_only(self, client: Client, sas_root: Album):
|
||||||
|
moderator = baker.make(
|
||||||
|
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)]
|
||||||
|
)
|
||||||
|
client.force_login(moderator)
|
||||||
|
url = reverse("sas:album_edit", kwargs={"album_id": sas_root.pk})
|
||||||
|
response = client.get(url)
|
||||||
|
assert response.status_code == 404
|
||||||
|
response = client.post(url)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("excluded", "is_valid"),
|
||||||
|
[
|
||||||
|
("name", False),
|
||||||
|
("date", False),
|
||||||
|
("file", True),
|
||||||
|
("parent", False),
|
||||||
|
("edit_groups", True),
|
||||||
|
("recursive", True),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_form_required(self, album: Album, excluded: str, is_valid: bool): # noqa: FBT001
|
||||||
|
data = {
|
||||||
|
"name": album.name[: Album.NAME_MAX_LENGTH],
|
||||||
|
"parent": baker.make(Album, parent=album.parent, is_moderated=True).pk,
|
||||||
|
"date": localdate().strftime("%Y-%m-%d"),
|
||||||
|
"file": "/random/path",
|
||||||
|
"edit_groups": [settings.SITH_GROUP_SAS_ADMIN_ID],
|
||||||
|
"recursive": False,
|
||||||
|
}
|
||||||
|
del data[excluded]
|
||||||
|
assert AlbumEditForm(data=data).is_valid() == is_valid
|
||||||
|
|
||||||
|
def test_form_album_name(self, album: Album):
|
||||||
|
data = {
|
||||||
|
"name": album.name[: Album.NAME_MAX_LENGTH],
|
||||||
|
"parent": album.pk,
|
||||||
|
"date": localdate().strftime("%Y-%m-%d"),
|
||||||
|
}
|
||||||
|
assert AlbumEditForm(data=data).is_valid()
|
||||||
|
|
||||||
|
data["name"] = album.name[: Album.NAME_MAX_LENGTH + 1]
|
||||||
|
assert not AlbumEditForm(data=data).is_valid()
|
||||||
|
|
||||||
|
def test_update_recursive_parent(self, client: Client, album: Album):
|
||||||
|
client.force_login(baker.make(User, is_superuser=True))
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"name": album.name[: Album.NAME_MAX_LENGTH],
|
||||||
|
"parent": album.pk,
|
||||||
|
"date": localdate().strftime("%Y-%m-%d"),
|
||||||
|
}
|
||||||
|
response = client.post(
|
||||||
|
reverse("sas:album_edit", kwargs={"album_id": album.pk}), payload
|
||||||
|
)
|
||||||
|
assertInHTML("<li>Boucle dans l'arborescence des dossiers</li>", response.text)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"user",
|
||||||
|
[
|
||||||
|
lambda: baker.make(User, is_superuser=True),
|
||||||
|
lambda: baker.make(
|
||||||
|
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)]
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"parent",
|
||||||
|
[
|
||||||
|
lambda: baker.make(
|
||||||
|
Album, parent_id=settings.SITH_SAS_ROOT_DIR_ID, is_moderated=True
|
||||||
|
),
|
||||||
|
lambda: Album.objects.get(id=settings.SITH_SAS_ROOT_DIR_ID),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_update(
|
||||||
|
self,
|
||||||
|
client: Client,
|
||||||
|
album: Album,
|
||||||
|
sas_root: Album,
|
||||||
|
user: Callable[[], User],
|
||||||
|
parent: Callable[[], Album],
|
||||||
|
):
|
||||||
|
client.force_login(user())
|
||||||
|
expected_redirect = reverse("sas:album", kwargs={"album_id": album.pk})
|
||||||
|
payload = {
|
||||||
|
"name": album.name[: Album.NAME_MAX_LENGTH],
|
||||||
|
"parent": parent().id,
|
||||||
|
"date": localdate().strftime("%Y-%m-%d"),
|
||||||
|
"recursive": False,
|
||||||
|
}
|
||||||
|
response = client.post(
|
||||||
|
reverse("sas:album_edit", kwargs={"album_id": album.pk}), payload
|
||||||
|
)
|
||||||
|
assertRedirects(response, expected_redirect)
|
||||||
|
album.refresh_from_db()
|
||||||
|
assert album.name == payload["name"]
|
||||||
|
assert album.parent.id == payload["parent"]
|
||||||
|
assert localdate(album.date) == localdate()
|
||||||
|
|
||||||
|
|
||||||
class TestSasModeration(TestCase):
|
class TestSasModeration(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|||||||
+7
-1
@@ -85,7 +85,9 @@ class SASMainView(UseFragmentsMixin, TemplateView):
|
|||||||
kwargs["categories"] = list(
|
kwargs["categories"] = list(
|
||||||
albums_qs.filter(parent_id=settings.SITH_SAS_ROOT_DIR_ID).order_by("id")
|
albums_qs.filter(parent_id=settings.SITH_SAS_ROOT_DIR_ID).order_by("id")
|
||||||
)
|
)
|
||||||
kwargs["latest"] = list(albums_qs.order_by("-id")[:5])
|
kwargs["latest"] = list(
|
||||||
|
albums_qs.exclude(id=settings.SITH_SAS_ROOT_DIR_ID).order_by("-id")[:5]
|
||||||
|
)
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
@@ -126,6 +128,9 @@ def send_thumb(request, picture_id):
|
|||||||
|
|
||||||
class AlbumView(CanViewMixin, UseFragmentsMixin, DetailView):
|
class AlbumView(CanViewMixin, UseFragmentsMixin, DetailView):
|
||||||
model = Album
|
model = Album
|
||||||
|
# exclude the SAS from the album accessible with this view
|
||||||
|
# the SAS can be viewed only with SASMainView
|
||||||
|
queryset = Album.objects.exclude(id=settings.SITH_SAS_ROOT_DIR_ID)
|
||||||
pk_url_kwarg = "album_id"
|
pk_url_kwarg = "album_id"
|
||||||
template_name = "sas/album.jinja"
|
template_name = "sas/album.jinja"
|
||||||
|
|
||||||
@@ -262,6 +267,7 @@ class PictureAskRemovalView(CanViewMixin, DetailView, FormView):
|
|||||||
|
|
||||||
class AlbumEditView(CanEditMixin, UpdateView):
|
class AlbumEditView(CanEditMixin, UpdateView):
|
||||||
model = Album
|
model = Album
|
||||||
|
queryset = Album.objects.exclude(id=settings.SITH_SAS_ROOT_DIR_ID)
|
||||||
form_class = AlbumEditForm
|
form_class = AlbumEditForm
|
||||||
template_name = "core/edit.jinja"
|
template_name = "core/edit.jinja"
|
||||||
pk_url_kwarg = "album_id"
|
pk_url_kwarg = "album_id"
|
||||||
|
|||||||
Reference in New Issue
Block a user