Compare commits
9 Commits
782ffbbe6d
...
dcba801dde
| Author | SHA1 | Date |
|---|---|---|
|
|
dcba801dde | |
|
|
20761920d3 | |
|
|
b48140e9c3 | |
|
|
98a39f8e4f | |
|
|
271163a889 | |
|
|
5a4097f4fe | |
|
|
994f4ee64a | |
|
|
fac92511ee | |
|
|
d2fb0fa707 |
|
|
@ -0,0 +1,85 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"lishwist/db"
|
||||||
|
"lishwist/templates"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoginProps struct {
|
||||||
|
GeneralError string
|
||||||
|
SuccessfulRegistration bool
|
||||||
|
Username templates.InputProps
|
||||||
|
Password templates.InputProps
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLoginProps(username, password string) *LoginProps {
|
||||||
|
return &LoginProps{
|
||||||
|
Username: templates.InputProps{
|
||||||
|
Name: "username",
|
||||||
|
Required: true,
|
||||||
|
Value: username,
|
||||||
|
},
|
||||||
|
Password: templates.InputProps{
|
||||||
|
Name: "password",
|
||||||
|
Type: "password",
|
||||||
|
Required: true,
|
||||||
|
Value: password,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *LoginProps) Validate() (valid bool) {
|
||||||
|
valid = true
|
||||||
|
|
||||||
|
if !p.Username.Validate() {
|
||||||
|
valid = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.Password.Validate() {
|
||||||
|
valid = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Login(username, password string) *LoginProps {
|
||||||
|
props := NewLoginProps(username, password)
|
||||||
|
|
||||||
|
valid := props.Validate()
|
||||||
|
props.Password.Value = ""
|
||||||
|
if !valid {
|
||||||
|
log.Printf("Invalid props: %#v\n", props)
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := db.GetUserByName(username)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to fetch user: %s\n", err)
|
||||||
|
props.GeneralError = "Username or password invalid"
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
if user == nil {
|
||||||
|
log.Printf("User not found by name: %q\n", username)
|
||||||
|
props.GeneralError = "Username or password invalid"
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
|
||||||
|
passHash, err := user.GetPassHash()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Failed to get password hash: " + err.Error())
|
||||||
|
props.GeneralError = "Something went wrong. Error code: Momo"
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bcrypt.CompareHashAndPassword(passHash, []byte(password))
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Username or password invalid: " + err.Error())
|
||||||
|
props.GeneralError = "Username or password invalid"
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,8 @@ type RegisterProps struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RegisterProps) Validate() (valid bool) {
|
func (p *RegisterProps) Validate() (valid bool) {
|
||||||
|
valid = true
|
||||||
|
|
||||||
if p.Password.Value != p.ConfirmPassword.Value {
|
if p.Password.Value != p.ConfirmPassword.Value {
|
||||||
p.ConfirmPassword.Error = "Passwords didn't match"
|
p.ConfirmPassword.Error = "Passwords didn't match"
|
||||||
valid = false
|
valid = false
|
||||||
|
|
@ -69,24 +71,27 @@ func Register(username, newPassword, confirmPassword string) *RegisterProps {
|
||||||
props.Password.Value = ""
|
props.Password.Value = ""
|
||||||
props.ConfirmPassword.Value = ""
|
props.ConfirmPassword.Value = ""
|
||||||
if !valid {
|
if !valid {
|
||||||
|
log.Printf("Invalid props: %#v\n", props)
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
existingUser, _ := db.GetUserByName(username)
|
existingUser, _ := db.GetUserByName(username)
|
||||||
if existingUser != nil {
|
if existingUser != nil {
|
||||||
|
log.Printf("Username is taken: %q\n", username)
|
||||||
props.Username.Error = "Username is taken"
|
props.Username.Error = "Username is taken"
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
hashedPasswordBytes, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.MinCost)
|
hashedPasswordBytes, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.MinCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("Failed to hash password: %s\n", err)
|
||||||
props.GeneralError = "Something went wrong. Error code: Aang"
|
props.GeneralError = "Something went wrong. Error code: Aang"
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.CreateUser(username, hashedPasswordBytes)
|
_, err = db.CreateUser(username, hashedPasswordBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Registration error:", err)
|
log.Printf("Failed to create user: %s\n", err)
|
||||||
props.GeneralError = "Something went wrong. Error code: Ozai"
|
props.GeneralError = "Something went wrong. Error code: Ozai"
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,61 +1,121 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
import "database/sql"
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
Id string
|
Id string
|
||||||
Name string
|
Name string
|
||||||
Reference string
|
Reference string
|
||||||
|
Members []User
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) MemberIndex(userId string) int {
|
||||||
|
for i, u := range g.Members {
|
||||||
|
if u.Id == userId {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryForGroup(query string, args ...any) (*Group, error) {
|
func queryForGroup(query string, args ...any) (*Group, error) {
|
||||||
var id string
|
var group Group
|
||||||
var name string
|
err := database.QueryRow(query, args...).Scan(&group.Id, &group.Name, &group.Reference)
|
||||||
var reference string
|
|
||||||
err := database.QueryRow(query, args...).Scan(&id, &name, &reference)
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
members, err := queryForGroupMembers(group.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
group.Members = members
|
||||||
|
return &group, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryForGroups(query string, args ...any) ([]Group, error) {
|
||||||
|
groups := []Group{}
|
||||||
|
rows, err := database.Query(query)
|
||||||
|
if err != nil {
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
var group Group
|
||||||
|
err := rows.Scan(&group.Id, &group.Name, &group.Reference)
|
||||||
|
if err != nil {
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
members, err := queryForGroupMembers(group.Id)
|
||||||
|
if err != nil {
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
group.Members = members
|
||||||
|
groups = append(groups, group)
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
if err != nil {
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
return groups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryForGroupMembers(groupId string) ([]User, error) {
|
||||||
|
query := "SELECT user.id, user.name, user.reference, user.is_admin, user.is_live FROM v_user AS user JOIN group_member ON group_member.user_id = user.id JOIN [group] ON [group].id = group_member.group_id WHERE [group].id = ? ORDER BY group_member.user_id"
|
||||||
|
members, err := queryForUsers(query, groupId)
|
||||||
|
if err != nil {
|
||||||
|
return members, fmt.Errorf("Failed to get members: %w", err)
|
||||||
|
}
|
||||||
|
return members, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroupByReference(reference string) (*Group, error) {
|
||||||
|
query := "SELECT [group].id, [group].name, [group].reference FROM [group] WHERE [group].reference = ?"
|
||||||
|
return queryForGroup(query, reference)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllGroups() ([]Group, error) {
|
||||||
|
query := "SELECT id, name, reference FROM [group];"
|
||||||
|
return queryForGroups(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateGroup(name string, reference string) (*Group, error) {
|
||||||
|
stmt := "INSERT INTO [group] (name, reference) VALUES (?, ?)"
|
||||||
|
result, err := database.Exec(stmt, name, reference)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
id, err := result.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
group := Group{
|
group := Group{
|
||||||
Id: id,
|
Id: strconv.FormatInt(id, 10),
|
||||||
Name: name,
|
Name: name,
|
||||||
Reference: reference,
|
Reference: reference,
|
||||||
}
|
}
|
||||||
return &group, nil
|
return &group, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGroupByReference(reference string) (*Group, error) {
|
func (g *Group) AddUser(userId string) error {
|
||||||
stmt := "SELECT [group].id, [group].name, [group].reference FROM [group] WHERE [group].reference = ?"
|
stmt := "INSERT INTO group_member (group_id, user_id) VALUES (?, ?)"
|
||||||
return queryForGroup(stmt, reference)
|
_, err := database.Exec(stmt, g.Id, userId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Group) GetMembers() ([]User, error) {
|
func (g *Group) RemoveUser(userId string) error {
|
||||||
stmt := "SELECT user.id, user.name, user.reference FROM user JOIN group_member ON group_member.user_id = user.id JOIN [group] ON [group].id = group_member.group_id WHERE [group].id = ?"
|
stmt := "DELETE FROM group_member WHERE group_id = ? AND user_id = ?"
|
||||||
rows, err := database.Query(stmt, g.Id)
|
_, err := database.Exec(stmt, g.Id, userId)
|
||||||
users := []User{}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return users, err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
return nil
|
||||||
for rows.Next() {
|
|
||||||
var id string
|
|
||||||
var name string
|
|
||||||
var reference string
|
|
||||||
err := rows.Scan(&id, &name, &reference)
|
|
||||||
if err != nil {
|
|
||||||
return users, err
|
|
||||||
}
|
|
||||||
users = append(users, User{
|
|
||||||
Id: id,
|
|
||||||
Name: name,
|
|
||||||
Reference: reference,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
err = rows.Err()
|
|
||||||
if err != nil {
|
|
||||||
return users, err
|
|
||||||
}
|
|
||||||
return users, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ CREATE TABLE IF NOT EXISTS "user" (
|
||||||
"id" INTEGER NOT NULL UNIQUE,
|
"id" INTEGER NOT NULL UNIQUE,
|
||||||
"name" TEXT NOT NULL UNIQUE,
|
"name" TEXT NOT NULL UNIQUE,
|
||||||
"reference" TEXT NOT NULL UNIQUE,
|
"reference" TEXT NOT NULL UNIQUE,
|
||||||
"motto" TEXT NOT NULL,
|
"motto" TEXT NOT NULL DEFAULT "",
|
||||||
"password_hash" TEXT NOT NULL,
|
"password_hash" TEXT NOT NULL,
|
||||||
|
"is_admin" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"is_live" INTEGER NOT NULL DEFAULT 1,
|
||||||
PRIMARY KEY("id" AUTOINCREMENT)
|
PRIMARY KEY("id" AUTOINCREMENT)
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS "gift" (
|
CREATE TABLE IF NOT EXISTS "gift" (
|
||||||
|
|
@ -37,4 +39,15 @@ CREATE TABLE IF NOT EXISTS "session" (
|
||||||
"value" TEXT NOT NULL,
|
"value" TEXT NOT NULL,
|
||||||
PRIMARY KEY("id" AUTOINCREMENT)
|
PRIMARY KEY("id" AUTOINCREMENT)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
DROP VIEW IF EXISTS "v_user";
|
||||||
|
CREATE VIEW "v_user"
|
||||||
|
AS
|
||||||
|
SELECT * FROM user WHERE user.is_live = 1;
|
||||||
|
|
||||||
|
-- DROP VIEW IF EXISTS "v_wish";
|
||||||
|
-- CREATE VIEW "v_wish"
|
||||||
|
-- AS
|
||||||
|
-- SELECT gift.id, gift.name, gift.sent FROM gift JOIN user AS recipient;
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE user ADD COLUMN "is_live" INTEGER NOT NULL DEFAULT 1;
|
||||||
|
|
||||||
|
ALTER TABLE user RENAME TO old_user;
|
||||||
|
|
||||||
|
CREATE TABLE "user" (
|
||||||
|
"id" INTEGER NOT NULL UNIQUE,
|
||||||
|
"name" TEXT NOT NULL UNIQUE,
|
||||||
|
"reference" TEXT NOT NULL UNIQUE,
|
||||||
|
"motto" TEXT NOT NULL DEFAULT "",
|
||||||
|
"password_hash" TEXT NOT NULL,
|
||||||
|
"is_admin" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"is_live" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
PRIMARY KEY("id" AUTOINCREMENT)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO user SELECT * FROM old_user;
|
||||||
|
|
||||||
|
DROP TABLE "old_user";
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
@ -11,6 +11,8 @@ type User struct {
|
||||||
Id string
|
Id string
|
||||||
Name string
|
Name string
|
||||||
Reference string
|
Reference string
|
||||||
|
IsAdmin bool
|
||||||
|
IsLive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Gift struct {
|
type Gift struct {
|
||||||
|
|
@ -27,35 +29,75 @@ type Gift struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryForUser(query string, args ...any) (*User, error) {
|
func queryForUser(query string, args ...any) (*User, error) {
|
||||||
var id string
|
var u User
|
||||||
var name string
|
err := database.QueryRow(query, args...).Scan(&u.Id, &u.Name, &u.Reference, &u.IsAdmin, &u.IsLive)
|
||||||
var reference string
|
|
||||||
err := database.QueryRow(query, args...).Scan(&id, &name, &reference)
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
user := User{
|
return &u, nil
|
||||||
Id: id,
|
}
|
||||||
Name: name,
|
|
||||||
Reference: reference,
|
func queryForUsers(query string, args ...any) ([]User, error) {
|
||||||
|
rows, err := database.Query(query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return &user, nil
|
defer rows.Close()
|
||||||
|
users := []User{}
|
||||||
|
for rows.Next() {
|
||||||
|
var u User
|
||||||
|
err = rows.Scan(&u.Id, &u.Name, &u.Reference, &u.IsAdmin, &u.IsLive)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
users = append(users, u)
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllUsers() ([]User, error) {
|
||||||
|
stmt := "SELECT id, name, reference, is_admin, is_live FROM user"
|
||||||
|
return queryForUsers(stmt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUser(id string) (*User, error) {
|
||||||
|
stmt := "SELECT id, name, reference, is_admin, is_live FROM v_user WHERE id = ?"
|
||||||
|
return queryForUser(stmt, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserByName(username string) (*User, error) {
|
func GetUserByName(username string) (*User, error) {
|
||||||
stmt := "SELECT user.id, user.name, user.reference FROM user WHERE user.name = ?"
|
stmt := "SELECT id, name, reference, is_admin, is_live FROM v_user WHERE name = ?"
|
||||||
return queryForUser(stmt, username)
|
return queryForUser(stmt, username)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserByReference(reference string) (*User, error) {
|
func GetUserByReference(reference string) (*User, error) {
|
||||||
stmt := "SELECT user.id, user.name, user.reference FROM user WHERE user.reference = ?"
|
stmt := "SELECT id, name, reference, is_admin, is_live FROM v_user WHERE reference = ?"
|
||||||
return queryForUser(stmt, reference)
|
return queryForUser(stmt, reference)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAnyUserByReference(reference string) (*User, error) {
|
||||||
|
stmt := "SELECT id, name, reference, is_admin, is_live FROM user WHERE reference = ?"
|
||||||
|
return queryForUser(stmt, reference)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetLive(setting bool) error {
|
||||||
|
query := "UPDATE user SET is_live = ? WHERE reference = ?"
|
||||||
|
_, err := database.Exec(query, setting, u.Reference)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.IsLive = setting
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func CreateUser(username string, passHash []byte) (*User, error) {
|
func CreateUser(username string, passHash []byte) (*User, error) {
|
||||||
stmt := "INSERT INTO user (name, motto, reference, password_hash) VALUES (?, '', ?, ?)"
|
stmt := "INSERT INTO user (name, reference, password_hash) VALUES (?, ?, ?)"
|
||||||
reference, err := uuid.NewRandom()
|
reference, err := uuid.NewRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -76,7 +118,7 @@ func CreateUser(username string, passHash []byte) (*User, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) GetPassHash() ([]byte, error) {
|
func (u *User) GetPassHash() ([]byte, error) {
|
||||||
stmt := "SELECT user.password_hash FROM user WHERE user.id = ?"
|
stmt := "SELECT password_hash FROM v_user WHERE id = ?"
|
||||||
var passHash string
|
var passHash string
|
||||||
err := database.QueryRow(stmt, u.Id).Scan(&passHash)
|
err := database.QueryRow(stmt, u.Id).Scan(&passHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -86,7 +128,7 @@ func (u *User) GetPassHash() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) CountGifts() (int, error) {
|
func (u *User) CountGifts() (int, error) {
|
||||||
stmt := "SELECT COUNT(gift.id) AS gift_count FROM gift JOIN user ON gift.recipient_id = user.id LEFT JOIN user AS claimant ON gift.claimant_id = claimant.id WHERE gift.creator_id = user.id AND user.id = ?"
|
stmt := "SELECT COUNT(gift.id) AS gift_count FROM gift WHERE gift.creator_id = ?1 AND gift.recipient_id = ?1"
|
||||||
var giftCount int
|
var giftCount int
|
||||||
err := database.QueryRow(stmt, u.Id).Scan(&giftCount)
|
err := database.QueryRow(stmt, u.Id).Scan(&giftCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -96,7 +138,7 @@ func (u *User) CountGifts() (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) GetGifts() ([]Gift, error) {
|
func (u *User) GetGifts() ([]Gift, error) {
|
||||||
stmt := "SELECT gift.id, gift.name, claimant.id, claimant.name, gift.sent FROM gift JOIN user ON gift.recipient_id = user.id LEFT JOIN user AS claimant ON gift.claimant_id = claimant.id WHERE gift.creator_id = user.id AND user.id = ?"
|
stmt := "SELECT gift.id, gift.name, gift.sent FROM gift WHERE gift.creator_id = ?1 AND gift.recipient_id = ?1"
|
||||||
rows, err := database.Query(stmt, u.Id)
|
rows, err := database.Query(stmt, u.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -106,18 +148,14 @@ func (u *User) GetGifts() ([]Gift, error) {
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var id string
|
var id string
|
||||||
var name string
|
var name string
|
||||||
var claimantId sql.NullString
|
|
||||||
var claimantName sql.NullString
|
|
||||||
var sent bool
|
var sent bool
|
||||||
err = rows.Scan(&id, &name, &claimantId, &claimantName, &sent)
|
err = rows.Scan(&id, &name, &sent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
gift := Gift{
|
gift := Gift{
|
||||||
Id: id,
|
Id: id,
|
||||||
Name: name,
|
Name: name,
|
||||||
ClaimantId: claimantId.String,
|
|
||||||
ClaimantName: claimantName.String,
|
|
||||||
Sent: sent,
|
Sent: sent,
|
||||||
}
|
}
|
||||||
gifts = append(gifts, gift)
|
gifts = append(gifts, gift)
|
||||||
|
|
@ -132,15 +170,15 @@ func (u *User) GetGifts() ([]Gift, error) {
|
||||||
func (u *User) GetOtherUserGifts(otherUserReference string) ([]Gift, error) {
|
func (u *User) GetOtherUserGifts(otherUserReference string) ([]Gift, error) {
|
||||||
otherUser, err := GetUserByReference(otherUserReference)
|
otherUser, err := GetUserByReference(otherUserReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("Failed to get other user: %w", err)
|
||||||
}
|
}
|
||||||
if otherUser.Id == u.Id {
|
if otherUser.Id == u.Id {
|
||||||
return nil, fmt.Errorf("Not allowed to view own foreign wishlist")
|
return nil, fmt.Errorf("Not allowed to view own foreign wishlist")
|
||||||
}
|
}
|
||||||
stmt := "SELECT gift.id, gift.name, claimant.id, claimant.name, gift.sent, gift.creator_id, creator.name, gift.recipient_id FROM gift JOIN user ON gift.recipient_id = user.id LEFT JOIN user AS claimant ON gift.claimant_id = claimant.id LEFT JOIN user AS creator ON gift.creator_id = creator.id WHERE user.id = ?"
|
stmt := "SELECT gift.id, gift.name, claimant.id, claimant.name, gift.sent, gift.creator_id, creator.name, gift.recipient_id FROM gift JOIN v_user AS user ON gift.recipient_id = user.id LEFT JOIN v_user AS claimant ON gift.claimant_id = claimant.id LEFT JOIN v_user AS creator ON gift.creator_id = creator.id WHERE user.id = ?"
|
||||||
rows, err := database.Query(stmt, otherUser.Id)
|
rows, err := database.Query(stmt, otherUser.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("Failed to execute query: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
gifts := []Gift{}
|
gifts := []Gift{}
|
||||||
|
|
@ -155,7 +193,7 @@ func (u *User) GetOtherUserGifts(otherUserReference string) ([]Gift, error) {
|
||||||
var recipientId string
|
var recipientId string
|
||||||
err = rows.Scan(&id, &name, &claimantId, &claimantName, &sent, &creatorId, &creatorName, &recipientId)
|
err = rows.Scan(&id, &name, &claimantId, &claimantName, &sent, &creatorId, &creatorName, &recipientId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("Failed to scan row: %w", err)
|
||||||
}
|
}
|
||||||
gift := Gift{
|
gift := Gift{
|
||||||
Id: id,
|
Id: id,
|
||||||
|
|
@ -171,13 +209,13 @@ func (u *User) GetOtherUserGifts(otherUserReference string) ([]Gift, error) {
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
err = rows.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("Rows returned an error: %w", err)
|
||||||
}
|
}
|
||||||
return gifts, nil
|
return gifts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) GetTodo() ([]Gift, error) {
|
func (u *User) GetTodo() ([]Gift, error) {
|
||||||
stmt := "SELECT gift.id, gift.name, gift.sent, recipient.name, recipient.reference FROM gift JOIN user ON gift.claimant_id = user.id JOIN user AS recipient ON gift.recipient_id = recipient.id WHERE user.id = ? ORDER BY gift.sent ASC, gift.name"
|
stmt := "SELECT gift.id, gift.name, gift.sent, recipient.name, recipient.reference FROM gift JOIN v_user AS user ON gift.claimant_id = user.id JOIN v_user AS recipient ON gift.recipient_id = recipient.id WHERE user.id = ? ORDER BY gift.sent ASC, gift.name"
|
||||||
rows, err := database.Query(stmt, u.Id)
|
rows, err := database.Query(stmt, u.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -367,7 +405,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 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)
|
rows, err := database.Query(stmt, u.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -395,35 +433,6 @@ func (u *User) GetGroups() ([]Group, error) {
|
||||||
return groups, nil
|
return groups, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) GetPeers(groupId string) ([]User, error) {
|
|
||||||
stmt := "SELECT user.id, user.name, user.reference FROM user JOIN group_member ON group_member.user_id = user.id JOIN [group] ON [group].id = group_member.group_id WHERE [group].id = ? AND user.id != ?"
|
|
||||||
rows, err := database.Query(stmt, groupId, u.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
users := []User{}
|
|
||||||
for rows.Next() {
|
|
||||||
var id string
|
|
||||||
var name string
|
|
||||||
var reference string
|
|
||||||
err := rows.Scan(&id, &name, &reference)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
users = append(users, User{
|
|
||||||
Id: id,
|
|
||||||
Name: name,
|
|
||||||
Reference: reference,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
err = rows.Err()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return users, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *User) GetGroupByReference(reference string) (*Group, error) {
|
func (u *User) GetGroupByReference(reference string) (*Group, error) {
|
||||||
stmt := "SELECT [group].id, [group].name, [group].reference FROM [group] JOIN group_member ON [group].id == group_member.group_id WHERE [group].reference = ? AND group_member.user_id = ?"
|
stmt := "SELECT [group].id, [group].name, [group].reference FROM [group] JOIN group_member ON [group].id == group_member.group_id WHERE [group].reference = ? AND group_member.user_id = ?"
|
||||||
return queryForGroup(stmt, reference, u.Id)
|
return queryForGroup(stmt, reference, u.Id)
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ type pageProps struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Page(w http.ResponseWriter, publicMessage string, status int, err error) {
|
func Page(w http.ResponseWriter, publicMessage string, status int, err error) {
|
||||||
|
w.WriteHeader(status)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%s --- %s\n", publicMessage, err)
|
log.Printf("%s --- %s\n", publicMessage, err)
|
||||||
}
|
}
|
||||||
templates.Execute(w, "error_page.gotmpl", pageProps{publicMessage})
|
templates.Execute(w, "error_page.gotmpl", pageProps{publicMessage})
|
||||||
http.Error(w, "", http.StatusInternalServerError)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
gob.Register(&api.RegisterProps{})
|
gob.Register(&api.RegisterProps{})
|
||||||
gob.Register(&routing.LoginProps{})
|
gob.Register(&api.LoginProps{})
|
||||||
|
|
||||||
err := db.Open()
|
err := db.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -27,7 +27,7 @@ func main() {
|
||||||
|
|
||||||
store, err := db.NewSessionStore()
|
store, err := db.NewSessionStore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to ")
|
log.Fatalf("Failed to initialize session store: %s\n", err)
|
||||||
}
|
}
|
||||||
store.Options.MaxAge = 86_400
|
store.Options.MaxAge = 86_400
|
||||||
store.Options.Secure = !env.InDev
|
store.Options.Secure = !env.InDev
|
||||||
|
|
@ -44,14 +44,23 @@ func main() {
|
||||||
r.Html.Public.HandleFunc("GET /list/{userReference}", route.PublicWishlist)
|
r.Html.Public.HandleFunc("GET /list/{userReference}", route.PublicWishlist)
|
||||||
r.Html.Public.HandleFunc("GET /group/{groupReference}", route.PublicGroupPage)
|
r.Html.Public.HandleFunc("GET /group/{groupReference}", route.PublicGroupPage)
|
||||||
|
|
||||||
r.Html.Private.HandleFunc("GET /{$}", route.Home)
|
r.Html.Private.Handle("GET /{$}", route.ExpectUser(route.Home))
|
||||||
r.Html.Private.HandleFunc("POST /{$}", route.HomePost)
|
r.Html.Private.Handle("POST /{$}", route.ExpectUser(route.HomePost))
|
||||||
r.Html.Private.HandleFunc("GET /list/{userReference}", route.ForeignWishlist)
|
r.Html.Private.Handle("GET /list/{userReference}", route.ExpectUser(route.ForeignWishlist))
|
||||||
r.Html.Private.HandleFunc("POST /list/{userReference}", route.ForeignWishlistPost)
|
r.Html.Private.Handle("POST /list/{userReference}", route.ExpectUser(route.ForeignWishlistPost))
|
||||||
r.Html.Private.HandleFunc("GET /group/{groupReference}", route.GroupPage)
|
r.Html.Private.Handle("GET /group/{groupReference}", route.ExpectUser(route.GroupPage))
|
||||||
r.Html.Private.HandleFunc("POST /logout", route.LogoutPost)
|
r.Html.Private.HandleFunc("POST /logout", route.LogoutPost)
|
||||||
|
r.Html.Private.HandleFunc("GET /", routing.NotFound)
|
||||||
|
|
||||||
r.Json.Public.HandleFunc("POST /register", route.RegisterPostJson)
|
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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/Teajey/sqlstore"
|
"github.com/Teajey/sqlstore"
|
||||||
)
|
)
|
||||||
|
|
@ -29,10 +30,10 @@ type Router struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (s *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
contentType := r.Header.Get("Content-Type")
|
accept := r.Header.Get("Accept")
|
||||||
|
|
||||||
switch contentType {
|
switch {
|
||||||
case "application/json":
|
case strings.HasPrefix(accept, "application/json"):
|
||||||
s.Json.ServeHTTP(w, r)
|
s.Json.ServeHTTP(w, r)
|
||||||
default:
|
default:
|
||||||
s.Html.ServeHTTP(w, r)
|
s.Html.ServeHTTP(w, r)
|
||||||
|
|
|
||||||
|
|
@ -18,16 +18,23 @@ func NewContext(store *sqlstore.Store) *Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (auth *Context) ExpectUser(r *http.Request) *db.User {
|
func (ctx *Context) ExpectUser(next func(*db.User, http.ResponseWriter, *http.Request)) http.Handler {
|
||||||
session, _ := auth.store.Get(r, "lishwist_user")
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
session, _ := ctx.store.Get(r, "lishwist_user")
|
||||||
username, ok := session.Values["username"].(string)
|
username, ok := session.Values["username"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatalln("Failed to get username")
|
log.Println("Failed to get username")
|
||||||
|
http.Error(w, "", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.GetUserByName(username)
|
user, err := db.GetUserByName(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to get user: %s\n", err)
|
log.Printf("Failed to get user: %s\n", err)
|
||||||
|
http.Error(w, "", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return user
|
|
||||||
|
next(user, w, r)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,16 @@ package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func writeGeneralError(w http.ResponseWriter, msg string, status int) {
|
func writeGeneralErrorJson(w http.ResponseWriter, status int, format string, a ...any) {
|
||||||
|
msg := fmt.Sprintf(format, a...)
|
||||||
|
log.Printf("General error: %s\n", msg)
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
escapedMsg := strings.ReplaceAll(msg, `"`, `\"`)
|
escapedMsg := strings.ReplaceAll(msg, `"`, `\"`)
|
||||||
_, _ = w.Write([]byte(fmt.Sprintf(`{"GeneralError":"%s"}`, escapedMsg)))
|
_, _ = w.Write([]byte(fmt.Sprintf(`{"GeneralError":"%s"}`, escapedMsg)))
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,9 @@ type foreignWishlistProps struct {
|
||||||
Gifts []db.Gift
|
Gifts []db.Gift
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) ForeignWishlist(w http.ResponseWriter, r *http.Request) {
|
func (ctx *Context) ForeignWishlist(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
userReference := r.PathValue("userReference")
|
userReference := r.PathValue("userReference")
|
||||||
user := ctx.ExpectUser(r)
|
if currentUser.Reference == userReference {
|
||||||
if user.Reference == userReference {
|
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -30,12 +29,12 @@ func (ctx *Context) ForeignWishlist(w http.ResponseWriter, r *http.Request) {
|
||||||
error.Page(w, "User not found", http.StatusNotFound, err)
|
error.Page(w, "User not found", http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gifts, err := user.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)
|
error.Page(w, "An error occurred while fetching this user's wishlist :(", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p := foreignWishlistProps{CurrentUserId: user.Id, CurrentUserName: user.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)
|
templates.Execute(w, "foreign_wishlist.gotmpl", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"lishwist/db"
|
"lishwist/db"
|
||||||
"lishwist/error"
|
"lishwist/error"
|
||||||
|
|
@ -9,15 +11,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupProps struct {
|
type GroupProps struct {
|
||||||
Name string
|
Group *db.Group
|
||||||
Members []db.User
|
|
||||||
CurrentUsername string
|
CurrentUsername string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) GroupPage(w http.ResponseWriter, r *http.Request) {
|
func (ctx *Context) GroupPage(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
user := ctx.ExpectUser(r)
|
|
||||||
groupReference := r.PathValue("groupReference")
|
groupReference := r.PathValue("groupReference")
|
||||||
group, err := user.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)
|
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
|
@ -26,15 +26,11 @@ func (ctx *Context) GroupPage(w http.ResponseWriter, r *http.Request) {
|
||||||
error.Page(w, "Group not found. (It might be because you're not a member)", http.StatusNotFound, nil)
|
error.Page(w, "Group not found. (It might be because you're not a member)", http.StatusNotFound, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
peers, err := user.GetPeers(group.Id)
|
index := group.MemberIndex(currentUser.Id)
|
||||||
if err != nil {
|
group.Members = slices.Delete(group.Members, index, index+1)
|
||||||
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p := GroupProps{
|
p := GroupProps{
|
||||||
Name: group.Name,
|
Group: group,
|
||||||
Members: peers,
|
CurrentUsername: currentUser.Name,
|
||||||
CurrentUsername: user.Name,
|
|
||||||
}
|
}
|
||||||
templates.Execute(w, "group_page.gotmpl", p)
|
templates.Execute(w, "group_page.gotmpl", p)
|
||||||
}
|
}
|
||||||
|
|
@ -46,14 +42,114 @@ func (ctx *Context) PublicGroupPage(w http.ResponseWriter, r *http.Request) {
|
||||||
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
members, err := group.GetMembers()
|
|
||||||
if err != nil {
|
|
||||||
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p := GroupProps{
|
p := GroupProps{
|
||||||
Name: group.Name,
|
Group: group,
|
||||||
Members: members,
|
|
||||||
}
|
}
|
||||||
templates.Execute(w, "public_group_page.gotmpl", p)
|
templates.Execute(w, "public_group_page.gotmpl", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) GroupPost(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !currentUser.IsAdmin {
|
||||||
|
NotFoundJson(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "Failed to parse form: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var group *db.Group
|
||||||
|
|
||||||
|
reference := r.PathValue("groupReference")
|
||||||
|
name := r.Form.Get("name")
|
||||||
|
addUsers := r.Form["addUser"]
|
||||||
|
removeUsers := r.Form["removeUser"]
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
createdGroup, err := db.CreateGroup(name, reference)
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "Failed to create group: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
group = createdGroup
|
||||||
|
} else {
|
||||||
|
existingGroup, err := db.GetGroupByReference(reference)
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "Failed to get group: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if existingGroup == nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusNotFound, "Group not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
group = existingGroup
|
||||||
|
|
||||||
|
for _, userId := range removeUsers {
|
||||||
|
index := group.MemberIndex(userId)
|
||||||
|
if index == -1 {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "Group %q does not contain a user with id %s", reference, userId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = group.RemoveUser(userId)
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "On group %q failed to remove user with id %s: %s", reference, userId, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
group.Members = slices.Delete(group.Members, index, index+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, userId := range addUsers {
|
||||||
|
user, err := db.GetUser(userId)
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "Groups exists, but a user with id %s could not be fetched: %s", userId, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user == nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "Groups exists, but a user with id %s does not exist", userId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = group.AddUser(user.Id)
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "Groups exists, but failed to add user with id %s: %s", userId, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
group.Members = append(group.Members, *user)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = json.NewEncoder(w).Encode(group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) GroupsJson(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !currentUser.IsAdmin {
|
||||||
|
NotFoundJson(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groups, err := db.GetAllGroups()
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "Failed to get groups: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = json.NewEncoder(w).Encode(groups)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) Group(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !currentUser.IsAdmin {
|
||||||
|
NotFoundJson(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
groupReference := r.PathValue("groupReference")
|
||||||
|
group, err := db.GetGroupByReference(groupReference)
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusBadRequest, "Couldn't get group: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if group == nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusNotFound, "Group not found.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = json.NewEncoder(w).Encode(group)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,41 +18,40 @@ type HomeProps struct {
|
||||||
Groups []db.Group
|
Groups []db.Group
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) Home(w http.ResponseWriter, r *http.Request) {
|
func (ctx *Context) Home(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
user := ctx.ExpectUser(r)
|
gifts, err := currentUser.GetGifts()
|
||||||
gifts, err := user.GetGifts()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
todo, err := user.GetTodo()
|
todo, err := currentUser.GetTodo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
groups, err := user.GetGroups()
|
groups, err := currentUser.GetGroups()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p := HomeProps{Username: user.Name, Gifts: gifts, Todo: todo, Reference: user.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)
|
templates.Execute(w, "home.gotmpl", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) HomePost(w http.ResponseWriter, r *http.Request) {
|
func (ctx *Context) HomePost(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
http.Error(w, "Couldn't parse form", http.StatusBadRequest)
|
http.Error(w, "Couldn't parse form", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch r.Form.Get("intent") {
|
switch r.Form.Get("intent") {
|
||||||
case "add_idea":
|
case "add_idea":
|
||||||
ctx.WishlistAdd(w, r)
|
ctx.WishlistAdd(currentUser, w, r)
|
||||||
return
|
return
|
||||||
case "delete_idea":
|
case "delete_idea":
|
||||||
ctx.WishlistDelete(w, r)
|
ctx.WishlistDelete(currentUser, w, r)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
ctx.TodoUpdate(w, r)
|
ctx.TodoUpdate(currentUser, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package routing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func decodeJsonParams(r *http.Request, v any) error {
|
|
||||||
dec := json.NewDecoder(r.Body)
|
|
||||||
dec.DisallowUnknownFields()
|
|
||||||
err := dec.Decode(&v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +1,18 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"lishwist/db"
|
"encoding/json"
|
||||||
|
"lishwist/api"
|
||||||
sesh "lishwist/session"
|
sesh "lishwist/session"
|
||||||
"lishwist/templates"
|
"lishwist/templates"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginProps struct {
|
|
||||||
GeneralError string
|
|
||||||
SuccessfulRegistration bool
|
|
||||||
Username templates.InputProps
|
|
||||||
Password templates.InputProps
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLoginProps() LoginProps {
|
|
||||||
return LoginProps{
|
|
||||||
Username: templates.InputProps{
|
|
||||||
Name: "username",
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
Password: templates.InputProps{
|
|
||||||
Name: "password",
|
|
||||||
Type: "password",
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *Context) Login(w http.ResponseWriter, r *http.Request) {
|
func (ctx *Context) Login(w http.ResponseWriter, r *http.Request) {
|
||||||
session, _ := ctx.store.Get(r, "lishwist_user")
|
session, _ := ctx.store.Get(r, "lishwist_user")
|
||||||
|
|
||||||
props := NewLoginProps()
|
props := api.NewLoginProps("", "")
|
||||||
|
|
||||||
flash, err := sesh.GetFirstFlash(w, r, session, "login_props")
|
flash, err := sesh.GetFirstFlash(w, r, session, "login_props")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -43,7 +20,7 @@ func (ctx *Context) Login(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
flashProps, ok := flash.(*LoginProps)
|
flashProps, ok := flash.(*api.LoginProps)
|
||||||
if ok {
|
if ok {
|
||||||
props.Username.Value = flashProps.Username.Value
|
props.Username.Value = flashProps.Username.Value
|
||||||
|
|
||||||
|
|
@ -75,28 +52,10 @@ func (ctx *Context) LoginPost(w http.ResponseWriter, r *http.Request) {
|
||||||
username := r.Form.Get("username")
|
username := r.Form.Get("username")
|
||||||
password := r.Form.Get("password")
|
password := r.Form.Get("password")
|
||||||
|
|
||||||
props := NewLoginProps()
|
props := api.Login(username, password)
|
||||||
props.Username.Value = username
|
if props != nil {
|
||||||
|
|
||||||
user, err := db.GetUserByName(username)
|
|
||||||
if user == nil || err != nil {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
props.GeneralError = "Username or password invalid"
|
|
||||||
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
passHash, err := user.GetPassHash()
|
|
||||||
if err != nil {
|
|
||||||
props.GeneralError = "Something went wrong. Error code: Momo"
|
|
||||||
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bcrypt.CompareHashAndPassword(passHash, []byte(password))
|
|
||||||
if err != nil {
|
|
||||||
props.GeneralError = "Username or password invalid"
|
|
||||||
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
|
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
|
||||||
|
_ = json.NewEncoder(w).Encode(props)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package routing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"lishwist/error"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NotFoundJson(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Add("Content-Type", "application/json; charset=utf-8")
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ func (ctx *Context) Register(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
session, _ := ctx.store.Get(r, "lishwist_user")
|
session, _ := ctx.store.Get(r, "lishwist_user")
|
||||||
if flashes := session.Flashes("register_props"); len(flashes) > 0 {
|
if flashes := session.Flashes("register_props"); len(flashes) > 0 {
|
||||||
|
log.Printf("Register found flashes: %#v\n", flashes)
|
||||||
flashProps, _ := flashes[0].(*api.RegisterProps)
|
flashProps, _ := flashes[0].(*api.RegisterProps)
|
||||||
props.Username.Value = flashProps.Username.Value
|
props.Username.Value = flashProps.Username.Value
|
||||||
|
|
||||||
|
|
@ -44,27 +45,9 @@ func (ctx *Context) RegisterPost(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if props != nil {
|
if props != nil {
|
||||||
ctx.RedirectWithFlash(w, r, "/register", "register_props", &props)
|
ctx.RedirectWithFlash(w, r, "/register", "register_props", &props)
|
||||||
|
_ = json.NewEncoder(w).Encode(props)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.RedirectWithFlash(w, r, "/", "successful_registration", true)
|
ctx.RedirectWithFlash(w, r, "/", "successful_registration", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonParams struct {
|
|
||||||
Username string
|
|
||||||
NewPassword string
|
|
||||||
ConfirmPassword string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *Context) RegisterPostJson(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var params jsonParams
|
|
||||||
err := decodeJsonParams(r, ¶ms)
|
|
||||||
if err != nil {
|
|
||||||
writeGeneralError(w, "Failed to decode json params: "+err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
props := api.Register(params.Username, params.NewPassword, params.ConfirmPassword)
|
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(props)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"lishwist/db"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ctx *Context) TodoUpdate(w http.ResponseWriter, r *http.Request) {
|
func (ctx *Context) TodoUpdate(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
user := ctx.ExpectUser(r)
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
|
@ -14,14 +14,14 @@ func (ctx *Context) TodoUpdate(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Form.Get("intent") {
|
switch r.Form.Get("intent") {
|
||||||
case "unclaim_todo":
|
case "unclaim_todo":
|
||||||
unclaims := r.Form["gift"]
|
unclaims := r.Form["gift"]
|
||||||
err := user.ClaimGifts([]string{}, unclaims)
|
err := currentUser.ClaimGifts([]string{}, unclaims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Failed to update claim...", http.StatusInternalServerError)
|
http.Error(w, "Failed to update claim...", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "complete_todo":
|
case "complete_todo":
|
||||||
claims := r.Form["gift"]
|
claims := r.Form["gift"]
|
||||||
err := user.CompleteGifts(claims)
|
err := currentUser.CompleteGifts(claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to complete gifts: %s\n", err)
|
log.Printf("Failed to complete gifts: %s\n", err)
|
||||||
http.Error(w, "Failed to complete gifts...", http.StatusInternalServerError)
|
http.Error(w, "Failed to complete gifts...", http.StatusInternalServerError)
|
||||||
|
|
@ -29,6 +29,7 @@ func (ctx *Context) TodoUpdate(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
http.Error(w, "Invalid intent", http.StatusBadRequest)
|
http.Error(w, "Invalid intent", http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package routing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"lishwist/db"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ctx *Context) UsersJson(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !currentUser.IsAdmin {
|
||||||
|
NotFoundJson(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
users, err := db.GetAllUsers()
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to get users: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = json.NewEncoder(w).Encode(users)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) User(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !currentUser.IsAdmin {
|
||||||
|
NotFoundJson(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reference := r.PathValue("userReference")
|
||||||
|
|
||||||
|
user, err := db.GetUserByReference(reference)
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to get user: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user == nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusNotFound, "User not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = json.NewEncoder(w).Encode(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) UserPost(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !currentUser.IsAdmin {
|
||||||
|
NotFoundJson(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to parse form: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reference := r.PathValue("userReference")
|
||||||
|
if reference == currentUser.Reference {
|
||||||
|
writeGeneralErrorJson(w, http.StatusForbidden, "You cannot delete yourself.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := db.GetAnyUserByReference(reference)
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to get user: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user == nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusNotFound, "User not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
intent := r.Form.Get("intent")
|
||||||
|
|
||||||
|
if intent != "" {
|
||||||
|
err = user.SetLive(intent != "delete")
|
||||||
|
if err != nil {
|
||||||
|
writeGeneralErrorJson(w, http.StatusInternalServerError, "Failed to delete user: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = json.NewEncoder(w).Encode(user)
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"lishwist/db"
|
||||||
"lishwist/error"
|
"lishwist/error"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ctx *Context) WishlistAdd(w http.ResponseWriter, r *http.Request) {
|
func (ctx *Context) WishlistAdd(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
user := ctx.ExpectUser(r)
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newGiftName := r.Form.Get("gift_name")
|
newGiftName := r.Form.Get("gift_name")
|
||||||
err := user.AddGift(newGiftName)
|
err := currentUser.AddGift(newGiftName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to add gift.", http.StatusInternalServerError, err)
|
error.Page(w, "Failed to add gift.", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
|
@ -20,14 +20,13 @@ func (ctx *Context) WishlistAdd(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) WishlistDelete(w http.ResponseWriter, r *http.Request) {
|
func (ctx *Context) WishlistDelete(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
user := ctx.ExpectUser(r)
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targets := r.Form["gift"]
|
targets := r.Form["gift"]
|
||||||
err := user.RemoveGifts(targets...)
|
err := currentUser.RemoveGifts(targets...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to remove gifts.", http.StatusInternalServerError, err)
|
error.Page(w, "Failed to remove gifts.", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
|
@ -35,8 +34,7 @@ func (ctx *Context) WishlistDelete(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) ForeignWishlistPost(w http.ResponseWriter, r *http.Request) {
|
func (ctx *Context) ForeignWishlistPost(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||||
user := ctx.ExpectUser(r)
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
error.Page(w, "Failed to parse form...", http.StatusBadRequest, err)
|
error.Page(w, "Failed to parse form...", http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
|
|
@ -46,14 +44,14 @@ func (ctx *Context) ForeignWishlistPost(w http.ResponseWriter, r *http.Request)
|
||||||
case "claim":
|
case "claim":
|
||||||
claims := r.Form["unclaimed"]
|
claims := r.Form["unclaimed"]
|
||||||
unclaims := r.Form["claimed"]
|
unclaims := r.Form["claimed"]
|
||||||
err := user.ClaimGifts(claims, unclaims)
|
err := currentUser.ClaimGifts(claims, unclaims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to update claim...", http.StatusInternalServerError, err)
|
error.Page(w, "Failed to update claim...", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "complete":
|
case "complete":
|
||||||
claims := r.Form["claimed"]
|
claims := r.Form["claimed"]
|
||||||
err := user.CompleteGifts(claims)
|
err := currentUser.CompleteGifts(claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error.Page(w, "Failed to complete gifts...", http.StatusInternalServerError, nil)
|
error.Page(w, "Failed to complete gifts...", http.StatusInternalServerError, nil)
|
||||||
return
|
return
|
||||||
|
|
@ -64,7 +62,7 @@ func (ctx *Context) ForeignWishlistPost(w http.ResponseWriter, r *http.Request)
|
||||||
error.Page(w, "Gift name not provided", http.StatusBadRequest, nil)
|
error.Page(w, "Gift name not provided", http.StatusBadRequest, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := user.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)
|
error.Page(w, "Failed to add gift idea to other user...", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
|
@ -73,7 +71,7 @@ func (ctx *Context) ForeignWishlistPost(w http.ResponseWriter, r *http.Request)
|
||||||
claims := r.Form["unclaimed"]
|
claims := r.Form["unclaimed"]
|
||||||
unclaims := r.Form["claimed"]
|
unclaims := r.Form["claimed"]
|
||||||
gifts := append(claims, unclaims...)
|
gifts := append(claims, unclaims...)
|
||||||
err := user.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)
|
error.Page(w, "Failed to remove gift idea for other user...", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@
|
||||||
<div class="container py-5">
|
<div class="container py-5">
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2><em>{{.Name}}</em> group members</h2>
|
<h2><em>{{.Group.Name}}</em> group members</h2>
|
||||||
{{with .Members}}
|
{{with .Group.Members}}
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{{range .}}
|
{{range .}}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
<button id="unclaimSubmit" class="btn btn-warning" type="submit" name="intent" value="unclaim_todo"
|
<button id="unclaimSubmit" class="btn btn-warning" type="submit" name="intent" value="unclaim_todo"
|
||||||
disabled>Unclaim</button>
|
disabled>Unclaim</button>
|
||||||
<button id="completeSubmit" class="btn btn-success" type="submit" name="mode" value="complete_todo"
|
<button id="completeSubmit" class="btn btn-success" type="submit" name="intent" value="complete_todo"
|
||||||
disabled>Complete</button>
|
disabled>Complete</button>
|
||||||
</form>
|
</form>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@
|
||||||
<div class="container py-5">
|
<div class="container py-5">
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2><em>{{.Name}}</em> group members</h2>
|
<h2><em>{{.Group.Name}}</em> group members</h2>
|
||||||
<p>{{template "login_prompt"}} to see your groups</p>
|
<p>{{template "login_prompt"}} to see your groups</p>
|
||||||
{{with .Members}}
|
{{with .Group.Members}}
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{{range .}}
|
{{range .}}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue