realm/playground: Add API endpoint for deleting a playground entry.

Similar to the previous commit, we have added a `do_*` function
which does the deletion from the DB. The next commit handles sending
the events when both adding and deleting a playground entry.

Added the openAPI format data to zulip.yaml for DELETE
/realm/playgrounds/{playground_id}. Also added python and curl
examples to remove-playground.md.

Tests added.
This commit is contained in:
Sumanth V Rao 2020-10-27 06:51:22 +05:30
parent 251b415987
commit d2e5b62dce
9 changed files with 129 additions and 3 deletions

View File

@ -0,0 +1,28 @@
# Remove a playground
{generate_api_description(/realm/playgrounds/{playground_id}:delete)}
## Usage examples
{start_tabs}
{tab|python}
{generate_code_example(python)|/realm/playgrounds/{playground_id}:delete|example}
{tab|curl}
{generate_code_example(curl)|/realm/playgrounds/{playground_id}:delete|example}
{end_tabs}
## Parameters
{generate_api_arguments_table|zulip.yaml|/realm/playgrounds/{playground_id}:delete}
## Response
#### Example response
A typical successful JSON response may look like:
{generate_code_example|/realm/playgrounds/{playground_id}:delete|fixture(200)}

View File

@ -60,6 +60,7 @@
* [Add a linkifier](/api/add-linkifier) * [Add a linkifier](/api/add-linkifier)
* [Remove a linkifier](/api/remove-linkifier) * [Remove a linkifier](/api/remove-linkifier)
* [Add a playground](/api/add-playground) * [Add a playground](/api/add-playground)
* [Remove a playground](/api/remove-playground)
* [Get all custom emoji](/api/get-custom-emoji) * [Get all custom emoji](/api/get-custom-emoji)
* [Upload custom emoji](/api/upload-custom-emoji) * [Upload custom emoji](/api/upload-custom-emoji)
* [Get all custom profile fields](/api/get-custom-profile-fields) * [Get all custom profile fields](/api/get-custom-profile-fields)

View File

@ -6602,6 +6602,10 @@ def do_add_realm_playground(realm: Realm, **kwargs: Any) -> int:
return realm_playground.id return realm_playground.id
def do_remove_realm_playground(realm_playground: RealmPlayground) -> None:
realm_playground.delete()
def get_occupied_streams(realm: Realm) -> QuerySet: def get_occupied_streams(realm: Realm) -> QuerySet:
# TODO: Make a generic stub for QuerySet # TODO: Make a generic stub for QuerySet
""" Get streams with subscribers """ """ Get streams with subscribers """

View File

@ -14,6 +14,7 @@ from django.utils.timezone import now as timezone_now
from zerver.lib.actions import ( from zerver.lib.actions import (
do_add_linkifier, do_add_linkifier,
do_add_reaction, do_add_reaction,
do_add_realm_playground,
do_create_user, do_create_user,
update_user_presence, update_user_presence,
) )
@ -277,6 +278,19 @@ def add_realm_playground() -> Dict[str, object]:
} }
@openapi_param_value_generator(["/realm/playgrounds/{playground_id}:delete"])
def remove_realm_playground() -> Dict[str, object]:
playground_info = dict(
name="Python playground",
pygments_language="Python",
url_prefix="https://python.example.com",
)
playground_id = do_add_realm_playground(get_realm("zulip"), **playground_info)
return {
"playground_id": playground_id,
}
@openapi_param_value_generator(["/users/{user_id}:delete"]) @openapi_param_value_generator(["/users/{user_id}:delete"])
def deactivate_user() -> Dict[str, object]: def deactivate_user() -> Dict[str, object]:
user_profile = do_create_user( user_profile = do_create_user(

View File

@ -396,6 +396,17 @@ def add_realm_playground(client: Client) -> None:
validate_against_openapi_schema(result, "/realm/playgrounds", "post", "200") validate_against_openapi_schema(result, "/realm/playgrounds", "post", "200")
@openapi_test_function("/realm/playgrounds/{playground_id}:delete")
def remove_realm_playground(client: Client) -> None:
# {code_example|start}
# Remove the playground with ID 1
result = client.call_endpoint(url="/realm/playgrounds/1", method="DELETE")
# {code_example|end}
validate_against_openapi_schema(result, "/realm/playgrounds/{playground_id}", "delete", "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:
@ -1436,6 +1447,7 @@ def test_server_organizations(client: Client) -> None:
add_realm_playground(client) add_realm_playground(client)
get_server_settings(client) get_server_settings(client)
remove_realm_filter(client) remove_realm_filter(client)
remove_realm_playground(client)
get_realm_emoji(client) get_realm_emoji(client)
upload_custom_emoji(client) upload_custom_emoji(client)
get_realm_profile_fields(client) get_realm_profile_fields(client)

View File

@ -6621,6 +6621,31 @@ paths:
description: | description: |
The numeric ID assigned to this playground. The numeric ID assigned to this playground.
example: {"id": 1, "result": "success", "msg": ""} example: {"id": 1, "result": "success", "msg": ""}
/realm/playgrounds/{playground_id}:
delete:
operationId: remove_realm_playground
tags: ["server_and_organizations"]
description: |
Remove realm playground options to run code snippets in
custom playgrounds
`DELETE {{ api_url }}/v1/realm/playgrounds/{playground_id}`
parameters:
- name: playground_id
in: path
description: |
The ID of the playground that you want to remove.
schema:
type: integer
example: 1
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
/register: /register:
post: post:
operationId: register_queue operationId: register_queue

View File

@ -2,6 +2,7 @@ from typing import Dict
import orjson import orjson
from zerver.lib.actions import do_add_realm_playground
from zerver.lib.test_classes import ZulipTestCase from zerver.lib.test_classes import ZulipTestCase
from zerver.models import RealmPlayground, get_realm from zerver.models import RealmPlayground, get_realm
@ -93,3 +94,25 @@ class RealmPlaygroundTests(ZulipTestCase):
resp = self.api_post(hamlet, "/json/realm/playgrounds") resp = self.api_post(hamlet, "/json/realm/playgrounds")
self.assert_json_error(resp, "Must be an organization administrator") self.assert_json_error(resp, "Must be an organization administrator")
resp = self.api_delete(hamlet, "/json/realm/playgrounds/1")
self.assert_json_error(resp, "Must be an organization administrator")
def test_delete_realm_playground(self) -> None:
iago = self.example_user("iago")
realm = get_realm("zulip")
playground_info = dict(
name="Python playground",
pygments_language="Python",
url_prefix="https://python.example.com",
)
playground_id = do_add_realm_playground(realm, **playground_info)
self.assertTrue(RealmPlayground.objects.filter(name="Python playground").exists())
result = self.api_delete(iago, f"/json/realm/playgrounds/{playground_id + 1}")
self.assert_json_error(result, "Invalid playground")
result = self.api_delete(iago, f"/json/realm/playgrounds/{playground_id}")
self.assert_json_success(result)
self.assertFalse(RealmPlayground.objects.filter(name="Python").exists())

View File

@ -5,11 +5,11 @@ from django.http import HttpRequest, HttpResponse
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from zerver.decorator import require_realm_admin from zerver.decorator import require_realm_admin
from zerver.lib.actions import do_add_realm_playground from zerver.lib.actions import do_add_realm_playground, do_remove_realm_playground
from zerver.lib.request import REQ, JsonableError, has_request_variables from zerver.lib.request import REQ, JsonableError, has_request_variables
from zerver.lib.response import json_error, json_success from zerver.lib.response import json_error, json_success
from zerver.lib.validator import check_capped_string, check_url from zerver.lib.validator import check_capped_string, check_url
from zerver.models import RealmPlayground, UserProfile from zerver.models import Realm, RealmPlayground, UserProfile
def check_pygments_language(var_name: str, val: object) -> str: def check_pygments_language(var_name: str, val: object) -> str:
@ -25,6 +25,14 @@ def check_pygments_language(var_name: str, val: object) -> str:
return s return s
def access_playground_by_id(realm: Realm, playground_id: int) -> RealmPlayground:
try:
realm_playground = RealmPlayground.objects.get(id=playground_id, realm=realm)
except RealmPlayground.DoesNotExist:
raise JsonableError(_("Invalid playground"))
return realm_playground
@require_realm_admin @require_realm_admin
@has_request_variables @has_request_variables
def add_realm_playground( def add_realm_playground(
@ -44,3 +52,13 @@ def add_realm_playground(
except ValidationError as e: except ValidationError as e:
return json_error(e.messages[0], data={"errors": dict(e)}) return json_error(e.messages[0], data={"errors": dict(e)})
return json_success({"id": playground_id}) return json_success({"id": playground_id})
@require_realm_admin
@has_request_variables
def delete_realm_playground(
request: HttpRequest, user_profile: UserProfile, playground_id: int
) -> HttpResponse:
realm_playground = access_playground_by_id(user_profile.realm, playground_id)
do_remove_realm_playground(realm_playground)
return json_success()

View File

@ -121,7 +121,7 @@ from zerver.views.realm_export import delete_realm_export, export_realm, get_rea
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 create_linkifier, delete_linkifier, list_linkifiers from zerver.views.realm_linkifiers import create_linkifier, delete_linkifier, list_linkifiers
from zerver.views.realm_logo import delete_logo_backend, get_logo_backend, upload_logo from zerver.views.realm_logo import delete_logo_backend, get_logo_backend, upload_logo
from zerver.views.realm_playgrounds import add_realm_playground from zerver.views.realm_playgrounds import add_realm_playground, delete_realm_playground
from zerver.views.registration import ( from zerver.views.registration import (
accounts_home, accounts_home,
accounts_home_from_multiuse_invite, accounts_home_from_multiuse_invite,
@ -271,6 +271,7 @@ v1_api_and_json_patterns = [
rest_path("realm/filters/<int:filter_id>", DELETE=delete_linkifier), rest_path("realm/filters/<int:filter_id>", DELETE=delete_linkifier),
# realm/playgrounds -> zerver.views.realm_playgrounds # realm/playgrounds -> zerver.views.realm_playgrounds
rest_path("realm/playgrounds", POST=add_realm_playground), rest_path("realm/playgrounds", POST=add_realm_playground),
rest_path("realm/playgrounds/<int:playground_id>", DELETE=delete_realm_playground),
# realm/profile_fields -> zerver.views.custom_profile_fields # realm/profile_fields -> zerver.views.custom_profile_fields
rest_path( rest_path(
"realm/profile_fields", "realm/profile_fields",