mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-22 06:03:20 +00:00
start of work
This commit is contained in:
parent
0270fb764e
commit
cbbbdc4bbf
@ -529,13 +529,15 @@ class User(AbstractBaseUser):
|
||||
return False
|
||||
|
||||
@cached_property
|
||||
def can_create_subscription(self):
|
||||
from club.models import Club
|
||||
def can_create_subscription(self) -> bool:
|
||||
from club.models import Membership
|
||||
|
||||
for club in Club.objects.filter(id__in=settings.SITH_CAN_CREATE_SUBSCRIPTIONS):
|
||||
if club in self.clubs_with_rights:
|
||||
return True
|
||||
return False
|
||||
return (
|
||||
Membership.objects.board()
|
||||
.ongoing()
|
||||
.filter(club_id__in=settings.SITH_CAN_CREATE_SUBSCRIPTIONS)
|
||||
.exists()
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def is_launderette_manager(self):
|
||||
|
@ -1,3 +1,4 @@
|
||||
import "htmx-ext-response-targets/response-targets";
|
||||
import htmx from "htmx.org";
|
||||
|
||||
Object.assign(window, { htmx });
|
||||
|
@ -406,7 +406,7 @@ class Galaxy(models.Model):
|
||||
cls.logger.debug(f"\t\t> Scaled distance: {value}")
|
||||
return int(value)
|
||||
|
||||
def rule(self, picture_count_threshold=10) -> None:
|
||||
def rule(self, picture_count_threshold=-1) -> None:
|
||||
"""Main function of the Galaxy.
|
||||
|
||||
Iterate over all the rulable users to promote them to citizens.
|
||||
|
6
package-lock.json
generated
6
package-lock.json
generated
@ -22,6 +22,7 @@
|
||||
"d3-force-3d": "^3.0.5",
|
||||
"easymde": "^2.18.0",
|
||||
"glob": "^11.0.0",
|
||||
"htmx-ext-response-targets": "^2.0.1",
|
||||
"htmx.org": "^2.0.3",
|
||||
"jquery": "^3.7.1",
|
||||
"jquery-ui": "^1.14.0",
|
||||
@ -4140,6 +4141,11 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/htmx-ext-response-targets": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/htmx-ext-response-targets/-/htmx-ext-response-targets-2.0.1.tgz",
|
||||
"integrity": "sha512-uCMw098+0xcrs7UW/s8l8hqj5wfOaVnVV7286cS+TNMNguo8fQpi/PEaZuT4VUysIiRcjj4pcTkuaP6Q9iJ3XA=="
|
||||
},
|
||||
"node_modules/htmx.org": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.3.tgz",
|
||||
|
@ -14,7 +14,9 @@
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "GPL-3.0-only",
|
||||
"sideEffects": [".css"],
|
||||
"sideEffects": [
|
||||
".css"
|
||||
],
|
||||
"imports": {
|
||||
"#openapi": "./staticfiles/generated/openapi/index.ts",
|
||||
"#core:*": "./core/static/bundled/*",
|
||||
@ -47,6 +49,7 @@
|
||||
"easymde": "^2.18.0",
|
||||
"glob": "^11.0.0",
|
||||
"htmx.org": "^2.0.3",
|
||||
"htmx-ext-response-targets": "^2.0.1",
|
||||
"jquery": "^3.7.1",
|
||||
"jquery-ui": "^1.14.0",
|
||||
"jquery.shorten": "^1.0.0",
|
||||
|
@ -1,9 +1,6 @@
|
||||
from pydantic import TypeAdapter
|
||||
|
||||
from core.views.widgets.select import (
|
||||
AutoCompleteSelect,
|
||||
AutoCompleteSelectMultiple,
|
||||
)
|
||||
from core.views.widgets.select import AutoCompleteSelect, AutoCompleteSelectMultiple
|
||||
from sas.models import Album
|
||||
from sas.schemas import AlbumSchema
|
||||
|
||||
|
@ -5,7 +5,7 @@ from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from core.models import User
|
||||
from core.views.forms import SelectDate, SelectDateTime
|
||||
from core.views.forms import SelectDateTime
|
||||
from core.views.widgets.select import AutoCompleteSelectUser
|
||||
from subscription.models import Subscription
|
||||
|
||||
@ -21,37 +21,15 @@ class SelectionDateForm(forms.Form):
|
||||
)
|
||||
|
||||
|
||||
class SubscriptionForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Subscription
|
||||
fields = ["member", "subscription_type", "payment_method", "location"]
|
||||
widgets = {"member": AutoCompleteSelectUser}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["member"].required = False
|
||||
self.fields |= forms.fields_for_model(
|
||||
User,
|
||||
fields=["first_name", "last_name", "email", "date_of_birth"],
|
||||
widgets={"date_of_birth": SelectDate},
|
||||
)
|
||||
|
||||
def clean_member(self):
|
||||
subscriber = self.cleaned_data.get("member")
|
||||
if subscriber:
|
||||
subscriber = User.objects.filter(id=subscriber.id).first()
|
||||
return subscriber
|
||||
|
||||
class SubscriptionNewUserForm(forms.Form):
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
if (
|
||||
cleaned_data.get("member") is None
|
||||
and "last_name" not in self.errors.as_data()
|
||||
"last_name" not in self.errors.as_data()
|
||||
and "first_name" not in self.errors.as_data()
|
||||
and "email" not in self.errors.as_data()
|
||||
and "date_of_birth" not in self.errors.as_data()
|
||||
):
|
||||
self.errors.pop("member", None)
|
||||
if self.errors:
|
||||
return cleaned_data
|
||||
if User.objects.filter(email=cleaned_data.get("email")).first() is not None:
|
||||
@ -70,19 +48,17 @@ class SubscriptionForm(forms.ModelForm):
|
||||
u.set_password(str(random.randrange(1000000, 10000000)))
|
||||
u.save()
|
||||
cleaned_data["member"] = u
|
||||
elif cleaned_data.get("member") is not None:
|
||||
self.errors.pop("last_name", None)
|
||||
self.errors.pop("first_name", None)
|
||||
self.errors.pop("email", None)
|
||||
self.errors.pop("date_of_birth", None)
|
||||
if cleaned_data.get("member") is None:
|
||||
# This should be handled here,
|
||||
# but it is done in the Subscription model's clean method
|
||||
# TODO investigate why!
|
||||
raise ValidationError(
|
||||
_(
|
||||
"You must either choose an existing "
|
||||
"user or create a new one properly"
|
||||
)
|
||||
)
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class SubscriptionForm(forms.ModelForm):
|
||||
"""Form to add a subscription to an existing user."""
|
||||
|
||||
template_name = "subscription/fragments/existing_user_form.html"
|
||||
|
||||
class Meta:
|
||||
model = Subscription
|
||||
fields = ["member", "subscription_type", "payment_method", "location"]
|
||||
widgets = {"member": AutoCompleteSelectUser}
|
||||
|
||||
def clean_subscription_type(self):
|
||||
raise ValidationError("ptdr non")
|
||||
|
@ -0,0 +1,12 @@
|
||||
{#<form#}
|
||||
{# hx-post="{{ url("subscription:subscription-fragment-existing-user") }}"#}
|
||||
{# hx-swap="innerHTML"#}
|
||||
{# hx-target="#existing-user-subscription-form-fields"#}
|
||||
{# id="existing-user-subscription-form"#}
|
||||
{#>#}
|
||||
{# {% csrf_token %}#}
|
||||
{# <div id="existing-user-subscription-form-fields">#}
|
||||
{{ form.as_div }}
|
||||
{# </div>#}
|
||||
{# <input type="submit" value="{% trans %}Save{% endtrans %}">#}
|
||||
{#</form>#}
|
@ -4,59 +4,65 @@
|
||||
{% trans %}New subscription{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{# The following statics are bundled with our autocomplete select.
|
||||
However, if one tries to swap a form by another, then the urls in script-once
|
||||
and link-once disappear.
|
||||
So we give them here.
|
||||
If the aforementioned bug is resolved, you can remove this. #}
|
||||
{% block additional_js %}
|
||||
<script defer src="{{ static("webpack/core/components/ajax-select-index.ts") }}"></script>
|
||||
{% endblock %}
|
||||
{% block additional_css %}
|
||||
<link rel="stylesheet" href="{{ static("webpack/core/components/ajax-select-index.css") }}">
|
||||
<link rel="stylesheet" href="{{ static("core/components/ajax-select.scss") }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans %}New subscription{% endtrans %}</h3>
|
||||
<div id="user_info"></div>
|
||||
<form action="" method="post" id="subscription_form">
|
||||
<div id="subscription-form" x-data="{existing_member: true}" hx-ext="response-targets">
|
||||
<form
|
||||
hx-post="{{ url("subscription:subscription-fragment-existing-user") }}"
|
||||
hx-swap="innerHTML"
|
||||
hx-target-2*="#user_infos"
|
||||
hx-target-3*="#user_infos"
|
||||
hx-disabled-elt="find input[type='submit']"
|
||||
id="existing-user-subscription-form"
|
||||
>
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors() }}
|
||||
<p>{{ form.member.errors }}<label for="{{ form.member.name }}">{{ form.member.label }}</label> {{ form.member }}</p>
|
||||
<div id="new_member">
|
||||
<p>{{ form.first_name.errors }}<label for="{{ form.first_name.name }}">{{ form.first_name.label }}</label> {{ form.first_name }}</p>
|
||||
<p>{{ form.last_name.errors }}<label for="{{ form.last_name.name }}">{{ form.last_name.label }}</label> {{ form.last_name }}</p>
|
||||
<p>{{ form.email.errors }}<label for="{{ form.email.name }}">{{ form.email.label }}</label> {{ form.email }}</p>
|
||||
<p>{{ form.date_of_birth.errors }}<label for="{{ form.date_of_birth.name }}">{{ form.date_of_birth.label}}</label> {{ form.date_of_birth }}</p>
|
||||
<div id="existing-user-subscription-form-fields">
|
||||
{{ existing_user_form }}
|
||||
</div>
|
||||
<p>{{ form.subscription_type.errors }}<label for="{{ form.subscription_type.name }}">{{ form.subscription_type.label }}</label> {{ form.subscription_type }}</p>
|
||||
<p>{{ form.payment_method.errors }}<label for="{{ form.payment_method.name }}">{{ form.payment_method.label }}</label> {{
|
||||
form.payment_method }}</p>
|
||||
<p>{% trans %}Eboutic is reserved to specific users. In doubt, don't use it.{% endtrans %}</p>
|
||||
<p>{{ form.location.errors }}<label for="{{ form.location.name }}">{{ form.location.label }}</label> {{ form.location }}</p>
|
||||
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
|
||||
<input type="submit" value="{% trans %}Save{% endtrans %}">
|
||||
</form>
|
||||
</div>
|
||||
{# <template x-if="!$refs.member_search?.widget?.items?.length">#}
|
||||
{# <div id="new-member" @click="console.log($refs.member_search.widget.items)">#}
|
||||
{# <p>#}
|
||||
{# {{ existing_user_form.first_name.errors }}#}
|
||||
{# <label for="{{ existing_user_form.first_name.name }}">{{ existing_user_form.first_name.label }}</label>#}
|
||||
{# {{ existing_user_form.first_name }}#}
|
||||
{# </p>#}
|
||||
{# <p>#}
|
||||
{# {{ existing_user_form.last_name.errors }}#}
|
||||
{# <label for="{{ existing_user_form.last_name.name }}">{{ existing_user_form.last_name.label }}</label>#}
|
||||
{# {{ existing_user_form.last_name }}#}
|
||||
{# </p>#}
|
||||
{# <p>#}
|
||||
{# {{ existing_user_form.email.errors }}#}
|
||||
{# <label for="{{ existing_user_form.email.name }}">{{ existing_user_form.email.label }}</label>#}
|
||||
{# {{ existing_user_form.email }}#}
|
||||
{# </p>#}
|
||||
{# <p>#}
|
||||
{# {{ existing_user_form.date_of_birth.errors }}#}
|
||||
{# <label for="{{ existing_user_form.date_of_birth.name }}">{{ existing_user_form.date_of_birth.label}}</label>#}
|
||||
{# {{ existing_user_form.date_of_birth }}#}
|
||||
{# </p>#}
|
||||
{# </div>#}
|
||||
{# </template>#}
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
$( function() {
|
||||
select = $("#id_member");
|
||||
member_block = $("#subscription_form #new_member");
|
||||
user_info = $("#user_info");
|
||||
function display_new_member() {
|
||||
if (select.val()) {
|
||||
member_block.hide();
|
||||
member_block.children().each(function() {
|
||||
$(this).children().each(function() {
|
||||
$(this).removeAttr('required');
|
||||
});
|
||||
});
|
||||
user_info.load("/user/"+select.val()+"/mini");
|
||||
user_info.show();
|
||||
} else {
|
||||
member_block.show();
|
||||
member_block.children().each(function() {
|
||||
$(this).children().each(function() {
|
||||
$(this).prop('required', true);
|
||||
});
|
||||
});
|
||||
|
||||
user_info.empty();
|
||||
user_info.hide();
|
||||
}
|
||||
}
|
||||
select.on("change", display_new_member);
|
||||
display_new_member();
|
||||
} );
|
||||
</script>
|
||||
{% endblock %}
|
||||
{#{% block script %}#}
|
||||
{# {{ super() }}#}
|
||||
{##}
|
||||
{#{% endblock %}#}
|
||||
|
@ -15,10 +15,19 @@
|
||||
|
||||
from django.urls import path
|
||||
|
||||
from subscription.views import NewSubscription, SubscriptionsStatsView
|
||||
from subscription.views import (
|
||||
CreateSubscriptionExistingUserFragment,
|
||||
NewSubscription,
|
||||
SubscriptionsStatsView,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
# Subscription views
|
||||
path("", NewSubscription.as_view(), name="subscription"),
|
||||
path(
|
||||
"existing-user/",
|
||||
CreateSubscriptionExistingUserFragment.as_view(),
|
||||
name="subscription-fragment-existing-user",
|
||||
),
|
||||
path("stats/", SubscriptionsStatsView.as_view(), name="stats"),
|
||||
]
|
||||
|
@ -13,85 +13,96 @@
|
||||
#
|
||||
#
|
||||
|
||||
import secrets
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import HttpResponse
|
||||
from django.urls import reverse_lazy
|
||||
from django.views.generic.edit import CreateView, FormView
|
||||
from django.utils.timezone import localdate
|
||||
from django.views.generic import TemplateView
|
||||
from django.views.generic.edit import FormView
|
||||
|
||||
from subscription.forms import SelectionDateForm, SubscriptionForm
|
||||
from subscription.forms import (
|
||||
SelectionDateForm,
|
||||
SubscriptionForm,
|
||||
SubscriptionNewUserForm,
|
||||
)
|
||||
from subscription.models import Subscription
|
||||
|
||||
|
||||
class NewSubscription(CreateView):
|
||||
class CanCreateSubscriptionMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
return self.request.user.can_create_subscription
|
||||
|
||||
|
||||
class NewSubscription(CanCreateSubscriptionMixin, TemplateView):
|
||||
template_name = "subscription/subscription.jinja"
|
||||
form_class = SubscriptionForm
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
if request.user.can_create_subscription:
|
||||
return super().dispatch(request, *arg, **kwargs)
|
||||
raise PermissionDenied
|
||||
|
||||
def get_initial(self):
|
||||
if "member" in self.request.GET:
|
||||
return {
|
||||
"member": self.request.GET["member"],
|
||||
"subscription_type": "deux-semestres",
|
||||
def get_context_data(self, **kwargs):
|
||||
return super().get_context_data(**kwargs) | {
|
||||
"existing_user_form": SubscriptionForm(),
|
||||
"new_user_form": SubscriptionNewUserForm(),
|
||||
}
|
||||
return {"subscription_type": "deux-semestres"}
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.subscription_start = Subscription.compute_start(
|
||||
duration=settings.SITH_SUBSCRIPTIONS[form.instance.subscription_type][
|
||||
"duration"
|
||||
],
|
||||
user=form.instance.member,
|
||||
)
|
||||
form.instance.subscription_end = Subscription.compute_end(
|
||||
duration=settings.SITH_SUBSCRIPTIONS[form.instance.subscription_type][
|
||||
"duration"
|
||||
],
|
||||
start=form.instance.subscription_start,
|
||||
user=form.instance.member,
|
||||
)
|
||||
return super().form_valid(form)
|
||||
|
||||
class CreateSubscriptionExistingUserFragment(CanCreateSubscriptionMixin, FormView):
|
||||
"""Create a subscription for a user who already exists."""
|
||||
|
||||
form_class = SubscriptionForm
|
||||
success_url = reverse_lazy("subscription:subscription-fragment-existing-user")
|
||||
|
||||
def render_to_response(self, context, **response_kwargs):
|
||||
print(context["form"])
|
||||
print(str(context["form"]))
|
||||
print(context["form"].render())
|
||||
return HttpResponse(context["form"].render(), **response_kwargs)
|
||||
|
||||
# def dispatch(self, request, *args, **kwargs):
|
||||
# s = SubscriptionForm()
|
||||
# print(s)
|
||||
# return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
# def form_valid(self, form):
|
||||
# duration = settings.SITH_SUBSCRIPTIONS[form.instance.subscription_type][
|
||||
# "duration"
|
||||
# ]
|
||||
# form.instance.subscription_start = Subscription.compute_start(
|
||||
# duration=duration, user=form.instance.member
|
||||
# )
|
||||
# form.instance.subscription_end = Subscription.compute_end(
|
||||
# duration=duration,
|
||||
# start=form.instance.subscription_start,
|
||||
# user=form.instance.member,
|
||||
# )
|
||||
# return super().form_valid(form)
|
||||
|
||||
|
||||
class SubscriptionsStatsView(FormView):
|
||||
template_name = "subscription/stats.jinja"
|
||||
form_class = SelectionDateForm
|
||||
success_url = reverse_lazy("subscriptions:stats")
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
import datetime
|
||||
|
||||
self.start_date = datetime.datetime.today()
|
||||
self.start_date = localdate()
|
||||
self.end_date = self.start_date
|
||||
res = super().dispatch(request, *arg, **kwargs)
|
||||
if request.user.is_root or request.user.is_board_member:
|
||||
return res
|
||||
return super().dispatch(request, *arg, **kwargs)
|
||||
raise PermissionDenied
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.form = self.get_form()
|
||||
self.start_date = self.form["start_date"]
|
||||
self.end_date = self.form["end_date"]
|
||||
res = super().post(request, *args, **kwargs)
|
||||
if request.user.is_root or request.user.is_board_member:
|
||||
return res
|
||||
raise PermissionDenied
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
def get_initial(self):
|
||||
init = {
|
||||
return {
|
||||
"start_date": self.start_date.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"end_date": self.end_date.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
return init
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
from subscription.models import Subscription
|
||||
|
||||
kwargs = super().get_context_data(**kwargs)
|
||||
kwargs["subscriptions_total"] = Subscription.objects.filter(
|
||||
subscription_end__gte=self.end_date, subscription_start__lte=self.start_date
|
||||
@ -100,6 +111,3 @@ class SubscriptionsStatsView(FormView):
|
||||
kwargs["payment_types"] = settings.SITH_COUNTER_PAYMENT_METHOD
|
||||
kwargs["locations"] = settings.SITH_SUBSCRIPTION_LOCATIONS
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
return reverse_lazy("subscriptions:stats")
|
||||
|
@ -85,6 +85,7 @@ export default {
|
||||
inject({
|
||||
// biome-ignore lint/style/useNamingConvention: that's how it's called
|
||||
Alpine: "alpinejs",
|
||||
htmx: "htmx.org"
|
||||
}),
|
||||
viteStaticCopy({
|
||||
targets: [
|
||||
|
Loading…
Reference in New Issue
Block a user