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.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
}
}