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, _paginate, ) _logger = logging.getLogger(__name__) def _ser_notif(n): return { 'id': n.id, 'title': n.title or '', 'message': n.message or '', 'type': n.type or 'info', 'is_read': n.is_read, 'read_at': str(n.read_at) if n.read_at else None, 'reference_model': n.reference_model or None, 'reference_id': n.reference_id or None, 'created_at': str(n.create_date) if n.create_date else '', } def _ser_rule(r): return { 'id': r.id, 'name': r.name or '', 'event_type': r.event_type or '', 'template': r.template or '', 'is_active': r.is_active, 'recipients': r.recipients or 'all', 'channels': r.channels or '', } class NotificationsController(http.Controller): @http.route('/api/notifications', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def list_notifications(self, **kw): try: M = request.env['encoach.notification'].sudo() domain = [('user_id', '=', request.env.uid)] if kw.get('type'): domain.append(('type', '=', kw['type'])) if kw.get('is_read') == 'false': domain.append(('is_read', '=', False)) elif kw.get('is_read') == 'true': domain.append(('is_read', '=', True)) offset, limit, page = _paginate(kw) total = M.search_count(domain) recs = M.search(domain, offset=offset, limit=limit, order='create_date desc') items = [_ser_notif(r) for r in recs] return _json_response({'items': items, 'data': items, 'total': total, 'page': page, 'size': limit}) except Exception as e: return _error_response(str(e), 500) @http.route('/api/notifications//read', type='http', auth='public', methods=['POST'], csrf=False) @jwt_required def mark_read(self, nid, **kw): try: rec = request.env['encoach.notification'].sudo().browse(nid) if not rec.exists(): return _error_response('Not found', 404) from datetime import datetime rec.write({'is_read': True, 'read_at': str(datetime.now())}) return _json_response(_ser_notif(rec)) except Exception as e: return _error_response(str(e), 500) @http.route('/api/notifications/read-all', type='http', auth='public', methods=['POST'], csrf=False) @jwt_required def mark_all_read(self, **kw): try: from datetime import datetime recs = request.env['encoach.notification'].sudo().search([ ('user_id', '=', request.env.uid), ('is_read', '=', False) ]) recs.write({'is_read': True, 'read_at': str(datetime.now())}) return _json_response({'success': True}) except Exception as e: return _error_response(str(e), 500) @http.route('/api/notifications/unread-count', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def unread_count(self, **kw): try: count = request.env['encoach.notification'].sudo().search_count([ ('user_id', '=', request.env.uid), ('is_read', '=', False) ]) return _json_response({'count': count}) except Exception as e: return _error_response(str(e), 500) # ── Rules ──────────────────────────────────────────────────────── @http.route('/api/notification-rules', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def list_rules(self, **kw): try: recs = request.env['encoach.notification.rule'].sudo().search([], order='id desc') return _json_response([_ser_rule(r) for r in recs]) except Exception as e: return _error_response(str(e), 500) @http.route('/api/notification-rules', type='http', auth='public', methods=['POST'], csrf=False) @jwt_required def create_rule(self, **kw): try: body = _get_json_body() vals = { 'name': body.get('name', ''), 'event_type': body.get('event_type', ''), } if body.get('template'): vals['template'] = body['template'] if body.get('recipients'): vals['recipients'] = body['recipients'] if body.get('channels'): vals['channels'] = body['channels'] if 'is_active' in body: vals['is_active'] = bool(body['is_active']) rec = request.env['encoach.notification.rule'].sudo().create(vals) return _json_response(_ser_rule(rec)) except Exception as e: return _error_response(str(e), 500) @http.route('/api/notification-rules/', type='http', auth='public', methods=['PATCH', 'PUT'], csrf=False) @jwt_required def update_rule(self, rid, **kw): try: rec = request.env['encoach.notification.rule'].sudo().browse(rid) if not rec.exists(): return _error_response('Not found', 404) body = _get_json_body() vals = {} for k in ('name', 'event_type', 'template', 'recipients', 'channels'): if k in body: vals[k] = body[k] if 'is_active' in body: vals['is_active'] = bool(body['is_active']) if vals: rec.write(vals) return _json_response(_ser_rule(rec)) except Exception as e: return _error_response(str(e), 500) @http.route('/api/notification-rules/', type='http', auth='public', methods=['DELETE'], csrf=False) @jwt_required def delete_rule(self, rid, **kw): try: rec = request.env['encoach.notification.rule'].sudo().browse(rid) if rec.exists(): rec.unlink() return _json_response({'success': True}) except Exception as e: return _error_response(str(e), 500) # ── Preferences ────────────────────────────────────────────────── @http.route('/api/notification-preferences', type='http', auth='public', methods=['GET'], csrf=False) @jwt_required def get_preferences(self, **kw): try: M = request.env['encoach.notification.preference'].sudo() rec = M.search([('user_id', '=', request.env.uid)], limit=1) if not rec: rec = M.create({'user_id': request.env.uid}) return _json_response({ 'email_enabled': rec.email_enabled, 'push_enabled': rec.push_enabled, 'in_app_enabled': rec.in_app_enabled, 'digest_frequency': rec.digest_frequency, }) except Exception as e: return _error_response(str(e), 500) @http.route('/api/notification-preferences', type='http', auth='public', methods=['PATCH', 'PUT'], csrf=False) @jwt_required def update_preferences(self, **kw): try: M = request.env['encoach.notification.preference'].sudo() rec = M.search([('user_id', '=', request.env.uid)], limit=1) if not rec: rec = M.create({'user_id': request.env.uid}) body = _get_json_body() vals = {} for k in ('email_enabled', 'push_enabled', 'in_app_enabled'): if k in body: vals[k] = bool(body[k]) if 'digest_frequency' in body: vals['digest_frequency'] = body['digest_frequency'] if vals: rec.write(vals) return _json_response({ 'email_enabled': rec.email_enabled, 'push_enabled': rec.push_enabled, 'in_app_enabled': rec.in_app_enabled, 'digest_frequency': rec.digest_frequency, }) except Exception as e: return _error_response(str(e), 500)