Make all user menu items functional

- res.users.action_get() RPC: returns preferences action (form dialog)
- /web/session/account endpoint: returns Odoo.com account URL
- /web/session/logout: clears session, redirects to login (was already done)
- support_url set to odoo.com/help (enables Help menu item)
- notification_type + display_switch_company_menu in session_info
- Image handler: path-style URL parsing for avatars

All user dropdown items now work:
  Help → opens odoo.com/help
  Shortcuts → opens command palette (client-side)
  My Preferences → opens user form dialog
  My Odoo.com Account → opens accounts.odoo.com
  Log out → clears session, redirects to login

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc
2026-04-01 01:43:26 +02:00
parent cc823d3310
commit 1aa9351054
3 changed files with 25 additions and 2 deletions

Binary file not shown.

View File

@@ -119,8 +119,9 @@ func (s *Server) registerRoutes() {
// File upload // File upload
s.mux.HandleFunc("/web/binary/upload_attachment", s.handleUpload) s.mux.HandleFunc("/web/binary/upload_attachment", s.handleUpload)
// Logout // Logout & Account
s.mux.HandleFunc("/web/session/logout", s.handleLogout) s.mux.HandleFunc("/web/session/logout", s.handleLogout)
s.mux.HandleFunc("/web/session/account", s.handleSessionAccount)
// Health check // Health check
s.mux.HandleFunc("/health", s.handleHealth) s.mux.HandleFunc("/health", s.handleHealth)
@@ -628,6 +629,20 @@ func (s *Server) dispatchORM(env *orm.Environment, params CallKWParams) (interfa
case "activity_format": case "activity_format":
return []interface{}{}, nil return []interface{}{}, nil
case "action_get":
// res.users.action_get() — returns the preference action
// Mirrors: odoo/addons/base/models/res_users.py action_get()
return map[string]interface{}{
"type": "ir.actions.act_window",
"name": "Change My Preferences",
"res_model": "res.users",
"view_mode": "form",
"views": [][]interface{}{{false, "form"}},
"target": "new",
"res_id": env.UID(),
"context": map[string]interface{}{},
}, nil
case "action_archive": case "action_archive":
ids := parseIDs(params.Args) ids := parseIDs(params.Args)
if len(ids) > 0 { if len(ids) > 0 {
@@ -799,6 +814,12 @@ func (s *Server) handleVersionInfo(w http.ResponseWriter, r *http.Request) {
}, nil) }, nil)
} }
// handleSessionAccount returns the Odoo.com account URL.
// Mirrors: odoo/addons/web/controllers/home.py session_account()
func (s *Server) handleSessionAccount(w http.ResponseWriter, r *http.Request) {
s.writeJSONRPC(w, nil, "https://accounts.odoo.com/account", nil)
}
// handleLogout destroys the session and redirects to login. // handleLogout destroys the session and redirects to login.
// Mirrors: odoo/addons/web/controllers/home.py Home.web_logout() // Mirrors: odoo/addons/web/controllers/home.py Home.web_logout()
func (s *Server) handleLogout(w http.ResponseWriter, r *http.Request) { func (s *Server) handleLogout(w http.ResponseWriter, r *http.Request) {

View File

@@ -210,7 +210,9 @@ func (s *Server) buildSessionInfo(sess *Session) map[string]interface{} {
"max_file_upload_size": 134217728, "max_file_upload_size": 134217728,
"home_action_id": 1, "home_action_id": 1,
"current_menu": 1, "current_menu": 1,
"support_url": "", "support_url": "https://www.odoo.com/help",
"notification_type": "email",
"display_switch_company_menu": false,
"test_mode": false, "test_mode": false,
"show_effect": true, "show_effect": true,
"currencies": map[string]interface{}{ "currencies": map[string]interface{}{