1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-07-08 08:10:21 +02:00

Compare commits

...

16 Commits

Author SHA1 Message Date
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
d43fbe7ac6 Merge branch 'harden' into 'beta'
Harden Django project configuration

See merge request bde/nk20!194
2022-03-09 12:30:23 +01:00
df5f9b5f1e Harden Django project configuration
Set session and CSRF cookies as secure for production.
Set HSTS header to let browser remember HTTPS for 1 year.
2022-03-09 12:12:56 +01:00
4161248bff Add permissions to view/create/change/delete OAuth2 applications
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2022-03-09 12:06:19 +01:00
58136f3c48 Fix permission checks in the /api/me view
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2022-03-09 11:45:24 +01:00
d9b4e0a9a9 Fix membership tables for clubs without an ending membership date
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2022-02-13 17:53:05 +01:00
8563a8d235 Fix membership tables for clubs without an ending membership date
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2022-02-13 17:51:22 +01:00
5f69232560 Merge branch 'beta' into 'main'
Optional scopes + small bug fix

See merge request bde/nk20!193
2022-02-12 14:37:58 +01:00
1eb72044c2 Merge branch 'beta' into 'master'
Changements variés et mineurs

Closes #107 et #91

See merge request bde/nk20!191
2021-12-13 21:16:26 +01:00
ca2b9f061c Merge branch 'beta' into 'master'
Multiples fix, réparation des pots

Closes #75

See merge request bde/nk20!186
2021-10-05 12:02:03 +02:00
10 changed files with 169 additions and 8 deletions

View File

@ -38,6 +38,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
</a> </a>
<input id="alias" type="text" class="form-control" placeholder="Nom/note ..."> <input id="alias" type="text" class="form-control" placeholder="Nom/note ...">
<button id="trigger" class="btn btn-secondary">Click me !</button>
<hr> <hr>
@ -63,15 +64,46 @@ SPDX-License-Identifier: GPL-3.0-or-later
refreshBalance(); 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) { alias_obj.keyup(function(event) {
let code = event.originalEvent.keyCode let code = event.originalEvent.keyCode
if (65 <= code <= 122 || code === 13) { if (65 <= code <= 122 || code === 13) {
debounce(reloadTable)() debounce(reloadTable)()
} }
if (code === 0)
process_qrcode();
}); });
$(document).ready(init); $(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() { function init() {
$(".table-row").click(function (e) { $(".table-row").click(function (e) {
let target = e.target.parentElement; let target = e.target.parentElement;

View File

@ -60,12 +60,12 @@ class OAuthSerializer(serializers.ModelSerializer):
def get_profile(self, obj): def get_profile(self, obj):
# Display the profile of the user only if we have rights to see it. # Display the profile of the user only if we have rights to see it.
return ProfileSerializer().to_representation(obj.profile) \ return ProfileSerializer().to_representation(obj.profile) \
if PermissionBackend.has_perm(get_current_request(), obj.profile, 'view') else None if PermissionBackend.check_perm(get_current_request(), 'member.view_profile', obj.profile) else None
def get_note(self, obj): def get_note(self, obj):
# Display the note of the user only if we have rights to see it. # Display the note of the user only if we have rights to see it.
return NoteSerializer().to_representation(obj.note) \ return NoteSerializer().to_representation(obj.note) \
if PermissionBackend.has_perm(get_current_request(), obj.note, 'view') else None if PermissionBackend.check_perm(get_current_request(), 'note.view_note', obj.note) else None
def get_memberships(self, obj): def get_memberships(self, obj):
# Display only memberships that we are allowed to see. # Display only memberships that we are allowed to see.

View File

@ -258,7 +258,7 @@ class Club(models.Model):
This function is called each time the club detail view is displayed. This function is called each time the club detail view is displayed.
Update the year of the membership dates. Update the year of the membership dates.
""" """
if not self.membership_start: if not self.membership_start or not self.membership_end:
return return
today = datetime.date.today() today = datetime.date.today()

View File

@ -120,7 +120,7 @@ class MembershipTable(tables.Table):
club=record.club, club=record.club,
user=record.user, user=record.user,
date_start__gte=record.club.membership_start, date_start__gte=record.club.membership_start,
date_end__lte=record.club.membership_end, date_end__lte=record.club.membership_end or date(9999, 12, 31),
).exists(): # If the renew is not yet performed ).exists(): # If the renew is not yet performed
empty_membership = Membership( empty_membership = Membership(
club=record.club, club=record.club,

View File

@ -52,7 +52,10 @@
{% if user_object.pk == user.pk %} {% if user_object.pk == user.pk %}
<div class="text-center"> <div class="text-center">
<a class="small badge badge-secondary" href="{% url 'member:auth_token' %}"> <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> </a>
</div> </div>
{% endif %} {% endif %}

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

@ -24,4 +24,5 @@ urlpatterns = [
path('user/<int:pk>/update_pic/', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"), path('user/<int:pk>/update_pic/', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"),
path('user/<int:pk>/aliases/', views.ProfileAliasView.as_view(), name="user_alias"), path('user/<int:pk>/aliases/', views.ProfileAliasView.as_view(), name="user_alias"),
path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'), 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

@ -331,6 +331,14 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
context['token'] = Token.objects.get_or_create(user=self.request.user)[0] context['token'] = Token.objects.get_or_create(user=self.request.user)[0]
return context 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 # # CLUB #

View File

@ -2903,6 +2903,70 @@
"description": "(Dé)bloquer la note de son club et indiquer que cela a été fait manuellement" "description": "(Dé)bloquer la note de son club et indiquer que cela a été fait manuellement"
} }
}, },
{
"model": "permission.permission",
"pk": 186,
"fields": {
"model": [
"oauth2_provider",
"application"
],
"query": "{\"user\": [\"user\"]}",
"type": "view",
"mask": 1,
"field": "",
"permanent": true,
"description": "Voir ses applications OAuth2"
}
},
{
"model": "permission.permission",
"pk": 187,
"fields": {
"model": [
"oauth2_provider",
"application"
],
"query": "{\"user\": [\"user\"]}",
"type": "create",
"mask": 1,
"field": "",
"permanent": true,
"description": "Créer une application OAuth2"
}
},
{
"model": "permission.permission",
"pk": 188,
"fields": {
"model": [
"oauth2_provider",
"application"
],
"query": "{\"user\": [\"user\"]}",
"type": "change",
"mask": 1,
"field": "",
"permanent": true,
"description": "Modifier une application OAuth2"
}
},
{
"model": "permission.permission",
"pk": 189,
"fields": {
"model": [
"oauth2_provider",
"application"
],
"query": "{\"user\": [\"user\"]}",
"type": "delete",
"mask": 1,
"field": "",
"permanent": true,
"description": "Supprimer une application OAuth2"
}
},
{ {
"model": "permission.role", "model": "permission.role",
"pk": 1, "pk": 1,
@ -2933,7 +2997,11 @@
126, 126,
161, 161,
162, 162,
165 165,
186,
187,
188,
189
] ]
} }
}, },
@ -3314,7 +3382,11 @@
182, 182,
183, 183,
184, 184,
185 185,
186,
187,
188,
189
] ]
} }
}, },

View File

@ -24,6 +24,15 @@ ALLOWED_HOSTS = [
os.getenv('NOTE_URL', 'localhost'), os.getenv('NOTE_URL', 'localhost'),
] ]
# Use secure cookies in production
SESSION_COOKIE_SECURE = not DEBUG
CSRF_COOKIE_SECURE = not DEBUG
# Remember HTTPS for 1 year
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# Application definition # Application definition