mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-07-08 08:10:21 +02:00
Compare commits
20 Commits
svg_icons
...
132afc3d15
Author | SHA1 | Date | |
---|---|---|---|
132afc3d15
|
|||
6bf16a181a
|
|||
e20df82346
|
|||
f88eae924c
|
|||
4b6e3ba546
|
|||
bf0fe3479f | |||
45ba4f9537
|
|||
b204805ce2
|
|||
2f28e34cec
|
|||
9c8ea2cd41
|
|||
41289857b2 | |||
28a8792c9f
|
|||
58cafad032
|
|||
7848cd9cc2
|
|||
d18ccfac23
|
|||
e479e1e3a4 | |||
82b0c83b1f | |||
38ca414ef6
|
|||
fd811053c7
|
|||
9d386d1ecf
|
@ -1,8 +1,8 @@
|
|||||||
# NoteKfet 2020
|
# NoteKfet 2020
|
||||||
|
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.txt)
|
[](https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
[](https://gitlab.crans.org/bde/nk20/commits/master)
|
[](https://gitlab.crans.org/bde/nk20/commits/main)
|
||||||
[](https://gitlab.crans.org/bde/nk20/commits/master)
|
[](https://gitlab.crans.org/bde/nk20/commits/main)
|
||||||
|
|
||||||
## Table des matières
|
## Table des matières
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
prompt: "Password of the database (leave it blank to skip database init)"
|
prompt: "Password of the database (leave it blank to skip database init)"
|
||||||
private: yes
|
private: yes
|
||||||
vars:
|
vars:
|
||||||
mirror: mirror.crans.org
|
mirror: eclats.crans.org
|
||||||
roles:
|
roles:
|
||||||
- 1-apt-basic
|
- 1-apt-basic
|
||||||
- 2-nk20
|
- 2-nk20
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
note:
|
note:
|
||||||
server_name: note.crans.org
|
server_name: note.crans.org
|
||||||
git_branch: master
|
git_branch: main
|
||||||
serve_static: true
|
serve_static: true
|
||||||
cron_enabled: true
|
cron_enabled: true
|
||||||
email: notekfet2020@lists.crans.org
|
email: notekfet2020@lists.crans.org
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
---
|
---
|
||||||
- name: Add buster-backports to apt sources
|
- name: Add buster-backports to apt sources if needed
|
||||||
apt_repository:
|
apt_repository:
|
||||||
repo: deb http://{{ mirror }}/debian buster-backports main
|
repo: deb http://{{ mirror }}/debian buster-backports main
|
||||||
state: present
|
state: present
|
||||||
when: ansible_facts['distribution'] == "Debian"
|
when:
|
||||||
|
- ansible_distribution == "Debian"
|
||||||
|
- ansible_distribution_major_version | int == 10
|
||||||
|
|
||||||
- name: Install note_kfet APT dependencies
|
- name: Install note_kfet APT dependencies
|
||||||
apt:
|
apt:
|
||||||
update_cache: true
|
update_cache: true
|
||||||
default_release: "{{ 'buster-backports' if ansible_facts['distribution'] == 'Debian' }}"
|
|
||||||
install_recommends: false
|
install_recommends: false
|
||||||
name:
|
name:
|
||||||
# Common tools
|
# Common tools
|
||||||
|
@ -168,6 +168,9 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
|||||||
Don't display the entry interface if the user has no right to see it (no right to add an entry for itself),
|
Don't display the entry interface if the user has no right to see it (no right to add an entry for itself),
|
||||||
it is closed or doesn't manage entries.
|
it is closed or doesn't manage entries.
|
||||||
"""
|
"""
|
||||||
|
if not self.request.user.is_authenticated:
|
||||||
|
return self.handle_no_permission()
|
||||||
|
|
||||||
activity = Activity.objects.get(pk=self.kwargs["pk"])
|
activity = Activity.objects.get(pk=self.kwargs["pk"])
|
||||||
|
|
||||||
sample_entry = Entry(activity=activity, note=self.request.user.note)
|
sample_entry = Entry(activity=activity, note=self.request.user.note)
|
||||||
|
18
apps/member/migrations/0008_auto_20211005_1544.py
Normal file
18
apps/member/migrations/0008_auto_20211005_1544.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 2.2.24 on 2021-10-05 13:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('member', '0007_auto_20210313_1235'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='department',
|
||||||
|
field=models.CharField(choices=[('A0', 'Informatics (A0)'), ('A1', 'Mathematics (A1)'), ('A2', 'Physics (A2)'), ("A'2", "Applied physics (A'2)"), ("A''2", "Chemistry (A''2)"), ('A3', 'Biology (A3)'), ('B1234', 'SAPHIRE (B1234)'), ('B1', 'Mechanics (B1)'), ('B2', 'Civil engineering (B2)'), ('B3', 'Mechanical engineering (B3)'), ('B4', 'EEA (B4)'), ('C', 'Design (C)'), ('D2', 'Economy-management (D2)'), ('D3', 'Social sciences (D3)'), ('E', 'English (E)'), ('EXT', 'External (EXT)')], max_length=8, verbose_name='department'),
|
||||||
|
),
|
||||||
|
]
|
@ -18,7 +18,7 @@ from django.views.generic import DetailView, UpdateView, TemplateView
|
|||||||
from django.views.generic.edit import FormMixin
|
from django.views.generic.edit import FormMixin
|
||||||
from django_tables2.views import SingleTableView
|
from django_tables2.views import SingleTableView
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
from note.models import Alias, NoteUser
|
from note.models import Alias, NoteUser, NoteClub
|
||||||
from note.models.transactions import Transaction, SpecialTransaction
|
from note.models.transactions import Transaction, SpecialTransaction
|
||||||
from note.tables import HistoryTable, AliasTable
|
from note.tables import HistoryTable, AliasTable
|
||||||
from note_kfet.middlewares import _set_current_request
|
from note_kfet.middlewares import _set_current_request
|
||||||
@ -174,7 +174,7 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
|||||||
modified_note = NoteUser.objects.get(pk=user.note.pk)
|
modified_note = NoteUser.objects.get(pk=user.note.pk)
|
||||||
# Don't log these tests
|
# Don't log these tests
|
||||||
modified_note._no_signal = True
|
modified_note._no_signal = True
|
||||||
modified_note.is_active = True
|
modified_note.is_active = False
|
||||||
modified_note.inactivity_reason = 'manual'
|
modified_note.inactivity_reason = 'manual'
|
||||||
context["can_lock_note"] = user.note.is_active and PermissionBackend\
|
context["can_lock_note"] = user.note.is_active and PermissionBackend\
|
||||||
.check_perm(self.request, "note.change_noteuser_is_active", modified_note)
|
.check_perm(self.request, "note.change_noteuser_is_active", modified_note)
|
||||||
@ -183,14 +183,14 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
|||||||
modified_note._force_save = True
|
modified_note._force_save = True
|
||||||
modified_note.save()
|
modified_note.save()
|
||||||
context["can_force_lock"] = user.note.is_active and PermissionBackend\
|
context["can_force_lock"] = user.note.is_active and PermissionBackend\
|
||||||
.check_perm(self.request, "note.change_note_is_active", modified_note)
|
.check_perm(self.request, "note.change_noteuser_is_active", modified_note)
|
||||||
old_note._force_save = True
|
old_note._force_save = True
|
||||||
old_note._no_signal = True
|
old_note._no_signal = True
|
||||||
old_note.save()
|
old_note.save()
|
||||||
modified_note.refresh_from_db()
|
modified_note.refresh_from_db()
|
||||||
modified_note.is_active = True
|
modified_note.is_active = True
|
||||||
context["can_unlock_note"] = not user.note.is_active and PermissionBackend\
|
context["can_unlock_note"] = not user.note.is_active and PermissionBackend\
|
||||||
.check_perm(self.request, "note.change_note_is_active", modified_note)
|
.check_perm(self.request, "note.change_noteuser_is_active", modified_note)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@ -256,7 +256,8 @@ class ProfileAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
|||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
note = context['object'].note
|
note = context['object'].note
|
||||||
context["aliases"] = AliasTable(
|
context["aliases"] = AliasTable(
|
||||||
note.alias.filter(PermissionBackend.filter_queryset(self.request, Alias, "view")).distinct().all())
|
note.alias.filter(PermissionBackend.filter_queryset(self.request, Alias, "view")).distinct()
|
||||||
|
.order_by('normalized_name').all())
|
||||||
context["can_create"] = PermissionBackend.check_perm(self.request, "note.add_alias", Alias(
|
context["can_create"] = PermissionBackend.check_perm(self.request, "note.add_alias", Alias(
|
||||||
note=context["object"].note,
|
note=context["object"].note,
|
||||||
name="",
|
name="",
|
||||||
@ -403,9 +404,12 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
|||||||
"""
|
"""
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
club = context["club"]
|
club = self.object
|
||||||
|
context["note"] = club.note
|
||||||
|
|
||||||
if PermissionBackend.check_perm(self.request, "member.change_club_membership_start", club):
|
if PermissionBackend.check_perm(self.request, "member.change_club_membership_start", club):
|
||||||
club.update_membership_dates()
|
club.update_membership_dates()
|
||||||
|
|
||||||
# managers list
|
# managers list
|
||||||
managers = Membership.objects.filter(club=self.object, roles__name="Bureau de club",
|
managers = Membership.objects.filter(club=self.object, roles__name="Bureau de club",
|
||||||
date_start__lte=date.today(), date_end__gte=date.today())\
|
date_start__lte=date.today(), date_end__gte=date.today())\
|
||||||
@ -443,6 +447,29 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
|||||||
context["can_add_members"] = PermissionBackend()\
|
context["can_add_members"] = PermissionBackend()\
|
||||||
.has_perm(self.request.user, "member.add_membership", empty_membership)
|
.has_perm(self.request.user, "member.add_membership", empty_membership)
|
||||||
|
|
||||||
|
# Check permissions to see if the authenticated user can lock/unlock the note
|
||||||
|
with transaction.atomic():
|
||||||
|
modified_note = NoteClub.objects.get(pk=club.note.pk)
|
||||||
|
# Don't log these tests
|
||||||
|
modified_note._no_signal = True
|
||||||
|
modified_note.is_active = False
|
||||||
|
modified_note.inactivity_reason = 'manual'
|
||||||
|
context["can_lock_note"] = club.note.is_active and PermissionBackend \
|
||||||
|
.check_perm(self.request, "note.change_noteclub_is_active", modified_note)
|
||||||
|
old_note = NoteClub.objects.select_for_update().get(pk=club.note.pk)
|
||||||
|
modified_note.inactivity_reason = 'forced'
|
||||||
|
modified_note._force_save = True
|
||||||
|
modified_note.save()
|
||||||
|
context["can_force_lock"] = club.note.is_active and PermissionBackend \
|
||||||
|
.check_perm(self.request, "note.change_noteclub_is_active", modified_note)
|
||||||
|
old_note._force_save = True
|
||||||
|
old_note._no_signal = True
|
||||||
|
old_note.save()
|
||||||
|
modified_note.refresh_from_db()
|
||||||
|
modified_note.is_active = True
|
||||||
|
context["can_unlock_note"] = not club.note.is_active and PermissionBackend \
|
||||||
|
.check_perm(self.request, "note.change_noteclub_is_active", modified_note)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
import html
|
import html
|
||||||
|
|
||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html, mark_safe
|
||||||
from django_tables2.utils import A
|
from django_tables2.utils import A
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from note_kfet.middlewares import get_current_request
|
from note_kfet.middlewares import get_current_request
|
||||||
@ -197,6 +197,17 @@ class ButtonTable(tables.Table):
|
|||||||
verbose_name=_("Edit"),
|
verbose_name=_("Edit"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
hideshow = tables.Column(
|
||||||
|
verbose_name=_("Hide/Show"),
|
||||||
|
accessor="pk",
|
||||||
|
attrs={
|
||||||
|
'td': {
|
||||||
|
'class': 'col-sm-1',
|
||||||
|
'id': lambda record: "hideshow_" + str(record.pk),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
delete_col = tables.TemplateColumn(template_code=DELETE_TEMPLATE,
|
delete_col = tables.TemplateColumn(template_code=DELETE_TEMPLATE,
|
||||||
extra_context={"delete_trans": _('delete')},
|
extra_context={"delete_trans": _('delete')},
|
||||||
attrs={'td': {'class': 'col-sm-1'}},
|
attrs={'td': {'class': 'col-sm-1'}},
|
||||||
@ -204,3 +215,16 @@ class ButtonTable(tables.Table):
|
|||||||
|
|
||||||
def render_amount(self, value):
|
def render_amount(self, value):
|
||||||
return pretty_money(value)
|
return pretty_money(value)
|
||||||
|
|
||||||
|
def order_category(self, queryset, is_descending):
|
||||||
|
return queryset.order_by(f"{'-' if is_descending else ''}category__name"), True
|
||||||
|
|
||||||
|
def render_hideshow(self, record):
|
||||||
|
val = '<button id="'
|
||||||
|
val += str(record.pk)
|
||||||
|
val += '" class="btn btn-secondary btn-sm" \
|
||||||
|
onclick="hideshow(' + str(record.id) + ',' + \
|
||||||
|
str(record.display).lower() + ')">'
|
||||||
|
val += str(_("Hide/Show"))
|
||||||
|
val += '</button>'
|
||||||
|
return mark_safe(val)
|
||||||
|
@ -31,29 +31,29 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
|
|
||||||
{% block extrajavascript %}
|
{% block extrajavascript %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
function refreshMatchedWords() {
|
||||||
|
$("tr").each(function() {
|
||||||
|
let pattern = $('#search_field').val();
|
||||||
|
if (pattern) {
|
||||||
|
$(this).find("td:eq(0), td:eq(1), td:eq(3), td:eq(6)").each(function () {
|
||||||
|
$(this).html($(this).text().replace(new RegExp(pattern, 'i'), "<mark>$&</mark>"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadTable() {
|
||||||
|
let pattern = $('#search_field').val();
|
||||||
|
$("#buttons_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + " #buttons_table", refreshMatchedWords);
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
let searchbar_obj = $("#search_field");
|
let searchbar_obj = $("#search_field");
|
||||||
let timer_on = false;
|
let timer_on = false;
|
||||||
let timer;
|
let timer;
|
||||||
|
|
||||||
function refreshMatchedWords() {
|
|
||||||
$("tr").each(function() {
|
|
||||||
let pattern = searchbar_obj.val();
|
|
||||||
if (pattern) {
|
|
||||||
$(this).find("td:eq(0), td:eq(1), td:eq(3), td:eq(6)").each(function () {
|
|
||||||
$(this).html($(this).text().replace(new RegExp(pattern, 'i'), "<mark>$&</mark>"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshMatchedWords();
|
refreshMatchedWords();
|
||||||
|
|
||||||
function reloadTable() {
|
|
||||||
let pattern = searchbar_obj.val();
|
|
||||||
$("#buttons_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + " #buttons_table", refreshMatchedWords);
|
|
||||||
}
|
|
||||||
|
|
||||||
searchbar_obj.keyup(function() {
|
searchbar_obj.keyup(function() {
|
||||||
if (timer_on)
|
if (timer_on)
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
@ -77,5 +77,28 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
addMsg('{% trans "Unable to delete button "%} #' + button_id, 'danger')
|
addMsg('{% trans "Unable to delete button "%} #' + button_id, 'danger')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// on click of button "hide/show", call the API
|
||||||
|
function hideshow(id, displayed) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/note/transaction/template/' + id + '/',
|
||||||
|
type: 'PATCH',
|
||||||
|
dataType: 'json',
|
||||||
|
headers: {
|
||||||
|
'X-CSRFTOKEN': CSRF_TOKEN
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
display: !displayed
|
||||||
|
},
|
||||||
|
success: function() {
|
||||||
|
if(displayed)
|
||||||
|
addMsg("{% trans "Button hidden"%}", 'success', 1000)
|
||||||
|
else addMsg("{% trans "Button displayed"%}", 'success', 1000)
|
||||||
|
reloadTable()
|
||||||
|
},
|
||||||
|
error: function (err) {
|
||||||
|
addMsg("{% trans "An error occured"%}", 'danger')
|
||||||
|
}})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -90,9 +90,9 @@ class TransactionTemplateListView(ProtectQuerysetMixin, LoginRequiredMixin, Sing
|
|||||||
if "search" in self.request.GET:
|
if "search" in self.request.GET:
|
||||||
pattern = self.request.GET["search"]
|
pattern = self.request.GET["search"]
|
||||||
qs = qs.filter(
|
qs = qs.filter(
|
||||||
Q(name__iregex="^" + pattern)
|
Q(name__iregex=pattern)
|
||||||
| Q(destination__club__name__iregex="^" + pattern)
|
| Q(destination__club__name__iregex=pattern)
|
||||||
| Q(category__name__iregex="^" + pattern)
|
| Q(category__name__iregex=pattern)
|
||||||
| Q(description__iregex=pattern)
|
| Q(description__iregex=pattern)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -977,7 +977,7 @@
|
|||||||
],
|
],
|
||||||
"query": "[\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}]",
|
"query": "[\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}]",
|
||||||
"type": "view",
|
"type": "view",
|
||||||
"mask": 1,
|
"mask": 2,
|
||||||
"field": "",
|
"field": "",
|
||||||
"permanent": false,
|
"permanent": false,
|
||||||
"description": "Voir les transactions d'un club"
|
"description": "Voir les transactions d'un club"
|
||||||
@ -2511,7 +2511,7 @@
|
|||||||
"note",
|
"note",
|
||||||
"noteuser"
|
"noteuser"
|
||||||
],
|
],
|
||||||
"query": "[\"AND\", {\"user\": [\"user\"]}, [\"OR\", {\"inactivity_reason\": \"manual\"}, {\"inactivity_reason\": null}]]",
|
"query": "[\"AND\", {\"user\": [\"user\"]}, [\"OR\", {\"inactivity_reason\": \"manual\"}, {\"is_active\": true}]]",
|
||||||
"type": "change",
|
"type": "change",
|
||||||
"mask": 1,
|
"mask": 1,
|
||||||
"field": "is_active",
|
"field": "is_active",
|
||||||
@ -2527,7 +2527,7 @@
|
|||||||
"note",
|
"note",
|
||||||
"noteuser"
|
"noteuser"
|
||||||
],
|
],
|
||||||
"query": "[\"AND\", {\"user\": [\"user\"]}, [\"OR\", {\"inactivity_reason\": \"manual\"}, {\"inactivity_reason\": null}]]",
|
"query": "[\"AND\", {\"user\": [\"user\"]}, [\"OR\", {\"inactivity_reason\": \"manual\"}, {\"is_active\": true}]]",
|
||||||
"type": "change",
|
"type": "change",
|
||||||
"mask": 1,
|
"mask": 1,
|
||||||
"field": "inactivity_reason",
|
"field": "inactivity_reason",
|
||||||
@ -2871,6 +2871,38 @@
|
|||||||
"description": "Changer l'image de n'importe quelle note"
|
"description": "Changer l'image de n'importe quelle note"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 184,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"note",
|
||||||
|
"noteclub"
|
||||||
|
],
|
||||||
|
"query": "[\"AND\", {\"club\": [\"club\"]}, [\"OR\", {\"inactivity_reason\": \"manual\"}, {\"is_active\": true}]]",
|
||||||
|
"type": "change",
|
||||||
|
"mask": 3,
|
||||||
|
"field": "is_active",
|
||||||
|
"permanent": true,
|
||||||
|
"description": "(Dé)bloquer la note de son club manuellement"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "permission.permission",
|
||||||
|
"pk": 185,
|
||||||
|
"fields": {
|
||||||
|
"model": [
|
||||||
|
"note",
|
||||||
|
"noteclub"
|
||||||
|
],
|
||||||
|
"query": "[\"AND\", {\"club\": [\"club\"]}, [\"OR\", {\"inactivity_reason\": \"manual\"}, {\"is_active\": true}]]",
|
||||||
|
"type": "change",
|
||||||
|
"mask": 3,
|
||||||
|
"field": "inactivity_reason",
|
||||||
|
"permanent": true,
|
||||||
|
"description": "(Dé)bloquer la note de son club et indiquer que cela a été fait manuellement"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"model": "permission.role",
|
"model": "permission.role",
|
||||||
"pk": 1,
|
"pk": 1,
|
||||||
@ -3010,7 +3042,9 @@
|
|||||||
166,
|
166,
|
||||||
167,
|
167,
|
||||||
168,
|
168,
|
||||||
182
|
182,
|
||||||
|
184,
|
||||||
|
185
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3278,7 +3312,9 @@
|
|||||||
180,
|
180,
|
||||||
181,
|
181,
|
||||||
182,
|
182,
|
||||||
183
|
183,
|
||||||
|
184,
|
||||||
|
185
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3338,7 +3374,8 @@
|
|||||||
45,
|
45,
|
||||||
46,
|
46,
|
||||||
148,
|
148,
|
||||||
149
|
149,
|
||||||
|
182
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -11,25 +11,25 @@
|
|||||||
<div class="accordion" id="accordionApps">
|
<div class="accordion" id="accordionApps">
|
||||||
{% for app, app_scopes in scopes.items %}
|
{% for app, app_scopes in scopes.items %}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header" id="app-{{ app.name.lower }}-title">
|
<div class="card-header" id="app-{{ app.name|slugify }}-title">
|
||||||
<a class="text-decoration-none collapsed" href="#" data-toggle="collapse"
|
<a class="text-decoration-none collapsed" href="#" data-toggle="collapse"
|
||||||
data-target="#app-{{ app.name.lower }}" aria-expanded="false"
|
data-target="#app-{{ app.name|slugify }}" aria-expanded="false"
|
||||||
aria-controls="app-{{ app.name.lower }}">
|
aria-controls="app-{{ app.name|slugify }}">
|
||||||
{{ app.name }}
|
{{ app.name }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse" id="app-{{ app.name.lower }}" aria-labelledby="app-{{ app.name.lower }}" data-target="#accordionApps">
|
<div class="collapse" id="app-{{ app.name|slugify }}" aria-labelledby="app-{{ app.name|slugify }}" data-target="#accordionApps">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% for scope_id, scope_desc in app_scopes.items %}
|
{% for scope_id, scope_desc in app_scopes.items %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-check-label" for="scope-{{ app.name.lower }}-{{ scope_id }}">
|
<label class="form-check-label" for="scope-{{ app.name|slugify }}-{{ scope_id }}">
|
||||||
<input type="checkbox" id="scope-{{ app.name.lower }}-{{ scope_id }}"
|
<input type="checkbox" id="scope-{{ app.name|slugify }}-{{ scope_id }}"
|
||||||
name="scope-{{ app.name.lower }}" class="checkboxinput form-check-input" value="{{ scope_id }}">
|
name="scope-{{ app.name|slugify }}" class="checkboxinput form-check-input" value="{{ scope_id }}">
|
||||||
{{ scope_desc }}
|
{{ scope_desc }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<p id="url-{{ app.name.lower }}">
|
<p id="url-{{ app.name|slugify }}">
|
||||||
<a href="{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code" target="_blank">
|
<a href="{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code" target="_blank">
|
||||||
{{ request.scheme }}://{{ request.get_host }}{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code
|
{{ request.scheme }}://{{ request.get_host }}{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code
|
||||||
</a>
|
</a>
|
||||||
@ -51,11 +51,10 @@
|
|||||||
{% block extrajavascript %}
|
{% block extrajavascript %}
|
||||||
<script>
|
<script>
|
||||||
{% for app in scopes.keys %}
|
{% for app in scopes.keys %}
|
||||||
let elements = document.getElementsByName("scope-{{ app.name.lower }}");
|
for (let element of document.getElementsByName("scope-{{ app.name|slugify }}")) {
|
||||||
for (let element of elements) {
|
|
||||||
element.onchange = function (event) {
|
element.onchange = function (event) {
|
||||||
let scope = ""
|
let scope = ""
|
||||||
for (let element of elements) {
|
for (let element of document.getElementsByName("scope-{{ app.name|slugify }}")) {
|
||||||
if (element.checked) {
|
if (element.checked) {
|
||||||
scope += element.value + " "
|
scope += element.value + " "
|
||||||
}
|
}
|
||||||
@ -63,7 +62,7 @@
|
|||||||
|
|
||||||
scope = scope.substr(0, scope.length - 1)
|
scope = scope.substr(0, scope.length - 1)
|
||||||
|
|
||||||
document.getElementById("url-{{ app.name.lower }}").innerHTML = 'Scopes : ' + scope
|
document.getElementById("url-{{ app.name|slugify }}").innerHTML = 'Scopes : ' + scope
|
||||||
+ '<br><a href="{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code&scope='+ scope.replaceAll(' ', '%20')
|
+ '<br><a href="{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code&scope='+ scope.replaceAll(' ', '%20')
|
||||||
+ '" target="_blank">{{ request.scheme }}://{{ request.get_host }}{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code&scope='
|
+ '" target="_blank">{{ request.scheme }}://{{ request.get_host }}{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code&scope='
|
||||||
+ scope.replaceAll(' ', '%20') + '</a>'
|
+ scope.replaceAll(' ', '%20') + '</a>'
|
||||||
|
Submodule apps/scripts updated: 7a022b9407...86bc2d2698
18
apps/treasury/migrations/0004_auto_20211005_1544.py
Normal file
18
apps/treasury/migrations/0004_auto_20211005_1544.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 2.2.24 on 2021-10-05 13:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('treasury', '0003_auto_20210321_1034'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='sogecredit',
|
||||||
|
name='transactions',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='_sogecredit_transactions_+', to='note.MembershipTransaction', verbose_name='membership transactions'),
|
||||||
|
),
|
||||||
|
]
|
@ -86,7 +86,7 @@ Génération
|
|||||||
|
|
||||||
Les factures peuvent s'exporter au format PDF (là est tout leur intérêt). Pour cela, on utilise le template LaTeX
|
Les factures peuvent s'exporter au format PDF (là est tout leur intérêt). Pour cela, on utilise le template LaTeX
|
||||||
présent à l'adresse suivante :
|
présent à l'adresse suivante :
|
||||||
`/templates/treasury/invoice_sample.tex <https://gitlab.crans.org/bde/nk20/-/tree/master/templates/treasury/invoice_sample.tex>`_
|
`/templates/treasury/invoice_sample.tex <https://gitlab.crans.org/bde/nk20/-/tree/main/templates/treasury/invoice_sample.tex>`_
|
||||||
|
|
||||||
On le remplit avec les données de la facture et les données du BDE, hard-codées. On copie le template rempli dans un
|
On le remplit avec les données de la facture et les données du BDE, hard-codées. On copie le template rempli dans un
|
||||||
ficher tex dans un dossier temporaire. On fait ensuite 2 appels à ``pdflatex`` pour générer la facture au format PDF.
|
ficher tex dans un dossier temporaire. On fait ensuite 2 appels à ``pdflatex`` pour générer la facture au format PDF.
|
||||||
|
@ -88,7 +88,7 @@ On clone donc le dépôt en tant que ``www-data`` :
|
|||||||
|
|
||||||
$ sudo -u www-data git clone https://gitlab.crans.org/bde/nk20.git /var/www/note_kfet
|
$ sudo -u www-data git clone https://gitlab.crans.org/bde/nk20.git /var/www/note_kfet
|
||||||
|
|
||||||
Par défaut, le dépôt est configuré pour suivre la branche ``master``, qui est la branche
|
Par défaut, le dépôt est configuré pour suivre la branche ``main``, qui est la branche
|
||||||
stable, notamment installée sur `<https://note.crans.org/>`_. Pour changer de branche,
|
stable, notamment installée sur `<https://note.crans.org/>`_. Pour changer de branche,
|
||||||
notamment passer sur la branche ``beta`` sur un serveur de pré-production (un peu comme
|
notamment passer sur la branche ``beta`` sur un serveur de pré-production (un peu comme
|
||||||
`<https://note-dev.crans.org/>`_), on peut faire :
|
`<https://note-dev.crans.org/>`_), on peut faire :
|
||||||
@ -587,7 +587,7 @@ Dans ce fichier, remplissez :
|
|||||||
---
|
---
|
||||||
note:
|
note:
|
||||||
server_name: note.crans.org
|
server_name: note.crans.org
|
||||||
git_branch: master
|
git_branch: main
|
||||||
cron_enabled: true
|
cron_enabled: true
|
||||||
email: notekfet2020@lists.crans.org
|
email: notekfet2020@lists.crans.org
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-09-28 17:02+0200\n"
|
"POT-Creation-Date: 2021-10-07 22:55+0200\n"
|
||||||
"PO-Revision-Date: 2020-11-16 20:02+0000\n"
|
"PO-Revision-Date: 2020-11-16 20:02+0000\n"
|
||||||
"Last-Translator: Yohann D'ANELLO <ynerant@crans.org>\n"
|
"Last-Translator: Yohann D'ANELLO <ynerant@crans.org>\n"
|
||||||
"Language-Team: French <http://translate.ynerant.fr/projects/nk20/nk20/fr/>\n"
|
"Language-Team: French <http://translate.ynerant.fr/projects/nk20/nk20/fr/>\n"
|
||||||
@ -279,7 +279,7 @@ msgstr "Prénom"
|
|||||||
msgid "Note"
|
msgid "Note"
|
||||||
msgstr "Note"
|
msgstr "Note"
|
||||||
|
|
||||||
#: apps/activity/tables.py:90 apps/member/tables.py:49
|
#: apps/activity/tables.py:90 apps/member/tables.py:50
|
||||||
msgid "Balance"
|
msgid "Balance"
|
||||||
msgstr "Solde du compte"
|
msgstr "Solde du compte"
|
||||||
|
|
||||||
@ -320,13 +320,13 @@ msgstr "Entrées"
|
|||||||
msgid "Return to activity page"
|
msgid "Return to activity page"
|
||||||
msgstr "Retour à la page de l'activité"
|
msgstr "Retour à la page de l'activité"
|
||||||
|
|
||||||
#: apps/activity/templates/activity/activity_entry.html:89
|
#: apps/activity/templates/activity/activity_entry.html:94
|
||||||
#: apps/activity/templates/activity/activity_entry.html:124
|
#: apps/activity/templates/activity/activity_entry.html:129
|
||||||
msgid "Entry done, but caution: the user is not a Kfet member."
|
msgid "Entry done, but caution: the user is not a Kfet member."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Entrée effectuée, mais attention : la personne n'est pas un adhérent Kfet."
|
"Entrée effectuée, mais attention : la personne n'est pas un adhérent Kfet."
|
||||||
|
|
||||||
#: apps/activity/templates/activity/activity_entry.html:127
|
#: apps/activity/templates/activity/activity_entry.html:132
|
||||||
msgid "Entry done!"
|
msgid "Entry done!"
|
||||||
msgstr "Entrée effectuée !"
|
msgstr "Entrée effectuée !"
|
||||||
|
|
||||||
@ -404,33 +404,33 @@ msgstr "Créer une nouvelle activité"
|
|||||||
msgid "Activities"
|
msgid "Activities"
|
||||||
msgstr "Activités"
|
msgstr "Activités"
|
||||||
|
|
||||||
#: apps/activity/views.py:95
|
#: apps/activity/views.py:93
|
||||||
msgid "Activity detail"
|
msgid "Activity detail"
|
||||||
msgstr "Détails de l'activité"
|
msgstr "Détails de l'activité"
|
||||||
|
|
||||||
#: apps/activity/views.py:115
|
#: apps/activity/views.py:113
|
||||||
msgid "Update activity"
|
msgid "Update activity"
|
||||||
msgstr "Modifier l'activité"
|
msgstr "Modifier l'activité"
|
||||||
|
|
||||||
#: apps/activity/views.py:142
|
#: apps/activity/views.py:140
|
||||||
msgid "Invite guest to the activity \"{}\""
|
msgid "Invite guest to the activity \"{}\""
|
||||||
msgstr "Invitation pour l'activité « {} »"
|
msgstr "Invitation pour l'activité « {} »"
|
||||||
|
|
||||||
#: apps/activity/views.py:177
|
#: apps/activity/views.py:178
|
||||||
msgid "You are not allowed to display the entry interface for this activity."
|
msgid "You are not allowed to display the entry interface for this activity."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous n'êtes pas autorisé à afficher l'interface des entrées pour cette "
|
"Vous n'êtes pas autorisé à afficher l'interface des entrées pour cette "
|
||||||
"activité."
|
"activité."
|
||||||
|
|
||||||
#: apps/activity/views.py:180
|
#: apps/activity/views.py:181
|
||||||
msgid "This activity does not support activity entries."
|
msgid "This activity does not support activity entries."
|
||||||
msgstr "Cette activité ne requiert pas d'entrées."
|
msgstr "Cette activité ne requiert pas d'entrées."
|
||||||
|
|
||||||
#: apps/activity/views.py:183
|
#: apps/activity/views.py:184
|
||||||
msgid "This activity is closed."
|
msgid "This activity is closed."
|
||||||
msgstr "Cette activité est fermée."
|
msgstr "Cette activité est fermée."
|
||||||
|
|
||||||
#: apps/activity/views.py:279
|
#: apps/activity/views.py:280
|
||||||
msgid "Entry for activity \"{}\""
|
msgid "Entry for activity \"{}\""
|
||||||
msgstr "Entrées pour l'activité « {} »"
|
msgstr "Entrées pour l'activité « {} »"
|
||||||
|
|
||||||
@ -466,7 +466,7 @@ msgstr "nouvelles données"
|
|||||||
msgid "create"
|
msgid "create"
|
||||||
msgstr "créer"
|
msgstr "créer"
|
||||||
|
|
||||||
#: apps/logs/models.py:65 apps/note/tables.py:165 apps/note/tables.py:201
|
#: apps/logs/models.py:65 apps/note/tables.py:165 apps/note/tables.py:211
|
||||||
#: apps/permission/models.py:127 apps/treasury/tables.py:38
|
#: apps/permission/models.py:127 apps/treasury/tables.py:38
|
||||||
#: apps/wei/tables.py:74
|
#: apps/wei/tables.py:74
|
||||||
msgid "delete"
|
msgid "delete"
|
||||||
@ -850,33 +850,33 @@ msgstr "l'adhésion commence le"
|
|||||||
msgid "membership ends on"
|
msgid "membership ends on"
|
||||||
msgstr "l'adhésion finit le"
|
msgstr "l'adhésion finit le"
|
||||||
|
|
||||||
#: apps/member/models.py:422
|
#: apps/member/models.py:428
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "The role {role} does not apply to the club {club}."
|
msgid "The role {role} does not apply to the club {club}."
|
||||||
msgstr "Le rôle {role} ne s'applique pas au club {club}."
|
msgstr "Le rôle {role} ne s'applique pas au club {club}."
|
||||||
|
|
||||||
#: apps/member/models.py:431 apps/member/views.py:651
|
#: apps/member/models.py:437 apps/member/views.py:651
|
||||||
msgid "User is already a member of the club"
|
msgid "User is already a member of the club"
|
||||||
msgstr "L'utilisateur est déjà membre du club"
|
msgstr "L'utilisateur est déjà membre du club"
|
||||||
|
|
||||||
#: apps/member/models.py:443 apps/member/views.py:660
|
#: apps/member/models.py:449 apps/member/views.py:660
|
||||||
msgid "User is not a member of the parent club"
|
msgid "User is not a member of the parent club"
|
||||||
msgstr "L'utilisateur n'est pas membre du club parent"
|
msgstr "L'utilisateur n'est pas membre du club parent"
|
||||||
|
|
||||||
#: apps/member/models.py:496
|
#: apps/member/models.py:502
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Membership of {user} for the club {club}"
|
msgid "Membership of {user} for the club {club}"
|
||||||
msgstr "Adhésion de {user} pour le club {club}"
|
msgstr "Adhésion de {user} pour le club {club}"
|
||||||
|
|
||||||
#: apps/member/models.py:499 apps/note/models/transactions.py:389
|
#: apps/member/models.py:505 apps/note/models/transactions.py:389
|
||||||
msgid "membership"
|
msgid "membership"
|
||||||
msgstr "adhésion"
|
msgstr "adhésion"
|
||||||
|
|
||||||
#: apps/member/models.py:500
|
#: apps/member/models.py:506
|
||||||
msgid "memberships"
|
msgid "memberships"
|
||||||
msgstr "adhésions"
|
msgstr "adhésions"
|
||||||
|
|
||||||
#: apps/member/tables.py:137
|
#: apps/member/tables.py:139
|
||||||
msgid "Renew"
|
msgid "Renew"
|
||||||
msgstr "Renouveler"
|
msgstr "Renouveler"
|
||||||
|
|
||||||
@ -1535,7 +1535,7 @@ msgstr "Cliquez pour valider"
|
|||||||
msgid "No reason specified"
|
msgid "No reason specified"
|
||||||
msgstr "Pas de motif spécifié"
|
msgstr "Pas de motif spécifié"
|
||||||
|
|
||||||
#: apps/note/tables.py:169 apps/note/tables.py:203 apps/treasury/tables.py:39
|
#: apps/note/tables.py:169 apps/note/tables.py:213 apps/treasury/tables.py:39
|
||||||
#: apps/treasury/templates/treasury/invoice_confirm_delete.html:30
|
#: apps/treasury/templates/treasury/invoice_confirm_delete.html:30
|
||||||
#: apps/treasury/templates/treasury/sogecredit_detail.html:65
|
#: apps/treasury/templates/treasury/sogecredit_detail.html:65
|
||||||
#: apps/wei/tables.py:75 apps/wei/tables.py:118
|
#: apps/wei/tables.py:75 apps/wei/tables.py:118
|
||||||
@ -1556,6 +1556,10 @@ msgstr "Supprimer"
|
|||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Éditer"
|
msgstr "Éditer"
|
||||||
|
|
||||||
|
#: apps/note/tables.py:201 apps/note/tables.py:224
|
||||||
|
msgid "Hide/Show"
|
||||||
|
msgstr "Afficher/Masquer"
|
||||||
|
|
||||||
#: apps/note/templates/note/conso_form.html:22
|
#: apps/note/templates/note/conso_form.html:22
|
||||||
#: apps/note/templates/note/transaction_form.html:48
|
#: apps/note/templates/note/transaction_form.html:48
|
||||||
msgid "Please select a note"
|
msgid "Please select a note"
|
||||||
@ -1685,6 +1689,18 @@ msgstr "le bouton a bien été supprimé "
|
|||||||
msgid "Unable to delete button "
|
msgid "Unable to delete button "
|
||||||
msgstr "Impossible de supprimer le bouton "
|
msgstr "Impossible de supprimer le bouton "
|
||||||
|
|
||||||
|
#: apps/note/templates/note/transactiontemplate_list.html:95
|
||||||
|
msgid "Button hidden"
|
||||||
|
msgstr "Bouton masqué"
|
||||||
|
|
||||||
|
#: apps/note/templates/note/transactiontemplate_list.html:96
|
||||||
|
msgid "Button displayed"
|
||||||
|
msgstr "Bouton affiché"
|
||||||
|
|
||||||
|
#: apps/note/templates/note/transactiontemplate_list.html:100
|
||||||
|
msgid "An error occured"
|
||||||
|
msgstr "Une erreur s'est produite"
|
||||||
|
|
||||||
#: apps/note/views.py:36
|
#: apps/note/views.py:36
|
||||||
msgid "Transfer money"
|
msgid "Transfer money"
|
||||||
msgstr "Transférer de l'argent"
|
msgstr "Transférer de l'argent"
|
||||||
@ -3501,8 +3517,3 @@ msgstr ""
|
|||||||
"vous connecter. Vous devez vous rendre à la Kfet et payer les frais "
|
"vous connecter. Vous devez vous rendre à la Kfet et payer les frais "
|
||||||
"d'adhésion. Vous devez également valider votre adresse email en suivant le "
|
"d'adhésion. Vous devez également valider votre adresse email en suivant le "
|
||||||
"lien que vous avez reçu."
|
"lien que vous avez reçu."
|
||||||
|
|
||||||
#~ msgid "You are not a Kfet member, so you can't use your note account."
|
|
||||||
#~ msgstr ""
|
|
||||||
#~ "Vous n'êtes pas adhérent Kfet, vous ne pouvez par conséquent pas utiliser "
|
|
||||||
#~ "votre compte note."
|
|
||||||
|
6
note_kfet/static/js/turbolinks.js
Normal file
6
note_kfet/static/js/turbolinks.js
Normal file
File diff suppressed because one or more lines are too long
@ -33,8 +33,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
<script src="{% static "jquery/jquery.min.js" %}"></script>
|
<script src="{% static "jquery/jquery.min.js" %}"></script>
|
||||||
<script src="{% static "popper.js/umd/popper.min.js" %}"></script>
|
<script src="{% static "popper.js/umd/popper.min.js" %}"></script>
|
||||||
<script src="{% static "bootstrap4/js/bootstrap.min.js" %}"></script>
|
<script src="{% static "bootstrap4/js/bootstrap.min.js" %}"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/turbolinks/5.2.0/turbolinks.js"
|
<script src="{% static "js/turbolinks.js" %}"></script>
|
||||||
crossorigin="anonymous"></script>
|
|
||||||
<script src="{% static "js/base.js" %}"></script>
|
<script src="{% static "js/base.js" %}"></script>
|
||||||
<script src="{% static "js/konami.js" %}"></script>
|
<script src="{% static "js/konami.js" %}"></script>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user