djgentelella 0.4.30__py3-none-any.whl → 0.5.0__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 +7 -1
- djgentelella/firmador_digital/consumers/sign.py +24 -3
- djgentelella/firmador_digital/forms.py +140 -0
- djgentelella/firmador_digital/models.py +20 -2
- 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/locale/es/LC_MESSAGES/django.mo +0 -0
- djgentelella/locale/es/LC_MESSAGES/django.po +67 -0
- djgentelella/locale/es/LC_MESSAGES/djangojs.mo +0 -0
- djgentelella/locale/es/LC_MESSAGES/djangojs.po +9 -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/models.py +96 -0
- djgentelella/models_manager.py +40 -0
- djgentelella/serializers/firmador_digital.py +9 -1
- djgentelella/serializers/selects.py +14 -0
- djgentelella/static/djgentelella.flags.vendors.min.css +1 -1
- 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/bootstrap-datetimepicker/bootstrap-datetimepicker.min.css.map +75 -7
- djgentelella/static/vendors/flags/1x1/ac.svg +75 -7
- djgentelella/static/vendors/flags/1x1/cp.svg +75 -7
- djgentelella/static/vendors/flags/1x1/dg.svg +75 -7
- djgentelella/static/vendors/flags/1x1/ea.svg +75 -7
- djgentelella/static/vendors/flags/1x1/es-ct.svg +75 -7
- djgentelella/static/vendors/flags/1x1/es-ga.svg +75 -7
- djgentelella/static/vendors/flags/1x1/ic.svg +75 -7
- djgentelella/static/vendors/flags/1x1/ta.svg +75 -7
- djgentelella/static/vendors/flags/1x1/xx.svg +75 -7
- djgentelella/static/vendors/flags/4x3/ac.svg +75 -7
- djgentelella/static/vendors/flags/4x3/cp.svg +75 -7
- djgentelella/static/vendors/flags/4x3/dg.svg +75 -7
- djgentelella/static/vendors/flags/4x3/ea.svg +75 -7
- djgentelella/static/vendors/flags/4x3/es-ct.svg +75 -7
- djgentelella/static/vendors/flags/4x3/es-ga.svg +75 -7
- djgentelella/static/vendors/flags/4x3/ic.svg +75 -7
- djgentelella/static/vendors/flags/4x3/ta.svg +75 -7
- djgentelella/static/vendors/flags/4x3/xx.svg +75 -7
- 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 +58 -0
- djgentelella/trash/filterset.py +20 -0
- djgentelella/trash/serializer.py +45 -0
- djgentelella/urls.py +8 -1
- 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.0.dist-info}/METADATA +2 -2
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/RECORD +80 -68
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/AUTHORS +0 -0
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/LICENSE.txt +0 -0
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/WHEEL +0 -0
- {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/top_level.txt +0 -0
djgentelella/__init__.py
CHANGED
djgentelella/admin.py
CHANGED
|
@@ -2,7 +2,7 @@ from django.contrib import admin
|
|
|
2
2
|
|
|
3
3
|
from djgentelella.firmador_digital.models import UserSignatureConfig
|
|
4
4
|
from djgentelella.models import MenuItem, Help, GentelellaSettings, Notification, \
|
|
5
|
-
ChunkedUpload
|
|
5
|
+
ChunkedUpload, Trash
|
|
6
6
|
from djgentelella.models import PermissionsCategoryManagement
|
|
7
7
|
from djgentelella.utils import clean_cache
|
|
8
8
|
|
|
@@ -33,6 +33,11 @@ class ChunkedUploadAdmin(admin.ModelAdmin):
|
|
|
33
33
|
class UserSignatureConfigAdmin(admin.ModelAdmin):
|
|
34
34
|
list_display = ('id', 'user', 'config')
|
|
35
35
|
|
|
36
|
+
class TrashAdmin(admin.ModelAdmin):
|
|
37
|
+
list_display = ("id", "deleted_by", "content_type", "object_id", "object_repr", "created_at")
|
|
38
|
+
ordering = ("-created_at",)
|
|
39
|
+
search_fields = ("id",)
|
|
40
|
+
|
|
36
41
|
admin.site.register(UserSignatureConfig, UserSignatureConfigAdmin)
|
|
37
42
|
admin.site.register(ChunkedUpload, ChunkedUploadAdmin)
|
|
38
43
|
admin.site.register(MenuItem, MenuAdmin)
|
|
@@ -40,3 +45,4 @@ admin.site.register(Help)
|
|
|
40
45
|
admin.site.register(PermissionsCategoryManagement)
|
|
41
46
|
admin.site.register(GentelellaSettings, GentelellaSettingsAdmin)
|
|
42
47
|
admin.site.register(Notification, NotificationAdmin)
|
|
48
|
+
admin.site.register(Trash, TrashAdmin)
|
|
@@ -12,7 +12,7 @@ from djgentelella.firmador_digital.utils import RemoteSignerClient
|
|
|
12
12
|
from djgentelella.serializers.firmador_digital import (
|
|
13
13
|
WSRequest,
|
|
14
14
|
InitialSignatureSerializer,
|
|
15
|
-
CompleteSignatureSerializer,
|
|
15
|
+
CompleteSignatureSerializer, ValidateDocumentSerializer,
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
logger = logging.getLogger("djgentelella")
|
|
@@ -35,24 +35,30 @@ class SignConsumer(JsonWebsocketConsumer):
|
|
|
35
35
|
return InitialSignatureSerializer(data=content)
|
|
36
36
|
if serializer.validated_data["action"] == "complete_signature":
|
|
37
37
|
return CompleteSignatureSerializer(data=content)
|
|
38
|
+
if serializer.validated_data["action"] == "validate_document":
|
|
39
|
+
return ValidateDocumentSerializer(data=content)
|
|
38
40
|
|
|
39
41
|
def disconnect(self, close_code):
|
|
40
42
|
super().disconnect(close_code)
|
|
43
|
+
logger.info(f"Disconnect {close_code}")
|
|
41
44
|
|
|
42
45
|
def receive_json(self, content, **kwargs):
|
|
43
46
|
"""
|
|
44
47
|
Called with decoded JSON content.
|
|
45
48
|
"""
|
|
49
|
+
socket_id = ""
|
|
46
50
|
try:
|
|
47
51
|
serializer = self.get_serializer(content)
|
|
48
52
|
|
|
49
53
|
if serializer.is_valid():
|
|
50
|
-
|
|
54
|
+
socket_id = serializer.validated_data['socket_id']
|
|
51
55
|
match serializer.validated_data["action"]:
|
|
52
56
|
case "initial_signature":
|
|
53
57
|
self.do_initial_signature(serializer)
|
|
54
58
|
case "complete_signature":
|
|
55
59
|
self.do_complete_signature(serializer)
|
|
60
|
+
case "validate_document":
|
|
61
|
+
self.do_validate_document(serializer)
|
|
56
62
|
case _:
|
|
57
63
|
self.do_default(serializer)
|
|
58
64
|
else:
|
|
@@ -63,6 +69,7 @@ class SignConsumer(JsonWebsocketConsumer):
|
|
|
63
69
|
"details": serializer.errors,
|
|
64
70
|
"status": 400,
|
|
65
71
|
"code": 11,
|
|
72
|
+
'socket_id': serializer.data.get('socket_id')
|
|
66
73
|
})
|
|
67
74
|
logger.error("Invalid request.")
|
|
68
75
|
|
|
@@ -74,9 +81,20 @@ class SignConsumer(JsonWebsocketConsumer):
|
|
|
74
81
|
"details": str(e),
|
|
75
82
|
"status": 500,
|
|
76
83
|
"code": 999,
|
|
84
|
+
"socket_id": socket_id
|
|
77
85
|
})
|
|
78
86
|
logger.error("An unexpected error occurred.", exc_info=e)
|
|
79
87
|
|
|
88
|
+
def do_validate_document(self, serializer):
|
|
89
|
+
signer = RemoteSignerClient(self.scope["user"])
|
|
90
|
+
|
|
91
|
+
response = signer.validate_document(
|
|
92
|
+
instance=serializer.validated_data["instance"],
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
response['socket_id'] = serializer.validated_data['socket_id']
|
|
96
|
+
self.send_json(response)
|
|
97
|
+
|
|
80
98
|
def do_initial_signature(self, serializer):
|
|
81
99
|
signer = RemoteSignerClient(self.scope["user"])
|
|
82
100
|
|
|
@@ -87,6 +105,8 @@ class SignConsumer(JsonWebsocketConsumer):
|
|
|
87
105
|
docsettings=serializer.validated_data["docsettings"],
|
|
88
106
|
)
|
|
89
107
|
|
|
108
|
+
response['socket_id'] = serializer.validated_data['socket_id']
|
|
109
|
+
|
|
90
110
|
# remove signer image
|
|
91
111
|
if "imageIcon" in response:
|
|
92
112
|
del response["imageIcon"]
|
|
@@ -103,7 +123,8 @@ class SignConsumer(JsonWebsocketConsumer):
|
|
|
103
123
|
signer = RemoteSignerClient(self.scope["user"])
|
|
104
124
|
data = dict(serializer.validated_data)
|
|
105
125
|
response = signer.complete_signature(data)
|
|
106
|
-
self.send_json({"result": response
|
|
126
|
+
self.send_json({"result": response,
|
|
127
|
+
'socket_id': serializer.validated_data['socket_id']})
|
|
107
128
|
except Exception as e:
|
|
108
129
|
logger.error("Complete the signature fail", exc_info=e)
|
|
109
130
|
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
+
import base64
|
|
1
2
|
import logging
|
|
3
|
+
from io import BytesIO
|
|
2
4
|
|
|
3
5
|
from django import forms
|
|
4
6
|
from django.core.exceptions import ValidationError
|
|
7
|
+
from django.core.files.uploadedfile import UploadedFile
|
|
8
|
+
from django.templatetags.static import static
|
|
9
|
+
from django.utils.safestring import mark_safe
|
|
5
10
|
from django.utils.translation import gettext_lazy as _
|
|
6
11
|
|
|
12
|
+
from djgentelella.firmador_digital.models import UserSignatureConfig, \
|
|
13
|
+
get_signature_default, FORMATS_DATE, FONT_ALIGNMENT
|
|
7
14
|
from djgentelella.firmador_digital.signvalue_utils import ValueDSParser
|
|
8
15
|
from djgentelella.forms.forms import GTForm
|
|
9
16
|
from djgentelella.widgets import core as genwidgets
|
|
17
|
+
from djgentelella.widgets.core import FileInput
|
|
10
18
|
|
|
11
19
|
logger = logging.getLogger('djgentelella')
|
|
12
20
|
|
|
@@ -26,3 +34,135 @@ class RenderValueForm(GTForm, ValueDSParser):
|
|
|
26
34
|
_("Invalid value not encoded as b64 o json parser error"),
|
|
27
35
|
code="invalid")
|
|
28
36
|
return jsondata
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class SignatureConfigForm(GTForm, forms.ModelForm):
|
|
40
|
+
contact = forms.CharField(
|
|
41
|
+
required=False,
|
|
42
|
+
max_length=100,
|
|
43
|
+
widget=genwidgets.TextInput,
|
|
44
|
+
label=_("Contact")
|
|
45
|
+
)
|
|
46
|
+
dateFormat = forms.ChoiceField(
|
|
47
|
+
widget=genwidgets.Select,
|
|
48
|
+
required=True,
|
|
49
|
+
choices=FORMATS_DATE,
|
|
50
|
+
label=_("Date format")
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
defaultSignMessage = forms.CharField(
|
|
54
|
+
widget=genwidgets.Textarea,
|
|
55
|
+
required=False,
|
|
56
|
+
max_length=100,
|
|
57
|
+
label=_("Signature message")
|
|
58
|
+
)
|
|
59
|
+
fontAlignment = forms.ChoiceField(
|
|
60
|
+
choices=FONT_ALIGNMENT,
|
|
61
|
+
widget=genwidgets.Select,
|
|
62
|
+
required=True,
|
|
63
|
+
label=_("Font alignment")
|
|
64
|
+
)
|
|
65
|
+
fontColor = forms.CharField(
|
|
66
|
+
max_length=50,
|
|
67
|
+
widget=genwidgets.ColorInput,
|
|
68
|
+
required=True,
|
|
69
|
+
label=_("Font color"),
|
|
70
|
+
initial="#FFFFFF",
|
|
71
|
+
)
|
|
72
|
+
fontSize = forms.IntegerField(
|
|
73
|
+
min_value=5,
|
|
74
|
+
max_value=28,
|
|
75
|
+
initial=7,
|
|
76
|
+
widget=genwidgets.NumberInput,
|
|
77
|
+
label=_("Font size")
|
|
78
|
+
)
|
|
79
|
+
place = forms.CharField(
|
|
80
|
+
required=False,
|
|
81
|
+
max_length=100,
|
|
82
|
+
widget=genwidgets.TextInput,
|
|
83
|
+
label=_("Place")
|
|
84
|
+
)
|
|
85
|
+
reason = forms.CharField(
|
|
86
|
+
required=False,
|
|
87
|
+
max_length=100,
|
|
88
|
+
widget=genwidgets.TextInput,
|
|
89
|
+
label=_("Reason")
|
|
90
|
+
)
|
|
91
|
+
isVisibleSignature = forms.BooleanField(
|
|
92
|
+
required=False,
|
|
93
|
+
widget=genwidgets.YesNoInput,
|
|
94
|
+
label=_("Visible signature")
|
|
95
|
+
)
|
|
96
|
+
image = forms.ImageField(
|
|
97
|
+
required=False,
|
|
98
|
+
widget=FileInput,
|
|
99
|
+
label=_("Signature image")
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
default_render_type = "as_grid"
|
|
103
|
+
|
|
104
|
+
grid_representation = [
|
|
105
|
+
[["contact"]],
|
|
106
|
+
[["place"]],
|
|
107
|
+
[["reason"]],
|
|
108
|
+
[["image"], ["preview_image"]],
|
|
109
|
+
[["dateFormat"], ["isVisibleSignature"]],
|
|
110
|
+
[["fontSize"], ["fontColor"], ["fontAlignment"]],
|
|
111
|
+
[["defaultSignMessage"]],
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
class Meta:
|
|
115
|
+
model = UserSignatureConfig
|
|
116
|
+
fields = []
|
|
117
|
+
|
|
118
|
+
def __init__(self, *args, **kwargs):
|
|
119
|
+
super().__init__(*args, **kwargs)
|
|
120
|
+
|
|
121
|
+
cfg = self.instance.config if getattr(self.instance, "config",
|
|
122
|
+
None) else get_signature_default()
|
|
123
|
+
for key, value in cfg.items():
|
|
124
|
+
if key in self.fields:
|
|
125
|
+
self.fields[key].initial = value
|
|
126
|
+
|
|
127
|
+
def preview_image(self):
|
|
128
|
+
label = _("Image preview")
|
|
129
|
+
src = static("gentelella/images/default.png")
|
|
130
|
+
|
|
131
|
+
if self.instance and self.instance.config:
|
|
132
|
+
image_b64 = self.instance.config.get("image")
|
|
133
|
+
if image_b64 and image_b64.startswith("data:image"):
|
|
134
|
+
src = image_b64
|
|
135
|
+
|
|
136
|
+
return mark_safe(f"""
|
|
137
|
+
<label for="image-preview"><strong>{label}:</strong></label><br>
|
|
138
|
+
<div class="d-flex justify-content-center">
|
|
139
|
+
<img id="image-preview" alt="{label}" src="{src}" style="max-height:100px; max-width:300px; display:block;">
|
|
140
|
+
</div>
|
|
141
|
+
""")
|
|
142
|
+
|
|
143
|
+
def save(self, commit=True):
|
|
144
|
+
data = get_signature_default()
|
|
145
|
+
prev_image = self.instance.config.get("image")
|
|
146
|
+
|
|
147
|
+
for key in data.keys():
|
|
148
|
+
if key in self.cleaned_data:
|
|
149
|
+
val = self.cleaned_data[key]
|
|
150
|
+
if key == "image":
|
|
151
|
+
if isinstance(val, UploadedFile):
|
|
152
|
+
# el usuario subió un nuevo archivo
|
|
153
|
+
buffered = BytesIO()
|
|
154
|
+
for chunk in val.chunks():
|
|
155
|
+
buffered.write(chunk)
|
|
156
|
+
mime = val.content_type
|
|
157
|
+
b64 = base64.b64encode(buffered.getvalue()).decode()
|
|
158
|
+
val = f"data:{mime};base64,{b64}"
|
|
159
|
+
else:
|
|
160
|
+
# no se subió archivo nuevo → conservamos imagen anterior
|
|
161
|
+
val = prev_image
|
|
162
|
+
|
|
163
|
+
if isinstance(data[key], str) and not isinstance(val, str):
|
|
164
|
+
val = str(val)
|
|
165
|
+
data[key] = val
|
|
166
|
+
|
|
167
|
+
self.instance.config = data
|
|
168
|
+
return super().save(commit=commit)
|
|
@@ -1,16 +1,33 @@
|
|
|
1
|
+
from django.utils.translation import gettext_lazy as _
|
|
1
2
|
from django.contrib.auth import get_user_model
|
|
2
3
|
from django.db import models
|
|
3
4
|
|
|
5
|
+
FORMATS_DATE = [
|
|
6
|
+
("dd/MM/yyyy hh:mm:ss a", "dd/MM/yyyy hh:mm:ss a"),
|
|
7
|
+
("yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"),
|
|
8
|
+
("MM/dd/yyyy hh:mm:ss a", "MM/dd/yyyy hh:mm:ss a"),
|
|
9
|
+
("dd-MM-yyyy", "dd-MM-yyyy"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
FONT_ALIGNMENT = (
|
|
13
|
+
('NONE', _('None')),
|
|
14
|
+
('RIGHT', _('Right')),
|
|
15
|
+
('LEFT', _('Left')),
|
|
16
|
+
('TOP', _('Top')),
|
|
17
|
+
('BOTTOM', _('Bottom')),
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
4
21
|
def get_signature_default():
|
|
5
22
|
return {
|
|
6
|
-
"backgroundColor": "
|
|
23
|
+
"backgroundColor": "transparent",
|
|
7
24
|
"cAdESLevel": "LTA",
|
|
8
25
|
"contact": "",
|
|
9
26
|
"country": "CR",
|
|
10
27
|
"dateFormat": "dd/MM/yyyy hh\:mm\:ss a",
|
|
11
28
|
"defaultSignMessage": "Esta es una representación gráfica únicamente,\nverifique la validez de la firma.",
|
|
12
29
|
"font": "Nimbus Sans Regular",
|
|
13
|
-
"fontAlignment": "
|
|
30
|
+
"fontAlignment": "None",
|
|
14
31
|
"fontColor": "000000",
|
|
15
32
|
"fontSize": "7",
|
|
16
33
|
"image": "",
|
|
@@ -25,6 +42,7 @@ def get_signature_default():
|
|
|
25
42
|
"signY": "60",
|
|
26
43
|
"xAdESLevel": "LTA",
|
|
27
44
|
"isVisibleSignature": False,
|
|
45
|
+
"hideSignatureAdvice": False,
|
|
28
46
|
}
|
|
29
47
|
|
|
30
48
|
|
|
@@ -47,6 +47,17 @@ class RemoteSignerClient:
|
|
|
47
47
|
)
|
|
48
48
|
return response.json()
|
|
49
49
|
|
|
50
|
+
def validate_document(self, instance):
|
|
51
|
+
b64doc = self.get_b64document(instance['value'])
|
|
52
|
+
files = {
|
|
53
|
+
"b64Document": b64doc,
|
|
54
|
+
"DocumentExtension": ".pdf",
|
|
55
|
+
}
|
|
56
|
+
response = requests.post(
|
|
57
|
+
settings.FIRMADOR_VALIDA_URL, json=files
|
|
58
|
+
)
|
|
59
|
+
return response.json()
|
|
60
|
+
|
|
50
61
|
def _finalize_signature(self, data_to_sign, task):
|
|
51
62
|
result = None
|
|
52
63
|
error_msg = _("An unexpected error occurred during the signing process.")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from django.contrib import messages
|
|
2
|
+
from django.contrib.auth.decorators import login_required
|
|
3
|
+
from django.shortcuts import render, get_object_or_404, redirect
|
|
4
|
+
from django.utils.translation import gettext_lazy as _
|
|
5
|
+
|
|
6
|
+
from djgentelella.firmador_digital.forms import SignatureConfigForm
|
|
7
|
+
from djgentelella.firmador_digital.models import UserSignatureConfig
|
|
8
|
+
|
|
9
|
+
@login_required
|
|
10
|
+
def update_signature_settings(request):
|
|
11
|
+
|
|
12
|
+
config, is_created = UserSignatureConfig.objects.get_or_create(user=request.user)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if request.method == "POST":
|
|
16
|
+
form = SignatureConfigForm(request.POST, request.FILES, instance=config, render_type="as_grid")
|
|
17
|
+
if form.is_valid():
|
|
18
|
+
form.save()
|
|
19
|
+
messages.success(request, _("Updated signature settings successfully."))
|
|
20
|
+
return redirect("signature_config")
|
|
21
|
+
else:
|
|
22
|
+
form = SignatureConfigForm(instance=config, render_type="as_grid")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
return render(
|
|
26
|
+
request,
|
|
27
|
+
"gentelella/digital_signature/update_signature_settings.html",
|
|
28
|
+
context={
|
|
29
|
+
"form": form
|
|
30
|
+
}
|
|
31
|
+
)
|
|
@@ -70,8 +70,19 @@ class DigitalSignatureRenderFileAPIView(APIView):
|
|
|
70
70
|
return Response(file_data, content_type='application/pdf')
|
|
71
71
|
|
|
72
72
|
def get_instance_file(self, instance, fieldname):
|
|
73
|
+
# check if instance and fieldname are not None
|
|
74
|
+
if not instance or not fieldname:
|
|
75
|
+
return None
|
|
76
|
+
|
|
73
77
|
file_path = getattr(instance, fieldname)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
if not file_path:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
# check if not file
|
|
82
|
+
try:
|
|
83
|
+
with open(file_path.path, 'rb') as f:
|
|
84
|
+
file_data = f.read()
|
|
85
|
+
|
|
86
|
+
return file_data
|
|
87
|
+
except (FileNotFoundError, OSError):
|
|
88
|
+
return None
|
djgentelella/forms/forms.py
CHANGED
|
@@ -69,6 +69,11 @@ class GTForm(forms.Form):
|
|
|
69
69
|
case _:
|
|
70
70
|
self.renderer.form_template_name = self.template_name_horizontal
|
|
71
71
|
|
|
72
|
+
def get_error_for_grid(self, name):
|
|
73
|
+
if name in self.errors:
|
|
74
|
+
return self.errors[name]
|
|
75
|
+
return None
|
|
76
|
+
|
|
72
77
|
@property
|
|
73
78
|
def grid(self):
|
|
74
79
|
"""
|
|
@@ -97,10 +102,13 @@ class GTForm(forms.Form):
|
|
|
97
102
|
row_list = []
|
|
98
103
|
for field in col:
|
|
99
104
|
if field in dic_fields and dic_fields[field]:
|
|
100
|
-
row_list.append(
|
|
105
|
+
row_list.append(
|
|
106
|
+
(dic_fields[field], self.get_error_for_grid(field))
|
|
107
|
+
)
|
|
101
108
|
else:
|
|
102
109
|
if hasattr(self, field):
|
|
103
|
-
row_list.append(getattr(self, field)()
|
|
110
|
+
row_list.append((getattr(self, field)(),
|
|
111
|
+
self.get_error_for_grid(field)))
|
|
104
112
|
col_list.append(row_list)
|
|
105
113
|
grid.append(col_list)
|
|
106
114
|
return grid
|
djgentelella/groute.py
CHANGED
|
@@ -18,7 +18,10 @@ def register_lookups(prefix='', basename=None):
|
|
|
18
18
|
def decore(klass):
|
|
19
19
|
if basename in ['userbase', 'groupbase']:
|
|
20
20
|
from djgentelella import settings
|
|
21
|
-
if
|
|
21
|
+
if klass.__module__ == 'djgentelella.gtselects':
|
|
22
|
+
if settings.REGISTER_DEFAULT_USER_API:
|
|
23
|
+
routes.register(prefix, klass, basename=basename)
|
|
24
|
+
else:
|
|
22
25
|
routes.register(prefix, klass, basename=basename)
|
|
23
26
|
else:
|
|
24
27
|
routes.register(prefix, klass, basename=basename)
|
|
Binary file
|
|
@@ -616,3 +616,70 @@ 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
|
+
msgid "Signature image"
|
|
677
|
+
msgstr "Imagen de firma"
|
|
678
|
+
|
|
679
|
+
msgid "Image preview"
|
|
680
|
+
msgstr "Vista previa de imagen"
|
|
681
|
+
|
|
682
|
+
msgid "Image signature"
|
|
683
|
+
msgstr "Imagen de firma"
|
|
684
|
+
msgid "Expand"
|
|
685
|
+
msgstr "Expandir"
|
|
Binary file
|
|
@@ -213,3 +213,12 @@ 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"
|
|
@@ -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
|
+
]
|