Skip to content

Commit

Permalink
Merge pull request #29 from depocoder/dev
Browse files Browse the repository at this point in the history
release 0.4
  • Loading branch information
depocoder authored Oct 4, 2024
2 parents 6c07118 + b74d912 commit 58452b9
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 27 deletions.
6 changes: 2 additions & 4 deletions backend/yet_another_calendar/web/api/bulk/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ async def refresh_events(
) -> schema.RefreshedCalendarResponse:
"""Clear events cache."""
cached_json = await get_cached_calendar(body, jwt_token, calendar_id, cookies)
if isinstance(cached_json, dict):
cached_calendar = schema.CalendarResponse(**cached_json)
if isinstance(cached_json, schema.CalendarResponse):
cached_calendar = cached_json
cached_calendar = schema.CalendarResponse.model_validate(cached_json)
calendar = await get_calendar(body, jwt_token, calendar_id, cookies)
changed = cached_calendar.get_hash() != calendar.get_hash()
try:
Expand All @@ -45,6 +42,7 @@ async def refresh_events(
**{**calendar.model_dump(by_alias=True), "changed": changed},
)


async def get_calendar(
body: modeus_schema.ModeusEventsBody,
jwt_token: str,
Expand Down
5 changes: 3 additions & 2 deletions backend/yet_another_calendar/web/api/bulk/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

router = APIRouter()


@router.post("/events/")
async def get_calendar(
body: modeus_schema.ModeusEventsBody,
Expand All @@ -27,6 +28,7 @@ async def get_calendar(
cached_calendar = await integration.get_cached_calendar(body, jwt_token, calendar_id, cookies)
return schema.CalendarResponse.model_validate(cached_calendar)


@router.post("/refresh_events/")
async def refresh_calendar(
body: modeus_schema.ModeusEventsBody,
Expand All @@ -38,5 +40,4 @@ async def refresh_calendar(
Refresh events in redis.
"""


return await integration.refresh_events(body, jwt_token, calendar_id, cookies)
return await integration.refresh_events(body, jwt_token, calendar_id, cookies)
13 changes: 7 additions & 6 deletions backend/yet_another_calendar/web/api/modeus/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ async def get_post_url(session: AsyncClient, token_length: int = 16) -> URL:
"state": token_hex(token_length),
}
response = await session.get(auth_url, params=auth_data, follow_redirects=True)
# response.raise_for_status()
post_url = response.url
if post_url is None:
raise HTTPException(detail=f"Can't get post_url. Response: {response.text}", status_code=response.status_code)
raise HTTPException(detail=f"Modeus error. Can't get post_url. Response: {response.text}",
status_code=response.status_code)
return post_url


Expand All @@ -63,11 +63,11 @@ async def get_auth_form(session: AsyncClient, username: str, password: str) -> T
html = BeautifulSoup(html_text, "lxml")
error_tag = html.find(id="errorText")
if error_tag is not None and error_tag.text != "":
raise HTTPException(detail=error_tag.text, status_code=response.status_code)
raise HTTPException(detail=f"Modeus error. {error_tag.text}", status_code=response.status_code)

form = html.form
if form is None:
raise HTTPException(detail="Can't get form.", status_code=response.status_code)
raise HTTPException(detail="Modeus error. Can't get form.", status_code=response.status_code)
return form


Expand Down Expand Up @@ -104,11 +104,12 @@ async def login(username: str, __password: str, timeout: int = 15) -> str:
# so we use HEAD in the latter one to get only target URL and extract the token
response = await session.head(response.headers["Location"], headers=headers)
if response.url is None:
raise HTTPException(detail='Username/password is incorrect.', status_code=response.status_code)
raise HTTPException(detail='Modeus error. Username/password is incorrect.',
status_code=response.status_code)
token = _extract_token_from_url(response.url.fragment)
if token is None:
raise HTTPException(
detail=f"Can't get token. Response: {response.text}", status_code=response.status_code,
detail=f"Modeus error. Can't get token. Response: {response.text}", status_code=response.status_code,
)
return token

Expand Down
6 changes: 3 additions & 3 deletions backend/yet_another_calendar/web/api/netology/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async def auth_netology(username: str, password: str, timeout: int = 15) -> sche
},
)
if response.status_code == status.HTTP_401_UNAUTHORIZED:
raise HTTPException(detail='Username/password is incorrect.', status_code=response.status_code)
raise HTTPException(detail='Netology error. Username/password is incorrect.', status_code=response.status_code)
response.raise_for_status()
return schema.NetologyCookies(**session.cookies)

Expand All @@ -53,7 +53,7 @@ async def send_request(
session.cookies = httpx.Cookies(cookies.model_dump(by_alias=True))
response = await session.request(**request_settings)
if response.status_code == status.HTTP_401_UNAUTHORIZED:
raise HTTPException(detail='Cookies expired.', status_code=response.status_code)
raise HTTPException(detail='Netology error. Cookies expired.', status_code=response.status_code)
response.raise_for_status()
return response.json()

Expand All @@ -65,7 +65,7 @@ async def get_utmn_course(cookies: schema.NetologyCookies) -> schema.NetologyPro
response = await send_request(cookies, request_settings=request_settings)
netology_program = schema.CoursesResponse(**response).get_utmn_program()
if not netology_program:
raise HTTPException(detail=f"Can't find netology program {settings.netology_course_name}",
raise HTTPException(detail=f"Netology error. Can't find netology program {settings.netology_course_name}",
status_code=status.HTTP_404_NOT_FOUND)
return netology_program

Expand Down
59 changes: 47 additions & 12 deletions backend/yet_another_calendar/web/application.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,57 @@
import logging
from importlib import metadata
from pathlib import Path
from typing import Any

from fastapi import FastAPI
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import UJSONResponse
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from httpx import HTTPError
from pydantic import ValidationError
from starlette.responses import Response

from yet_another_calendar.log import configure_logging
from yet_another_calendar.settings import settings
from yet_another_calendar.web.api.router import api_router
from yet_another_calendar.web.lifespan import lifespan_setup

APP_ROOT = Path(__file__).parent.parent
logger = logging.getLogger(__name__)


async def task_group_exception_handler(request: Request, exc: ExceptionGroup[Any]) -> Response:
exceptions = exc.exceptions
if exceptions and isinstance(exceptions[0], HTTPException):
raise exceptions[0]
if exceptions and isinstance(exceptions[0], ValidationError):
return await validation_exception_handler(request, exceptions[0])
if exceptions and isinstance(exceptions[0], HTTPError):
return await request_error_exception_handler(request, exceptions[0])
if exceptions:
any_exception = exceptions[0]
logger.exception(f"Unhandled exception: {any_exception}")
return Response(
status_code=403,
content=f"Oops! Something went wrong: {any_exception}",
)
raise exc


async def validation_exception_handler(request: Request, exc: ValidationError) -> Response:
logger.exception(f"Unhandled validation exception: {exc}")
return Response(
status_code=500,
content=f"Oops! Api changed: {exc}",
)


async def request_error_exception_handler(request: Request, exc: HTTPError) -> Response:
logger.exception(f"Unhandled request exception: {exc}")
return Response(
status_code=500,
content=f"Oops! Api changed: {exc}",
)


def get_app() -> FastAPI:
"""
Expand All @@ -33,20 +71,17 @@ def get_app() -> FastAPI:
openapi_url="/api/openapi.json",
default_response_class=UJSONResponse,
)
if settings.debug:
origins = [
"http://127.0.0.1:3000",
"http://127.0.0.1:3001",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

)

app.add_exception_handler(ExceptionGroup, task_group_exception_handler) # type: ignore
app.add_exception_handler(ValidationError, validation_exception_handler) # type: ignore
app.add_exception_handler(HTTPError, request_error_exception_handler) # type: ignore
# Main router for the API.
app.include_router(router=api_router, prefix="/api")
# Adds static directory.
Expand Down

0 comments on commit 58452b9

Please sign in to comment.