Source code for fmn.api.api_models

# SPDX-FileCopyrightText: Contributors to the Fedora Project
#
# SPDX-License-Identifier: MIT

import logging
import re
from typing import Annotated, Any, Generic, Literal, TypeVar

from pydantic import BaseModel as PydanticBaseModel
from pydantic import Field, validator
from pydantic.generics import GenericModel
from pydantic.utils import GetterDict

from ..core.constants import ArtifactType

log = logging.getLogger(__name__)


[docs]class BaseModel(PydanticBaseModel):
[docs] class Config: orm_mode = True
# Tracking rules with specific types for params
[docs]class ListParamTrackingRule(BaseModel): name: Literal["artifacts-owned", "artifacts-group-owned", "users-followed"] params: list[str]
[docs]class NoParamTrackingRule(BaseModel): name: Literal["related-events"] params: str | None
[docs]class ArtifactsFollowedTrackingRule(BaseModel): name: Literal["artifacts-followed"] params: list[dict[Literal["name", "type"], str]]
TrackingRule = Annotated[ ListParamTrackingRule | NoParamTrackingRule | ArtifactsFollowedTrackingRule, Field(discriminator="name"), ] # DB models EMAIL_ADDRESS_RE = re.compile(r"[\w_.-]+@[\w.-]+") MATRIX_ADDRESS_RE = re.compile(r"@[\w_-]+:[\w.-]+")
[docs]class Destination(BaseModel): protocol: str address: str
[docs] @validator("address") def address_format(cls, v, values): if values["protocol"] == "email" and not EMAIL_ADDRESS_RE.match(v): raise ValueError("The email address does not look right") elif values["protocol"] == "matrix" and not MATRIX_ADDRESS_RE.match(v): raise ValueError("The Matrix address should be in the form @username:server.tld") return v
[docs]class Filters(BaseModel): applications: list[str] = [] severities: list[str] = [] topic: str | None = None my_actions: bool = False
[docs]class GRGetterDict(GetterDict):
[docs] def get(self, key: str, default: Any) -> Any: if key == "filters": return {f.name: f.params for f in self._obj.filters} return super().get(key, default)
[docs]class GenerationRule(BaseModel): id: int | None destinations: list[Destination] filters: Filters
[docs] class Config: getter_dict = GRGetterDict
[docs]class User(BaseModel): id: int | None name: str is_admin: bool = False
[docs]class NewRule(BaseModel): name: str | None = None disabled: bool = False tracking_rule: TrackingRule generation_rules: list[GenerationRule]
[docs]class Rule(NewRule): id: int user: User generated_last_week: int = 0
[docs]class RulePatch(BaseModel): disabled: bool | None = None
# Dropdown options T = TypeVar("T")
[docs]class Option(GenericModel, Generic[T]): label: str value: T
[docs]class Artifact(BaseModel): type: ArtifactType name: str
[docs]class ArtifactOptionsGroup(BaseModel): label: str options: list[Option[Artifact]]