apps/feeds/handlers_admin.go 6.0 K raw
1
package main
2
3
import (
4
	"fmt"
5
	"net/http"
6
	"strings"
7
8
	"github.com/stevedylandev/andromeda/pkg/auth"
9
	"github.com/stevedylandev/andromeda/pkg/web"
10
)
11
12
func (a *App) loginGetHandler(w http.ResponseWriter, r *http.Request) {
13
	web.Render(a.Templates, w, "login.html", loginPageData{Error: r.URL.Query().Get("error")}, a.Log)
14
}
15
16
func (a *App) loginPostHandler(w http.ResponseWriter, r *http.Request) {
17
	if a.AdminPassword == "" {
18
		web.RedirectWithError(w, r, "/admin/login", "No admin password configured")
19
		return
20
	}
21
	if err := r.ParseForm(); err != nil {
22
		web.RedirectWithError(w, r, "/admin/login", "Bad request")
23
		return
24
	}
25
	if !auth.VerifyPassword(r.FormValue("password"), a.AdminPassword) {
26
		web.RedirectWithError(w, r, "/admin/login", "Invalid password")
27
		return
28
	}
29
	token, err := a.Sessions.Create()
30
	if err != nil {
31
		a.Log.Error("create session failed", "err", err)
32
		web.RedirectWithError(w, r, "/admin/login", "Session error")
33
		return
34
	}
35
	a.Sessions.PruneExpired()
36
	http.SetCookie(w, a.Sessions.SessionCookie(token))
37
	http.Redirect(w, r, "/admin", http.StatusSeeOther)
38
}
39
40
func (a *App) logoutHandler(w http.ResponseWriter, r *http.Request) {
41
	if cookie, err := r.Cookie(a.Sessions.CookieName); err == nil {
42
		a.Sessions.Delete(cookie.Value)
43
	}
44
	http.SetCookie(w, a.Sessions.ClearCookie())
45
	http.Redirect(w, r, "/admin/login", http.StatusSeeOther)
46
}
47
48
func (a *App) adminHandler(w http.ResponseWriter, r *http.Request) {
49
	subs, _ := listSubscriptions(a.DB)
50
	cats, _ := listCategories(a.DB)
51
	catMap := map[int64]string{}
52
	for _, c := range cats {
53
		catMap[c.ID] = c.Name
54
	}
55
	rows := []adminSubRow{}
56
	for _, s := range subs {
57
		rows = append(rows, adminSubRow{ID: s.ID, Title: s.Title, FeedURL: s.FeedURL, SiteURL: firstNonEmpty(nullStringValue(s.SiteURL), s.FeedURL), CategoryName: catMap[s.CategoryID.Int64], LastFetchedAt: nullStringValue(s.LastFetchedAt), LastError: nullStringValue(s.LastError)})
58
	}
59
	web.Render(a.Templates, w, "admin.html", adminPageData{Success: r.URL.Query().Get("success"), Error: r.URL.Query().Get("error"), Subscriptions: rows, Categories: cats, PollIntervalMinutes: a.pollIntervalMinutes(), ItemCap: a.ItemCap, APIKeyConfigured: a.APIKey != ""}, a.Log)
60
}
61
62
func (a *App) discoverFeedsHandler(w http.ResponseWriter, r *http.Request) {
63
	if err := r.ParseForm(); err != nil {
64
		web.WriteError(w, http.StatusBadRequest, "bad request")
65
		return
66
	}
67
	feeds, err := discoverFeeds(r.Context(), r.FormValue("base_url"))
68
	if err != nil {
69
		web.WriteError(w, http.StatusBadRequest, err.Error())
70
		return
71
	}
72
	web.WriteJSON(w, http.StatusOK, feeds)
73
}
74
75
func (a *App) addFeedHandler(w http.ResponseWriter, r *http.Request) {
76
	if err := r.ParseForm(); err != nil {
77
		web.RedirectWithError(w, r, "/admin", "Bad request")
78
		return
79
	}
80
	body := createSubscriptionBody{FeedURL: r.FormValue("feed_url"), CategoryName: r.FormValue("category_name")}
81
	if _, err := a.createSubscription(r.Context(), body, true); err != nil {
82
		if isAlreadySubscribedError(err) {
83
			web.RedirectWithError(w, r, "/admin", "Already subscribed")
84
			return
85
		}
86
		web.RedirectWithError(w, r, "/admin", "Failed to add feed")
87
		return
88
	}
89
	web.RedirectWithSuccess(w, r, "/admin", "Feed added and will be fetched in the background")
90
}
91
92
func (a *App) deleteFeedHandler(w http.ResponseWriter, r *http.Request) {
93
	id, ok := web.PathInt64(r, "id")
94
	if !ok {
95
		web.RedirectWithError(w, r, "/admin", "Invalid feed ID")
96
		return
97
	}
98
	deleted, err := deleteSubscription(a.DB, id)
99
	if err != nil || !deleted {
100
		web.RedirectWithError(w, r, "/admin", "Failed to remove")
101
		return
102
	}
103
	web.RedirectWithSuccess(w, r, "/admin", "Feed removed")
104
}
105
106
func (a *App) updateSubCategoryHandler(w http.ResponseWriter, r *http.Request) {
107
	id, ok := web.PathInt64(r, "id")
108
	if !ok {
109
		web.RedirectWithError(w, r, "/admin", "Invalid feed ID")
110
		return
111
	}
112
	if err := r.ParseForm(); err != nil {
113
		web.RedirectWithError(w, r, "/admin", "Bad request")
114
		return
115
	}
116
	categoryID, err := a.resolveCategory(nil, r.FormValue("category_name"))
117
	if err != nil {
118
		web.RedirectWithError(w, r, "/admin", "Failed to update category")
119
		return
120
	}
121
	if err := updateSubscriptionCategory(a.DB, id, categoryID); err != nil {
122
		web.RedirectWithError(w, r, "/admin", "Failed to update category")
123
		return
124
	}
125
	web.RedirectWithSuccess(w, r, "/admin", "Category updated")
126
}
127
128
func (a *App) addCategoryHandler(w http.ResponseWriter, r *http.Request) {
129
	if err := r.ParseForm(); err != nil {
130
		web.RedirectWithError(w, r, "/admin", "Bad request")
131
		return
132
	}
133
	name := strings.TrimSpace(r.FormValue("name"))
134
	if name == "" {
135
		web.RedirectWithError(w, r, "/admin", "Name required")
136
		return
137
	}
138
	if _, err := getOrCreateCategory(a.DB, name); err != nil {
139
		web.RedirectWithError(w, r, "/admin", "Failed to add category")
140
		return
141
	}
142
	web.RedirectWithSuccess(w, r, "/admin", "Category added")
143
}
144
145
func (a *App) deleteCategoryHandler(w http.ResponseWriter, r *http.Request) {
146
	id, ok := web.PathInt64(r, "id")
147
	if !ok {
148
		web.RedirectWithError(w, r, "/admin", "Invalid category ID")
149
		return
150
	}
151
	deleted, err := deleteCategory(a.DB, id)
152
	if err != nil {
153
		web.RedirectWithError(w, r, "/admin", "Failed to remove category")
154
		return
155
	}
156
	if !deleted {
157
		web.RedirectWithError(w, r, "/admin", "Category not found")
158
		return
159
	}
160
	web.RedirectWithSuccess(w, r, "/admin", "Category removed")
161
}
162
163
func (a *App) importOPMLHandler(w http.ResponseWriter, r *http.Request) {
164
	summary, err := a.readAndImportOPML(r)
165
	if err != nil {
166
		web.RedirectWithError(w, r, "/admin", "No file uploaded")
167
		return
168
	}
169
	web.RedirectWithSuccess(w, r, "/admin", fmt.Sprintf("Imported %d, skipped %d", summary.Imported, summary.Skipped))
170
}
171
172
func (a *App) updateSettingsFormHandler(w http.ResponseWriter, r *http.Request) {
173
	if err := r.ParseForm(); err != nil {
174
		web.RedirectWithError(w, r, "/admin", "Bad request")
175
		return
176
	}
177
	mins, ok := formPollMinutes(r)
178
	if !ok {
179
		web.RedirectWithError(w, r, "/admin", "Interval must be 1-1440")
180
		return
181
	}
182
	if err := setSetting(a.DB, "poll_interval_minutes", fmt.Sprintf("%d", mins)); err != nil {
183
		web.RedirectWithError(w, r, "/admin", "Failed to save settings")
184
		return
185
	}
186
	web.RedirectWithSuccess(w, r, "/admin", "Settings saved")
187
}