feat: use rsvp module #6
|
|
@ -3,3 +3,4 @@ gin-bin
|
||||||
lishwist.db
|
lishwist.db
|
||||||
.env*.local
|
.env*.local
|
||||||
server/db/init_sql.go
|
server/db/init_sql.go
|
||||||
|
.ignored/
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginProps struct {
|
type LoginProps struct {
|
||||||
GeneralError string
|
GeneralError string `json:",omitempty"`
|
||||||
SuccessfulRegistration bool
|
SuccessfulRegistration bool `json:",omitempty"`
|
||||||
Username templates.InputProps
|
Username templates.InputProps
|
||||||
Password templates.InputProps
|
Password templates.InputProps
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,27 +40,27 @@ func queryForGroup(query string, args ...any) (*Group, error) {
|
||||||
|
|
||||||
func queryForGroups(query string, args ...any) ([]Group, error) {
|
func queryForGroups(query string, args ...any) ([]Group, error) {
|
||||||
groups := []Group{}
|
groups := []Group{}
|
||||||
rows, err := database.Query(query)
|
rows, err := database.Query(query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return groups, err
|
return groups, fmt.Errorf("Query failed: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var group Group
|
var group Group
|
||||||
err := rows.Scan(&group.Id, &group.Name, &group.Reference)
|
err := rows.Scan(&group.Id, &group.Name, &group.Reference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return groups, err
|
return groups, fmt.Errorf("Failed to scan row: %w", err)
|
||||||
}
|
}
|
||||||
members, err := queryForGroupMembers(group.Id)
|
members, err := queryForGroupMembers(group.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return groups, err
|
return groups, fmt.Errorf("Failed to query for group members: %w", err)
|
||||||
}
|
}
|
||||||
group.Members = members
|
group.Members = members
|
||||||
groups = append(groups, group)
|
groups = append(groups, group)
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
err = rows.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return groups, err
|
return groups, fmt.Errorf("Rows error: %w", err)
|
||||||
}
|
}
|
||||||
return groups, nil
|
return groups, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,14 @@ type User struct {
|
||||||
type Gift struct {
|
type Gift struct {
|
||||||
Id string
|
Id string
|
||||||
Name string
|
Name string
|
||||||
ClaimantId string
|
ClaimantId string `json:",omitempty"`
|
||||||
ClaimantName string
|
ClaimantName string `json:",omitempty"`
|
||||||
Sent bool
|
Sent bool
|
||||||
RecipientId string
|
RecipientId string `json:",omitempty"`
|
||||||
RecipientName string
|
RecipientName string `json:",omitempty"`
|
||||||
RecipientRef string
|
RecipientRef string `json:",omitempty"`
|
||||||
CreatorId string
|
CreatorId string `json:",omitempty"`
|
||||||
CreatorName string
|
CreatorName string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryForUser(query string, args ...any) (*User, error) {
|
func queryForUser(query string, args ...any) (*User, error) {
|
||||||
|
|
@ -406,31 +406,7 @@ func (u *User) AddGiftToUser(otherUserReference string, giftName string) error {
|
||||||
|
|
||||||
func (u *User) GetGroups() ([]Group, error) {
|
func (u *User) GetGroups() ([]Group, error) {
|
||||||
stmt := "SELECT [group].id, [group].name, [group].reference FROM [group] JOIN group_member ON group_member.group_id = [group].id JOIN v_user AS user ON user.id = group_member.user_id WHERE user.id = ?"
|
stmt := "SELECT [group].id, [group].name, [group].reference FROM [group] JOIN group_member ON group_member.group_id = [group].id JOIN v_user AS user ON user.id = group_member.user_id WHERE user.id = ?"
|
||||||
rows, err := database.Query(stmt, u.Id)
|
return queryForGroups(stmt, u.Id)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
groups := []Group{}
|
|
||||||
for rows.Next() {
|
|
||||||
var id string
|
|
||||||
var name string
|
|
||||||
var reference string
|
|
||||||
err := rows.Scan(&id, &name, &reference)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
groups = append(groups, Group{
|
|
||||||
Id: id,
|
|
||||||
Name: name,
|
|
||||||
Reference: reference,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
err = rows.Err()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return groups, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) GetGroupByReference(reference string) (*Group, error) {
|
func (u *User) GetGroupByReference(reference string) (*Group, error) {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package error
|
|
||||||
|
|
||||||
import (
|
|
||||||
"lishwist/templates"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type pageProps struct {
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
func Page(w http.ResponseWriter, publicMessage string, status int, err error) {
|
|
||||||
w.WriteHeader(status)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("%s --- %s\n", publicMessage, err)
|
|
||||||
}
|
|
||||||
templates.Execute(w, "error_page.gotmpl", pageProps{publicMessage})
|
|
||||||
}
|
|
||||||
|
|
@ -35,32 +35,26 @@ func main() {
|
||||||
|
|
||||||
r := router.New(store)
|
r := router.New(store)
|
||||||
|
|
||||||
route := routing.NewContext(store)
|
r.Public.HandleFunc("GET /", routing.Login)
|
||||||
|
r.Public.HandleFunc("GET /group/{groupReference}", routing.PublicGroupPage)
|
||||||
|
r.Public.HandleFunc("GET /list/{userReference}", routing.PublicWishlist)
|
||||||
|
r.Public.HandleFunc("GET /register", routing.Register)
|
||||||
|
r.Public.HandleFunc("POST /", routing.LoginPost)
|
||||||
|
r.Public.HandleFunc("POST /register", routing.RegisterPost)
|
||||||
|
|
||||||
r.Html.Public.HandleFunc("GET /register", route.Register)
|
r.Private.HandleFunc("GET /", routing.NotFound)
|
||||||
r.Html.Public.HandleFunc("POST /register", route.RegisterPost)
|
r.Private.HandleFunc("GET /group/{groupReference}", routing.ExpectUser(routing.GroupPage))
|
||||||
r.Html.Public.HandleFunc("GET /", route.Login)
|
r.Private.HandleFunc("GET /groups", routing.ExpectUser(routing.GroupsJson))
|
||||||
r.Html.Public.HandleFunc("POST /", route.LoginPost)
|
r.Private.HandleFunc("GET /groups/{groupReference}", routing.ExpectUser(routing.Group))
|
||||||
r.Html.Public.HandleFunc("GET /list/{userReference}", route.PublicWishlist)
|
r.Private.HandleFunc("GET /list/{userReference}", routing.ExpectUser(routing.ForeignWishlist))
|
||||||
r.Html.Public.HandleFunc("GET /group/{groupReference}", route.PublicGroupPage)
|
r.Private.HandleFunc("GET /users", routing.ExpectUser(routing.Users))
|
||||||
|
r.Private.HandleFunc("GET /users/{userReference}", routing.ExpectUser(routing.User))
|
||||||
r.Html.Private.Handle("GET /{$}", route.ExpectUser(route.Home))
|
r.Private.HandleFunc("GET /{$}", routing.ExpectUser(routing.Home))
|
||||||
r.Html.Private.Handle("POST /{$}", route.ExpectUser(route.HomePost))
|
r.Private.HandleFunc("POST /groups/{groupReference}", routing.ExpectUser(routing.GroupPost))
|
||||||
r.Html.Private.Handle("GET /list/{userReference}", route.ExpectUser(route.ForeignWishlist))
|
r.Private.HandleFunc("POST /list/{userReference}", routing.ExpectUser(routing.ForeignWishlistPost))
|
||||||
r.Html.Private.Handle("POST /list/{userReference}", route.ExpectUser(route.ForeignWishlistPost))
|
r.Private.HandleFunc("POST /logout", routing.LogoutPost)
|
||||||
r.Html.Private.Handle("GET /group/{groupReference}", route.ExpectUser(route.GroupPage))
|
r.Private.HandleFunc("POST /users/{userReference}", routing.ExpectUser(routing.UserPost))
|
||||||
r.Html.Private.HandleFunc("POST /logout", route.LogoutPost)
|
r.Private.HandleFunc("POST /{$}", routing.ExpectUser(routing.HomePost))
|
||||||
r.Html.Private.HandleFunc("GET /", routing.NotFound)
|
|
||||||
|
|
||||||
r.Json.Public.HandleFunc("GET /", routing.NotFoundJson)
|
|
||||||
|
|
||||||
r.Json.Private.Handle("GET /users", route.ExpectUser(route.UsersJson))
|
|
||||||
r.Json.Private.Handle("GET /users/{userReference}", route.ExpectUser(route.User))
|
|
||||||
r.Json.Private.Handle("POST /users/{userReference}", route.ExpectUser(route.UserPost))
|
|
||||||
r.Json.Private.Handle("GET /groups", route.ExpectUser(route.GroupsJson))
|
|
||||||
r.Json.Private.Handle("POST /groups/{groupReference}", route.ExpectUser(route.GroupPost))
|
|
||||||
r.Json.Private.Handle("GET /groups/{groupReference}", route.ExpectUser(route.Group))
|
|
||||||
r.Json.Private.HandleFunc("GET /", routing.NotFoundJson)
|
|
||||||
|
|
||||||
http.Handle("/", r)
|
http.Handle("/", r)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"lishwist/rsvp"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/Teajey/sqlstore"
|
"github.com/Teajey/sqlstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VisibilityRouter struct {
|
type VisibilityRouter struct {
|
||||||
Store *sqlstore.Store
|
Store *sqlstore.Store
|
||||||
Public *http.ServeMux
|
Public *rsvp.ServeMux
|
||||||
Private *http.ServeMux
|
Private *rsvp.ServeMux
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *VisibilityRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (s *VisibilityRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
@ -24,33 +24,10 @@ func (s *VisibilityRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Router struct {
|
func New(store *sqlstore.Store) *VisibilityRouter {
|
||||||
Json VisibilityRouter
|
return &VisibilityRouter{
|
||||||
Html VisibilityRouter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
accept := r.Header.Get("Accept")
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(accept, "application/json"):
|
|
||||||
s.Json.ServeHTTP(w, r)
|
|
||||||
default:
|
|
||||||
s.Html.ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(store *sqlstore.Store) *Router {
|
|
||||||
return &Router{
|
|
||||||
Json: VisibilityRouter{
|
|
||||||
Store: store,
|
Store: store,
|
||||||
Public: http.NewServeMux(),
|
Public: rsvp.NewServeMux(store),
|
||||||
Private: http.NewServeMux(),
|
Private: rsvp.NewServeMux(store),
|
||||||
},
|
|
||||||
Html: VisibilityRouter{
|
|
||||||
Store: store,
|
|
||||||
Public: http.NewServeMux(),
|
|
||||||
Private: http.NewServeMux(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,39 +2,23 @@ package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"lishwist/db"
|
"lishwist/db"
|
||||||
"log"
|
"lishwist/rsvp"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Teajey/sqlstore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Context struct {
|
func ExpectUser(next func(*db.User, http.Header, *rsvp.Request) rsvp.Response) rsvp.HandlerFunc {
|
||||||
store *sqlstore.Store
|
return func(w http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
}
|
session := r.GetSession()
|
||||||
|
username, ok := session.GetValue("username").(string)
|
||||||
func NewContext(store *sqlstore.Store) *Context {
|
|
||||||
return &Context{
|
|
||||||
store,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *Context) ExpectUser(next func(*db.User, http.ResponseWriter, *http.Request)) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
session, _ := ctx.store.Get(r, "lishwist_user")
|
|
||||||
username, ok := session.Values["username"].(string)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Println("Failed to get username")
|
return rsvp.Error(http.StatusInternalServerError, "Something went wrong.").Log("Failed to get username from session")
|
||||||
http.Error(w, "", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.GetUserByName(username)
|
user, err := db.GetUserByName(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to get user: %s\n", err)
|
return rsvp.Error(http.StatusInternalServerError, "Something went wrong.").Log("Failed to get user %q: %s", username, err)
|
||||||
http.Error(w, "", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
next(user, w, r)
|
return next(user, w, r)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@ package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"lishwist/db"
|
"lishwist/db"
|
||||||
"lishwist/error"
|
"lishwist/rsvp"
|
||||||
"lishwist/templates"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -14,28 +13,24 @@ type foreignWishlistProps struct {
|
||||||
Gifts []db.Gift
|
Gifts []db.Gift
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) ForeignWishlist(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func ForeignWishlist(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
userReference := r.PathValue("userReference")
|
userReference := r.PathValue("userReference")
|
||||||
if currentUser.Reference == userReference {
|
if currentUser.Reference == userReference {
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
return rsvp.SeeOther("/")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
otherUser, err := db.GetUserByReference(userReference)
|
otherUser, err := db.GetUserByReference(userReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching this user :(", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "An error occurred while fetching this user :(").Log("Couldn't get user by reference %q: %s", userReference, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if otherUser == nil {
|
if otherUser == nil {
|
||||||
error.Page(w, "User not found", http.StatusNotFound, err)
|
return rsvp.Error(http.StatusInternalServerError, "User not found")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
gifts, err := currentUser.GetOtherUserGifts(userReference)
|
gifts, err := currentUser.GetOtherUserGifts(userReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching this user's wishlist :(", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "An error occurred while fetching this user :(").Log("%q couldn't get wishes of other user %q: %s", currentUser.Name, otherUser.Name, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
p := foreignWishlistProps{CurrentUserId: currentUser.Id, CurrentUserName: currentUser.Name, Username: otherUser.Name, Gifts: gifts}
|
p := foreignWishlistProps{CurrentUserId: currentUser.Id, CurrentUserName: currentUser.Name, Username: otherUser.Name, Gifts: gifts}
|
||||||
templates.Execute(w, "foreign_wishlist.gotmpl", p)
|
return rsvp.Data("foreign_wishlist.gotmpl", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
type publicWishlistProps struct {
|
type publicWishlistProps struct {
|
||||||
|
|
@ -43,22 +38,19 @@ type publicWishlistProps struct {
|
||||||
GiftCount int
|
GiftCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) PublicWishlist(w http.ResponseWriter, r *http.Request) {
|
func PublicWishlist(h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
userReference := r.PathValue("userReference")
|
userReference := r.PathValue("userReference")
|
||||||
otherUser, err := db.GetUserByReference(userReference)
|
otherUser, err := db.GetUserByReference(userReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching this user :(", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "An error occurred while fetching this user :(").Log("Couldn't get user by reference %q on public wishlist: %s", userReference, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if otherUser == nil {
|
if otherUser == nil {
|
||||||
error.Page(w, "User not found", http.StatusNotFound, err)
|
return rsvp.Error(http.StatusInternalServerError, "User not found")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
giftCount, err := otherUser.CountGifts()
|
giftCount, err := otherUser.CountGifts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching data about this user :(", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "An error occurred while fetching this user :(").Log("Couldn't get wishes of user %q on public wishlist: %s", otherUser.Name, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
p := publicWishlistProps{Username: otherUser.Name, GiftCount: giftCount}
|
p := publicWishlistProps{Username: otherUser.Name, GiftCount: giftCount}
|
||||||
templates.Execute(w, "public_foreign_wishlist.gotmpl", p)
|
return rsvp.Data("public_foreign_wishlist.gotmpl", p)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"lishwist/db"
|
"lishwist/db"
|
||||||
"lishwist/error"
|
"lishwist/rsvp"
|
||||||
"lishwist/templates"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupProps struct {
|
type GroupProps struct {
|
||||||
|
|
@ -15,16 +13,14 @@ type GroupProps struct {
|
||||||
CurrentUsername string
|
CurrentUsername string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) GroupPage(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func GroupPage(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
groupReference := r.PathValue("groupReference")
|
groupReference := r.PathValue("groupReference")
|
||||||
group, err := currentUser.GetGroupByReference(groupReference)
|
group, err := currentUser.GetGroupByReference(groupReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "An error occurred while fetching this group :(").Log("Couldn't get group: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if group == nil {
|
if group == nil {
|
||||||
error.Page(w, "Group not found. (It might be because you're not a member)", http.StatusNotFound, nil)
|
return rsvp.Error(http.StatusNotFound, "Group not found. (It might be because you're not a member)").Log("Couldn't get group: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
index := group.MemberIndex(currentUser.Id)
|
index := group.MemberIndex(currentUser.Id)
|
||||||
group.Members = slices.Delete(group.Members, index, index+1)
|
group.Members = slices.Delete(group.Members, index, index+1)
|
||||||
|
|
@ -32,68 +28,58 @@ func (ctx *Context) GroupPage(currentUser *db.User, w http.ResponseWriter, r *ht
|
||||||
Group: group,
|
Group: group,
|
||||||
CurrentUsername: currentUser.Name,
|
CurrentUsername: currentUser.Name,
|
||||||
}
|
}
|
||||||
templates.Execute(w, "group_page.gotmpl", p)
|
return rsvp.Data("group_page.gotmpl", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) PublicGroupPage(w http.ResponseWriter, r *http.Request) {
|
func PublicGroupPage(h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
groupReference := r.PathValue("groupReference")
|
groupReference := r.PathValue("groupReference")
|
||||||
group, err := db.GetGroupByReference(groupReference)
|
group, err := db.GetGroupByReference(groupReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "An error occurred while fetching this group :(").Log("Couldn't get group: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
p := GroupProps{
|
p := GroupProps{
|
||||||
Group: group,
|
Group: group,
|
||||||
}
|
}
|
||||||
templates.Execute(w, "public_group_page.gotmpl", p)
|
return rsvp.Data("public_group_page.gotmpl", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) GroupPost(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func GroupPost(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if !currentUser.IsAdmin {
|
if !currentUser.IsAdmin {
|
||||||
NotFoundJson(w, r)
|
return NotFound(h, r)
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := r.ParseForm(); err != nil {
|
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "Failed to parse form: "+err.Error())
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
form := r.ParseForm()
|
||||||
|
|
||||||
var group *db.Group
|
var group *db.Group
|
||||||
|
|
||||||
reference := r.PathValue("groupReference")
|
reference := r.PathValue("groupReference")
|
||||||
name := r.Form.Get("name")
|
name := form.Get("name")
|
||||||
addUsers := r.Form["addUser"]
|
addUsers := form["addUser"]
|
||||||
removeUsers := r.Form["removeUser"]
|
removeUsers := form["removeUser"]
|
||||||
|
|
||||||
if name != "" {
|
if name != "" {
|
||||||
createdGroup, err := db.CreateGroup(name, reference)
|
createdGroup, err := db.CreateGroup(name, reference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "Failed to create group: "+err.Error())
|
return rsvp.Error(http.StatusInternalServerError, "Failed to create group: %w", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
group = createdGroup
|
group = createdGroup
|
||||||
} else {
|
} else {
|
||||||
existingGroup, err := db.GetGroupByReference(reference)
|
existingGroup, err := db.GetGroupByReference(reference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "Failed to get group: "+err.Error())
|
return rsvp.Error(http.StatusInternalServerError, "Failed to get group: %w", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if existingGroup == nil {
|
if existingGroup == nil {
|
||||||
writeGeneralErrorJson(w, http.StatusNotFound, "Group not found")
|
return rsvp.Error(http.StatusNotFound, "Group not found", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
group = existingGroup
|
group = existingGroup
|
||||||
|
|
||||||
for _, userId := range removeUsers {
|
for _, userId := range removeUsers {
|
||||||
index := group.MemberIndex(userId)
|
index := group.MemberIndex(userId)
|
||||||
if index == -1 {
|
if index == -1 {
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "Group %q does not contain a user with id %s", reference, userId)
|
return rsvp.Error(http.StatusBadRequest, "Group %q does not contain a user with id %s", reference, userId)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
err = group.RemoveUser(userId)
|
err = group.RemoveUser(userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "On group %q failed to remove user with id %s: %s", reference, userId, err)
|
return rsvp.Error(http.StatusInternalServerError, "On group %q failed to remove user with id %s: %s", reference, userId, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
group.Members = slices.Delete(group.Members, index, index+1)
|
group.Members = slices.Delete(group.Members, index, index+1)
|
||||||
}
|
}
|
||||||
|
|
@ -102,54 +88,47 @@ func (ctx *Context) GroupPost(currentUser *db.User, w http.ResponseWriter, r *ht
|
||||||
for _, userId := range addUsers {
|
for _, userId := range addUsers {
|
||||||
user, err := db.GetUser(userId)
|
user, err := db.GetUser(userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "Groups exists, but a user with id %s could not be fetched: %s", userId, err)
|
return rsvp.Error(http.StatusInternalServerError, "Groups exists, but a user with id %s could not be fetched: %s", userId, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if user == nil {
|
if user == nil {
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "Groups exists, but a user with id %s does not exist", userId)
|
return rsvp.Error(http.StatusInternalServerError, "Groups exists, but a user with id %s does not exist", userId)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
err = group.AddUser(user.Id)
|
err = group.AddUser(user.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "Groups exists, but failed to add user with id %s: %s", userId, err)
|
return rsvp.Error(http.StatusInternalServerError, "Groups exists, but failed to add user with id %s: %s", userId, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
group.Members = append(group.Members, *user)
|
group.Members = append(group.Members, *user)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(group)
|
return rsvp.Data("", group)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) GroupsJson(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func GroupsJson(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if !currentUser.IsAdmin {
|
if !currentUser.IsAdmin {
|
||||||
NotFoundJson(w, r)
|
return NotFound(h, r)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
groups, err := db.GetAllGroups()
|
groups, err := db.GetAllGroups()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "Failed to get groups: "+err.Error())
|
return rsvp.Error(http.StatusInternalServerError, "Failed to get groups: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(groups)
|
return rsvp.Data("", groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) Group(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func Group(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if !currentUser.IsAdmin {
|
if !currentUser.IsAdmin {
|
||||||
NotFoundJson(w, r)
|
return NotFound(h, r)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
groupReference := r.PathValue("groupReference")
|
groupReference := r.PathValue("groupReference")
|
||||||
group, err := db.GetGroupByReference(groupReference)
|
group, err := db.GetGroupByReference(groupReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusBadRequest, "Couldn't get group: %s", err)
|
return rsvp.Error(http.StatusInternalServerError, "Couldn't get group: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if group == nil {
|
if group == nil {
|
||||||
writeGeneralErrorJson(w, http.StatusNotFound, "Group not found.")
|
return rsvp.Error(http.StatusNotFound, "Group not found.")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(group)
|
return rsvp.Data("", group)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ import (
|
||||||
|
|
||||||
"lishwist/db"
|
"lishwist/db"
|
||||||
"lishwist/env"
|
"lishwist/env"
|
||||||
"lishwist/error"
|
"lishwist/rsvp"
|
||||||
"lishwist/templates"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type HomeProps struct {
|
type HomeProps struct {
|
||||||
|
|
@ -18,40 +17,31 @@ type HomeProps struct {
|
||||||
Groups []db.Group
|
Groups []db.Group
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) Home(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func Home(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
gifts, err := currentUser.GetGifts()
|
gifts, err := currentUser.GetGifts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "An error occurred while fetching your wishlist :(").Log("Failed to get gifts: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
todo, err := currentUser.GetTodo()
|
todo, err := currentUser.GetTodo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "An error occurred while fetching your wishlist :(").Log("Failed to get todo: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
groups, err := currentUser.GetGroups()
|
groups, err := currentUser.GetGroups()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "An error occurred while fetching your wishlist :(").Log("Failed to get groups: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
p := HomeProps{Username: currentUser.Name, Gifts: gifts, Todo: todo, Reference: currentUser.Reference, HostUrl: env.HostUrl.String(), Groups: groups}
|
p := HomeProps{Username: currentUser.Name, Gifts: gifts, Todo: todo, Reference: currentUser.Reference, HostUrl: env.HostUrl.String(), Groups: groups}
|
||||||
templates.Execute(w, "home.gotmpl", p)
|
return rsvp.Data("home.gotmpl", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) HomePost(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func HomePost(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if err := r.ParseForm(); err != nil {
|
form := r.ParseForm()
|
||||||
http.Error(w, "Couldn't parse form", http.StatusBadRequest)
|
switch form.Get("intent") {
|
||||||
return
|
|
||||||
}
|
|
||||||
switch r.Form.Get("intent") {
|
|
||||||
case "add_idea":
|
case "add_idea":
|
||||||
ctx.WishlistAdd(currentUser, w, r)
|
return WishlistAdd(currentUser, h, r)
|
||||||
return
|
|
||||||
case "delete_idea":
|
case "delete_idea":
|
||||||
ctx.WishlistDelete(currentUser, w, r)
|
return WishlistDelete(currentUser, h, r)
|
||||||
return
|
|
||||||
default:
|
default:
|
||||||
ctx.TodoUpdate(currentUser, w, r)
|
return TodoUpdate(currentUser, h, r)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,17 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"lishwist/api"
|
"lishwist/api"
|
||||||
sesh "lishwist/session"
|
"lishwist/rsvp"
|
||||||
"lishwist/templates"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ctx *Context) Login(w http.ResponseWriter, r *http.Request) {
|
func Login(h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
session, _ := ctx.store.Get(r, "lishwist_user")
|
session := r.GetSession()
|
||||||
|
|
||||||
props := api.NewLoginProps("", "")
|
props := api.NewLoginProps("", "")
|
||||||
|
|
||||||
flash, err := sesh.GetFirstFlash(w, r, session, "login_props")
|
flash := session.FlashGet("login_props")
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "Something went wrong. Error code: Zuko", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
flashProps, ok := flash.(*api.LoginProps)
|
flashProps, ok := flash.(*api.LoginProps)
|
||||||
if ok {
|
if ok {
|
||||||
props.Username.Value = flashProps.Username.Value
|
props.Username.Value = flashProps.Username.Value
|
||||||
|
|
@ -29,46 +21,30 @@ func (ctx *Context) Login(w http.ResponseWriter, r *http.Request) {
|
||||||
props.Password.Error = flashProps.Password.Error
|
props.Password.Error = flashProps.Password.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
flash, err = sesh.GetFirstFlash(w, r, session, "successful_registration")
|
flash = session.FlashGet("successful_registration")
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "Something went wrong. Error code: Zuko", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
successfulReg, _ := flash.(bool)
|
successfulReg, _ := flash.(bool)
|
||||||
if successfulReg {
|
if successfulReg {
|
||||||
props.SuccessfulRegistration = true
|
props.SuccessfulRegistration = true
|
||||||
}
|
}
|
||||||
|
|
||||||
templates.Execute(w, "login.gotmpl", props)
|
return rsvp.Data("login.gotmpl", props).SaveSession(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) LoginPost(w http.ResponseWriter, r *http.Request) {
|
func LoginPost(h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if err := r.ParseForm(); err != nil {
|
form := r.ParseForm()
|
||||||
http.Error(w, "Couldn't parse form", http.StatusBadRequest)
|
session := r.GetSession()
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
username := r.Form.Get("username")
|
username := form.Get("username")
|
||||||
password := r.Form.Get("password")
|
password := form.Get("password")
|
||||||
|
|
||||||
props := api.Login(username, password)
|
props := api.Login(username, password)
|
||||||
if props != nil {
|
if props != nil {
|
||||||
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
|
return rsvp.SeeOther("/").SaveSession(session)
|
||||||
_ = json.NewEncoder(w).Encode(props)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Overwriting any existing cookie or session here. So we don't care if there's an error
|
session.SetID("")
|
||||||
session, _ := ctx.store.Get(r, "lishwist_user")
|
session.SetValue("authorized", true)
|
||||||
session.ID = ""
|
session.SetValue("username", username)
|
||||||
session.Values["authorized"] = true
|
|
||||||
session.Values["username"] = username
|
|
||||||
if err := session.Save(r, w); err != nil {
|
|
||||||
log.Println("Couldn't save session:", err)
|
|
||||||
http.Error(w, "Something went wrong. Error code: Zuko", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
http.Redirect(w, r, r.URL.Path, http.StatusSeeOther)
|
return rsvp.SeeOther(r.URL().Path).SaveSession(session)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,15 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"lishwist/rsvp"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ctx *Context) LogoutPost(w http.ResponseWriter, r *http.Request) {
|
func LogoutPost(h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
session, err := ctx.store.Get(r, "lishwist_user")
|
session := r.GetSession()
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "Something went wrong. Error code: Iroh", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
session.Options.MaxAge = 0
|
session.Options().MaxAge = 0
|
||||||
session.Values = nil
|
session.ClearValues()
|
||||||
if err := session.Save(r, w); err != nil {
|
|
||||||
http.Error(w, "Something went wrong. Error code: Azula", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
return rsvp.SeeOther("/").SaveSession(session)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,9 @@ package routing
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"lishwist/error"
|
"lishwist/rsvp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NotFoundJson(w http.ResponseWriter, r *http.Request) {
|
func NotFound(h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
w.Header().Add("Content-Type", "application/json; charset=utf-8")
|
return rsvp.Error(http.StatusNotFound, "Page not found")
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
_, _ = w.Write([]byte(`{"GeneralError":"Not Found"}`))
|
|
||||||
}
|
|
||||||
|
|
||||||
func NotFound(w http.ResponseWriter, r *http.Request) {
|
|
||||||
error.Page(w, "404 -- Page not found", http.StatusNotFound, nil)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package routing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (ctx *Context) RedirectWithFlash(w http.ResponseWriter, r *http.Request, url string, key string, flash any) {
|
|
||||||
session, _ := ctx.store.Get(r, "lishwist_user")
|
|
||||||
session.AddFlash(flash, key)
|
|
||||||
if err := session.Save(r, w); err != nil {
|
|
||||||
log.Println("Couldn't save session:", err)
|
|
||||||
http.Error(w, "Something went wrong. Error code: Zuko", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
http.Redirect(w, r, url, http.StatusSeeOther)
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +1,19 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"lishwist/api"
|
"lishwist/api"
|
||||||
"lishwist/templates"
|
"lishwist/rsvp"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ctx *Context) Register(w http.ResponseWriter, r *http.Request) {
|
func Register(h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
props := api.NewRegisterProps("", "", "")
|
props := api.NewRegisterProps("", "", "")
|
||||||
|
|
||||||
session, _ := ctx.store.Get(r, "lishwist_user")
|
session := r.GetSession()
|
||||||
if flashes := session.Flashes("register_props"); len(flashes) > 0 {
|
flash := session.FlashGet("register_props")
|
||||||
log.Printf("Register found flashes: %#v\n", flashes)
|
|
||||||
flashProps, _ := flashes[0].(*api.RegisterProps)
|
flashProps, _ := flash.(*api.RegisterProps)
|
||||||
|
if flashProps != nil {
|
||||||
props.Username.Value = flashProps.Username.Value
|
props.Username.Value = flashProps.Username.Value
|
||||||
|
|
||||||
props.GeneralError = flashProps.GeneralError
|
props.GeneralError = flashProps.GeneralError
|
||||||
|
|
@ -22,32 +21,25 @@ func (ctx *Context) Register(w http.ResponseWriter, r *http.Request) {
|
||||||
props.ConfirmPassword.Error = flashProps.ConfirmPassword.Error
|
props.ConfirmPassword.Error = flashProps.ConfirmPassword.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := session.Save(r, w); err != nil {
|
return rsvp.Data("register.gotmpl", props).SaveSession(session)
|
||||||
log.Println("Couldn't save session:", err)
|
|
||||||
http.Error(w, "Something went wrong. Error code: Zuko", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
templates.Execute(w, "register.gotmpl", props)
|
func RegisterPost(h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
}
|
form := r.ParseForm()
|
||||||
|
|
||||||
func (ctx *Context) RegisterPost(w http.ResponseWriter, r *http.Request) {
|
username := form.Get("username")
|
||||||
if err := r.ParseForm(); err != nil {
|
newPassword := form.Get("newPassword")
|
||||||
http.Error(w, "Couldn't parse form", http.StatusBadRequest)
|
confirmPassword := form.Get("confirmPassword")
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
username := r.Form.Get("username")
|
|
||||||
newPassword := r.Form.Get("newPassword")
|
|
||||||
confirmPassword := r.Form.Get("confirmPassword")
|
|
||||||
|
|
||||||
props := api.Register(username, newPassword, confirmPassword)
|
props := api.Register(username, newPassword, confirmPassword)
|
||||||
|
|
||||||
|
s := r.GetSession()
|
||||||
|
|
||||||
if props != nil {
|
if props != nil {
|
||||||
ctx.RedirectWithFlash(w, r, "/register", "register_props", &props)
|
s.FlashSet(&props, "register_props")
|
||||||
_ = json.NewEncoder(w).Encode(props)
|
return rsvp.SeeOther("/register").SaveSession(s)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.RedirectWithFlash(w, r, "/", "successful_registration", true)
|
s.FlashSet(true, "successful_registration")
|
||||||
|
return rsvp.SeeOther("/").SaveSession(s)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,34 +2,28 @@ package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"lishwist/db"
|
"lishwist/db"
|
||||||
"log"
|
"lishwist/rsvp"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ctx *Context) TodoUpdate(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func TodoUpdate(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if err := r.ParseForm(); err != nil {
|
form := r.ParseForm()
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
switch form.Get("intent") {
|
||||||
}
|
|
||||||
switch r.Form.Get("intent") {
|
|
||||||
case "unclaim_todo":
|
case "unclaim_todo":
|
||||||
unclaims := r.Form["gift"]
|
unclaims := form["gift"]
|
||||||
err := currentUser.ClaimGifts([]string{}, unclaims)
|
err := currentUser.ClaimGifts([]string{}, unclaims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Failed to update claim...", http.StatusInternalServerError)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to update claim...").LogError(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case "complete_todo":
|
case "complete_todo":
|
||||||
claims := r.Form["gift"]
|
claims := form["gift"]
|
||||||
err := currentUser.CompleteGifts(claims)
|
err := currentUser.CompleteGifts(claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to complete gifts: %s\n", err)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to complete gifts...").LogError(err)
|
||||||
http.Error(w, "Failed to complete gifts...", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
http.Error(w, "Invalid intent", http.StatusBadRequest)
|
return rsvp.Error(http.StatusBadRequest, "Invalid intent")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
return rsvp.SeeOther("/")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,82 +1,70 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"lishwist/db"
|
"lishwist/db"
|
||||||
|
"lishwist/rsvp"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ctx *Context) UsersJson(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func Users(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if !currentUser.IsAdmin {
|
if !currentUser.IsAdmin {
|
||||||
NotFoundJson(w, r)
|
return NotFound(h, r)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := db.GetAllUsers()
|
users, err := db.GetAllUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to get users: "+err.Error())
|
return rsvp.Error(http.StatusInternalServerError, "Failed to get users: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(users)
|
return rsvp.Data("", users)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) User(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func User(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if !currentUser.IsAdmin {
|
if !currentUser.IsAdmin {
|
||||||
NotFoundJson(w, r)
|
return NotFound(h, r)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reference := r.PathValue("userReference")
|
reference := r.PathValue("userReference")
|
||||||
|
|
||||||
user, err := db.GetUserByReference(reference)
|
user, err := db.GetUserByReference(reference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to get user: %s", err)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to get user: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if user == nil {
|
if user == nil {
|
||||||
writeGeneralErrorJson(w, http.StatusNotFound, "User not found")
|
return rsvp.Error(http.StatusNotFound, "User not found")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(user)
|
return rsvp.Data("", user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) UserPost(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func UserPost(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if !currentUser.IsAdmin {
|
if !currentUser.IsAdmin {
|
||||||
NotFoundJson(w, r)
|
return NotFound(h, r)
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := r.ParseForm(); err != nil {
|
|
||||||
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to parse form: %s", err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form := r.ParseForm()
|
||||||
|
|
||||||
reference := r.PathValue("userReference")
|
reference := r.PathValue("userReference")
|
||||||
if reference == currentUser.Reference {
|
if reference == currentUser.Reference {
|
||||||
writeGeneralErrorJson(w, http.StatusForbidden, "You cannot delete yourself.")
|
return rsvp.Error(http.StatusForbidden, "You cannot delete yourself.")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.GetAnyUserByReference(reference)
|
user, err := db.GetAnyUserByReference(reference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to get user: %s", err)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to get user: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if user == nil {
|
if user == nil {
|
||||||
writeGeneralErrorJson(w, http.StatusNotFound, "User not found")
|
return rsvp.Error(http.StatusNotFound, "User not found")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intent := r.Form.Get("intent")
|
intent := form.Get("intent")
|
||||||
|
|
||||||
if intent != "" {
|
if intent != "" {
|
||||||
err = user.SetLive(intent != "delete")
|
err = user.SetLive(intent != "delete")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to delete user: "+err.Error())
|
return rsvp.Error(http.StatusInternalServerError, "Failed to delete user: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(user)
|
return rsvp.Data("", user)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,82 +2,67 @@ package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"lishwist/db"
|
"lishwist/db"
|
||||||
"lishwist/error"
|
"lishwist/rsvp"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ctx *Context) WishlistAdd(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func WishlistAdd(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if err := r.ParseForm(); err != nil {
|
form := r.ParseForm()
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
newGiftName := form.Get("gift_name")
|
||||||
return
|
|
||||||
}
|
|
||||||
newGiftName := r.Form.Get("gift_name")
|
|
||||||
err := currentUser.AddGift(newGiftName)
|
err := currentUser.AddGift(newGiftName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to add gift.", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to add gift.").LogError(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
return rsvp.SeeOther("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) WishlistDelete(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func WishlistDelete(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if err := r.ParseForm(); err != nil {
|
form := r.ParseForm()
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
targets := form["gift"]
|
||||||
return
|
|
||||||
}
|
|
||||||
targets := r.Form["gift"]
|
|
||||||
err := currentUser.RemoveGifts(targets...)
|
err := currentUser.RemoveGifts(targets...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to remove gifts.", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to remove gifts.").LogError(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
return rsvp.SeeOther("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) ForeignWishlistPost(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
func ForeignWishlistPost(currentUser *db.User, h http.Header, r *rsvp.Request) rsvp.Response {
|
||||||
if err := r.ParseForm(); err != nil {
|
form := r.ParseForm()
|
||||||
error.Page(w, "Failed to parse form...", http.StatusBadRequest, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userReference := r.PathValue("userReference")
|
userReference := r.PathValue("userReference")
|
||||||
switch r.Form.Get("intent") {
|
intent := form.Get("intent")
|
||||||
|
switch intent {
|
||||||
case "claim":
|
case "claim":
|
||||||
claims := r.Form["unclaimed"]
|
claims := form["unclaimed"]
|
||||||
unclaims := r.Form["claimed"]
|
unclaims := form["claimed"]
|
||||||
err := currentUser.ClaimGifts(claims, unclaims)
|
err := currentUser.ClaimGifts(claims, unclaims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to update claim...", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to update claim...").LogError(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case "complete":
|
case "complete":
|
||||||
claims := r.Form["claimed"]
|
claims := form["claimed"]
|
||||||
err := currentUser.CompleteGifts(claims)
|
err := currentUser.CompleteGifts(claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to complete gifts...", http.StatusInternalServerError, nil)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to complete gifts...").LogError(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case "add":
|
case "add":
|
||||||
giftName := r.Form.Get("gift_name")
|
giftName := form.Get("gift_name")
|
||||||
if giftName == "" {
|
if giftName == "" {
|
||||||
error.Page(w, "Gift name not provided", http.StatusBadRequest, nil)
|
return rsvp.Error(http.StatusBadRequest, "Gift name not provided")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
err := currentUser.AddGiftToUser(userReference, giftName)
|
err := currentUser.AddGiftToUser(userReference, giftName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to add gift idea to other user...", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to add gift idea to other user...").LogError(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
case "delete":
|
case "delete":
|
||||||
claims := r.Form["unclaimed"]
|
claims := form["unclaimed"]
|
||||||
unclaims := r.Form["claimed"]
|
unclaims := form["claimed"]
|
||||||
gifts := append(claims, unclaims...)
|
gifts := append(claims, unclaims...)
|
||||||
err := currentUser.RemoveGifts(gifts...)
|
err := currentUser.RemoveGifts(gifts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to remove gift idea for other user...", http.StatusInternalServerError, err)
|
return rsvp.Error(http.StatusInternalServerError, "Failed to remove gift idea for other user...").LogError(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
http.Error(w, "Invalid intent", http.StatusBadRequest)
|
return rsvp.Error(http.StatusBadRequest, "Invalid intent %q", intent)
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, "/list/"+userReference, http.StatusSeeOther)
|
return rsvp.SeeOther("/list/" + userReference)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package rsvp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/Teajey/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServeMux struct {
|
||||||
|
inner *http.ServeMux
|
||||||
|
store *sqlstore.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServeMux(store *sqlstore.Store) *ServeMux {
|
||||||
|
return &ServeMux{
|
||||||
|
inner: http.NewServeMux(),
|
||||||
|
store: store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
m.inner.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Handler interface {
|
||||||
|
ServeHTTP(h http.Header, r *Request) Response
|
||||||
|
}
|
||||||
|
|
||||||
|
type HandlerFunc func(h http.Header, r *Request) Response
|
||||||
|
|
||||||
|
func (m *ServeMux) HandleFunc(pattern string, handler HandlerFunc) {
|
||||||
|
m.inner.HandleFunc(pattern, func(w http.ResponseWriter, stdReq *http.Request) {
|
||||||
|
r := wrapStdRequest(m.store, stdReq)
|
||||||
|
|
||||||
|
response := handler(w.Header(), &r)
|
||||||
|
|
||||||
|
err := response.Write(w, stdReq)
|
||||||
|
if err != nil {
|
||||||
|
response.Data = struct{ Message error }{err}
|
||||||
|
response.HtmlTemplateName = "error_page.gotmpl"
|
||||||
|
response.Status = http.StatusInternalServerError
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = response.Write(w, stdReq)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to write rsvp.Response to bytes: %s\n", err)
|
||||||
|
http.Error(w, "Failed to write response", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ServeMux) Handle(pattern string, handler Handler) {
|
||||||
|
m.HandleFunc(pattern, handler.ServeHTTP)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package rsvp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/Teajey/sqlstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
inner *http.Request
|
||||||
|
store *sqlstore.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapStdRequest(store *sqlstore.Store, r *http.Request) Request {
|
||||||
|
return Request{
|
||||||
|
inner: r,
|
||||||
|
store: store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) GetSession() Session {
|
||||||
|
session, _ := r.store.Get(r.inner, "lishwist_user")
|
||||||
|
return Session{session}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) ParseForm() url.Values {
|
||||||
|
err := r.inner.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to parse form: %s\n", err)
|
||||||
|
}
|
||||||
|
return r.inner.Form
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) PathValue(name string) string {
|
||||||
|
return r.inner.PathValue(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) URL() *url.URL {
|
||||||
|
return r.inner.URL
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
package rsvp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"lishwist/templates"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
HtmlTemplateName string
|
||||||
|
Data any
|
||||||
|
SeeOther string
|
||||||
|
Session *Session
|
||||||
|
Status int
|
||||||
|
LogMessage string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (res *Response) Write(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
if res.Session != nil {
|
||||||
|
err := res.Session.inner.Save(r, w)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to write session: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.SeeOther != "" {
|
||||||
|
http.Redirect(w, r, res.SeeOther, http.StatusSeeOther)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyBytes := bytes.NewBuffer([]byte{})
|
||||||
|
accept := r.Header.Get("Accept")
|
||||||
|
|
||||||
|
if res.LogMessage != "" {
|
||||||
|
log.Printf("%s --- %s\n", res.Data, res.LogMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Status != 0 {
|
||||||
|
w.WriteHeader(res.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.Contains(accept, "text/html"):
|
||||||
|
if res.HtmlTemplateName == "" {
|
||||||
|
err := json.NewEncoder(bodyBytes).Encode(res.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := templates.Execute(bodyBytes, res.HtmlTemplateName, res.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case strings.Contains(accept, "application/json"):
|
||||||
|
err := json.NewEncoder(bodyBytes).Encode(res.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err := json.NewEncoder(bodyBytes).Encode(res.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := w.Write(bodyBytes.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to write rsvp.Response to HTTP: %s\n", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Data(htmlTemplateName string, data any) Response {
|
||||||
|
return Response{
|
||||||
|
HtmlTemplateName: htmlTemplateName,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Response) Log(format string, a ...any) Response {
|
||||||
|
r.LogMessage = fmt.Sprintf(format, a...)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Response) LogError(err error) Response {
|
||||||
|
r.LogMessage = fmt.Sprintf("%s", err)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Response) SaveSession(s Session) Response {
|
||||||
|
r.Session = &s
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func SeeOther(url string) Response {
|
||||||
|
return Response{SeeOther: url}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(status int, format string, a ...any) Response {
|
||||||
|
return Response{
|
||||||
|
Status: status,
|
||||||
|
HtmlTemplateName: "error_page.gotmpl",
|
||||||
|
Data: struct{ Message string }{fmt.Sprintf(format, a...)},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package rsvp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Session struct {
|
||||||
|
inner *sessions.Session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) FlashGet(key ...string) any {
|
||||||
|
list := s.inner.Flashes(key...)
|
||||||
|
if len(list) < 1 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return list[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) FlashSet(value any, key ...string) {
|
||||||
|
s.inner.AddFlash(value, key...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) SetID(value string) {
|
||||||
|
s.inner.ID = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) SetValue(key any, value any) {
|
||||||
|
s.inner.Values[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) GetValue(key any) any {
|
||||||
|
return s.inner.Values[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) ClearValues() {
|
||||||
|
s.inner.Values = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) Options() *sessions.Options {
|
||||||
|
return s.inner.Options
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,7 @@ package templates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"io"
|
||||||
"net/http"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -33,12 +32,12 @@ func (p *InputProps) Validate() bool {
|
||||||
|
|
||||||
var tmpls map[string]*template.Template = loadTemplates()
|
var tmpls map[string]*template.Template = loadTemplates()
|
||||||
|
|
||||||
func Execute(w http.ResponseWriter, name string, data any) {
|
func Execute(w io.Writer, name string, data any) error {
|
||||||
err := tmpls[name].Execute(w, data)
|
err := tmpls[name].Execute(w, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to execute '%s' template: %s\n", name, err)
|
return fmt.Errorf("Failed to execute '%s' template: %w\n", name, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadTemplates() map[string]*template.Template {
|
func loadTemplates() map[string]*template.Template {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue