blog.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. from fastapi import APIRouter, Depends, HTTPException, Request
  2. from typing import List, Optional
  3. from pydantic import BaseModel
  4. from datetime import datetime
  5. import db
  6. import mysql.connector
  7. import auth_utils
  8. router = APIRouter(prefix="/blog", tags=["blog"])
  9. class PostBase(BaseModel):
  10. slug: str
  11. title_en: str
  12. title_me: Optional[str] = None
  13. title_ru: Optional[str] = None
  14. title_ua: Optional[str] = None
  15. excerpt_en: Optional[str] = None
  16. excerpt_me: Optional[str] = None
  17. excerpt_ru: Optional[str] = None
  18. excerpt_ua: Optional[str] = None
  19. content_en: str
  20. content_me: Optional[str] = None
  21. content_ru: Optional[str] = None
  22. content_ua: Optional[str] = None
  23. category: Optional[str] = None
  24. image_url: Optional[str] = None
  25. is_published: bool = False
  26. class PostCreate(PostBase):
  27. pass
  28. class PostUpdate(PostBase):
  29. pass
  30. class Post(PostBase):
  31. id: int
  32. created_at: datetime
  33. updated_at: datetime
  34. class Config:
  35. from_attributes = True
  36. @router.get("/", response_model=List[Post])
  37. async def get_posts(published_only: bool = True):
  38. query = "SELECT * FROM posts"
  39. if published_only:
  40. query += " WHERE is_published = TRUE"
  41. query += " ORDER BY created_at DESC"
  42. return db.execute_query(query)
  43. @router.get("/{id_or_slug}", response_model=Post)
  44. async def get_post(id_or_slug: str):
  45. # Try by slug first
  46. res = db.execute_query("SELECT * FROM posts WHERE slug = %s", (id_or_slug,))
  47. if res: return res[0]
  48. # If not found, try by ID if it looks like an int
  49. if id_or_slug.isdigit():
  50. res = db.execute_query("SELECT * FROM posts WHERE id = %s", (int(id_or_slug),))
  51. if res: return res[0]
  52. raise HTTPException(status_code=404, detail="Post not found")
  53. @router.post("/", response_model=Post)
  54. async def create_post(post: PostCreate, token: str = Depends(auth_utils.oauth2_scheme)):
  55. payload = auth_utils.decode_token(token)
  56. if not payload or payload.get("role") != 'admin':
  57. raise HTTPException(status_code=403, detail="Admin role required")
  58. query = """
  59. INSERT INTO posts (
  60. slug, title_en, title_me, title_ru, title_ua,
  61. excerpt_en, excerpt_me, excerpt_ru, excerpt_ua,
  62. content_en, content_me, content_ru, content_ua,
  63. category, image_url, is_published
  64. ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
  65. """
  66. values = (
  67. post.slug, post.title_en, post.title_me, post.title_ru, post.title_ua,
  68. post.excerpt_en, post.excerpt_me, post.excerpt_ru, post.excerpt_ua,
  69. post.content_en, post.content_me, post.content_ru, post.content_ua,
  70. post.category, post.image_url, post.is_published
  71. )
  72. try:
  73. new_id = db.execute_commit(query, values)
  74. res = db.execute_query("SELECT * FROM posts WHERE id = %s", (new_id,))
  75. return res[0]
  76. except mysql.connector.Error as err:
  77. raise HTTPException(status_code=400, detail=str(err))
  78. @router.put("/{post_id}", response_model=Post)
  79. async def update_post(post_id: int, post: PostUpdate, token: str = Depends(auth_utils.oauth2_scheme)):
  80. payload = auth_utils.decode_token(token)
  81. if not payload or payload.get("role") != 'admin':
  82. raise HTTPException(status_code=403, detail="Admin role required")
  83. query = """
  84. UPDATE posts SET
  85. slug=%s, title_en=%s, title_me=%s, title_ru=%s, title_ua=%s,
  86. excerpt_en=%s, excerpt_me=%s, excerpt_ru=%s, excerpt_ua=%s,
  87. content_en=%s, content_me=%s, content_ru=%s, content_ua=%s,
  88. category=%s, image_url=%s, is_published=%s
  89. WHERE id = %s
  90. """
  91. values = (
  92. post.slug, post.title_en, post.title_me, post.title_ru, post.title_ua,
  93. post.excerpt_en, post.excerpt_me, post.excerpt_ru, post.excerpt_ua,
  94. post.content_en, post.content_me, post.content_ru, post.content_ua,
  95. post.category, post.image_url, post.is_published, post_id
  96. )
  97. db.execute_commit(query, values)
  98. res = db.execute_query("SELECT * FROM posts WHERE id = %s", (post_id,))
  99. if not res:
  100. raise HTTPException(status_code=404, detail="Post not found")
  101. return res[0]
  102. @router.delete("/{post_id}")
  103. async def delete_post(post_id: int, token: str = Depends(auth_utils.oauth2_scheme)):
  104. payload = auth_utils.decode_token(token)
  105. if not payload or payload.get("role") != 'admin':
  106. raise HTTPException(status_code=403, detail="Admin role required")
  107. # We don't easily get rowcount from execute_commit as I wrote it,
  108. # but we can check existence first or modify execute_commit.
  109. # For now, let's just execute it.
  110. db.execute_commit("DELETE FROM posts WHERE id = %s", (post_id,))
  111. return {"message": "Post deleted successfully"}