api: record actions in journal (#48010)
This commit is contained in:
parent
b7b9a3babb
commit
78b07aa497
|
@ -343,6 +343,7 @@ class PasswordChange(BaseRpcView):
|
|||
def rpc(self, request, serializer):
|
||||
serializer.user.set_password(serializer.validated_data['new_password'])
|
||||
serializer.user.save()
|
||||
request.journal.record('manager.user.password.change', form=serializer, api=True)
|
||||
return {'result': 1}, status.HTTP_200_OK
|
||||
|
||||
|
||||
|
@ -778,8 +779,19 @@ class UsersAPI(api_mixins.GetOrCreateMixinView, HookMixin, ExceptionHandlerMixin
|
|||
if not self.request.user.has_perm(perm):
|
||||
raise PermissionDenied(u'You do not have permission %s' % perm)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
super().perform_create(serializer)
|
||||
self.request.journal.record('manager.user.creation', form=serializer, api=True)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
super().perform_update(serializer)
|
||||
attributes = serializer.validated_data.pop('attributes', {})
|
||||
serializer.validated_data.update(attributes)
|
||||
self.request.journal.record('manager.user.profile.edit', form=serializer, api=True)
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
self.check_perm('custom_user.delete_user', instance.ou)
|
||||
self.request.journal.record('manager.user.deletion', target_user=instance, api=True)
|
||||
super(UsersAPI, self).perform_destroy(instance)
|
||||
|
||||
class SynchronizationSerializer(serializers.Serializer):
|
||||
|
@ -820,6 +832,7 @@ class UsersAPI(api_mixins.GetOrCreateMixinView, HookMixin, ExceptionHandlerMixin
|
|||
)
|
||||
|
||||
utils.send_password_reset_mail(user, request=request)
|
||||
request.journal.record('manager.user.password.reset.request', target_user=user, api=True)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@action(detail=True, methods=['post'], permission_classes=(DjangoPermission('custom_user.change_user'),))
|
||||
|
@ -875,8 +888,17 @@ class RolesAPI(api_mixins.GetOrCreateMixinView, ExceptionHandlerMixin, ModelView
|
|||
def perform_destroy(self, instance):
|
||||
if not self.request.user.has_perm(perm='a2_rbac.delete_role', obj=instance):
|
||||
raise PermissionDenied(u'User %s can\'t create role %s' % (self.request.user, instance))
|
||||
self.request.journal.record('manager.role.deletion', role=instance, api=True)
|
||||
super(RolesAPI, self).perform_destroy(instance)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
super().perform_create(serializer)
|
||||
self.request.journal.record('manager.role.creation', role=serializer.instance, api=True)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
super().perform_update(serializer)
|
||||
self.request.journal.record('manager.role.edit', role=serializer.instance, form=serializer, api=True)
|
||||
|
||||
|
||||
class RolesMembersAPI(UsersAPI):
|
||||
def initial(self, request, *args, **kwargs):
|
||||
|
@ -919,6 +941,7 @@ class RoleMembershipAPI(ExceptionHandlerMixin, APIView):
|
|||
if not request.user.has_perm('a2_rbac.manage_members_role', obj=self.role):
|
||||
raise PermissionDenied(u'User not allowed to manage role members')
|
||||
self.role.members.add(self.member)
|
||||
request.journal.record('manager.role.membership.grant', role=self.role, member=self.member, api=True)
|
||||
return Response(
|
||||
{'result': 1, 'detail': _('User successfully added to role')}, status=status.HTTP_201_CREATED
|
||||
)
|
||||
|
@ -927,6 +950,9 @@ class RoleMembershipAPI(ExceptionHandlerMixin, APIView):
|
|||
if not request.user.has_perm('a2_rbac.manage_members_role', obj=self.role):
|
||||
raise PermissionDenied(u'User not allowed to manage role members')
|
||||
self.role.members.remove(self.member)
|
||||
request.journal.record(
|
||||
'manager.role.membership.removal', role=self.role, member=self.member, api=True
|
||||
)
|
||||
return Response(
|
||||
{'result': 1, 'detail': _('User successfully removed from role')}, status=status.HTTP_200_OK
|
||||
)
|
||||
|
@ -944,7 +970,7 @@ class RoleMembershipsAPI(ExceptionHandlerMixin, APIView):
|
|||
Role = get_role_model()
|
||||
User = get_user_model()
|
||||
self.role = get_object_or_404(Role, uuid=kwargs['role_uuid'])
|
||||
self.members = []
|
||||
self.members = set()
|
||||
|
||||
perm = 'a2_rbac.manage_members_role'
|
||||
authorized = request.user.has_perm(perm, obj=self.role)
|
||||
|
@ -967,7 +993,7 @@ class RoleMembershipsAPI(ExceptionHandlerMixin, APIView):
|
|||
_("Missing 'uuid' key for dict entry %s " "of the 'data' payload") % entry
|
||||
)
|
||||
try:
|
||||
self.members.append(User.objects.get(uuid=uuid))
|
||||
self.members.add(User.objects.get(uuid=uuid))
|
||||
except User.DoesNotExist:
|
||||
raise ValidationError(_('No known user for UUID %s') % entry['uuid'])
|
||||
|
||||
|
@ -976,18 +1002,27 @@ class RoleMembershipsAPI(ExceptionHandlerMixin, APIView):
|
|||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.role.members.add(*self.members)
|
||||
for member in self.members:
|
||||
request.journal.record('manager.role.membership.grant', role=self.role, member=member, api=True)
|
||||
return Response(
|
||||
{'result': 1, 'detail': _('Users successfully added to role')}, status=status.HTTP_201_CREATED
|
||||
)
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
self.role.members.remove(*self.members)
|
||||
for member in self.members:
|
||||
request.journal.record('manager.role.membership.removal', role=self.role, member=member, api=True)
|
||||
return Response(
|
||||
{'result': 1, 'detail': _('Users successfully removed from role')}, status=status.HTTP_200_OK
|
||||
)
|
||||
|
||||
def patch(self, request, *args, **kwargs):
|
||||
old_members = set(self.role.members.all())
|
||||
self.role.members.set(self.members)
|
||||
for member in self.members:
|
||||
request.journal.record('manager.role.membership.grant', role=self.role, member=member, api=True)
|
||||
for member in old_members.difference(self.members):
|
||||
request.journal.record('manager.role.membership.removal', role=self.role, member=member, api=True)
|
||||
return Response(
|
||||
{'result': 1, 'detail': _('Users successfully assigned to role')}, status=status.HTTP_200_OK
|
||||
)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.19 on 2021-05-19 15:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('journal', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='api',
|
||||
field=models.BooleanField(default=False, verbose_name='API'),
|
||||
),
|
||||
]
|
|
@ -86,15 +86,20 @@ class EventTypeDefinition(metaclass=EventTypeDefinitionMeta):
|
|||
retention_days = None
|
||||
|
||||
@classmethod
|
||||
def record(cls, user=None, session=None, references=None, data=None):
|
||||
def record(cls, user=None, session=None, references=None, data=None, api=False):
|
||||
event_type = EventType.objects.get_for_name(cls.name)
|
||||
|
||||
if user and not isinstance(user, User):
|
||||
# API user from DRF or OIDC
|
||||
user = None
|
||||
|
||||
Event.objects.create(
|
||||
type=event_type,
|
||||
user=user,
|
||||
session_id=session and session.session_key,
|
||||
references=references or None, # NULL values take less space
|
||||
data=data or None, # NULL values take less space
|
||||
api=api,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@ -321,6 +326,8 @@ class Event(models.Model):
|
|||
|
||||
data = JSONField(verbose_name=_('data'), null=True)
|
||||
|
||||
api = models.BooleanField(verbose_name=_('API'), default=False)
|
||||
|
||||
objects = EventManager.from_queryset(EventQuerySet)()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
@ -136,3 +136,12 @@ to users with this email address.</tt>.'''
|
|||
You can use <tt>username:john</tt> to find all events related \
|
||||
to users whose username is <tt>john</tt>.'''
|
||||
)
|
||||
|
||||
def search_by_api(self, lexem):
|
||||
yield Q(api=bool(lexem == 'true'))
|
||||
|
||||
search_by_api.documentation = _(
|
||||
'''\
|
||||
You can use <tt>api:true</tt> to find all events related \
|
||||
to API calls.'''
|
||||
)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<tr data-event-id="{{ event.id }}" data-event-cursor="{{ event.cursor }}" data-event-type="{{ event.type.name }}">
|
||||
<td class="journal-list--timestamp-column">{% block event-timestamp %}{{ event.timestamp }}{% endblock %}</td>
|
||||
<td class="journal-list--user-column" {% if event.user %}data-user-id="{{ event.user.id }}"{% endif %}>{% block event-user %}{% firstof event.user.get_full_name event.user "-" %}{% endblock %}</td>
|
||||
<td class="journal-list--session-column">{% block event-session %}{{ event.session_id_shortened|default:"-" }}{% endblock %}</td>
|
||||
<td class="journal-list--session-column">{% block event-session %}{% if event.api %}API{% else %}{{ event.session_id_shortened|default:"-" }}{% endif %}{% endblock %}</td>
|
||||
<td class="journal-list--message-column">{% block event-message %}{{ event.message|default:"-" }}{% endblock %}</td>
|
||||
</tr>
|
||||
{% if forloop.last %}
|
||||
|
|
|
@ -26,6 +26,9 @@ def _json_value(value):
|
|||
|
||||
|
||||
def form_to_old_new(form):
|
||||
if hasattr(form, 'validated_data'):
|
||||
# form is a DRF serializer
|
||||
return {'new': {k: _json_value(v) for k, v in form.validated_data.items()}}
|
||||
old = {}
|
||||
new = {}
|
||||
for key in form.changed_data:
|
||||
|
|
|
@ -42,8 +42,8 @@ class ManagerUserCreation(EventTypeDefinition):
|
|||
label = _('user creation')
|
||||
|
||||
@classmethod
|
||||
def record(cls, user, session, form):
|
||||
super().record(user=user, session=session, references=[form.instance])
|
||||
def record(cls, user, session, form, api=False):
|
||||
super().record(user=user, session=session, references=[form.instance], api=api)
|
||||
|
||||
@classmethod
|
||||
def get_message(cls, event, context):
|
||||
|
@ -62,8 +62,10 @@ class ManagerUserProfileEdit(EventTypeDefinition):
|
|||
label = _('user profile edit')
|
||||
|
||||
@classmethod
|
||||
def record(cls, user, session, form):
|
||||
super().record(user=user, session=session, references=[form.instance], data=form_to_old_new(form))
|
||||
def record(cls, user, session, form, api=False):
|
||||
super().record(
|
||||
user=user, session=session, references=[form.instance], data=form_to_old_new(form), api=api
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_message(cls, event, context):
|
||||
|
@ -107,12 +109,13 @@ class ManagerUserPasswordChange(EventTypeDefinition):
|
|||
label = _('user password change')
|
||||
|
||||
@classmethod
|
||||
def record(cls, user, session, form):
|
||||
def record(cls, user, session, form, api=False):
|
||||
cleaned_data = getattr(form, 'cleaned_data', {})
|
||||
data = {
|
||||
'generate_password': form.cleaned_data['generate_password'],
|
||||
'send_mail': form.cleaned_data['send_mail'],
|
||||
'generate_password': cleaned_data.get('generate_password', False),
|
||||
'send_mail': cleaned_data.get('send_mail', False),
|
||||
}
|
||||
super().record(user=user, session=session, references=[form.instance], data=data)
|
||||
super().record(user=user, session=session, references=[form.instance], data=data, api=api)
|
||||
|
||||
@classmethod
|
||||
def get_message(cls, event, context):
|
||||
|
@ -137,9 +140,9 @@ class ManagerUserPasswordResetRequest(EventTypeDefinition):
|
|||
label = _('user password reset request')
|
||||
|
||||
@classmethod
|
||||
def record(cls, user, session, target_user):
|
||||
def record(cls, user, session, target_user, api=False):
|
||||
super().record(
|
||||
user=user, session=session, references=[target_user], data={'email': target_user.email}
|
||||
user=user, session=session, references=[target_user], data={'email': target_user.email}, api=api
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@ -256,8 +259,8 @@ class ManagerUserDeletion(EventTypeDefinition):
|
|||
label = _('user deletion')
|
||||
|
||||
@classmethod
|
||||
def record(cls, user, session, target_user):
|
||||
super().record(user=user, session=session, references=[target_user])
|
||||
def record(cls, user, session, target_user, api=False):
|
||||
super().record(user=user, session=session, references=[target_user], api=api)
|
||||
|
||||
@classmethod
|
||||
def get_message(cls, event, context):
|
||||
|
@ -296,7 +299,7 @@ class ManagerUserSSOAuthorizationDeletion(EventTypeWithService):
|
|||
|
||||
class RoleEventsMixin(EventTypeDefinition):
|
||||
@classmethod
|
||||
def record(self, user, session, role, references=None, data=None):
|
||||
def record(self, user, role, session=None, references=None, data=None, api=False):
|
||||
references = references or []
|
||||
references = [role] + references
|
||||
data = data or {}
|
||||
|
@ -306,6 +309,7 @@ class RoleEventsMixin(EventTypeDefinition):
|
|||
session=session,
|
||||
references=references,
|
||||
data=data,
|
||||
api=api,
|
||||
)
|
||||
|
||||
|
||||
|
@ -328,8 +332,8 @@ class ManagerRoleEdit(RoleEventsMixin):
|
|||
label = _('role edit')
|
||||
|
||||
@classmethod
|
||||
def record(cls, user, session, role, form):
|
||||
super().record(user=user, session=session, role=role, data=form_to_old_new(form))
|
||||
def record(cls, user, session, role, form, api=False):
|
||||
super().record(user=user, session=session, role=role, data=form_to_old_new(form), api=api)
|
||||
|
||||
@classmethod
|
||||
def get_message(cls, event, context):
|
||||
|
@ -362,9 +366,9 @@ class ManagerRoleMembershipGrant(RoleEventsMixin):
|
|||
label = _('role membership grant')
|
||||
|
||||
@classmethod
|
||||
def record(cls, user, session, role, member):
|
||||
def record(cls, user, session, role, member, api=False):
|
||||
data = {'member_name': member.get_full_name()}
|
||||
super().record(user=user, session=session, role=role, references=[member], data=data)
|
||||
super().record(user=user, session=session, role=role, references=[member], data=data, api=api)
|
||||
|
||||
@classmethod
|
||||
def get_message(cls, event, context):
|
||||
|
@ -384,9 +388,9 @@ class ManagerRoleMembershipRemoval(RoleEventsMixin):
|
|||
label = _('role membership removal')
|
||||
|
||||
@classmethod
|
||||
def record(cls, user, session, role, member):
|
||||
def record(cls, user, session, role, member, api=False):
|
||||
data = {'member_name': member.get_full_name()}
|
||||
super().record(user=user, session=session, role=role, references=[member], data=data)
|
||||
super().record(user=user, session=session, role=role, references=[member], data=data, api=api)
|
||||
|
||||
@classmethod
|
||||
def get_message(cls, event, context):
|
||||
|
|
|
@ -42,7 +42,7 @@ from authentic2.utils import good_next_url
|
|||
from django_rbac.models import SEARCH_OP
|
||||
from django_rbac.utils import get_ou_model, get_role_model
|
||||
|
||||
from .utils import basic_authorization_header, get_link_from_mail, login
|
||||
from .utils import assert_event, basic_authorization_header, get_link_from_mail, login
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
@ -243,6 +243,7 @@ def test_api_users_update_with_email_verified(settings, app, admin, simple_user)
|
|||
user = User.objects.get(id=simple_user.id)
|
||||
assert user.email_verified
|
||||
assert resp.json['email_verified']
|
||||
assert_event('manager.user.profile.edit', user=admin, api=True)
|
||||
|
||||
user.email_verified = True
|
||||
user.email = 'johnny.doeny@foo.bar'
|
||||
|
@ -329,6 +330,7 @@ def test_api_users_create_with_email_verified(settings, app, admin):
|
|||
assert resp.json['email_verified']
|
||||
user = User.objects.get(uuid=resp.json['uuid'])
|
||||
assert user.email_verified
|
||||
assert_event('manager.user.creation', user=admin, api=True)
|
||||
|
||||
|
||||
def test_api_users_create_without_email_verified(settings, app, admin):
|
||||
|
@ -786,6 +788,13 @@ def test_api_role_add_member(app, api_user, role, member):
|
|||
elif authorized:
|
||||
assert resp.json['result'] == 1
|
||||
assert resp.json['detail'] == 'User successfully added to role'
|
||||
assert_event(
|
||||
'manager.role.membership.grant',
|
||||
user=api_user if isinstance(api_user, User) else None,
|
||||
api=True,
|
||||
role_name=role.name,
|
||||
member_name=member.get_full_name(),
|
||||
)
|
||||
else:
|
||||
assert resp.json['result'] == 0
|
||||
assert resp.json['errors'] == 'User not allowed to manage role members'
|
||||
|
@ -812,6 +821,13 @@ def test_api_role_remove_member(app, api_user, role, member):
|
|||
assert resp.json['detail'] == 'User successfully removed from role'
|
||||
resp = app.get('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=404)
|
||||
assert resp.json == {'result': 0, 'errors': {'detail': 'Not found.'}}
|
||||
assert_event(
|
||||
'manager.role.membership.removal',
|
||||
user=api_user if isinstance(api_user, User) else None,
|
||||
api=True,
|
||||
role_name=role.name,
|
||||
member_name=member.get_full_name(),
|
||||
)
|
||||
else:
|
||||
assert resp.json['result'] == 0
|
||||
assert resp.json['errors'] == 'User not allowed to manage role members'
|
||||
|
@ -847,6 +863,13 @@ def test_api_role_add_members(app, api_user, role, member, member_rando2):
|
|||
assert resp.json['detail'] == 'Users successfully added to role'
|
||||
for m in [member, member_rando2]:
|
||||
assert m in role.members.all()
|
||||
assert_event(
|
||||
'manager.role.membership.grant',
|
||||
user=api_user if isinstance(api_user, User) else None,
|
||||
api=True,
|
||||
role_name=role.name,
|
||||
member_name=m.get_full_name(),
|
||||
)
|
||||
else:
|
||||
assert resp.json['result'] == 0
|
||||
assert resp.json['errors'] == 'User not allowed to manage role members'
|
||||
|
@ -882,12 +905,22 @@ def test_api_role_remove_members(app, api_user, role, member, member_rando2):
|
|||
assert resp.json['detail'] == 'Users successfully removed from role'
|
||||
for m in [member, member_rando2]:
|
||||
assert m not in role.members.all()
|
||||
assert_event(
|
||||
'manager.role.membership.removal',
|
||||
user=api_user if isinstance(api_user, User) else None,
|
||||
api=True,
|
||||
role_name=role.name,
|
||||
member_name=m.get_full_name(),
|
||||
)
|
||||
else:
|
||||
assert resp.json['result'] == 0
|
||||
assert resp.json['errors'] == 'User not allowed to manage role members'
|
||||
|
||||
|
||||
def test_api_role_set_members(app, api_user, role, member, member_rando2):
|
||||
def test_api_role_set_members(app, api_user, role, member, member_rando2, ou_rando):
|
||||
user = User.objects.create(
|
||||
username='test3', first_name='test3', last_name='test3', email='test3@test.org', ou=ou_rando
|
||||
)
|
||||
app.authorization = ('Basic', (api_user.username, api_user.username))
|
||||
|
||||
authorized = api_user.has_perm('a2_rbac.manage_members_role', role)
|
||||
|
@ -903,6 +936,7 @@ def test_api_role_set_members(app, api_user, role, member, member_rando2):
|
|||
|
||||
payload = {"data": []}
|
||||
|
||||
role.members.add(user)
|
||||
for m in [member, member_rando2, member_rando2]: # test no duplicate
|
||||
payload['data'].append({"uuid": m.uuid})
|
||||
|
||||
|
@ -918,6 +952,20 @@ def test_api_role_set_members(app, api_user, role, member, member_rando2):
|
|||
assert len(role.members.all()) == 2
|
||||
for m in [member, member_rando2]:
|
||||
assert m in role.members.all()
|
||||
assert_event(
|
||||
'manager.role.membership.grant',
|
||||
user=api_user if isinstance(api_user, User) else None,
|
||||
api=True,
|
||||
role_name=role.name,
|
||||
member_name=m.get_full_name(),
|
||||
)
|
||||
assert_event(
|
||||
'manager.role.membership.removal',
|
||||
user=api_user if isinstance(api_user, User) else None,
|
||||
api=True,
|
||||
role_name=role.name,
|
||||
member_name=user.get_full_name(),
|
||||
)
|
||||
else:
|
||||
assert resp.json['result'] == 0
|
||||
assert resp.json['errors'] == 'User not allowed to manage role members'
|
||||
|
@ -1226,6 +1274,7 @@ def test_password_change(app, ou1, admin):
|
|||
response = app.post_json(url, params=payload)
|
||||
assert response.json['result'] == 1
|
||||
assert User.objects.get(username='john.doe').check_password('password2')
|
||||
assert_event('manager.user.password.change', user=admin, api=True)
|
||||
|
||||
|
||||
def test_password_reset(app, ou1, admin, user_ou1, mailoutbox):
|
||||
|
@ -1247,6 +1296,7 @@ def test_password_reset(app, ou1, admin, user_ou1, mailoutbox):
|
|||
mail = mailoutbox[0]
|
||||
assert mail.to[0] == email
|
||||
assert 'http://testserver/accounts/password/reset/confirm/' in mail.body
|
||||
assert_event('manager.user.password.reset.request', user=admin, api=True)
|
||||
|
||||
|
||||
def test_users_email(app, ou1, admin, user_ou1, mailoutbox):
|
||||
|
@ -1274,6 +1324,7 @@ def test_api_delete_role(app, admin_ou1, role_ou1):
|
|||
app.authorization = ('Basic', (admin_ou1.username, admin_ou1.username))
|
||||
app.delete('/api/roles/{}/'.format(role_ou1.uuid))
|
||||
assert not len(Role.objects.filter(slug='role_ou1'))
|
||||
assert_event('manager.role.deletion', user=admin_ou1, api=True, role_name=role_ou1.name)
|
||||
|
||||
|
||||
def test_api_delete_role_unauthorized(app, simple_user, role_ou1):
|
||||
|
@ -1289,6 +1340,7 @@ def test_api_patch_role(app, admin_ou1, role_ou1):
|
|||
'slug': 'updated-role',
|
||||
}
|
||||
app.patch_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data)
|
||||
assert_event('manager.role.edit', user=admin_ou1, api=True, role_name=role_ou1.name)
|
||||
|
||||
# The role API won't change the organizational unit attribute:
|
||||
role_ou1.refresh_from_db()
|
||||
|
@ -1317,6 +1369,7 @@ def test_api_put_role(app, admin_ou1, role_ou1, ou1):
|
|||
assert role_ou1.name == 'updated-role'
|
||||
assert role_ou1.slug == 'updated-role'
|
||||
assert role_ou1.ou.slug == 'ou1'
|
||||
assert_event('manager.role.edit', user=admin_ou1, api=True, role_name=role_ou1.name)
|
||||
|
||||
|
||||
def test_api_put_role_unauthorized(app, simple_user, role_ou1, ou1):
|
||||
|
@ -1334,6 +1387,7 @@ def test_api_post_role(app, admin_ou1, ou1):
|
|||
|
||||
role_data = {'slug': 'coffee-manager', 'name': 'Coffee Manager', 'ou': 'ou1'}
|
||||
resp = app.post_json('/api/roles/', params=role_data)
|
||||
assert_event('manager.role.creation', user=admin_ou1, api=True, role_name='Coffee Manager')
|
||||
assert isinstance(resp.json, dict)
|
||||
uuid = resp.json['uuid']
|
||||
|
||||
|
@ -1870,12 +1924,14 @@ def test_api_users_required_date_attributes(settings, app, admin, simple_user):
|
|||
]
|
||||
|
||||
# update with values pass
|
||||
del payload['id']
|
||||
payload['prefered_color'] = 'blue'
|
||||
payload['date'] = '1515-1-15'
|
||||
payload['birthdate'] = '1900-2-22'
|
||||
payload['date'] = '1515-01-15'
|
||||
payload['birthdate'] = '1900-02-22'
|
||||
resp = app.put_json(
|
||||
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
|
||||
)
|
||||
assert_event('manager.user.profile.edit', user=admin, api=True, new=payload)
|
||||
|
||||
# value are properly returned on a get
|
||||
resp = app.get('/api/users/{}/'.format(simple_user.uuid), headers=headers, status=200)
|
||||
|
@ -2247,6 +2303,13 @@ def test_api_password_change_user_delete(app, settings, admin, ou1):
|
|||
assert User.objects.get(username='john.doe').check_password('password2')
|
||||
|
||||
|
||||
def test_api_users_delete(settings, app, admin, simple_user):
|
||||
headers = basic_authorization_header(admin)
|
||||
resp = app.delete_json('/api/users/{}/'.format(simple_user.uuid), headers=headers)
|
||||
assert not User.objects.filter(pk=simple_user.pk).exists()
|
||||
assert_event('manager.user.deletion', user=admin, api=True)
|
||||
|
||||
|
||||
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework')
|
||||
def test_api_statistics_list(app, admin):
|
||||
OU = get_ou_model()
|
||||
|
|
|
@ -79,7 +79,7 @@ def events(db, freezer):
|
|||
make("user.login.failure", username="agent")
|
||||
make("user.login", user=user, session=session1, how="password")
|
||||
make("user.password.change", user=user, session=session1)
|
||||
edit_profile_form = mock.Mock()
|
||||
edit_profile_form = mock.Mock(spec=["instance", "initial", "changed_data", "cleaned_data"])
|
||||
edit_profile_form.initial = {'email': "user@example.com", 'first_name': "John"}
|
||||
edit_profile_form.changed_data = ["first_name"]
|
||||
edit_profile_form.cleaned_data = {'first_name': "Jane"}
|
||||
|
@ -1030,6 +1030,15 @@ def test_search(app, superuser, events):
|
|||
for p in zip(pq('tbody td.journal-list--user-column'), pq('tbody td.journal-list--message-column'))
|
||||
] == [['Johnny doe', 'login using password']]
|
||||
|
||||
Event.objects.filter(type__name='manager.user.creation').update(api=True)
|
||||
response.form.set('search', 'api:true')
|
||||
response = response.form.submit()
|
||||
assert (
|
||||
text_content(response.pyquery('tbody tr td.journal-list--message-column')[0]).strip()
|
||||
== 'creation of user "Johnny doe"'
|
||||
)
|
||||
assert text_content(response.pyquery('tbody tr td.journal-list--session-column')[0]).strip() == 'API'
|
||||
|
||||
response.form.set('search', '')
|
||||
response.form['event_type'].select(text='Profile changes')
|
||||
response = response.form.submit()
|
||||
|
|
|
@ -264,8 +264,8 @@ def text_content(node):
|
|||
return ''.join(node.itertext()) if node is not None else ''
|
||||
|
||||
|
||||
def assert_event(event_type_name, user=None, session=None, service=None, target_user=None, **data):
|
||||
qs = Event.objects.filter(type__name=event_type_name)
|
||||
def assert_event(event_type_name, user=None, session=None, service=None, target_user=None, api=False, **data):
|
||||
qs = Event.objects.filter(type__name=event_type_name, api=api)
|
||||
if user:
|
||||
qs = qs.filter(user=user)
|
||||
else:
|
||||
|
@ -281,9 +281,13 @@ def assert_event(event_type_name, user=None, session=None, service=None, target_
|
|||
if target_user:
|
||||
qs = qs.which_references(target_user)
|
||||
|
||||
assert qs.count() == 1
|
||||
count = qs.count()
|
||||
assert count > 0
|
||||
|
||||
if data:
|
||||
if not data:
|
||||
assert count == 1
|
||||
|
||||
if data and count == 1:
|
||||
event = qs.get()
|
||||
assert event.data, 'no event.data, should be %s' % data
|
||||
for key, value in data.items():
|
||||
|
@ -293,6 +297,8 @@ def assert_event(event_type_name, user=None, session=None, service=None, target_
|
|||
event.data.get(key),
|
||||
value,
|
||||
)
|
||||
elif data and count > 1:
|
||||
assert qs.filter(**{'data__' + k: v for k, v in data.items()}).count() == 1
|
||||
|
||||
|
||||
@httmock.HTTMock
|
||||
|
|
Loading…
Reference in New Issue