-
-
Notifications
You must be signed in to change notification settings - Fork 184
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
Changes from 32 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 4079ea0
revert to before Submissions name change
RuthShryock eb67d2b
:This reverts commit 4079ea05a8eed915ad74143a43c7be665b70e6a8.
RuthShryock 0f9ac39
Merge branch 'main' of github.com:kobotoolbox/kpi into access-log-exp…
RuthShryock 2836ea3
fix circular import error
RuthShryock b69a006
fix formatting
RuthShryock 04dc2cd
rename ExportTaskBase, ExportTask, and SynchronousExport to have Subm…
RuthShryock 4c46fb0
fix formatting
RuthShryock de7f7f5
Merge branch 'main' of github.com:kobotoolbox/kpi into access-log-exp…
RuthShryock ff45ba8
fix migration error by creating common export tasks for each project …
RuthShryock 7837192
fix formatting
RuthShryock 6c60768
simplify refactor with ExportTaskMixin and adding get_data and defaul…
RuthShryock 43ce879
updating branch with main
RuthShryock a0a2d5e
add access log export endpoints and tests
RuthShryock bd5c994
rename functions and variables, fix grammar, and allow for views to b…
RuthShryock 91fefc7
Merge branch 'main' of github.com:kobotoolbox/kpi into endpoints-for-…
RuthShryock 0640937
Merge branch 'access-log-export-task-class' of github.com:kobotoolbox…
RuthShryock cd25b98
remove view from data for access log exports
RuthShryock 6c3e3af
Revert "refactor(organizations): add of useSession hook TASK-1305 (#…
RuthShryock dd5650d
Revert "feat(InlineMessage): add new type TASK-987 (#5305)"
RuthShryock cd35d96
Merge branch 'main' into endpoints-for-access-logs-export
RuthShryock 039063b
Reapply "refactor(organizations): add of useSession hook TASK-1305 (…
RuthShryock 33e1c0a
Reapply "feat(InlineMessage): add new type TASK-987 (#5305)"
RuthShryock 6ca21ec
refactor to include two endpoints, add documentation, return a list o…
RuthShryock 13d31b2
Merge branch 'main' of github.com:kobotoolbox/kpi into endpoints-for-…
RuthShryock fee5f37
fix formatting
RuthShryock 6eac898
fix tests
RuthShryock 189a860
fix failing tests
RuthShryock 1d41380
Update kobo/apps/audit_log/views.py
RuthShryock c9cbb7e
Update kobo/apps/audit_log/views.py
RuthShryock 8d8f763
Update kobo/apps/audit_log/views.py
RuthShryock 7f88c37
check get_all_logs in tests and fix formatting
RuthShryock 0383afb
fix error messages to apply to access logs
RuthShryock 350c22e
fix assert statments in test cases
RuthShryock File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -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 | ||||||
|
||||||
|
@@ -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): | ||||||
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) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit (nonblocking)
Suggested change
|
||||||
|
||||||
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 project history 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 project history logs already in progress.', | ||||||
response_second.json()['error'], | ||||||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 = [] |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above