-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathnews_router.py
More file actions
160 lines (113 loc) · 5.08 KB
/
Copy pathnews_router.py
File metadata and controls
160 lines (113 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import os
from pathlib import Path
from typing import Annotated
from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status
import datetime
from fastapi.responses import FileResponse
from sqlalchemy import and_
from api_schemas.news_schemas import NewsCreate, NewsRead, NewsUpdate
from database import DB_dependency
from db_models.news_model import News_DB
from db_models.user_model import User_DB
from helpers.constants import NEWS_PER_PAGE
from helpers.image_checker import validate_image
from helpers.rate_limit import rate_limit
from helpers.types import ALLOWED_EXT, ALLOWED_IMG_SIZES, ALLOWED_IMG_TYPES, ASSETS_BASE_PATH
from services.news_service import create_new_news, update_existing_news, bump_existing_news
from user.permission import Permission
news_router = APIRouter()
@news_router.get("/all", response_model=list[NewsRead])
def get_all_news(db: DB_dependency):
news = db.query(News_DB).order_by(News_DB.bumped_at.desc()).all()
return news
@news_router.get("/{news_id}", response_model=NewsRead)
def get_news(news_id: int, db: DB_dependency):
news = db.query(News_DB).filter_by(id=news_id).one_or_none()
if news is None:
raise HTTPException(status.HTTP_404_NOT_FOUND)
return news
@news_router.post("/", response_model=NewsRead)
def create_news(data: NewsCreate, author: Annotated[User_DB, Permission.require("manage", "News")], db: DB_dependency):
news = create_new_news(data, author.id, db)
return news
@news_router.post("/{news_id}/image", dependencies=[Permission.require("manage", "News"), Depends(rate_limit())])
async def post_news_image(news_id: int, db: DB_dependency, image: UploadFile = File()):
news = db.query(News_DB).get(news_id)
if not news:
raise HTTPException(404, "No event found")
if image:
await validate_image(image)
filename: str = str(image.filename)
_, ext = os.path.splitext(filename)
ext = ext.lower()
if ext not in ALLOWED_EXT:
raise HTTPException(400, "file extension not allowed")
dest_path = Path(f"{ASSETS_BASE_PATH}/news/{news.id}{ext}")
news.image_exist = True
try:
dest_path.write_bytes(image.file.read())
except:
news.image_exist = False
db.commit()
@news_router.get("/{news_id}/image/stream", dependencies=[Depends(rate_limit(limit=100))])
def get_news_image_stream(news_id: int, db: DB_dependency):
news = db.query(News_DB).get(news_id)
if not news:
raise HTTPException(404, "No image for this news")
asset_dir = Path(f"{ASSETS_BASE_PATH}") / "news"
matches = list(asset_dir.glob(f"{news.id}.*"))
if not matches:
raise HTTPException(404, "Image not found")
filename = matches[0].name
internal = f"/{ASSETS_BASE_PATH}/news/{filename}"
return FileResponse(internal)
@news_router.get("/{news_id}/image/{size}", dependencies=[Depends(rate_limit(limit=100))])
def get_news_image(news_id: int, size: ALLOWED_IMG_TYPES, db: DB_dependency):
dims = ALLOWED_IMG_SIZES[size]
news = db.query(News_DB).get(news_id)
if not news:
raise HTTPException(404, "No image for this news")
asset_dir = Path(f"{ASSETS_BASE_PATH}") / "news"
matches = list(asset_dir.glob(f"{news.id}.*"))
if not matches:
raise HTTPException(404, "Image not found")
filename = matches[0].name
internal = f"/internal/{dims}{ASSETS_BASE_PATH}/news/{filename}"
return Response(status_code=200, headers={"X-Accel-Redirect": internal})
@news_router.delete(
"/{news_id}",
dependencies=[Permission.require("manage", "News")],
status_code=status.HTTP_204_NO_CONTENT,
)
def delete_news(news_id: int, db: DB_dependency):
news = db.query(News_DB).filter_by(id=news_id).one_or_none()
if news is None:
raise HTTPException(status.HTTP_404_NOT_FOUND)
db.delete(news)
db.commit()
return
@news_router.patch("/{news_id}", dependencies=[Permission.require("manage", "News")], response_model=NewsRead)
def update_news(news_id: int, updated_news: NewsUpdate, db: DB_dependency):
news = update_existing_news(news_id, updated_news, db)
return news
@news_router.patch("/bump/{news_id}", dependencies=[Permission.require("manage", "News")], response_model=NewsRead)
def bump_news(news_id: int, db: DB_dependency):
news = bump_existing_news(news_id, db)
return news
@news_router.get("/page/{page_nbr}", response_model=list[NewsRead])
def get_paginated_news(page_nbr: int, db: DB_dependency):
if page_nbr < 0:
raise HTTPException(400, detail="Invalid page number")
offset = page_nbr * NEWS_PER_PAGE
paginated_news = db.query(News_DB).order_by(News_DB.bumped_at.desc()).offset(offset).limit(NEWS_PER_PAGE).all()
return paginated_news
@news_router.get("/pinned/", response_model=list[NewsRead])
def get_pinned_news(db: DB_dependency):
now = datetime.datetime.now(datetime.UTC)
pinned_news = (
db.query(News_DB)
.filter(and_(News_DB.pinned_from < now, News_DB.pinned_to > now))
.order_by(News_DB.bumped_at.desc())
.all()
)
return pinned_news