djgentelella 0.4.30__py3-none-any.whl → 0.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- djgentelella/__init__.py +4 -1
- djgentelella/admin.py +41 -2
- djgentelella/firmador_digital/consumers/sign.py +24 -3
- djgentelella/firmador_digital/forms.py +140 -0
- djgentelella/firmador_digital/models.py +19 -24
- djgentelella/firmador_digital/utils.py +11 -0
- djgentelella/firmador_digital/views.py +31 -0
- djgentelella/firmador_digital/viewsets.py +15 -4
- djgentelella/forms/forms.py +10 -2
- djgentelella/groute.py +4 -1
- djgentelella/history/api.py +145 -0
- djgentelella/history/filterset.py +23 -0
- djgentelella/history/serializers.py +50 -0
- djgentelella/history/utils.py +70 -0
- djgentelella/locale/es/LC_MESSAGES/django.mo +0 -0
- djgentelella/locale/es/LC_MESSAGES/django.po +105 -0
- djgentelella/locale/es/LC_MESSAGES/djangojs.mo +0 -0
- djgentelella/locale/es/LC_MESSAGES/djangojs.po +46 -0
- djgentelella/migrations/0014_trash.py +31 -0
- djgentelella/migrations/0015_trash_deleted_by.py +21 -0
- djgentelella/migrations/0016_trash_created_at.py +20 -0
- djgentelella/migrations/0017_alter_chunkedupload_status.py +18 -0
- djgentelella/migrations/0018_alter_chunkedupload_status.py +18 -0
- djgentelella/models.py +97 -0
- djgentelella/models_manager.py +40 -0
- djgentelella/serializers/firmador_digital.py +9 -1
- djgentelella/serializers/selects.py +14 -0
- djgentelella/static/djgentelella.readonly.vendors.min.css +9 -5
- djgentelella/static/djgentelella.readonly.vendors.min.js +1 -1
- djgentelella/static/gentelella/css/custom.css +23 -2
- djgentelella/static/gentelella/css/modern.css +15 -0
- djgentelella/static/gentelella/css/modern_black_white.css +15 -0
- djgentelella/static/gentelella/css/pdfviewer.css +43 -1
- djgentelella/static/gentelella/images/default.png +0 -0
- djgentelella/static/gentelella/js/base/digital_signature.js +318 -79
- djgentelella/static/gentelella/js/base/form.common.js +9 -4
- djgentelella/static/gentelella/js/base/select2_wrap.js +15 -1
- djgentelella/static/gentelella/js/base/select2related.js +5 -0
- djgentelella/static/gentelella/js/base.js +347 -83
- djgentelella/static/gentelella/js/custom.js +6 -1
- djgentelella/static/gentelella/js/datatables.js +15 -0
- djgentelella/static/gentelella/js/digital_signature_update.js +29 -0
- djgentelella/static/gentelella/js/obj_api_management.js +403 -344
- djgentelella/static/gentelella/js/widgets.js +10 -1
- djgentelella/static/vendors/timeline/css/timeline.css +9 -5
- djgentelella/static/vendors/timeline/js/timeline.js +1 -1
- djgentelella/templates/forms/as_grid.html +2 -2
- djgentelella/templates/forms/as_inline.html +3 -5
- djgentelella/templates/gentelella/app/sidebar.html +16 -13
- djgentelella/templates/gentelella/digital_signature/update_signature_settings.html +45 -0
- djgentelella/templates/gentelella/registration/reset_done.html +24 -0
- djgentelella/templates/gentelella/widgets/digital_signature.html +47 -11
- djgentelella/trash/api.py +77 -0
- djgentelella/trash/filterset.py +20 -0
- djgentelella/trash/serializer.py +45 -0
- djgentelella/urls.py +13 -2
- djgentelella/views/select2autocomplete.py +40 -0
- djgentelella/widgets/core.py +6 -5
- djgentelella/widgets/digital_signature.py +5 -21
- djgentelella/widgets/selects.py +47 -0
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.1.dist-info}/METADATA +2 -2
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.1.dist-info}/RECORD +66 -48
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.1.dist-info}/AUTHORS +0 -0
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.1.dist-info}/LICENSE.txt +0 -0
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.1.dist-info}/WHEEL +0 -0
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from django.contrib.admin.models import LogEntry
|
|
2
|
+
from django.contrib.contenttypes.models import ContentType
|
|
3
|
+
from django.utils.translation import gettext_lazy as _
|
|
4
|
+
from rest_framework import serializers
|
|
5
|
+
from djgentelella.serializers import GTDateField, GTDateTimeField
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class HistorySerializer(serializers.ModelSerializer):
|
|
10
|
+
user = serializers.SerializerMethodField()
|
|
11
|
+
action_flag = serializers.SerializerMethodField()
|
|
12
|
+
action_time = GTDateTimeField()
|
|
13
|
+
change_message = serializers.SerializerMethodField()
|
|
14
|
+
actions = serializers.SerializerMethodField()
|
|
15
|
+
|
|
16
|
+
def get_user(self, obj):
|
|
17
|
+
if not obj or not obj.user:
|
|
18
|
+
return _("No user found")
|
|
19
|
+
name = obj.user.get_full_name()
|
|
20
|
+
return name or obj.user.username
|
|
21
|
+
|
|
22
|
+
def get_action_flag(self, obj):
|
|
23
|
+
if obj.action_flag == 4:
|
|
24
|
+
return _("Hard deleted")
|
|
25
|
+
elif obj.action_flag == 5:
|
|
26
|
+
return _("Restored")
|
|
27
|
+
|
|
28
|
+
return obj.get_action_flag_display()
|
|
29
|
+
|
|
30
|
+
def get_change_message(self, obj):
|
|
31
|
+
return obj.change_message
|
|
32
|
+
|
|
33
|
+
def get_actions(self, obj):
|
|
34
|
+
return {
|
|
35
|
+
"create": False,
|
|
36
|
+
"update": False,
|
|
37
|
+
"destroy": False,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class Meta:
|
|
41
|
+
model = LogEntry
|
|
42
|
+
fields = "__all__"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class HistoryDataTableSerializer(serializers.Serializer):
|
|
46
|
+
data = serializers.ListField(child=HistorySerializer(), required=True)
|
|
47
|
+
draw = serializers.IntegerField(required=True)
|
|
48
|
+
recordsFiltered = serializers.IntegerField(required=True)
|
|
49
|
+
recordsTotal = serializers.IntegerField(required=True)
|
|
50
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from django.utils.translation import gettext_lazy as _
|
|
2
|
+
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
|
|
3
|
+
from django.contrib.contenttypes.models import ContentType
|
|
4
|
+
|
|
5
|
+
HARD_DELETION = 4
|
|
6
|
+
RESTORE = 5
|
|
7
|
+
|
|
8
|
+
ACTIONS = {
|
|
9
|
+
ADDITION: _("created"),
|
|
10
|
+
CHANGE: _("updated"),
|
|
11
|
+
DELETION: _("deleted"),
|
|
12
|
+
HARD_DELETION: _("hard deleted"),
|
|
13
|
+
RESTORE: _("restored"),
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def add_log(
|
|
18
|
+
user,
|
|
19
|
+
object,
|
|
20
|
+
action_flag,
|
|
21
|
+
model_name=None,
|
|
22
|
+
changed_data=None,
|
|
23
|
+
object_repr="",
|
|
24
|
+
change_message="",
|
|
25
|
+
content_type=None,
|
|
26
|
+
):
|
|
27
|
+
if content_type is None:
|
|
28
|
+
content_type = ContentType.objects.get_for_model(object)
|
|
29
|
+
|
|
30
|
+
if model_name is None:
|
|
31
|
+
model_name = object._meta.verbose_name
|
|
32
|
+
|
|
33
|
+
if not isinstance(action_flag, int):
|
|
34
|
+
raise ValueError("action_flag must be an integer")
|
|
35
|
+
|
|
36
|
+
action_label = ACTIONS.get(action_flag, str(action_flag))
|
|
37
|
+
|
|
38
|
+
if not object_repr:
|
|
39
|
+
object_repr = _("An object of model %(model)s has been %(action)s") % {
|
|
40
|
+
"model": _(str(model_name).capitalize()),
|
|
41
|
+
"action": action_label,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
changed_data = changed_data or []
|
|
45
|
+
|
|
46
|
+
if change_message:
|
|
47
|
+
if action_flag != DELETION and changed_data:
|
|
48
|
+
verbose_changes = [object._meta.get_field(f).verbose_name for f in
|
|
49
|
+
changed_data]
|
|
50
|
+
|
|
51
|
+
change_message = _("%(msg)s. Fields: %(fields)s") % {
|
|
52
|
+
"msg": change_message,
|
|
53
|
+
"fields": ", ".join(verbose_changes),
|
|
54
|
+
}
|
|
55
|
+
else: # delete, restore, hard delete
|
|
56
|
+
change_message = _("The record %(obj)s of model %(model)s has been %(action)s") % {
|
|
57
|
+
"obj": str(object),
|
|
58
|
+
"model": _(model_name),
|
|
59
|
+
"action": action_label,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
LogEntry.objects.log_action(
|
|
63
|
+
user_id=user.id,
|
|
64
|
+
content_type_id=content_type.id,
|
|
65
|
+
object_id=object.pk,
|
|
66
|
+
object_repr=object_repr,
|
|
67
|
+
action_flag=action_flag,
|
|
68
|
+
change_message=change_message,
|
|
69
|
+
)
|
|
70
|
+
|
|
Binary file
|
|
@@ -616,3 +616,108 @@ msgstr "Iniciar"
|
|
|
616
616
|
|
|
617
617
|
msgid "Unknown"
|
|
618
618
|
msgstr "Desconocido"
|
|
619
|
+
|
|
620
|
+
msgid "LEFT"
|
|
621
|
+
msgstr "IZQUIERDA"
|
|
622
|
+
|
|
623
|
+
msgid "CENTER"
|
|
624
|
+
msgstr "CENTRO"
|
|
625
|
+
|
|
626
|
+
msgid "RIGHT"
|
|
627
|
+
msgstr "DERECHA"
|
|
628
|
+
|
|
629
|
+
msgid "Signature settings"
|
|
630
|
+
msgstr "Configuración de firma"
|
|
631
|
+
|
|
632
|
+
msgid "Updated signature settings successfully."
|
|
633
|
+
msgstr "Configuración de firma actualizada correctamente."
|
|
634
|
+
|
|
635
|
+
msgid "Background color"
|
|
636
|
+
msgstr "Color de fondo"
|
|
637
|
+
|
|
638
|
+
msgid "Contact"
|
|
639
|
+
msgstr "Contacto"
|
|
640
|
+
|
|
641
|
+
msgid "Date format"
|
|
642
|
+
msgstr "Formato de fecha"
|
|
643
|
+
|
|
644
|
+
msgid "Signature message"
|
|
645
|
+
msgstr "Mensaje de firma"
|
|
646
|
+
|
|
647
|
+
msgid "Font"
|
|
648
|
+
msgstr "Fuente"
|
|
649
|
+
|
|
650
|
+
msgid "Font alignment"
|
|
651
|
+
msgstr "Alineación de fuente"
|
|
652
|
+
|
|
653
|
+
msgid "Font color"
|
|
654
|
+
msgstr "Color de fuente"
|
|
655
|
+
|
|
656
|
+
msgid "Font size"
|
|
657
|
+
msgstr "Tamaño de fuente"
|
|
658
|
+
|
|
659
|
+
msgid "Place"
|
|
660
|
+
msgstr "Lugar"
|
|
661
|
+
|
|
662
|
+
msgid "Reason"
|
|
663
|
+
msgstr "Razón"
|
|
664
|
+
|
|
665
|
+
msgid "Visible signature"
|
|
666
|
+
msgstr "Firma visible"
|
|
667
|
+
|
|
668
|
+
msgid "This registry of trash does not exist."
|
|
669
|
+
msgstr "Este registro de papelera no existe."
|
|
670
|
+
|
|
671
|
+
msgid "The registry was successfully restored."
|
|
672
|
+
msgstr "El registro fue restaurado con éxito."
|
|
673
|
+
|
|
674
|
+
msgid "The registry could not be restored."
|
|
675
|
+
msgstr "No se pudo restaurar el registro."
|
|
676
|
+
|
|
677
|
+
msgid "Signature image"
|
|
678
|
+
msgstr "Imagen de firma"
|
|
679
|
+
|
|
680
|
+
msgid "Image preview"
|
|
681
|
+
msgstr "Vista previa de imagen"
|
|
682
|
+
|
|
683
|
+
msgid "Image signature"
|
|
684
|
+
msgstr "Imagen de firma"
|
|
685
|
+
msgid "Expand"
|
|
686
|
+
msgstr "Expandir"
|
|
687
|
+
|
|
688
|
+
# history
|
|
689
|
+
msgid "Restoration"
|
|
690
|
+
msgstr "Restaurado"
|
|
691
|
+
|
|
692
|
+
msgid "deleted"
|
|
693
|
+
msgstr "eliminado"
|
|
694
|
+
|
|
695
|
+
msgid "Hard deleted"
|
|
696
|
+
msgstr "Eliminación permanente"
|
|
697
|
+
|
|
698
|
+
msgid "History"
|
|
699
|
+
msgstr "Historial"
|
|
700
|
+
|
|
701
|
+
msgid "General"
|
|
702
|
+
msgstr "General"
|
|
703
|
+
|
|
704
|
+
msgid "restored"
|
|
705
|
+
msgstr "restaurado"
|
|
706
|
+
|
|
707
|
+
msgid "Restored"
|
|
708
|
+
msgstr "Restaurado"
|
|
709
|
+
|
|
710
|
+
msgid "hard deleted"
|
|
711
|
+
msgstr "eliminado permanentemente"
|
|
712
|
+
|
|
713
|
+
msgid "%(msg)s. Fields: %(fields)s"
|
|
714
|
+
msgstr "%(msg)s. Campos: %(fields)s"
|
|
715
|
+
|
|
716
|
+
msgid "The record %(obj)s of model %(model)s has been %(action)s"
|
|
717
|
+
msgstr "El registro %(obj)s del modelo %(model)s ha sido %(action)s"
|
|
718
|
+
|
|
719
|
+
msgid "An object of model %(model)s has been %(action)s"
|
|
720
|
+
msgstr "Un objeto del modelo %(model)s ha sido %(action)s"
|
|
721
|
+
|
|
722
|
+
msgid "%(obj)s in trash"
|
|
723
|
+
msgstr "%(obj)s en papelera"
|
|
Binary file
|
|
@@ -213,3 +213,49 @@ msgstr ""
|
|
|
213
213
|
|
|
214
214
|
msgid "loading"
|
|
215
215
|
msgstr "Cargando"
|
|
216
|
+
|
|
217
|
+
msgid "Please, sign the document before saving"
|
|
218
|
+
msgstr "Por favor, firme el documento antes de guardar"
|
|
219
|
+
|
|
220
|
+
msgid "The document is not digitally signed. Please sign the document before saving."
|
|
221
|
+
msgstr "El documento no está firmado digitalmente. Por favor, firme el documento antes de guardar."
|
|
222
|
+
|
|
223
|
+
msgid "The document was saved"
|
|
224
|
+
msgstr "El documento se ha guardado"
|
|
225
|
+
|
|
226
|
+
# history
|
|
227
|
+
msgid "Restoration"
|
|
228
|
+
msgstr "Restaurado"
|
|
229
|
+
|
|
230
|
+
msgid "deleted"
|
|
231
|
+
msgstr "eliminado"
|
|
232
|
+
|
|
233
|
+
msgid "Hard deleted"
|
|
234
|
+
msgstr "Eliminación permanente"
|
|
235
|
+
|
|
236
|
+
msgid "History"
|
|
237
|
+
msgstr "Historial"
|
|
238
|
+
|
|
239
|
+
msgid "General"
|
|
240
|
+
msgstr "General"
|
|
241
|
+
|
|
242
|
+
msgid "restored"
|
|
243
|
+
msgstr "restaurado"
|
|
244
|
+
|
|
245
|
+
msgid "Restored"
|
|
246
|
+
msgstr "Restaurado"
|
|
247
|
+
|
|
248
|
+
msgid "hard deleted"
|
|
249
|
+
msgstr "eliminado permanentemente"
|
|
250
|
+
|
|
251
|
+
msgid "%(msg)s. Fields: %(fields)s"
|
|
252
|
+
msgstr "%(msg)s. Campos: %(fields)s"
|
|
253
|
+
|
|
254
|
+
msgid "The record %(obj)s of model %(model)s has been %(action)s"
|
|
255
|
+
msgstr "El registro %(obj)s del modelo %(model)s ha sido %(action)s"
|
|
256
|
+
|
|
257
|
+
msgid "An object of model %(model)s has been %(action)s"
|
|
258
|
+
msgstr "Un objeto del modelo %(model)s ha sido %(action)s"
|
|
259
|
+
|
|
260
|
+
msgid "%(obj)s in trash"
|
|
261
|
+
msgstr "%(obj)s en papelera"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Generated by Django 5.1.6 on 2025-08-03 17:13
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('contenttypes', '0002_remove_content_type_name'),
|
|
11
|
+
('djgentelella', '0013_usersignatureconfig'),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
operations = [
|
|
15
|
+
migrations.CreateModel(
|
|
16
|
+
name='Trash',
|
|
17
|
+
fields=[
|
|
18
|
+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
19
|
+
('object_id', models.PositiveIntegerField(verbose_name='Object ID')),
|
|
20
|
+
('object_repr', models.CharField(help_text='Value of str(instance) at deletion time', max_length=200, verbose_name='Object repr')),
|
|
21
|
+
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype', verbose_name='Content type')),
|
|
22
|
+
],
|
|
23
|
+
options={
|
|
24
|
+
'verbose_name': 'Trash',
|
|
25
|
+
'verbose_name_plural': 'Trash',
|
|
26
|
+
'ordering': ('id',),
|
|
27
|
+
'indexes': [models.Index(fields=['content_type', 'object_id'], name='djgentelell_content_9fa474_idx')],
|
|
28
|
+
'unique_together': {('content_type', 'object_id')},
|
|
29
|
+
},
|
|
30
|
+
),
|
|
31
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Generated by Django 5.1.6 on 2025-08-03 17:29
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
('djgentelella', '0014_trash'),
|
|
12
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.AddField(
|
|
17
|
+
model_name='trash',
|
|
18
|
+
name='deleted_by',
|
|
19
|
+
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Deleted by'),
|
|
20
|
+
),
|
|
21
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Generated by Django 5.1.6 on 2025-08-03 17:54
|
|
2
|
+
|
|
3
|
+
import django.utils.timezone
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('djgentelella', '0015_trash_deleted_by'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddField(
|
|
15
|
+
model_name='trash',
|
|
16
|
+
name='created_at',
|
|
17
|
+
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
|
18
|
+
preserve_default=False,
|
|
19
|
+
),
|
|
20
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 5.2.5 on 2025-08-29 23:46
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('djgentelella', '0016_trash_created_at'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='chunkedupload',
|
|
15
|
+
name='status',
|
|
16
|
+
field=models.PositiveSmallIntegerField(choices=[(1, 'Uploading'), (2, 'Complete')], default=1),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 5.2.5 on 2025-08-29 23:55
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('djgentelella', '0017_alter_chunkedupload_status'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='chunkedupload',
|
|
15
|
+
name='status',
|
|
16
|
+
field=models.PositiveSmallIntegerField(choices=[(1, 'Subiendo'), (2, 'Completo')], default=1),
|
|
17
|
+
),
|
|
18
|
+
]
|
djgentelella/models.py
CHANGED
|
@@ -5,7 +5,12 @@ from django.utils.translation import gettext_lazy as _
|
|
|
5
5
|
from tree_queries.models import TreeNode
|
|
6
6
|
|
|
7
7
|
from djgentelella.chunked_upload.models import AbstractChunkedUpload
|
|
8
|
+
from django.contrib.contenttypes.models import ContentType
|
|
9
|
+
from django.contrib.contenttypes.fields import GenericForeignKey
|
|
10
|
+
from .models_manager import ObjectManager, AllObjectsManager, \
|
|
11
|
+
DeletedObjectsManager
|
|
8
12
|
|
|
13
|
+
from djgentelella.history.utils import add_log, ADDITION
|
|
9
14
|
|
|
10
15
|
class GentelellaSettings(models.Model):
|
|
11
16
|
"""
|
|
@@ -123,3 +128,95 @@ class ChunkedUpload(AbstractChunkedUpload):
|
|
|
123
128
|
null=DEFAULT_MODEL_USER_FIELD_NULL,
|
|
124
129
|
blank=DEFAULT_MODEL_USER_FIELD_BLANK
|
|
125
130
|
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# Trash
|
|
134
|
+
class Trash(models.Model):
|
|
135
|
+
"""
|
|
136
|
+
Trash generic. Each row represents an instance deleted.
|
|
137
|
+
"""
|
|
138
|
+
content_type = models.ForeignKey(ContentType, on_delete=models.PROTECT,
|
|
139
|
+
verbose_name=_("Content type"))
|
|
140
|
+
object_id = models.PositiveIntegerField(verbose_name=_("Object ID"))
|
|
141
|
+
content_object = GenericForeignKey("content_type", "object_id")
|
|
142
|
+
object_repr = models.CharField(
|
|
143
|
+
_("Object repr"), max_length=200,
|
|
144
|
+
help_text=_("Value of str(instance) at deletion time"),
|
|
145
|
+
)
|
|
146
|
+
deleted_by = models.ForeignKey(
|
|
147
|
+
User,
|
|
148
|
+
on_delete=models.SET_NULL,
|
|
149
|
+
null=True,
|
|
150
|
+
blank=True,
|
|
151
|
+
verbose_name=_("Deleted by")
|
|
152
|
+
)
|
|
153
|
+
created_at = models.DateTimeField(auto_now_add=True)
|
|
154
|
+
|
|
155
|
+
class Meta:
|
|
156
|
+
ordering = ("id",)
|
|
157
|
+
unique_together = ("content_type", "object_id")
|
|
158
|
+
indexes = [
|
|
159
|
+
models.Index(fields=["content_type", "object_id"]),
|
|
160
|
+
]
|
|
161
|
+
verbose_name = _("Trash")
|
|
162
|
+
verbose_name_plural = _("Trash")
|
|
163
|
+
|
|
164
|
+
def __str__(self):
|
|
165
|
+
return _("%(obj)s in trash") % {"obj": self.object_repr}
|
|
166
|
+
|
|
167
|
+
def restore(self, user=None):
|
|
168
|
+
obj = self.content_object
|
|
169
|
+
|
|
170
|
+
# if `is_deleted` is in the model, unmark it
|
|
171
|
+
if hasattr(obj, "restore"):
|
|
172
|
+
obj.restore()
|
|
173
|
+
|
|
174
|
+
self.delete() # delete the instance of trash
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def hard_delete(self):
|
|
178
|
+
"""
|
|
179
|
+
Permanent deletion of the original object and then the trash entry.
|
|
180
|
+
"""
|
|
181
|
+
obj = self.content_object
|
|
182
|
+
|
|
183
|
+
if obj is None:
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
obj.delete(hard=True)
|
|
187
|
+
|
|
188
|
+
super().delete()
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class DeletedWithTrash(models.Model):
|
|
192
|
+
is_deleted = models.BooleanField(default=False, db_index=True)
|
|
193
|
+
|
|
194
|
+
objects = ObjectManager()
|
|
195
|
+
objects_with_deleted = AllObjectsManager()
|
|
196
|
+
objects_deleted_only = DeletedObjectsManager()
|
|
197
|
+
|
|
198
|
+
class Meta:
|
|
199
|
+
abstract = True
|
|
200
|
+
|
|
201
|
+
def delete(self, using=None, keep_parents=False, *, hard=False, user=None):
|
|
202
|
+
if hard:
|
|
203
|
+
# Permanent deletion
|
|
204
|
+
return super().delete(using=using, keep_parents=keep_parents)
|
|
205
|
+
|
|
206
|
+
self.is_deleted = True
|
|
207
|
+
self.save(update_fields=["is_deleted"])
|
|
208
|
+
|
|
209
|
+
# create trash instance
|
|
210
|
+
trash = Trash.objects.get_or_create(
|
|
211
|
+
content_type=ContentType.objects.get_for_model(self.__class__),
|
|
212
|
+
object_id=self.pk,
|
|
213
|
+
defaults={
|
|
214
|
+
"object_repr": str(self)[:200],
|
|
215
|
+
"deleted_by": user,
|
|
216
|
+
},
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# Restore an object
|
|
220
|
+
def restore(self):
|
|
221
|
+
self.is_deleted = False
|
|
222
|
+
self.save(update_fields=["is_deleted"])
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ObjectQuerySet(models.QuerySet):
|
|
5
|
+
# Non-deleted records
|
|
6
|
+
def alive(self):
|
|
7
|
+
return self.filter(is_deleted=False)
|
|
8
|
+
|
|
9
|
+
# Only deleted records
|
|
10
|
+
def dead(self):
|
|
11
|
+
return self.filter(is_deleted=True)
|
|
12
|
+
|
|
13
|
+
# Overridden delete (soft delete)
|
|
14
|
+
def delete(self):
|
|
15
|
+
return super().update(is_deleted=True)
|
|
16
|
+
|
|
17
|
+
# Permanent deletion
|
|
18
|
+
def hard_delete(self):
|
|
19
|
+
return super().delete()
|
|
20
|
+
|
|
21
|
+
# Bulk restore
|
|
22
|
+
def restore(self):
|
|
23
|
+
return self.update(is_deleted=False)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ObjectManager(models.Manager):
|
|
27
|
+
# Only alive objects by default
|
|
28
|
+
def get_queryset(self):
|
|
29
|
+
return ObjectQuerySet(self.model, using=self._db).alive()
|
|
30
|
+
|
|
31
|
+
class AllObjectsManager(models.Manager):
|
|
32
|
+
# Explicit access to all objects
|
|
33
|
+
def get_queryset(self):
|
|
34
|
+
return ObjectQuerySet(self.model, using=self._db)
|
|
35
|
+
|
|
36
|
+
class DeletedObjectsManager(models.Manager):
|
|
37
|
+
# Only deleted objects
|
|
38
|
+
def get_queryset(self):
|
|
39
|
+
return ObjectQuerySet(self.model, using=self._db).dead()
|
|
40
|
+
|
|
@@ -69,7 +69,8 @@ class RequestInitialDoc(serializers.Serializer):
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
class WSRequest(serializers.Serializer):
|
|
72
|
-
action = serializers.CharField()
|
|
72
|
+
action = serializers.CharField(required=True)
|
|
73
|
+
socket_id = serializers.CharField(required=True)
|
|
73
74
|
|
|
74
75
|
|
|
75
76
|
class CardSerializer(serializers.Serializer):
|
|
@@ -88,6 +89,7 @@ class SignatureSerializer(serializers.Serializer):
|
|
|
88
89
|
|
|
89
90
|
class InitialSignatureSerializer(serializers.Serializer):
|
|
90
91
|
action = serializers.CharField()
|
|
92
|
+
socket_id = serializers.CharField(required=True)
|
|
91
93
|
docsettings = DocumentSettingsSerializer()
|
|
92
94
|
card = CardSerializer()
|
|
93
95
|
logo_url = serializers.CharField(required=False, allow_null=True, allow_blank=True)
|
|
@@ -96,8 +98,14 @@ class InitialSignatureSerializer(serializers.Serializer):
|
|
|
96
98
|
|
|
97
99
|
class CompleteSignatureSerializer(serializers.Serializer):
|
|
98
100
|
action = serializers.CharField()
|
|
101
|
+
socket_id = serializers.CharField(required=True)
|
|
99
102
|
documentid = serializers.CharField()
|
|
100
103
|
certificate = serializers.CharField()
|
|
101
104
|
signature = SignatureSerializer()
|
|
102
105
|
logo_url = serializers.CharField(required=False, allow_null=True, allow_blank=True)
|
|
103
106
|
instance = InstanceSerializer()
|
|
107
|
+
|
|
108
|
+
class ValidateDocumentSerializer(serializers.Serializer):
|
|
109
|
+
action = serializers.CharField()
|
|
110
|
+
socket_id = serializers.CharField(required=True)
|
|
111
|
+
instance = InstanceSerializer()
|
|
@@ -30,3 +30,17 @@ class GTS2SerializerBase(serializers.Serializer):
|
|
|
30
30
|
text = serializers.SerializerMethodField()
|
|
31
31
|
disabled = serializers.SerializerMethodField()
|
|
32
32
|
selected = serializers.SerializerMethodField()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ChoicesGTS2Serializer(GTS2SerializerBase):
|
|
36
|
+
def __init__(self, *args, choices=None, **kwargs):
|
|
37
|
+
self.choices = dict(choices)
|
|
38
|
+
super().__init__(*args, **kwargs)
|
|
39
|
+
|
|
40
|
+
def get_id(self, obj):
|
|
41
|
+
return obj
|
|
42
|
+
|
|
43
|
+
def get_text(self, obj):
|
|
44
|
+
if obj in self.choices:
|
|
45
|
+
return self.choices[obj]
|
|
46
|
+
return obj
|
|
@@ -808,6 +808,7 @@
|
|
|
808
808
|
position: relative;
|
|
809
809
|
overflow: hidden;
|
|
810
810
|
border-top: 1px solid #e5e5e5;
|
|
811
|
+
direction: ltr;
|
|
811
812
|
}
|
|
812
813
|
.tl-timenav .tl-timenav-line {
|
|
813
814
|
position: absolute;
|
|
@@ -2018,7 +2019,6 @@
|
|
|
2018
2019
|
.tl-slidenav-previous .tl-slidenav-content-container,
|
|
2019
2020
|
.tl-slidenav-next .tl-slidenav-content-container {
|
|
2020
2021
|
width: 100px;
|
|
2021
|
-
position: absolute;
|
|
2022
2022
|
}
|
|
2023
2023
|
.tl-slidenav-previous .tl-slidenav-title,
|
|
2024
2024
|
.tl-slidenav-next .tl-slidenav-title,
|
|
@@ -2104,7 +2104,7 @@
|
|
|
2104
2104
|
.tl-slidenav-next {
|
|
2105
2105
|
text-align: right;
|
|
2106
2106
|
margin-right: 10px;
|
|
2107
|
-
right:
|
|
2107
|
+
right: 0;
|
|
2108
2108
|
}
|
|
2109
2109
|
.tl-slidenav-next .tl-slidenav-title,
|
|
2110
2110
|
.tl-slidenav-next .tl-slidenav-description {
|
|
@@ -2118,6 +2118,7 @@
|
|
|
2118
2118
|
}
|
|
2119
2119
|
.tl-slidenav-previous {
|
|
2120
2120
|
text-align: left;
|
|
2121
|
+
left: 0;
|
|
2121
2122
|
margin-left: 10px;
|
|
2122
2123
|
}
|
|
2123
2124
|
.tl-slidenav-previous .tl-slidenav-icon {
|
|
@@ -2126,6 +2127,12 @@
|
|
|
2126
2127
|
.tl-slidenav-previous .tl-slidenav-icon:before {
|
|
2127
2128
|
content: "\e650";
|
|
2128
2129
|
}
|
|
2130
|
+
[dir="rtl"] .tl-slidenav-previous {
|
|
2131
|
+
direction: ltr;
|
|
2132
|
+
}
|
|
2133
|
+
[dir="rtl"] .tl-slidenav-next:hover .tl-slidenav-icon {
|
|
2134
|
+
margin-right: -4px;
|
|
2135
|
+
}
|
|
2129
2136
|
/* NAVIGATION HOVER
|
|
2130
2137
|
================================================== */
|
|
2131
2138
|
.tl-slidenav-previous:hover .tl-slidenav-title,
|
|
@@ -2154,9 +2161,6 @@
|
|
|
2154
2161
|
.tl-slidenav-previous:focus-visible .tl-slidenav-icon {
|
|
2155
2162
|
margin-left: -4px;
|
|
2156
2163
|
}
|
|
2157
|
-
.tl-skinny .tl-slidenav-next {
|
|
2158
|
-
right: 32px;
|
|
2159
|
-
}
|
|
2160
2164
|
.tl-skinny .tl-slidenav-next .tl-slidenav-icon {
|
|
2161
2165
|
margin-left: 8px;
|
|
2162
2166
|
}
|