mirror of https://github.com/zulip/zulip.git
realm_export: Add a new endpoint to fetch private data export consents.
This commit adds a new endpoint `export/realm/consents` to fetch the consents of users for their private data exports. Fixes part of #31201.
This commit is contained in:
parent
ffbf2aaaff
commit
86194efe7b
|
@ -20,6 +20,12 @@ format used by the Zulip server that they are interacting with.
|
||||||
|
|
||||||
## Changes in Zulip 10.0
|
## Changes in Zulip 10.0
|
||||||
|
|
||||||
|
**Feature level 295**
|
||||||
|
|
||||||
|
* [`GET /export/realm/consents`](/api/get-realm-export-consents): Added
|
||||||
|
a new endpoint to fetch the consents of users for their [private data
|
||||||
|
exports](/help/export-your-organization#full-export-with-member-consent).
|
||||||
|
|
||||||
**Feature level 294**
|
**Feature level 294**
|
||||||
|
|
||||||
* [`POST /register`](/api/register-queue): Clients that do not
|
* [`POST /register`](/api/register-queue): Clients that do not
|
||||||
|
|
|
@ -118,6 +118,7 @@
|
||||||
* [Update realm-level defaults of user settings](/api/update-realm-user-settings-defaults)
|
* [Update realm-level defaults of user settings](/api/update-realm-user-settings-defaults)
|
||||||
* [Get all public data exports](/api/get-realm-exports)
|
* [Get all public data exports](/api/get-realm-exports)
|
||||||
* [Create a public data export](/api/export-realm)
|
* [Create a public data export](/api/export-realm)
|
||||||
|
* [Get data export consent state](/api/get-realm-export-consents)
|
||||||
|
|
||||||
#### Real-time events
|
#### Real-time events
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
||||||
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
||||||
# entries in the endpoint's documentation in `zulip.yaml`.
|
# entries in the endpoint's documentation in `zulip.yaml`.
|
||||||
|
|
||||||
API_FEATURE_LEVEL = 294 # Last bumped for `include_daectivated_groups` client capability.
|
API_FEATURE_LEVEL = 295 # Last bumped for `/export/realm/consents` endpoint.
|
||||||
|
|
||||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||||
# only when going from an old version of the code to a newer version. Bump
|
# only when going from an old version of the code to a newer version. Bump
|
||||||
|
|
|
@ -694,6 +694,16 @@ def export_realm(client: Client) -> None:
|
||||||
validate_against_openapi_schema(result, "/export/realm", "post", "200")
|
validate_against_openapi_schema(result, "/export/realm", "post", "200")
|
||||||
|
|
||||||
|
|
||||||
|
@openapi_test_function("/export/realm/consents:get")
|
||||||
|
def get_realm_export_consents(client: Client) -> None:
|
||||||
|
# {code_example|start}
|
||||||
|
# Get the consents of users for their private data exports.
|
||||||
|
result = client.call_endpoint(url="/export/realm/consents", method="GET")
|
||||||
|
# {code_example|end}
|
||||||
|
assert_success_response(result)
|
||||||
|
validate_against_openapi_schema(result, "/export/realm/consents", "get", "200")
|
||||||
|
|
||||||
|
|
||||||
@openapi_test_function("/users/me:get")
|
@openapi_test_function("/users/me:get")
|
||||||
def get_profile(client: Client) -> None:
|
def get_profile(client: Client) -> None:
|
||||||
# {code_example|start}
|
# {code_example|start}
|
||||||
|
@ -1822,6 +1832,7 @@ def test_server_organizations(client: Client) -> None:
|
||||||
create_realm_profile_field(client)
|
create_realm_profile_field(client)
|
||||||
export_realm(client)
|
export_realm(client)
|
||||||
get_realm_exports(client)
|
get_realm_exports(client)
|
||||||
|
get_realm_export_consents(client)
|
||||||
|
|
||||||
|
|
||||||
def test_errors(client: Client) -> None:
|
def test_errors(client: Client) -> None:
|
||||||
|
|
|
@ -12763,6 +12763,57 @@ paths:
|
||||||
description: |
|
description: |
|
||||||
An example JSON error response for when the public data export
|
An example JSON error response for when the public data export
|
||||||
exceeds the maximum allowed data export size.
|
exceeds the maximum allowed data export size.
|
||||||
|
/export/realm/consents:
|
||||||
|
get:
|
||||||
|
operationId: get-realm-export-consents
|
||||||
|
summary: Get data export consent state
|
||||||
|
tags: ["server_and_organizations"]
|
||||||
|
x-requires-administrator: true
|
||||||
|
description: |
|
||||||
|
Fetches which users have [consented](/help/export-your-organization#full-export-with-member-consent)
|
||||||
|
for their private data to be exported by organization administrators.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 10.0 (feature level 295).
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Success.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/JsonSuccessBase"
|
||||||
|
- additionalProperties: false
|
||||||
|
properties:
|
||||||
|
result: {}
|
||||||
|
msg: {}
|
||||||
|
ignored_parameters_unsupported: {}
|
||||||
|
export_consents:
|
||||||
|
type: array
|
||||||
|
description: |
|
||||||
|
An array of objects where each object contains a user ID and
|
||||||
|
whether the user has consented for their private data to be exported.
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
properties:
|
||||||
|
user_id:
|
||||||
|
description: |
|
||||||
|
The user ID.
|
||||||
|
type: integer
|
||||||
|
consented:
|
||||||
|
description: |
|
||||||
|
Whether the user has consented for their private data export.
|
||||||
|
type: boolean
|
||||||
|
example:
|
||||||
|
{
|
||||||
|
"export_consents":
|
||||||
|
[
|
||||||
|
{"user_id": 11, "consented": true},
|
||||||
|
{"user_id": 6, "consented": false},
|
||||||
|
],
|
||||||
|
"msg": "",
|
||||||
|
"result": "success",
|
||||||
|
}
|
||||||
/invites:
|
/invites:
|
||||||
get:
|
get:
|
||||||
operationId: get-invites
|
operationId: get-invites
|
||||||
|
|
|
@ -6,6 +6,7 @@ from django.conf import settings
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from analytics.models import RealmCount
|
from analytics.models import RealmCount
|
||||||
|
from zerver.actions.user_settings import do_change_user_setting
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
from zerver.lib.queue import queue_json_publish
|
from zerver.lib.queue import queue_json_publish
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
|
@ -16,7 +17,7 @@ from zerver.lib.test_helpers import (
|
||||||
stdout_suppressed,
|
stdout_suppressed,
|
||||||
use_s3_backend,
|
use_s3_backend,
|
||||||
)
|
)
|
||||||
from zerver.models import Realm, RealmAuditLog
|
from zerver.models import Realm, RealmAuditLog, UserProfile
|
||||||
from zerver.models.realm_audit_logs import AuditLogEventType
|
from zerver.models.realm_audit_logs import AuditLogEventType
|
||||||
from zerver.views.realm_export import export_realm
|
from zerver.views.realm_export import export_realm
|
||||||
|
|
||||||
|
@ -323,3 +324,30 @@ class RealmExportTest(ZulipTestCase):
|
||||||
result,
|
result,
|
||||||
f"Please request a manual export from {settings.ZULIP_ADMINISTRATOR}.",
|
f"Please request a manual export from {settings.ZULIP_ADMINISTRATOR}.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_get_users_export_consents(self) -> None:
|
||||||
|
admin = self.example_user("iago")
|
||||||
|
self.login_user(admin)
|
||||||
|
|
||||||
|
# By default, export consent is set to False.
|
||||||
|
self.assertFalse(
|
||||||
|
UserProfile.objects.filter(
|
||||||
|
realm=admin.realm, is_active=True, is_bot=False, allow_private_data_export=True
|
||||||
|
).exists()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Hamlet and Aaron consented to export their private data.
|
||||||
|
hamlet = self.example_user("hamlet")
|
||||||
|
aaron = self.example_user("aaron")
|
||||||
|
for user in [hamlet, aaron]:
|
||||||
|
do_change_user_setting(user, "allow_private_data_export", True, acting_user=None)
|
||||||
|
|
||||||
|
# Verify export consents of users.
|
||||||
|
result = self.client_get("/json/export/realm/consents")
|
||||||
|
response_dict = self.assert_json_success(result)
|
||||||
|
export_consents = response_dict["export_consents"]
|
||||||
|
for export_consent in export_consents:
|
||||||
|
if export_consent["user_id"] in [hamlet.id, aaron.id]:
|
||||||
|
self.assertTrue(export_consent["consented"])
|
||||||
|
continue
|
||||||
|
self.assertFalse(export_consent["consented"])
|
||||||
|
|
|
@ -112,3 +112,14 @@ def delete_realm_export(request: HttpRequest, user: UserProfile, export_id: int)
|
||||||
raise JsonableError(_("Export still in progress"))
|
raise JsonableError(_("Export still in progress"))
|
||||||
do_delete_realm_export(user, audit_log_entry)
|
do_delete_realm_export(user, audit_log_entry)
|
||||||
return json_success(request)
|
return json_success(request)
|
||||||
|
|
||||||
|
|
||||||
|
@require_realm_admin
|
||||||
|
def get_users_export_consents(request: HttpRequest, user: UserProfile) -> HttpResponse:
|
||||||
|
rows = UserProfile.objects.filter(realm=user.realm, is_active=True, is_bot=False).values(
|
||||||
|
"id", "allow_private_data_export"
|
||||||
|
)
|
||||||
|
export_consents = [
|
||||||
|
{"user_id": row["id"], "consented": row["allow_private_data_export"]} for row in rows
|
||||||
|
]
|
||||||
|
return json_success(request, data={"export_consents": export_consents})
|
||||||
|
|
|
@ -119,7 +119,12 @@ from zerver.views.realm_domains import (
|
||||||
patch_realm_domain,
|
patch_realm_domain,
|
||||||
)
|
)
|
||||||
from zerver.views.realm_emoji import delete_emoji, list_emoji, upload_emoji
|
from zerver.views.realm_emoji import delete_emoji, list_emoji, upload_emoji
|
||||||
from zerver.views.realm_export import delete_realm_export, export_realm, get_realm_exports
|
from zerver.views.realm_export import (
|
||||||
|
delete_realm_export,
|
||||||
|
export_realm,
|
||||||
|
get_realm_exports,
|
||||||
|
get_users_export_consents,
|
||||||
|
)
|
||||||
from zerver.views.realm_icon import delete_icon_backend, get_icon_backend, upload_icon
|
from zerver.views.realm_icon import delete_icon_backend, get_icon_backend, upload_icon
|
||||||
from zerver.views.realm_linkifiers import (
|
from zerver.views.realm_linkifiers import (
|
||||||
create_linkifier,
|
create_linkifier,
|
||||||
|
@ -504,6 +509,7 @@ v1_api_and_json_patterns = [
|
||||||
# export/realm -> zerver.views.realm_export
|
# export/realm -> zerver.views.realm_export
|
||||||
rest_path("export/realm", POST=export_realm, GET=get_realm_exports),
|
rest_path("export/realm", POST=export_realm, GET=get_realm_exports),
|
||||||
rest_path("export/realm/<int:export_id>", DELETE=delete_realm_export),
|
rest_path("export/realm/<int:export_id>", DELETE=delete_realm_export),
|
||||||
|
rest_path("export/realm/consents", GET=get_users_export_consents),
|
||||||
]
|
]
|
||||||
|
|
||||||
integrations_view = IntegrationView.as_view()
|
integrations_view = IntegrationView.as_view()
|
||||||
|
|
Loading…
Reference in New Issue