feat: redirect to /settings with error banner when Gitea API token is expired
Add isTokenError() helper that detects HTTP 401/403 responses from the Gitea API, and redirectOnTokenError() that redirects to /settings with an error=token_expired query parameter. Update Dashboard, ListIssues, and ListPulls handlers to check for token errors. The settings page now displays an error banner explaining the token needs to be refreshed. Closes leeworks-agents/gitea-mobile#192 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -78,6 +78,31 @@ func getToken(r *http.Request) string {
|
||||
return middleware.TokenFromContext(r.Context())
|
||||
}
|
||||
|
||||
// isTokenError returns true if the error indicates an expired or revoked API token.
|
||||
func isTokenError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
msg := err.Error()
|
||||
return strings.Contains(msg, "API error 401") || strings.Contains(msg, "API error 403")
|
||||
}
|
||||
|
||||
// redirectOnTokenError checks if the error is a token auth error and redirects
|
||||
// to /settings with an error banner. Returns true if a redirect was performed.
|
||||
func redirectOnTokenError(w http.ResponseWriter, r *http.Request, err error) bool {
|
||||
if !isTokenError(err) {
|
||||
return false
|
||||
}
|
||||
slog.Warn("Gitea API token expired or revoked, redirecting to settings", "error", err)
|
||||
if isHTMX(r) {
|
||||
w.Header().Set("HX-Redirect", "/settings?error=token_expired")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
} else {
|
||||
http.Redirect(w, r, "/settings?error=token_expired", http.StatusSeeOther)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// getUserOrgs returns the list of org names the user belongs to.
|
||||
func (h *Handler) getUserOrgs(r *http.Request) []string {
|
||||
token := getToken(r)
|
||||
@@ -263,6 +288,9 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
queue, err := h.Client.GetTriageQueue(r.Context(), token, queryOrgs)
|
||||
if err != nil {
|
||||
if redirectOnTokenError(w, r, err) {
|
||||
return
|
||||
}
|
||||
slog.Error("failed to get triage queue", "error", err)
|
||||
data.Error = "Error loading triage queue."
|
||||
} else {
|
||||
@@ -346,6 +374,9 @@ func (h *Handler) ListIssues(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
result, err := h.Client.ListAllIssues(r.Context(), token, queryOrgs, selectedState, page, selectedLabel, selectedRepo)
|
||||
if err != nil {
|
||||
if redirectOnTokenError(w, r, err) {
|
||||
return
|
||||
}
|
||||
slog.Error("failed to list issues", "error", err)
|
||||
data.Error = "Error loading issues."
|
||||
} else {
|
||||
@@ -451,6 +482,9 @@ func (h *Handler) ListPulls(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
result, err := h.Client.ListAllPullRequests(r.Context(), token, queryOrgs, selectedState, page, selectedLabel, selectedRepo)
|
||||
if err != nil {
|
||||
if redirectOnTokenError(w, r, err) {
|
||||
return
|
||||
}
|
||||
slog.Error("failed to list pull requests", "error", err)
|
||||
data.Error = "Error loading pull requests."
|
||||
} else {
|
||||
|
||||
@@ -45,6 +45,13 @@ func (h *SettingsHandler) handleGet(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
data := settingsData{HasToken: hasToken}
|
||||
|
||||
// Show error banner when redirected due to expired/revoked token.
|
||||
if r.URL.Query().Get("error") == "token_expired" {
|
||||
data.Message = "Your Gitea API token is expired or has been revoked. Please enter a new token."
|
||||
data.MessageType = "error"
|
||||
}
|
||||
|
||||
h.renderSettings(w, data)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user