Coverage for app/routes/logging.py: 81%

72 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-05-02 02:49 +0000

1from flask import request, Blueprint 

2from app.services.log_service import log_event, get_all_logs, get_logs_by_user, log_suggestion, get_ai_usage, get_logs_by_class 

3from flasgger import swag_from 

4from app.models.response import * 

5from app.models.status_codes import StatusCodes 

6 

7 

8 

9logging_bp = Blueprint('logging', __name__) 

10 

11 

12@logging_bp.route('/logs', methods=['POST']) 

13@swag_from({ 

14 'tags': ['Logging'], 

15 'summary': 'Log an event', 

16 'description': 'Logs the event to the database.', 

17 'parameters': [ 

18 { 

19 'name': 'body', 

20 'in': 'body', 

21 'required': True, 

22 'schema': { 

23 'type': 'object', 

24 'properties': { 

25 'event': { 

26 'type': 'string', 

27 'example': 'User logged in' 

28 }, 

29 'metadata': { 

30 'type': 'object', 

31 'example': { 

32 'userID': 12345, 

33 'time_lapse': 1708 

34 } 

35 } 

36 }, 

37 'required': ['event', 'metadata'] 

38 } 

39 } 

40 ], 

41 'responses': { 

42 '200': { 

43 'description': 'Event logged successfully', 

44 'schema': { 

45 'type': 'object', 

46 'properties': { 

47 'status': {'type': 'string', 'example': 'logged'} 

48 } 

49 } 

50 }, 

51 '400': { 

52 'description': 'Bad request or invalid input', 

53 'schema': { 

54 'type': 'object', 

55 'properties': { 

56 'status': {'type': 'string', 'example': 'error'}, 

57 'message': {'type': 'string', 'example': 'Missing required fields: event'} 

58 } 

59 } 

60 }, 

61 '500': { 

62 'description': 'Internal server error' 

63 } 

64 } 

65}) 

66def log_event_route(): 

67 """ 

68 Logs the event to the database. 

69 See Swagger docs for more information. 

70 """ 

71 data = request.json 

72 

73 required_fields = ['event', 'time_lapse', 'metadata'] 

74 missing_fields = [field for field in required_fields if field not in data] 

75 

76 if missing_fields: 

77 return error_response( 

78 f"Missing required fields: {', '.join(missing_fields)}", 

79 None, 

80 StatusCodes.BAD_REQUEST 

81 ) 

82 

83 try: 

84 log_event(data) 

85 return success_response( 

86 "Logged event", 

87 None, 

88 StatusCodes.CREATED 

89 ) 

90 

91 except Exception as e: 

92 return error_response( 

93 f"Error logging event: {e}", 

94 None, 

95 StatusCodes.SERVER_ERROR 

96 ) 

97 

98 

99@logging_bp.route('/logs', methods=['GET']) 

100@swag_from({ 

101 'tags': ['Logging'], 

102 'summary': 'Retrieve all logs', 

103 'description': 'Fetches all logged events from the database.', 

104 'responses': { 

105 '200': { 

106 'description': 'List of logs', 

107 'schema': { 

108 'type': 'array', 

109 'items': { 

110 'type': 'object', 

111 'properties': { 

112 'id': {'type': 'integer', 'example': 1}, 

113 'timestamp': {'type': 'number', 'example': 1708401940}, 

114 'event': {'type': 'string', 'example': 'user_login'}, 

115 'data': {'type': 'object', 'example': {'user_id': 12345}} 

116 } 

117 } 

118 } 

119 }, 

120 '500': { 

121 'description': 'Internal server error' 

122 } 

123 } 

124}) 

125def get_all_logs_route(): 

126 """ 

127 Retrieve all logs in the database 

128 See Swagger docs for more information. 

129 """ 

130 try: 

131 logs = get_all_logs() 

132 return success_response( 

133 "All logs", 

134 logs, 

135 StatusCodes.OK 

136 ) 

137 

138 except Exception as e: 

139 return error_response( 

140 f"Error fetching logs: {e}", 

141 None, 

142 StatusCodes.SERVER_ERROR 

143 ) 

144 

145 

146@logging_bp.route('/logs/<string:user_id>', methods=['GET']) 

147@swag_from({ 

148 'tags': ['Logging'], 

149 'summary': 'TODO Retrieve logs by user ID', 

150 'description': 'Fetches all logged events associated with a specific user ID.', 

151 'parameters': [ 

152 { 

153 'name': 'user_id', 

154 'in': 'path', 

155 'required': True, 

156 'type': 'string', 

157 'description': 'The ID of the user whose logs are being retrieved.', 

158 'example': 12345 

159 } 

160 ], 

161 'responses': { 

162 '200': { 

163 'description': 'List of logs for the specified user', 

164 'schema': { 

165 'type': 'array', 

166 'items': { 

167 'type': 'object', 

168 'properties': { 

169 'id': {'type': 'integer', 'example': 1}, 

170 'timestamp': {'type': 'number', 'example': 1708401940}, 

171 'event': {'type': 'string', 'example': 'user_login'}, 

172 'data': {'type': 'object', 'example': {'user_id': 12345}} 

173 } 

174 } 

175 } 

176 }, 

177 '404': { 

178 'description': 'No logs found for the specified user' 

179 }, 

180 '500': { 

181 'description': 'Internal server error' 

182 } 

183 } 

184}) 

185def get_logs_by_user_route(user_id): 

186 """ 

187 Get all logs for a specific user 

188 See Swagger docs for more information. 

189 """ 

190 try: 

191 user_section_id = request.args.get("user_section_id") 

192 user_class_id = request.args.get("user_class_id") 

193 

194 logs = get_logs_by_user(user_id, user_section_id=user_section_id, user_class_id=user_class_id) 

195 

196 if not logs: 

197 return success_response( 

198 f"No logs found for user {user_id}", 

199 ) 

200 

201 return success_response( 

202 f"Logs for user {user_id}", 

203 logs, 

204 ) 

205 except Exception as e: 

206 return error_response( 

207 f"Error fetching logs for user {user_id}: {e}", 

208 None, 

209 StatusCodes.SERVER_ERROR 

210 ) 

211 

212@logging_bp.route("/logs/class/<string:class_id>", methods=["GET"]) 

213def get_logs_by_class_route(class_id): 

214 """ 

215 Get all logs for a specific class (user_class_id) 

216 """ 

217 try: 

218 logs = get_logs_by_class(class_id) 

219 

220 if not logs: 

221 return success_response( 

222 f"No logs found for class {class_id}", 

223 [] 

224 ) 

225 

226 return success_response( 

227 f"Logs for class {class_id}", 

228 logs, 

229 ) 

230 except Exception as e: 

231 return error_response( 

232 f"Error fetching logs for class {class_id}: {e}", 

233 None, 

234 StatusCodes.SERVER_ERROR 

235 ) 

236 

237 

238 

239@logging_bp.route('/logs/suggestion', methods=['POST']) 

240@swag_from({ 

241 'tags': ['Logging'], 

242 'summary': 'Log a suggestion', 

243 'description': 'Logs a suggestion to the database.', 

244 'parameters': [ 

245 { 

246 'name': 'body', 

247 'in': 'body', 

248 'required': True, 

249 'schema': { 

250 'type': 'object', 

251 'properties': { 

252 'prompt': { 

253 'type': 'string', 

254 'example': 'function add(a, b)' 

255 }, 

256 'suggestionText': { 

257 'type': 'string', 

258 'example': '{\n return a + b;\n}' 

259 }, 

260 'hasBug': { 

261 'type': 'boolean', 

262 'example': False 

263 }, 

264 'model': { 

265 'type': 'string', 

266 'example': 'gpt-3' 

267 }, 

268 'userSectionid': { 

269 'type': 'string', 

270 'example': '12345' 

271 }, 

272 }, 

273 'required': ['prompt', 'suggestionText', 'hasBug', 'model'] 

274 } 

275 } 

276 ], 

277 'responses': { 

278 '200': { 

279 'description': 'Suggestion logged successfully', 

280 'schema': { 

281 'type': 'object', 

282 'properties': { 

283 'status': {'type': 'string', 'example': 'success'}, 

284 'data': { 

285 'type': 'object', 

286 'properties': { 

287 'id': {'type': 'string', 'example': "12345"}, 

288 'prompt': {'type': 'string', 'example': 'function add(a, b)'}, 

289 'suggestionText': {'type': 'string', 'example': '{\n return a + b;\n}'}, 

290 'hasBug': {'type': 'boolean', 'example': False}, 

291 'model': {'type': 'string', 'example': 'gpt-3'}, 

292 'created_at': {'type': 'timestamp', 'example': '2023-10-01T12:00:00Z'} 

293 } 

294 } 

295 } 

296 } 

297 }, 

298 '400': { 

299 'description': 'Bad request or invalid input', 

300 'schema': { 

301 'type': 'object', 

302 'properties': { 

303 'status': {'type': 'string', 'example': 'error'}, 

304 'message': {'type': 'string', 'example': 'Missing required fields: prompt, suggestionText'} 

305 } 

306 } 

307 }, 

308 '500': { 

309 'description': 'Internal server error', 

310 'schema': { 

311 'type': 'object', 

312 'properties': { 

313 'status': {'type': 'string', 'example': 'error'}, 

314 'message': {'type': 'string', 'example': 'Internal server error'} 

315 } 

316 } 

317 } 

318 } 

319}) 

320def log_suggestion_route(): 

321 data = request.json 

322 

323 # Validate required fields 

324 required_fields = ['prompt', 'suggestionArray', 'hasBug', 'model', 'userSectionId'] 

325 missing_fields = [field for field in required_fields if field not in data] 

326 

327 if missing_fields: 

328 return error_response( 

329 f"Missing required fields: {', '.join(missing_fields)}", 

330 None, 

331 StatusCodes.BAD_REQUEST 

332 ) 

333 

334 suggestion = { 

335 'prompt': data['prompt'], 

336 'suggestion_array': data['suggestionArray'], 

337 'has_bug': data['hasBug'], 

338 'model': data['model'], 

339 'user_section_id': data.get('userSectionId') 

340 } 

341 

342 try: 

343 logged_suggestion = log_suggestion(suggestion) 

344 

345 return success_response( 

346 "Logged suggestion", 

347 logged_suggestion['id'], 

348 StatusCodes.CREATED 

349 ) 

350 

351 except Exception as e: 

352 return error_response( 

353 f"Error logging event: {e}", 

354 None, 

355 StatusCodes.SERVER_ERROR 

356 ) 

357 

358@logging_bp.route('/logs/ai', methods=['GET']) 

359def ai_usage_route(): 

360 """ 

361 Retrieve AI usage statistics 

362 See Swagger docs for more information. 

363 """ 

364 try: 

365 ai_usage = get_ai_usage() 

366 

367 return success_response( 

368 "AI usage statistics", 

369 ai_usage, 

370 StatusCodes.OK 

371 ) 

372 

373 except Exception as e: 

374 return error_response( 

375 f"Error fetching AI usage: {e}", 

376 None, 

377 StatusCodes.SERVER_ERROR 

378 ) 

379 

380@logging_bp.route('/health', methods=['GET']) 

381def health_check(): 

382 """ 

383 Health check endpoint to verify the service is running. 

384 """ 

385 return success_response( 

386 "Service is running", 

387 None, 

388 StatusCodes.OK 

389 ) 

390