mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-10 03:49:24 +00:00
@ -1,12 +1,13 @@
|
||||
import random
|
||||
from datetime import date, timedelta
|
||||
from datetime import timezone as tz
|
||||
from decimal import Decimal
|
||||
from typing import Iterator
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db.models import Exists, F, Min, OuterRef, Subquery, Sum
|
||||
from django.db.models import Count, Exists, F, Min, OuterRef, Subquery, Sum
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.utils.timezone import make_aware, now
|
||||
from faker import Faker
|
||||
@ -22,6 +23,7 @@ from counter.models import (
|
||||
Refilling,
|
||||
Selling,
|
||||
)
|
||||
from forum.models import Forum, ForumMessage, ForumTopic
|
||||
from pedagogy.models import UV
|
||||
from subscription.models import Subscription
|
||||
|
||||
@ -97,6 +99,8 @@ class Command(BaseCommand):
|
||||
self.create_sales(sellers)
|
||||
self.stdout.write("Creating permanences...")
|
||||
self.create_permanences(sellers)
|
||||
self.stdout.write("Filling the forum...")
|
||||
self.create_forums()
|
||||
|
||||
self.stdout.write("Done")
|
||||
|
||||
@ -288,7 +292,8 @@ class Command(BaseCommand):
|
||||
since=Subquery(
|
||||
Subscription.objects.filter(member__customer=OuterRef("pk"))
|
||||
.annotate(res=Min("subscription_start"))
|
||||
.values("res")[:1]
|
||||
.values("res")
|
||||
.order_by("res")[:1]
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -381,3 +386,72 @@ class Command(BaseCommand):
|
||||
)
|
||||
)
|
||||
Permanency.objects.bulk_create(perms)
|
||||
|
||||
def create_forums(self):
|
||||
forumers = random.sample(list(User.objects.all()), 100)
|
||||
most_actives = random.sample(forumers, 10)
|
||||
categories = list(Forum.objects.filter(is_category=True))
|
||||
new_forums = [
|
||||
Forum(name=self.faker.text(20), parent=random.choice(categories))
|
||||
for _ in range(15)
|
||||
]
|
||||
Forum.objects.bulk_create(new_forums)
|
||||
forums = list(Forum.objects.filter(is_category=False))
|
||||
new_topics = [
|
||||
ForumTopic(
|
||||
_title=self.faker.text(20),
|
||||
author=random.choice(most_actives),
|
||||
forum=random.choice(forums),
|
||||
)
|
||||
for _ in range(100)
|
||||
]
|
||||
ForumTopic.objects.bulk_create(new_topics)
|
||||
topics = list(ForumTopic.objects.all())
|
||||
|
||||
def get_author():
|
||||
if random.random() > 0.5:
|
||||
return random.choice(most_actives)
|
||||
return random.choice(forumers)
|
||||
|
||||
messages = []
|
||||
for t in topics:
|
||||
nb_messages = max(1, int(random.normalvariate(mu=90, sigma=50)))
|
||||
dates = sorted(
|
||||
[
|
||||
self.faker.date_time_between("-15y", "-1d", tzinfo=tz.utc)
|
||||
for _ in range(nb_messages)
|
||||
],
|
||||
reverse=True,
|
||||
)
|
||||
messages.extend(
|
||||
[
|
||||
ForumMessage(
|
||||
topic=t,
|
||||
author=get_author(),
|
||||
date=d,
|
||||
message="\n\n".join(
|
||||
self.faker.paragraphs(random.randint(1, 4))
|
||||
),
|
||||
)
|
||||
for d in dates
|
||||
]
|
||||
)
|
||||
ForumMessage.objects.bulk_create(messages)
|
||||
ForumTopic.objects.update(
|
||||
_message_number=Subquery(
|
||||
ForumMessage.objects.filter(topic_id=OuterRef("pk"))
|
||||
.values("topic_id")
|
||||
.annotate(res=Count("*"))
|
||||
.values("res")
|
||||
),
|
||||
_last_message_id=Subquery(
|
||||
ForumMessage.objects.order_by("-date").values("id")[:1]
|
||||
),
|
||||
)
|
||||
for f in Forum.objects.filter(parent__isnull=False):
|
||||
# this is a N+1 queries, but it's ok,
|
||||
# since there are quite a few forums
|
||||
# and trying to do it with a single query
|
||||
# would result in a big whibbly-woobly hacky queryset
|
||||
f.set_last_message()
|
||||
f.set_topic_number()
|
||||
|
@ -1256,165 +1256,6 @@ textarea {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/*------------------------------FORUM----------------------------------*/
|
||||
|
||||
#forum {
|
||||
.button {
|
||||
background-color: rgb(230, 230, 230);
|
||||
padding: 10px;
|
||||
font-weight: bold;
|
||||
border-radius: 5px;
|
||||
&:hover {
|
||||
background-color: rgb(211, 211, 211);
|
||||
}
|
||||
}
|
||||
.topic {
|
||||
border: solid $primary-neutral-color 1px;
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
p {
|
||||
margin: 1px;
|
||||
font-size: smaller;
|
||||
}
|
||||
a {
|
||||
color: $black-color;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.tools {
|
||||
font-size: x-small;
|
||||
border: none;
|
||||
font-weight: bold;
|
||||
a {
|
||||
padding: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: small;
|
||||
font-weight: bold;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.last_message date {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.last_message span {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.forum {
|
||||
background: $primary-neutral-light-color;
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
p {
|
||||
margin: 1px;
|
||||
font-size: smaller;
|
||||
}
|
||||
a {
|
||||
color: $black-color;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.search_bar {
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
.search_check {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.search_bouton {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.category {
|
||||
margin-top: 5px;
|
||||
background: $secondary-color;
|
||||
color: white;
|
||||
border-radius: 10px 10px 0 0;
|
||||
.title {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
background: $secondary-neutral-light-color;
|
||||
&:nth-child(odd) {
|
||||
background: $primary-neutral-light-color;
|
||||
}
|
||||
.title {
|
||||
font-size: 100%;
|
||||
}
|
||||
&.unread {
|
||||
background: #e9eea1;
|
||||
}
|
||||
}
|
||||
|
||||
.msg_author.deleted {
|
||||
background: #ffcfcf;
|
||||
}
|
||||
|
||||
.msg_content {
|
||||
&.deleted {
|
||||
background: #ffefef;
|
||||
}
|
||||
display: inline-block;
|
||||
width: 80%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.msg_author {
|
||||
display: inline-block;
|
||||
width: 19%;
|
||||
text-align: center;
|
||||
img {
|
||||
max-width: 70%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.msg_header {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.msg_meta {
|
||||
font-size: small;
|
||||
list-style-type: none;
|
||||
li {
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.forum_signature {
|
||||
color: hsl(0, 0%, 75%);
|
||||
border-top: 1px solid hsl(0, 0%, 75%);
|
||||
a {
|
||||
color: hsl(0, 0%, 75%);
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------FOOTER-------------------------------*/
|
||||
|
||||
footer {
|
||||
|
@ -11,6 +11,7 @@
|
||||
<link rel="stylesheet" href="{{ scss('core/markdown.scss') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/header.scss') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/navbar.scss') }}">
|
||||
<link rel="stylesheet" href="{{ scss('core/pagination.scss') }}">
|
||||
<link rel="stylesheet" href="{{ static('vendored/select2/select2.min.css') }}">
|
||||
|
||||
{% block jquery_css %}
|
||||
|
@ -156,27 +156,47 @@
|
||||
</nav>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro paginate(page_obj, paginator, js_action) %}
|
||||
{% set js = js_action|default('') %}
|
||||
{% if page_obj.has_previous() or page_obj.has_next() %}
|
||||
{% if page_obj.has_previous() %}
|
||||
<a {% if js %} type="submit" onclick="{{ js }}" {% endif %} href="?page={{ page_obj.previous_page_number() }}">{% trans %}Previous{% endtrans %}</a>
|
||||
{% macro paginate_jinja(current_page, paginator) %}
|
||||
{# Add pagination buttons for pages without Alpine.
|
||||
|
||||
This must be coupled with a view that handles pagination
|
||||
with the Django Paginator object.
|
||||
|
||||
Parameters:
|
||||
current_page (django.core.paginator.Page): the current page object
|
||||
paginator (django.core.paginator.Paginator): the paginator object
|
||||
#}
|
||||
<nav class="pagination">
|
||||
{% if current_page.has_previous() %}
|
||||
<a href="?page={{ current_page.previous_page_number() }}">
|
||||
<button>
|
||||
<i class="fa fa-caret-left"></i>
|
||||
</button>
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="disabled">{% trans %}Previous{% endtrans %}</span>
|
||||
<button disabled="disabled"><i class="fa fa-caret-left"></i></button>
|
||||
{% endif %}
|
||||
{% for i in paginator.page_range %}
|
||||
{% if page_obj.number == i %}
|
||||
<span class="active">{{ i }} <span class="sr-only">({% trans %}current{% endtrans %})</span></span>
|
||||
{% for i in paginator.get_elided_page_range(current_page.number) %}
|
||||
{% if i == current_page.number %}
|
||||
<button class="active">{{ i }}</button>
|
||||
{% elif i == paginator.ELLIPSIS %}
|
||||
<strong>{{ paginator.ELLIPSIS }}</strong>
|
||||
{% else %}
|
||||
<a {% if js %} type="submit" onclick="{{ js }}" {% endif %} href="?page={{ i }}">{{ i }}</a>
|
||||
<a href="?page={{ i }}">
|
||||
<button>{{ i }}</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if page_obj.has_next() %}
|
||||
<a {% if js %} type="submit" onclick="{{ js }}" {% endif %} href="?page={{ page_obj.next_page_number() }}">{% trans %}Next{% endtrans %}</a>
|
||||
{% if current_page.has_next() %}
|
||||
<a href="?page={{ current_page.next_page_number() }}">
|
||||
<button>
|
||||
<i class="fa fa-caret-right"></i>
|
||||
</button>
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="disabled">{% trans %}Next{% endtrans %}</span>
|
||||
<button disabled="disabled"><i class="fa fa-caret-right"></i></button>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro select_all_checkbox(form_id) %}
|
||||
|
Reference in New Issue
Block a user