0001-api-record-actions-in-journal-48010.patch
src/authentic2/api_views.py | ||
---|---|---|
343 | 343 |
def rpc(self, request, serializer): |
344 | 344 |
serializer.user.set_password(serializer.validated_data['new_password']) |
345 | 345 |
serializer.user.save() |
346 |
request.journal.record('manager.user.password.change', form=serializer, api=True) |
|
346 | 347 |
return {'result': 1}, status.HTTP_200_OK |
347 | 348 | |
348 | 349 | |
... | ... | |
778 | 779 |
if not self.request.user.has_perm(perm): |
779 | 780 |
raise PermissionDenied(u'You do not have permission %s' % perm) |
780 | 781 | |
782 |
def perform_create(self, serializer): |
|
783 |
super().perform_create(serializer) |
|
784 |
self.request.journal.record('manager.user.creation', form=serializer, api=True) |
|
785 | ||
786 |
def perform_update(self, serializer): |
|
787 |
super().perform_update(serializer) |
|
788 |
attributes = serializer.validated_data.pop('attributes', {}) |
|
789 |
serializer.validated_data.update(attributes) |
|
790 |
self.request.journal.record('manager.user.profile.edit', form=serializer, api=True) |
|
791 | ||
781 | 792 |
def perform_destroy(self, instance): |
782 | 793 |
self.check_perm('custom_user.delete_user', instance.ou) |
794 |
self.request.journal.record('manager.user.deletion', target_user=instance, api=True) |
|
783 | 795 |
super(UsersAPI, self).perform_destroy(instance) |
784 | 796 | |
785 | 797 |
class SynchronizationSerializer(serializers.Serializer): |
... | ... | |
820 | 832 |
) |
821 | 833 | |
822 | 834 |
utils.send_password_reset_mail(user, request=request) |
835 |
request.journal.record('manager.user.password.reset.request', target_user=user, api=True) |
|
823 | 836 |
return Response(status=status.HTTP_204_NO_CONTENT) |
824 | 837 | |
825 | 838 |
@action(detail=True, methods=['post'], permission_classes=(DjangoPermission('custom_user.change_user'),)) |
... | ... | |
875 | 888 |
def perform_destroy(self, instance): |
876 | 889 |
if not self.request.user.has_perm(perm='a2_rbac.delete_role', obj=instance): |
877 | 890 |
raise PermissionDenied(u'User %s can\'t create role %s' % (self.request.user, instance)) |
891 |
self.request.journal.record('manager.role.deletion', role=instance, api=True) |
|
878 | 892 |
super(RolesAPI, self).perform_destroy(instance) |
879 | 893 | |
894 |
def perform_create(self, serializer): |
|
895 |
super().perform_create(serializer) |
|
896 |
self.request.journal.record('manager.role.creation', role=serializer.instance, api=True) |
|
897 | ||
898 |
def perform_update(self, serializer): |
|
899 |
super().perform_update(serializer) |
|
900 |
self.request.journal.record('manager.role.edit', role=serializer.instance, form=serializer, api=True) |
|
901 | ||
880 | 902 | |
881 | 903 |
class RolesMembersAPI(UsersAPI): |
882 | 904 |
def initial(self, request, *args, **kwargs): |
... | ... | |
919 | 941 |
if not request.user.has_perm('a2_rbac.manage_members_role', obj=self.role): |
920 | 942 |
raise PermissionDenied(u'User not allowed to manage role members') |
921 | 943 |
self.role.members.add(self.member) |
944 |
request.journal.record('manager.role.membership.grant', role=self.role, member=self.member, api=True) |
|
922 | 945 |
return Response( |
923 | 946 |
{'result': 1, 'detail': _('User successfully added to role')}, status=status.HTTP_201_CREATED |
924 | 947 |
) |
... | ... | |
927 | 950 |
if not request.user.has_perm('a2_rbac.manage_members_role', obj=self.role): |
928 | 951 |
raise PermissionDenied(u'User not allowed to manage role members') |
929 | 952 |
self.role.members.remove(self.member) |
953 |
request.journal.record( |
|
954 |
'manager.role.membership.removal', role=self.role, member=self.member, api=True |
|
955 |
) |
|
930 | 956 |
return Response( |
931 | 957 |
{'result': 1, 'detail': _('User successfully removed from role')}, status=status.HTTP_200_OK |
932 | 958 |
) |
... | ... | |
944 | 970 |
Role = get_role_model() |
945 | 971 |
User = get_user_model() |
946 | 972 |
self.role = get_object_or_404(Role, uuid=kwargs['role_uuid']) |
947 |
self.members = []
|
|
973 |
self.members = set()
|
|
948 | 974 | |
949 | 975 |
perm = 'a2_rbac.manage_members_role' |
950 | 976 |
authorized = request.user.has_perm(perm, obj=self.role) |
... | ... | |
967 | 993 |
_("Missing 'uuid' key for dict entry %s " "of the 'data' payload") % entry |
968 | 994 |
) |
969 | 995 |
try: |
970 |
self.members.append(User.objects.get(uuid=uuid))
|
|
996 |
self.members.add(User.objects.get(uuid=uuid))
|
|
971 | 997 |
except User.DoesNotExist: |
972 | 998 |
raise ValidationError(_('No known user for UUID %s') % entry['uuid']) |
973 | 999 | |
... | ... | |
976 | 1002 | |
977 | 1003 |
def post(self, request, *args, **kwargs): |
978 | 1004 |
self.role.members.add(*self.members) |
1005 |
for member in self.members: |
|
1006 |
request.journal.record('manager.role.membership.grant', role=self.role, member=member, api=True) |
|
979 | 1007 |
return Response( |
980 | 1008 |
{'result': 1, 'detail': _('Users successfully added to role')}, status=status.HTTP_201_CREATED |
981 | 1009 |
) |
982 | 1010 | |
983 | 1011 |
def delete(self, request, *args, **kwargs): |
984 | 1012 |
self.role.members.remove(*self.members) |
1013 |
for member in self.members: |
|
1014 |
request.journal.record('manager.role.membership.removal', role=self.role, member=member, api=True) |
|
985 | 1015 |
return Response( |
986 | 1016 |
{'result': 1, 'detail': _('Users successfully removed from role')}, status=status.HTTP_200_OK |
987 | 1017 |
) |
988 | 1018 | |
989 | 1019 |
def patch(self, request, *args, **kwargs): |
1020 |
old_members = set(self.role.members.all()) |
|
990 | 1021 |
self.role.members.set(self.members) |
1022 |
for member in self.members: |
|
1023 |
request.journal.record('manager.role.membership.grant', role=self.role, member=member, api=True) |
|
1024 |
for member in old_members.difference(self.members): |
|
1025 |
request.journal.record('manager.role.membership.removal', role=self.role, member=member, api=True) |
|
991 | 1026 |
return Response( |
992 | 1027 |
{'result': 1, 'detail': _('Users successfully assigned to role')}, status=status.HTTP_200_OK |
993 | 1028 |
) |
src/authentic2/apps/journal/migrations/0002_event_api.py | ||
---|---|---|
1 |
# Generated by Django 2.2.19 on 2021-05-19 15:25 |
|
2 | ||
3 |
from django.db import migrations, models |
|
4 | ||
5 | ||
6 |
class Migration(migrations.Migration): |
|
7 | ||
8 |
dependencies = [ |
|
9 |
('journal', '0001_initial'), |
|
10 |
] |
|
11 | ||
12 |
operations = [ |
|
13 |
migrations.AddField( |
|
14 |
model_name='event', |
|
15 |
name='api', |
|
16 |
field=models.BooleanField(default=False, verbose_name='API'), |
|
17 |
), |
|
18 |
] |
src/authentic2/apps/journal/models.py | ||
---|---|---|
85 | 85 |
retention_days = None |
86 | 86 | |
87 | 87 |
@classmethod |
88 |
def record(cls, user=None, session=None, references=None, data=None): |
|
88 |
def record(cls, user=None, session=None, references=None, data=None, api=False):
|
|
89 | 89 |
event_type = EventType.objects.get_for_name(cls.name) |
90 | 90 | |
91 |
if user and not isinstance(user, User): |
|
92 |
# API user from DRF or OIDC |
|
93 |
user = None |
|
94 | ||
91 | 95 |
Event.objects.create( |
92 | 96 |
type=event_type, |
93 | 97 |
user=user, |
94 | 98 |
session_id=session and session.session_key, |
95 | 99 |
references=references or None, # NULL values take less space |
96 | 100 |
data=data or None, # NULL values take less space |
101 |
api=api, |
|
97 | 102 |
) |
98 | 103 | |
99 | 104 |
@classmethod |
... | ... | |
320 | 325 | |
321 | 326 |
data = JSONField(verbose_name=_('data'), null=True) |
322 | 327 | |
328 |
api = models.BooleanField(verbose_name=_('API'), default=False) |
|
329 | ||
323 | 330 |
objects = EventManager.from_queryset(EventQuerySet)() |
324 | 331 | |
325 | 332 |
def __init__(self, *args, **kwargs): |
src/authentic2/apps/journal/search_engine.py | ||
---|---|---|
136 | 136 |
You can use <tt>username:john</tt> to find all events related \ |
137 | 137 |
to users whose username is <tt>john</tt>.''' |
138 | 138 |
) |
139 | ||
140 |
def search_by_api(self, lexem): |
|
141 |
yield Q(api=bool(lexem == 'true')) |
|
142 | ||
143 |
search_by_api.documentation = _( |
|
144 |
'''\ |
|
145 |
You can use <tt>api:true</tt> to find all events related \ |
|
146 |
to API calls.''' |
|
147 |
) |
src/authentic2/apps/journal/templates/journal/event_list.html | ||
---|---|---|
16 | 16 |
<tr data-event-id="{{ event.id }}" data-event-cursor="{{ event.cursor }}" data-event-type="{{ event.type.name }}"> |
17 | 17 |
<td class="journal-list--timestamp-column">{% block event-timestamp %}{{ event.timestamp }}{% endblock %}</td> |
18 | 18 |
<td class="journal-list--user-column" {% if event.user %}data-user-id="{{ event.user.id }}"{% endif %}>{% block event-user %}{{ event.user.get_full_name|default:"-" }}{% endblock %}</td> |
19 |
<td class="journal-list--session-column">{% block event-session %}{{ event.session_id_shortened|default:"-" }}{% endblock %}</td>
|
|
19 |
<td class="journal-list--session-column">{% block event-session %}{% if event.api %}API{% else %}{{ event.session_id_shortened|default:"-" }}{% endif %}{% endblock %}</td>
|
|
20 | 20 |
<td class="journal-list--message-column">{% block event-message %}{{ event.message|default:"-" }}{% endblock %}</td> |
21 | 21 |
</tr> |
22 | 22 |
{% if forloop.last %} |
src/authentic2/apps/journal/utils.py | ||
---|---|---|
26 | 26 | |
27 | 27 | |
28 | 28 |
def form_to_old_new(form): |
29 |
if hasattr(form, 'validated_data'): |
|
30 |
# form is a DRF serializer |
|
31 |
return {'new': {k: _json_value(v) for k, v in form.validated_data.items()}} |
|
29 | 32 |
old = {} |
30 | 33 |
new = {} |
31 | 34 |
for key in form.changed_data: |
src/authentic2/manager/journal_event_types.py | ||
---|---|---|
31 | 31 |
label = _('user creation') |
32 | 32 | |
33 | 33 |
@classmethod |
34 |
def record(cls, user, session, form): |
|
35 |
super().record(user=user, session=session, references=[form.instance]) |
|
34 |
def record(cls, user, session, form, api=False):
|
|
35 |
super().record(user=user, session=session, references=[form.instance], api=api)
|
|
36 | 36 | |
37 | 37 |
@classmethod |
38 | 38 |
def get_message(cls, event, context): |
... | ... | |
51 | 51 |
label = _('user profile edit') |
52 | 52 | |
53 | 53 |
@classmethod |
54 |
def record(cls, user, session, form): |
|
55 |
super().record(user=user, session=session, references=[form.instance], data=form_to_old_new(form)) |
|
54 |
def record(cls, user, session, form, api=False): |
|
55 |
if hasattr(form, 'validated_data'): |
|
56 |
attributes = form.validated_data.pop('attributes', {}) |
|
57 |
form.validated_data.update(attributes) |
|
58 |
super().record( |
|
59 |
user=user, session=session, references=[form.instance], data=form_to_old_new(form), api=api |
|
60 |
) |
|
56 | 61 | |
57 | 62 |
@classmethod |
58 | 63 |
def get_message(cls, event, context): |
... | ... | |
96 | 101 |
label = _('user password change') |
97 | 102 | |
98 | 103 |
@classmethod |
99 |
def record(cls, user, session, form): |
|
104 |
def record(cls, user, session, form, api=False): |
|
105 |
cleaned_data = getattr(form, 'cleaned_data', {}) |
|
100 | 106 |
data = { |
101 |
'generate_password': form.cleaned_data['generate_password'],
|
|
102 |
'send_mail': form.cleaned_data['send_mail'],
|
|
107 |
'generate_password': cleaned_data.get('generate_password', False),
|
|
108 |
'send_mail': cleaned_data.get('send_mail', False),
|
|
103 | 109 |
} |
104 |
super().record(user=user, session=session, references=[form.instance], data=data) |
|
110 |
super().record(user=user, session=session, references=[form.instance], data=data, api=api)
|
|
105 | 111 | |
106 | 112 |
@classmethod |
107 | 113 |
def get_message(cls, event, context): |
... | ... | |
126 | 132 |
label = _('user password reset request') |
127 | 133 | |
128 | 134 |
@classmethod |
129 |
def record(cls, user, session, target_user): |
|
135 |
def record(cls, user, session, target_user, api=False):
|
|
130 | 136 |
super().record( |
131 |
user=user, session=session, references=[target_user], data={'email': target_user.email} |
|
137 |
user=user, session=session, references=[target_user], data={'email': target_user.email}, api=api
|
|
132 | 138 |
) |
133 | 139 | |
134 | 140 |
@classmethod |
... | ... | |
219 | 225 |
label = _('user deletion') |
220 | 226 | |
221 | 227 |
@classmethod |
222 |
def record(cls, user, session, target_user): |
|
223 |
super().record(user=user, session=session, references=[target_user]) |
|
228 |
def record(cls, user, session, target_user, api=False):
|
|
229 |
super().record(user=user, session=session, references=[target_user], api=api)
|
|
224 | 230 | |
225 | 231 |
@classmethod |
226 | 232 |
def get_message(cls, event, context): |
... | ... | |
259 | 265 | |
260 | 266 |
class RoleEventsMixin(EventTypeDefinition): |
261 | 267 |
@classmethod |
262 |
def record(self, user, session, role, references=None, data=None):
|
|
268 |
def record(self, user, role, session=None, references=None, data=None, api=False):
|
|
263 | 269 |
references = references or [] |
264 | 270 |
references = [role] + references |
265 | 271 |
data = data or {} |
... | ... | |
269 | 275 |
session=session, |
270 | 276 |
references=references, |
271 | 277 |
data=data, |
278 |
api=api, |
|
272 | 279 |
) |
273 | 280 | |
274 | 281 | |
... | ... | |
291 | 298 |
label = _('role edit') |
292 | 299 | |
293 | 300 |
@classmethod |
294 |
def record(cls, user, session, role, form): |
|
295 |
super().record(user=user, session=session, role=role, data=form_to_old_new(form)) |
|
301 |
def record(cls, user, session, role, form, api=False):
|
|
302 |
super().record(user=user, session=session, role=role, data=form_to_old_new(form), api=api)
|
|
296 | 303 | |
297 | 304 |
@classmethod |
298 | 305 |
def get_message(cls, event, context): |
... | ... | |
325 | 332 |
label = _('role membership grant') |
326 | 333 | |
327 | 334 |
@classmethod |
328 |
def record(cls, user, session, role, member): |
|
335 |
def record(cls, user, session, role, member, api=False):
|
|
329 | 336 |
data = {'member_name': member.get_full_name()} |
330 |
super().record(user=user, session=session, role=role, references=[member], data=data) |
|
337 |
super().record(user=user, session=session, role=role, references=[member], data=data, api=api)
|
|
331 | 338 | |
332 | 339 |
@classmethod |
333 | 340 |
def get_message(cls, event, context): |
... | ... | |
347 | 354 |
label = _('role membership removal') |
348 | 355 | |
349 | 356 |
@classmethod |
350 |
def record(cls, user, session, role, member): |
|
357 |
def record(cls, user, session, role, member, api=False):
|
|
351 | 358 |
data = {'member_name': member.get_full_name()} |
352 |
super().record(user=user, session=session, role=role, references=[member], data=data) |
|
359 |
super().record(user=user, session=session, role=role, references=[member], data=data, api=api)
|
|
353 | 360 | |
354 | 361 |
@classmethod |
355 | 362 |
def get_message(cls, event, context): |
tests/test_api.py | ||
---|---|---|
42 | 42 |
from django_rbac.models import SEARCH_OP |
43 | 43 |
from django_rbac.utils import get_ou_model, get_role_model |
44 | 44 | |
45 |
from .utils import basic_authorization_header, get_link_from_mail, login |
|
45 |
from .utils import assert_event, basic_authorization_header, get_link_from_mail, login
|
|
46 | 46 | |
47 | 47 |
pytestmark = pytest.mark.django_db |
48 | 48 | |
... | ... | |
218 | 218 |
user = User.objects.get(id=simple_user.id) |
219 | 219 |
assert user.email_verified |
220 | 220 |
assert resp.json['email_verified'] |
221 |
assert_event('manager.user.profile.edit', user=admin, api=True) |
|
221 | 222 | |
222 | 223 |
user.email_verified = True |
223 | 224 |
user.email = 'johnny.doeny@foo.bar' |
... | ... | |
304 | 305 |
assert resp.json['email_verified'] |
305 | 306 |
user = User.objects.get(uuid=resp.json['uuid']) |
306 | 307 |
assert user.email_verified |
308 |
assert_event('manager.user.creation', user=admin, api=True) |
|
307 | 309 | |
308 | 310 | |
309 | 311 |
def test_api_users_create_without_email_verified(settings, app, admin): |
... | ... | |
867 | 869 |
elif authorized: |
868 | 870 |
assert resp.json['result'] == 1 |
869 | 871 |
assert resp.json['detail'] == 'User successfully added to role' |
872 |
assert_event( |
|
873 |
'manager.role.membership.grant', |
|
874 |
user=api_user if isinstance(api_user, User) else None, |
|
875 |
api=True, |
|
876 |
role_name=role.name, |
|
877 |
member_name=member.get_full_name(), |
|
878 |
) |
|
870 | 879 |
else: |
871 | 880 |
assert resp.json['result'] == 0 |
872 | 881 |
assert resp.json['errors'] == 'User not allowed to manage role members' |
... | ... | |
893 | 902 |
assert resp.json['detail'] == 'User successfully removed from role' |
894 | 903 |
resp = app.get('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=404) |
895 | 904 |
assert resp.json == {'result': 0, 'errors': {'detail': 'Not found.'}} |
905 |
assert_event( |
|
906 |
'manager.role.membership.removal', |
|
907 |
user=api_user if isinstance(api_user, User) else None, |
|
908 |
api=True, |
|
909 |
role_name=role.name, |
|
910 |
member_name=member.get_full_name(), |
|
911 |
) |
|
896 | 912 |
else: |
897 | 913 |
assert resp.json['result'] == 0 |
898 | 914 |
assert resp.json['errors'] == 'User not allowed to manage role members' |
... | ... | |
928 | 944 |
assert resp.json['detail'] == 'Users successfully added to role' |
929 | 945 |
for m in [member, member_rando2]: |
930 | 946 |
assert m in role.members.all() |
947 |
assert_event( |
|
948 |
'manager.role.membership.grant', |
|
949 |
user=api_user if isinstance(api_user, User) else None, |
|
950 |
api=True, |
|
951 |
role_name=role.name, |
|
952 |
member_name=m.get_full_name(), |
|
953 |
) |
|
931 | 954 |
else: |
932 | 955 |
assert resp.json['result'] == 0 |
933 | 956 |
assert resp.json['errors'] == 'User not allowed to manage role members' |
... | ... | |
963 | 986 |
assert resp.json['detail'] == 'Users successfully removed from role' |
964 | 987 |
for m in [member, member_rando2]: |
965 | 988 |
assert m not in role.members.all() |
989 |
assert_event( |
|
990 |
'manager.role.membership.removal', |
|
991 |
user=api_user if isinstance(api_user, User) else None, |
|
992 |
api=True, |
|
993 |
role_name=role.name, |
|
994 |
member_name=m.get_full_name(), |
|
995 |
) |
|
966 | 996 |
else: |
967 | 997 |
assert resp.json['result'] == 0 |
968 | 998 |
assert resp.json['errors'] == 'User not allowed to manage role members' |
969 | 999 | |
970 | 1000 | |
971 |
def test_api_role_set_members(app, api_user, role, member, member_rando2): |
|
1001 |
def test_api_role_set_members(app, api_user, role, member, member_rando2, ou_rando): |
|
1002 |
user = User.objects.create( |
|
1003 |
username='test3', first_name='test3', last_name='test3', email='test3@test.org', ou=ou_rando |
|
1004 |
) |
|
972 | 1005 |
app.authorization = ('Basic', (api_user.username, api_user.username)) |
973 | 1006 | |
974 | 1007 |
authorized = api_user.has_perm('a2_rbac.manage_members_role', role) |
... | ... | |
984 | 1017 | |
985 | 1018 |
payload = {"data": []} |
986 | 1019 | |
1020 |
role.members.add(user) |
|
987 | 1021 |
for m in [member, member_rando2, member_rando2]: # test no duplicate |
988 | 1022 |
payload['data'].append({"uuid": m.uuid}) |
989 | 1023 | |
... | ... | |
999 | 1033 |
assert len(role.members.all()) == 2 |
1000 | 1034 |
for m in [member, member_rando2]: |
1001 | 1035 |
assert m in role.members.all() |
1036 |
assert_event( |
|
1037 |
'manager.role.membership.grant', |
|
1038 |
user=api_user if isinstance(api_user, User) else None, |
|
1039 |
api=True, |
|
1040 |
role_name=role.name, |
|
1041 |
member_name=m.get_full_name(), |
|
1042 |
) |
|
1043 |
assert_event( |
|
1044 |
'manager.role.membership.removal', |
|
1045 |
user=api_user if isinstance(api_user, User) else None, |
|
1046 |
api=True, |
|
1047 |
role_name=role.name, |
|
1048 |
member_name=user.get_full_name(), |
|
1049 |
) |
|
1002 | 1050 |
else: |
1003 | 1051 |
assert resp.json['result'] == 0 |
1004 | 1052 |
assert resp.json['errors'] == 'User not allowed to manage role members' |
... | ... | |
1307 | 1355 |
response = app.post_json(url, params=payload) |
1308 | 1356 |
assert response.json['result'] == 1 |
1309 | 1357 |
assert User.objects.get(username='john.doe').check_password('password2') |
1358 |
assert_event('manager.user.password.change', user=admin, api=True) |
|
1310 | 1359 | |
1311 | 1360 | |
1312 | 1361 |
def test_password_reset(app, ou1, admin, user_ou1, mailoutbox): |
... | ... | |
1328 | 1377 |
mail = mailoutbox[0] |
1329 | 1378 |
assert mail.to[0] == email |
1330 | 1379 |
assert 'http://testserver/accounts/password/reset/confirm/' in mail.body |
1380 |
assert_event('manager.user.password.reset.request', user=admin, api=True) |
|
1331 | 1381 | |
1332 | 1382 | |
1333 | 1383 |
def test_users_email(app, ou1, admin, user_ou1, mailoutbox): |
... | ... | |
1355 | 1405 |
app.authorization = ('Basic', (admin_ou1.username, admin_ou1.username)) |
1356 | 1406 |
app.delete('/api/roles/{}/'.format(role_ou1.uuid)) |
1357 | 1407 |
assert not len(Role.objects.filter(slug='role_ou1')) |
1408 |
assert_event('manager.role.deletion', user=admin_ou1, api=True, role_name=role_ou1.name) |
|
1358 | 1409 | |
1359 | 1410 | |
1360 | 1411 |
def test_api_delete_role_unauthorized(app, simple_user, role_ou1): |
... | ... | |
1370 | 1421 |
'slug': 'updated-role', |
1371 | 1422 |
} |
1372 | 1423 |
app.patch_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data) |
1424 |
assert_event('manager.role.edit', user=admin_ou1, api=True, role_name=role_ou1.name) |
|
1373 | 1425 | |
1374 | 1426 |
# The role API won't change the organizational unit attribute: |
1375 | 1427 |
role_ou1.refresh_from_db() |
... | ... | |
1398 | 1450 |
assert role_ou1.name == 'updated-role' |
1399 | 1451 |
assert role_ou1.slug == 'updated-role' |
1400 | 1452 |
assert role_ou1.ou.slug == 'ou1' |
1453 |
assert_event('manager.role.edit', user=admin_ou1, api=True, role_name=role_ou1.name) |
|
1401 | 1454 | |
1402 | 1455 | |
1403 | 1456 |
def test_api_put_role_unauthorized(app, simple_user, role_ou1, ou1): |
... | ... | |
1415 | 1468 | |
1416 | 1469 |
role_data = {'slug': 'coffee-manager', 'name': 'Coffee Manager', 'ou': 'ou1'} |
1417 | 1470 |
resp = app.post_json('/api/roles/', params=role_data) |
1471 |
assert_event('manager.role.creation', user=admin_ou1, api=True, role_name='Coffee Manager') |
|
1418 | 1472 |
assert isinstance(resp.json, dict) |
1419 | 1473 |
uuid = resp.json['uuid'] |
1420 | 1474 | |
... | ... | |
1978 | 2032 |
] |
1979 | 2033 | |
1980 | 2034 |
# update with values pass |
2035 |
del payload['id'] |
|
1981 | 2036 |
payload['prefered_color'] = 'blue' |
1982 |
payload['date'] = '1515-1-15' |
|
1983 |
payload['birthdate'] = '1900-2-22' |
|
2037 |
payload['date'] = '1515-01-15'
|
|
2038 |
payload['birthdate'] = '1900-02-22'
|
|
1984 | 2039 |
resp = app.put_json( |
1985 | 2040 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
1986 | 2041 |
) |
2042 |
assert_event('manager.user.profile.edit', user=admin, api=True, new=payload) |
|
1987 | 2043 | |
1988 | 2044 |
# value are properly returned on a get |
1989 | 2045 |
resp = app.get('/api/users/{}/'.format(simple_user.uuid), headers=headers, status=200) |
... | ... | |
2355 | 2411 |
assert User.objects.get(username='john.doe').check_password('password2') |
2356 | 2412 | |
2357 | 2413 | |
2414 |
def test_api_users_delete(settings, app, admin, simple_user): |
|
2415 |
headers = basic_authorization_header(admin) |
|
2416 |
resp = app.delete_json('/api/users/{}/'.format(simple_user.uuid), headers=headers) |
|
2417 |
assert not User.objects.filter(pk=simple_user.pk).exists() |
|
2418 |
assert_event('manager.user.deletion', user=admin, api=True) |
|
2419 | ||
2420 | ||
2358 | 2421 |
@pytest.mark.skipif(drf_version.startswith('3.4'), reason='no support for old django rest framework') |
2359 | 2422 |
def test_api_statistics_list(app, admin): |
2360 | 2423 |
OU = get_ou_model() |
tests/test_manager_journal.py | ||
---|---|---|
79 | 79 |
make("user.login.failure", username="agent") |
80 | 80 |
make("user.login", user=user, session=session1, how="password") |
81 | 81 |
make("user.password.change", user=user, session=session1) |
82 |
edit_profile_form = mock.Mock() |
|
82 |
edit_profile_form = mock.Mock(spec=["instance", "initial", "changed_data", "cleaned_data"])
|
|
83 | 83 |
edit_profile_form.initial = {'email': "user@example.com", 'first_name': "John"} |
84 | 84 |
edit_profile_form.changed_data = ["first_name"] |
85 | 85 |
edit_profile_form.cleaned_data = {'first_name': "Jane"} |
... | ... | |
973 | 973 |
for p in zip(pq('tbody td.journal-list--user-column'), pq('tbody td.journal-list--message-column')) |
974 | 974 |
] == [['Johnny doe', 'login using password']] |
975 | 975 | |
976 |
Event.objects.filter(type__name='manager.user.creation').update(api=True) |
|
977 |
response.form.set('search', 'api:true') |
|
978 |
response = response.form.submit() |
|
979 |
assert ( |
|
980 |
text_content(response.pyquery('tbody tr td.journal-list--message-column')[0]).strip() |
|
981 |
== 'creation of user "Johnny doe"' |
|
982 |
) |
|
983 |
assert text_content(response.pyquery('tbody tr td.journal-list--session-column')[0]).strip() == 'API' |
|
984 | ||
976 | 985 |
response.form.set('search', '') |
977 | 986 |
response.form['event_type'].select(text='Profile changes') |
978 | 987 |
response = response.form.submit() |
tests/utils.py | ||
---|---|---|
264 | 264 |
return ''.join(node.itertext()) if node is not None else '' |
265 | 265 | |
266 | 266 | |
267 |
def assert_event(event_type_name, user=None, session=None, service=None, **data): |
|
268 |
qs = Event.objects.filter(type__name=event_type_name) |
|
267 |
def assert_event(event_type_name, user=None, session=None, service=None, api=False, **data):
|
|
268 |
qs = Event.objects.filter(type__name=event_type_name, api=api)
|
|
269 | 269 |
if user: |
270 | 270 |
qs = qs.filter(user=user) |
271 | 271 |
else: |
... | ... | |
279 | 279 |
else: |
280 | 280 |
qs = qs.exclude(qs._which_references_query(models.Service)) |
281 | 281 | |
282 |
assert qs.count() == 1 |
|
282 |
count = qs.count() |
|
283 |
assert count > 0 |
|
283 | 284 | |
284 |
if data: |
|
285 |
if not data: |
|
286 |
assert count == 1 |
|
287 | ||
288 |
if data and count == 1: |
|
285 | 289 |
event = qs.get() |
286 | 290 |
assert event.data, 'no event.data, should be %s' % data |
287 | 291 |
for key, value in data.items(): |
... | ... | |
291 | 295 |
event.data.get(key), |
292 | 296 |
value, |
293 | 297 |
) |
298 |
elif data and count > 1: |
|
299 |
assert qs.filter(**{'data__' + k: v for k, v in data.items()}).count() == 1 |
|
294 | 300 | |
295 | 301 | |
296 | 302 |
@httmock.HTTMock |
297 |
- |