package handlers import ( "context" "encoding/json" "net/http" "git.warky.dev/wdevs/whatshooked/pkg/config" "git.warky.dev/wdevs/whatshooked/pkg/logging" ) // Accounts returns the list of all configured WhatsApp accounts func (h *Handlers) Accounts(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") writeJSON(w, h.config.WhatsApp) } // AddAccount adds a new WhatsApp account to the system func (h *Handlers) AddAccount(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var account config.WhatsAppConfig if err := json.NewDecoder(r.Body).Decode(&account); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Connect to the account if err := h.whatsappMgr.Connect(context.Background(), account); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Update config h.config.WhatsApp = append(h.config.WhatsApp, account) if h.configPath != "" { if err := config.Save(h.configPath, h.config); err != nil { logging.Error("Failed to save config after adding account", "account_id", account.ID, "error", err) } else { logging.Info("Config saved after adding account", "account_id", account.ID) } } w.WriteHeader(http.StatusCreated) writeJSON(w, map[string]string{"status": "ok", "account_id": account.ID}) } // RemoveAccount removes a WhatsApp account from the system func (h *Handlers) RemoveAccount(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { ID string `json:"id"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Disconnect the account if err := h.whatsappMgr.Disconnect(req.ID); err != nil { logging.Warn("Failed to disconnect account during removal", "account_id", req.ID, "error", err) // Continue with removal even if disconnect fails } // Remove from config found := false newAccounts := make([]config.WhatsAppConfig, 0) for _, acc := range h.config.WhatsApp { if acc.ID != req.ID { newAccounts = append(newAccounts, acc) } else { found = true } } if !found { http.Error(w, "Account not found", http.StatusNotFound) return } h.config.WhatsApp = newAccounts // Save config if h.configPath != "" { if err := config.Save(h.configPath, h.config); err != nil { logging.Error("Failed to save config after removing account", "account_id", req.ID, "error", err) } else { logging.Info("Config saved after removing account", "account_id", req.ID) } } writeJSON(w, map[string]string{"status": "ok"}) } // DisableAccount disables a WhatsApp account func (h *Handlers) DisableAccount(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { ID string `json:"id"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Find the account found := false for i := range h.config.WhatsApp { if h.config.WhatsApp[i].ID == req.ID { found = true // Check if already disabled if h.config.WhatsApp[i].Disabled { logging.Info("Account already disabled", "account_id", req.ID) writeJSON(w, map[string]string{"status": "ok", "message": "account already disabled"}) return } // Disconnect the account if err := h.whatsappMgr.Disconnect(req.ID); err != nil { logging.Warn("Failed to disconnect account during disable", "account_id", req.ID, "error", err) // Continue with disabling even if disconnect fails } // Mark as disabled h.config.WhatsApp[i].Disabled = true logging.Info("Account disabled", "account_id", req.ID) break } } if !found { http.Error(w, "Account not found", http.StatusNotFound) return } // Save config if h.configPath != "" { if err := config.Save(h.configPath, h.config); err != nil { logging.Error("Failed to save config after disabling account", "account_id", req.ID, "error", err) http.Error(w, "Failed to save configuration", http.StatusInternalServerError) return } logging.Info("Config saved after disabling account", "account_id", req.ID) } writeJSON(w, map[string]string{"status": "ok", "account_id": req.ID}) } // EnableAccount enables a WhatsApp account func (h *Handlers) EnableAccount(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { ID string `json:"id"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Find the account var accountConfig *config.WhatsAppConfig for i := range h.config.WhatsApp { if h.config.WhatsApp[i].ID == req.ID { accountConfig = &h.config.WhatsApp[i] break } } if accountConfig == nil { http.Error(w, "Account not found", http.StatusNotFound) return } // Check if already enabled if !accountConfig.Disabled { logging.Info("Account already enabled", "account_id", req.ID) writeJSON(w, map[string]string{"status": "ok", "message": "account already enabled"}) return } // Mark as enabled accountConfig.Disabled = false // Connect the account if err := h.whatsappMgr.Connect(context.Background(), *accountConfig); err != nil { logging.Error("Failed to connect account during enable", "account_id", req.ID, "error", err) // Revert the disabled flag accountConfig.Disabled = true http.Error(w, "Failed to connect account: "+err.Error(), http.StatusInternalServerError) return } logging.Info("Account enabled and connected", "account_id", req.ID) // Save config if h.configPath != "" { if err := config.Save(h.configPath, h.config); err != nil { logging.Error("Failed to save config after enabling account", "account_id", req.ID, "error", err) http.Error(w, "Failed to save configuration", http.StatusInternalServerError) return } logging.Info("Config saved after enabling account", "account_id", req.ID) } writeJSON(w, map[string]string{"status": "ok", "account_id": req.ID}) } // UpdateAccount updates an existing WhatsApp account configuration func (h *Handlers) UpdateAccount(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost && r.Method != http.MethodPut { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var updates config.WhatsAppConfig if err := json.NewDecoder(r.Body).Decode(&updates); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if updates.ID == "" { http.Error(w, "Account ID is required", http.StatusBadRequest) return } // Find the account found := false var oldConfig config.WhatsAppConfig for i := range h.config.WhatsApp { if h.config.WhatsApp[i].ID == updates.ID { found = true oldConfig = h.config.WhatsApp[i] // Update fields (preserve ID and Type) updates.ID = oldConfig.ID if updates.Type == "" { updates.Type = oldConfig.Type } h.config.WhatsApp[i] = updates logging.Info("Account configuration updated", "account_id", updates.ID) break } } if !found { http.Error(w, "Account not found", http.StatusNotFound) return } // If the account was enabled and settings changed, reconnect it if !updates.Disabled { // Disconnect old connection if err := h.whatsappMgr.Disconnect(updates.ID); err != nil { logging.Warn("Failed to disconnect account during update", "account_id", updates.ID, "error", err) } // Reconnect with new settings if err := h.whatsappMgr.Connect(context.Background(), updates); err != nil { logging.Error("Failed to reconnect account after update", "account_id", updates.ID, "error", err) http.Error(w, "Failed to reconnect account: "+err.Error(), http.StatusInternalServerError) return } logging.Info("Account reconnected with new settings", "account_id", updates.ID) } // Save config if h.configPath != "" { if err := config.Save(h.configPath, h.config); err != nil { logging.Error("Failed to save config after updating account", "account_id", updates.ID, "error", err) http.Error(w, "Failed to save configuration", http.StatusInternalServerError) return } logging.Info("Config saved after updating account", "account_id", updates.ID) } writeJSON(w, map[string]string{"status": "ok", "account_id": updates.ID}) }