Files
2025-12-06 00:20:09 +05:00

98 lines
3.2 KiB
Python

from datetime import datetime
from typing import List, Optional
from fastapi import HTTPException
from app.db.database import db
from bson import ObjectId
from app.models.news import NewsCreate, NewsUpdate, NewsInDB
news_collection = db["news"]
class NewsService:
@staticmethod
def _to_news_in_db(doc) -> NewsInDB:
return NewsInDB(
id=str(doc["_id"]),
title=doc["title"],
markdown=doc["markdown"],
preview=doc.get("preview"),
tags=doc.get("tags", []),
is_published=doc.get("is_published", True),
created_at=doc["created_at"],
updated_at=doc["updated_at"],
)
async def list_news(self, limit: int = 20, skip: int = 0, include_unpublished: bool = False) -> List[NewsInDB]:
query = {}
if not include_unpublished:
query["is_published"] = True
cursor = (
news_collection
.find(query)
.sort("created_at", -1)
.skip(skip)
.limit(limit)
)
docs = await cursor.to_list(length=limit)
return [self._to_news_in_db(d) for d in docs]
async def get_news(self, news_id: str) -> NewsInDB:
try:
oid = ObjectId(news_id)
except:
raise HTTPException(status_code=400, detail="Invalid news id")
doc = await news_collection.find_one({"_id": oid})
if not doc:
raise HTTPException(status_code=404, detail="News not found")
return self._to_news_in_db(doc)
async def create_news(self, payload: NewsCreate) -> NewsInDB:
now = datetime.utcnow()
doc = {
"title": payload.title,
"markdown": payload.markdown,
"preview": payload.preview,
"tags": payload.tags,
"is_published": payload.is_published,
"created_at": now,
"updated_at": now,
}
result = await news_collection.insert_one(doc)
doc["_id"] = result.inserted_id
return self._to_news_in_db(doc)
async def update_news(self, news_id: str, payload: NewsUpdate) -> NewsInDB:
try:
oid = ObjectId(news_id)
except:
raise HTTPException(status_code=400, detail="Invalid news id")
update_data = {k: v for k, v in payload.dict(exclude_unset=True).items()}
if not update_data:
return await self.get_news(news_id)
update_data["updated_at"] = datetime.utcnow()
result = await news_collection.find_one_and_update(
{"_id": oid},
{"$set": update_data},
return_document=True,
)
if not result:
raise HTTPException(status_code=404, detail="News not found")
return self._to_news_in_db(result)
async def delete_news(self, news_id: str):
try:
oid = ObjectId(news_id)
except:
raise HTTPException(status_code=400, detail="Invalid news id")
result = await news_collection.delete_one({"_id": oid})
if result.deleted_count == 0:
raise HTTPException(status_code=404, detail="News not found")
return {"status": "success"}