mirror of https://gitlab.crans.org/bde/nk20
Compare commits
6 Commits
58fe8914cf
...
66defee3ea
Author | SHA1 | Date |
---|---|---|
Yohann D'ANELLO | 66defee3ea | |
Yohann D'ANELLO | f8a4087e56 | |
Yohann D'ANELLO | 94086505e6 | |
Yohann D'ANELLO | 6c8843e5fc | |
Yohann D'ANELLO | 0e8174aacd | |
Yohann D'ANELLO | 0e3c4fcaf6 |
|
@ -68,12 +68,8 @@ class HistoryTable(tables.Table):
|
||||||
"note.change_transaction_invalidity_reason", record) else None,
|
"note.change_transaction_invalidity_reason", record) else None,
|
||||||
"onmouseover": lambda record: '$("#invalidity_reason_'
|
"onmouseover": lambda record: '$("#invalidity_reason_'
|
||||||
+ str(record.id) + '").show();$("#invalidity_reason_'
|
+ str(record.id) + '").show();$("#invalidity_reason_'
|
||||||
+ str(record.id) + '").focus();'
|
+ str(record.id) + '").focus();',
|
||||||
if PermissionBackend.check_perm(get_current_authenticated_user(),
|
"onmouseout": lambda record: '$("#invalidity_reason_' + str(record.id) + '").hide()',
|
||||||
"note.change_transaction_invalidity_reason", record) else None,
|
|
||||||
"onmouseout": lambda record: '$("#invalidity_reason_' + str(record.id) + '").hide()'
|
|
||||||
if PermissionBackend.check_perm(get_current_authenticated_user(),
|
|
||||||
"note.change_transaction_invalidity_reason", record) else None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -101,15 +97,18 @@ class HistoryTable(tables.Table):
|
||||||
"""
|
"""
|
||||||
When the validation status is hovered, an input field is displayed to let the user specify an invalidity reason
|
When the validation status is hovered, an input field is displayed to let the user specify an invalidity reason
|
||||||
"""
|
"""
|
||||||
|
has_perm = PermissionBackend\
|
||||||
|
.check_perm(get_current_authenticated_user(), "note.change_transaction_invalidity_reason", record)
|
||||||
|
|
||||||
val = "✔" if value else "✖"
|
val = "✔" if value else "✖"
|
||||||
if not PermissionBackend\
|
|
||||||
.check_perm(get_current_authenticated_user(), "note.change_transaction_invalidity_reason", record):
|
if value and not has_perm:
|
||||||
return val
|
return val
|
||||||
|
|
||||||
val += "<input type='text' class='form-control' id='invalidity_reason_" + str(record.id) \
|
val += "<input type='text' class='form-control' id='invalidity_reason_" + str(record.id) \
|
||||||
+ "' value='" + (html.escape(record.invalidity_reason)
|
+ "' value='" + (html.escape(record.invalidity_reason)
|
||||||
if record.invalidity_reason else ("" if value else str(_("No reason specified")))) \
|
if record.invalidity_reason else ("" if value else str(_("No reason specified")))) \
|
||||||
+ "'" + ("" if value else " disabled") \
|
+ "'" + ("" if value and has_perm else " disabled") \
|
||||||
+ " placeholder='" + html.escape(_("invalidity reason").capitalize()) + "'" \
|
+ " placeholder='" + html.escape(_("invalidity reason").capitalize()) + "'" \
|
||||||
+ " style='position: absolute; width: 15em; margin-left: -15.5em; margin-top: -2em; display: none;'>"
|
+ " style='position: absolute; width: 15em; margin-left: -15.5em; margin-top: -2em; display: none;'>"
|
||||||
return format_html(val)
|
return format_html(val)
|
||||||
|
|
|
@ -4,12 +4,15 @@
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
import operator
|
import operator
|
||||||
|
from copy import copy
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.core.mail import mail_admins
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import F, Q, Model
|
from django.db.models import F, Q, Model
|
||||||
|
from django.forms import model_to_dict
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,35 +41,40 @@ class InstancedPermission:
|
||||||
if permission_type == self.type:
|
if permission_type == self.type:
|
||||||
self.update_query()
|
self.update_query()
|
||||||
|
|
||||||
# Don't increase indexes, if the primary key is an AutoField
|
obj = copy(obj)
|
||||||
if not hasattr(obj, "pk") or not obj.pk:
|
obj.pk = 0
|
||||||
obj.pk = 0
|
|
||||||
oldpk = None
|
|
||||||
else:
|
|
||||||
oldpk = obj.pk
|
|
||||||
# Ensure previous models are deleted
|
# Ensure previous models are deleted
|
||||||
for ignored in range(1000):
|
for ignored in range(1000):
|
||||||
if self.model.model_class().objects.filter(pk=obj.pk).exists():
|
if self.model.model_class().objects.filter(pk=0).exists():
|
||||||
# If the object exists, that means that one permission is currently checked.
|
# If the object exists, that means that one permission is currently checked.
|
||||||
# We wait before the other permission, at most 1 second.
|
# We wait before the other permission, at most 1 second.
|
||||||
sleep(0.001)
|
sleep(0.001)
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
for o in self.model.model_class().objects.filter(pk=obj.pk).all():
|
for o in self.model.model_class().objects.filter(pk=0).all():
|
||||||
o._force_delete = True
|
o._force_delete = True
|
||||||
Model.delete(o)
|
Model.delete(o)
|
||||||
|
# An object with pk 0 wouldn't deleted. That's not normal, we alert admins.
|
||||||
|
msg = "Lors de la vérification d'une permission d'ajout, un objet de clé primaire nulle était "\
|
||||||
|
"encore présent.\n"\
|
||||||
|
"Type de permission : " + self.type + "\n"\
|
||||||
|
"Modèle : " + str(self.model) + "\n"\
|
||||||
|
"Objet trouvé : " + str(model_to_dict(o)) + "\n\n"\
|
||||||
|
"--\nLe BDE"
|
||||||
|
mail_admins("[Note Kfet] Un objet a été supprimé de force", msg)
|
||||||
|
|
||||||
# Force insertion, no data verification, no trigger
|
# Force insertion, no data verification, no trigger
|
||||||
obj._force_save = True
|
obj._force_save = True
|
||||||
Model.save(obj, force_insert=True)
|
Model.save(obj, force_insert=True)
|
||||||
# We don't want log anything
|
# We don't want log anything
|
||||||
obj._no_log = True
|
obj._no_log = True
|
||||||
ret = self.model.model_class().objects.filter(self.query & Q(pk=obj.pk)).exists()
|
ret = self.model.model_class().objects.filter(self.query & Q(pk=0)).exists()
|
||||||
# Delete testing object
|
# Delete testing object
|
||||||
obj._force_delete = True
|
obj._force_delete = True
|
||||||
Model.delete(obj)
|
Model.delete(obj)
|
||||||
|
|
||||||
# If the primary key was specified, we restore it
|
with open("/tmp/log", "w") as f:
|
||||||
obj.pk = oldpk
|
f.write(str(obj) + ", " + str(obj.pk) + ", " + str(self.model.model_class().objects.filter(pk=0).exists()))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
if permission_type == self.type:
|
if permission_type == self.type:
|
||||||
|
|
|
@ -179,8 +179,6 @@ class FutureUserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableVi
|
||||||
| Q(profile__section__iregex=pattern)
|
| Q(profile__section__iregex=pattern)
|
||||||
| Q(username__iregex="^" + pattern)
|
| Q(username__iregex="^" + pattern)
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
qs = qs.none()
|
|
||||||
|
|
||||||
return qs[:20]
|
return qs[:20]
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1f300c3b7bac0b7a31c1a252a83ba68a8268d33d
|
Subproject commit f41a5a32f7417a874b497640373ea3911eb1e133
|
|
@ -236,14 +236,12 @@ class WEIRegistrationsView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTable
|
||||||
pattern = self.request.GET.get("search", "")
|
pattern = self.request.GET.get("search", "")
|
||||||
|
|
||||||
if not pattern:
|
if not pattern:
|
||||||
return qs.none()
|
qs = qs.filter(
|
||||||
|
Q(user__first_name__iregex=pattern)
|
||||||
qs = qs.filter(
|
| Q(user__last_name__iregex=pattern)
|
||||||
Q(user__first_name__iregex=pattern)
|
| Q(user__note__alias__name__iregex="^" + pattern)
|
||||||
| Q(user__last_name__iregex=pattern)
|
| Q(user__note__alias__normalized_name__iregex="^" + Alias.normalize(pattern))
|
||||||
| Q(user__note__alias__name__iregex="^" + pattern)
|
)
|
||||||
| Q(user__note__alias__normalized_name__iregex="^" + Alias.normalize(pattern))
|
|
||||||
)
|
|
||||||
|
|
||||||
return qs[:20]
|
return qs[:20]
|
||||||
|
|
||||||
|
|
|
@ -217,6 +217,7 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
|
||||||
// Clear search on click
|
// Clear search on click
|
||||||
field.click(function () {
|
field.click(function () {
|
||||||
field.tooltip('hide');
|
field.tooltip('hide');
|
||||||
|
field.removeClass('is-invalid');
|
||||||
field.val("");
|
field.val("");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -233,6 +234,8 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
|
||||||
|
|
||||||
// When the user type something, the matched aliases are refreshed
|
// When the user type something, the matched aliases are refreshed
|
||||||
field.keyup(function (e) {
|
field.keyup(function (e) {
|
||||||
|
field.removeClass('is-invalid');
|
||||||
|
|
||||||
if (e.originalEvent.charCode === 13)
|
if (e.originalEvent.charCode === 13)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,22 @@ function reset() {
|
||||||
* Apply all transactions: all notes in `notes` buy each item in `buttons`
|
* Apply all transactions: all notes in `notes` buy each item in `buttons`
|
||||||
*/
|
*/
|
||||||
function consumeAll() {
|
function consumeAll() {
|
||||||
|
let error = false;
|
||||||
|
|
||||||
|
if (notes_display.length === 0) {
|
||||||
|
$("#note").addClass('is-invalid');
|
||||||
|
$("#note_list").html(li("", "<strong>Ajoutez des émetteurs.</strong>", "text-danger"));
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttons.length === 0) {
|
||||||
|
$("#consos_list").html(li("", "<strong>Ajoutez des consommations.</strong>", "text-danger"));
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return;
|
||||||
|
|
||||||
notes_display.forEach(function(note_display) {
|
notes_display.forEach(function(note_display) {
|
||||||
buttons.forEach(function(button) {
|
buttons.forEach(function(button) {
|
||||||
consume(note_display.note, note_display.name, button.dest, button.quantity * note_display.quantity, button.amount,
|
consume(note_display.note, note_display.name, button.dest, button.quantity * note_display.quantity, button.amount,
|
||||||
|
|
|
@ -219,6 +219,16 @@ $("#btn_transfer").click(function() {
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sources_notes_display.length && !$("#type_credit").is(':checked')) {
|
||||||
|
$("#source_note").addClass('is-invalid');
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dests_notes_display.length && !$("#type_debit").is(':checked')) {
|
||||||
|
$("#dest_note").addClass('is-invalid');
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -286,6 +296,7 @@ $("#btn_transfer").click(function() {
|
||||||
addMsg("Le transfert de "
|
addMsg("Le transfert de "
|
||||||
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
|
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
|
||||||
+ " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger", 10000);
|
+ " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger", 10000);
|
||||||
|
reset();
|
||||||
}).fail(function (err) {
|
}).fail(function (err) {
|
||||||
addMsg("Le transfert de "
|
addMsg("Le transfert de "
|
||||||
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
|
+ pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name
|
||||||
|
@ -300,11 +311,6 @@ $("#btn_transfer").click(function() {
|
||||||
let given_reason = reason;
|
let given_reason = reason;
|
||||||
let source_id, dest_id;
|
let source_id, dest_id;
|
||||||
if ($("#type_credit").is(':checked')) {
|
if ($("#type_credit").is(':checked')) {
|
||||||
if (!dests_notes_display.length) {
|
|
||||||
$("#dest_note").addClass('is-invalid');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
user_note = dests_notes_display[0].note.id;
|
user_note = dests_notes_display[0].note.id;
|
||||||
source_id = special_note;
|
source_id = special_note;
|
||||||
dest_id = user_note;
|
dest_id = user_note;
|
||||||
|
@ -313,11 +319,6 @@ $("#btn_transfer").click(function() {
|
||||||
reason += " (" + given_reason + ")";
|
reason += " (" + given_reason + ")";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!sources_notes_display.length) {
|
|
||||||
$("#source_note").addClass('is-invalid');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
user_note = sources_notes_display[0].note.id;
|
user_note = sources_notes_display[0].note.id;
|
||||||
source_id = user_note;
|
source_id = user_note;
|
||||||
dest_id = special_note;
|
dest_id = special_note;
|
||||||
|
|
|
@ -53,9 +53,9 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer text-center">
|
<div class="card-footer text-center">
|
||||||
<a id="consume_all" href="#" class="btn btn-primary">
|
<span id="consume_all" class="btn btn-primary">
|
||||||
{% trans "Consume!" %}
|
{% trans "Consume!" %}
|
||||||
</a>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue