mirror of
https://github.com/ansible/awx.git
synced 2026-03-09 05:29:26 -02:30
Get created_by and modified_by updating automatically.
This commit is contained in:
@@ -253,11 +253,7 @@ class ListAPIView(generics.ListAPIView, GenericAPIView):
|
|||||||
|
|
||||||
class ListCreateAPIView(ListAPIView, generics.ListCreateAPIView):
|
class ListCreateAPIView(ListAPIView, generics.ListCreateAPIView):
|
||||||
# Base class for a list view that allows creating new objects.
|
# Base class for a list view that allows creating new objects.
|
||||||
|
pass
|
||||||
def pre_save(self, obj):
|
|
||||||
super(ListCreateAPIView, self).pre_save(obj)
|
|
||||||
if isinstance(obj, PrimordialModel):
|
|
||||||
obj.created_by = self.request.user
|
|
||||||
|
|
||||||
class SubListAPIView(ListAPIView):
|
class SubListAPIView(ListAPIView):
|
||||||
# Base class for a read-only sublist view.
|
# Base class for a read-only sublist view.
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ d2to1==0.2.11 (d2to1/*)
|
|||||||
distribute==0.7.3 (no files)
|
distribute==0.7.3 (no files)
|
||||||
django-auth-ldap==1.1.8 (django_auth_ldap/*)
|
django-auth-ldap==1.1.8 (django_auth_ldap/*)
|
||||||
django-celery==3.1.10 (djcelery/*)
|
django-celery==3.1.10 (djcelery/*)
|
||||||
|
django-crum==0.6.1 (crum/*)
|
||||||
django-extensions==1.3.3 (django_extensions/*)
|
django-extensions==1.3.3 (django_extensions/*)
|
||||||
django-jsonfield==0.9.12 (jsonfield/*, minor fix in jsonfield/fields.py)
|
django-jsonfield==0.9.12 (jsonfield/*, minor fix in jsonfield/fields.py)
|
||||||
django-polymorphic==0.5.3 (polymorphic/*)
|
django-polymorphic==0.5.3 (polymorphic/*)
|
||||||
|
|||||||
87
awx/lib/site-packages/crum/__init__.py
Normal file
87
awx/lib/site-packages/crum/__init__.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# Python
|
||||||
|
import contextlib
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
|
||||||
|
_thread_locals = threading.local()
|
||||||
|
|
||||||
|
_logger = logging.getLogger('crum')
|
||||||
|
|
||||||
|
__version__ = '0.6.1'
|
||||||
|
|
||||||
|
__all__ = ['get_current_request', 'get_current_user', 'impersonate']
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def impersonate(user=None):
|
||||||
|
"""Temporarily impersonate the given user for audit trails."""
|
||||||
|
try:
|
||||||
|
current_user = get_current_user(_return_false=True)
|
||||||
|
set_current_user(user)
|
||||||
|
yield user
|
||||||
|
finally:
|
||||||
|
set_current_user(current_user)
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_request():
|
||||||
|
"""Return the request associated with the current thread."""
|
||||||
|
return getattr(_thread_locals, 'request', None)
|
||||||
|
|
||||||
|
|
||||||
|
def set_current_request(request=None):
|
||||||
|
"""Update the request associated with the current thread."""
|
||||||
|
_thread_locals.request = request
|
||||||
|
# Clear the current user if also clearing the request.
|
||||||
|
if not request:
|
||||||
|
set_current_user(False)
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_user(_return_false=False):
|
||||||
|
"""Return the user associated with the current request thread."""
|
||||||
|
from crum.signals import current_user_getter
|
||||||
|
top_priority = -9999
|
||||||
|
top_user = False if _return_false else None
|
||||||
|
results = current_user_getter.send_robust(get_current_user)
|
||||||
|
for receiver, response in results:
|
||||||
|
priority = 0
|
||||||
|
if isinstance(response, Exception):
|
||||||
|
_logger.exception('%r raised exception: %s', receiver, response)
|
||||||
|
continue
|
||||||
|
elif isinstance(response, (tuple, list)) and response:
|
||||||
|
user = response[0]
|
||||||
|
if len(response) > 1:
|
||||||
|
priority = response[1]
|
||||||
|
elif response or response in (None, False):
|
||||||
|
user = response
|
||||||
|
else:
|
||||||
|
_logger.error('%r returned invalid response: %r', receiver,
|
||||||
|
response)
|
||||||
|
continue
|
||||||
|
if user is not False:
|
||||||
|
if priority > top_priority:
|
||||||
|
top_priority = priority
|
||||||
|
top_user = user
|
||||||
|
return top_user
|
||||||
|
|
||||||
|
|
||||||
|
def set_current_user(user=None):
|
||||||
|
"""Update the user associated with the current request thread."""
|
||||||
|
from crum.signals import current_user_setter
|
||||||
|
results = current_user_setter.send_robust(set_current_user, user=user)
|
||||||
|
for receiver, response in results:
|
||||||
|
if isinstance(response, Exception):
|
||||||
|
_logger.exception('%r raised exception: %s', receiver, response)
|
||||||
|
|
||||||
|
|
||||||
|
class CurrentRequestUserMiddleware(object):
|
||||||
|
"""Middleware to capture the request and user from the current thread."""
|
||||||
|
|
||||||
|
def process_request(self, request):
|
||||||
|
set_current_request(request)
|
||||||
|
|
||||||
|
def process_response(self, request, response):
|
||||||
|
set_current_request(None)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def process_exception(self, request, exception):
|
||||||
|
set_current_request(None)
|
||||||
44
awx/lib/site-packages/crum/signals.py
Normal file
44
awx/lib/site-packages/crum/signals.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Django
|
||||||
|
from django.dispatch import Signal, receiver
|
||||||
|
|
||||||
|
__all__ = ['current_user_getter']
|
||||||
|
|
||||||
|
|
||||||
|
# Signal used when getting current user. Receivers should return a tuple of
|
||||||
|
# (user, priority).
|
||||||
|
current_user_getter = Signal(providing_args=[])
|
||||||
|
|
||||||
|
|
||||||
|
# Signal used when setting current user. Receivers should store the current
|
||||||
|
# user as needed. Return values are ignored.
|
||||||
|
current_user_setter = Signal(providing_args=['user'])
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(current_user_getter)
|
||||||
|
def _get_current_user_from_request(sender, **kwargs):
|
||||||
|
"""Signal handler to retrieve current user from request."""
|
||||||
|
from crum import get_current_request
|
||||||
|
return (getattr(get_current_request(), 'user', False), -10)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(current_user_getter)
|
||||||
|
def _get_current_user_from_thread_locals(sender, **kwargs):
|
||||||
|
"""Signal handler to retrieve current user from thread locals."""
|
||||||
|
from crum import _thread_locals
|
||||||
|
return (getattr(_thread_locals, 'user', False), 10)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(current_user_setter)
|
||||||
|
def _set_current_user_on_request(sender, **kwargs):
|
||||||
|
"""Signal handler to store current user to request."""
|
||||||
|
from crum import get_current_request
|
||||||
|
request = get_current_request()
|
||||||
|
if request:
|
||||||
|
request.user = kwargs['user']
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(current_user_setter)
|
||||||
|
def _set_current_user_on_thread_locals(sender, **kwargs):
|
||||||
|
"""Signal handler to store current user on thread locals."""
|
||||||
|
from crum import _thread_locals
|
||||||
|
_thread_locals.user = kwargs['user']
|
||||||
@@ -27,6 +27,9 @@ from taggit.managers import TaggableManager
|
|||||||
# Django-Celery
|
# Django-Celery
|
||||||
from djcelery.models import TaskMeta
|
from djcelery.models import TaskMeta
|
||||||
|
|
||||||
|
# Django-CRUM
|
||||||
|
from crum import get_current_user
|
||||||
|
|
||||||
# Ansible Tower
|
# Ansible Tower
|
||||||
from awx.main.utils import encrypt_field
|
from awx.main.utils import encrypt_field
|
||||||
|
|
||||||
@@ -284,6 +287,20 @@ class PrimordialModel(CreatedModifiedModel):
|
|||||||
self.save(update_fields=update_fields)
|
self.save(update_fields=update_fields)
|
||||||
return update_fields
|
return update_fields
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
update_fields = kwargs.get('update_fields', [])
|
||||||
|
user = get_current_user()
|
||||||
|
if user and not user.pk:
|
||||||
|
user = None
|
||||||
|
if not self.pk:
|
||||||
|
self.created_by = user
|
||||||
|
if 'created_by' not in update_fields:
|
||||||
|
update_fields.append('created_by')
|
||||||
|
self.modified_by = user
|
||||||
|
if 'modified_by' not in update_fields:
|
||||||
|
update_fields.append('modified_by')
|
||||||
|
super(PrimordialModel, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def clean_description(self):
|
def clean_description(self):
|
||||||
# Description should always be empty string, never null.
|
# Description should always be empty string, never null.
|
||||||
return self.description or ''
|
return self.description or ''
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ from django.conf import settings
|
|||||||
from django.db.models.signals import pre_save, post_save, pre_delete, post_delete, m2m_changed
|
from django.db.models.signals import pre_save, post_save, pre_delete, post_delete, m2m_changed
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
# Django-CRUM
|
||||||
|
from crum import get_current_request
|
||||||
|
from crum.signals import current_user_getter
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models import *
|
from awx.main.models import *
|
||||||
from awx.api.serializers import *
|
from awx.api.serializers import *
|
||||||
@@ -361,3 +365,15 @@ def activity_stream_associate(sender, instance, **kwargs):
|
|||||||
activity_entry.save()
|
activity_entry.save()
|
||||||
getattr(activity_entry, object1).add(obj1)
|
getattr(activity_entry, object1).add(obj1)
|
||||||
getattr(activity_entry, object2).add(obj2_actual)
|
getattr(activity_entry, object2).add(obj2_actual)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(current_user_getter)
|
||||||
|
def get_current_user_from_drf_request(sender, **kwargs):
|
||||||
|
'''
|
||||||
|
Provider a signal handler to return the current user from the current
|
||||||
|
request when using Django REST Framework. Requires that the APIView set
|
||||||
|
drf_request on the underlying Django Request object.
|
||||||
|
'''
|
||||||
|
request = get_current_request()
|
||||||
|
drf_request = getattr(request, 'drf_request', None)
|
||||||
|
return (getattr(drf_request, 'user', False), 0)
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ TEMPLATE_CONTEXT_PROCESSORS += (
|
|||||||
MIDDLEWARE_CLASSES += (
|
MIDDLEWARE_CLASSES += (
|
||||||
'django.middleware.transaction.TransactionMiddleware',
|
'django.middleware.transaction.TransactionMiddleware',
|
||||||
# Middleware loaded after this point will be subject to transactions.
|
# Middleware loaded after this point will be subject to transactions.
|
||||||
'awx.main.middleware.ActivityStreamMiddleware'
|
'awx.main.middleware.ActivityStreamMiddleware',
|
||||||
|
'crum.CurrentRequestUserMiddleware',
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_DIRS = (
|
TEMPLATE_DIRS = (
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ Django>=1.4
|
|||||||
#boto
|
#boto
|
||||||
#django-auth-ldap
|
#django-auth-ldap
|
||||||
#django-celery
|
#django-celery
|
||||||
|
#django-crum
|
||||||
#django-extensions
|
#django-extensions
|
||||||
#django-jsonfield
|
#django-jsonfield
|
||||||
#django-split-settings
|
#django-split-settings
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ Django-1.5.5.tar.gz
|
|||||||
#boto-2.27.0.tar.gz
|
#boto-2.27.0.tar.gz
|
||||||
#django-auth-ldap-1.1.8.tar.gz
|
#django-auth-ldap-1.1.8.tar.gz
|
||||||
#django-celery-3.1.10.tar.gz
|
#django-celery-3.1.10.tar.gz
|
||||||
|
#django-crum-0.6.1.tar.gz
|
||||||
#django-extensions-1.3.3.tar.gz
|
#django-extensions-1.3.3.tar.gz
|
||||||
#django-jsonfield-0.9.12.tar.gz
|
#django-jsonfield-0.9.12.tar.gz
|
||||||
#django_polymorphic-0.5.3.tar.gz
|
#django_polymorphic-0.5.3.tar.gz
|
||||||
|
|||||||
BIN
requirements/django-crum-0.6.1.tar.gz
Normal file
BIN
requirements/django-crum-0.6.1.tar.gz
Normal file
Binary file not shown.
@@ -9,6 +9,7 @@ Django>=1.4
|
|||||||
#boto
|
#boto
|
||||||
#django-auth-ldap
|
#django-auth-ldap
|
||||||
#django-celery
|
#django-celery
|
||||||
|
#django-crum
|
||||||
#django-extensions
|
#django-extensions
|
||||||
#django-jsonfield
|
#django-jsonfield
|
||||||
#django-polymorphic
|
#django-polymorphic
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ Django-1.5.5.tar.gz
|
|||||||
#boto-2.27.0.tar.gz
|
#boto-2.27.0.tar.gz
|
||||||
#django-auth-ldap-1.1.8.tar.gz
|
#django-auth-ldap-1.1.8.tar.gz
|
||||||
#django-celery-3.1.10.tar.gz
|
#django-celery-3.1.10.tar.gz
|
||||||
|
#django-crum-0.6.1.tar.gz
|
||||||
#django-extensions-1.3.3.tar.gz
|
#django-extensions-1.3.3.tar.gz
|
||||||
#django-jsonfield-0.9.12.tar.gz
|
#django-jsonfield-0.9.12.tar.gz
|
||||||
#django_polymorphic-0.5.3.tar.gz
|
#django_polymorphic-0.5.3.tar.gz
|
||||||
|
|||||||
Reference in New Issue
Block a user