mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			89 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from typing import List
 | 
						|
 | 
						|
import uri_template
 | 
						|
from django.core.exceptions import ValidationError
 | 
						|
from django.core.validators import RegexValidator
 | 
						|
from django.db import models
 | 
						|
from django.db.models import CASCADE
 | 
						|
from django.utils.translation import gettext as _
 | 
						|
from typing_extensions import override
 | 
						|
 | 
						|
from zerver.lib.types import RealmPlaygroundDict
 | 
						|
from zerver.models.linkifiers import url_template_validator
 | 
						|
from zerver.models.realms import Realm
 | 
						|
 | 
						|
 | 
						|
class RealmPlayground(models.Model):
 | 
						|
    """Server side storage model to store playground information needed by our
 | 
						|
    'view code in playground' feature in code blocks.
 | 
						|
    """
 | 
						|
 | 
						|
    MAX_PYGMENTS_LANGUAGE_LENGTH = 40
 | 
						|
 | 
						|
    realm = models.ForeignKey(Realm, on_delete=CASCADE)
 | 
						|
    url_template = models.TextField(validators=[url_template_validator])
 | 
						|
 | 
						|
    # User-visible display name used when configuring playgrounds in the settings page and
 | 
						|
    # when displaying them in the playground links popover.
 | 
						|
    name = models.TextField(db_index=True)
 | 
						|
 | 
						|
    # This stores the pygments lexer subclass names and not the aliases themselves.
 | 
						|
    pygments_language = models.CharField(
 | 
						|
        db_index=True,
 | 
						|
        max_length=MAX_PYGMENTS_LANGUAGE_LENGTH,
 | 
						|
        # We validate to see if this conforms to the character set allowed for a
 | 
						|
        # language in the code block.
 | 
						|
        validators=[
 | 
						|
            RegexValidator(
 | 
						|
                regex=r"^[ a-zA-Z0-9_+-./#]*$", message=_("Invalid characters in pygments language")
 | 
						|
            )
 | 
						|
        ],
 | 
						|
    )
 | 
						|
 | 
						|
    class Meta:
 | 
						|
        unique_together = (("realm", "pygments_language", "name"),)
 | 
						|
 | 
						|
    @override
 | 
						|
    def __str__(self) -> str:
 | 
						|
        return f"{self.realm.string_id}: {self.pygments_language} {self.name}"
 | 
						|
 | 
						|
    @override
 | 
						|
    def clean(self) -> None:
 | 
						|
        """Validate whether the URL template is valid for the playground,
 | 
						|
        ensuring that "code" is the sole variable present in it.
 | 
						|
 | 
						|
        Django's `full_clean` calls `clean_fields` followed by `clean` method
 | 
						|
        and stores all ValidationErrors from all stages to return as JSON.
 | 
						|
        """
 | 
						|
 | 
						|
        # Do not continue the check if the url template is invalid to begin
 | 
						|
        # with. The ValidationError for invalid template will only be raised by
 | 
						|
        # the validator set on the url_template field instead of here to avoid
 | 
						|
        # duplicates.
 | 
						|
        if not uri_template.validate(self.url_template):
 | 
						|
            return
 | 
						|
 | 
						|
        # Extract variables used in the URL template.
 | 
						|
        template_variables = set(uri_template.URITemplate(self.url_template).variable_names)
 | 
						|
 | 
						|
        if "code" not in template_variables:
 | 
						|
            raise ValidationError(_('Missing the required variable "code" in the URL template'))
 | 
						|
 | 
						|
        # The URL template should only contain a single variable, which is "code".
 | 
						|
        if len(template_variables) != 1:
 | 
						|
            raise ValidationError(
 | 
						|
                _('"code" should be the only variable present in the URL template'),
 | 
						|
            )
 | 
						|
 | 
						|
 | 
						|
def get_realm_playgrounds(realm: Realm) -> List[RealmPlaygroundDict]:
 | 
						|
    return [
 | 
						|
        RealmPlaygroundDict(
 | 
						|
            id=playground.id,
 | 
						|
            name=playground.name,
 | 
						|
            pygments_language=playground.pygments_language,
 | 
						|
            url_template=playground.url_template,
 | 
						|
        )
 | 
						|
        for playground in RealmPlayground.objects.filter(realm=realm).all()
 | 
						|
    ]
 |