mirror of
https://github.com/ae-utbm/sith.git
synced 2024-12-22 07:41:14 +00:00
Add tooltip on current registered card, allow barmen to delete cards and make card deletion a fragment
This commit is contained in:
parent
466fe58763
commit
4975475e85
@ -42,6 +42,29 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[tooltip] {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
[tooltip]:before {
|
||||||
|
opacity: 0;
|
||||||
|
z-index: 1;
|
||||||
|
content: attr(tooltip);
|
||||||
|
background: $white-color;
|
||||||
|
color: $black-color;
|
||||||
|
border: 1px solid $black-color;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
top: 1em;
|
||||||
|
position: absolute;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: opacity 500ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
[tooltip]:hover:before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.ib {
|
.ib {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
@ -308,6 +331,7 @@ body {
|
|||||||
font-size: 120%;
|
font-size: 120%;
|
||||||
background-color: unset;
|
background-color: unset;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -318,14 +342,17 @@ body {
|
|||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:after {
|
&:hover:after {
|
||||||
border-bottom-color: darken($primary-neutral-light-color, 20%);
|
border-bottom-color: darken($primary-neutral-light-color, 20%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active:after {
|
&.active:after {
|
||||||
border-bottom-color: $primary-dark-color;
|
border-bottom-color: $primary-dark-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,13 @@
|
|||||||
<em class="no-cards">{% trans %}No student card registered.{% endtrans %}</em>
|
<em class="no-cards">{% trans %}No student card registered.{% endtrans %}</em>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>
|
<p>
|
||||||
{% trans %}Registered{% endtrans %} <i class="fa fa-check"></i> -
|
{% trans %}Card registered{% endtrans %}</span>
|
||||||
<a href="{{ url('counter:delete_student_card', customer_id=customer.pk) }}">
|
<span tooltip="{% trans uid=customer.student_card.uid %}uid: {{ uid }} {% endtrans %}"><i class="fa fa-check" style="color: green"></i></span> -
|
||||||
{% trans %}Delete{% endtrans %}
|
<button
|
||||||
</a>
|
hx-get="{{ url('counter:delete_student_card', customer_id=customer.pk) }}"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-target="#student_card_form"
|
||||||
|
>{% trans %}Delete{% endtrans %}</button>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
<div id="student_card_form">
|
||||||
|
<form hx-post="{{ action }}" hx-swap="outerHTML" hx-target="#student_card_form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>{% trans obj=object %}Are you sure you want to delete "{{ obj }}"?{% endtrans %}</p>
|
||||||
|
<input type="submit" value="{% trans %}Confirm{% endtrans %}" />
|
||||||
|
<input
|
||||||
|
hx-get="{{ action_cancel }}"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-target="#student_card_form"
|
||||||
|
type="submit"
|
||||||
|
name="cancel"
|
||||||
|
value="{% trans %}Cancel{% endtrans %}"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
@ -198,8 +198,7 @@ class TestStudentCard(TestCase):
|
|||||||
StudentCard, customer=cls.customer.customer, uid="8A89B82018B0A0"
|
StudentCard, customer=cls.customer.customer, uid="8A89B82018B0A0"
|
||||||
)
|
)
|
||||||
|
|
||||||
def setUp(self):
|
def login_in_counter(self):
|
||||||
# Auto login on counter
|
|
||||||
self.client.post(
|
self.client.post(
|
||||||
reverse("counter:login", args=[self.counter.id]),
|
reverse("counter:login", args=[self.counter.id]),
|
||||||
{"username": self.barmen.username, "password": "plop"},
|
{"username": self.barmen.username, "password": "plop"},
|
||||||
@ -222,6 +221,7 @@ class TestStudentCard(TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def test_search_user_with_student_card(self):
|
def test_search_user_with_student_card(self):
|
||||||
|
self.login_in_counter()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse("counter:details", args=[self.counter.id]),
|
reverse("counter:details", args=[self.counter.id]),
|
||||||
{"code": self.valid_card.uid},
|
{"code": self.valid_card.uid},
|
||||||
@ -233,6 +233,7 @@ class TestStudentCard(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_add_student_card_from_counter(self):
|
def test_add_student_card_from_counter(self):
|
||||||
|
self.login_in_counter()
|
||||||
for uid in ["8B90734A802A8F", "ABCAAAFAAFAAAB", "15248196326518"]:
|
for uid in ["8B90734A802A8F", "ABCAAAFAAFAAAB", "15248196326518"]:
|
||||||
customer = subscriber_user.make().customer
|
customer = subscriber_user.make().customer
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
@ -251,6 +252,7 @@ class TestStudentCard(TestCase):
|
|||||||
assert customer.student_card.uid == uid
|
assert customer.student_card.uid == uid
|
||||||
|
|
||||||
def test_add_student_card_from_counter_fail(self):
|
def test_add_student_card_from_counter_fail(self):
|
||||||
|
self.login_in_counter()
|
||||||
customer = subscriber_user.make().customer
|
customer = subscriber_user.make().customer
|
||||||
for uid, error_msg in self.invalid_uids():
|
for uid, error_msg in self.invalid_uids():
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
@ -269,25 +271,15 @@ class TestStudentCard(TestCase):
|
|||||||
assert not hasattr(customer, "student_card")
|
assert not hasattr(customer, "student_card")
|
||||||
|
|
||||||
def test_add_student_card_from_counter_unauthorized(self):
|
def test_add_student_card_from_counter_unauthorized(self):
|
||||||
barman = subscriber_user.make()
|
|
||||||
self.counter.sellers.add(barman)
|
|
||||||
customer = self.customer.customer
|
|
||||||
# There is someone logged to a counter
|
|
||||||
# with the client of this TestCase instance,
|
|
||||||
# so we create a new client, in order to check
|
|
||||||
# that using a client not logged to a counter
|
|
||||||
# where another client is logged still isn't authorized.
|
|
||||||
client = Client()
|
|
||||||
|
|
||||||
def send_valid_request(counter_id):
|
def send_valid_request(counter_id):
|
||||||
return client.post(
|
return self.client.post(
|
||||||
reverse(
|
reverse(
|
||||||
"counter:add_student_card", kwargs={"customer_id": customer.pk}
|
"counter:add_student_card", kwargs={"customer_id": self.customer.pk}
|
||||||
),
|
),
|
||||||
{"uid": "8B90734A802A8F"},
|
{"uid": "8B90734A802A8F"},
|
||||||
HTTP_REFERER=reverse(
|
HTTP_REFERER=reverse(
|
||||||
"counter:click",
|
"counter:click",
|
||||||
kwargs={"counter_id": counter_id, "user_id": customer.pk},
|
kwargs={"counter_id": counter_id, "user_id": self.customer.pk},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -295,7 +287,7 @@ class TestStudentCard(TestCase):
|
|||||||
assert send_valid_request(self.counter.id).status_code == 403
|
assert send_valid_request(self.counter.id).status_code == 403
|
||||||
|
|
||||||
# Send to a non bar counter
|
# Send to a non bar counter
|
||||||
client.force_login(self.club_admin)
|
self.client.force_login(self.club_admin)
|
||||||
assert send_valid_request(self.club_counter.id).status_code == 403
|
assert send_valid_request(self.club_counter.id).status_code == 403
|
||||||
|
|
||||||
def test_delete_student_card_with_owner(self):
|
def test_delete_student_card_with_owner(self):
|
||||||
@ -322,6 +314,24 @@ class TestStudentCard(TestCase):
|
|||||||
self.customer.customer.refresh_from_db()
|
self.customer.customer.refresh_from_db()
|
||||||
assert not hasattr(self.customer.customer, "student_card")
|
assert not hasattr(self.customer.customer, "student_card")
|
||||||
|
|
||||||
|
def test_delete_student_card_from_counter(self):
|
||||||
|
self.login_in_counter()
|
||||||
|
self.client.post(
|
||||||
|
reverse(
|
||||||
|
"counter:delete_student_card",
|
||||||
|
kwargs={"customer_id": self.customer.customer.pk},
|
||||||
|
),
|
||||||
|
http_referer=reverse(
|
||||||
|
"counter:click",
|
||||||
|
kwargs={
|
||||||
|
"counter_id": self.counter.id,
|
||||||
|
"user_id": self.customer.customer.pk,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.customer.customer.refresh_from_db()
|
||||||
|
assert not hasattr(self.customer.customer, "student_card")
|
||||||
|
|
||||||
def test_delete_student_card_fail(self):
|
def test_delete_student_card_fail(self):
|
||||||
"""Test that non-admin users cannot delete student cards"""
|
"""Test that non-admin users cannot delete student cards"""
|
||||||
self.client.force_login(self.subscriber)
|
self.client.force_login(self.subscriber)
|
||||||
@ -336,7 +346,7 @@ class TestStudentCard(TestCase):
|
|||||||
assert not hasattr(self.subscriber.customer, "student_card")
|
assert not hasattr(self.subscriber.customer, "student_card")
|
||||||
|
|
||||||
def test_add_student_card_from_user_preferences(self):
|
def test_add_student_card_from_user_preferences(self):
|
||||||
users = [self.subscriber, self.board_admin, self.root]
|
users = [self.customer, self.board_admin, self.root]
|
||||||
uids = ["8B90734A802A8F", "ABCAAAFAAFAAAB", "15248196326518"]
|
uids = ["8B90734A802A8F", "ABCAAAFAAFAAAB", "15248196326518"]
|
||||||
for user, uid in itertools.product(users, uids):
|
for user, uid in itertools.product(users, uids):
|
||||||
self.customer.customer.student_card.delete()
|
self.customer.customer.student_card.delete()
|
||||||
@ -353,7 +363,7 @@ class TestStudentCard(TestCase):
|
|||||||
|
|
||||||
self.customer.customer.refresh_from_db()
|
self.customer.customer.refresh_from_db()
|
||||||
assert self.customer.customer.student_card.uid == uid
|
assert self.customer.customer.student_card.uid == uid
|
||||||
self.assertContains(response, text="Enregistré")
|
self.assertContains(response, text="Carte enregistrée")
|
||||||
|
|
||||||
def test_add_student_card_from_user_preferences_fail(self):
|
def test_add_student_card_from_user_preferences_fail(self):
|
||||||
customer = subscriber_user.make()
|
customer = subscriber_user.make()
|
||||||
|
@ -22,22 +22,32 @@ from django.utils.translation import gettext as _
|
|||||||
from django.views.generic.edit import DeleteView, FormView
|
from django.views.generic.edit import DeleteView, FormView
|
||||||
|
|
||||||
from core.utils import FormFragmentTemplateData
|
from core.utils import FormFragmentTemplateData
|
||||||
from core.views import CanEditMixin
|
from core.views import can_edit
|
||||||
from counter.forms import StudentCardForm
|
from counter.forms import StudentCardForm
|
||||||
from counter.models import Customer, StudentCard
|
from counter.models import Customer, StudentCard
|
||||||
from counter.utils import is_logged_in_counter
|
from counter.utils import is_logged_in_counter
|
||||||
|
|
||||||
|
|
||||||
class StudentCardDeleteView(DeleteView, CanEditMixin):
|
class StudentCardDeleteView(DeleteView):
|
||||||
"""View used to delete a card from a user."""
|
"""View used to delete a card from a user. This is a fragment view !"""
|
||||||
|
|
||||||
model = StudentCard
|
model = StudentCard
|
||||||
template_name = "core/delete_confirm.jinja"
|
template_name = "counter/fragments/delete_student_card.jinja"
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request: HttpRequest, *args, **kwargs):
|
||||||
self.customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
|
self.customer = get_object_or_404(Customer, pk=kwargs["customer_id"])
|
||||||
|
if not is_logged_in_counter(request) and not can_edit(
|
||||||
|
self.get_object(), request.user
|
||||||
|
):
|
||||||
|
raise PermissionDenied()
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context["action"] = self.request.path
|
||||||
|
context["action_cancel"] = self.get_success_url()
|
||||||
|
return context
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
if not hasattr(self.customer, "student_card"):
|
if not hasattr(self.customer, "student_card"):
|
||||||
raise Http404(
|
raise Http404(
|
||||||
@ -47,7 +57,9 @@ class StudentCardDeleteView(DeleteView, CanEditMixin):
|
|||||||
return self.customer.student_card
|
return self.customer.student_card
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
return reverse("core:user_prefs", kwargs={"user_id": self.customer.user_id})
|
return reverse(
|
||||||
|
"counter:add_student_card", kwargs={"customer_id": self.customer.pk}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class StudentCardFormView(FormView):
|
class StudentCardFormView(FormView):
|
||||||
|
@ -369,7 +369,7 @@ msgstr "Compte en banque : "
|
|||||||
#: core/templates/core/user_clubs.jinja:34
|
#: core/templates/core/user_clubs.jinja:34
|
||||||
#: core/templates/core/user_clubs.jinja:63
|
#: core/templates/core/user_clubs.jinja:63
|
||||||
#: core/templates/core/user_edit.jinja:62
|
#: core/templates/core/user_edit.jinja:62
|
||||||
#: counter/templates/counter/fragments/create_student_card.jinja:18
|
#: counter/templates/counter/fragments/create_student_card.jinja:22
|
||||||
#: counter/templates/counter/last_ops.jinja:35
|
#: counter/templates/counter/last_ops.jinja:35
|
||||||
#: counter/templates/counter/last_ops.jinja:65
|
#: counter/templates/counter/last_ops.jinja:65
|
||||||
#: election/templates/election/election_detail.jinja:191
|
#: election/templates/election/election_detail.jinja:191
|
||||||
@ -2574,18 +2574,21 @@ msgstr "Confirmation de suppression"
|
|||||||
|
|
||||||
#: core/templates/core/delete_confirm.jinja:16
|
#: core/templates/core/delete_confirm.jinja:16
|
||||||
#: core/templates/core/file_delete_confirm.jinja:29
|
#: core/templates/core/file_delete_confirm.jinja:29
|
||||||
|
#: counter/templates/counter/fragments/delete_student_card.jinja:4
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Are you sure you want to delete \"%(obj)s\"?"
|
msgid "Are you sure you want to delete \"%(obj)s\"?"
|
||||||
msgstr "Êtes-vous sûr de vouloir supprimer \"%(obj)s\" ?"
|
msgstr "Êtes-vous sûr de vouloir supprimer \"%(obj)s\" ?"
|
||||||
|
|
||||||
#: core/templates/core/delete_confirm.jinja:17
|
#: core/templates/core/delete_confirm.jinja:17
|
||||||
#: core/templates/core/file_delete_confirm.jinja:36
|
#: core/templates/core/file_delete_confirm.jinja:36
|
||||||
|
#: counter/templates/counter/fragments/delete_student_card.jinja:5
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmation"
|
msgstr "Confirmation"
|
||||||
|
|
||||||
#: core/templates/core/delete_confirm.jinja:20
|
#: core/templates/core/delete_confirm.jinja:20
|
||||||
#: core/templates/core/file_delete_confirm.jinja:46
|
#: core/templates/core/file_delete_confirm.jinja:46
|
||||||
#: counter/templates/counter/counter_click.jinja:104
|
#: counter/templates/counter/counter_click.jinja:104
|
||||||
|
#: counter/templates/counter/fragments/delete_student_card.jinja:12
|
||||||
#: sas/templates/sas/ask_picture_removal.jinja:20
|
#: sas/templates/sas/ask_picture_removal.jinja:20
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Annuler"
|
msgstr "Annuler"
|
||||||
@ -4044,8 +4047,13 @@ msgid "No student card registered."
|
|||||||
msgstr "Aucune carte étudiante enregistrée."
|
msgstr "Aucune carte étudiante enregistrée."
|
||||||
|
|
||||||
#: counter/templates/counter/fragments/create_student_card.jinja:16
|
#: counter/templates/counter/fragments/create_student_card.jinja:16
|
||||||
msgid "Registered"
|
msgid "Card registered"
|
||||||
msgstr "Enregistré"
|
msgstr "Carte enregistrée"
|
||||||
|
|
||||||
|
#: counter/templates/counter/fragments/create_student_card.jinja:17
|
||||||
|
#, python-format
|
||||||
|
msgid "uid: %(uid)s "
|
||||||
|
msgstr "uid: %(uid)s"
|
||||||
|
|
||||||
#: counter/templates/counter/invoices_call.jinja:8
|
#: counter/templates/counter/invoices_call.jinja:8
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -4317,7 +4325,7 @@ msgstr "Administration des comptoirs"
|
|||||||
msgid "Product types"
|
msgid "Product types"
|
||||||
msgstr "Types de produit"
|
msgstr "Types de produit"
|
||||||
|
|
||||||
#: counter/views/student_card.py:44
|
#: counter/views/student_card.py:54
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(name)s has no registered student card"
|
msgid "%(name)s has no registered student card"
|
||||||
msgstr "%(name)s n'a pas de carte étudiante enregistrée"
|
msgstr "%(name)s n'a pas de carte étudiante enregistrée"
|
||||||
|
Loading…
Reference in New Issue
Block a user