# -*- coding: utf-8 -*- from odoo import http, fields from odoo.http import request import json import logging _logger = logging.getLogger(__name__) class ExpertController(http.Controller): @http.route('/expert_theme/test', type='http', auth='user') def test_controller(self): """Simple test endpoint to verify controller is working""" return request.make_json_response({ 'success': True, 'message': 'Controller is working!', 'timestamp': fields.Datetime.now() }) @http.route('/expert_theme/get_css_variables', type='http', auth='user') def get_css_variables(self): """Get CSS variables for the active theme configuration""" try: config = request.env['expert.theme.config'].get_active_config() css_variables = config.get_css_variables() return request.make_json_response({ 'success': True, 'css_variables': css_variables }) except Exception as e: return request.make_json_response({ 'success': False, 'error': str(e) }) @http.route('/expert_theme/apply_theme', type='http', auth='user', methods=['POST']) def apply_theme(self): """Apply theme changes immediately""" try: # Get the active configuration config = request.env['expert.theme.config'].get_active_config() # Apply the theme (this could trigger cache invalidation, etc.) config.apply_theme() return request.make_json_response({ 'success': True, 'message': 'Theme applied successfully!' }) except Exception as e: return request.make_json_response({ 'success': False, 'error': str(e) }) @http.route('/web/login', type='http', auth='none', methods=['GET', 'POST'], csrf=False) def web_login(self, redirect=None, **kw): """Override Odoo login to use expert login templates when configured. - POST: delegate to standard Odoo login logic (authentication, redirects, etc.). - GET: render the active expert login template if not 'default', otherwise use standard login. """ # Import Home from its new location in Odoo 18 from odoo.addons.web.controllers.home import Home # Handle login submission via standard controller if request.httprequest.method == 'POST': home = Home() return home.web_login(redirect=redirect, **kw) # GET: decide which template to render try: login_template = request.env['expert.login.template'].sudo().get_active_template() template_name = login_template.get_template_name() except Exception as e: _logger.error("Error getting active login template: %s", e) template_name = 'web.login' # For default template, just call the standard login if template_name == 'web.login': home = Home() return home.web_login(redirect=redirect, **kw) # Try to render the selected expert template; fall back to default on error try: return request.render(template_name, { 'redirect': redirect or '', 'login': kw.get('login', ''), 'login_template': login_template, }) except Exception as e: _logger.error("Error rendering login template '%s': %s", template_name, e) home = Home() return home.web_login(redirect=redirect, **kw) @http.route('/expert_theme/get_login_template_styles', type='http', auth='public', methods=['GET']) def get_login_template_styles(self): """Get CSS styles for the active login template (public access for login page)""" try: template = request.env['expert.login.template'].sudo().get_active_template() styles = template.get_template_styles() return request.make_json_response({ 'success': True, 'styles': styles }) except Exception as e: # Return default styles if error return request.make_json_response({ 'success': False, 'error': str(e), 'styles': {'background_color': '#FFFFFF'} }) @http.route('/expert_theme/get_installed_modules_http', type='http', auth='user') def get_installed_modules_http(self): """Return list of installed modules for the home page via HTTP""" try: # Get all installed modules installed_modules = request.env['ir.module.module'].search([ ('state', '=', 'installed'), ('name', '!=', 'expert_theme') # Exclude our own module ]) # Get all top-level menu items that belong to installed modules menu_items = request.env['ir.ui.menu'].search([ ('parent_id', '=', False), # Top level menus only ('active', '=', True), ('name', 'not in', ['Expert Home', 'Dashboard']) # Exclude our own menus ]) result = [] installed_module_names = installed_modules.mapped('name') debug_info = { 'total_installed_modules': len(installed_modules), 'total_menu_items': len(menu_items) } for menu in menu_items: # Check if this menu belongs to an installed module module_name = None if menu.web_icon and ',' in menu.web_icon: module_name = menu.web_icon.split(',')[0] # Include menu if it belongs to an installed module OR if it has no web_icon (base modules) if (module_name and module_name in installed_module_names) or not menu.web_icon: # Create URL based on action type - use proper Odoo navigation if menu.action and menu.action.type == 'ir.actions.act_window': # For act_window, use the action ID url = f'/web#action={menu.action.id}' elif menu.action and menu.action.type == 'ir.actions.client': # For client actions, use the action ID url = f'/web#action={menu.action.id}' elif menu.action and menu.action.type == 'ir.actions.server': # For server actions, use the action ID url = f'/web#action={menu.action.id}' else: # For menus without actions, use menu_id url = f'/web#menu_id={menu.id}' result.append({ 'id': menu.id, 'name': menu.name, 'web_icon': menu.web_icon or 'base,static/description/icon.png', 'action': menu.action.id if menu.action else False, 'url': url, 'module_name': module_name }) return request.make_json_response({ 'success': True, 'modules': result, 'debug_info': debug_info }) except Exception as e: return request.make_json_response({ 'success': False, 'error': str(e) }) @http.route('/web/signup', type='http', auth='public', methods=['GET', 'POST'], website=True, csrf=False) def web_auth_signup(self, redirect=None, **kw): """Override Odoo signup to use expert signup templates when modern template is active. - POST: delegate to standard Odoo signup logic (authentication, redirects, etc.). - GET: render the active expert signup template if modern template is active, otherwise use standard signup. """ # Import AuthSignupHome from auth_signup module try: from odoo.addons.auth_signup.controllers.main import AuthSignupHome except ImportError: # If auth_signup is not installed, return 404 from werkzeug.exceptions import NotFound raise NotFound() # Handle signup submission via standard controller if request.httprequest.method == 'POST': auth_signup_home = AuthSignupHome() return auth_signup_home.web_auth_signup(redirect=redirect, **kw) # GET: decide which template to render try: login_template = request.env['expert.login.template'].sudo().get_active_template() template_name = login_template.get_signup_template_name() except Exception as e: _logger.error("Error getting active signup template: %s", e) template_name = 'auth_signup.signup' # For default template, just call the standard signup if template_name == 'auth_signup.signup': auth_signup_home = AuthSignupHome() return auth_signup_home.web_auth_signup(redirect=redirect, **kw) # Try to render the selected expert template; fall back to default on error try: # Get signup context from auth_signup auth_signup_home = AuthSignupHome() qcontext = auth_signup_home.get_auth_signup_qcontext() qcontext.update({ 'redirect': redirect or '', 'login': kw.get('login', ''), 'login_template': login_template, }) response = request.render(template_name, qcontext) response.headers['X-Frame-Options'] = 'SAMEORIGIN' response.headers['Content-Security-Policy'] = "frame-ancestors 'self'" return response except Exception as e: _logger.error("Error rendering signup template '%s': %s", template_name, e) auth_signup_home = AuthSignupHome() return auth_signup_home.web_auth_signup(redirect=redirect, **kw) @http.route('/web/reset_password', type='http', auth='public', methods=['GET', 'POST'], website=True, csrf=False) def web_auth_reset_password(self, redirect=None, **kw): """Override Odoo reset password to use expert reset password templates when modern template is active. - POST: delegate to standard Odoo reset password logic (authentication, redirects, etc.). - GET: render the active expert reset password template if modern template is active, otherwise use standard reset password. """ # Import AuthSignupHome from auth_signup module try: from odoo.addons.auth_signup.controllers.main import AuthSignupHome except ImportError: # If auth_signup is not installed, return 404 from werkzeug.exceptions import NotFound raise NotFound() # Handle reset password submission via standard controller if request.httprequest.method == 'POST': auth_signup_home = AuthSignupHome() return auth_signup_home.web_auth_reset_password(redirect=redirect, **kw) # GET: decide which template to render try: login_template = request.env['expert.login.template'].sudo().get_active_template() template_name = login_template.get_reset_password_template_name() except Exception as e: _logger.error("Error getting active reset password template: %s", e) template_name = 'auth_signup.reset_password' # For default template, just call the standard reset password if template_name == 'auth_signup.reset_password': auth_signup_home = AuthSignupHome() return auth_signup_home.web_auth_reset_password(redirect=redirect, **kw) # Try to render the selected expert template; fall back to default on error try: # Get reset password context from auth_signup auth_signup_home = AuthSignupHome() qcontext = auth_signup_home.get_auth_signup_qcontext() qcontext.update({ 'redirect': redirect or '', 'login': kw.get('login', ''), 'login_template': login_template, }) response = request.render(template_name, qcontext) response.headers['X-Frame-Options'] = 'SAMEORIGIN' response.headers['Content-Security-Policy'] = "frame-ancestors 'self'" return response except Exception as e: _logger.error("Error rendering reset password template '%s': %s", template_name, e) auth_signup_home = AuthSignupHome() return auth_signup_home.web_auth_reset_password(redirect=redirect, **kw)