import json import logging from odoo import http from odoo.http import request from odoo.addons.encoach_api.controllers.base import ( jwt_required, _json_response, _error_response, _get_json_body, ) _logger = logging.getLogger(__name__) def _rubric_to_dict(rec): criteria_text = rec.criteria or '' criteria_count = 0 if criteria_text: try: parsed = json.loads(criteria_text) if isinstance(parsed, list): criteria_count = len(parsed) elif isinstance(parsed, dict): criteria_count = len(parsed) else: criteria_count = len([l for l in criteria_text.split('\n') if l.strip()]) except (json.JSONDecodeError, ValueError): criteria_count = len([l for l in criteria_text.split('\n') if l.strip()]) levels = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'] if rec.levels: try: parsed_levels = json.loads(rec.levels) if isinstance(parsed_levels, list) and parsed_levels: levels = parsed_levels except (json.JSONDecodeError, ValueError): pass return { 'id': rec.id, 'name': rec.name, 'skill': rec.skill or '', 'exam_type': rec.exam_type or '', 'criteria': criteria_count or 1, 'criteria_text': criteria_text, 'levels': levels, 'created': rec.create_date.strftime('%Y-%m-%d') if rec.create_date else '', } class EncoachRubricController(http.Controller): @http.route('/api/rubrics', type='http', auth='none', methods=['GET'], csrf=False) @jwt_required def list_rubrics(self, **kw): try: Rubric = request.env['encoach.rubric'].sudo() limit = int(kw.get('limit', 50)) offset = int(kw.get('offset', 0)) records = Rubric.search([], limit=limit, offset=offset, order='create_date desc') total = Rubric.search_count([]) return _json_response({ 'items': [_rubric_to_dict(r) for r in records], 'total': total, }) except Exception as e: _logger.exception('rubrics list failed') return _json_response({'error': str(e)}, 500) @http.route('/api/rubrics', type='http', auth='none', methods=['POST'], csrf=False) @jwt_required def create_rubric(self, **kw): try: body = _get_json_body() name = body.get('name', '').strip() if not name: return _error_response('name is required', 400) vals = { 'name': name, 'skill': body.get('skill', 'writing'), 'criteria': body.get('criteria', ''), 'exam_type': body.get('exam_type', 'academic'), } if 'levels' in body: vals['levels'] = json.dumps(body['levels']) rec = request.env['encoach.rubric'].sudo().create(vals) return _json_response(_rubric_to_dict(rec), 201) except Exception as e: _logger.exception('rubric create failed') return _json_response({'error': str(e)}, 500) @http.route('/api/rubrics/', type='http', auth='none', methods=['PUT'], csrf=False) @jwt_required def update_rubric(self, rubric_id, **kw): try: rec = request.env['encoach.rubric'].sudo().browse(rubric_id) if not rec.exists(): return _error_response('Rubric not found', 404) body = _get_json_body() vals = {} if 'name' in body: vals['name'] = body['name'] if 'skill' in body: vals['skill'] = body['skill'] if 'criteria' in body: vals['criteria'] = body['criteria'] if 'exam_type' in body: vals['exam_type'] = body['exam_type'] if 'levels' in body: vals['levels'] = json.dumps(body['levels']) if vals: rec.write(vals) return _json_response(_rubric_to_dict(rec)) except Exception as e: _logger.exception('rubric update failed') return _json_response({'error': str(e)}, 500) @http.route('/api/rubrics/', type='http', auth='none', methods=['DELETE'], csrf=False) @jwt_required def delete_rubric(self, rubric_id, **kw): try: rec = request.env['encoach.rubric'].sudo().browse(rubric_id) if not rec.exists(): return _error_response('Rubric not found', 404) rec.unlink() return _json_response({'success': True}) except Exception as e: _logger.exception('rubric delete failed') return _json_response({'error': str(e)}, 500) def _group_to_dict(rec): return { 'id': rec.id, 'name': rec.name, 'rubric_ids': rec.rubric_ids.ids, 'rubric_names': [r.name for r in rec.rubric_ids], 'created': rec.create_date.strftime('%Y-%m-%d') if rec.create_date else '', } class EncoachRubricGroupController(http.Controller): @http.route('/api/rubric-groups', type='http', auth='none', methods=['GET'], csrf=False) @jwt_required def list_rubric_groups(self, **kw): try: Group = request.env['encoach.rubric.group'].sudo() limit = int(kw.get('limit', 50)) offset = int(kw.get('offset', 0)) records = Group.search([], limit=limit, offset=offset, order='create_date desc') total = Group.search_count([]) return _json_response({ 'items': [_group_to_dict(r) for r in records], 'total': total, }) except Exception as e: _logger.exception('rubric-groups list failed') return _json_response({'error': str(e)}, 500) @http.route('/api/rubric-groups', type='http', auth='none', methods=['POST'], csrf=False) @jwt_required def create_rubric_group(self, **kw): try: body = _get_json_body() name = body.get('name', '').strip() if not name: return _error_response('name is required', 400) rubric_ids = body.get('rubric_ids', []) rec = request.env['encoach.rubric.group'].sudo().create({ 'name': name, 'rubric_ids': [(6, 0, rubric_ids)], }) return _json_response(_group_to_dict(rec), 201) except Exception as e: _logger.exception('rubric-group create failed') return _json_response({'error': str(e)}, 500) @http.route('/api/rubric-groups/', type='http', auth='none', methods=['PUT'], csrf=False) @jwt_required def update_rubric_group(self, group_id, **kw): try: rec = request.env['encoach.rubric.group'].sudo().browse(group_id) if not rec.exists(): return _error_response('Group not found', 404) body = _get_json_body() vals = {} if 'name' in body: vals['name'] = body['name'] if 'rubric_ids' in body: vals['rubric_ids'] = [(6, 0, body['rubric_ids'])] if vals: rec.write(vals) return _json_response(_group_to_dict(rec)) except Exception as e: _logger.exception('rubric-group update failed') return _json_response({'error': str(e)}, 500) @http.route('/api/rubric-groups/', type='http', auth='none', methods=['DELETE'], csrf=False) @jwt_required def delete_rubric_group(self, group_id, **kw): try: rec = request.env['encoach.rubric.group'].sudo().browse(group_id) if not rec.exists(): return _error_response('Group not found', 404) rec.unlink() return _json_response({'success': True}) except Exception as e: _logger.exception('rubric-group delete failed') return _json_response({'error': str(e)}, 500)