aboutsummaryrefslogtreecommitdiff
path: root/cmd/web/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/web/handlers')
-rw-r--r--cmd/web/handlers/blog.go206
-rw-r--r--cmd/web/handlers/login.go26
-rw-r--r--cmd/web/handlers/routes.go4
3 files changed, 207 insertions, 29 deletions
diff --git a/cmd/web/handlers/blog.go b/cmd/web/handlers/blog.go
index 573e52f..8d9a811 100644
--- a/cmd/web/handlers/blog.go
+++ b/cmd/web/handlers/blog.go
@@ -1,10 +1,16 @@
package handlers
import (
+ "bytes"
"database/sql"
"html/template"
+ "io"
"log"
+ "mime/multipart"
"net/http"
+ "os"
+ "strconv"
+ "time"
"paterissa.net/mblog/internal/models"
)
@@ -13,9 +19,167 @@ type blogContext struct {
err *log.Logger
db *sql.DB
+ Post models.Post
Rows []models.Post
Name string
IsAuth bool
+ Offset int
+}
+
+func (ctx *blogContext) viewPost(w http.ResponseWriter, r *http.Request) {
+ ctx.Rows = []models.Post{}
+ postId := r.URL.Query().Get("id")
+
+ stmt, err := ctx.db.Prepare("SELECT p.id, u.name, p.time, p.brief, p.content FROM posts p INNER JOIN logins u ON p.user_id = u.id WHERE p.id = $1;")
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Could not prepare statement for DB: %v\n", err)
+ return
+ }
+
+ row := stmt.QueryRow(postId)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Could not load post from DB: %v\n", err)
+ return
+ }
+
+ var p models.Post
+ err = row.Scan(&p.Id, &p.Name, &p.Time, &p.Brief, &p.Content)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Could not load post from DB: %v\n", err)
+ return
+ }
+
+ p.FormattedTime = p.Time.Format(time.ANSIC)
+ ctx.Post = p
+
+ files := []string{
+ "ui/html/base.tmpl.html",
+ "ui/html/music_player.tmpl.html",
+ "ui/html/pages/post.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
+ }
+}
+
+func (ctx *blogContext) post(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
+ }
+
+ 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
+ }
+
+ 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;
+ }
+
+ err = r.ParseMultipartForm(4 << 20)
+ if err != nil {
+ w.WriteHeader(http.StatusUnprocessableEntity)
+ w.Write([]byte("Failed to retrieve form data"))
+ ctx.err.Printf("Could not parse request form: %v\n", err)
+ return
+ }
+
+ var buffer bytes.Buffer
+ boundary := "----internal-parser-req"
+ writer := multipart.NewWriter(&buffer)
+ writer.SetBoundary(boundary)
+ writer.WriteField("user_id", strconv.Itoa(int(userId)))
+
+ part, err := writer.CreateFormField("raw")
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Could not create form field: %v\n", err)
+ return
+ }
+
+ _, err = part.Write([]byte(r.Form.Get("raw")))
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Could not create form field: %v\n", err)
+ return
+ }
+
+ writer.Close()
+
+ proxyReq, err := http.NewRequest(r.Method, "http://127.0.0.1:" + os.Getenv("parser_port"), bytes.NewReader(buffer.Bytes()))
+ proxyReq.Header = make(http.Header)
+ for key, val := range r.Header {
+ if key != "Content-Length" {
+ proxyReq.Header[key] = val;
+ }
+ }
+
+ proxyReq.Header.Set("Content-Type", writer.FormDataContentType())
+
+ resp, err := http.DefaultClient.Do(proxyReq)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Fail response from parser: %v\n", err)
+ return
+ }
+ if resp.StatusCode != http.StatusOK {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte("Internal Error"))
+
+ body, err := io.ReadAll(resp.Body)
+ if err == nil {
+ ctx.err.Printf("Fail response from parser: %s\n", body)
+ }
+
+ return
+ }
+
+ defer resp.Body.Close()
+
+ return
}
func (ctx *blogContext) index(w http.ResponseWriter, r *http.Request) {
@@ -32,15 +196,13 @@ func (ctx *blogContext) index(w http.ResponseWriter, r *http.Request) {
ctx.IsAuth = true;
}
- offset := r.URL.Query().Get("offset")
- if offset == "" {
- offset = "20"
- }
+ ctx.Offset, _ = strconv.Atoi(r.URL.Query().Get("offset"))
- rows, err := ctx.db.Query("SELECT p.id, u.name, p.time, p.content FROM posts p INNER JOIN logins u ON p.user_id = u.id WHERE p.id < " + offset + " ORDER BY p.id DESC LIMIT 20;")
+ rows, err := ctx.db.Query("SELECT p.id, u.name, p.time, p.brief FROM posts p INNER JOIN logins u ON p.user_id = u.id WHERE p.id > " + strconv.Itoa(ctx.Offset) + " ORDER BY p.id DESC LIMIT 20;")
if err != nil {
- ctx.err.Print(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ 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()
@@ -48,12 +210,15 @@ func (ctx *blogContext) index(w http.ResponseWriter, r *http.Request) {
for rows.Next() {
var p models.Post
- if err = rows.Scan(&p.Id, &p.Name, &p.Time, &p.Content); err != nil {
- ctx.err.Print(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ if err = rows.Scan(&p.Id, &p.Name, &p.Time, &p.Brief); err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Could not load row: %v\n", err)
return
}
+ p.FormattedTime = p.Time.Format(time.ANSIC)
+
ctx.Rows = append(ctx.Rows, p)
}
@@ -63,17 +228,28 @@ func (ctx *blogContext) index(w http.ResponseWriter, r *http.Request) {
"ui/html/pages/index.tmpl.html",
}
- compiled, err := template.ParseFiles(files...)
+ funcMap := template.FuncMap{
+ "add": func(a int, b int) int {
+ return a + b;
+ },
+ "sub": func(a int, b int) int {
+ return a - b;
+ },
+ }
+
+ compiled, err := template.New("blog").Funcs(funcMap).ParseFiles(files...)
if err != nil {
- ctx.err.Print(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ 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 {
- ctx.err.Print(err.Error())
- http.Error(w, "Internal Server Error", 500)
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Could not execute template: %v\n", err)
return
}
}
diff --git a/cmd/web/handlers/login.go b/cmd/web/handlers/login.go
index e867e07..87684ba 100644
--- a/cmd/web/handlers/login.go
+++ b/cmd/web/handlers/login.go
@@ -21,13 +21,13 @@ type loginContext struct {
func (ctx *loginContext) index(w http.ResponseWriter, r *http.Request) {
files := []string{
"ui/html/base.tmpl.html",
- "ui/html/login.tmpl.html",
"ui/html/music_player.tmpl.html",
+ "ui/html/pages/login.tmpl.html",
}
compiled, err := template.ParseFiles(files...)
if err != nil {
- w.WriteHeader(500)
+ w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal Server Error"))
ctx.err.Printf("Failed to parse templates: %v\n", err)
return
@@ -35,7 +35,7 @@ func (ctx *loginContext) index(w http.ResponseWriter, r *http.Request) {
err = compiled.ExecuteTemplate(w, "base", ctx)
if err != nil {
- w.WriteHeader(500)
+ w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal Server Error"))
ctx.err.Printf("Failed to parse templates: %v\n", err)
return
@@ -46,14 +46,14 @@ func (ctx *loginContext) index(w http.ResponseWriter, r *http.Request) {
func (ctx *loginContext) login(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
- w.WriteHeader(405)
+ w.WriteHeader(http.StatusMethodNotAllowed)
w.Write([]byte("Method Not Allowed"))
return
}
err := r.ParseForm()
if err != nil {
- w.WriteHeader(500)
+ w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal Error"))
ctx.err.Printf("Failed to retrieve form data: %v\n", err)
return
@@ -65,7 +65,7 @@ func (ctx *loginContext) login(w http.ResponseWriter, r *http.Request) {
stmt, err := ctx.db.Prepare("SELECT * FROM logins WHERE name = $1;")
if err != nil {
- w.WriteHeader(500)
+ w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal Error"))
ctx.err.Printf("Failed to retrieve form data: %v\n", err)
return
@@ -77,7 +77,7 @@ func (ctx *loginContext) login(w http.ResponseWriter, r *http.Request) {
row := stmt.QueryRow(user)
err = row.Scan(&u.Id, &u.Name, &u.Time, &u.PassOne, &u.PassTwo)
if err != nil {
- w.WriteHeader(401)
+ w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Unauthorized"))
ctx.err.Printf("Failed to retrieve user info from DB: %v\n", err)
return
@@ -86,7 +86,7 @@ func (ctx *loginContext) login(w http.ResponseWriter, r *http.Request) {
passOneErr := bcrypt.CompareHashAndPassword([]byte(u.PassOne), []byte(passOne))
passTwoErr := bcrypt.CompareHashAndPassword([]byte(u.PassTwo), []byte(passTwo))
if passOneErr != nil || passTwoErr != nil {
- w.WriteHeader(401)
+ w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Failed to login - not authorized"))
return
}
@@ -103,7 +103,7 @@ func (ctx *loginContext) login(w http.ResponseWriter, r *http.Request) {
commit, err := ctx.db.Prepare("INSERT INTO cookies (content, user_id, expiration) VALUES ($1, $2, $3);")
if err != nil {
- w.WriteHeader(500)
+ w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal Error"))
ctx.err.Printf("Failed to prepare DB statement: %v\n", err)
return
@@ -111,7 +111,7 @@ func (ctx *loginContext) login(w http.ResponseWriter, r *http.Request) {
_, err = commit.Exec(cookie.Value, u.Id, cookie.Expires)
if err != nil {
- w.WriteHeader(500)
+ w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal Error"))
ctx.err.Printf("Failed to prepare DB statement: %v\n", err)
}
@@ -124,14 +124,14 @@ func (ctx *loginContext) login(w http.ResponseWriter, r *http.Request) {
func (ctx *loginContext) logout(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("paterissa_session_token")
if err != nil {
- w.WriteHeader(405)
+ w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Unauthorized"))
return
}
stmt, err := ctx.db.Prepare("UPDATE cookies SET expiration = $1 WHERE content = $2;")
if err != nil {
- w.WriteHeader(500)
+ w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal Error"))
ctx.err.Printf("Could not prepare DB statement: %v\n", err)
return
@@ -140,7 +140,7 @@ func (ctx *loginContext) logout(w http.ResponseWriter, r *http.Request) {
_, err = stmt.Exec(time.Now(), cookie.Value)
if err != nil {
- w.WriteHeader(500)
+ w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal Error"))
ctx.err.Printf("Could not execute DB statement: %v\n", err)
return
diff --git a/cmd/web/handlers/routes.go b/cmd/web/handlers/routes.go
index 0196331..a4c9c09 100644
--- a/cmd/web/handlers/routes.go
+++ b/cmd/web/handlers/routes.go
@@ -34,7 +34,9 @@ func RegisterEndpoints(app types.Application, db *sql.DB) *http.ServeMux {
}
blogRouter := http.NewServeMux()
- blogRouter.HandleFunc("/", blog.index)
+ blogRouter.HandleFunc("/", auth.CheckAndInvalidate(blog.index))
+ blogRouter.HandleFunc("/post/new", auth.Resolve(blog.post))
+ blogRouter.HandleFunc("/post", blog.viewPost)
blogRouter.HandleFunc("/login", login.handle)
blogRouter.HandleFunc("/logout", auth.Resolve(login.logout))