package handlers import ( "database/sql" "html/template" "log" "net/http" "strings" "time" "github.com/mmcdole/gofeed" "paterissa.net/mblog/internal/models" ) type written struct { Title string Published string Link string } type video struct { Title string Description string Published string Link string } type rssContext struct { err *log.Logger db *sql.DB Feed models.Feed Written []written Videos []video Rows []models.Feed IsAuth bool } func (ctx *rssContext) new(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { w.WriteHeader(http.StatusMethodNotAllowed) w.Write([]byte("Method Not Allowed")) return } cookie, err := r.Cookie("paterissa_session_token") if err != nil { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Unauthorized")) return } err = r.ParseForm() if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Server Error")) return } name := r.Form.Get("name") url := r.Form.Get("url") category := r.Form.Get("category") stmt, err := ctx.db.Prepare("SELECT * FROM cookies WHERE content = $1;") if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not load cookies from DB: %v\n", err) return } defer stmt.Close() var id uint64 var content string var userId uint64 var expiration time.Time row := stmt.QueryRow(cookie.Value) err = row.Scan(&id, &content, &userId, &expiration) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) return } insertStmt, err := ctx.db.Prepare("INSERT INTO feeds (name, user_id, url, category) VALUES ($1, $2, $3, $4);") if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not prepare insert statement to DB: %v\n", err) return } defer insertStmt.Close() var categoryInt int switch category { case "YouTube": categoryInt = models.YoutubeFeed case "Text": fallthrough default: categoryInt = models.TextFeed } _, err = insertStmt.Exec(name, userId, url, categoryInt) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not execute feed into DB: %v\n", err) return } http.Redirect(w, r, "/feeds", http.StatusFound) return } func (ctx *rssContext) feed(w http.ResponseWriter, r *http.Request) { ctx.Videos = []video{} ctx.Written = []written{} ctx.Feed = models.Feed{} id := r.URL.Query().Get("id") stmt, err := ctx.db.Prepare("SELECT * FROM feeds WHERE id = $1;") if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not load feeds from DB: %v\n", err) return } defer stmt.Close() var f models.Feed row := stmt.QueryRow(id) err = row.Scan(&f.Id, &f.Name, &f.User, &f.Url, &f.Category) ctx.Feed = f parser := gofeed.NewParser() feed, err := parser.ParseURL(f.Url) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not parse RSS feed: %v\n", err) return } files := []string{ "ui/html/base.tmpl.html", "ui/html/music_player.tmpl.html", } switch f.Category { case models.YoutubeFeed: files = append(files, "ui/html/pages/video_feed.tmpl.html") for _, raw := range feed.Items { var v video v.Title = raw.Title v.Description = raw.Extensions["media"]["group"][0].Children["description"][0].Value v.Published = raw.Published v.Link = strings.Replace(raw.Link, "watch?v=", "embed/", 1) ctx.Videos = append(ctx.Videos, v) } case models.TextFeed: fallthrough default: files = append(files, "ui/html/pages/feed.tmpl.html") for _, raw := range feed.Items { var t written t.Title = raw.Title t.Published = raw.Published t.Link = raw.Link ctx.Written = append(ctx.Written, t) } } compiled, err := template.ParseFiles(files...) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not parse template: %v\n", err) return } err = compiled.ExecuteTemplate(w, "base", ctx) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not execute template: %v\n", err) return } return } func (ctx *rssContext) index(w http.ResponseWriter, r *http.Request) { ctx.Rows = []models.Feed{} ctx.IsAuth = false _, err := r.Cookie("paterissa_session_token") if err == nil { ctx.IsAuth = true } rows, err := ctx.db.Query("SELECT f.id, f.name, u.name, f.url FROM feeds f INNER JOIN logins u ON f.user_id = u.id ORDER BY f.name ASC;") if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not load posts from DB: %v\n", err) return } defer rows.Close() for rows.Next() { var f models.Feed if err = rows.Scan(&f.Id, &f.Name, &f.User, &f.Url); err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not load posts from DB: %v\n", err) return } ctx.Rows = append(ctx.Rows, f) } files := []string{ "ui/html/base.tmpl.html", "ui/html/music_player.tmpl.html", "ui/html/pages/feed_index.tmpl.html", } compiled, err := template.ParseFiles(files...) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not parse template: %v\n", err) return } err = compiled.ExecuteTemplate(w, "base", ctx) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("Internal Error")) ctx.err.Printf("Could not execute template: %v\n", err) return } }