Coverage for server / routes / student / student_theme.py: 100%
21 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-10-04 09:33 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-10-04 09:33 +0000
1"""
2Student Theme Routes
4This module defines the API routes for student profile themes, allowing students to
5customize their profile appearance with different visual themes.
7Routes:
8- GET /v1/student/account/theme/fetch - Get current theme
9- POST /v1/student/account/theme/apply - Apply a new theme
10- PUT /v1/student/account/theme/update - Update theme settings
11- DELETE /v1/student/account/theme/delete - Delete theme and revert to default
12"""
14from fastapi import APIRouter, Body, Depends, Request, status
15from typing import Dict
17# Authentication
18from server.authentication.auth0_bearer import Auth0Bearer
19from server.services.growthbook import require_feature
21_THEME_DEPS = [
22 Depends(Auth0Bearer(access_levels=["student"])),
23 Depends(require_feature("student.theme_management")),
24]
26# Models
27from server.models.themes import ThemeApply, ThemeResponse, ThemeUpdate
29# Services
30from server.services.student.student_theme import studentThemeService
32router = APIRouter()
33theme_service = studentThemeService()
35@router.get(
36 "/fetch",
37 dependencies=_THEME_DEPS,
38 status_code=status.HTTP_200_OK,
39 response_model=Dict,
40 description="As a student, I can fetch my current profile theme information",
41 summary="Get current profile theme information",
42 responses={
43 200: {
44 "description": "Successfully retrieved theme details",
45 "content": {
46 "application/json": {
47 "example": {
48 "theme_id": "dark-mode",
49 "theme_name": "Dark Mode",
50 "colors": {
51 "primary": "#7b68ee",
52 "secondary": "#6c757d",
53 "accent": "#00c6a9",
54 "text": "#f8f9fa",
55 "background": "#212529"
56 },
57 "font": {
58 "family": "Roboto, sans-serif",
59 "size": "16px",
60 "heading_scale": 1.2
61 },
62 "layout": {
63 "spacing": "16px",
64 "border_radius": "4px",
65 "card_style": "shadow"
66 },
67 "is_default": False,
68 "created_at": "2025-02-15T12:00:00Z",
69 "updated_at": "2025-02-15T12:00:00Z"
70 }
71 }
72 }
73 },
74 401: {"description": "Invalid or missing authentication"},
75 404: {"description": "No theme found"},
76 500: {"description": "Server-side issue"}
77 }
78)
79async def fetch_theme(request: Request) -> Dict:
80 """
81 Get the current theme for the authenticated student.
83 Args:
84 request (Request): The HTTP request containing user authentication
86 Returns:
87 ThemeResponse: The current theme details
88 """
89 return await theme_service.get_current_theme(request)
92@router.post(
93 "/apply",
94 dependencies=_THEME_DEPS,
95 status_code=status.HTTP_201_CREATED,
96 response_model=ThemeResponse,
97 description="As a student, I can apply a new theme to my profile",
98 summary="Apply a new theme to profile",
99 responses={
100 201: {
101 "description": "New theme successfully applied",
102 "content": {
103 "application/json": {
104 "example": {
105 "theme_id": "light-blue",
106 "theme_name": "Light Blue",
107 "colors": {
108 "primary": "#0d6efd",
109 "secondary": "#6c757d",
110 "accent": "#0dcaf0",
111 "text": "#212529",
112 "background": "#f8f9fa"
113 },
114 "font": {
115 "family": "Open Sans, sans-serif",
116 "size": "16px",
117 "heading_scale": 1.2
118 },
119 "layout": {
120 "spacing": "14px",
121 "border_radius": "6px",
122 "card_style": "shadow"
123 },
124 "is_default": False,
125 "created_at": "2025-01-10T10:30:00Z",
126 "updated_at": "2025-01-10T10:30:00Z"
127 }
128 }
129 }
130 },
131 400: {"description": "Invalid theme ID"},
132 401: {"description": "Invalid or missing authentication"},
133 404: {"description": "Theme not found"},
134 500: {"description": "Server-side issue"}
135 }
136)
137async def apply_theme(
138 request: Request,
139 theme_data: ThemeApply = Body(...)
140) -> ThemeResponse:
141 """
142 Apply a theme to the authenticated student's profile.
144 Args:
145 request (Request): The HTTP request containing user authentication
146 theme_data (ThemeApply): The theme ID to apply
148 Returns:
149 ThemeResponse: The applied theme details
150 """
151 return await theme_service.apply_theme(request, theme_data.theme_id, theme_data.color_mode)
154@router.put(
155 "/update",
156 dependencies=_THEME_DEPS,
157 status_code=status.HTTP_200_OK,
158 response_model=ThemeResponse,
159 description="As a student, I can update my current theme settings",
160 summary="Update current theme settings",
161 responses={
162 200: {
163 "description": "Theme settings updated successfully",
164 },
165 400: {"description": "Invalid theme data"},
166 401: {"description": "Invalid or missing authentication"},
167 404: {"description": "No active theme found"},
168 500: {"description": "Server-side issue"}
169 }
170)
171async def update_theme(
172 request: Request,
173 theme_data: ThemeUpdate = Body(...)
174) -> ThemeResponse:
175 """
176 Update the current theme settings for the authenticated student.
178 Args:
179 request (Request): The HTTP request containing user authentication
180 theme_data (ThemeUpdate): Partial theme data to update
182 Returns:
183 ThemeResponse: The updated theme details
184 """
185 return await theme_service.update_theme(request, theme_data)
188@router.delete(
189 "/delete",
190 dependencies=_THEME_DEPS,
191 status_code=status.HTTP_200_OK,
192 response_model=Dict,
193 description="As a student, I can delete my theme and revert to default",
194 summary="Delete theme and revert to default",
195 responses={
196 200: {
197 "description": "Theme deleted, reverted to default",
198 },
199 401: {"description": "Invalid or missing authentication"},
200 404: {"description": "No active theme found to delete"},
201 500: {"description": "Server-side issue"}
202 }
203)
204async def delete_theme(request: Request) -> Dict:
205 """
206 Delete the active theme for the authenticated student (soft delete).
208 Args:
209 request (Request): The HTTP request containing user authentication
211 Returns:
212 Dict: Default theme details after deletion
213 """
214 return await theme_service.delete_theme(request)