Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(accessLogsExport): create new endpoints TASK-1147  #5304

Merged
merged 34 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
09373fb
add AccessLogExportTask class, refactored Project View exports to cre…
RuthShryock Nov 5, 2024
4079ea0
revert to before Submissions name change
RuthShryock Nov 14, 2024
eb67d2b
:This reverts commit 4079ea05a8eed915ad74143a43c7be665b70e6a8.
RuthShryock Nov 14, 2024
0f9ac39
Merge branch 'main' of github.com:kobotoolbox/kpi into access-log-exp…
RuthShryock Nov 14, 2024
2836ea3
fix circular import error
RuthShryock Nov 14, 2024
b69a006
fix formatting
RuthShryock Nov 14, 2024
04dc2cd
rename ExportTaskBase, ExportTask, and SynchronousExport to have Subm…
RuthShryock Nov 15, 2024
4c46fb0
fix formatting
RuthShryock Nov 15, 2024
de7f7f5
Merge branch 'main' of github.com:kobotoolbox/kpi into access-log-exp…
RuthShryock Nov 20, 2024
ff45ba8
fix migration error by creating common export tasks for each project …
RuthShryock Nov 20, 2024
7837192
fix formatting
RuthShryock Nov 20, 2024
6c60768
simplify refactor with ExportTaskMixin and adding get_data and defaul…
RuthShryock Nov 26, 2024
43ce879
updating branch with main
RuthShryock Nov 26, 2024
a0a2d5e
add access log export endpoints and tests
RuthShryock Nov 26, 2024
bd5c994
rename functions and variables, fix grammar, and allow for views to b…
RuthShryock Nov 27, 2024
91fefc7
Merge branch 'main' of github.com:kobotoolbox/kpi into endpoints-for-…
RuthShryock Nov 27, 2024
0640937
Merge branch 'access-log-export-task-class' of github.com:kobotoolbox…
RuthShryock Nov 27, 2024
cd25b98
remove view from data for access log exports
RuthShryock Nov 27, 2024
6c3e3af
Revert "refactor(organizations): add of useSession hook TASK-1305 (#…
RuthShryock Nov 27, 2024
dd5650d
Revert "feat(InlineMessage): add new type TASK-987 (#5305)"
RuthShryock Nov 27, 2024
cd35d96
Merge branch 'main' into endpoints-for-access-logs-export
RuthShryock Dec 2, 2024
039063b
Reapply "refactor(organizations): add of useSession hook TASK-1305 (…
RuthShryock Dec 2, 2024
33e1c0a
Reapply "feat(InlineMessage): add new type TASK-987 (#5305)"
RuthShryock Dec 2, 2024
6ca21ec
refactor to include two endpoints, add documentation, return a list o…
RuthShryock Dec 3, 2024
13d31b2
Merge branch 'main' of github.com:kobotoolbox/kpi into endpoints-for-…
RuthShryock Dec 3, 2024
fee5f37
fix formatting
RuthShryock Dec 3, 2024
6eac898
fix tests
RuthShryock Dec 3, 2024
189a860
fix failing tests
RuthShryock Dec 4, 2024
1d41380
Update kobo/apps/audit_log/views.py
RuthShryock Dec 4, 2024
c9cbb7e
Update kobo/apps/audit_log/views.py
RuthShryock Dec 4, 2024
8d8f763
Update kobo/apps/audit_log/views.py
RuthShryock Dec 4, 2024
7f88c37
check get_all_logs in tests and fix formatting
RuthShryock Dec 4, 2024
0383afb
fix error messages to apply to access logs
RuthShryock Dec 4, 2024
350c22e
fix assert statments in test cases
RuthShryock Dec 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 179 additions & 5 deletions kobo/apps/audit_log/tests/api/v2/test_api_audit_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@
from rest_framework.reverse import reverse

from kobo.apps.audit_log.audit_actions import AuditAction
from kobo.apps.audit_log.models import (
AccessLog,
AuditLog,
AuditType,
)
from kobo.apps.audit_log.models import AccessLog, AuditLog, AuditType
from kobo.apps.audit_log.tests.test_signals import skip_login_access_log
from kobo.apps.kobo_auth.shortcuts import User
from kpi.constants import (
ACCESS_LOG_SUBMISSION_AUTH_TYPE,
ACCESS_LOG_SUBMISSION_GROUP_AUTH_TYPE,
)
from kpi.models.import_export_task import AccessLogExportTask
from kpi.tests.base_test_case import BaseTestCase
from kpi.urls.router_api_v2 import URL_NAMESPACE as ROUTER_URL_NAMESPACE

Expand Down Expand Up @@ -430,3 +427,180 @@ def test_can_search_access_logs_by_date_including_submission_groups(self):
group['metadata']['auth_type'],
ACCESS_LOG_SUBMISSION_GROUP_AUTH_TYPE,
)


class ApiAccessLogsExportTestCase(BaseAuditLogTestCase):

def get_endpoint_basename(self):
return 'access-logs-export-list'

def test_export_as_anonymous_returns_unauthorized(self):
self.client.logout()
response = self.client.post(self.url)
assert response.status_code == status.HTTP_401_UNAUTHORIZED

def test_export_for_user_returns_success(self):
self.force_login_user(User.objects.get(username='anotheruser'))
response = self.client.post(self.url)
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)

def test_export_for_superuser_commences(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

self.force_login_user(User.objects.get(username='admin'))
response = self.client.post(self.url)
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)

def test_create_export_task_on_post(self):
test_user = User.objects.get(username='anotheruser')
self.force_login_user(test_user)

response = self.client.post(self.url)
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)

task = (
AccessLogExportTask.objects.filter(user=test_user)
.order_by('-date_created')
.first()
)
self.assertIsNotNone(task)
self.assertIn(task.status, ['created', 'processing', 'complete'])
rgraber marked this conversation as resolved.
Show resolved Hide resolved
self.assertEqual(task.get_all_logs, False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit (nonblocking)

Suggested change
self.assertEqual(task.get_all_logs, False)
self.assertFalse(task.get_all_logs)


def test_get_status_of_tasks(self):
test_user = User.objects.get(username='anotheruser')
self.force_login_user(test_user)

AccessLogExportTask.objects.create(
user=test_user,
get_all_logs=False,
data={
'type': 'access_logs_export',
},
)

response_status = self.client.get(self.url)
self.assertEqual(response_status.status_code, status.HTTP_200_OK)

# Assert the response contains a list of tasks
tasks = response_status.json()
self.assertIsInstance(tasks, list)
self.assertGreater(len(tasks), 0) # Ensure at least one task is present

# Assert the structure of the first task in the list
first_task = tasks[0]
self.assertIn('uid', first_task)
self.assertIn('status', first_task)
self.assertIn('date_created', first_task)

def test_multiple_export_tasks_not_allowed(self):
test_user = User.objects.get(username='anotheruser')
self.force_login_user(test_user)

response_first = self.client.post(self.url)
self.assertEqual(response_first.status_code, status.HTTP_202_ACCEPTED)

task = (
AccessLogExportTask.objects.filter(user=test_user)
.order_by('-date_created')
.first()
)
task.status = 'processing'
task.save()

response_second = self.client.post(self.url)
self.assertEqual(response_second.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn(
'Export task for user access logs already in progress.',
response_second.json()['error'],
)


class AllApiAccessLogsExportTestCase(BaseAuditLogTestCase):

def get_endpoint_basename(self):
return 'all-access-logs-export-list'

def test_export_as_anonymous_returns_unauthorized(self):
self.client.logout()
response = self.client.post(self.url)
assert response.status_code == status.HTTP_401_UNAUTHORIZED

def test_regular_user_cannot_export_access_logs(self):
self.force_login_user(User.objects.get(username='anotheruser'))
response = self.client.post(self.url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

def test_export_access_logs_for_superuser_returns_success(self):
self.force_login_user(User.objects.get(username='admin'))
response = self.client.post(self.url)
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)

def test_superuser_create_export_task_on_post(self):
test_superuser = User.objects.get(username='admin')
self.force_login_user(test_superuser)

response = self.client.post(self.url)
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)

task = (
AccessLogExportTask.objects.filter(user=test_superuser)
.order_by('-date_created')
.first()
)
self.assertIsNotNone(task)
self.assertIn(task.status, ['created', 'processing', 'complete'])
self.assertEqual(task.get_all_logs, True)

def test_superuser_get_status_tasks(self):
test_superuser = User.objects.get(username='admin')
self.force_login_user(test_superuser)

AccessLogExportTask.objects.create(
user=test_superuser,
get_all_logs=False,
data={
'type': 'access_logs_export',
},
)

response_status = self.client.get(self.url)
self.assertEqual(response_status.status_code, status.HTTP_200_OK)

# Assert the response contains a list of tasks
tasks = response_status.json()
self.assertIsInstance(tasks, list)
self.assertGreater(len(tasks), 0) # Ensure at least one task is present

# Assert the structure of the first task in the list
first_task = tasks[0]
self.assertIn('uid', first_task)
self.assertIn('status', first_task)
rgraber marked this conversation as resolved.
Show resolved Hide resolved
self.assertIn('date_created', first_task)

def test_permission_denied_for_non_superusers_on_get_status(self):
non_superuser = User.objects.get(username='anotheruser')
self.force_login_user(non_superuser)

response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

def test_multiple_export_tasks_not_allowed(self):
test_superuser = User.objects.get(username='admin')
self.force_login_user(test_superuser)

response_first = self.client.post(self.url)
self.assertEqual(response_first.status_code, status.HTTP_202_ACCEPTED)

task = (
AccessLogExportTask.objects.filter(user=test_superuser)
.order_by('-date_created')
.first()
)
task.status = 'processing'
task.save()

response_second = self.client.post(self.url)
self.assertEqual(response_second.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn(
'Export task for all access logs already in progress.',
response_second.json()['error'],
)
14 changes: 13 additions & 1 deletion kobo/apps/audit_log/urls.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
from rest_framework.routers import DefaultRouter

from .views import AccessLogViewSet, AllAccessLogViewSet, AuditLogViewSet
from .views import (
AccessLogsExportViewSet,
AccessLogViewSet,
AllAccessLogsExportViewSet,
AllAccessLogViewSet,
AuditLogViewSet,
)

router = DefaultRouter()
router.register(r'audit-logs', AuditLogViewSet, basename='audit-log')
router.register(r'access-logs', AllAccessLogViewSet, basename='all-access-logs')
router.register(r'access-logs/me', AccessLogViewSet, basename='access-log')
router.register(
r'access-logs/export', AllAccessLogsExportViewSet, basename='all-access-logs-export'
)
router.register(
r'access-logs/me/export', AccessLogsExportViewSet, basename='access-logs-export'
)

urlpatterns = []
Loading
Loading