1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-06-22 02:18:21 +02:00

Compare commits

...

19 Commits

Author SHA1 Message Date
77788d4f46 Merge branch 'qrcode' into 'main'
Draft: Qrcode

See merge request bde/nk20!196
2025-04-16 09:09:14 +02:00
ff4353d344 Merge branch 'update_invoice_template' into 'main'
Update invoice template

See merge request bde/nk20!307
2025-04-15 18:11:18 +02:00
6969cee0f3 Merge branch 'time-display' into 'main'
Fixed some non timezone-aware displays

See merge request bde/nk20!303
2025-04-15 17:28:28 +02:00
8e2b24b2da Merge branch 'options_order' into 'main'
Options order

See merge request bde/nk20!306
2025-04-13 23:12:05 +02:00
bd76c280ec Update forms.py 2025-04-13 22:59:04 +02:00
ca0a95ba9e Update transaction_form.html 2025-04-13 22:32:49 +02:00
614f76e699 Add BDA email as an option to fix NL updates
Commit [1] removed default BDA email address from extract_ml_registrations script code. We should now add it to cron.

[1] 3dd5f6e3e0

See merge request bde/nk20!305
2025-04-13 20:17:44 +02:00
a5815f0bc7 Add BDA email as an option to fix NL updates
Commit [1] removed default BDA email address from extract_ml_registrations script code. We should now add it to cron.

[1] 3dd5f6e3e0
2025-04-13 19:56:20 +02:00
84e9fea15f linters 2025-04-04 14:46:43 +02:00
b7a660ee40 bootstrap: fix minor issues with profile picture cropping
* Add required [1] "display: block;" style property to img element
* Fix image overflow in modal. As cropper size inherits from img's parent element [2] (including padding according to my research), we need to wrap modal body into another div that has the padding we want.
* Remove ability [3] to click away to dismiss the modal as it often interfered with user interaction when cropping.

[1] https://github.com/fengyuanchen/cropperjs/tree/v1?tab=readme-ov-file#example
[2] https://github.com/fengyuanchen/cropperjs/tree/v1?tab=readme-ov-file#notes
[3] https://getbootstrap.com/docs/4.0/components/modal/#options

See merge request bde/nk20!301
2025-04-04 01:14:46 +02:00
b9ebb1718a Fixed some non timezone-aware displays 2025-04-04 00:29:22 +02:00
93aed87265 bootstrap: fix minor issues with profile picture cropping
* Add required [1] "display: block;" style property to img element
* Fix image overflow in modal. As cropper size inherits from img's parent element [2] (including padding according to my research), we need to wrap modal body into another div that has the padding we want.
* Remove ability [3] to click away to dismiss the modal as it often interfered with user interaction when cropping.

[1] https://github.com/fengyuanchen/cropperjs/tree/v1?tab=readme-ov-file#example
[2] https://github.com/fengyuanchen/cropperjs/tree/v1?tab=readme-ov-file#notes
[3] https://getbootstrap.com/docs/4.0/components/modal/#options

Signed-off-by: Alexis Mercier des Rochettes <apernouille@gmail.com>
2025-03-24 17:36:30 +01:00
e6f3084588 Added a first pass for automatically entering an activity with a qrcode 2023-10-11 18:01:51 +02:00
145e55da75 remove useless comment 2022-03-22 15:06:04 +01:00
d3ba95cdca Insecable space for more clarity 2022-03-22 15:04:41 +01:00
8ffb0ebb56 Use DetailView 2022-03-22 14:59:01 +01:00
5038af9e34 Final html template 2022-03-22 14:58:26 +01:00
819b4214c9 Add QRCode View, URL and test template 2022-03-22 12:26:44 +01:00
b8a93b0b75 Add link to QR code 2022-03-19 16:25:15 +01:00
11 changed files with 94 additions and 11 deletions

View File

@ -201,7 +201,8 @@ class Entry(models.Model):
def save(self, *args, **kwargs):
qs = Entry.objects.filter(~Q(pk=self.pk), activity=self.activity, note=self.note, guest=self.guest)
if qs.exists():
raise ValidationError(_("Already entered on ") + _("{:%Y-%m-%d %H:%M:%S}").format(qs.get().time, ))
raise ValidationError(_("Already entered on ")
+ _("{:%Y-%m-%d %H:%M:%S}").format(timezone.localtime(qs.get().time), ))
if self.guest:
self.note = self.guest.inviter

View File

@ -55,7 +55,7 @@ class GuestTable(tables.Table):
def render_entry(self, record):
if record.has_entry:
return str(_("Entered on ") + str(_("{:%Y-%m-%d %H:%M:%S}").format(record.entry.time, )))
return str(_("Entered on ") + str(_("{:%Y-%m-%d %H:%M:%S}").format(timezone.localtime(record.entry.time))))
return mark_safe('<button id="{id}" class="btn btn-danger btn-sm" onclick="remove_guest(this.id)"> '
'{delete_trans}</button>'.format(id=record.id, delete_trans=_("remove").capitalize()))

View File

@ -38,6 +38,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
</a>
<input id="alias" type="text" class="form-control" placeholder="Nom/note ...">
<button id="trigger" class="btn btn-secondary">Click me !</button>
<hr>
@ -63,15 +64,46 @@ SPDX-License-Identifier: GPL-3.0-or-later
refreshBalance();
}
function process_qrcode() {
let name = alias_obj.val();
$.get("/api/note/note?search=" + name + "&format=json").done(
function (res) {
let note = res.results[0];
$.post("/api/activity/entry/?format=json", {
csrfmiddlewaretoken: CSRF_TOKEN,
activity: {{ activity.id }},
note: note.id,
guest: null
}).done(function () {
addMsg(interpolate(gettext(
"Entry made for %s whose balance is %s €"),
[note.name, note.balance / 100]), "success", 4000);
reloadTable(true);
}).fail(function (xhr) {
errMsg(xhr.responseJSON, 4000);
});
}).fail(function (xhr) {
errMsg(xhr.responseJSON, 4000);
});
}
alias_obj.keyup(function(event) {
let code = event.originalEvent.keyCode
if (65 <= code <= 122 || code === 13) {
debounce(reloadTable)()
}
if (code === 0)
process_qrcode();
});
$(document).ready(init);
alias_obj2 = document.getElementById("alias");
$("#trigger").click(function (e) {
addMsg("Clicked", "success", 1000);
alias_obj.val(alias_obj.val() + "\0");
alias_obj2.dispatchEvent(new KeyboardEvent('keyup'));
})
function init() {
$(".table-row").click(function (e) {
let target = e.target.parentElement;
@ -168,4 +200,4 @@ SPDX-License-Identifier: GPL-3.0-or-later
});
}
</script>
{% endblock %}
{% endblock %}

View File

@ -23,7 +23,7 @@ from .models import Profile, Club, Membership
class CustomAuthenticationForm(AuthenticationForm):
permission_mask = forms.ModelChoiceField(
label=_("Permission mask"),
queryset=PermissionMask.objects.order_by("rank"),
queryset=PermissionMask.objects.order_by("-rank"),
empty_label=None,
)

View File

@ -60,7 +60,10 @@
{% if user_object.pk == user.pk %}
<div class="text-center">
<a class="small badge badge-secondary" href="{% url 'member:auth_token' %}">
<i class="fa fa-cogs"></i>{% trans 'API token' %}
<i class="fa fa-cogs"></i>&nbsp;{% trans 'API token' %}
</a>
<a class="small badge badge-secondary" href="{% url 'member:qr_code' user_object.pk %}">
<i class="fa fa-qrcode"></i>&nbsp;{% trans 'QR Code' %}
</a>
</div>
{% endif %}

View File

@ -20,12 +20,14 @@ SPDX-License-Identifier: GPL-3.0-or-later
</form>
</div>
<!-- MODAL TO CROP THE IMAGE -->
<div class="modal fade" id="modalCrop">
<div class="modal fade" id="modalCrop" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<img src="" id="modal-image" style="max-width: 100%;">
</div>
<div class="modal-body-wrapper" style="width: 500px; height: 500px; padding: 16px;">
<div class="modal-body" style="width: 100%; height: 100%; padding: 0">
<img src="" id="modal-image" style="display: block; max-width: 100%;">
</div>
</div>
<div class="modal-footer">
<div class="btn-group pull-left" role="group">
<button type="button" class="btn btn-default" id="js-zoom-in">

View File

@ -0,0 +1,36 @@
{% extends "base.html" %}
{% comment %}
SPDX-License-Identifier: GPL-3.0-or-later
{% endcomment %}
{% load i18n %}
{% block content %}
<div class="card bg-light">
<h3 class="card-header text-center">
{% trans "QR Code for" %} {{ user_object.username }} ({{ user_object.first_name }} {{user_object.last_name }})
</h3>
<div class="text-center" id="qrcode">
</div>
</div>
{% endblock %}
{% block extrajavascript %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js" integrity="sha512-CNgIRecGo7nphbeZ04Sc13ka07paqdeTu0WR1IM4kNcpmBAUSHSQX0FslNhTDadL4O5SAGapGt4FodqL8My0mA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
var qrc = new QRCode(document.getElementById("qrcode"), {
text: "{{ user_object.pk }}\0",
width: 1024,
height: 1024
});
</script>
{% endblock %}
{% block extracss %}
<style>
img {
width: 100%
}
</style>
{% endblock %}

View File

@ -25,4 +25,5 @@ urlpatterns = [
path('user/<int:pk>/aliases/', views.ProfileAliasView.as_view(), name="user_alias"),
path('user/<int:pk>/trust', views.ProfileTrustView.as_view(), name="user_trust"),
path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
path('user/<int:pk>/qr_code/', views.QRCodeView.as_view(), name='qr_code'),
]

View File

@ -402,6 +402,14 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
context['token'] = Token.objects.get_or_create(user=self.request.user)[0]
return context
class QRCodeView(LoginRequiredMixin, DetailView):
"""
Affiche le QR Code
"""
model = User
context_object_name = "user_object"
template_name = "member/qr_code.html"
extra_context = {"title": _("QR Code")}
# ******************************* #
# CLUB #

View File

@ -89,7 +89,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
</ul>
<div class="card-body">
<select id="debit_type" class="form-control custom-select d-none">
{% for special_type in special_types %}
{% for special_type in special_types|slice:"::-1" %}
<option value="{{ special_type.id }}">{{ special_type.special_type }}</option>
{% endfor %}
</select>

View File

@ -27,5 +27,5 @@ MAILTO=notekfet2020@lists.crans.org
# Vider les tokens Oauth2
00 6 * * * root cd /var/www/note_kfet && env/bin/python manage.py cleartokens -v 0
# Envoyer la liste des abonnés à la NL BDA
00 10 * * 0 root cd /var/www/note_kfet && env/bin/python manage.py extract_ml_registrations -t art
00 10 * * 0 root cd /var/www/note_kfet && env/bin/python manage.py extract_ml_registrations -t art -e "bda.ensparissaclay@gmail.com"