import json import logging from odoo import http from odoo.http import request from .base import EncoachMixin _logger = logging.getLogger(__name__) class StatsController(EncoachMixin, http.Controller): # -------------------------------------------------------------- save @http.route('/api/stats', type='http', auth='public', methods=['POST', 'OPTIONS'], csrf=False, cors='*') def save_stats(self, **kwargs): try: user = self._authenticate() if not user: return self._error_response('Unauthorized', 401) body = self._get_json_body() stat_id = body.get('_id') or body.get('id') Stat = request.env['encoach.stat'].sudo() vals = {} if body.get('sessionId'): vals['session_id'] = int(body['sessionId']) if body.get('module'): vals['module'] = body['module'] if 'score' in body: vals['score'] = body['score'] if body.get('result') is not None: vals['result'] = json.dumps(body['result']) if isinstance(body['result'], dict) else body['result'] if body.get('examId'): vals['exam_id'] = int(body['examId']) if body.get('assignmentId'): vals['assignment_id'] = int(body['assignmentId']) if stat_id: record = Stat.browse(int(stat_id)) if record.exists(): record.write(vals) return self._json_response(self._serialize_stat(record)) vals['user_id'] = user.id record = Stat.create(vals) return self._json_response(self._serialize_stat(record), status=201) except Exception: _logger.exception("Save stats error") return self._error_response('Internal server error', 500) # --------------------------------------------------------------- get @http.route( '/api/stats/', type='http', auth='public', methods=['GET', 'OPTIONS'], csrf=False, cors='*', ) def get_stat(self, stat_id, **kwargs): try: user = self._authenticate() if not user: return self._error_response('Unauthorized', 401) stat = request.env['encoach.stat'].sudo().browse(stat_id) if not stat.exists(): return self._error_response('Stat not found', 404) return self._json_response(self._serialize_stat(stat)) except Exception: _logger.exception("Get stat error") return self._error_response('Internal server error', 500) # --------------------------------------------------------- statistical @http.route('/api/statistical', type='http', auth='public', methods=['POST', 'OPTIONS'], csrf=False, cors='*') def statistical_query(self, **kwargs): """Run statistical queries against exam stats.""" try: user = self._authenticate() if not user: return self._error_response('Unauthorized', 401) body = self._get_json_body() Stat = request.env['encoach.stat'].sudo() domain = [] user_id = body.get('userId') if user_id: domain.append(('user_id', '=', int(user_id))) module = body.get('module') if module: domain.append(('module', '=', module)) group_id = body.get('groupId') if group_id: domain.append(('assignment_id.group_id', '=', int(group_id))) assignment_id = body.get('assignmentId') if assignment_id: domain.append(('assignment_id', '=', int(assignment_id))) date_from = body.get('dateFrom') if date_from: domain.append(('create_date', '>=', date_from)) date_to = body.get('dateTo') if date_to: domain.append(('create_date', '<=', date_to)) stats = Stat.search(domain, order='create_date desc') scores = [s.score for s in stats if s.score] avg_score = sum(scores) / len(scores) if scores else 0 total = len(stats) module_breakdown = {} for s in stats: mod = getattr(s, 'module', 'unknown') if mod not in module_breakdown: module_breakdown[mod] = {'count': 0, 'scores': []} module_breakdown[mod]['count'] += 1 if s.score: module_breakdown[mod]['scores'].append(s.score) for mod, data in module_breakdown.items(): data['average'] = sum(data['scores']) / len(data['scores']) if data['scores'] else 0 del data['scores'] return self._json_response({ 'total': total, 'averageScore': round(avg_score, 2), 'moduleBreakdown': module_breakdown, 'stats': [self._serialize_stat(s) for s in stats[:100]], }) except Exception: _logger.exception("Statistical query error") return self._error_response('Internal server error', 500)