diff --git a/src/app/core/config.py b/src/app/core/config.py index 35c6750..fea112a 100644 --- a/src/app/core/config.py +++ b/src/app/core/config.py @@ -30,6 +30,10 @@ class Settings(BaseSettings): POSTGRES_PORT: int = 5432 POSTGRES_DB: str + @property + def LOGIN_URL(self) -> str: + return self.SECRET_KEY[-10:] + def get_postgres_dsn(self, _async: bool=False) -> PostgresDsn: scheme = 'postgresql+asyncpg' if _async else 'postgresql' diff --git a/src/app/crud/crud_post.py b/src/app/crud/crud_post.py index 0c75c59..1972130 100644 --- a/src/app/crud/crud_post.py +++ b/src/app/crud/crud_post.py @@ -66,4 +66,13 @@ class CRUDPost(CRUDBase[Post, PostCreate, PostUpdate]): def create(self): raise DeprecationWarning("Use create_with_owner instead") + async def remove_by_slug(self, db: Session, *, slug: str) -> Post: + q = select(self.model).where(self.model.slug == slug) + obj = await db.execute(q) + obj = obj.scalar_one() + await db.delete(obj) + await db.commit() + + return obj + post = CRUDPost(Post) \ No newline at end of file diff --git a/src/app/crud/crud_user.py b/src/app/crud/crud_user.py index c588f65..fce901f 100644 --- a/src/app/crud/crud_user.py +++ b/src/app/crud/crud_user.py @@ -1,12 +1,23 @@ -from typing import Any, Dict, Optional, Union +from typing import ( + Any, + Dict, + Optional, + Union +) from sqlalchemy.orm import Session from sqlalchemy.future import select -from app.core.security import get_password_hash, verify_password +from app.core.security import ( + get_password_hash, + verify_password +) from app.crud.base import CRUDBase from app.models.user import User -from app.schemas.user import UserCreate, UserUpdate +from app.schemas.user import ( + UserCreate, + UserUpdate +) class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]): diff --git a/src/app/db/base_class.py b/src/app/db/base_class.py index df4c135..9a98a85 100644 --- a/src/app/db/base_class.py +++ b/src/app/db/base_class.py @@ -1,6 +1,9 @@ from typing import Any -from sqlalchemy.ext.declarative import as_declarative, declared_attr +from sqlalchemy.ext.declarative import ( + as_declarative, + declared_attr +) from sqlalchemy import ( DateTime, Column diff --git a/src/app/models/user.py b/src/app/models/user.py index 78f5d96..6d85ea1 100644 --- a/src/app/models/user.py +++ b/src/app/models/user.py @@ -1,4 +1,9 @@ -from sqlalchemy import Boolean, Column, Integer, String +from sqlalchemy import ( + Boolean, + Column, + Integer, + String +) from sqlalchemy.orm import relationship from app.db.base_class import Base diff --git a/src/app/schemas/post.py b/src/app/schemas/post.py index ae93056..03d6fee 100644 --- a/src/app/schemas/post.py +++ b/src/app/schemas/post.py @@ -4,13 +4,16 @@ from pydantic import ( BaseModel, Field, PastDatetime, - computed_field, - TypeAdapter + TypeAdapter, + field_validator ) +from app.utils.custom_functions import html2text + from app.core.config import settings + class PostBase(BaseModel): title: Optional[str] = Field(max_length=100) text: Optional[str] = None @@ -26,23 +29,48 @@ class PostCreate(PostBase): class PostUpdate(PostBase): ... -class PostInTemplate(PostBase): +class PostInTemplate(BaseModel): title: str text: str created_at: PastDatetime + slug: str class Config: from_attributes = True + @field_validator('text', mode='after') + @classmethod + def html_to_text(cls, v: str) -> str: + return html2text(v)[:60] + ListPostInTemplate = TypeAdapter(list[PostInTemplate]) +class PostDetail(BaseModel): + title: str + text: str + created_at: PastDatetime + image_path: str + + class Config: + from_attributes = True + + @field_validator('image_path', mode='after') + @classmethod + def absolute_image_path(cls, v: str) -> str | None: + return str( + settings.MEDIA_FOLDER / + settings.FILE_FOLDERS['post_images'] / + v + ) + + class PostInDBBase(PostBase): slug: str title: str text: str - image_path: Optional[str] = None + image_path: str owner_id: int class Config: @@ -50,14 +78,11 @@ class PostInDBBase(PostBase): class Post(PostInDBBase): - @computed_field - @property - def image_url(self) -> str | None: - if self.image_path is None: - return None - + @field_validator('image_path', mode='after') + @classmethod + def absolute_image_path(cls, v: str) -> str | None: return str( settings.MEDIA_FOLDER / settings.FILE_FOLDERS['post_images'] / - self.image_path + v ) \ No newline at end of file diff --git a/src/app/templates/admin/delete-post.html b/src/app/templates/admin/delete-post.html new file mode 100644 index 0000000..8552fdb --- /dev/null +++ b/src/app/templates/admin/delete-post.html @@ -0,0 +1,31 @@ + + + +
+ + +