add handler, html templates, Makefile and migrations

This commit is contained in:
Philipp 2021-08-29 16:37:20 +02:00
commit a06e8db2ff
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: 276B613AF9DBE9C3
22 changed files with 1001 additions and 0 deletions

69
web/comment_handler.go Normal file
View file

@ -0,0 +1,69 @@
package web
import (
"net/http"
"git.snrd.de/Spaenny/goddit"
"github.com/go-chi/chi"
"github.com/google/uuid"
)
type CommentHandler struct {
store goddit.Store
}
func (h *CommentHandler) Store() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
content := r.FormValue("content")
idStr := chi.URLParam(r, "postID")
id, err := uuid.Parse(idStr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := h.store.CreateComment(&goddit.Comment{
ID: uuid.New(),
PostID: id,
Content: content,
}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, r.Referer(), http.StatusFound)
}
}
func (h *CommentHandler) Vote() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
idStr := chi.URLParam(r, "id")
id, err := uuid.Parse(idStr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
c, err := h.store.Comment(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
dir := r.URL.Query().Get("dir")
if dir == "up" {
c.Votes++
} else if dir == "down" {
c.Votes--
}
if err := h.store.UpdateComment(&c); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, r.Referer(), http.StatusFound)
}
}

63
web/handler.go Normal file
View file

@ -0,0 +1,63 @@
package web
import (
"html/template"
"net/http"
"git.snrd.de/Spaenny/goddit"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
)
func NewHandler(store goddit.Store) *Handler {
h := &Handler{
Mux: chi.NewMux(),
store: store,
}
threads := ThreadHandler{store: store}
posts := PostHandler{store: store}
comments := CommentHandler{store: store}
h.Use(middleware.Logger)
h.Get("/", h.Home())
h.Route("/threads", func(r chi.Router) {
r.Get("/", threads.List())
r.Get("/new", threads.Create())
r.Post("/", threads.Store())
r.Get("/{id}", threads.Show())
r.Post("/{id}/delete", threads.Delete())
r.Get("/{id}/new", posts.Create())
r.Post("/{id}", posts.Store())
r.Get("/{threadID}/{postID}", posts.Show())
r.Get("/{threadID}/{postID}/vote", posts.Vote())
r.Post("/{threadID}/{postID}", comments.Store())
})
h.Get("/comments/{id}/vote", comments.Vote())
return h
}
type Handler struct {
*chi.Mux
store goddit.Store
}
func (h *Handler) Home() http.HandlerFunc {
type data struct {
Posts []goddit.Post
}
tmpl := template.Must(template.ParseFiles("templates/layout.html", "templates/home.html"))
return func(w http.ResponseWriter, r *http.Request) {
pp, err := h.store.Posts()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
tmpl.Execute(w, data{Posts: pp})
}
}

150
web/post_handler.go Normal file
View file

@ -0,0 +1,150 @@
package web
import (
"html/template"
"net/http"
"git.snrd.de/Spaenny/goddit"
"github.com/go-chi/chi"
"github.com/google/uuid"
)
type PostHandler struct {
store goddit.Store
}
func (h *PostHandler) Create() http.HandlerFunc {
type data struct {
Thread goddit.Thread
}
tmpl := template.Must(template.ParseFiles("templates/layout.html", "templates/post_create.html"))
return func(w http.ResponseWriter, r *http.Request) {
idStr := chi.URLParam(r, "id")
id, err := uuid.Parse(idStr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
t, err := h.store.Thread(id)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
tmpl.Execute(w, data{Thread: t})
}
}
func (h *PostHandler) Show() http.HandlerFunc {
type data struct {
Thread goddit.Thread
Post goddit.Post
Comments []goddit.Comment
}
tmpl := template.Must(template.ParseFiles("templates/layout.html", "templates/post.html"))
return func(w http.ResponseWriter, r *http.Request) {
postIDStr := chi.URLParam(r, "postID")
threadIDStr := chi.URLParam(r, "threadID")
postID, err := uuid.Parse(postIDStr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
threadID, err := uuid.Parse(threadIDStr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
p, err := h.store.Post(postID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
cc, err := h.store.CommentsByPost(p.ID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
t, err := h.store.Thread(threadID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
tmpl.Execute(w, data{Thread: t, Post: p, Comments: cc})
}
}
func (h *PostHandler) Store() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
title := r.FormValue("title")
content := r.FormValue("content")
idStr := chi.URLParam(r, "id")
id, err := uuid.Parse(idStr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
t, err := h.store.Thread(id)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
p := &goddit.Post{
ID: uuid.New(),
ThreadID: t.ID,
Title: title,
Content: content,
}
if err := h.store.CreatePost(p); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/threads/"+t.ID.String()+"/"+p.ID.String(), http.StatusFound)
}
}
func (h *PostHandler) Vote() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
idStr := chi.URLParam(r, "postID")
id, err := uuid.Parse(idStr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
p, err := h.store.Post(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
dir := r.URL.Query().Get("dir")
if dir == "up" {
p.Votes++
} else if dir == "down" {
p.Votes--
}
if err := h.store.UpdatePost(&p); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, r.Referer(), http.StatusFound)
}
}

103
web/thread_handler.go Normal file
View file

@ -0,0 +1,103 @@
package web
import (
"html/template"
"net/http"
"git.snrd.de/Spaenny/goddit"
"github.com/go-chi/chi"
"github.com/google/uuid"
)
type ThreadHandler struct {
store goddit.Store
}
func (h *ThreadHandler) List() http.HandlerFunc {
type data struct {
Threads []goddit.Thread
}
tmpl := template.Must(template.ParseFiles("templates/layout.html", "templates/threads.html"))
return func(w http.ResponseWriter, r *http.Request) {
tt, err := h.store.Threads()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
tmpl.Execute(w, data{Threads: tt})
}
}
func (h *ThreadHandler) Create() http.HandlerFunc {
tmpl := template.Must(template.ParseFiles("templates/layout.html", "templates/thread_create.html"))
return func(w http.ResponseWriter, r *http.Request) {
tmpl.Execute(w, nil)
}
}
func (h *ThreadHandler) Show() http.HandlerFunc {
type data struct {
Thread goddit.Thread
Posts []goddit.Post
}
tmpl := template.Must(template.ParseFiles("templates/layout.html", "templates/thread.html"))
return func(w http.ResponseWriter, r *http.Request) {
idStr := chi.URLParam(r, "id")
id, err := uuid.Parse(idStr)
if err != nil {
http.NotFound(w, r)
return
}
t, err := h.store.Thread(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
pp, err := h.store.PostsByThread(t.ID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
tmpl.Execute(w, data{Thread: t, Posts: pp})
}
}
func (h *ThreadHandler) Store() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
title := r.FormValue("title")
description := r.FormValue("description")
if err := h.store.CreateThread(&goddit.Thread{
ID: uuid.New(),
Title: title,
Description: description,
}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/threads", http.StatusFound)
}
}
func (h *ThreadHandler) Delete() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
idStr := chi.URLParam(r, "id")
id, err := uuid.Parse(idStr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := h.store.DeleteThread(id); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/threads", http.StatusFound)
}
}