Serialize History and expose to API
This commit is contained in:
parent
73362b69c6
commit
ce4602018b
|
@ -131,10 +131,11 @@ class MetaInfo(models.Model):
|
||||||
class HistoryIndex(models.Model):
|
class HistoryIndex(models.Model):
|
||||||
content_type = models.ForeignKey(ContentType, null=True, on_delete=models.SET_NULL)
|
content_type = models.ForeignKey(ContentType, null=True, on_delete=models.SET_NULL)
|
||||||
object_id = models.PositiveIntegerField()
|
object_id = models.PositiveIntegerField()
|
||||||
content_object = GenericForeignKey('content_type', 'object_id')
|
history = GenericForeignKey('content_type', 'object_id')
|
||||||
|
|
||||||
owner_id = models.PositiveIntegerField()
|
owner_id = models.PositiveIntegerField()
|
||||||
owner_name = models.TextField()
|
owner_name = models.TextField()
|
||||||
|
object_name = models.TextField()
|
||||||
history_user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
|
history_user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
|
||||||
history_date = models.DateTimeField()
|
history_date = models.DateTimeField()
|
||||||
history_type = models.TextField()
|
history_type = models.TextField()
|
||||||
|
|
|
@ -41,6 +41,13 @@ class ReadOnly(BasePermission):
|
||||||
def has_object_permission(self, request, view, obj):
|
def has_object_permission(self, request, view, obj):
|
||||||
return bool(request.method in SAFE_METHODS)
|
return bool(request.method in SAFE_METHODS)
|
||||||
|
|
||||||
|
class IsAdmin(BasePermission):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return bool(
|
||||||
|
request.user
|
||||||
|
and is_admin_director(request.user)
|
||||||
|
)
|
||||||
|
|
||||||
class IsAdminOrReadOnly(BasePermission):
|
class IsAdminOrReadOnly(BasePermission):
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
return bool(
|
return bool(
|
||||||
|
|
|
@ -396,3 +396,17 @@ class MyPasswordChangeSerializer(PasswordChangeSerializer):
|
||||||
raise ValidationError(dict(non_field_errors='Problem connecting to LDAP server: set.'))
|
raise ValidationError(dict(non_field_errors='Problem connecting to LDAP server: set.'))
|
||||||
|
|
||||||
super().save()
|
super().save()
|
||||||
|
|
||||||
|
|
||||||
|
class HistoryChangeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = models.HistoryChange
|
||||||
|
fields = ['field', 'old', 'new']
|
||||||
|
|
||||||
|
class HistorySerializer(serializers.ModelSerializer):
|
||||||
|
changes = HistoryChangeSerializer(many=True)
|
||||||
|
history_user = serializers.StringRelatedField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.HistoryIndex
|
||||||
|
fields = '__all__'
|
||||||
|
|
|
@ -10,6 +10,9 @@ from .permissions import is_admin_director
|
||||||
def get_object_owner(obj):
|
def get_object_owner(obj):
|
||||||
full_name = lambda member: member.first_name + ' ' + member.last_name
|
full_name = lambda member: member.first_name + ' ' + member.last_name
|
||||||
|
|
||||||
|
if obj.__class__.__name__ == 'Member':
|
||||||
|
return full_name(obj), obj.id
|
||||||
|
|
||||||
if getattr(obj, 'user', False):
|
if getattr(obj, 'user', False):
|
||||||
return full_name(obj.user.member), obj.user.member.id
|
return full_name(obj.user.member), obj.user.member.id
|
||||||
|
|
||||||
|
@ -35,27 +38,45 @@ def post_create_historical_record_callback(
|
||||||
using,
|
using,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
changes = history_instance.diff_against(history_instance.prev_record).changes
|
history_type = history_instance.get_history_type_display()
|
||||||
|
object_name = instance.__class__.__name__
|
||||||
|
|
||||||
if changes:
|
if object_name in ['User']: return
|
||||||
|
|
||||||
|
if history_type == 'Changed':
|
||||||
|
changes = history_instance.diff_against(history_instance.prev_record).changes
|
||||||
|
else:
|
||||||
|
changes = []
|
||||||
|
|
||||||
|
# it's possible for changes to be empty if model saved with no diff
|
||||||
|
if changes or history_type in ['Created', 'Deleted']:
|
||||||
owner = get_object_owner(instance)
|
owner = get_object_owner(instance)
|
||||||
|
|
||||||
index = models.HistoryIndex.objects.create(
|
index = models.HistoryIndex.objects.create(
|
||||||
content_object=history_instance,
|
history=history_instance,
|
||||||
owner_name=owner[0],
|
|
||||||
owner_id=owner[1],
|
owner_id=owner[1],
|
||||||
|
owner_name=owner[0],
|
||||||
|
object_name=object_name,
|
||||||
history_user=history_user,
|
history_user=history_user,
|
||||||
history_date=history_instance.history_date,
|
history_date=history_instance.history_date,
|
||||||
history_type=history_instance.get_history_type_display(),
|
history_type=history_type,
|
||||||
revert_url=history_instance.revert_url(),
|
revert_url=history_instance.revert_url(),
|
||||||
is_system=bool(history_user == None),
|
is_system=bool(history_user == None),
|
||||||
is_admin=is_admin_director(history_user),
|
is_admin=is_admin_director(history_user),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
change_old = change.old or ''
|
||||||
|
change_new = change.new or ''
|
||||||
|
|
||||||
|
if len(change_old) > 200:
|
||||||
|
change_old = change_old[:200] + '... [truncated]'
|
||||||
|
if len(change_new) > 200:
|
||||||
|
change_new = change_new[:200] + '... [truncated]'
|
||||||
|
|
||||||
for change in changes:
|
for change in changes:
|
||||||
models.HistoryChange.objects.create(
|
models.HistoryChange.objects.create(
|
||||||
index=index,
|
index=index,
|
||||||
field=change.field,
|
field=change.field,
|
||||||
old=change.old,
|
old=change_old,
|
||||||
new=change.new,
|
new=change_new,
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,6 +23,7 @@ from .permissions import (
|
||||||
IsObjOwnerOrAdmin,
|
IsObjOwnerOrAdmin,
|
||||||
IsSessionInstructorOrAdmin,
|
IsSessionInstructorOrAdmin,
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
|
IsAdmin,
|
||||||
IsAdminOrReadOnly,
|
IsAdminOrReadOnly,
|
||||||
IsInstructorOrReadOnly
|
IsInstructorOrReadOnly
|
||||||
)
|
)
|
||||||
|
@ -413,6 +414,12 @@ class PasteView(views.APIView):
|
||||||
raise exceptions.ValidationError(dict(paste='This field is required.'))
|
raise exceptions.ValidationError(dict(paste='This field is required.'))
|
||||||
|
|
||||||
|
|
||||||
|
class HistoryViewSet(Base, List, Retrieve):
|
||||||
|
permission_classes = [AllowMetadata | IsAdmin]
|
||||||
|
serializer_class = serializers.HistorySerializer
|
||||||
|
queryset = models.HistoryIndex.objects.order_by('-history_date')
|
||||||
|
|
||||||
|
|
||||||
class RegistrationView(RegisterView):
|
class RegistrationView(RegisterView):
|
||||||
serializer_class = serializers.MyRegisterSerializer
|
serializer_class = serializers.MyRegisterSerializer
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ router.register(r'stats', views.StatsViewSet, basename='stats')
|
||||||
router.register(r'search', views.SearchViewSet, basename='search')
|
router.register(r'search', views.SearchViewSet, basename='search')
|
||||||
router.register(r'members', views.MemberViewSet, basename='members')
|
router.register(r'members', views.MemberViewSet, basename='members')
|
||||||
router.register(r'courses', views.CourseViewSet, basename='course')
|
router.register(r'courses', views.CourseViewSet, basename='course')
|
||||||
|
router.register(r'history', views.HistoryViewSet, basename='history')
|
||||||
router.register(r'sessions', views.SessionViewSet, basename='session')
|
router.register(r'sessions', views.SessionViewSet, basename='session')
|
||||||
router.register(r'training', views.TrainingViewSet, basename='training')
|
router.register(r'training', views.TrainingViewSet, basename='training')
|
||||||
router.register(r'transactions', views.TransactionViewSet, basename='transaction')
|
router.register(r'transactions', views.TransactionViewSet, basename='transaction')
|
||||||
|
|
Loading…
Reference in New Issue
Block a user