# Copyright 2024 The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.
"""Data models for db scopes."""
import re
from django.core.exceptions import ValidationError
from django.db import models
#: Name of the fallback scope used for transitioning to scoped models
FALLBACK_SCOPE_NAME = "debusine"
#: Scope names reserved for use in toplevel URL path components
RESERVED_SCOPE_NAMES = frozenset(
(
"accounts",
"admin",
"api",
"api-auth",
"artifact",
"task-status",
"user",
"workers",
"work-request",
"workspace",
)
)
#: Regexp matching the structure of scope names
scope_name_regex = re.compile(r"^[A-Za-z][A-Za-z0-9+._-]*$")
def is_valid_scope_name(value: str) -> bool:
"""Check if value is a valid scope name."""
if value in RESERVED_SCOPE_NAMES:
return False
return bool(scope_name_regex.match(value))
def validate_scope_name(value: str) -> None:
"""Validate scope names."""
if not is_valid_scope_name(value):
raise ValidationError(
"%(value)r is not a valid scope name", params={"value": value}
)
[docs]class Scope(models.Model):
"""
Scope model.
This is used to create different distinct sets of groups and workspaces
"""
name = models.CharField(
max_length=255, unique=True, validators=[validate_scope_name]
)
def __str__(self) -> str:
"""Return basic information of Scope."""
return self.name