chore: small change in api.

This commit is contained in:
EstrellaXD
2023-08-08 14:12:19 +08:00
parent 1c4e8dc293
commit 69a4daca0c
15 changed files with 115 additions and 69 deletions

View File

@@ -6,6 +6,7 @@ from .config import router as config_router
from .download import router as download_router
from .log import router as log_router
from .program import router as program_router
from .rss import router as rss_router
__all__ = "v1"
@@ -17,3 +18,4 @@ v1.include_router(program_router)
v1.include_router(download_router)
v1.include_router(bangumi_router)
v1.include_router(config_router)
v1.include_router(rss_router)

View File

@@ -3,7 +3,7 @@ from datetime import timedelta
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from module.models.user import User
from module.models.user import User, UserUpdate
from module.security.api import (
auth_user,
get_current_user,
@@ -16,10 +16,11 @@ router = APIRouter(prefix="/auth", tags=["auth"])
@router.post("/login", response_model=dict)
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
username = form_data.username
password = form_data.password
auth_user(username, password)
token = create_access_token(data={"sub": username}, expires_delta=timedelta(days=1))
user = User(username=form_data.username, password=form_data.password)
auth_user(user)
token = create_access_token(
data={"sub": user.username}, expires_delta=timedelta(days=1)
)
return {"access_token": token, "token_type": "bearer", "expire": 86400}
@@ -44,7 +45,9 @@ async def logout(current_user: User = Depends(get_current_user)):
@router.post("/update", response_model=dict)
async def update_user(user_data: User, current_user: User = Depends(get_current_user)):
async def update_user(
user_data: UserUpdate, current_user: User = Depends(get_current_user)
):
if not current_user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"

View File

@@ -2,13 +2,13 @@ from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.responses import JSONResponse
from module.manager import TorrentManager
from module.models import Bangumi
from module.models import Bangumi, BangumiUpdate
from module.security.api import get_current_user
router = APIRouter(prefix="/bangumi", tags=["bangumi"])
@router.get("/getAll", response_model=list[Bangumi])
@router.get("/get/all", response_model=list[Bangumi])
async def get_all_data(current_user=Depends(get_current_user)):
if not current_user:
raise HTTPException(
@@ -18,7 +18,7 @@ async def get_all_data(current_user=Depends(get_current_user)):
return manager.bangumi.search_all()
@router.get("/getData/{bangumi_id}", response_model=Bangumi)
@router.get("/get/{bangumi_id}", response_model=Bangumi)
async def get_data(bangumi_id: str, current_user=Depends(get_current_user)):
if not current_user:
raise HTTPException(
@@ -28,17 +28,19 @@ async def get_data(bangumi_id: str, current_user=Depends(get_current_user)):
return manager.search_one(bangumi_id)
@router.post("/updateRule")
async def update_rule(data: Bangumi, current_user=Depends(get_current_user)):
@router.patch("/update/{bangumi_id}")
async def update_rule(
bangumi_id: int, data: BangumiUpdate, current_user=Depends(get_current_user)
):
if not current_user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
)
with TorrentManager() as manager:
return manager.update_rule(data)
return manager.update_rule(bangumi_id, data)
@router.delete("/deleteRule/{bangumi_id}")
@router.delete("/delete/{bangumi_id}")
async def delete_rule(
bangumi_id: str, file: bool = False, current_user=Depends(get_current_user)
):
@@ -50,7 +52,7 @@ async def delete_rule(
return manager.delete_rule(bangumi_id, file)
@router.delete("/disableRule/{bangumi_id}")
@router.delete("/disable/{bangumi_id}")
async def disable_rule(
bangumi_id: str, file: bool = False, current_user=Depends(get_current_user)
):
@@ -62,7 +64,7 @@ async def disable_rule(
return manager.disable_rule(bangumi_id, file)
@router.get("/enableRule/{bangumi_id}")
@router.get("/enable/{bangumi_id}")
async def enable_rule(bangumi_id: str, current_user=Depends(get_current_user)):
if not current_user:
raise HTTPException(
@@ -72,7 +74,7 @@ async def enable_rule(bangumi_id: str, current_user=Depends(get_current_user)):
return manager.enable_rule(bangumi_id)
@router.get("/resetAll")
@router.get("/reset/all")
async def reset_all(current_user=Depends(get_current_user)):
if not current_user:
raise HTTPException(

View File

@@ -1,7 +1,6 @@
import logging
import os
import signal
import sys
from fastapi import APIRouter, Depends, HTTPException, status

View File

@@ -1,9 +1,9 @@
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.responses import JSONResponse
from module.models import RSSItem
from module.models import RSSItem, RSSUpdate
from module.rss import RSSEngine
from module.security import get_current_user
from module.security.api import get_current_user
from module.downloader import DownloadClient
@@ -20,34 +20,36 @@ async def get_rss(current_user=Depends(get_current_user)):
return engine.rss.search_all()
@router.delete("/delete/{id}")
async def delete_rss(_id: int, current_user=Depends(get_current_user)):
@router.delete("/delete/{rss_id}")
async def delete_rss(rss_id: int, current_user=Depends(get_current_user)):
if not current_user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
)
with RSSEngine() as engine:
result = engine.rss.delete(_id)
result = engine.rss.delete(rss_id)
if result:
return JSONResponse(
status_code=status.HTTP_200_OK,
content={"status": f"Success deleted {_id}"},
content={"status": f"Success deleted {rss_id}"},
)
else:
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"status": f"Failed to delete {_id}"},
content={"status": f"Failed to delete {rss_id}"},
)
@router.put("/update/{id}")
async def update_rss(data: RSSItem, current_user=Depends(get_current_user)):
@router.patch("/update/{rss_id}")
async def update_rss(
rss_id: int, data: RSSUpdate, current_user=Depends(get_current_user)
):
if not current_user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
)
with RSSEngine() as engine:
result = engine.rss.update(data)
result = engine.rss.update(rss_id, data)
if result:
return JSONResponse(
status_code=status.HTTP_200_OK,
@@ -66,8 +68,8 @@ async def refresh_all(current_user=Depends(get_current_user)):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
)
with RSSEngine() as engine:
response = engine.refresh_rss()
with RSSEngine() as engine, DownloadClient() as client:
response = engine.refresh_rss(client)
if response:
return JSONResponse(
status_code=status.HTTP_200_OK,
@@ -80,21 +82,21 @@ async def refresh_all(current_user=Depends(get_current_user)):
)
@router.get("/refresh/{id}")
async def refresh_rss(_id: int, current_user=Depends(get_current_user)):
@router.get("/refresh/{rss_id}")
async def refresh_rss(rss_id: int, current_user=Depends(get_current_user)):
if not current_user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid token"
)
with RSSEngine() as engine:
response = engine.refresh_rss(_id)
with RSSEngine() as engine, DownloadClient() as client:
response = engine.refresh_rss(client, rss_id)
if response:
return JSONResponse(
status_code=status.HTTP_200_OK,
content={"status": f"Success refresh {_id}"},
content={"status": f"Success refresh {rss_id}"},
)
else:
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"status": f"Failed to refresh {_id}"},
)
content={"status": f"Failed to refresh {rss_id}"},
)

View File

@@ -2,8 +2,7 @@ import logging
from sqlmodel import Session, select, delete
from .engine import engine
from module.models import RSSItem
from module.models import RSSItem, RSSUpdate
logger = logging.getLogger(__name__)
@@ -25,12 +24,21 @@ class RSSDatabase:
self.session.commit()
self.session.refresh(data)
def update(self, data: RSSItem):
self.session.add(data)
def update(self, _id: int, data: RSSUpdate):
# Check if exists
statement = select(RSSItem).where(RSSItem.id == _id)
db_data = self.session.exec(statement).first()
if not db_data:
return False
# Update
dict_data = data.dict(exclude_unset=True)
for key, value in dict_data.items():
setattr(db_data, key, value)
self.session.add(db_data)
self.session.commit()
self.session.refresh(data)
self.session.refresh(db_data)
return True
# TODO: Check if this is needed
def search_id(self, _id: int) -> RSSItem:
return self.session.get(RSSItem, _id)

View File

@@ -20,7 +20,7 @@ class UserDatabase:
raise HTTPException(status_code=404, detail="User not found")
return result
def auth_user(self, user: UserLogin) -> bool:
def auth_user(self, user: User) -> bool:
statement = select(User).where(User.username == user.username)
result = self.session.exec(statement).first()
if not result:

View File

@@ -4,7 +4,7 @@ import re
from pathlib import Path
from module.conf import settings
from module.models import Bangumi
from module.models import Bangumi, BangumiUpdate
logger = logging.getLogger(__name__)
@@ -49,7 +49,7 @@ class TorrentPath:
return self._file_depth(file_path) <= 2
@staticmethod
def _gen_save_path(data: Bangumi):
def _gen_save_path(data: Bangumi | BangumiUpdate):
folder = (
f"{data.official_title} ({data.year})" if data.year else data.official_title
)

View File

@@ -4,14 +4,14 @@ from fastapi.responses import JSONResponse
from module.database import Database
from module.downloader import DownloadClient
from module.models import Bangumi
from module.models import Bangumi, BangumiUpdate
logger = logging.getLogger(__name__)
class TorrentManager(Database):
@staticmethod
def __match_torrents_list(data: Bangumi) -> list:
def __match_torrents_list(data: Bangumi | BangumiUpdate) -> list:
with DownloadClient() as client:
torrents = client.get_torrent_info(status_filter=None)
return [
@@ -97,16 +97,14 @@ class TorrentManager(Database):
status_code=406, content={"msg": f"Can't find bangumi id {_id}"}
)
def update_rule(self, data: Bangumi):
old_data = self.bangumi.search_id(data.id)
def update_rule(self, bangumi_id, data: BangumiUpdate):
old_data = self.bangumi.search_id(bangumi_id)
if not old_data:
logger.error(f"[Manager] Can't find data with {data.id}")
return JSONResponse(
status_code=406, content={"msg": f"Can't find data with {data.id}"}
)
logger.error(f"[Manager] Can't find data with {bangumi_id}")
return {"status": False, "msg": f"Can't find data with {bangumi_id}"}
else:
# Move torrent
match_list = self.__match_torrents_list(data)
match_list = self.__match_torrents_list(old_data.save_path)
with DownloadClient() as client:
path = client._gen_save_path(data)
if match_list:

View File

@@ -43,7 +43,7 @@ class BangumiUpdate(SQLModel):
subtitle: Optional[str] = Field(alias="subtitle", title="字幕")
eps_collect: bool = Field(default=False, alias="eps_collect", title="是否已收集")
offset: int = Field(default=0, alias="offset", title="番剧偏移量")
filter: str = Field(default="720, \\d+-\\d+", alias="filter", title="番剧过滤器")
filter: str = Field(default="720,\\d+-\\d+", alias="filter", title="番剧过滤器")
rss_link: str = Field(default="", alias="rss_link", title="番剧RSS链接")
poster_link: Optional[str] = Field(alias="poster_link", title="番剧海报链接")
added: bool = Field(default=False, alias="added", title="是否已添加")

View File

@@ -0,0 +1,8 @@
from pydantic import BaseModel, Field
class ResponseModel(BaseModel):
status: bool = Field(..., example=True)
status_code: int = Field(..., example=200)
msg_en: str
msg_zh: str

View File

@@ -58,6 +58,7 @@ class RSSEngine(Database):
rss_item = self.rss.search_id(rss_id)
rss_items = [rss_item] if rss_item else []
# From RSS Items, get all torrents
logger.debug(f"[Engine] Get {len(rss_items)} RSS items")
for rss_item in rss_items:
new_torrents = self.pull_rss(rss_item)
# Get all enabled bangumi data
@@ -65,6 +66,7 @@ class RSSEngine(Database):
matched_data = self.match_torrent(torrent)
if matched_data:
if client.add_torrent(torrent, matched_data):
logger.debug(f"[Engine] Add torrent {torrent.name} to client")
torrent.downloaded = True
# Add all torrents to database
self.torrent.add_all(new_torrents)

View File

@@ -2,7 +2,7 @@ from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from module.database import Database
from module.models.user import User
from module.models.user import User, UserUpdate
from .jwt import verify_token
@@ -38,7 +38,7 @@ async def get_token_data(token: str = Depends(oauth2_scheme)):
return payload
def update_user_info(user_data: User, current_user):
def update_user_info(user_data: UserUpdate, current_user):
try:
with Database() as db:
db.user.update_user(current_user.username, user_data)
@@ -47,6 +47,6 @@ def update_user_info(user_data: User, current_user):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
def auth_user(username, password):
def auth_user(user: User):
with Database() as db:
db.user.auth_user(username, password)
db.user.auth_user(user)

View File

@@ -1,4 +1,4 @@
import type { BangumiRule } from '#/bangumi';
import type { BangumiRule, BangumiUpdate } from '#/bangumi';
import type { ApiSuccess } from '#/api';
export const apiBangumi = {
@@ -7,7 +7,7 @@ export const apiBangumi = {
* @returns 所有 bangumi 数据
*/
async getAll() {
const { data } = await axios.get<BangumiRule[]>('api/v1/bangumi/getAll');
const { data } = await axios.get<BangumiRule[]>('api/v1/bangumi/get/all');
return data;
},
@@ -19,7 +19,7 @@ export const apiBangumi = {
*/
async getRule(bangumiId: number) {
const { data } = await axios.get<BangumiRule>(
`api/v1/bangumi/getRule/${bangumiId}`
`api/v1/bangumi/get/${bangumiId}`
);
return data;
@@ -27,12 +27,13 @@ export const apiBangumi = {
/**
* 更新指定 bangumiId 的规则
* @param bangumiData - 需要更新的规则
* @param bangumiId - 需要更新的 bangumi 的 id
* @param bangumiRule
* @returns axios 请求返回的数据
*/
async updateRule(bangumiRule: BangumiRule) {
const { data } = await axios.post<ApiSuccess>(
'api/v1/bangumi/updateRule',
async updateRule(bangumiId: number, bangumiRule: BangumiUpdate) {
const { data } = await axios.patch<ApiSuccess>(
`api/v1/bangumi/update/${bangumiId}`,
bangumiRule
);
return data;
@@ -46,7 +47,7 @@ export const apiBangumi = {
*/
async deleteRule(bangumiId: number, file: boolean) {
const { data } = await axios.delete<ApiSuccess>(
`api/v1/bangumi/deleteRule/${bangumiId}`,
`api/v1/bangumi/delete/${bangumiId}`,
{
params: {
file,
@@ -64,7 +65,7 @@ export const apiBangumi = {
*/
async disableRule(bangumiId: number, file: boolean) {
const { data } = await axios.delete<ApiSuccess>(
`api/v1/bangumi/disableRule/${bangumiId}`,
`api/v1/bangumi/disable/${bangumiId}`,
{
params: {
file,
@@ -80,7 +81,7 @@ export const apiBangumi = {
*/
async enableRule(bangumiId: number) {
const { data } = await axios.get<ApiSuccess>(
`api/v1/bangumi/enableRule/${bangumiId}`
`api/v1/bangumi/enable/${bangumiId}`
);
return data;
},

View File

@@ -19,3 +19,24 @@ export interface BangumiRule {
title_raw: string;
year: string | null;
}
export interface BangumiUpdate {
added: boolean;
deleted: boolean;
dpi: string;
eps_collect: boolean;
filter: string;
group_name: string;
official_title: string;
offset: number;
poster_link: string | null;
rss_link: string;
rule_name: string;
save_path: string;
season: number;
season_raw: string;
source: string | null;
subtitle: string;
title_raw: string;
year: string | null;
}