djgentelella 0.5.0__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 +1 -1
- djgentelella/admin.py +34 -1
- djgentelella/firmador_digital/models.py +16 -39
- 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 +38 -0
- djgentelella/locale/es/LC_MESSAGES/djangojs.mo +0 -0
- djgentelella/locale/es/LC_MESSAGES/djangojs.po +37 -0
- djgentelella/migrations/0017_alter_chunkedupload_status.py +18 -0
- djgentelella/migrations/0018_alter_chunkedupload_status.py +18 -0
- djgentelella/models.py +3 -2
- djgentelella/static/djgentelella.flags.vendors.min.css +1 -1
- djgentelella/static/vendors/bootstrap-datetimepicker/bootstrap-datetimepicker.min.css.map +7 -75
- djgentelella/static/vendors/flags/1x1/ac.svg +7 -75
- djgentelella/static/vendors/flags/1x1/cp.svg +7 -75
- djgentelella/static/vendors/flags/1x1/dg.svg +7 -75
- djgentelella/static/vendors/flags/1x1/ea.svg +7 -75
- djgentelella/static/vendors/flags/1x1/es-ct.svg +7 -75
- djgentelella/static/vendors/flags/1x1/es-ga.svg +7 -75
- djgentelella/static/vendors/flags/1x1/ic.svg +7 -75
- djgentelella/static/vendors/flags/1x1/ta.svg +7 -75
- djgentelella/static/vendors/flags/1x1/xx.svg +7 -75
- djgentelella/static/vendors/flags/4x3/ac.svg +7 -75
- djgentelella/static/vendors/flags/4x3/cp.svg +7 -75
- djgentelella/static/vendors/flags/4x3/dg.svg +7 -75
- djgentelella/static/vendors/flags/4x3/ea.svg +7 -75
- djgentelella/static/vendors/flags/4x3/es-ct.svg +7 -75
- djgentelella/static/vendors/flags/4x3/es-ga.svg +7 -75
- djgentelella/static/vendors/flags/4x3/ic.svg +7 -75
- djgentelella/static/vendors/flags/4x3/ta.svg +7 -75
- djgentelella/static/vendors/flags/4x3/xx.svg +7 -75
- djgentelella/trash/api.py +19 -0
- djgentelella/urls.py +5 -1
- {djgentelella-0.5.0.dist-info → djgentelella-0.5.1.dist-info}/METADATA +1 -1
- {djgentelella-0.5.0.dist-info → djgentelella-0.5.1.dist-info}/RECORD +42 -36
- {djgentelella-0.5.0.dist-info → djgentelella-0.5.1.dist-info}/AUTHORS +0 -0
- {djgentelella-0.5.0.dist-info → djgentelella-0.5.1.dist-info}/LICENSE.txt +0 -0
- {djgentelella-0.5.0.dist-info → djgentelella-0.5.1.dist-info}/WHEEL +0 -0
- {djgentelella-0.5.0.dist-info → djgentelella-0.5.1.dist-info}/top_level.txt +0 -0
djgentelella/__init__.py
CHANGED
djgentelella/admin.py
CHANGED
|
@@ -5,7 +5,9 @@ from djgentelella.models import MenuItem, Help, GentelellaSettings, Notification
|
|
|
5
5
|
ChunkedUpload, Trash
|
|
6
6
|
from djgentelella.models import PermissionsCategoryManagement
|
|
7
7
|
from djgentelella.utils import clean_cache
|
|
8
|
-
|
|
8
|
+
from django.contrib.admin.models import LogEntry
|
|
9
|
+
from djgentelella.history.utils import ACTIONS
|
|
10
|
+
from django.utils.translation import gettext_lazy as _
|
|
9
11
|
|
|
10
12
|
class MenuAdmin(admin.ModelAdmin):
|
|
11
13
|
filter_horizontal = ['permission']
|
|
@@ -38,6 +40,36 @@ class TrashAdmin(admin.ModelAdmin):
|
|
|
38
40
|
ordering = ("-created_at",)
|
|
39
41
|
search_fields = ("id",)
|
|
40
42
|
|
|
43
|
+
|
|
44
|
+
class ActionFlagFilter(admin.SimpleListFilter):
|
|
45
|
+
title = _("Action")
|
|
46
|
+
parameter_name = "action_flag"
|
|
47
|
+
|
|
48
|
+
def lookups(self, request, model_admin):
|
|
49
|
+
return [(k, str(v)) for k, v in ACTIONS.items()]
|
|
50
|
+
|
|
51
|
+
def queryset(self, request, queryset):
|
|
52
|
+
val = self.value()
|
|
53
|
+
if not val:
|
|
54
|
+
return queryset
|
|
55
|
+
try:
|
|
56
|
+
return queryset.filter(action_flag=int(val))
|
|
57
|
+
except ValueError:
|
|
58
|
+
return queryset.none()
|
|
59
|
+
|
|
60
|
+
class LogEntryAdmin(admin.ModelAdmin):
|
|
61
|
+
verbose_name = _("History")
|
|
62
|
+
verbose_name_plural = _("History")
|
|
63
|
+
list_display = ("id", "action_time", "user", "content_type", "object_id", "object_repr", "action_label", "change_message")
|
|
64
|
+
search_fields = ("content_type__app_label", "content_type__model", "object_id", "user__username")
|
|
65
|
+
list_filter = (
|
|
66
|
+
ActionFlagFilter,
|
|
67
|
+
)
|
|
68
|
+
def action_label(self, obj):
|
|
69
|
+
return ACTIONS.get(obj.action_flag, obj.get_action_flag_display() or obj.action_flag)
|
|
70
|
+
action_label.short_description = _("Action")
|
|
71
|
+
|
|
72
|
+
|
|
41
73
|
admin.site.register(UserSignatureConfig, UserSignatureConfigAdmin)
|
|
42
74
|
admin.site.register(ChunkedUpload, ChunkedUploadAdmin)
|
|
43
75
|
admin.site.register(MenuItem, MenuAdmin)
|
|
@@ -46,3 +78,4 @@ admin.site.register(PermissionsCategoryManagement)
|
|
|
46
78
|
admin.site.register(GentelellaSettings, GentelellaSettingsAdmin)
|
|
47
79
|
admin.site.register(Notification, NotificationAdmin)
|
|
48
80
|
admin.site.register(Trash, TrashAdmin)
|
|
81
|
+
admin.site.register(LogEntry, LogEntryAdmin)
|
|
@@ -1,49 +1,26 @@
|
|
|
1
|
-
from django.utils.translation import gettext_lazy as _
|
|
2
1
|
from django.contrib.auth import get_user_model
|
|
3
2
|
from django.db import models
|
|
3
|
+
from django.utils.translation import gettext_lazy as _
|
|
4
4
|
|
|
5
|
-
FORMATS_DATE = [
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
("dd-MM-yyyy", "dd-MM-yyyy"),
|
|
10
|
-
]
|
|
5
|
+
FORMATS_DATE = [("dd/MM/yyyy hh:mm:ss a", "dd/MM/yyyy hh:mm:ss a"),
|
|
6
|
+
("yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss"),
|
|
7
|
+
("MM/dd/yyyy hh:mm:ss a", "MM/dd/yyyy hh:mm:ss a"),
|
|
8
|
+
("dd-MM-yyyy", "dd-MM-yyyy"), ]
|
|
11
9
|
|
|
12
|
-
FONT_ALIGNMENT = (
|
|
13
|
-
|
|
14
|
-
('RIGHT', _('Right')),
|
|
15
|
-
('LEFT', _('Left')),
|
|
16
|
-
('TOP', _('Top')),
|
|
17
|
-
('BOTTOM', _('Bottom')),
|
|
18
|
-
)
|
|
10
|
+
FONT_ALIGNMENT = (('NONE', _('None')), ('RIGHT', _('Right')), ('LEFT', _('Left')),
|
|
11
|
+
('TOP', _('Top')), ('BOTTOM', _('Bottom')),)
|
|
19
12
|
|
|
20
13
|
|
|
21
14
|
def get_signature_default():
|
|
22
|
-
return {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"fontColor": "000000",
|
|
32
|
-
"fontSize": "7",
|
|
33
|
-
"image": "",
|
|
34
|
-
"language": "es",
|
|
35
|
-
"pAdESLevel": "LTA",
|
|
36
|
-
"place": "",
|
|
37
|
-
"portNumber": "3516",
|
|
38
|
-
"reason": "",
|
|
39
|
-
"signHeight": "33",
|
|
40
|
-
"signWidth": "133",
|
|
41
|
-
"signX": "40",
|
|
42
|
-
"signY": "60",
|
|
43
|
-
"xAdESLevel": "LTA",
|
|
44
|
-
"isVisibleSignature": False,
|
|
45
|
-
"hideSignatureAdvice": False,
|
|
46
|
-
}
|
|
15
|
+
return {"backgroundColor": "transparent", "cAdESLevel": "LTA", "contact": "",
|
|
16
|
+
"country": "CR", "dateFormat": "dd/MM/yyyy hh:mm:ss a",
|
|
17
|
+
"defaultSignMessage": "Esta es una representación gráfica únicamente,\nverifique la validez de la firma.",
|
|
18
|
+
"font": "Nimbus Sans Regular", "fontAlignment": "None",
|
|
19
|
+
"fontColor": "000000",
|
|
20
|
+
"fontSize": "7", "image": "", "language": "es", "pAdESLevel": "LTA",
|
|
21
|
+
"place": "", "portNumber": "3516", "reason": "", "signHeight": "33",
|
|
22
|
+
"signWidth": "133", "signX": "40", "signY": "60", "xAdESLevel": "LTA",
|
|
23
|
+
"isVisibleSignature": False, "hideSignatureAdvice": False, }
|
|
47
24
|
|
|
48
25
|
|
|
49
26
|
class UserSignatureConfig(models.Model):
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from djgentelella.objectmanagement import AuthAllPermBaseObjectManagement
|
|
2
|
+
from django.utils.translation import gettext_lazy as _
|
|
3
|
+
from djgentelella.history.utils import add_log
|
|
4
|
+
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
|
|
5
|
+
from djgentelella.history.serializers import HistoryDataTableSerializer
|
|
6
|
+
from djgentelella.history.filterset import HistoryFilterSet
|
|
7
|
+
from rest_framework.authentication import SessionAuthentication
|
|
8
|
+
from rest_framework.filters import SearchFilter, OrderingFilter
|
|
9
|
+
from rest_framework.pagination import LimitOffsetPagination
|
|
10
|
+
from django_filters.rest_framework import DjangoFilterBackend
|
|
11
|
+
from rest_framework.response import Response
|
|
12
|
+
from django.conf import settings
|
|
13
|
+
from django.db.models import Q
|
|
14
|
+
from django.contrib.contenttypes.models import ContentType
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseViewSetWithLogs(AuthAllPermBaseObjectManagement):
|
|
19
|
+
|
|
20
|
+
def perform_create(self, serializer):
|
|
21
|
+
super().perform_create(serializer)
|
|
22
|
+
new_instance = serializer.instance
|
|
23
|
+
|
|
24
|
+
add_log(
|
|
25
|
+
self.request.user,
|
|
26
|
+
new_instance,
|
|
27
|
+
ADDITION,
|
|
28
|
+
new_instance._meta.verbose_name.title().lower(),
|
|
29
|
+
[],
|
|
30
|
+
change_message=_("Created"),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def perform_update(self, serializer):
|
|
34
|
+
# get the instance before the update
|
|
35
|
+
instance = self.get_object()
|
|
36
|
+
old_values = {
|
|
37
|
+
field: getattr(instance, field)
|
|
38
|
+
for field in serializer.validated_data.keys()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
super().perform_update(serializer)
|
|
42
|
+
|
|
43
|
+
new_instance = serializer.instance
|
|
44
|
+
# get changed fields
|
|
45
|
+
changed_fields = []
|
|
46
|
+
|
|
47
|
+
for field in serializer.validated_data.keys():
|
|
48
|
+
old_value = old_values.get(field)
|
|
49
|
+
new_value = getattr(new_instance, field)
|
|
50
|
+
if old_value != new_value:
|
|
51
|
+
changed_fields.append(field)
|
|
52
|
+
|
|
53
|
+
add_log(
|
|
54
|
+
self.request.user,
|
|
55
|
+
new_instance,
|
|
56
|
+
CHANGE,
|
|
57
|
+
new_instance._meta.verbose_name.title().lower(),
|
|
58
|
+
changed_data=changed_fields,
|
|
59
|
+
change_message=_("Updated"),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def perform_destroy(self, instance):
|
|
63
|
+
instance = self.get_object()
|
|
64
|
+
if instance._meta.verbose_name.title() in self.models_log:
|
|
65
|
+
add_log(
|
|
66
|
+
self.request.user,
|
|
67
|
+
instance,
|
|
68
|
+
DELETION,
|
|
69
|
+
instance._meta.verbose_name.title().lower(),
|
|
70
|
+
change_message=_("Deleted"),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
super().perform_destroy(instance)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class HistoryViewSet(AuthAllPermBaseObjectManagement):
|
|
77
|
+
authentication_classes = [SessionAuthentication]
|
|
78
|
+
serializer_class = HistoryDataTableSerializer
|
|
79
|
+
queryset = LogEntry.objects.all()
|
|
80
|
+
pagination_class = LimitOffsetPagination
|
|
81
|
+
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
|
|
82
|
+
search_fields = ["object_repr"]
|
|
83
|
+
filterset_class = HistoryFilterSet
|
|
84
|
+
ordering_fields = ["-action_time"]
|
|
85
|
+
ordering = ("-action_time",)
|
|
86
|
+
perms = {"list": ["admin.view_logentry"]}
|
|
87
|
+
|
|
88
|
+
def get_queryset(self):
|
|
89
|
+
queryset = self.queryset
|
|
90
|
+
|
|
91
|
+
# check allowed models in settings
|
|
92
|
+
allowed = getattr(settings, "GT_HISTORY_ALLOWED_MODELS", None)
|
|
93
|
+
|
|
94
|
+
if allowed:
|
|
95
|
+
allowed_ctypes = self.contenttypes_from_settings(allowed)
|
|
96
|
+
|
|
97
|
+
if not allowed_ctypes.exists():
|
|
98
|
+
return queryset.none()
|
|
99
|
+
|
|
100
|
+
queryset = queryset.filter(content_type__in=allowed_ctypes).distinct()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# check contenttype param in form
|
|
104
|
+
ctypes_param = self.request.GET.get("contenttype")
|
|
105
|
+
print(allowed)
|
|
106
|
+
if ctypes_param and ctypes_param in allowed:
|
|
107
|
+
|
|
108
|
+
ctypes_qs = self.contenttypes_from_settings([ctypes_param])
|
|
109
|
+
print(ctypes_qs)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
if not ctypes_qs.exists():
|
|
113
|
+
return queryset.none()
|
|
114
|
+
|
|
115
|
+
queryset = queryset.filter(content_type__in=ctypes_qs).distinct()
|
|
116
|
+
|
|
117
|
+
# default values
|
|
118
|
+
return queryset
|
|
119
|
+
|
|
120
|
+
def contenttypes_from_settings(self, entries):
|
|
121
|
+
q = Q()
|
|
122
|
+
for item in entries:
|
|
123
|
+
if isinstance(item, str) and "." in item:
|
|
124
|
+
app_label, model_name = item.split(".", 1)
|
|
125
|
+
app_label = app_label.strip()
|
|
126
|
+
model_key = model_name.strip().lower()
|
|
127
|
+
q |= Q(app_label=app_label, model=model_key)
|
|
128
|
+
|
|
129
|
+
if not q:
|
|
130
|
+
return ContentType.objects.none()
|
|
131
|
+
return ContentType.objects.filter(q)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def list(self, request, *args, **kwargs):
|
|
135
|
+
queryset = self.filter_queryset(self.get_queryset())
|
|
136
|
+
page = self.paginate_queryset(queryset)
|
|
137
|
+
data = page if page is not None else queryset
|
|
138
|
+
|
|
139
|
+
response = {
|
|
140
|
+
"data": data,
|
|
141
|
+
"recordsTotal": LogEntry.objects.count(),
|
|
142
|
+
"recordsFiltered": queryset.count(),
|
|
143
|
+
"draw": self.request.GET.get("draw", 1),
|
|
144
|
+
}
|
|
145
|
+
return Response(self.get_serializer(response).data)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from django.contrib.admin.models import LogEntry
|
|
2
|
+
from django_filters.rest_framework import FilterSet, ChoiceFilter
|
|
3
|
+
from django_filters import DateTimeFromToRangeFilter
|
|
4
|
+
from djgentelella.fields.drfdatetime import DateTimeRangeTextWidget
|
|
5
|
+
from djgentelella.history.utils import ACTIONS
|
|
6
|
+
|
|
7
|
+
class HistoryFilterSet(FilterSet):
|
|
8
|
+
action_time = DateTimeFromToRangeFilter(
|
|
9
|
+
widget=DateTimeRangeTextWidget(attrs={"placeholder": "DD/MM/YYYY/"})
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
action_flag = ChoiceFilter(
|
|
13
|
+
field_name="action_flag",
|
|
14
|
+
choices=[(k, str(v)) for k, v in ACTIONS.items()], # added 4 y 5
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
class Meta:
|
|
18
|
+
model = LogEntry
|
|
19
|
+
fields = {
|
|
20
|
+
"object_repr": ["icontains"],
|
|
21
|
+
"change_message": ["icontains"],
|
|
22
|
+
"user": ["exact"],
|
|
23
|
+
}
|
|
@@ -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
|
|
@@ -673,6 +673,7 @@ msgstr "El registro fue restaurado con éxito."
|
|
|
673
673
|
|
|
674
674
|
msgid "The registry could not be restored."
|
|
675
675
|
msgstr "No se pudo restaurar el registro."
|
|
676
|
+
|
|
676
677
|
msgid "Signature image"
|
|
677
678
|
msgstr "Imagen de firma"
|
|
678
679
|
|
|
@@ -683,3 +684,40 @@ msgid "Image signature"
|
|
|
683
684
|
msgstr "Imagen de firma"
|
|
684
685
|
msgid "Expand"
|
|
685
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
|
|
@@ -222,3 +222,40 @@ msgstr "El documento no está firmado digitalmente. Por favor, firme el document
|
|
|
222
222
|
|
|
223
223
|
msgid "The document was saved"
|
|
224
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,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
|
@@ -10,6 +10,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey
|
|
|
10
10
|
from .models_manager import ObjectManager, AllObjectsManager, \
|
|
11
11
|
DeletedObjectsManager
|
|
12
12
|
|
|
13
|
+
from djgentelella.history.utils import add_log, ADDITION
|
|
13
14
|
|
|
14
15
|
class GentelellaSettings(models.Model):
|
|
15
16
|
"""
|
|
@@ -161,7 +162,7 @@ class Trash(models.Model):
|
|
|
161
162
|
verbose_name_plural = _("Trash")
|
|
162
163
|
|
|
163
164
|
def __str__(self):
|
|
164
|
-
return _("
|
|
165
|
+
return _("%(obj)s in trash") % {"obj": self.object_repr}
|
|
165
166
|
|
|
166
167
|
def restore(self, user=None):
|
|
167
168
|
obj = self.content_object
|
|
@@ -206,7 +207,7 @@ class DeletedWithTrash(models.Model):
|
|
|
206
207
|
self.save(update_fields=["is_deleted"])
|
|
207
208
|
|
|
208
209
|
# create trash instance
|
|
209
|
-
Trash.objects.get_or_create(
|
|
210
|
+
trash = Trash.objects.get_or_create(
|
|
210
211
|
content_type=ContentType.objects.get_for_model(self.__class__),
|
|
211
212
|
object_id=self.pk,
|
|
212
213
|
defaults={
|