apps/feeds/handlers_api.go 5.5 K raw
1
package main
2
3
import (
4
	"net/http"
5
6
	"github.com/stevedylandev/andromeda/pkg/web"
7
)
8
9
func (a *App) listItemsAPI(w http.ResponseWriter, r *http.Request) {
10
	items, err := listItems(a.DB, itemFilterFromRequest(r))
11
	if err != nil {
12
		web.WriteError(w, http.StatusInternalServerError, err.Error())
13
		return
14
	}
15
	web.WriteJSON(w, http.StatusOK, map[string]any{"items": items})
16
}
17
18
func (a *App) markItemReadAPI(isRead bool) http.HandlerFunc {
19
	return func(w http.ResponseWriter, r *http.Request) {
20
		id, ok := web.PathInt64(r, "id")
21
		if !ok {
22
			web.WriteError(w, http.StatusBadRequest, "invalid item id")
23
			return
24
		}
25
		updated, err := markItemRead(a.DB, id, isRead)
26
		if err != nil {
27
			web.WriteError(w, http.StatusInternalServerError, err.Error())
28
			return
29
		}
30
		if !updated {
31
			web.WriteError(w, http.StatusNotFound, "item not found")
32
			return
33
		}
34
		web.WriteJSON(w, http.StatusOK, map[string]any{"ok": true, "is_read": isRead})
35
	}
36
}
37
38
func (a *App) listSubscriptionsAPI(w http.ResponseWriter, r *http.Request) {
39
	subs, err := listSubscriptions(a.DB)
40
	if err != nil {
41
		web.WriteError(w, http.StatusInternalServerError, err.Error())
42
		return
43
	}
44
	views := make([]subscriptionView, 0, len(subs))
45
	for _, sub := range subs {
46
		views = append(views, toSubscriptionView(sub))
47
	}
48
	web.WriteJSON(w, http.StatusOK, map[string]any{"subscriptions": views})
49
}
50
51
func (a *App) createSubscriptionAPI(w http.ResponseWriter, r *http.Request) {
52
	var body createSubscriptionBody
53
	if !web.DecodeJSON(w, r, &body) {
54
		return
55
	}
56
	sub, err := a.createSubscription(r.Context(), body, false)
57
	if err != nil {
58
		if isAlreadySubscribedError(err) {
59
			w.WriteHeader(http.StatusNoContent)
60
			return
61
		}
62
		web.WriteError(w, http.StatusBadRequest, err.Error())
63
		return
64
	}
65
	web.WriteJSON(w, http.StatusCreated, map[string]any{"subscription": toSubscriptionView(*sub)})
66
}
67
68
func (a *App) updateSubscriptionAPI(w http.ResponseWriter, r *http.Request) {
69
	id, ok := web.PathInt64(r, "id")
70
	if !ok {
71
		web.WriteError(w, http.StatusBadRequest, "invalid subscription id")
72
		return
73
	}
74
	var body updateSubscriptionBody
75
	if !web.DecodeJSON(w, r, &body) {
76
		return
77
	}
78
	categoryID, err := a.resolveSubscriptionCategory(body)
79
	if err != nil {
80
		web.WriteError(w, http.StatusInternalServerError, err.Error())
81
		return
82
	}
83
	if err := updateSubscriptionCategory(a.DB, id, categoryID); err != nil {
84
		web.WriteError(w, http.StatusInternalServerError, err.Error())
85
		return
86
	}
87
	web.WriteJSON(w, http.StatusOK, map[string]any{"ok": true})
88
}
89
90
func (a *App) deleteSubscriptionAPI(w http.ResponseWriter, r *http.Request) {
91
	id, ok := web.PathInt64(r, "id")
92
	if !ok {
93
		web.WriteError(w, http.StatusBadRequest, "invalid subscription id")
94
		return
95
	}
96
	deleted, err := deleteSubscription(a.DB, id)
97
	if err != nil {
98
		web.WriteError(w, http.StatusInternalServerError, err.Error())
99
		return
100
	}
101
	if !deleted {
102
		web.WriteError(w, http.StatusNotFound, "subscription not found")
103
		return
104
	}
105
	web.WriteJSON(w, http.StatusOK, map[string]any{"ok": true})
106
}
107
108
func (a *App) listCategoriesAPI(w http.ResponseWriter, r *http.Request) {
109
	cats, err := listCategories(a.DB)
110
	if err != nil {
111
		web.WriteError(w, http.StatusInternalServerError, err.Error())
112
		return
113
	}
114
	web.WriteJSON(w, http.StatusOK, map[string]any{"categories": cats})
115
}
116
117
func (a *App) createCategoryAPI(w http.ResponseWriter, r *http.Request) {
118
	var body createCategoryBody
119
	if !web.DecodeJSON(w, r, &body) {
120
		return
121
	}
122
	cat, err := getOrCreateCategory(a.DB, body.Name)
123
	if err != nil {
124
		web.WriteError(w, http.StatusInternalServerError, err.Error())
125
		return
126
	}
127
	web.WriteJSON(w, http.StatusCreated, map[string]any{"category": cat})
128
}
129
130
func (a *App) deleteCategoryAPI(w http.ResponseWriter, r *http.Request) {
131
	id, ok := web.PathInt64(r, "id")
132
	if !ok {
133
		web.WriteError(w, http.StatusBadRequest, "invalid category id")
134
		return
135
	}
136
	deleted, err := deleteCategory(a.DB, id)
137
	if err != nil {
138
		web.WriteError(w, http.StatusInternalServerError, err.Error())
139
		return
140
	}
141
	if !deleted {
142
		web.WriteError(w, http.StatusNotFound, "category not found")
143
		return
144
	}
145
	web.WriteJSON(w, http.StatusOK, map[string]any{"ok": true})
146
}
147
148
func (a *App) importOPMLAPI(w http.ResponseWriter, r *http.Request) {
149
	summary, err := a.readAndImportOPML(r)
150
	if err != nil {
151
		web.WriteError(w, http.StatusBadRequest, err.Error())
152
		return
153
	}
154
	web.WriteJSON(w, http.StatusOK, summary)
155
}
156
157
func (a *App) getSettingsAPI(w http.ResponseWriter, r *http.Request) {
158
	web.WriteJSON(w, http.StatusOK, map[string]any{"poll_interval_minutes": a.pollIntervalMinutes(), "default_poll_minutes": a.DefaultPollMinutes, "item_cap_per_feed": a.ItemCap, "api_key_configured": a.APIKey != ""})
159
}
160
161
func (a *App) updateSettingsAPI(w http.ResponseWriter, r *http.Request) {
162
	var body updateSettingsBody
163
	if !web.DecodeJSON(w, r, &body) {
164
		return
165
	}
166
	if body.PollIntervalMinutes != nil {
167
		if !validPollMinutes(*body.PollIntervalMinutes) {
168
			web.WriteError(w, http.StatusBadRequest, "poll_interval_minutes must be between 1 and 1440")
169
			return
170
		}
171
		if err := setSetting(a.DB, "poll_interval_minutes", itoa(*body.PollIntervalMinutes)); err != nil {
172
			web.WriteError(w, http.StatusInternalServerError, err.Error())
173
			return
174
		}
175
	}
176
	web.WriteJSON(w, http.StatusOK, map[string]any{"ok": true})
177
}
178
179
func (a *App) discoverAPI(w http.ResponseWriter, r *http.Request) {
180
	var body discoverBody
181
	if !web.DecodeJSON(w, r, &body) {
182
		return
183
	}
184
	feeds, err := discoverFeeds(r.Context(), body.BaseURL)
185
	if err != nil {
186
		web.WriteError(w, http.StatusBadRequest, err.Error())
187
		return
188
	}
189
	web.WriteJSON(w, http.StatusOK, map[string]any{"feeds": feeds})
190
}