246 lines
6.3 KiB
Go
246 lines
6.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
"wishlify/auth"
|
|
"wishlify/model"
|
|
"wishlify/router"
|
|
|
|
"github.com/google/uuid"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func main() {
|
|
dbPath := os.Getenv("DB_PATH")
|
|
if dbPath == "" {
|
|
dbPath = "./sqlite.db"
|
|
}
|
|
|
|
db, err := gorm.Open(sqlite.Open("./sqlite.db"))
|
|
if err != nil {
|
|
log.Fatalf("failed to connect to db: %v\n", err)
|
|
}
|
|
|
|
if err := db.AutoMigrate(&model.User{}, &model.Wishlist{}); err != nil {
|
|
log.Fatalf("failed to migrate db: %v\n", err)
|
|
}
|
|
|
|
router := router.New()
|
|
|
|
router.Handle("OPTIONS /", func(w http.ResponseWriter, r *http.Request) error {
|
|
w.WriteHeader(200)
|
|
fmt.Fprintf(w, "ok")
|
|
return nil
|
|
})
|
|
|
|
router.Handle("POST /auth/register", func(w http.ResponseWriter, r *http.Request) error {
|
|
var body struct {
|
|
Email string `json:"email"`
|
|
Login string `json:"login"`
|
|
Password string `json:"password"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
|
w.WriteHeader(500)
|
|
return fmt.Errorf("failed to decode request body: %v", err)
|
|
}
|
|
|
|
if body.Email == "" || body.Login == "" || body.Password == "" {
|
|
w.WriteHeader(400)
|
|
return fmt.Errorf("invalid request; email, login and password are required")
|
|
}
|
|
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(body.Password), 10)
|
|
if err != nil {
|
|
w.WriteHeader(500)
|
|
return fmt.Errorf("failed to generate password hash: %v", err)
|
|
}
|
|
|
|
user := &model.User{
|
|
Email: body.Email,
|
|
Login: body.Login,
|
|
Password: string(hash),
|
|
}
|
|
if tx := db.Create(user); tx.Error != nil {
|
|
w.WriteHeader(400)
|
|
return fmt.Errorf("failed to create user: %v", tx.Error)
|
|
}
|
|
|
|
expiryTime := time.Now().Add(time.Hour * 24 * 7)
|
|
token, err := auth.GenerateUserToken(user.ID, expiryTime)
|
|
if err != nil {
|
|
w.WriteHeader(500)
|
|
return fmt.Errorf("failed to generate jwt: %v", err)
|
|
}
|
|
|
|
auth.SetUserCookie(w, token, expiryTime)
|
|
|
|
w.WriteHeader(201)
|
|
return router.SendJSON(w, user)
|
|
})
|
|
|
|
router.Handle("POST /auth/login", func(w http.ResponseWriter, r *http.Request) error {
|
|
var body struct {
|
|
Login string `json:"login"`
|
|
Password string `json:"password"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
|
w.WriteHeader(400)
|
|
return fmt.Errorf("failed to decode request body: %v", err)
|
|
}
|
|
|
|
if body.Login == "" || body.Password == "" {
|
|
w.WriteHeader(400)
|
|
return fmt.Errorf("invalid request; login and password are required")
|
|
}
|
|
|
|
user := &model.User{}
|
|
if tx := db.First(user, "login = ?", body.Login); tx.Error != nil {
|
|
w.WriteHeader(404)
|
|
return fmt.Errorf("user not found: %v", tx.Error)
|
|
}
|
|
|
|
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(body.Password)); err != nil {
|
|
w.WriteHeader(400)
|
|
return fmt.Errorf("invalid password: %v", err)
|
|
}
|
|
|
|
expiryTime := time.Now().Add(time.Hour * 24 * 7)
|
|
token, err := auth.GenerateUserToken(user.ID, expiryTime)
|
|
if err != nil {
|
|
w.WriteHeader(500)
|
|
return fmt.Errorf("failed to generate jwt: %v", err)
|
|
}
|
|
|
|
auth.SetUserCookie(w, token, expiryTime)
|
|
|
|
w.WriteHeader(200)
|
|
return router.SendJSON(w, user)
|
|
})
|
|
|
|
router.Handle("POST /auth/logout", func(w http.ResponseWriter, r *http.Request) error {
|
|
auth.RemoveUserCookie(w)
|
|
w.WriteHeader(200)
|
|
return router.SendJSON(w, struct {
|
|
Ok bool `json:"ok"`
|
|
}{true})
|
|
})
|
|
|
|
router.Handle("GET /user", func(w http.ResponseWriter, r *http.Request) error {
|
|
userId, err := auth.GetUserIdFromRequest(r)
|
|
if err != nil {
|
|
w.WriteHeader(401)
|
|
return fmt.Errorf("unauthorized: %v", err)
|
|
}
|
|
|
|
user := &model.User{}
|
|
if tx := db.First(user, "id = ?", userId); tx.Error != nil {
|
|
w.WriteHeader(404)
|
|
return fmt.Errorf("user not found: %v", tx.Error)
|
|
}
|
|
|
|
return router.SendJSON(w, user)
|
|
})
|
|
|
|
router.Handle("GET /user/wishlists", func(w http.ResponseWriter, r *http.Request) error {
|
|
userId, err := auth.GetUserIdFromRequest(r)
|
|
if err != nil {
|
|
w.WriteHeader(401)
|
|
return fmt.Errorf("unauthorized: %v", err)
|
|
}
|
|
|
|
wishlists := []model.Wishlist{}
|
|
if tx := db.Find(&wishlists, "user_id = ?", userId); tx.Error != nil {
|
|
w.WriteHeader(404)
|
|
return fmt.Errorf("no wishlists found: %v", err)
|
|
}
|
|
|
|
w.WriteHeader(200)
|
|
return router.SendJSON(w, wishlists)
|
|
})
|
|
|
|
router.Handle("POST /user/wishlists", func(w http.ResponseWriter, r *http.Request) error {
|
|
userId, err := auth.GetUserIdFromRequest(r)
|
|
if err != nil {
|
|
w.WriteHeader(401)
|
|
return fmt.Errorf("unauthorized: %v", err)
|
|
}
|
|
|
|
var body struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
|
w.WriteHeader(400)
|
|
return fmt.Errorf("failed to decode request body: %v", err)
|
|
}
|
|
|
|
if body.Name == "" {
|
|
w.WriteHeader(400)
|
|
return fmt.Errorf("invalid request; name is required")
|
|
}
|
|
|
|
uid, err := uuid.NewV7()
|
|
if err != nil {
|
|
w.WriteHeader(500)
|
|
return fmt.Errorf("failed to generate uuid for new wishlist: %v", err)
|
|
}
|
|
|
|
wishlist := &model.Wishlist{
|
|
UUID: uid.String(),
|
|
Name: body.Name,
|
|
Description: body.Description,
|
|
UserID: userId,
|
|
}
|
|
if tx := db.Create(wishlist); tx.Error != nil {
|
|
w.WriteHeader(500)
|
|
return fmt.Errorf("failed to create wishlist: %v", tx.Error)
|
|
}
|
|
|
|
return router.SendJSON(w, wishlist)
|
|
})
|
|
|
|
router.Handle("GET /wishlists/{uid}", func(w http.ResponseWriter, r *http.Request) error {
|
|
uid := r.PathValue("uid")
|
|
|
|
wishlist := &model.Wishlist{}
|
|
if tx := db.First(wishlist, "uuid = ?", uid); tx.Error != nil {
|
|
w.WriteHeader(404)
|
|
return fmt.Errorf("wishlist not found: %v", tx.Error)
|
|
}
|
|
|
|
w.WriteHeader(200)
|
|
return router.SendJSON(w, wishlist)
|
|
})
|
|
|
|
router.Handle("DELETE /user/wishlists/{uid}", func(w http.ResponseWriter, r *http.Request) error {
|
|
userId, err := auth.GetUserIdFromRequest(r)
|
|
if err != nil {
|
|
w.WriteHeader(401)
|
|
return fmt.Errorf("unauthorized: %v", err)
|
|
}
|
|
|
|
uid := r.PathValue("uid")
|
|
|
|
if tx := db.Delete(&model.Wishlist{}, "uuid = ? AND user_id = ?", uid, userId); tx.Error != nil {
|
|
w.WriteHeader(404)
|
|
return fmt.Errorf("failed to delete wishlist: %v", tx.Error)
|
|
}
|
|
|
|
return router.SendJSON(w, struct {
|
|
Ok bool `json:"ok"`
|
|
}{true})
|
|
})
|
|
|
|
log.Println("starting http server")
|
|
if err := http.ListenAndServe(":5000", router.Mux()); err != nil {
|
|
log.Fatalf("failed to start http server: %v\n", err)
|
|
}
|
|
}
|