Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 38 additions & 8 deletions club/templates/club/club_tools.jinja
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
{% extends "core/base.jinja" %}
{% from "reservation/macros.jinja" import room_detail %}

{% block additional_css %}
<link rel="stylesheet" href="{{ static("core/components/card.scss") }}">
{% endblock %}

{% block content %}
<h3>{% trans %}Club tools{% endtrans %}</h3>
<h3>{% trans %}Club tools{% endtrans %} ({{ club.name }})</h3>
<div>
<h4>{% trans %}Communication:{% endtrans %}</h4>
<ul>
Expand All @@ -19,18 +24,43 @@
<li><a href="{{ url("club:club_roles", club_id=object.id) }}"></a></li>
{% endif %}
{% if object.trombi %}
<li> <a href="{{ url('trombi:detail', trombi_id=object.trombi.id) }}">{% trans %}Edit Trombi{% endtrans %}</a></li>
<li>
<a href="{{ url('trombi:detail', trombi_id=object.trombi.id) }}">
{% trans %}Edit Trombi{% endtrans %}</a>
</li>
{% else %}
<li> <a href="{{ url('trombi:create', club_id=object.id) }}">{% trans %}New Trombi{% endtrans %}</a></li>
<li> <a href="{{ url('club:poster_list', club_id=object.id) }}">{% trans %}Posters{% endtrans %}</a></li>
<li><a href="{{ url('trombi:create', club_id=object.id) }}">{% trans %}New Trombi{% endtrans %}</a></li>
<li><a href="{{ url('club:poster_list', club_id=object.id) }}">{% trans %}Posters{% endtrans %}</a></li>
{% endif %}
</ul>
<h4>{% trans %}Reservable rooms{% endtrans %}</h4>
<a
href="{{ url("reservation:room_create") }}?club={{ object.id }}"
class="btn btn-blue"
>
{% trans %}Add a room{% endtrans %}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avec l'utilisateur krophil, président club.

Ptet un ptit check pour retirer le bouton si t'as pas les droits pour ajouter une salle

Image Image

</a>
{%- if reservable_rooms|length > 0 -%}
<ul class="card-group">
{%- for room in reservable_rooms -%}
{{ room_detail(
room,
can_edit=user.can_edit(room),
can_delete=request.user.has_perm("reservation.delete_room")
) }}
{%- endfor -%}
</ul>
{%- else -%}
<p>
{% trans %}This club manages no reservable room{% endtrans %}
</p>
{%- endif -%}
<h4>{% trans %}Counters:{% endtrans %}</h4>
<ul>
{% for c in object.counters.filter(type="OFFICE") %}
<li>{{ c }}:
<a href="{{ url('counter:details', counter_id=c.id) }}">View</a>
<a href="{{ url('counter:admin', counter_id=c.id) }}">Edit</a>
{% for counter in counters %}
<li>{{ counter }}:
<a href="{{ url('counter:details', counter_id=counter.id) }}">View</a>
<a href="{{ url('counter:admin', counter_id=counter.id) }}">Edit</a>
</li>
{% endfor %}
</ul>
Expand Down
6 changes: 6 additions & 0 deletions club/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ class ClubToolsView(ClubTabsMixin, CanEditMixin, DetailView):
template_name = "club/club_tools.jinja"
current_tab = "tools"

def get_context_data(self, **kwargs):
return super().get_context_data(**kwargs) | {
"reservable_rooms": list(self.object.reservable_rooms.all()),
"counters": list(self.object.counters.filter(type="OFFICE")),
}


class ClubAddMembersFragment(
FragmentMixin, PermissionRequiredMixin, SuccessMessageMixin, CreateView
Expand Down
1 change: 0 additions & 1 deletion com/static/com/css/news-list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@
font-size: 85%;

#links_content {
overflow: auto;
box-shadow: $shadow-color 1px 1px 1px;
min-height: 20em;
padding: 1em;
Expand Down
10 changes: 9 additions & 1 deletion com/templates/com/news_list.jinja
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{% extends "core/base.jinja" %}
{% from "com/macros.jinja" import news_moderation_alert %}

{% block title %}AE UTBM{% endblock %}

{% block additional_css %}
<link rel="stylesheet" href="{{ static('com/css/news-list.scss') }}">
<link rel="stylesheet" href="{{ static('com/components/ics-calendar.scss') }}">
<link rel="stylesheet" href="{{ static('core/components/calendar.scss') }}">

{# Atom feed discovery, not really css but also goes there #}
<link rel="alternate" type="application/rss+xml" title="{% trans %}News feed{% endtrans %}" href="{{ url("com:news_feed") }}">
Expand Down Expand Up @@ -213,6 +215,12 @@
<i class="fa-solid fa-magnifying-glass fa-xl"></i>
<a href="{{ url("matmat:search") }}">{% trans %}Matmatronch{% endtrans %}</a>
</li>
{% if user.has_perm("reservation.view_reservationslot") %}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mhh, ça a pas vraiment l'air de fonctionner cette histoire
J'ai connecté plusieurs users et on arrive juste sur une page pétée parce que l'api renvoie une 403 dessus

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perso, j'ai bien ça
image

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, j'ai trouvé, d'après le populate, tous les cotisants ont cette perm.
En prod ce sera le cas ou pas ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oui
Après, c'est comme toutes les autres perms de django, on peut choisir directement dans l'interface admin quels groupes ont quelles perms

<li>
<i class="fa-solid fa-thumbtack fa-xl"></i>
<a href="{{ url("reservation:main") }}">{% trans %}Room reservation{% endtrans %}</a>
</li>
{% endif %}
<li>
<i class="fa-solid fa-check-to-slot fa-xl"></i>
<a href="{{ url("election:list") }}">{% trans %}Elections{% endtrans %}</a>
Expand Down
6 changes: 5 additions & 1 deletion core/management/commands/populate.py
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,11 @@ def _create_groups(self) -> PopulatedGroups:

subscribers = Group.objects.create(name="Cotisants")
subscribers.permissions.add(
*list(perms.filter(codename__in=["add_news", "add_uecomment"]))
*list(
perms.filter(
codename__in=["add_news", "add_uecomment", "view_reservationslot"]
)
)
)
old_subscribers = Group.objects.create(name="Anciens cotisants")
old_subscribers.permissions.add(
Expand Down
136 changes: 102 additions & 34 deletions core/management/commands/populate_more.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import random
from datetime import date, timedelta
from datetime import timezone as tz
from math import ceil
from typing import Iterator

from dateutil.relativedelta import relativedelta
Expand All @@ -25,6 +26,7 @@
)
from forum.models import Forum, ForumMessage, ForumTopic
from pedagogy.models import UE
from reservation.models import ReservationSlot, Room
from subscription.models import Subscription


Expand All @@ -42,45 +44,20 @@ def handle(self, *args, **options):
self.stdout.write("Creating users...")
users = self.create_users()
self.create_bans(random.sample(users, k=len(users) // 200)) # 0.5% of users
# len(subscribers) is approximately 480
subscribers = random.sample(users, k=int(0.8 * len(users)))
self.stdout.write("Creating subscriptions...")
self.create_subscriptions(subscribers)
self.stdout.write("Creating club memberships...")
users_qs = User.objects.filter(id__in=[s.id for s in subscribers])
subscribers_now = list(
users_qs.annotate(
filter=Exists(
Subscription.objects.filter(
member_id=OuterRef("pk"), subscription_end__gte=now()
)
)
)
)
old_subscribers = list(
users_qs.annotate(
filter=Exists(
Subscription.objects.filter(
member_id=OuterRef("pk"), subscription_end__lt=now()
)
)
)
)
self.make_club(
Club.objects.get(id=settings.SITH_MAIN_CLUB_ID),
random.sample(subscribers_now, k=min(30, len(subscribers_now))),
random.sample(old_subscribers, k=min(60, len(old_subscribers))),
)
self.make_club(
Club.objects.get(name="Troll Penché"),
random.sample(subscribers_now, k=min(20, len(subscribers_now))),
random.sample(old_subscribers, k=min(80, len(old_subscribers))),
)
self.create_club_memberships(subscribers)
self.stdout.write("Creating rooms and reservation...")
self.create_resources_and_reservations(random.sample(subscribers, k=40))
self.stdout.write("Creating uvs...")
self.create_ues()
self.stdout.write("Creating products...")
self.create_products()
self.stdout.write("Creating sales and refills...")
sellers = random.sample(list(User.objects.all()), 100)
sellers = list(User.objects.order_by("?")[:100])
self.create_sales(sellers)
self.stdout.write("Creating permanences...")
self.create_permanences(sellers)
Expand Down Expand Up @@ -215,6 +192,97 @@ def zip_roles(users: list[User]) -> Iterator[tuple[User, ClubRole]]:
memberships = Membership.objects.bulk_create(memberships)
Membership._add_club_groups(memberships)

def create_club_memberships(self, users: list[User]):
users_qs = User.objects.filter(id__in=[s.id for s in users])
subscribers_now = list(
users_qs.annotate(
filter=Exists(
Subscription.objects.filter(
member_id=OuterRef("pk"), subscription_end__gte=now()
)
)
)
)
old_subscribers = list(
users_qs.annotate(
filter=Exists(
Subscription.objects.filter(
member_id=OuterRef("pk"), subscription_end__lt=now()
)
)
)
)
self.make_club(
Club.objects.get(id=settings.SITH_MAIN_CLUB_ID),
random.sample(subscribers_now, k=min(30, len(subscribers_now))),
random.sample(old_subscribers, k=min(60, len(old_subscribers))),
)
self.make_club(
Club.objects.get(name="Troll Penché"),
random.sample(subscribers_now, k=min(20, len(subscribers_now))),
random.sample(old_subscribers, k=min(80, len(old_subscribers))),
)

def create_resources_and_reservations(self, users: list[User]):
"""Generate reservable rooms and reservations slots for those rooms.

Contrary to the other data generator,
this one generates more data than what is expected on the real db.
"""
ae = Club.objects.get(id=settings.SITH_MAIN_CLUB_ID)
pdf = Club.objects.get(id=settings.SITH_PDF_CLUB_ID)
troll = Club.objects.get(name="Troll Penché")
rooms = [
Room(
name=name,
club=club,
location=location,
description=self.faker.text(100),
)
for name, club, location in [
("Champi", ae, "BELFORT"),
("Muzik", ae, "BELFORT"),
("Pôle Tech", ae, "BELFORT"),
("Jolly", troll, "BELFORT"),
("Cookut", pdf, "BELFORT"),
("Lucky", pdf, "BELFORT"),
("Potards", pdf, "SEVENANS"),
("Bureau AE", ae, "SEVENANS"),
]
]
rooms = Room.objects.bulk_create(rooms)
reservations = []
for room in rooms:
# how much people use this room.
# The higher the number, the more reservations exist,
# the smaller the interval between two slot is,
# and the more future reservations have already been made ahead of time
affluence = random.randint(2, 6)
slot_start = make_aware(self.faker.past_datetime("-5y").replace(minute=0))
generate_until = make_aware(
self.faker.future_datetime(timedelta(days=1) * affluence**2)
)
while slot_start < generate_until:
if slot_start.hour < 8:
# if a reservation would start in the middle of the night
# make it start the next morning instead
slot_start += timedelta(hours=10 - slot_start.hour)
duration = timedelta(minutes=15) * (1 + int(random.gammavariate(3, 2)))
reservations.append(
ReservationSlot(
room=room,
author=random.choice(users),
start_at=slot_start,
end_at=slot_start + duration,
created_at=slot_start - self.faker.time_delta("+7d"),
)
)
slot_start += duration + (
timedelta(minutes=15) * ceil(random.expovariate(affluence / 192))
)
reservations.sort(key=lambda slot: slot.created_at)
ReservationSlot.objects.bulk_create(reservations)

def create_ues(self):
root = User.objects.get(username="root")
categories = ["CS", "TM", "OM", "QC", "EC"]
Expand Down Expand Up @@ -415,7 +483,7 @@ def create_permanences(self, sellers: list[User]):
Permanency.objects.bulk_create(perms)

def create_forums(self):
forumers = random.sample(list(User.objects.all()), 100)
forumers = list(User.objects.order_by("?")[:100])
most_actives = random.sample(forumers, 10)
categories = list(Forum.objects.filter(is_category=True))
new_forums = [
Expand All @@ -433,15 +501,15 @@ def create_forums(self):
for _ in range(100)
]
ForumTopic.objects.bulk_create(new_topics)
topics = list(ForumTopic.objects.all())
topics = list(ForumTopic.objects.values_list("id", flat=True))

def get_author():
if random.random() > 0.5:
return random.choice(most_actives)
return random.choice(forumers)

messages = []
for t in topics:
for topic_id in topics:
nb_messages = max(1, int(random.normalvariate(mu=90, sigma=50)))
dates = sorted(
[
Expand All @@ -453,7 +521,7 @@ def get_author():
messages.extend(
[
ForumMessage(
topic=t,
topic_id=topic_id,
author=get_author(),
date=d,
message="\n\n".join(
Expand Down
4 changes: 3 additions & 1 deletion core/static/bundled/base-bundle-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
* for more efficient tree-shaking and gzip compression.
*/

import { morph } from "@alpinejs/morph";
import sort from "@alpinejs/sort";
import Alpine from "alpinejs";
import { polyfillCountryFlagEmojis } from "country-flag-emoji-polyfill";
import htmx from "htmx.org";
import "htmx-ext-alpine-morph";
import { limitedChoices } from "#core:alpine/limited-choices";
import { expireOldStorage } from "#core:core/localstorage";
import { default as navbar } from "#core:core/navbar";
Expand All @@ -27,7 +29,7 @@ declare module "alpinejs" {
}
}

Alpine.plugin([sort, limitedChoices, notifications]);
Alpine.plugin([sort, limitedChoices, morph, notifications]);
// biome-ignore lint/style/useNamingConvention: it's how it's named
Object.assign(window, { Alpine });

Expand Down
Loading
Loading