Skip to content

Commit

Permalink
feat(projectHistoryLogs): record logs for transfering ownership TASK-…
Browse files Browse the repository at this point in the history
…944 (#5313)

### 📣 Summary
Record project history logs for project ownership transfers.

### 👀 Preview steps


Feature/no-change template:
1. ℹ️ Have at least 2 users and a project
2. Go to Project > Settings > Sharing
3. Transfer ownership to user2
4. Go to `http://localhost/api/v2/audit-logs/?q=log_type:project-history
AND metadata__asset_uid:<asset_uid>&format=json`
6. 🟢 There should be a new log with action="transfer" and the usual
metadata, plus an additional `metadata.username = "user2"` field


### 💭 Notes
This does not rely on the transfer being successful/accepted. We want to
log any attempt to transfer. Canceled requests will be handled in v2.
  • Loading branch information
rgraber authored Dec 3, 2024
1 parent 028afe5 commit 16b2fbc
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 2 deletions.
1 change: 1 addition & 0 deletions kobo/apps/audit_log/audit_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ class AuditAction(models.TextChoices):
UPDATE_NAME = 'update-name'
UPDATE_SETTINGS = 'update-settings'
UPDATE_QA = 'update-qa'
TRANSFER = 'transfer'
32 changes: 32 additions & 0 deletions kobo/apps/audit_log/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
ACCESS_LOG_SUBMISSION_AUTH_TYPE,
ACCESS_LOG_SUBMISSION_GROUP_AUTH_TYPE,
ACCESS_LOG_UNKNOWN_AUTH_TYPE,
ASSET_TYPE_SURVEY,
CLONE_ARG_NAME,
PERM_ADD_SUBMISSIONS,
PERM_VIEW_ASSET,
Expand Down Expand Up @@ -356,6 +357,7 @@ def create_from_request(cls, request):
'asset-permission-assignment-detail': cls.create_from_permissions_request,
'asset-permission-assignment-list': cls.create_from_permissions_request,
'asset-permission-assignment-clone': cls.handle_cloned_permissions,
'project-ownership-invite-list': cls.handle_ownership_transfer,
}
url_name = request.resolver_match.url_name
method = url_name_to_action.get(url_name, None)
Expand Down Expand Up @@ -823,3 +825,33 @@ def handle_cloned_permissions(cls, request):
'cloned_from': request._data[CLONE_ARG_NAME],
},
)

@classmethod
def handle_ownership_transfer(cls, request):
updated_data = getattr(request, 'updated_data')
transfers = updated_data['transfers'].values(
'asset__uid', 'asset__asset_type', 'asset__id'
)
logs = []
for transfer in transfers:
if transfer['asset__asset_type'] != ASSET_TYPE_SURVEY:
continue
logs.append(
ProjectHistoryLog(
object_id=transfer['asset__id'],
action=AuditAction.TRANSFER,
user=request.user,
app_label=Asset._meta.app_label,
model_name=Asset._meta.model_name,
log_type=AuditType.PROJECT_HISTORY,
user_uid=request.user.extra_details.uid,
metadata={
'asset_uid': transfer['asset__uid'],
'log_subtype': PROJECT_HISTORY_LOG_PERMISSION_SUBTYPE,
'ip_address': get_client_ip(request),
'source': get_human_readable_client_user_agent(request),
'username': updated_data['recipient.username'],
},
)
)
ProjectHistoryLog.objects.bulk_create(logs)
58 changes: 58 additions & 0 deletions kobo/apps/audit_log/tests/test_project_history_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from kobo.apps.hook.models import Hook
from kobo.apps.kobo_auth.shortcuts import User
from kpi.constants import (
ASSET_TYPE_TEMPLATE,
CLONE_ARG_NAME,
PERM_ADD_SUBMISSIONS,
PERM_CHANGE_SUBMISSIONS,
Expand Down Expand Up @@ -1302,3 +1303,60 @@ def test_clone_permissions_creates_logs(self):
expected_subtype=PROJECT_HISTORY_LOG_PERMISSION_SUBTYPE,
)
self.assertEqual(log_metadata['cloned_from'], second_asset.uid)

def test_transfer_creates_log(self):
log_metadata = self._base_project_history_log_test(
method=self.client.post,
url=reverse(
'api_v2:project-ownership-invite-list',
),
request_data={
'recipient': reverse(
'api_v2:user-kpi-detail', kwargs={'username': 'someuser'}
),
'assets': [self.asset.uid],
},
expected_action=AuditAction.TRANSFER,
expected_subtype=PROJECT_HISTORY_LOG_PERMISSION_SUBTYPE,
)
self.assertEqual(log_metadata['username'], 'someuser')

def test_transfer_multiple_creates_logs(self):
second_asset = Asset.objects.get(pk=2)
# make admin the owner of the other asset so we can transfer it
second_asset.owner = self.user
second_asset.save()
self.client.post(
path=reverse('api_v2:project-ownership-invite-list'),
data={
'recipient': reverse(
'api_v2:user-kpi-detail', kwargs={'username': 'someuser'}
),
'assets': [self.asset.uid, second_asset.uid],
},
)
self.assertEqual(ProjectHistoryLog.objects.count(), 2)
first_log = ProjectHistoryLog.objects.filter(
metadata__asset_uid=self.asset.uid, action=AuditAction.TRANSFER
)
self.assertTrue(first_log.exists())
second_log = ProjectHistoryLog.objects.filter(
metadata__asset_uid=second_asset.uid, action=AuditAction.TRANSFER
)
self.assertTrue(second_log.exists())

def test_no_log_created_for_non_project_transfer(self):
new_asset = Asset.objects.create(
owner=self.user,
asset_type=ASSET_TYPE_TEMPLATE,
)
self.client.post(
path=reverse('api_v2:project-ownership-invite-list'),
data={
'recipient': reverse(
'api_v2:user-kpi-detail', kwargs={'username': 'someuser'}
),
'assets': [new_asset.uid],
},
)
self.assertEqual(ProjectHistoryLog.objects.count(), 0)
6 changes: 4 additions & 2 deletions kobo/apps/project_ownership/views/invite.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from rest_framework import viewsets

from kpi.permissions import IsAuthenticated
from ...audit_log.base_views import AuditLoggedModelViewSet
from ..filters import InviteFilter
from ..models import Invite
from ..serializers import InviteSerializer


class InviteViewSet(viewsets.ModelViewSet):
class InviteViewSet(AuditLoggedModelViewSet):
"""
## List of invites
Expand Down Expand Up @@ -225,6 +225,8 @@ class InviteViewSet(viewsets.ModelViewSet):
serializer_class = InviteSerializer
permission_classes = (IsAuthenticated,)
filter_backends = (InviteFilter, )
log_type = 'project-history'
logged_fields = ['recipient.username', 'status', 'transfers']

def get_queryset(self):

Expand Down

0 comments on commit 16b2fbc

Please sign in to comment.