98 lines
3.2 KiB
Python
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"}
|