add textbox: submission works!!
Jes Olson j3s@c3f.net
Sun, 19 Mar 2023 06:09:44 -0700
5 files changed,
90 insertions(+),
38 deletions(-)
M
readme
→
readme
@@ -41,7 +41,7 @@ button: validate
POST /feeds/validate logged out: unauthorized. click here to login. - [ ] POST /feeds/validate + TODO: POST /feeds/validate make sure each url is resolvable check if feed exists in db already if it does, do nothing@@ -50,7 +50,7 @@ TODO: validate that title exists
redir -> /feeds/validate logged out: 401 unauthorized - [ ] GET /feeds/validate + TODO: GET /feeds/validate shows feed diff "if this all looks correct, hit submit:" button: submit
M
reaper/reaper.go
→
reaper/reaper.go
@@ -48,13 +48,19 @@ }
for { r.UpdateAll() - time.Sleep(12 * time.Hour) + time.Sleep(2 * time.Hour) } } -// Add fetches the given feed url, appends it to r.Feeds, and -// flushes it to the database +// Add fetches the given feed url and appends it to r.Feeds +// If the given URL is already in reaper.Feeds, Add will do nothing func (r *Reaper) Add(url string) error { + for i := range r.feeds { + if r.feeds[i].UpdateURL == url { + return nil + } + } + feed, err := rss.Fetch(url) if err != nil { return err@@ -64,16 +70,7 @@ r.mu.Lock()
r.feeds = append(r.feeds, *feed) r.mu.Unlock() - r.db.WriteFeed(feed) return nil -} - -// FlushAll flushes all feeds to the database -func (r *Reaper) FlushAll() { - // TODO: do we need this? - for _, feed := range r.feeds { - r.db.WriteFeed(&feed) - } } // UpdateAll fetches every feed & attempts updating them
M
site.go
→
site.go
@@ -170,38 +170,66 @@ }
feeds := s.reaper.GetUserFeeds(s.username(r)) if len(feeds) > 0 { - fmt.Fprintf(w, `<h3>your feeds</h3> - <table> - <thead> - <tr> - <th>title</th> - <th>url</th> - </tr> - </thead> - <tbody>`) + fmt.Fprintf(w, `<pre>you are subscribed to %d feeds</pre>`, len(feeds)) for _, feed := range feeds { fmt.Fprintf(w, ` - <tr> - <td><a href="%s">%s</a></td> - <td><p>%s</td> - <tr>`, feed.Link, feed.Title, feed.UpdateURL) +<details> +<summary>%s</summary> +<pre> +title: %s +url: %s +posts: %d +</pre> +</details>`, feed.Title, feed.Title, feed.UpdateURL, len(feed.Items)) } - fmt.Fprintf(w, `</tbody> - </table> - <h3>feed urls</h3> - <p>use this box to add/remove URLs that you'd like to follow - <form action="/feeds/validate" method="post"> - <textarea rows="10" cols="72">`) + fmt.Fprintf(w, `<pre>add/remove feed URLs to this box to change your subscriptions</pre> + <form method="POST" action="/feeds/submit"> + <textarea name="submit" rows="10" cols="72">`) for _, feed := range feeds { fmt.Fprintf(w, "%s\n", feed.UpdateURL) } - fmt.Fprintf(w, ` </textarea> + fmt.Fprintf(w, `</textarea> <br> - <input type="submit" value="submit"> + <input type="submit" value="update feeds"> </form>`) } // TODO: textbox with feed.URL // TODO: validate button +} + +func (s *Site) feedsSubmitHandler(w http.ResponseWriter, r *http.Request) { + if !methodAllowed(w, r, "POST") { + return + } + if !s.loggedIn(r) { + http.Error(w, "401 unauthorized", 401) + return + } + inputData := r.FormValue("submit") + if inputData == "" { + http.Error(w, "400 bad request: you must submit data", 400) + return + } + + // TODO: validate user input moar + feeds := strings.Split(inputData, "\r\n") + for _, feed := range feeds { + // TODO: show diff before submission (like tf plan) + // TODO: check if feed exists in db already? + // TODO: validate that title exists + if feed == "" { + continue + } + err := s.reaper.Add(feed) + if err != nil { + fmt.Println(err) + continue + } + s.db.WriteFeed(feed) + s.db.Subscribe(s.username(r), feed) + } + + http.Redirect(w, r, "/feeds", http.StatusSeeOther) } // username fetches a client's username based
M
sqlite/sql.go
→
sqlite/sql.go
@@ -4,7 +4,6 @@ import (
"database/sql" "log" - "github.com/SlyMarbo/rss" _ "github.com/glebarez/go-sqlite" )@@ -113,6 +112,23 @@ panic(err)
} } +func (s *DB) Subscribe(username string, feedURL string) { + uid := s.GetUserID(username) + fid := s.GetFeedID(feedURL) + var id int + err := s.sql.QueryRow("SELECT id FROM subscribe WHERE user_id=? AND feed_id=?", uid, fid).Scan(&id) + if err == sql.ErrNoRows { + _, err := s.sql.Exec("INSERT INTO subscribe (user_id, feed_id) VALUES (?, ?)", uid, fid) + if err != nil { + panic(err) + } + return + } + if err != nil { + panic(err) + } +} + func (s *DB) UserExists(username string) bool { var result string err := s.sql.QueryRow("SELECT username FROM user WHERE username=?", username).Scan(&result)@@ -182,10 +198,20 @@ }
return uid } +func (s *DB) GetFeedID(feedURL string) int { + var fid int + err := s.sql.QueryRow("SELECT id FROM feed WHERE url=?", feedURL).Scan(&fid) + if err != nil { + panic(err) + } + return fid +} + // WriteFeed writes an rss feed to the database for permanent storage -func (s *DB) WriteFeed(f *rss.Feed) { +// if the given feed already exists, WriteFeed does nothing. +func (s *DB) WriteFeed(url string) { _, err := s.sql.Exec(`INSERT INTO feed(url) VALUES(?) - ON CONFLICT(url) DO UPDATE SET url=?`, f.Link, f.Link) + ON CONFLICT(url) DO NOTHING`, url) if err != nil { panic(err) }