1
0
mirror of https://codeberg.org/diginaut/digimarks.git synced 2026-03-22 06:20:49 +01:00
Files
digimarks/src/digimarks/models.py

108 lines
3.0 KiB
Python

"""Models for digimarks.
Contains the bookmarks administration, users, tags, public tags and more.
"""
from datetime import UTC, datetime
from http import HTTPStatus
from typing import TypeVar
from pydantic import AnyUrl, computed_field
from sqlmodel import AutoString, Field, SQLModel
DEFAULT_THEME = 'freshgreen'
class User(SQLModel, table=True):
"""User account."""
id: int = Field(primary_key=True)
username: str
key: str
theme: str = Field(default=DEFAULT_THEME)
created_date: datetime
class Visibility:
"""Options for visibility of an object."""
VISIBLE: int = 0
DELETED: int = 1
HIDDEN: int = 2
# Type var used for building custom types for the DB
T = TypeVar('T')
def build_custom_type(internal_type: type[T]) -> type[AutoString]:
"""Create a type that is compatible with the database.
Based on https://github.com/fastapi/sqlmodel/discussions/847
"""
class CustomType(AutoString):
def process_bind_param(self, value, dialect) -> str | None:
if value is None:
return None
if isinstance(value, str):
# Test if value is valid to avoid `process_result_value` failing
try:
internal_type(value) # type: ignore[call-arg]
except ValueError as e:
raise ValueError(f'Invalid value for {internal_type.__name__}: {e}') from e
return str(value)
def process_result_value(self, value, dialect) -> T | None:
if value is None:
return None
return internal_type(value) # type: ignore[call-arg]
return CustomType
class Bookmark(SQLModel, table=True):
"""Bookmark object."""
id: int = Field(primary_key=True)
user_key: str = Field(foreign_key='user.key', nullable=False)
title: str = Field(default='', nullable=False)
url: AnyUrl = Field(default='', sa_type=build_custom_type(AnyUrl))
note: str = Field(default='', nullable=True)
# image: str = Field(default='')
url_hash: str = Field(default='', nullable=False)
tags: str = Field(default='')
starred: bool = Field(default=False)
favicon: str | None = Field(default=None)
http_status: int = Field(default=HTTPStatus.OK)
created_date: datetime = Field(default=datetime.now(UTC))
modified_date: datetime = Field(default=None, nullable=True)
deleted_date: datetime = Field(default=None, nullable=True)
status: int = Field(default=Visibility.VISIBLE)
@computed_field
@property
def tag_list(self) -> list[str]:
"""The tags but as a proper list."""
if self.tags:
return self.tags.split(',')
# Not tags, return empty list instead of [''] that split returns in that case
return []
class PublicTag(SQLModel, table=True):
"""Public tag object."""
id: int = Field(primary_key=True)
tag_key: str
user_key: str = Field(foreign_key='user.key')
tag: str
created_date: datetime = Field(default=datetime.now(UTC))