mirror of https://github.com/zulip/zulip.git
api: Add GET /users/{user_id}/subscription/{stream_id} endpoint.
This new endpoint returns a 'user' dictionary which, as of now, contains a single key 'is_subscribed' with a boolean value that represents whether the user with the given 'user_id' is subscribed to the stream with the given 'stream_id'. Fixes #14966.
This commit is contained in:
parent
d5cc29755e
commit
8c39ddfd28
|
@ -10,6 +10,11 @@ below features are supported.
|
||||||
|
|
||||||
## Changes in Zulip 2.2
|
## Changes in Zulip 2.2
|
||||||
|
|
||||||
|
**Feature level 12**
|
||||||
|
|
||||||
|
* [`GET users/{user_id}/subscriptions/{stream_id}`](/api/get-subscription-status):
|
||||||
|
New endpoint added for checking if another user is subscribed to a stream.
|
||||||
|
|
||||||
**Feature level 11**
|
**Feature level 11**
|
||||||
|
|
||||||
* [`POST /register`](/api/register-queue): Added
|
* [`POST /register`](/api/register-queue): Added
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Get user subscription status
|
||||||
|
|
||||||
|
{generate_api_description(/users/{user_id}/subscriptions/{stream_id}:get)}
|
||||||
|
|
||||||
|
## Usage examples
|
||||||
|
|
||||||
|
{start_tabs}
|
||||||
|
{tab|python}
|
||||||
|
|
||||||
|
{generate_code_example(python)|/users/{user_id}/subscriptions/{stream_id}:get|example}
|
||||||
|
|
||||||
|
{tab|curl}
|
||||||
|
|
||||||
|
{generate_code_example(curl)|/users/{user_id}/subscriptions/{stream_id}:get|example}
|
||||||
|
|
||||||
|
{end_tabs}
|
||||||
|
|
||||||
|
## Arguments
|
||||||
|
|
||||||
|
{generate_api_arguments_table|zulip.yaml|/users/{user_id}/subscriptions/{stream_id}:get}
|
||||||
|
|
||||||
|
## Response
|
||||||
|
|
||||||
|
#### Example response
|
||||||
|
|
||||||
|
A typical successful JSON response may look like:
|
||||||
|
|
||||||
|
{generate_code_example|/users/{user_id}/subscriptions/{stream_id}:get|fixture(200)}
|
|
@ -21,6 +21,7 @@
|
||||||
* [Add subscriptions](/api/add-subscriptions)
|
* [Add subscriptions](/api/add-subscriptions)
|
||||||
* [Update subscription settings](/api/update-subscription-properties)
|
* [Update subscription settings](/api/update-subscription-properties)
|
||||||
* [Remove subscriptions](/api/remove-subscriptions)
|
* [Remove subscriptions](/api/remove-subscriptions)
|
||||||
|
* [Get subscription status](/api/get-subscription-status)
|
||||||
* [Get topics in a stream](/api/get-stream-topics)
|
* [Get topics in a stream](/api/get-stream-topics)
|
||||||
* [Topic muting](/api/mute-topics)
|
* [Topic muting](/api/mute-topics)
|
||||||
* [Create a stream](/api/create-stream)
|
* [Create a stream](/api/create-stream)
|
||||||
|
|
|
@ -29,7 +29,7 @@ DESKTOP_WARNING_VERSION = "5.2.0"
|
||||||
#
|
#
|
||||||
# Changes should be accompanied by documentation explaining what the
|
# Changes should be accompanied by documentation explaining what the
|
||||||
# new level means in templates/zerver/api/changelog.md.
|
# new level means in templates/zerver/api/changelog.md.
|
||||||
API_FEATURE_LEVEL = 11
|
API_FEATURE_LEVEL = 12
|
||||||
|
|
||||||
# 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
|
||||||
|
|
|
@ -253,6 +253,19 @@ def update_user(client: Client) -> None:
|
||||||
# {code_example|end}
|
# {code_example|end}
|
||||||
validate_against_openapi_schema(result, '/users/{user_id}', 'patch', '400')
|
validate_against_openapi_schema(result, '/users/{user_id}', 'patch', '400')
|
||||||
|
|
||||||
|
@openapi_test_function("/users/{user_id}/subscriptions/{stream_id}:get")
|
||||||
|
def get_subscription_status(client: Client) -> None:
|
||||||
|
# {code_example|start}
|
||||||
|
# Check whether a user is a subscriber to a given stream.
|
||||||
|
user_id = 7
|
||||||
|
stream_id = 1
|
||||||
|
result = client.call_endpoint(
|
||||||
|
url='/users/{}/subscriptions/{}'.format(user_id, stream_id),
|
||||||
|
method='GET',
|
||||||
|
)
|
||||||
|
# {code_example|end}
|
||||||
|
validate_against_openapi_schema(result, '/users/{user_id}/subscriptions/{stream_id}', 'get', '200')
|
||||||
|
|
||||||
@openapi_test_function("/realm/filters:get")
|
@openapi_test_function("/realm/filters:get")
|
||||||
def get_realm_filters(client: Client) -> None:
|
def get_realm_filters(client: Client) -> None:
|
||||||
|
|
||||||
|
@ -1117,6 +1130,7 @@ def test_users(client: Client) -> None:
|
||||||
deactivate_user(client)
|
deactivate_user(client)
|
||||||
reactivate_user(client)
|
reactivate_user(client)
|
||||||
update_user(client)
|
update_user(client)
|
||||||
|
get_subscription_status(client)
|
||||||
get_profile(client)
|
get_profile(client)
|
||||||
update_notification_settings(client)
|
update_notification_settings(client)
|
||||||
upload_file(client)
|
upload_file(client)
|
||||||
|
|
|
@ -2628,6 +2628,40 @@ paths:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/NonExistingStreamError'
|
$ref: '#/components/schemas/NonExistingStreamError'
|
||||||
|
/users/{user_id}/subscriptions/{stream_id}:
|
||||||
|
get:
|
||||||
|
operationId: get_subscription_status
|
||||||
|
tags: ["streams"]
|
||||||
|
description: |
|
||||||
|
Check whether a user is subscribed to a stream.
|
||||||
|
|
||||||
|
`GET {{ api_url }}/v1/users/{user_id}/subscriptions/{stream_id}`
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 2.2 (feature level 11).
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/UserId'
|
||||||
|
example: 7
|
||||||
|
- $ref: '#/components/parameters/StreamIdInPath'
|
||||||
|
example: 1
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Success
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/components/schemas/JsonSuccess'
|
||||||
|
- properties:
|
||||||
|
is_subscribed:
|
||||||
|
type: boolean
|
||||||
|
description: |
|
||||||
|
Whether the user is subscribed to the stream.
|
||||||
|
- example:
|
||||||
|
{
|
||||||
|
"msg": "",
|
||||||
|
"result": "success",
|
||||||
|
"is_subscribed": false
|
||||||
|
}
|
||||||
/users/me/subscriptions/muted_topics:
|
/users/me/subscriptions/muted_topics:
|
||||||
patch:
|
patch:
|
||||||
operationId: mute_topic
|
operationId: mute_topic
|
||||||
|
|
|
@ -1093,6 +1093,38 @@ class UserProfileTest(ZulipTestCase):
|
||||||
get_user_by_id_in_realm_including_cross_realm(
|
get_user_by_id_in_realm_including_cross_realm(
|
||||||
hamlet.id, None)
|
hamlet.id, None)
|
||||||
|
|
||||||
|
def test_get_user_subscription_status(self) -> None:
|
||||||
|
self.login('hamlet')
|
||||||
|
iago = self.example_user('iago')
|
||||||
|
stream = get_stream('Rome', iago.realm)
|
||||||
|
|
||||||
|
# Invalid User ID.
|
||||||
|
result = self.client_get("/json/users/25/subscriptions/{}".format(stream.id))
|
||||||
|
self.assert_json_error(result, "No such user")
|
||||||
|
|
||||||
|
# Invalid Stream ID.
|
||||||
|
result = self.client_get("/json/users/{}/subscriptions/25".format(iago.id))
|
||||||
|
self.assert_json_error(result, "Invalid stream id")
|
||||||
|
|
||||||
|
result = ujson.loads(self.client_get("/json/users/{}/subscriptions/{}".format(iago.id, stream.id)).content)
|
||||||
|
self.assertFalse(result['is_subscribed'])
|
||||||
|
|
||||||
|
# Subscribe to the stream.
|
||||||
|
self.subscribe(iago, stream.name)
|
||||||
|
with queries_captured() as queries:
|
||||||
|
result = ujson.loads(self.client_get("/json/users/{}/subscriptions/{}".format(iago.id, stream.id)).content)
|
||||||
|
|
||||||
|
self.assert_length(queries, 7)
|
||||||
|
self.assertTrue(result['is_subscribed'])
|
||||||
|
|
||||||
|
# Logging in with a Guest user.
|
||||||
|
polonius = self.example_user("polonius")
|
||||||
|
self.login('polonius')
|
||||||
|
self.assertTrue(polonius.is_guest)
|
||||||
|
|
||||||
|
result = self.client_get("/json/users/{}/subscriptions/{}".format(iago.id, stream.id))
|
||||||
|
self.assert_json_error(result, "Invalid stream id")
|
||||||
|
|
||||||
class ActivateTest(ZulipTestCase):
|
class ActivateTest(ZulipTestCase):
|
||||||
def test_basics(self) -> None:
|
def test_basics(self) -> None:
|
||||||
user = self.example_user('hamlet')
|
user = self.example_user('hamlet')
|
||||||
|
|
|
@ -22,7 +22,7 @@ from zerver.lib.exceptions import CannotDeactivateLastUserError
|
||||||
from zerver.lib.integrations import EMBEDDED_BOTS
|
from zerver.lib.integrations import EMBEDDED_BOTS
|
||||||
from zerver.lib.request import has_request_variables, REQ
|
from zerver.lib.request import has_request_variables, REQ
|
||||||
from zerver.lib.response import json_error, json_success
|
from zerver.lib.response import json_error, json_success
|
||||||
from zerver.lib.streams import access_stream_by_name
|
from zerver.lib.streams import access_stream_by_name, access_stream_by_id, subscribed_to_stream
|
||||||
from zerver.lib.upload import upload_avatar_image
|
from zerver.lib.upload import upload_avatar_image
|
||||||
from zerver.lib.validator import check_bool, check_string, check_int, check_url, check_dict, check_list, \
|
from zerver.lib.validator import check_bool, check_string, check_int, check_url, check_dict, check_list, \
|
||||||
check_int_in
|
check_int_in
|
||||||
|
@ -471,3 +471,15 @@ def get_profile_backend(request: HttpRequest, user_profile: UserProfile) -> Http
|
||||||
result['max_message_id'] = messages[0].id
|
result['max_message_id'] = messages[0].id
|
||||||
|
|
||||||
return json_success(result)
|
return json_success(result)
|
||||||
|
|
||||||
|
@has_request_variables
|
||||||
|
def get_subscription_backend(request: HttpRequest, user_profile: UserProfile,
|
||||||
|
user_id: int=REQ(validator=check_int, path_only=True),
|
||||||
|
stream_id: int=REQ(validator=check_int, path_only=True)
|
||||||
|
) -> HttpResponse:
|
||||||
|
target_user = access_user_by_id(user_profile, user_id, read_only=True)
|
||||||
|
(stream, recipient, sub) = access_stream_by_id(user_profile, stream_id)
|
||||||
|
|
||||||
|
subscription_status = {'is_subscribed': subscribed_to_stream(target_user, stream_id)}
|
||||||
|
|
||||||
|
return json_success(subscription_status)
|
||||||
|
|
|
@ -149,6 +149,8 @@ v1_api_and_json_patterns = [
|
||||||
{'GET': 'zerver.views.users.get_members_backend',
|
{'GET': 'zerver.views.users.get_members_backend',
|
||||||
'PATCH': 'zerver.views.users.update_user_backend',
|
'PATCH': 'zerver.views.users.update_user_backend',
|
||||||
'DELETE': 'zerver.views.users.deactivate_user_backend'}),
|
'DELETE': 'zerver.views.users.deactivate_user_backend'}),
|
||||||
|
url(r'^users/(?P<user_id>[0-9]+)/subscriptions/(?P<stream_id>[0-9]+)$', rest_dispatch,
|
||||||
|
{'GET': 'zerver.views.users.get_subscription_backend'}),
|
||||||
url(r'^bots$', rest_dispatch,
|
url(r'^bots$', rest_dispatch,
|
||||||
{'GET': 'zerver.views.users.get_bots_backend',
|
{'GET': 'zerver.views.users.get_bots_backend',
|
||||||
'POST': 'zerver.views.users.add_bot_backend'}),
|
'POST': 'zerver.views.users.add_bot_backend'}),
|
||||||
|
|
Loading…
Reference in New Issue