Nice user interface and permission rework

This commit is contained in:
Antoine Bartuccio 2018-10-19 19:25:55 +02:00
parent 4669e5a4e9
commit 616b7ccfc8
Signed by: klmp200
GPG Key ID: E7245548C53F904B
6 changed files with 143 additions and 19 deletions

View File

@ -22,6 +22,24 @@
<p>{% trans trombi=user.trombi_user.trombi %}You already choose to be in that Trombi: {{ trombi }}.{% endtrans %} <p>{% trans trombi=user.trombi_user.trombi %}You already choose to be in that Trombi: {{ trombi }}.{% endtrans %}
<a href="{{ url('trombi:user_tools') }}">{% trans %}Go to my Trombi tools{% endtrans %}</a></p> <a href="{{ url('trombi:user_tools') }}">{% trans %}Go to my Trombi tools{% endtrans %}</a></p>
{% endif %} {% endif %}
{% if profile.customer %}
<h4>{% trans %}Student cards{% endtrans %}</h4>
<p>{% trans %}You can add a card by asking at a counter or add it yourself here. If you want to manually add a student card yourself, you'll need a NFC reader. We store the UID of the card which is 14 characters long.{% endtrans %}</p>
<form action="{{ url('counter:add_student_card', customer_id=profile.customer.pk) }}" method="post">
{% csrf_token %}
{{ student_card_form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form>
{% if profile.customer.student_cards.exists() %}
<ul>
{% for card in profile.customer.student_cards.all() %}
<li>{{ card.uid }} - <a href="{{ url('counter:delete_student_card', customer_id=profile.customer.pk, card_id=card.id) }}">{% trans %}Delete{% endtrans %}</a></li>
{% endfor %}
</ul>
{% else %}
<p>{% trans %}No student cards registered.{% endtrans %}</p>
{% endif %}
{% endif %}
{% endblock %} {% endblock %}

View File

@ -64,6 +64,7 @@ from core.views.forms import (
) )
from core.models import User, SithFile, Preferences, Gift from core.models import User, SithFile, Preferences, Gift
from subscription.models import Subscription from subscription.models import Subscription
from counter.views import StudentCardForm
from trombi.views import UserTrombiForm from trombi.views import UserTrombiForm
@ -741,6 +742,8 @@ class UserPreferencesView(UserTabsMixin, CanEditMixin, UpdateView):
kwargs = super(UserPreferencesView, self).get_context_data(**kwargs) kwargs = super(UserPreferencesView, self).get_context_data(**kwargs)
if not hasattr(self.object, "trombi_user"): if not hasattr(self.object, "trombi_user"):
kwargs["trombi_form"] = UserTrombiForm() kwargs["trombi_form"] = UserTrombiForm()
if self.object.customer:
kwargs["student_card_form"] = StudentCardForm()
return kwargs return kwargs

View File

@ -91,22 +91,7 @@ class Customer(models.Model):
""" """
Add a new student card on the customer account Add a new student card on the customer account
""" """
# If you are comming from a counter, only your connection to the counter is checked, not your right on the user to avoid wierd conflicts if not StudentCard.check_creation_permission(request, self, counter):
if counter != None and (
counter.type != "BAR"
or not (
"counter_token" in request.session.keys()
and request.session["counter_token"] == counter.token
)
or len(counter.get_barmen_list()) < 1
):
raise PermissionDenied
# If you are not comming from a counter, your permissions are checked
if not (
request.user.id == self.user.id
or request.user.is_board_member
or request.user.is_root
):
raise PermissionDenied raise PermissionDenied
StudentCard(customer=self, uid=uid).save() StudentCard(customer=self, uid=uid).save()
@ -769,6 +754,38 @@ class StudentCard(models.Model):
UID_SIZE = 14 UID_SIZE = 14
@staticmethod
def is_valid(uid):
return len(uid) == StudentCard.UID_SIZE
@staticmethod
def __comming_from_right_counter(request, counter):
return (
counter.type == "BAR"
and "counter_token" in request.session.keys()
and request.session["counter_token"] == counter.token
and len(counter.get_barmen_list()) > 0
)
@staticmethod
def __user_has_rights(customer, user):
return user.pk == customer.user.pk or user.is_board_member or user.is_root
@staticmethod
def check_creation_permission(request, customer, counter=None):
"""
If you are comming from a counter, only your connection to the counter is checked, not your right on the user to avoid wierd conflicts
If you are not comming from a counter, your permissions are checked
"""
if counter:
return StudentCard.__comming_from_right_counter(request, counter)
return StudentCard.__user_has_rights(customer, request.user)
def can_edit(self, obj):
if isinstance(obj, User):
return StudentCard.__user_has_rights(self.customer, obj)
return False
uid = models.CharField( uid = models.CharField(
_("uid"), max_length=14, unique=True, validators=[MinLengthValidator(4)] _("uid"), max_length=14, unique=True, validators=[MinLengthValidator(4)]
) )

View File

@ -40,6 +40,16 @@
{% endif %} {% endif %}
<input type="submit" value="{% trans %}Go{% endtrans %}" /> <input type="submit" value="{% trans %}Go{% endtrans %}" />
</form> </form>
<h6>{% trans %}Registered cards{% endtrans %}</h6>
{% if customer.student_cards.exists() %}
<ul>
{% for card in customer.student_cards.all() %}
<li>{{ card.uid }}</li>
{% endfor %}
</ul>
{% else %}
{% trans %}No card registered{% endtrans %}
{% endif %}
</div> </div>
<div id="bar_ui"> <div id="bar_ui">
<h5>{% trans %}Selling{% endtrans %}</h5> <h5>{% trans %}Selling{% endtrans %}</h5>

View File

@ -56,6 +56,16 @@ urlpatterns = [
EticketPDFView.as_view(), EticketPDFView.as_view(),
name="eticket_pdf", name="eticket_pdf",
), ),
url(
r"^customer/(?P<customer_id>[0-9]+)/card/add$",
StudentCardFormView.as_view(),
name="add_student_card",
),
url(
r"^customer/(?P<customer_id>[0-9]+)/card/delete/(?P<card_id>[0-9]+)/$",
StudentCardDeleteView.as_view(),
name="delete_student_card",
),
url(r"^admin/(?P<counter_id>[0-9]+)$", CounterEditView.as_view(), name="admin"), url(r"^admin/(?P<counter_id>[0-9]+)$", CounterEditView.as_view(), name="admin"),
url( url(
r"^admin/(?P<counter_id>[0-9]+)/prop$", r"^admin/(?P<counter_id>[0-9]+)/prop$",

View File

@ -33,6 +33,7 @@ from django.views.generic.edit import (
DeleteView, DeleteView,
ProcessFormView, ProcessFormView,
FormMixin, FormMixin,
FormView,
) )
from django.forms.models import modelform_factory from django.forms.models import modelform_factory
from django.forms import CheckboxSelectMultiple from django.forms import CheckboxSelectMultiple
@ -50,7 +51,7 @@ from datetime import date, timedelta, datetime
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
from ajax_select import make_ajax_field from ajax_select import make_ajax_field
from core.views import CanViewMixin, TabedViewMixin from core.views import CanViewMixin, TabedViewMixin, CanEditMixin
from core.views.forms import LoginForm, SelectDate, SelectDateTime from core.views.forms import LoginForm, SelectDate, SelectDateTime
from core.models import User from core.models import User
from subscription.models import Subscription from subscription.models import Subscription
@ -100,6 +101,45 @@ class CounterAdminMixin(View):
return super(CounterAdminMixin, self).dispatch(request, *args, **kwargs) return super(CounterAdminMixin, self).dispatch(request, *args, **kwargs)
class StudentCardForm(forms.ModelForm):
"""
Form for adding student cards
Only used for user profile since CounterClick is to complicated
"""
class Meta:
model = StudentCard
fields = ["uid"]
def clean(self):
cleaned_data = super(StudentCardForm, self).clean()
uid = cleaned_data.get("uid")
if not StudentCard.is_valid(uid):
raise forms.ValidationError(_("This uid is invalid"), code="invalid")
return cleaned_data
class StudentCardDeleteView(DeleteView):
"""
View used to delete a card from a user
"""
model = StudentCard
template_name = "core/delete_confirm.jinja"
pk_url_kwarg = "card_id"
def dispatch(self, request, *args, **kwargs):
self.customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
if not self.get_object().can_edit(self.customer.user):
raise PermissionDenied
return super(StudentCardDeleteView, self).dispatch(request, *args, **kwargs)
def get_success_url(self, **kwargs):
return reverse_lazy(
"core:user_prefs", kwargs={"user_id": self.customer.user.pk}
)
class GetUserForm(forms.Form): class GetUserForm(forms.Form):
""" """
The Form class aims at providing a valid user_id field in its cleaned data, in order to pass it to some view, The Form class aims at providing a valid user_id field in its cleaned data, in order to pass it to some view,
@ -109,7 +149,9 @@ class GetUserForm(forms.Form):
some nickname, first name, or last name (TODO) some nickname, first name, or last name (TODO)
""" """
code = forms.CharField(label="Code", max_length=10, required=False) code = forms.CharField(
label="Code", max_length=StudentCard.UID_SIZE, required=False
)
id = AutoCompleteSelectField( id = AutoCompleteSelectField(
"users", required=False, label=_("Select user"), help_text=None "users", required=False, label=_("Select user"), help_text=None
) )
@ -534,7 +576,7 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
""" """
uid = request.POST["student_card_uid"] uid = request.POST["student_card_uid"]
uid = str(uid) uid = str(uid)
if len(uid) != StudentCard.UID_SIZE: if not StudentCard.is_valid(uid):
request.session["not_valid_student_card_uid"] = True request.session["not_valid_student_card_uid"] = True
return False return False
@ -1788,3 +1830,27 @@ class CounterRefillingListView(CounterAdminTabsMixin, CounterAdminMixin, ListVie
kwargs = super(CounterRefillingListView, self).get_context_data(**kwargs) kwargs = super(CounterRefillingListView, self).get_context_data(**kwargs)
kwargs["counter"] = self.counter kwargs["counter"] = self.counter
return kwargs return kwargs
class StudentCardFormView(FormView):
"""
Add a new student card
"""
form_class = StudentCardForm
template_name = "core/create.jinja"
def dispatch(self, request, *args, **kwargs):
self.customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
return super(StudentCardFormView, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
data = form.clean()
res = super(FormView, self).form_valid(form)
self.customer.add_student_card(data["uid"], self.request)
return res
def get_success_url(self, **kwargs):
return reverse_lazy(
"core:user_prefs", kwargs={"user_id": self.customer.user.pk}
)