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) {
|
||||
valid = true
|
||||
|
||||
if p.Password.Value != p.ConfirmPassword.Value {
|
||||
p.ConfirmPassword.Error = "Passwords didn't match"
|
||||
valid = false
|
||||
|
|
@ -69,24 +71,27 @@ func Register(username, newPassword, confirmPassword string) *RegisterProps {
|
|||
props.Password.Value = ""
|
||||
props.ConfirmPassword.Value = ""
|
||||
if !valid {
|
||||
log.Printf("Invalid props: %#v\n", props)
|
||||
return props
|
||||
}
|
||||
|
||||
existingUser, _ := db.GetUserByName(username)
|
||||
if existingUser != nil {
|
||||
log.Printf("Username is taken: %q\n", username)
|
||||
props.Username.Error = "Username is taken"
|
||||
return props
|
||||
}
|
||||
|
||||
hashedPasswordBytes, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.MinCost)
|
||||
if err != nil {
|
||||
log.Printf("Failed to hash password: %s\n", err)
|
||||
props.GeneralError = "Something went wrong. Error code: Aang"
|
||||
return props
|
||||
}
|
||||
|
||||
_, err = db.CreateUser(username, hashedPasswordBytes)
|
||||
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"
|
||||
return props
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,61 +1,121 @@
|
|||
package db
|
||||
|
||||
import "database/sql"
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Group struct {
|
||||
Id string
|
||||
Name 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) {
|
||||
var id string
|
||||
var name string
|
||||
var reference string
|
||||
err := database.QueryRow(query, args...).Scan(&id, &name, &reference)
|
||||
var group Group
|
||||
err := database.QueryRow(query, args...).Scan(&group.Id, &group.Name, &group.Reference)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
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{
|
||||
Id: id,
|
||||
Id: strconv.FormatInt(id, 10),
|
||||
Name: name,
|
||||
Reference: reference,
|
||||
}
|
||||
return &group, nil
|
||||
}
|
||||
|
||||
func GetGroupByReference(reference string) (*Group, error) {
|
||||
stmt := "SELECT [group].id, [group].name, [group].reference FROM [group] WHERE [group].reference = ?"
|
||||
return queryForGroup(stmt, reference)
|
||||
func (g *Group) AddUser(userId string) error {
|
||||
stmt := "INSERT INTO group_member (group_id, user_id) VALUES (?, ?)"
|
||||
_, err := database.Exec(stmt, g.Id, userId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Group) GetMembers() ([]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 = ?"
|
||||
rows, err := database.Query(stmt, g.Id)
|
||||
users := []User{}
|
||||
func (g *Group) RemoveUser(userId string) error {
|
||||
stmt := "DELETE FROM group_member WHERE group_id = ? AND user_id = ?"
|
||||
_, err := database.Exec(stmt, g.Id, userId)
|
||||
if err != nil {
|
||||
return users, err
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
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
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ CREATE TABLE IF NOT EXISTS "user" (
|
|||
"id" INTEGER NOT NULL UNIQUE,
|
||||
"name" TEXT NOT NULL UNIQUE,
|
||||
"reference" TEXT NOT NULL UNIQUE,
|
||||
"motto" TEXT NOT NULL,
|
||||
"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)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "gift" (
|
||||
|
|
@ -37,4 +39,15 @@ CREATE TABLE IF NOT EXISTS "session" (
|
|||
"value" TEXT NOT NULL,
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Name string
|
||||
Reference string
|
||||
IsAdmin bool
|
||||
IsLive bool
|
||||
}
|
||||
|
||||
type Gift struct {
|
||||
|
|
@ -27,35 +29,75 @@ type Gift struct {
|
|||
}
|
||||
|
||||
func queryForUser(query string, args ...any) (*User, error) {
|
||||
var id string
|
||||
var name string
|
||||
var reference string
|
||||
err := database.QueryRow(query, args...).Scan(&id, &name, &reference)
|
||||
var u User
|
||||
err := database.QueryRow(query, args...).Scan(&u.Id, &u.Name, &u.Reference, &u.IsAdmin, &u.IsLive)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user := User{
|
||||
Id: id,
|
||||
Name: name,
|
||||
Reference: reference,
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
stmt := "INSERT INTO user (name, motto, reference, password_hash) VALUES (?, '', ?, ?)"
|
||||
stmt := "INSERT INTO user (name, reference, password_hash) VALUES (?, ?, ?)"
|
||||
reference, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -76,7 +118,7 @@ func CreateUser(username string, passHash []byte) (*User, 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
|
||||
err := database.QueryRow(stmt, u.Id).Scan(&passHash)
|
||||
if err != nil {
|
||||
|
|
@ -86,7 +128,7 @@ func (u *User) GetPassHash() ([]byte, 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
|
||||
err := database.QueryRow(stmt, u.Id).Scan(&giftCount)
|
||||
if err != nil {
|
||||
|
|
@ -96,7 +138,7 @@ func (u *User) CountGifts() (int, 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -106,19 +148,15 @@ func (u *User) GetGifts() ([]Gift, error) {
|
|||
for rows.Next() {
|
||||
var id string
|
||||
var name string
|
||||
var claimantId sql.NullString
|
||||
var claimantName sql.NullString
|
||||
var sent bool
|
||||
err = rows.Scan(&id, &name, &claimantId, &claimantName, &sent)
|
||||
err = rows.Scan(&id, &name, &sent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gift := Gift{
|
||||
Id: id,
|
||||
Name: name,
|
||||
ClaimantId: claimantId.String,
|
||||
ClaimantName: claimantName.String,
|
||||
Sent: sent,
|
||||
Id: id,
|
||||
Name: name,
|
||||
Sent: sent,
|
||||
}
|
||||
gifts = append(gifts, gift)
|
||||
}
|
||||
|
|
@ -132,15 +170,15 @@ func (u *User) GetGifts() ([]Gift, error) {
|
|||
func (u *User) GetOtherUserGifts(otherUserReference string) ([]Gift, error) {
|
||||
otherUser, err := GetUserByReference(otherUserReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Failed to get other user: %w", err)
|
||||
}
|
||||
if otherUser.Id == u.Id {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Failed to execute query: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
gifts := []Gift{}
|
||||
|
|
@ -155,7 +193,7 @@ func (u *User) GetOtherUserGifts(otherUserReference string) ([]Gift, error) {
|
|||
var recipientId string
|
||||
err = rows.Scan(&id, &name, &claimantId, &claimantName, &sent, &creatorId, &creatorName, &recipientId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Failed to scan row: %w", err)
|
||||
}
|
||||
gift := Gift{
|
||||
Id: id,
|
||||
|
|
@ -171,13 +209,13 @@ func (u *User) GetOtherUserGifts(otherUserReference string) ([]Gift, error) {
|
|||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Rows returned an error: %w", err)
|
||||
}
|
||||
return gifts, nil
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -367,7 +405,7 @@ func (u *User) AddGiftToUser(otherUserReference string, giftName string) 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -395,35 +433,6 @@ func (u *User) GetGroups() ([]Group, error) {
|
|||
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) {
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ type pageProps struct {
|
|||
}
|
||||
|
||||
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})
|
||||
http.Error(w, "", http.StatusInternalServerError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
func main() {
|
||||
gob.Register(&api.RegisterProps{})
|
||||
gob.Register(&routing.LoginProps{})
|
||||
gob.Register(&api.LoginProps{})
|
||||
|
||||
err := db.Open()
|
||||
if err != nil {
|
||||
|
|
@ -27,7 +27,7 @@ func main() {
|
|||
|
||||
store, err := db.NewSessionStore()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to ")
|
||||
log.Fatalf("Failed to initialize session store: %s\n", err)
|
||||
}
|
||||
store.Options.MaxAge = 86_400
|
||||
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 /group/{groupReference}", route.PublicGroupPage)
|
||||
|
||||
r.Html.Private.HandleFunc("GET /{$}", route.Home)
|
||||
r.Html.Private.HandleFunc("POST /{$}", route.HomePost)
|
||||
r.Html.Private.HandleFunc("GET /list/{userReference}", route.ForeignWishlist)
|
||||
r.Html.Private.HandleFunc("POST /list/{userReference}", route.ForeignWishlistPost)
|
||||
r.Html.Private.HandleFunc("GET /group/{groupReference}", route.GroupPage)
|
||||
r.Html.Private.Handle("GET /{$}", route.ExpectUser(route.Home))
|
||||
r.Html.Private.Handle("POST /{$}", route.ExpectUser(route.HomePost))
|
||||
r.Html.Private.Handle("GET /list/{userReference}", route.ExpectUser(route.ForeignWishlist))
|
||||
r.Html.Private.Handle("POST /list/{userReference}", route.ExpectUser(route.ForeignWishlistPost))
|
||||
r.Html.Private.Handle("GET /group/{groupReference}", route.ExpectUser(route.GroupPage))
|
||||
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package router
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Teajey/sqlstore"
|
||||
)
|
||||
|
|
@ -29,10 +30,10 @@ type Router struct {
|
|||
}
|
||||
|
||||
func (s *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
accept := r.Header.Get("Accept")
|
||||
|
||||
switch contentType {
|
||||
case "application/json":
|
||||
switch {
|
||||
case strings.HasPrefix(accept, "application/json"):
|
||||
s.Json.ServeHTTP(w, r)
|
||||
default:
|
||||
s.Html.ServeHTTP(w, r)
|
||||
|
|
|
|||
|
|
@ -18,16 +18,23 @@ func NewContext(store *sqlstore.Store) *Context {
|
|||
}
|
||||
}
|
||||
|
||||
func (auth *Context) ExpectUser(r *http.Request) *db.User {
|
||||
session, _ := auth.store.Get(r, "lishwist_user")
|
||||
username, ok := session.Values["username"].(string)
|
||||
if !ok {
|
||||
log.Fatalln("Failed to get username")
|
||||
}
|
||||
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 {
|
||||
log.Println("Failed to get username")
|
||||
http.Error(w, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := db.GetUserByName(username)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to get user: %s\n", err)
|
||||
}
|
||||
return user
|
||||
user, err := db.GetUserByName(username)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get user: %s\n", err)
|
||||
http.Error(w, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
next(user, w, r)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@ package routing
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"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)
|
||||
escapedMsg := strings.ReplaceAll(msg, `"`, `\"`)
|
||||
_, _ = 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
|
||||
}
|
||||
|
||||
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")
|
||||
user := ctx.ExpectUser(r)
|
||||
if user.Reference == userReference {
|
||||
if currentUser.Reference == userReference {
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
|
@ -30,12 +29,12 @@ func (ctx *Context) ForeignWishlist(w http.ResponseWriter, r *http.Request) {
|
|||
error.Page(w, "User not found", http.StatusNotFound, err)
|
||||
return
|
||||
}
|
||||
gifts, err := user.GetOtherUserGifts(userReference)
|
||||
gifts, err := currentUser.GetOtherUserGifts(userReference)
|
||||
if err != nil {
|
||||
error.Page(w, "An error occurred while fetching this user's wishlist :(", http.StatusInternalServerError, err)
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package routing
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"slices"
|
||||
|
||||
"lishwist/db"
|
||||
"lishwist/error"
|
||||
|
|
@ -9,15 +11,13 @@ import (
|
|||
)
|
||||
|
||||
type GroupProps struct {
|
||||
Name string
|
||||
Members []db.User
|
||||
Group *db.Group
|
||||
CurrentUsername string
|
||||
}
|
||||
|
||||
func (ctx *Context) GroupPage(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctx.ExpectUser(r)
|
||||
func (ctx *Context) GroupPage(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||
groupReference := r.PathValue("groupReference")
|
||||
group, err := user.GetGroupByReference(groupReference)
|
||||
group, err := currentUser.GetGroupByReference(groupReference)
|
||||
if err != nil {
|
||||
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
||||
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)
|
||||
return
|
||||
}
|
||||
peers, err := user.GetPeers(group.Id)
|
||||
if err != nil {
|
||||
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
index := group.MemberIndex(currentUser.Id)
|
||||
group.Members = slices.Delete(group.Members, index, index+1)
|
||||
p := GroupProps{
|
||||
Name: group.Name,
|
||||
Members: peers,
|
||||
CurrentUsername: user.Name,
|
||||
Group: group,
|
||||
CurrentUsername: currentUser.Name,
|
||||
}
|
||||
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)
|
||||
return
|
||||
}
|
||||
members, err := group.GetMembers()
|
||||
if err != nil {
|
||||
error.Page(w, "An error occurred while fetching this group :(", http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
p := GroupProps{
|
||||
Name: group.Name,
|
||||
Members: members,
|
||||
Group: group,
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (ctx *Context) Home(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctx.ExpectUser(r)
|
||||
gifts, err := user.GetGifts()
|
||||
func (ctx *Context) Home(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||
gifts, err := currentUser.GetGifts()
|
||||
if err != nil {
|
||||
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
todo, err := user.GetTodo()
|
||||
todo, err := currentUser.GetTodo()
|
||||
if err != nil {
|
||||
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
groups, err := user.GetGroups()
|
||||
groups, err := currentUser.GetGroups()
|
||||
if err != nil {
|
||||
error.Page(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError, err)
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
http.Error(w, "Couldn't parse form", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
switch r.Form.Get("intent") {
|
||||
case "add_idea":
|
||||
ctx.WishlistAdd(w, r)
|
||||
ctx.WishlistAdd(currentUser, w, r)
|
||||
return
|
||||
case "delete_idea":
|
||||
ctx.WishlistDelete(w, r)
|
||||
ctx.WishlistDelete(currentUser, w, r)
|
||||
return
|
||||
default:
|
||||
ctx.TodoUpdate(w, r)
|
||||
ctx.TodoUpdate(currentUser, w, r)
|
||||
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
|
||||
|
||||
import (
|
||||
"lishwist/db"
|
||||
"encoding/json"
|
||||
"lishwist/api"
|
||||
sesh "lishwist/session"
|
||||
"lishwist/templates"
|
||||
"log"
|
||||
"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) {
|
||||
session, _ := ctx.store.Get(r, "lishwist_user")
|
||||
|
||||
props := NewLoginProps()
|
||||
props := api.NewLoginProps("", "")
|
||||
|
||||
flash, err := sesh.GetFirstFlash(w, r, session, "login_props")
|
||||
if err != nil {
|
||||
|
|
@ -43,7 +20,7 @@ func (ctx *Context) Login(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
flashProps, ok := flash.(*LoginProps)
|
||||
flashProps, ok := flash.(*api.LoginProps)
|
||||
if ok {
|
||||
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")
|
||||
password := r.Form.Get("password")
|
||||
|
||||
props := NewLoginProps()
|
||||
props.Username.Value = username
|
||||
|
||||
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"
|
||||
props := api.Login(username, password)
|
||||
if props != nil {
|
||||
ctx.RedirectWithFlash(w, r, "/", "login_props", &props)
|
||||
_ = json.NewEncoder(w).Encode(props)
|
||||
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")
|
||||
if flashes := session.Flashes("register_props"); len(flashes) > 0 {
|
||||
log.Printf("Register found flashes: %#v\n", flashes)
|
||||
flashProps, _ := flashes[0].(*api.RegisterProps)
|
||||
props.Username.Value = flashProps.Username.Value
|
||||
|
||||
|
|
@ -44,27 +45,9 @@ func (ctx *Context) RegisterPost(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if props != nil {
|
||||
ctx.RedirectWithFlash(w, r, "/register", "register_props", &props)
|
||||
_ = json.NewEncoder(w).Encode(props)
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"lishwist/db"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (ctx *Context) TodoUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctx.ExpectUser(r)
|
||||
func (ctx *Context) TodoUpdate(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -14,14 +14,14 @@ func (ctx *Context) TodoUpdate(w http.ResponseWriter, r *http.Request) {
|
|||
switch r.Form.Get("intent") {
|
||||
case "unclaim_todo":
|
||||
unclaims := r.Form["gift"]
|
||||
err := user.ClaimGifts([]string{}, unclaims)
|
||||
err := currentUser.ClaimGifts([]string{}, unclaims)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to update claim...", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
case "complete_todo":
|
||||
claims := r.Form["gift"]
|
||||
err := user.CompleteGifts(claims)
|
||||
err := currentUser.CompleteGifts(claims)
|
||||
if err != nil {
|
||||
log.Printf("Failed to complete gifts: %s\n", err)
|
||||
http.Error(w, "Failed to complete gifts...", http.StatusInternalServerError)
|
||||
|
|
@ -29,6 +29,7 @@ func (ctx *Context) TodoUpdate(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
default:
|
||||
http.Error(w, "Invalid intent", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
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
|
||||
|
||||
import (
|
||||
"lishwist/db"
|
||||
"lishwist/error"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (ctx *Context) WishlistAdd(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctx.ExpectUser(r)
|
||||
func (ctx *Context) WishlistAdd(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
newGiftName := r.Form.Get("gift_name")
|
||||
err := user.AddGift(newGiftName)
|
||||
err := currentUser.AddGift(newGiftName)
|
||||
if err != nil {
|
||||
error.Page(w, "Failed to add gift.", http.StatusInternalServerError, err)
|
||||
return
|
||||
|
|
@ -20,14 +20,13 @@ func (ctx *Context) WishlistAdd(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (ctx *Context) WishlistDelete(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctx.ExpectUser(r)
|
||||
func (ctx *Context) WishlistDelete(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
targets := r.Form["gift"]
|
||||
err := user.RemoveGifts(targets...)
|
||||
err := currentUser.RemoveGifts(targets...)
|
||||
if err != nil {
|
||||
error.Page(w, "Failed to remove gifts.", http.StatusInternalServerError, err)
|
||||
return
|
||||
|
|
@ -35,8 +34,7 @@ func (ctx *Context) WishlistDelete(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (ctx *Context) ForeignWishlistPost(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctx.ExpectUser(r)
|
||||
func (ctx *Context) ForeignWishlistPost(currentUser *db.User, w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
error.Page(w, "Failed to parse form...", http.StatusBadRequest, err)
|
||||
return
|
||||
|
|
@ -46,14 +44,14 @@ func (ctx *Context) ForeignWishlistPost(w http.ResponseWriter, r *http.Request)
|
|||
case "claim":
|
||||
claims := r.Form["unclaimed"]
|
||||
unclaims := r.Form["claimed"]
|
||||
err := user.ClaimGifts(claims, unclaims)
|
||||
err := currentUser.ClaimGifts(claims, unclaims)
|
||||
if err != nil {
|
||||
error.Page(w, "Failed to update claim...", http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
case "complete":
|
||||
claims := r.Form["claimed"]
|
||||
err := user.CompleteGifts(claims)
|
||||
err := currentUser.CompleteGifts(claims)
|
||||
if err != nil {
|
||||
error.Page(w, "Failed to complete gifts...", http.StatusInternalServerError, nil)
|
||||
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)
|
||||
return
|
||||
}
|
||||
err := user.AddGiftToUser(userReference, giftName)
|
||||
err := currentUser.AddGiftToUser(userReference, giftName)
|
||||
if err != nil {
|
||||
error.Page(w, "Failed to add gift idea to other user...", http.StatusInternalServerError, err)
|
||||
return
|
||||
|
|
@ -73,7 +71,7 @@ func (ctx *Context) ForeignWishlistPost(w http.ResponseWriter, r *http.Request)
|
|||
claims := r.Form["unclaimed"]
|
||||
unclaims := r.Form["claimed"]
|
||||
gifts := append(claims, unclaims...)
|
||||
err := user.RemoveGifts(gifts...)
|
||||
err := currentUser.RemoveGifts(gifts...)
|
||||
if err != nil {
|
||||
error.Page(w, "Failed to remove gift idea for other user...", http.StatusInternalServerError, err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@
|
|||
<div class="container py-5">
|
||||
<section class="card">
|
||||
<div class="card-body">
|
||||
<h2><em>{{.Name}}</em> group members</h2>
|
||||
{{with .Members}}
|
||||
<h2><em>{{.Group.Name}}</em> group members</h2>
|
||||
{{with .Group.Members}}
|
||||
<ul class="list-group">
|
||||
{{range .}}
|
||||
<li class="list-group-item">
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
</ul>
|
||||
<button id="unclaimSubmit" class="btn btn-warning" type="submit" name="intent" value="unclaim_todo"
|
||||
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>
|
||||
</form>
|
||||
{{else}}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
<div class="container py-5">
|
||||
<section class="card">
|
||||
<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>
|
||||
{{with .Members}}
|
||||
{{with .Group.Members}}
|
||||
<ul class="list-group">
|
||||
{{range .}}
|
||||
<li class="list-group-item">
|
||||
|
|
@ -34,4 +34,4 @@
|
|||
</section>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
|||
Loading…
Reference in New Issue