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.
Files changed (80) hide show
  1. djgentelella/__init__.py +4 -1
  2. djgentelella/admin.py +7 -1
  3. djgentelella/firmador_digital/consumers/sign.py +24 -3
  4. djgentelella/firmador_digital/forms.py +140 -0
  5. djgentelella/firmador_digital/models.py +20 -2
  6. djgentelella/firmador_digital/utils.py +11 -0
  7. djgentelella/firmador_digital/views.py +31 -0
  8. djgentelella/firmador_digital/viewsets.py +15 -4
  9. djgentelella/forms/forms.py +10 -2
  10. djgentelella/groute.py +4 -1
  11. djgentelella/locale/es/LC_MESSAGES/django.mo +0 -0
  12. djgentelella/locale/es/LC_MESSAGES/django.po +67 -0
  13. djgentelella/locale/es/LC_MESSAGES/djangojs.mo +0 -0
  14. djgentelella/locale/es/LC_MESSAGES/djangojs.po +9 -0
  15. djgentelella/migrations/0014_trash.py +31 -0
  16. djgentelella/migrations/0015_trash_deleted_by.py +21 -0
  17. djgentelella/migrations/0016_trash_created_at.py +20 -0
  18. djgentelella/models.py +96 -0
  19. djgentelella/models_manager.py +40 -0
  20. djgentelella/serializers/firmador_digital.py +9 -1
  21. djgentelella/serializers/selects.py +14 -0
  22. djgentelella/static/djgentelella.flags.vendors.min.css +1 -1
  23. djgentelella/static/djgentelella.readonly.vendors.min.css +9 -5
  24. djgentelella/static/djgentelella.readonly.vendors.min.js +1 -1
  25. djgentelella/static/gentelella/css/custom.css +23 -2
  26. djgentelella/static/gentelella/css/modern.css +15 -0
  27. djgentelella/static/gentelella/css/modern_black_white.css +15 -0
  28. djgentelella/static/gentelella/css/pdfviewer.css +43 -1
  29. djgentelella/static/gentelella/images/default.png +0 -0
  30. djgentelella/static/gentelella/js/base/digital_signature.js +318 -79
  31. djgentelella/static/gentelella/js/base/form.common.js +9 -4
  32. djgentelella/static/gentelella/js/base/select2_wrap.js +15 -1
  33. djgentelella/static/gentelella/js/base/select2related.js +5 -0
  34. djgentelella/static/gentelella/js/base.js +347 -83
  35. djgentelella/static/gentelella/js/custom.js +6 -1
  36. djgentelella/static/gentelella/js/datatables.js +15 -0
  37. djgentelella/static/gentelella/js/digital_signature_update.js +29 -0
  38. djgentelella/static/gentelella/js/obj_api_management.js +403 -344
  39. djgentelella/static/gentelella/js/widgets.js +10 -1
  40. djgentelella/static/vendors/bootstrap-datetimepicker/bootstrap-datetimepicker.min.css.map +75 -7
  41. djgentelella/static/vendors/flags/1x1/ac.svg +75 -7
  42. djgentelella/static/vendors/flags/1x1/cp.svg +75 -7
  43. djgentelella/static/vendors/flags/1x1/dg.svg +75 -7
  44. djgentelella/static/vendors/flags/1x1/ea.svg +75 -7
  45. djgentelella/static/vendors/flags/1x1/es-ct.svg +75 -7
  46. djgentelella/static/vendors/flags/1x1/es-ga.svg +75 -7
  47. djgentelella/static/vendors/flags/1x1/ic.svg +75 -7
  48. djgentelella/static/vendors/flags/1x1/ta.svg +75 -7
  49. djgentelella/static/vendors/flags/1x1/xx.svg +75 -7
  50. djgentelella/static/vendors/flags/4x3/ac.svg +75 -7
  51. djgentelella/static/vendors/flags/4x3/cp.svg +75 -7
  52. djgentelella/static/vendors/flags/4x3/dg.svg +75 -7
  53. djgentelella/static/vendors/flags/4x3/ea.svg +75 -7
  54. djgentelella/static/vendors/flags/4x3/es-ct.svg +75 -7
  55. djgentelella/static/vendors/flags/4x3/es-ga.svg +75 -7
  56. djgentelella/static/vendors/flags/4x3/ic.svg +75 -7
  57. djgentelella/static/vendors/flags/4x3/ta.svg +75 -7
  58. djgentelella/static/vendors/flags/4x3/xx.svg +75 -7
  59. djgentelella/static/vendors/timeline/css/timeline.css +9 -5
  60. djgentelella/static/vendors/timeline/js/timeline.js +1 -1
  61. djgentelella/templates/forms/as_grid.html +2 -2
  62. djgentelella/templates/forms/as_inline.html +3 -5
  63. djgentelella/templates/gentelella/app/sidebar.html +16 -13
  64. djgentelella/templates/gentelella/digital_signature/update_signature_settings.html +45 -0
  65. djgentelella/templates/gentelella/registration/reset_done.html +24 -0
  66. djgentelella/templates/gentelella/widgets/digital_signature.html +47 -11
  67. djgentelella/trash/api.py +58 -0
  68. djgentelella/trash/filterset.py +20 -0
  69. djgentelella/trash/serializer.py +45 -0
  70. djgentelella/urls.py +8 -1
  71. djgentelella/views/select2autocomplete.py +40 -0
  72. djgentelella/widgets/core.py +6 -5
  73. djgentelella/widgets/digital_signature.py +5 -21
  74. djgentelella/widgets/selects.py +47 -0
  75. {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/METADATA +2 -2
  76. {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/RECORD +80 -68
  77. {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/AUTHORS +0 -0
  78. {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/LICENSE.txt +0 -0
  79. {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/WHEEL +0 -0
  80. {djgentelella-0.4.30.dist-info → djgentelella-0.5.0.dist-info}/top_level.txt +0 -0
djgentelella/__init__.py CHANGED
@@ -1 +1,4 @@
1
- __version__ = '0.4.30'
1
+ __version__ = '0.5.0'
2
+
3
+ if __name__ == '__main__':
4
+ print(__version__)
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": "transparente",
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": "RIGHT",
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
- file_data = None
75
- with open(file_path.path, 'rb') as f:
76
- file_data = f.read()
77
- return file_data
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
@@ -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(dic_fields[field])
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 settings.REGISTER_DEFAULT_USER_API:
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)
@@ -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"
@@ -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
+ ]