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__) ENTITY_MODEL = 'encoach.entity' def _entity_to_dict(entity): d = entity.to_api_dict() if hasattr(entity, 'to_api_dict') else { 'id': entity.id, 'name': entity.name, 'code': getattr(entity, 'code', '') or '', 'type': getattr(entity, 'type', '') or '', 'active': entity.active if hasattr(entity, 'active') else True, 'user_count': getattr(entity, 'user_count', 0) or 0, } d['role_count'] = len(entity.role_ids) if hasattr(entity, 'role_ids') else 0 return d def _role_to_dict(role): return { 'id': role.id, 'name': role.name, 'code': getattr(role, 'code', '') or '', 'entity_id': role.entity_id.id if hasattr(role, 'entity_id') and role.entity_id else None, 'permission_ids': role.permission_ids.ids if hasattr(role, 'permission_ids') else [], 'user_count': len(role.user_ids) if hasattr(role, 'user_ids') else 0, } class EntityController(http.Controller): @http.route('/api/entities', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def list_entities(self, **kw): try: M = request.env[ENTITY_MODEL].sudo() domain = [] if kw.get('search'): domain.append(('name', 'ilike', kw['search'])) if kw.get('type'): domain.append(('type', '=', kw['type'])) recs = M.search(domain, order='name') items = [_entity_to_dict(r) for r in recs] return _json_response({ 'data': items, 'items': items, 'total': len(items), }) except Exception as e: _logger.exception('list entities failed') return _error_response(str(e), 500) @http.route('/api/entities/', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def get_entity(self, entity_id, **kw): try: entity = request.env[ENTITY_MODEL].sudo().browse(entity_id) if not entity.exists(): return _error_response('Entity not found', 404) return _json_response({'data': _entity_to_dict(entity)}) except Exception as e: return _error_response(str(e), 500) @http.route('/api/entities', type='http', auth='public', methods=['POST'], csrf=False) @jwt_required def create_entity(self, **kw): body = _get_json_body() name = body.get('name', '').strip() if not name: return _error_response('Name is required', 400) code = body.get('code', '').strip() if not code: code = name.upper().replace(' ', '_')[:20] vals = {'name': name, 'code': code} for field in ('type', 'primary_color', 'secondary_color', 'background_color', 'login_title', 'login_description', 'results_release_mode'): if field in body: vals[field] = body[field] try: entity = request.env[ENTITY_MODEL].sudo().create(vals) return _json_response({'data': _entity_to_dict(entity)}, 201) except Exception as e: _logger.exception('Error creating entity') msg = str(e) if 'unique' in msg.lower() or 'duplicate' in msg.lower(): return _error_response( f'An entity with code "{code}" already exists', 409) return _error_response(msg, 500) @http.route('/api/entities/', type='http', auth='public', methods=['PATCH', 'PUT'], csrf=False) @jwt_required def update_entity(self, entity_id, **kw): body = _get_json_body() try: entity = request.env[ENTITY_MODEL].sudo().browse(entity_id) if not entity.exists(): return _error_response('Entity not found', 404) vals = {} for field in ('name', 'code', 'type', 'primary_color', 'secondary_color', 'background_color', 'login_title', 'login_description', 'results_release_mode', 'active'): if field in body: vals[field] = body[field] if vals: entity.write(vals) return _json_response({'data': _entity_to_dict(entity)}) except Exception as e: return _error_response(str(e), 500) @http.route('/api/entities/', type='http', auth='public', methods=['DELETE'], csrf=False) @jwt_required def delete_entity(self, entity_id, **kw): try: entity = request.env[ENTITY_MODEL].sudo().browse(entity_id) if not entity.exists(): return _error_response('Entity not found', 404) entity.sudo().unlink() return _json_response({'success': True}) except Exception as e: msg = str(e) if 'foreign key' in msg.lower() or 'restrict' in msg.lower(): return _error_response( 'Cannot delete: entity has linked users or roles', 409) return _error_response(msg, 500) @http.route('/api/entities//roles', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def list_entity_roles(self, entity_id, **kw): try: roles = request.env['encoach.role'].sudo().search([ ('entity_id', '=', entity_id) ]) return _json_response({ 'data': [_role_to_dict(r) for r in roles], 'total': len(roles), }) except Exception as e: return _error_response(str(e), 500) @http.route('/api/entities//roles', type='http', auth='public', methods=['POST'], csrf=False) @jwt_required def create_entity_role(self, entity_id, **kw): body = _get_json_body() name = body.get('name', '').strip() if not name: return _error_response('Role name is required', 400) vals = {'name': name, 'entity_id': entity_id} if body.get('permission_ids'): vals['permission_ids'] = [(6, 0, [int(p) for p in body['permission_ids']])] try: role = request.env['encoach.role'].sudo().create(vals) return _json_response({'data': _role_to_dict(role)}, 201) except Exception as e: return _error_response(str(e), 500)