mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	realm/playground: Add API endpoint for creating playground entry.
This endpoint will allow clients to create a playground entry containing the name, pygments language and url_prefix for the playground of their choice. Introduced the `do_*` function in-charge of creating the entry in the model. Handling the process of sending events which will be done in a follow up commit. Added the openAPI format data to zulip.yaml for POST /realm/playgrounds. Also added python and curl examples for using the endpoint in its markdown documented (add-playground.md). Tests added.
This commit is contained in:
		
							
								
								
									
										32
									
								
								templates/zerver/api/add-playground.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								templates/zerver/api/add-playground.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					# Add a playground
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{generate_api_description(/realm/playgrounds:post)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Usage examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{start_tabs}
 | 
				
			||||||
 | 
					{tab|python}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{generate_code_example(python)|/realm/playgrounds:post|example}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{tab|curl}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{generate_code_example(curl)|/realm/playgrounds:post|example}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{end_tabs}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{generate_api_arguments_table|zulip.yaml|/realm/playgrounds:post}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Return values
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{generate_return_values_table|zulip.yaml|/realm/playgrounds:post}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Example response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A typical successful JSON response may look like:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{generate_code_example|/realm/playgrounds:post|fixture(200)}
 | 
				
			||||||
@@ -59,6 +59,7 @@
 | 
				
			|||||||
* [Get linkifiers](/api/get-linkifiers)
 | 
					* [Get linkifiers](/api/get-linkifiers)
 | 
				
			||||||
* [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)
 | 
				
			||||||
* [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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -197,6 +197,7 @@ from zerver.models import (
 | 
				
			|||||||
    RealmDomain,
 | 
					    RealmDomain,
 | 
				
			||||||
    RealmEmoji,
 | 
					    RealmEmoji,
 | 
				
			||||||
    RealmFilter,
 | 
					    RealmFilter,
 | 
				
			||||||
 | 
					    RealmPlayground,
 | 
				
			||||||
    Recipient,
 | 
					    Recipient,
 | 
				
			||||||
    ScheduledEmail,
 | 
					    ScheduledEmail,
 | 
				
			||||||
    ScheduledMessage,
 | 
					    ScheduledMessage,
 | 
				
			||||||
@@ -6591,6 +6592,16 @@ def do_remove_realm_domain(
 | 
				
			|||||||
    send_event(realm, event, active_user_ids(realm.id))
 | 
					    send_event(realm, event, active_user_ids(realm.id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def do_add_realm_playground(realm: Realm, **kwargs: Any) -> int:
 | 
				
			||||||
 | 
					    realm_playground = RealmPlayground(realm=realm, **kwargs)
 | 
				
			||||||
 | 
					    # We expect full_clean to always pass since a thorough input validation
 | 
				
			||||||
 | 
					    # is performed in the view (using check_url, check_pygments_language, etc)
 | 
				
			||||||
 | 
					    # before calling this function.
 | 
				
			||||||
 | 
					    realm_playground.full_clean()
 | 
				
			||||||
 | 
					    realm_playground.save()
 | 
				
			||||||
 | 
					    return realm_playground.id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
# based on Zulip's OpenAPI definitions, as well as test setup and
 | 
					# based on Zulip's OpenAPI definitions, as well as test setup and
 | 
				
			||||||
# fetching of appropriate parameter values to use when running the
 | 
					# fetching of appropriate parameter values to use when running the
 | 
				
			||||||
# cURL examples as part of the tools/test-api test suite.
 | 
					# cURL examples as part of the tools/test-api test suite.
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
from functools import wraps
 | 
					from functools import wraps
 | 
				
			||||||
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
 | 
					from typing import Any, Callable, Dict, List, Optional, Set, Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -268,6 +268,15 @@ def upload_custom_emoji() -> Dict[str, object]:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@openapi_param_value_generator(["/realm/playgrounds:post"])
 | 
				
			||||||
 | 
					def add_realm_playground() -> Dict[str, object]:
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        "name": "Python2 playground",
 | 
				
			||||||
 | 
					        "pygments_language": json.dumps("Python2"),
 | 
				
			||||||
 | 
					        "url_prefix": json.dumps("https://python2.example.com"),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@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(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -380,6 +380,22 @@ def remove_realm_filter(client: Client) -> None:
 | 
				
			|||||||
    validate_against_openapi_schema(result, "/realm/filters/{filter_id}", "delete", "200")
 | 
					    validate_against_openapi_schema(result, "/realm/filters/{filter_id}", "delete", "200")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@openapi_test_function("/realm/playgrounds:post")
 | 
				
			||||||
 | 
					def add_realm_playground(client: Client) -> None:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # {code_example|start}
 | 
				
			||||||
 | 
					    # Add a realm playground for Python
 | 
				
			||||||
 | 
					    request = {
 | 
				
			||||||
 | 
					        "name": "Python playground",
 | 
				
			||||||
 | 
					        "pygments_language": json.dumps("Python"),
 | 
				
			||||||
 | 
					        "url_prefix": json.dumps("https://python.example.com"),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    result = client.call_endpoint(url="/realm/playgrounds", method="POST", request=request)
 | 
				
			||||||
 | 
					    # {code_example|end}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    validate_against_openapi_schema(result, "/realm/playgrounds", "post", "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:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1417,6 +1433,7 @@ def test_server_organizations(client: Client) -> None:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    get_realm_filters(client)
 | 
					    get_realm_filters(client)
 | 
				
			||||||
    add_realm_filter(client)
 | 
					    add_realm_filter(client)
 | 
				
			||||||
 | 
					    add_realm_playground(client)
 | 
				
			||||||
    get_server_settings(client)
 | 
					    get_server_settings(client)
 | 
				
			||||||
    remove_realm_filter(client)
 | 
					    remove_realm_filter(client)
 | 
				
			||||||
    get_realm_emoji(client)
 | 
					    get_realm_emoji(client)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6567,6 +6567,60 @@ paths:
 | 
				
			|||||||
            application/json:
 | 
					            application/json:
 | 
				
			||||||
              schema:
 | 
					              schema:
 | 
				
			||||||
                $ref: "#/components/schemas/JsonSuccess"
 | 
					                $ref: "#/components/schemas/JsonSuccess"
 | 
				
			||||||
 | 
					  /realm/playgrounds:
 | 
				
			||||||
 | 
					    post:
 | 
				
			||||||
 | 
					      operationId: add_realm_playground
 | 
				
			||||||
 | 
					      tags: ["server_and_organizations"]
 | 
				
			||||||
 | 
					      description: |
 | 
				
			||||||
 | 
					        Configure realm playgrounds options to run code snippets occuring
 | 
				
			||||||
 | 
					        in a code block using playgrounds which supports that language.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        `POST {{ api_url }}/v1/realm/playgrounds`
 | 
				
			||||||
 | 
					      parameters:
 | 
				
			||||||
 | 
					        - name: name
 | 
				
			||||||
 | 
					          in: query
 | 
				
			||||||
 | 
					          description: |
 | 
				
			||||||
 | 
					            The user-visible display name of the playground which can be
 | 
				
			||||||
 | 
					            used to pick the target playground, especially when multiple
 | 
				
			||||||
 | 
					            playground options exist for that programming language.
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          example: "Python playground"
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					        - name: pygments_language
 | 
				
			||||||
 | 
					          in: query
 | 
				
			||||||
 | 
					          description: |
 | 
				
			||||||
 | 
					            The name of the Pygments language lexer for that
 | 
				
			||||||
 | 
					            programming language.
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          example: "Python"
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					        - name: url_prefix
 | 
				
			||||||
 | 
					          in: query
 | 
				
			||||||
 | 
					          description: |
 | 
				
			||||||
 | 
					            The url prefix for the playground.
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          example: https://python.example.com
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					      responses:
 | 
				
			||||||
 | 
					        "200":
 | 
				
			||||||
 | 
					          description: Success.
 | 
				
			||||||
 | 
					          content:
 | 
				
			||||||
 | 
					            application/json:
 | 
				
			||||||
 | 
					              schema:
 | 
				
			||||||
 | 
					                allOf:
 | 
				
			||||||
 | 
					                  - $ref: "#/components/schemas/JsonSuccessBase"
 | 
				
			||||||
 | 
					                  - additionalProperties: false
 | 
				
			||||||
 | 
					                    properties:
 | 
				
			||||||
 | 
					                      result: {}
 | 
				
			||||||
 | 
					                      msg: {}
 | 
				
			||||||
 | 
					                      id:
 | 
				
			||||||
 | 
					                        type: integer
 | 
				
			||||||
 | 
					                        description: |
 | 
				
			||||||
 | 
					                          The numeric ID assigned to this playground.
 | 
				
			||||||
 | 
					                    example: {"id": 1, "result": "success", "msg": ""}
 | 
				
			||||||
  /register:
 | 
					  /register:
 | 
				
			||||||
    post:
 | 
					    post:
 | 
				
			||||||
      operationId: register_queue
 | 
					      operationId: register_queue
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										95
									
								
								zerver/tests/test_realm_playgrounds.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								zerver/tests/test_realm_playgrounds.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					from typing import Dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import orjson
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from zerver.lib.test_classes import ZulipTestCase
 | 
				
			||||||
 | 
					from zerver.models import RealmPlayground, get_realm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RealmPlaygroundTests(ZulipTestCase):
 | 
				
			||||||
 | 
					    def json_serialize(self, payload: Dict[str, str]) -> Dict[str, str]:
 | 
				
			||||||
 | 
					        payload["url_prefix"] = orjson.dumps(payload["url_prefix"]).decode()
 | 
				
			||||||
 | 
					        payload["pygments_language"] = orjson.dumps(payload["pygments_language"]).decode()
 | 
				
			||||||
 | 
					        return payload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_create_one_playground_entry(self) -> None:
 | 
				
			||||||
 | 
					        iago = self.example_user("iago")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        payload = {
 | 
				
			||||||
 | 
					            "name": "Python playground",
 | 
				
			||||||
 | 
					            "pygments_language": "Python",
 | 
				
			||||||
 | 
					            "url_prefix": "https://python.example.com",
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        # Now send a POST request to the API endpoint.
 | 
				
			||||||
 | 
					        resp = self.api_post(iago, "/json/realm/playgrounds", self.json_serialize(payload))
 | 
				
			||||||
 | 
					        self.assert_json_success(resp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Check if the actual object exists
 | 
				
			||||||
 | 
					        realm = get_realm("zulip")
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            RealmPlayground.objects.filter(realm=realm, name="Python playground").exists()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_create_multiple_playgrounds_for_same_language(self) -> None:
 | 
				
			||||||
 | 
					        iago = self.example_user("iago")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data = [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "name": "Python playground 1",
 | 
				
			||||||
 | 
					                "pygments_language": "Python",
 | 
				
			||||||
 | 
					                "url_prefix": "https://python.example.com",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "name": "Python playground 2",
 | 
				
			||||||
 | 
					                "pygments_language": "Python",
 | 
				
			||||||
 | 
					                "url_prefix": "https://python2.example.com",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        for payload in data:
 | 
				
			||||||
 | 
					            resp = self.api_post(iago, "/json/realm/playgrounds", self.json_serialize(payload))
 | 
				
			||||||
 | 
					            self.assert_json_success(resp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        realm = get_realm("zulip")
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            RealmPlayground.objects.filter(realm=realm, name="Python playground 1").exists()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertTrue(
 | 
				
			||||||
 | 
					            RealmPlayground.objects.filter(realm=realm, name="Python playground 2").exists()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_invalid_params(self) -> None:
 | 
				
			||||||
 | 
					        iago = self.example_user("iago")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        payload = {
 | 
				
			||||||
 | 
					            "name": "Invalid URL",
 | 
				
			||||||
 | 
					            "pygments_language": "Python",
 | 
				
			||||||
 | 
					            "url_prefix": "https://invalid-url",
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        resp = self.api_post(iago, "/json/realm/playgrounds", self.json_serialize(payload))
 | 
				
			||||||
 | 
					        self.assert_json_error(resp, "url_prefix is not a URL")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        payload["url_prefix"] = "https://python.example.com"
 | 
				
			||||||
 | 
					        payload["pygments_language"] = "a$b$c"
 | 
				
			||||||
 | 
					        resp = self.api_post(iago, "/json/realm/playgrounds", self.json_serialize(payload))
 | 
				
			||||||
 | 
					        self.assert_json_error(resp, "Invalid characters in pygments language")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_create_already_existing_playground(self) -> None:
 | 
				
			||||||
 | 
					        iago = self.example_user("iago")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        payload = {
 | 
				
			||||||
 | 
					            "name": "Python playground",
 | 
				
			||||||
 | 
					            "pygments_language": "Python",
 | 
				
			||||||
 | 
					            "url_prefix": "https://python.example.com",
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        serialized_payload = self.json_serialize(payload)
 | 
				
			||||||
 | 
					        resp = self.api_post(iago, "/json/realm/playgrounds", serialized_payload)
 | 
				
			||||||
 | 
					        self.assert_json_success(resp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        resp = self.api_post(iago, "/json/realm/playgrounds", serialized_payload)
 | 
				
			||||||
 | 
					        self.assert_json_error(resp, "Realm playground with this Realm and Name already exists.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_not_realm_admin(self) -> None:
 | 
				
			||||||
 | 
					        hamlet = self.example_user("hamlet")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        resp = self.api_post(hamlet, "/json/realm/playgrounds")
 | 
				
			||||||
 | 
					        self.assert_json_error(resp, "Must be an organization administrator")
 | 
				
			||||||
							
								
								
									
										46
									
								
								zerver/views/realm_playgrounds.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								zerver/views/realm_playgrounds.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
 | 
					from django.http import HttpRequest, HttpResponse
 | 
				
			||||||
 | 
					from django.utils.translation import ugettext as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from zerver.decorator import require_realm_admin
 | 
				
			||||||
 | 
					from zerver.lib.actions import do_add_realm_playground
 | 
				
			||||||
 | 
					from zerver.lib.request import REQ, JsonableError, has_request_variables
 | 
				
			||||||
 | 
					from zerver.lib.response import json_error, json_success
 | 
				
			||||||
 | 
					from zerver.lib.validator import check_capped_string, check_url
 | 
				
			||||||
 | 
					from zerver.models import RealmPlayground, UserProfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def check_pygments_language(var_name: str, val: object) -> str:
 | 
				
			||||||
 | 
					    s = check_capped_string(RealmPlayground.MAX_PYGMENTS_LANGUAGE_LENGTH)(var_name, val)
 | 
				
			||||||
 | 
					    # We don't want to restrict the language here to be only from the list of valid
 | 
				
			||||||
 | 
					    # Pygments languages. Keeping it open would allow us to hook up a "playground"
 | 
				
			||||||
 | 
					    # for custom "languages" that aren't known to Pygments. We use a similar strategy
 | 
				
			||||||
 | 
					    # even in our fenced_code markdown processor.
 | 
				
			||||||
 | 
					    valid_pygments_language = re.compile(r"^[ a-zA-Z0-9_+-./#]*$")
 | 
				
			||||||
 | 
					    matched_results = valid_pygments_language.match(s)
 | 
				
			||||||
 | 
					    if not matched_results:
 | 
				
			||||||
 | 
					        raise JsonableError(_("Invalid characters in pygments language"))
 | 
				
			||||||
 | 
					    return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@require_realm_admin
 | 
				
			||||||
 | 
					@has_request_variables
 | 
				
			||||||
 | 
					def add_realm_playground(
 | 
				
			||||||
 | 
					    request: HttpRequest,
 | 
				
			||||||
 | 
					    user_profile: UserProfile,
 | 
				
			||||||
 | 
					    name: str = REQ(),
 | 
				
			||||||
 | 
					    url_prefix: str = REQ(validator=check_url),
 | 
				
			||||||
 | 
					    pygments_language: str = REQ(validator=check_pygments_language),
 | 
				
			||||||
 | 
					) -> HttpResponse:
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        playground_id = do_add_realm_playground(
 | 
				
			||||||
 | 
					            realm=user_profile.realm,
 | 
				
			||||||
 | 
					            name=name.strip(),
 | 
				
			||||||
 | 
					            pygments_language=pygments_language.strip(),
 | 
				
			||||||
 | 
					            url_prefix=url_prefix.strip(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    except ValidationError as e:
 | 
				
			||||||
 | 
					        return json_error(e.messages[0], data={"errors": dict(e)})
 | 
				
			||||||
 | 
					    return json_success({"id": playground_id})
 | 
				
			||||||
@@ -121,6 +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.registration import (
 | 
					from zerver.views.registration import (
 | 
				
			||||||
    accounts_home,
 | 
					    accounts_home,
 | 
				
			||||||
    accounts_home_from_multiuse_invite,
 | 
					    accounts_home_from_multiuse_invite,
 | 
				
			||||||
@@ -268,6 +269,8 @@ v1_api_and_json_patterns = [
 | 
				
			|||||||
    # realm/filters -> zerver.views.realm_linkifiers
 | 
					    # realm/filters -> zerver.views.realm_linkifiers
 | 
				
			||||||
    rest_path("realm/filters", GET=list_linkifiers, POST=create_linkifier),
 | 
					    rest_path("realm/filters", GET=list_linkifiers, POST=create_linkifier),
 | 
				
			||||||
    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
 | 
				
			||||||
 | 
					    rest_path("realm/playgrounds", POST=add_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",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user