Merge branch 'beta' into 'master'

Changements variés et mineurs

Closes #107 et #91

See merge request bde/nk20!191
This commit is contained in:
ynerant 2021-12-13 21:16:26 +01:00
commit 1eb72044c2
14 changed files with 232 additions and 65 deletions

1
.gitignore vendored
View File

@ -47,6 +47,7 @@ backups/
env/
venv/
db.sqlite3
shell.nix
# ansibles customs host
ansible/host_vars/*.yaml

View File

@ -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),
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"])
sample_entry = Entry(activity=activity, note=self.request.user.note)

View 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'),
),
]

View File

@ -18,7 +18,7 @@ from django.views.generic import DetailView, UpdateView, TemplateView
from django.views.generic.edit import FormMixin
from django_tables2.views import SingleTableView
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.tables import HistoryTable, AliasTable
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)
# Don't log these tests
modified_note._no_signal = True
modified_note.is_active = True
modified_note.is_active = False
modified_note.inactivity_reason = 'manual'
context["can_lock_note"] = user.note.is_active and PermissionBackend\
.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.save()
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._no_signal = True
old_note.save()
modified_note.refresh_from_db()
modified_note.is_active = True
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
@ -256,7 +256,8 @@ class ProfileAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
context = super().get_context_data(**kwargs)
note = context['object'].note
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(
note=context["object"].note,
name="",
@ -403,9 +404,12 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
"""
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):
club.update_membership_dates()
# managers list
managers = Membership.objects.filter(club=self.object, roles__name="Bureau de club",
date_start__lte=date.today(), date_end__gte=date.today())\
@ -443,6 +447,29 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
context["can_add_members"] = PermissionBackend()\
.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

View File

@ -4,7 +4,7 @@
import html
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.utils.translation import gettext_lazy as _
from note_kfet.middlewares import get_current_request
@ -197,6 +197,17 @@ class ButtonTable(tables.Table):
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,
extra_context={"delete_trans": _('delete')},
attrs={'td': {'class': 'col-sm-1'}},
@ -204,3 +215,16 @@ class ButtonTable(tables.Table):
def render_amount(self, 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)

View File

@ -31,29 +31,29 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% block extrajavascript %}
<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() {
let searchbar_obj = $("#search_field");
let timer_on = false;
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();
function reloadTable() {
let pattern = searchbar_obj.val();
$("#buttons_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + " #buttons_table", refreshMatchedWords);
}
searchbar_obj.keyup(function() {
if (timer_on)
clearTimeout(timer);
@ -77,5 +77,28 @@ SPDX-License-Identifier: GPL-3.0-or-later
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>
{% endblock %}

View File

@ -90,9 +90,9 @@ class TransactionTemplateListView(ProtectQuerysetMixin, LoginRequiredMixin, Sing
if "search" in self.request.GET:
pattern = self.request.GET["search"]
qs = qs.filter(
Q(name__iregex="^" + pattern)
| Q(destination__club__name__iregex="^" + pattern)
| Q(category__name__iregex="^" + pattern)
Q(name__iregex=pattern)
| Q(destination__club__name__iregex=pattern)
| Q(category__name__iregex=pattern)
| Q(description__iregex=pattern)
)

View File

@ -977,7 +977,7 @@
],
"query": "[\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}]",
"type": "view",
"mask": 1,
"mask": 2,
"field": "",
"permanent": false,
"description": "Voir les transactions d'un club"
@ -2511,7 +2511,7 @@
"note",
"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",
"mask": 1,
"field": "is_active",
@ -2527,7 +2527,7 @@
"note",
"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",
"mask": 1,
"field": "inactivity_reason",
@ -2871,6 +2871,38 @@
"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",
"pk": 1,
@ -3010,7 +3042,9 @@
166,
167,
168,
182
182,
184,
185
]
}
},
@ -3278,7 +3312,9 @@
180,
181,
182,
183
183,
184,
185
]
}
},
@ -3338,7 +3374,8 @@
45,
46,
148,
149
149,
182
]
}
},

@ -1 +1 @@
Subproject commit 7a022b9407bdcbe97a78bfc10b2812c9b0aaf314
Subproject commit 86bc2d269853ad60391e242ff655f0dc83b5967d

View 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'),
),
]

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \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"
"Last-Translator: Yohann D'ANELLO <ynerant@crans.org>\n"
"Language-Team: French <http://translate.ynerant.fr/projects/nk20/nk20/fr/>\n"
@ -279,7 +279,7 @@ msgstr "Prénom"
msgid "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"
msgstr "Solde du compte"
@ -320,13 +320,13 @@ msgstr "Entrées"
msgid "Return to activity page"
msgstr "Retour à la page de l'activité"
#: apps/activity/templates/activity/activity_entry.html:89
#: apps/activity/templates/activity/activity_entry.html:124
#: apps/activity/templates/activity/activity_entry.html:94
#: apps/activity/templates/activity/activity_entry.html:129
msgid "Entry done, but caution: the user is not a Kfet member."
msgstr ""
"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!"
msgstr "Entrée effectuée !"
@ -404,33 +404,33 @@ msgstr "Créer une nouvelle activité"
msgid "Activities"
msgstr "Activités"
#: apps/activity/views.py:95
#: apps/activity/views.py:93
msgid "Activity detail"
msgstr "Détails de l'activité"
#: apps/activity/views.py:115
#: apps/activity/views.py:113
msgid "Update activity"
msgstr "Modifier l'activité"
#: apps/activity/views.py:142
#: apps/activity/views.py:140
msgid "Invite guest to the activity \"{}\""
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."
msgstr ""
"Vous n'êtes pas autorisé à afficher l'interface des entrées pour cette "
"activité."
#: apps/activity/views.py:180
#: apps/activity/views.py:181
msgid "This activity does not support activity entries."
msgstr "Cette activité ne requiert pas d'entrées."
#: apps/activity/views.py:183
#: apps/activity/views.py:184
msgid "This activity is closed."
msgstr "Cette activité est fermée."
#: apps/activity/views.py:279
#: apps/activity/views.py:280
msgid "Entry for activity \"{}\""
msgstr "Entrées pour l'activité « {} »"
@ -466,7 +466,7 @@ msgstr "nouvelles données"
msgid "create"
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/wei/tables.py:74
msgid "delete"
@ -850,33 +850,33 @@ msgstr "l'adhésion commence le"
msgid "membership ends on"
msgstr "l'adhésion finit le"
#: apps/member/models.py:422
#: apps/member/models.py:428
#, python-brace-format
msgid "The role {role} does not apply to the 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"
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"
msgstr "L'utilisateur n'est pas membre du club parent"
#: apps/member/models.py:496
#: apps/member/models.py:502
#, python-brace-format
msgid "Membership of {user} for the 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"
msgstr "adhésion"
#: apps/member/models.py:500
#: apps/member/models.py:506
msgid "memberships"
msgstr "adhésions"
#: apps/member/tables.py:137
#: apps/member/tables.py:139
msgid "Renew"
msgstr "Renouveler"
@ -1535,7 +1535,7 @@ msgstr "Cliquez pour valider"
msgid "No reason specified"
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/sogecredit_detail.html:65
#: apps/wei/tables.py:75 apps/wei/tables.py:118
@ -1556,6 +1556,10 @@ msgstr "Supprimer"
msgid "Edit"
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/transaction_form.html:48
msgid "Please select a note"
@ -1685,6 +1689,18 @@ msgstr "le bouton a bien été supprimé "
msgid "Unable to delete button "
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
msgid "Transfer money"
msgstr "Transférer de l'argent"
@ -3501,8 +3517,3 @@ msgstr ""
"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 "
"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."

File diff suppressed because one or more lines are too long

View File

@ -33,8 +33,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
<script src="{% static "jquery/jquery.min.js" %}"></script>
<script src="{% static "popper.js/umd/popper.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"
crossorigin="anonymous"></script>
<script src="{% static "js/turbolinks.js" %}"></script>
<script src="{% static "js/base.js" %}"></script>
<script src="{% static "js/konami.js" %}"></script>

View File

@ -4,14 +4,14 @@ django-bootstrap-datepicker-plus~=3.0.5
django-cas-server~=1.2.0
django-colorfield~=0.3.2
django-crispy-forms~=1.7.2
django-extensions~=2.1.4
django-filter~=2.1.0
django-extensions>=2.1.4
django-filter~=2.1
django-htcpcp-tea~=0.3.1
django-mailer~=2.0.1
django-oauth-toolkit~=1.3.3
django-phonenumber-field~=5.0.0
django-polymorphic~=2.0.3
djangorestframework~=3.9.0
django-polymorphic>=2.0.3,<3.0.0
djangorestframework>=3.9.0,<3.13.0
django-rest-polymorphic~=0.1.9
django-tables2~=2.3.1
python-memcached~=1.59