diff --git a/src/api/__init__.py b/src/api/__init__.py index 702836e..3c6388f 100644 --- a/src/api/__init__.py +++ b/src/api/__init__.py @@ -16,7 +16,6 @@ app.include_router(courses.router, prefix="/courses", tags=["Courses"]) app.include_router(dining.router, prefix="/dining", tags=["Dining"]) app.include_router(energy.router, prefix="/energy", tags=["Energy"]) -app.include_router(librarys.router, prefix="/lib", tags=["Library"]) app.include_router(librarys.router, prefix="/librarys", tags=["Library"]) app.include_router(locations.router, prefix="/locations", tags=["Locations"]) app.include_router(newsletters.router, prefix="/newsletters", tags=["Newsletters"]) diff --git a/src/api/models/resources/__init__.py b/src/api/models/resources/__init__.py deleted file mode 100644 index 20b1379..0000000 --- a/src/api/models/resources/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .resources import Resources diff --git a/src/api/models/resources/events.py b/src/api/models/resources/events.py deleted file mode 100644 index 20b1379..0000000 --- a/src/api/models/resources/events.py +++ /dev/null @@ -1 +0,0 @@ -from .resources import Resources diff --git a/src/api/models/resources/resources.py b/src/api/models/resources/resources.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/api/routers/buses.py b/src/api/routers/buses.py index 75d220e..233996a 100644 --- a/src/api/routers/buses.py +++ b/src/api/routers/buses.py @@ -37,26 +37,7 @@ class BusNandaData(BaseModel): buses = Buses() -@router.get( - "/nanda", - responses={ - 200: { - "content": { - "application/json": { - "example": { - "toward_south_campus_info": {}, - "weekday_bus_schedule_toward_south_campus": {}, - "weekend_bus_schedule_toward_south_campus": {}, - "toward_main_campus_info": {}, - "weekday_bus_schedule_toward_main_campus": {}, - "weekend_bus_schedule_toward_main_campus": {}, - } - }, - }, - }, - }, - response_model=BusNandaData, -) +@router.get("/nanda", response_model=BusNandaData) async def get_nanda(): """ 南大校區區間車資訊。 @@ -64,24 +45,7 @@ async def get_nanda(): return buses.get_nanda_data() -@router.get( - "/nanda/information/toward_main_campus", - responses={ - 200: { - "content": { - "application/json": { - "example": { - "direction": "往校本部 (To Main Campus)", - "duration": "2023/10/16 ~ 2023/11/12", - "route": "南大校區校門口右側(食品路校牆邊) → 台積館(經寶山路) → 人社院/生科館 → 綜二館 → 北校門口", - "routeEN": "The right side of NandaCampus front gate(Shipin Road) → TSMC Building(Baoshan Rd.) → CHSS/CLS Builing → General Building II→School North Gate", - } - }, - }, - }, - }, - response_model=BusInfo, -) +@router.get("/nanda/information/toward_main_campus", response_model=BusInfo) async def get_nanda_toward_main_campus_info() -> BusInfo: """ 南大往本部區間車資訊。 @@ -89,24 +53,7 @@ async def get_nanda_toward_main_campus_info() -> BusInfo: return buses.get_nanda_data()["toward_main_campus_info"] -@router.get( - "/nanda/information/toward_south_campus", - responses={ - 200: { - "content": { - "application/json": { - "example": { - "direction": "往南大校區 (To Nanda Campus)", - "duration": "2023/10/16 ~ 2023/11/12", - "route": "北校門口 → 綜二館 → 人社院/生科館 → 台積館(經寶山路) → 南大校區校門口右側(食品路校牆邊)", - "routeEN": "School North Gate → General Building II → CHSS/CLS Building → TSMC Building(Baoshan Rd.) → The right side of NandaCampus front gate(Shipin Road)", - } - }, - }, - }, - }, - response_model=BusInfo, -) +@router.get("/nanda/information/toward_south_campus", response_model=BusInfo) async def get_nanda_toward_south_campus_info() -> BusInfo: """ 本部往南大區間車資訊。 @@ -115,23 +62,7 @@ async def get_nanda_toward_south_campus_info() -> BusInfo: @router.get( - "/nanda/schedules/weekday/toward_main_campus", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - {"time": "7:20", "description": ""}, - {"time": "7:33", "description": "此為付費市區公車(83號公車直達兩校區)"}, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[BusSchedule], + "/nanda/schedules/weekday/toward_main_campus", response_model=list[BusSchedule] ) async def get_nanda_weekday_bus_schedule_toward_main_campus() -> list[BusSchedule]: """ @@ -141,23 +72,7 @@ async def get_nanda_weekday_bus_schedule_toward_main_campus() -> list[BusSchedul @router.get( - "/nanda/schedules/weekday/toward_south_campus", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - {"time": "7:30", "description": "此為付費市區公車(83號公車直達兩校區)"}, - {"time": "7:40", "description": ""}, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[BusSchedule], + "/nanda/schedules/weekday/toward_south_campus", response_model=list[BusSchedule] ) async def get_nanda_weekday_bus_schedule_toward_south_campus() -> list[BusSchedule]: """ @@ -167,25 +82,7 @@ async def get_nanda_weekday_bus_schedule_toward_south_campus() -> list[BusSchedu @router.get( - "/nanda/schedules/weekend/toward_main_campus", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - {"time": "8:00", "description": ""}, - {"time": "12:00", "description": ""}, - {"time": "14:00", "description": ""}, - {"time": "17:00", "description": ""}, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[BusSchedule], + "/nanda/schedules/weekend/toward_main_campus", response_model=list[BusSchedule] ) async def get_nanda_weekend_bus_schedule_toward_main_campus() -> list[BusSchedule]: """ @@ -195,25 +92,7 @@ async def get_nanda_weekend_bus_schedule_toward_main_campus() -> list[BusSchedul @router.get( - "/nanda/schedules/weekend/toward_south_campus", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - {"time": "8:30", "description": ""}, - {"time": "12:30", "description": ""}, - {"time": "14:30", "description": ""}, - {"time": "17:30", "description": ""}, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[BusSchedule], + "/nanda/schedules/weekend/toward_south_campus", response_model=list[BusSchedule] ) async def get_nanda_weekend_bus_schedule_toward_south_campus() -> list[BusSchedule]: """ diff --git a/src/api/routers/dining.py b/src/api/routers/dining.py index e41d9eb..d562585 100644 --- a/src/api/routers/dining.py +++ b/src/api/routers/dining.py @@ -38,40 +38,7 @@ class DiningBuilding(BaseModel): dining = Dining() -@router.get( - "/", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "building": "小吃部", - "restaurants": [ - { - "area": "小吃部", - "image": "https://img.onl/CYp5nN", - "name": "7-ELEVEN", - "note": "", - "phone": "0920-229-711, 03-5166254", - "schedule": { - "saturday": "24小時", - "sunday": "24小時", - "weekday": "24小時", - }, - }, - { - "...", - }, - ], - }, - ] - }, - }, - }, - }, - response_model=list[DiningBuilding], -) +@router.get("/", response_model=list[DiningBuilding]) def get_dining_data() -> list[DiningBuilding]: """ 取得所有餐廳資料。 @@ -79,19 +46,7 @@ def get_dining_data() -> list[DiningBuilding]: return dining.get_dining_data() -@router.get( - "/buildings", - responses={ - 200: { - "content": { - "application/json": { - "example": ["小吃部", "水木生活中心", "風雲樓", "綜合教學大樓(南大校區)", "其他餐廳"] - }, - }, - }, - }, - response_model=list[DiningBuildingName], -) +@router.get("/buildings", response_model=list[DiningBuildingName]) def get_all_building_names() -> list[DiningBuildingName]: """ 取得所有建築名稱。 @@ -99,38 +54,7 @@ def get_all_building_names() -> list[DiningBuildingName]: return dining.get_all_building_names() -@router.get( - "/buildings/{building_name}", - responses={ - 200: { - "content": { - "application/json": { - "example": { - "building": "小吃部", - "restaurants": [ - { - "area": "小吃部", - "image": "https://img.onl/CYp5nN", - "name": "7-ELEVEN", - "note": "", - "phone": "0920-229-711, 03-5166254", - "schedule": { - "saturday": "24小時", - "sunday": "24小時", - "weekday": "24小時", - }, - }, - { - "...", - }, - ], - } - }, - }, - }, - }, - response_model=DiningBuilding, -) +@router.get("/buildings/{building_name}", response_model=DiningBuilding) def get_dining_data( building_name: DiningBuildingName = Path(..., example="小吃部", description="建築名稱") ) -> DiningBuilding: @@ -140,19 +64,7 @@ def get_dining_data( return dining.query_by_building_name(building_name) -@router.get( - "/restaurants", - responses={ - 200: { - "content": { - "application/json": { - "example": ["7-ELEVEN", "麥當勞", "瑞斯飯糰", "漢城異國美食", "對味", "..."] - }, - }, - }, - }, - response_model=list[str], -) +@router.get("/restaurants", response_model=list[str]) def get_all_restaurant_names() -> list[str]: """ 取得所有餐廳名稱。 @@ -160,30 +72,7 @@ def get_all_restaurant_names() -> list[str]: return dining.get_all_restaurant_names() -@router.get( - "/restaurants/{restaurant_name}", - responses={ - 200: { - "content": { - "application/json": { - "example": { - "area": "小吃部", - "image": "https://img.onl/KvsZAz", - "name": "麥當勞", - "note": "", - "phone": "03-5727801", - "schedule": { - "saturday": "7:00-24:00", - "sunday": "7:00-24:00", - "weekday": "7:00-24:00", - }, - } - }, - }, - }, - }, - response_model=list[DiningRestaurant], -) +@router.get("/restaurants/{restaurant_name}", response_model=list[DiningRestaurant]) def get_dining_data( restaurant_name: str = Path(..., example="麥當勞", description="餐廳名稱") ): @@ -193,35 +82,7 @@ def get_dining_data( return dining.query_by_restaurant_name(restaurant_name) -@router.get( - "/scedules/{day_of_week}", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "area": "小吃部", - "image": "https://img.onl/KvsZAz", - "name": "麥當勞", - "note": "", - "phone": "03-5727801", - "schedule": { - "saturday": "7:00-24:00", - "sunday": "7:00-24:00", - "weekday": "7:00-24:00", - }, - }, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[DiningRestaurant], -) +@router.get("/scedules/{day_of_week}", response_model=list[DiningRestaurant]) def get_schedule_by_day_of_week( day_of_week: DiningSceduleName = Path(..., example="saturday", description="營業日") ) -> list[DiningRestaurant]: @@ -235,33 +96,7 @@ def get_schedule_by_day_of_week( @router.get( - "/searches/restaurants/{restaurant_name}", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "area": "小吃部", - "image": "https://img.onl/KvsZAz", - "name": "麥當勞", - "note": "", - "phone": "03-5727801", - "schedule": { - "saturday": "7:00-24:00", - "sunday": "7:00-24:00", - "weekday": "7:00-24:00", - }, - }, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[DiningRestaurant], + "/searches/restaurants/{restaurant_name}", response_model=list[DiningRestaurant] ) def fuzzy_search_restaurant_by_name( restaurant_name: str = Path(..., example="麵", description="餐廳名稱") diff --git a/src/api/routers/librarys.py b/src/api/routers/librarys.py index f9e01cf..e26f7f8 100644 --- a/src/api/routers/librarys.py +++ b/src/api/routers/librarys.py @@ -1,13 +1,7 @@ from enum import Enum -from typing import Optional -from fastapi import APIRouter, Path +from typing import Optional, List from pydantic import BaseModel, HttpUrl, Field - -import re -import json -from bs4 import BeautifulSoup - -from src.utils import cached_request +from fastapi import APIRouter, Path from src.utils.scraper import library_scraper @@ -38,12 +32,6 @@ class LibrarySpace(BaseModel): count: int = Field(..., description="空間剩餘數量") -class LibrarySpaceData(BaseModel): - rescode: int = Field(..., description="回傳代碼") - resmsg: str = Field(..., description="回傳訊息") - rows: list[LibrarySpace] = Field(..., description="各空間資料") - - class LibraryRssType(str, Enum): news = "news" eresources = "eresources" @@ -69,19 +57,10 @@ class LibraryRssItem(BaseModel): image: LibraryRssImage = Field(..., description="文章圖片") -class LibraryRssData(BaseModel): - title: str = Field(..., description="RSS 標題") - link: Optional[HttpUrl] = Field(..., description="RSS 來源連結") - description: str = Field(..., description="RSS 來源描述") - language: str = Field(..., description="RSS 語言") - pubDate: str = Field(..., description="RSS 發布日期") - item: list[LibraryRssItem] = Field(..., description="RSS 文章列表") - - router = APIRouter() -@router.get("/space", response_model=LibrarySpaceData) +@router.get("/space", response_model=List[LibrarySpace]) def get_library_space_data(): """ 取得空間使用資訊。 @@ -97,7 +76,7 @@ def get_library_lost_and_found(): return library_scraper.get_lost_and_found() -@router.get("/rss/{rss}", response_model=LibraryRssData) +@router.get("/rss/{rss}", response_model=List[LibraryRssItem]) def get_library_rss_data( rss: LibraryRssType = Path( ..., diff --git a/src/api/routers/locations.py b/src/api/routers/locations.py index 6ae7b49..277b564 100644 --- a/src/api/routers/locations.py +++ b/src/api/routers/locations.py @@ -28,34 +28,7 @@ class LocationSearchData(BaseModel): location = Location() -@router.get( - "/", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "id": "b876aa09-40a8-427b-8bc7-1933978690e2", - "data": { - "name": "光復路校門", - "name_en": "North gate", - "latitude": "24.796538", - "longitude": "120.997015", - }, - "create_time": "20231014T225400+0800", - "update_time": "20231014T225400+0800", - }, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[LocationData], -) +@router.get("/", response_model=list[LocationData]) def get_all_location(): """ 取得所有地點資訊。 @@ -67,80 +40,7 @@ def get_all_location(): raise HTTPException(status_code=500, detail="Internal Server Error") -@router.post( - "/searches", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "id": "82f872a8-a0f3-41df-bf6f-1df741e1cbcd", - "data": { - "name": "台積館", - "name_en": "TSMC Building", - "latitude": "24.78699", - "longitude": "120.98795", - }, - "create_time": "20231014T225400+0800", - "update_time": "20231014T225400+0800", - }, - { - "id": "7255f0d9-8eee-47b2-9165-20db7950fc0d", - "data": { - "name": "台達館", - "name_en": "DeltaHall", - "latitude": "24.79591", - "longitude": "120.99211", - }, - "create_time": "20231014T225400+0800", - "update_time": "20231014T225400+0800", - }, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[LocationData], -) -def search_location(search_data: LocationSearchData): - """ - 使用名稱模糊搜尋地點資訊。 - """ - result = location.fuzzy_search(search_data.name) - result = result[: search_data.max_result] - if result == []: - raise HTTPException(status_code=404, detail="Not found") - else: - return result - - -@router.get( - "/{id}", - responses={ - 200: { - "content": { - "application/json": { - "example": { - "id": "27833bfe-e387-4a8a-a182-9b617780e927", - "data": { - "name": "動機化學實驗館", - "name_en": "Chemistry and Power Mechanical Engineering Building", - "latitude": "24.796533", - "longitude": "120.995204", - }, - "create_time": "20231014T225400+0800", - "update_time": "20231014T225400+0800", - } - }, - }, - }, - }, - response_model=LocationData, -) +@router.get("/{id}", response_model=LocationData) def get_location(id: UUID = Path(..., description="要查詢的地點 id")): """ 使用地點 id 取得指定地點資訊。 @@ -152,45 +52,7 @@ def get_location(id: UUID = Path(..., description="要查詢的地點 id")): raise HTTPException(status_code=404, detail="Not found") -@router.get( - "/searches/{name}", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "id": "82f872a8-a0f3-41df-bf6f-1df741e1cbcd", - "data": { - "name": "台積館", - "name_en": "TSMC Building", - "latitude": "24.78699", - "longitude": "120.98795", - }, - "create_time": "20231014T225400+0800", - "update_time": "20231014T225400+0800", - }, - { - "id": "7255f0d9-8eee-47b2-9165-20db7950fc0d", - "data": { - "name": "台達館", - "name_en": "DeltaHall", - "latitude": "24.79591", - "longitude": "120.99211", - }, - "create_time": "20231014T225400+0800", - "update_time": "20231014T225400+0800", - }, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[LocationData], -) +@router.get("/searches/{name}", response_model=list[LocationData]) def search_location(name: str = Path(..., description="要查詢的地點")): """ 使用名稱模糊搜尋地點資訊。 @@ -200,3 +62,16 @@ def search_location(name: str = Path(..., description="要查詢的地點")): raise HTTPException(status_code=404, detail="Not found") else: return result + + +@router.post("/searches", response_model=list[LocationData]) +def search_location(search_data: LocationSearchData): + """ + 使用名稱模糊搜尋地點資訊。 + """ + result = location.fuzzy_search(search_data.name) + result = result[: search_data.max_result] + if result == []: + raise HTTPException(status_code=404, detail="Not found") + else: + return result diff --git a/src/api/routers/newsletters.py b/src/api/routers/newsletters.py index 8a925f8..0180198 100644 --- a/src/api/routers/newsletters.py +++ b/src/api/routers/newsletters.py @@ -1,5 +1,6 @@ import json from fastapi import APIRouter, Path, HTTPException +from pydantic import HttpUrl from src.utils.scraper import newsletter_scraper router = APIRouter() @@ -15,11 +16,7 @@ def get_all_newsletters(): @router.get("/{newsletter_name}") def get_newsletter_by_name( - newsletter_name: str = Path( - ..., - example="國立清華大學學生會電子報", - description="抓取的電子報名稱", - ) + newsletter_name: str = Path(..., example="國立清華大學學生會電子報", description="抓取的電子報名稱") ): """ 透過電子報名稱取得指定的電子報列表。 @@ -27,7 +24,6 @@ def get_newsletter_by_name( with open("data/newsletter_list.json", "r", encoding="utf-8") as f: data = f.read() data = json.loads(data) - print(data) for newsletter in data: if newsletter["name"] == newsletter_name: newsletter_link = newsletter["link"] @@ -39,7 +35,7 @@ def get_newsletter_by_name( @router.get("/paths/{newsletter_link:path}") def get_newsletter_by_link( - newsletter_link: str = Path( + newsletter_link: HttpUrl = Path( ..., example="https://newsletter.cc.nthu.edu.tw/nthu-list/index.php/zh/home-zh-tw/listid-44-", description="抓取的電子報網址", diff --git a/src/api/routers/phones.py b/src/api/routers/phones.py index 18c2184..bbe84c8 100644 --- a/src/api/routers/phones.py +++ b/src/api/routers/phones.py @@ -36,134 +36,17 @@ class ContactSearchData(BaseModel): phone = Phone() -@router.get( - "/", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "id": "acfe50cc-3922-4acb-9fd2-4774520e82bc", - "data": { - "name": "台積電-國立清華大學聯合研發中心", - "ext": "34071", - "tel": "N/A", - "fax": "N/A", - "email": "N/A", - "parents": [ - { - "name": "國際產學營運總中心", - "id": "bc7fd10a-8d4f-42f2-8ae8-d065f94321be", - } - ], - "children": [], - }, - "create_time": "20231014T225508+0800", - "update_time": "20231014T225508+0800", - }, - { - "...", - }, - ] - } - } - } - }, - response_model=list[ContactsData], -) +@router.get("/", response_model=list[ContactsData]) def get_all_phone(): """ 取得所有電話資料。 """ - try: - result = phone.get_all() - return result - except Exception as e: - raise HTTPException(status_code=500, detail="Internal Server Error") - - -@router.post( - "/searches", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "id": "acfe50cc-3922-4acb-9fd2-4774520e82bc", - "data": { - "name": "台積電-國立清華大學聯合研發中心", - "ext": "34071", - "tel": "N/A", - "fax": "N/A", - "email": "N/A", - "parents": [ - { - "name": "國際產學營運總中心", - "id": "bc7fd10a-8d4f-42f2-8ae8-d065f94321be", - } - ], - "children": [], - }, - "create_time": "20231014T225508+0800", - "update_time": "20231014T225508+0800", - }, - { - "...", - }, - ] - } - } - } - }, - response_model=list[ContactsData], -) -def search_phone(search_data: ContactSearchData): - """ - 根據名字模糊搜尋電話。 - """ - result = phone.fuzzy_search(search_data.name) - result = result[: search_data.max_result] - print(len(result)) - if result == []: - raise HTTPException(status_code=404, detail="Not found") - else: - return result + result = phone.get_all() + return result -@router.get( - "/{id}", - responses={ - 200: { - "content": { - "application/json": { - "example": { - "id": "acfe50cc-3922-4acb-9fd2-4774520e82bc", - "data": { - "name": "台積電-國立清華大學聯合研發中心", - "ext": "34071", - "tel": "N/A", - "fax": "N/A", - "email": "N/A", - "parents": [ - { - "name": "國際產學營運總中心", - "id": "bc7fd10a-8d4f-42f2-8ae8-d065f94321be", - } - ], - "children": [], - }, - "create_time": "20231014T225508+0800", - "update_time": "20231014T225508+0800", - } - } - } - } - }, - response_model=ContactsData, -) -def get_phone(id: UUID = Path(..., description="要查詢電話的 id")): +@router.get("/{id}", response_model=ContactsData) +def get_phone(id: UUID = Path(..., description="要查詢電話的 ID")): """ 使用電話 id 取得電話資料。 """ @@ -174,42 +57,7 @@ def get_phone(id: UUID = Path(..., description="要查詢電話的 id")): raise HTTPException(status_code=404, detail="Not found") -@router.get( - "/searches/{name}", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "id": "acfe50cc-3922-4acb-9fd2-4774520e82bc", - "data": { - "name": "台積電-國立清華大學聯合研發中心", - "ext": "34071", - "tel": "N/A", - "fax": "N/A", - "email": "N/A", - "parents": [ - { - "name": "國際產學營運總中心", - "id": "bc7fd10a-8d4f-42f2-8ae8-d065f94321be", - } - ], - "children": [], - }, - "create_time": "20231014T225508+0800", - "update_time": "20231014T225508+0800", - }, - { - "...", - }, - ] - } - } - } - }, - response_model=list[ContactsData], -) +@router.get("/searches/{name}", response_model=list[ContactsData]) def search_phone(name: str = Path(..., description="要查詢誰的電話")): """ 根據名字模糊搜尋電話。 @@ -219,3 +67,16 @@ def search_phone(name: str = Path(..., description="要查詢誰的電話")): raise HTTPException(status_code=404, detail="Not found") else: return result + + +@router.post("/searches", response_model=list[ContactsData]) +def search_phone(search_data: ContactSearchData): + """ + 根據名字模糊搜尋電話。 + """ + result = phone.fuzzy_search(search_data.name) + result = result[: search_data.max_result] + if result == []: + raise HTTPException(status_code=404, detail="Not found") + else: + return result diff --git a/src/api/routers/resources/__init__.py b/src/api/routers/resources/__init__.py index 27741a0..6a497d2 100644 --- a/src/api/routers/resources/__init__.py +++ b/src/api/routers/resources/__init__.py @@ -1 +1,8 @@ -from .resources import router +from fastapi import APIRouter + +from .events import router as events_router +from .careers import router as careers_router + +router = APIRouter() +router.include_router(events_router, prefix="/events", tags=["Events"]) +router.include_router(careers_router, prefix="/careers", tags=["Careers"]) diff --git a/src/api/routers/resources/careers.py b/src/api/routers/resources/careers.py new file mode 100644 index 0000000..af9233c --- /dev/null +++ b/src/api/routers/resources/careers.py @@ -0,0 +1,3 @@ +from fastapi import APIRouter + +router = APIRouter() diff --git a/src/api/routers/resources/events.py b/src/api/routers/resources/events.py index 92e3e4c..fcde6fb 100644 --- a/src/api/routers/resources/events.py +++ b/src/api/routers/resources/events.py @@ -1,11 +1,7 @@ from fastapi import APIRouter from src.utils.scraper import rpage_scraper, library_scraper, goodjob_scraper -router = APIRouter( - prefix="/events", - tags=["events"], - responses={404: {"description": "Not found"}}, -) +router = APIRouter() @router.get("/libarys") @@ -16,6 +12,14 @@ async def get_libarys_events(): return library_scraper.get_rss_data("exhibit") +@router.get("/goodjob") +async def get_goodjob_events(): + """ + 取得清華 JOB 讚的活動資料。 + """ + return goodjob_scraper.get_announcements("01003") + + @router.get("/global_affairs") async def get_global_affairs_events(): """ @@ -64,11 +68,3 @@ async def get_bulletin_student_events(): return rpage_scraper.announcement( "https://bulletin.site.nthu.edu.tw/p/403-1086-5085-1.php?Lang=zh-tw" ) - - -@router.get("/goodjob") -async def get_goodjob_events(): - """ - 取得清華 JOB 讚的活動資料。 - """ - return goodjob_scraper.get("01003") diff --git a/src/api/routers/resources/resources.py b/src/api/routers/resources/resources.py deleted file mode 100644 index 2f42096..0000000 --- a/src/api/routers/resources/resources.py +++ /dev/null @@ -1,6 +0,0 @@ -from fastapi import APIRouter - -from .events import router as events_router - -router = APIRouter() -router.include_router(events_router) diff --git a/src/api/routers/rpage.py b/src/api/routers/rpage.py index 4e6433d..d9bd6cb 100644 --- a/src/api/routers/rpage.py +++ b/src/api/routers/rpage.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, HTTPException, Path +from fastapi import APIRouter, Path from pydantic import BaseModel, HttpUrl, Field from typing import Optional @@ -14,33 +14,7 @@ class RpageData(BaseModel): router = APIRouter() -@router.get( - "/{full_path:path}", - responses={ - 200: { - "content": { - "application/json": { - "example": [ - { - "title": "更新112/11/6(一)~113/1/14(日)南大校區區間車時刻表", - "date": "2023-11-02 ", - "url": "https://affairs.site.nthu.edu.tw/p/406-1165-258110,r1065.php?Lang=zh-tw", - }, - { - "title": "112/10/16(一)~113/1/13(六)校園公車時刻表", - "date": "2023-10-12 ", - "url": "https://affairs.site.nthu.edu.tw/p/406-1165-256804,r1065.php?Lang=zh-tw", - }, - { - "...", - }, - ] - }, - }, - }, - }, - response_model=list[RpageData], -) +@router.get("/{full_path:path}", response_model=list[RpageData]) def get_rpage_data( full_path: HttpUrl = Path( ..., diff --git a/src/utils/scraper/goodjob_scraper.py b/src/utils/scraper/goodjob_scraper.py index 0b9f82a..437b145 100644 --- a/src/utils/scraper/goodjob_scraper.py +++ b/src/utils/scraper/goodjob_scraper.py @@ -1,8 +1,8 @@ -from src.utils import cached_request from bs4 import BeautifulSoup +from src.utils import cached_request -def get(data_type: str) -> list: +def get_announcements(data_type: str) -> list: """ 從 Goodjob 取得活動資料。 Args: @@ -23,6 +23,7 @@ def get(data_type: str) -> list: for item in items: title = item.select_one("h3").text date_month = item.select_one("div.g-color-text-light-v1 span.d-block").text + date_month = date_month.replace("月", "") date_year = item.select_one( "div.g-color-text-light-v1 span.d-block:nth-child(2)" ).text @@ -31,7 +32,7 @@ def get(data_type: str) -> list: { "title": title, "description": description, - "date": f"{date_year}年 {date_month}", + "date": f"{date_year}-{date_month}", } ) diff --git a/src/utils/scraper/library_scraper.py b/src/utils/scraper/library_scraper.py index eaef424..394bbe9 100644 --- a/src/utils/scraper/library_scraper.py +++ b/src/utils/scraper/library_scraper.py @@ -1,6 +1,7 @@ from bs4 import BeautifulSoup from cachetools import cached, TTLCache from datetime import datetime, timedelta +from fastapi import HTTPException import json import re import requests @@ -24,13 +25,14 @@ def _get_response(url: str, **kwargs) -> str: "user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36 Edg/112.0.1722.48", } response = requests.get(url, headers=headers, **kwargs) - if response.status_code != 200: - raise Exception(f"Request error: {response.status_code}") - return requests.get(url, headers=headers).text + status_code = response.status_code + if status_code != 200: + raise HTTPException(status_code, f"Request error: {status_code}") + return response.text @cached(cache=TTLCache(maxsize=4, ttl=60 * 60)) -def get_rss_data(rss_type: str) -> dict: +def get_rss_data(rss_type: str) -> list: """ Args: rss_type (str): RSS 類型,可選值: news(最新消息)、eresources(電子資源)、exhibit(展覽及活動)、branches(南大與人社分館) @@ -43,8 +45,8 @@ def get_rss_data(rss_type: str) -> dict: xml_string = _get_response(url) xml_string = xml_string.replace("
", "") dict = xmltodict.parse(xml_string) - dict = dict["rss"]["channel"] - return dict + rss_data = dict["rss"]["channel"]["item"] + return rss_data def get_number_of_goods(): @@ -83,7 +85,7 @@ def get_opening_hours(libaray_name): data["start_time"] = match.group(2) data["end_time"] = match.group(3) else: - raise Exception("No match") + raise HTTPException(404, "Not found") return data @@ -94,8 +96,11 @@ def get_space_data(): # 來源: https://libsms.lib.nthu.edu.tw/build/ url = "https://libsms.lib.nthu.edu.tw/RWDAPI_New/GetDevUseStatus.aspx" response = _get_response(url) - response = json.loads(response) - return response + data = json.loads(response) + if data["resmsg"] != "成功": + raise HTTPException(404, "Not found") + else: + return data["rows"] @cached(cache=TTLCache(maxsize=1, ttl=60 * 60)) diff --git a/src/utils/scraper/rpage_scraper.py b/src/utils/scraper/rpage_scraper.py index 9b423c8..17916f4 100644 --- a/src/utils/scraper/rpage_scraper.py +++ b/src/utils/scraper/rpage_scraper.py @@ -34,6 +34,12 @@ def announcement(url: str) -> list: title = None href = None - data.append({"title": title, "url": href, "date": date}) + data.append( + { + "title": title, + "link": href, + "date": date, + } + ) return data