Coverage for app.py: 96%

54 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2026-07-24 16:42 +0000

1import logging 

2from contextlib import asynccontextmanager 

3import httpx 

4from fastapi import FastAPI, Request 

5from fastapi.encoders import jsonable_encoder 

6from fastapi.responses import JSONResponse 

7from fastapi.exceptions import RequestValidationError 

8from config import settings 

9from model import * 

10from mongo import * 

11 

12 

13@asynccontextmanager 

14async def lifespan(app: FastAPI): 

15 app.state.http_client = httpx.Client(timeout=httpx.Timeout(5.0, read=30.0)) 

16 yield 

17 app.state.http_client.close() 

18 

19 

20def create_app() -> FastAPI: 

21 app = FastAPI(lifespan=lifespan) 

22 

23 from model.utils.response import NOJException 

24 

25 @app.exception_handler(NOJException) 

26 async def noj_exception_handler(request: Request, exc: NOJException): 

27 return JSONResponse( 

28 { 

29 'status': 'err', 

30 'message': exc.message, 

31 'data': exc.data, 

32 }, 

33 status_code=exc.status_code, 

34 ) 

35 

36 @app.exception_handler(RequestValidationError) 

37 async def validation_exception_handler(request: Request, 

38 exc: RequestValidationError): 

39 return JSONResponse( 

40 { 

41 'status': 'err', 

42 'message': 'Invalid request body', 

43 'data': jsonable_encoder(exc.errors()), 

44 }, 

45 status_code=400, 

46 ) 

47 

48 app.include_router(auth_router, prefix='/auth') 

49 app.include_router(profile_router, prefix='/profile') 

50 app.include_router(problem_router, prefix='/problem') 

51 app.include_router(submission_router, prefix='/submission') 

52 app.include_router(course_router, prefix='/course') 

53 app.include_router(homework_router, prefix='/homework') 

54 app.include_router(test_router, prefix='/test') 

55 app.include_router(ann_router, prefix='/ann') 

56 app.include_router(ranking_router, prefix='/ranking') 

57 app.include_router(post_router, prefix='/post') 

58 app.include_router(copycat_router, prefix='/copycat') 

59 app.include_router(health_router, prefix='/health') 

60 app.include_router(user_router, prefix='/user') 

61 app.include_router(user_options_router, prefix='/user') 

62 

63 _seed_db() 

64 

65 logger = logging.getLogger(__name__) 

66 if settings.SMTP_SERVER is None: 

67 logger.info( 

68 "'SMTP_SERVER' is not set. email-related function will be disabled" 

69 ) 

70 elif settings.SMTP_NOREPLY_PASSWORD is None: 

71 logger.info("'SMTP_NOREPLY' set but 'SMTP_NOREPLY_PASSWORD' not") 

72 

73 return app 

74 

75 

76def _seed_db(): 

77 if not User('first_admin'): 

78 ADMIN = { 

79 'username': 'first_admin', 

80 'password': 'firstpasswordforadmin', 

81 'email': 'i.am.first.admin@noj.tw', 

82 } 

83 PROFILE = { 

84 'displayed_name': 'the first admin', 

85 'bio': 'I am super good!!!!!', 

86 } 

87 admin = User.signup(**ADMIN) 

88 admin.update( 

89 active=True, 

90 role=0, 

91 profile=PROFILE, 

92 ) 

93 if not Course('Public'): 

94 Course.add_course('Public', 'first_admin') 

95 

96 

97app = create_app()