diff --git a/internal/config/config.go b/internal/config/config.go
index 0113ef7..2ecd3af 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -11,7 +11,6 @@ type ServerConfigs struct {
ServerAddress string
DataBaseURL string
- JwtSecret string
}
func GetServerConfigs() ServerConfigs {
@@ -24,11 +23,6 @@ func GetServerConfigs() ServerConfigs {
panic("Missing DATABASE_URL")
}
- config.JwtSecret = os.Getenv("JWT_SECRET")
- if config.JwtSecret == "" {
- panic("Missing JWT_SECRET")
- }
-
// optional - with defaults
envAutoMigrate := os.Getenv("AUTO_MIGRATE")
diff --git a/internal/controllers/controllers.go b/internal/controllers/controllers.go
deleted file mode 100644
index 152828d..0000000
--- a/internal/controllers/controllers.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package controllers
-
-type Controllers interface {
- UserController | TaskController
-}
diff --git a/internal/controllers/tasks.go b/internal/controllers/tasks.go
index edfebc9..7e86286 100644
--- a/internal/controllers/tasks.go
+++ b/internal/controllers/tasks.go
@@ -18,21 +18,20 @@ func NewTaskController(dbRepo database.Database) *TaskController {
}
}
-func (tc *TaskController) CreateTask(ownerId string) (models.Task, error) {
+func (tc *TaskController) CreateTask() (models.Task, error) {
task := models.Task{
Id: models.GenerateId(),
Title: "New Task",
Description: "New Task Description",
- OwnerId: ownerId,
}
return task, tc.DbRepo.CreateTask(task)
}
-func (tc *TaskController) ListTasks(ownerId string) ([]models.Task, error) {
- return tc.DbRepo.ListTasksByOwner(ownerId)
+func (tc *TaskController) ListTasks() ([]models.Task, error) {
+ return tc.DbRepo.ListTasks()
}
-func (tc *TaskController) RetrieveTask(ownerId, taskId string) (models.Task, error) {
+func (tc *TaskController) RetrieveTask(taskId string) (models.Task, error) {
task, err := tc.DbRepo.RetrieveTaskById(taskId)
if err != nil {
if err == sql.ErrNoRows {
@@ -42,15 +41,11 @@ func (tc *TaskController) RetrieveTask(ownerId, taskId string) (models.Task, err
return models.EmptyTask, err
}
- if task.OwnerId != ownerId {
- return models.EmptyTask, fiber.ErrNotFound
- }
-
return task, nil
}
-func (tc *TaskController) DeleteTask(ownerId, taskId string) error {
- _, err := tc.RetrieveTask(ownerId, taskId)
+func (tc *TaskController) DeleteTask(taskId string) error {
+ _, err := tc.RetrieveTask(taskId)
if err != nil {
return err
}
@@ -63,8 +58,8 @@ type TaskChange struct {
Description string `json:"description"`
}
-func (tc *TaskController) UpdateTask(ownerId, taskId string, changes TaskChange) error {
- task, err := tc.RetrieveTask(ownerId, taskId)
+func (tc *TaskController) UpdateTask(taskId string, changes TaskChange) error {
+ task, err := tc.RetrieveTask(taskId)
if err != nil {
return err
}
diff --git a/internal/controllers/users.go b/internal/controllers/users.go
deleted file mode 100644
index 22a12e0..0000000
--- a/internal/controllers/users.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package controllers
-
-import (
- "errors"
- "goth/internal/models"
- "goth/internal/repositories/database"
- "goth/internal/repositories/jwt"
- "goth/internal/utils"
- "time"
-
- "github.com/gofiber/fiber/v2"
-)
-
-type UserController struct {
- dbRepo database.Database
- jwtRepo jwt.JWT
-}
-
-func NewUserController(dbRepo database.Database, jwtRepo jwt.JWT) *UserController {
- return &UserController{dbRepo, jwtRepo}
-}
-
-func (uc *UserController) VerifyJWTCookie(token string) (models.User, error) {
- id, err := uc.jwtRepo.ParseJWT(token)
- if err != nil {
- return models.EmptyUser, err
- }
-
- return uc.dbRepo.RetrieveUserById(id)
-}
-
-type UserRequest struct {
- Username string `json:"username"`
- Password string `json:"password"`
-}
-
-func (uc *UserController) Login(req UserRequest, cookieName string) (*fiber.Cookie, error) {
- user, err := uc.dbRepo.RetrieveUserByName(req.Username)
- if err != nil {
- return nil, err
- }
-
- // slow checking -> design feature of bcrypt
- if !utils.CheckPasswordHash(req.Password, user.PswdHash) {
- return nil, errors.New("bad username or password")
- }
-
- expiration := time.Now().Add(7 * 24 * time.Hour)
- jwt, err := uc.jwtRepo.GenerateJWT(user.ID, expiration)
- if err != nil {
- return nil, err
- }
-
- return &fiber.Cookie{
- Expires: expiration,
- Name: cookieName,
- Value: jwt,
- }, nil
-}
-
-func (uc *UserController) Register(req UserRequest, cookieName string) (*fiber.Cookie, error) {
- hashedPassword, err := utils.HashPassword(req.Password)
- if err != nil {
- return nil, err
- }
-
- user := models.User{
- ID: models.GenerateId(),
- Username: req.Username,
- PswdHash: hashedPassword,
- }
-
- err = uc.dbRepo.InsertUser(user)
- if err != nil {
- return nil, err
- }
-
- expiration := time.Now().Add(7 * 24 * time.Hour)
- jwt, err := uc.jwtRepo.GenerateJWT(user.ID, expiration)
- if err != nil {
- return nil, err
- }
-
- return &fiber.Cookie{
- Expires: expiration,
- Name: cookieName,
- Value: jwt,
- }, nil
-}
diff --git a/internal/embeded/migrations/01_initial.down.sql b/internal/embeded/migrations/01_initial.down.sql
deleted file mode 100644
index cc1f647..0000000
--- a/internal/embeded/migrations/01_initial.down.sql
+++ /dev/null
@@ -1 +0,0 @@
-DROP TABLE users;
diff --git a/internal/embeded/migrations/01_initial.up.sql b/internal/embeded/migrations/01_initial.up.sql
deleted file mode 100644
index 7ce5571..0000000
--- a/internal/embeded/migrations/01_initial.up.sql
+++ /dev/null
@@ -1,8 +0,0 @@
--- SQLITE
-
-CREATE TABLE users (
- id UUID PRIMARY KEY,
- pswd_hash TEXT NOT NULL,
- username TEXT NOT NULL UNIQUE,
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
\ No newline at end of file
diff --git a/internal/embeded/migrations/02_tasks.down.sql b/internal/embeded/migrations/01_tasks.down.sql
similarity index 100%
rename from internal/embeded/migrations/02_tasks.down.sql
rename to internal/embeded/migrations/01_tasks.down.sql
diff --git a/internal/embeded/migrations/01_tasks.up.sql b/internal/embeded/migrations/01_tasks.up.sql
new file mode 100644
index 0000000..edd8b4c
--- /dev/null
+++ b/internal/embeded/migrations/01_tasks.up.sql
@@ -0,0 +1,8 @@
+-- SQLITE
+
+CREATE TABLE tasks (
+ id UUID PRIMARY KEY,
+ title TEXT NOT NULL,
+ description TEXT NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
diff --git a/internal/embeded/migrations/02_tasks.up.sql b/internal/embeded/migrations/02_tasks.up.sql
deleted file mode 100644
index dd98c06..0000000
--- a/internal/embeded/migrations/02_tasks.up.sql
+++ /dev/null
@@ -1,10 +0,0 @@
--- SQLITE
-
-CREATE TABLE tasks (
- id UUID PRIMARY KEY,
- title TEXT NOT NULL,
- owner_id UUID NOT NULL,
- description TEXT NOT NULL,
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- FOREIGN KEY (owner_id) REFERENCES users (id)
-);
diff --git a/internal/models/tasks.go b/internal/models/tasks.go
index 758b6ef..0f59fc9 100644
--- a/internal/models/tasks.go
+++ b/internal/models/tasks.go
@@ -4,7 +4,6 @@ type Task struct {
Id string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
- OwnerId string `json:"owner_id"`
}
var EmptyTask = Task{}
diff --git a/internal/models/users.go b/internal/models/users.go
deleted file mode 100644
index c885856..0000000
--- a/internal/models/users.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package models
-
-import "strings"
-
-type User struct {
- ID string `json:"id"`
- Username string `json:"username"`
- PswdHash string `json:"pswd_hash"`
-}
-
-var EmptyUser = User{}
-
-func GenerateNameFromEmail(email string) string {
- return strings.Split(email, "@")[0]
-}
diff --git a/internal/repositories/database/database.go b/internal/repositories/database/database.go
index 702cb2f..e4659ec 100644
--- a/internal/repositories/database/database.go
+++ b/internal/repositories/database/database.go
@@ -26,14 +26,14 @@ func (db *database) Close() error {
}
func (db *database) CreateTask(task models.Task) error {
- query := `INSERT INTO tasks (id, title, description, owner_id) VALUES (?, ?, ?, ?)`
- _, err := db.conn.Exec(query, task.Id, task.Title, task.Description, task.OwnerId)
+ query := `INSERT INTO tasks (id, title, description) VALUES (?, ?, ?)`
+ _, err := db.conn.Exec(query, task.Id, task.Title, task.Description)
return err
}
-func (db *database) ListTasksByOwner(ownerId string) ([]models.Task, error) {
- query := `SELECT id, title, owner_id, description FROM tasks WHERE owner_id = ?`
- rows, err := db.conn.Query(query, ownerId)
+func (db *database) ListTasks() ([]models.Task, error) {
+ query := `SELECT id, title, description FROM tasks`
+ rows, err := db.conn.Query(query)
if err != nil {
return nil, err
}
@@ -41,7 +41,7 @@ func (db *database) ListTasksByOwner(ownerId string) ([]models.Task, error) {
var tasks []models.Task
for rows.Next() {
var task models.Task
- err := rows.Scan(&task.Id, &task.Title, &task.OwnerId, &task.Description)
+ err := rows.Scan(&task.Id, &task.Title, &task.Description)
if err != nil {
return nil, err
}
@@ -53,11 +53,11 @@ func (db *database) ListTasksByOwner(ownerId string) ([]models.Task, error) {
}
func (db *database) RetrieveTaskById(taskId string) (models.Task, error) {
- query := `SELECT id, title, owner_id, description FROM tasks WHERE id = ?`
+ query := `SELECT id, title, description FROM tasks WHERE id = ?`
row := db.conn.QueryRow(query, taskId)
var task models.Task
- err := row.Scan(&task.Id, &task.Title, &task.OwnerId, &task.Description)
+ err := row.Scan(&task.Id, &task.Title, &task.Description)
if err != nil {
return models.EmptyTask, err
}
@@ -76,35 +76,3 @@ func (db *database) UpdateTask(task models.Task) error {
_, err := db.conn.Exec(query, task.Title, task.Description, task.Id)
return err
}
-
-func (db *database) InsertUser(user models.User) error {
- query := `INSERT INTO users (id, username, pswd_hash) VALUES (?, ?, ?)`
- _, err := db.conn.Exec(query, user.ID, user.Username, user.PswdHash)
- return err
-}
-
-func (db *database) RetrieveUserByName(username string) (models.User, error) {
- query := `SELECT id, username, pswd_hash FROM users WHERE username = ?`
- row := db.conn.QueryRow(query, username)
-
- var user models.User
- err := row.Scan(&user.ID, &user.Username, &user.PswdHash)
- if err != nil {
- return models.EmptyUser, err
- }
-
- return user, nil
-}
-
-func (db *database) RetrieveUserById(id string) (models.User, error) {
- query := `SELECT id, username, pswd_hash FROM users WHERE id = ?`
- row := db.conn.QueryRow(query, id)
-
- var user models.User
- err := row.Scan(&user.ID, &user.Username, &user.PswdHash)
- if err != nil {
- return models.EmptyUser, err
- }
-
- return user, nil
-}
diff --git a/internal/repositories/database/fake.go b/internal/repositories/database/fake.go
index b703246..ce4b1a5 100644
--- a/internal/repositories/database/fake.go
+++ b/internal/repositories/database/fake.go
@@ -2,7 +2,6 @@ package database
import (
"database/sql"
- "fmt"
"goth/internal/models"
_ "modernc.org/sqlite"
@@ -10,13 +9,11 @@ import (
type fakeDatabase struct {
tasks map[string]models.Task
- users map[string]models.User
}
func NewFakeDatabaseRepo() (Database, error) {
return &fakeDatabase{
tasks: make(map[string]models.Task),
- users: make(map[string]models.User),
}, nil
}
@@ -29,13 +26,11 @@ func (db *fakeDatabase) CreateTask(task models.Task) error {
return nil
}
-func (db *fakeDatabase) ListTasksByOwner(ownerId string) ([]models.Task, error) {
+func (db *fakeDatabase) ListTasks() ([]models.Task, error) {
tasks := make([]models.Task, 0)
for _, task := range db.tasks {
- if task.OwnerId == ownerId {
- tasks = append(tasks, task)
- }
+ tasks = append(tasks, task)
}
return tasks, nil
@@ -59,32 +54,3 @@ func (db *fakeDatabase) UpdateTask(task models.Task) error {
db.tasks[task.Id] = task
return nil
}
-
-func (db *fakeDatabase) InsertUser(user models.User) error {
- _, ok := db.users[user.ID]
- if ok {
- return fmt.Errorf("non unique email")
- }
-
- db.users[user.ID] = user
- return nil
-}
-
-func (db *fakeDatabase) RetrieveUserById(id string) (models.User, error) {
- user, ok := db.users[id]
- if !ok {
- return models.EmptyUser, sql.ErrNoRows
- }
-
- return user, nil
-}
-
-func (db *fakeDatabase) RetrieveUserByName(username string) (models.User, error) {
- for _, u := range db.users {
- if u.Username == username {
- return u, nil
- }
- }
-
- return models.EmptyUser, sql.ErrNoRows
-}
diff --git a/internal/repositories/database/interface.go b/internal/repositories/database/interface.go
index 459501b..9d540a2 100644
--- a/internal/repositories/database/interface.go
+++ b/internal/repositories/database/interface.go
@@ -13,9 +13,5 @@ type Database interface {
RetrieveTaskById(taskId string) (models.Task, error)
UpdateTask(task models.Task) error
DeleteTask(taskId string) error
- ListTasksByOwner(ownerId string) ([]models.Task, error)
-
- InsertUser(user models.User) error
- RetrieveUserById(id string) (models.User, error)
- RetrieveUserByName(username string) (models.User, error)
+ ListTasks() ([]models.Task, error)
}
diff --git a/internal/repositories/jwt/interface.go b/internal/repositories/jwt/interface.go
deleted file mode 100644
index 723ca49..0000000
--- a/internal/repositories/jwt/interface.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package jwt
-
-import (
- "time"
-)
-
-// type JWTClaims struct {
-// Id string `json:"id"`
-// gojwt.RegisteredClaims
-// }
-
-type JWT interface {
- GenerateJWT(sub string, expiration time.Time) (string, error)
- ParseJWT(token string) (string, error)
-}
diff --git a/internal/repositories/jwt/jwt.go b/internal/repositories/jwt/jwt.go
deleted file mode 100644
index fbd1582..0000000
--- a/internal/repositories/jwt/jwt.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package jwt
-
-import (
- "goth/internal/config"
- "time"
-
- gojwt "github.com/golang-jwt/jwt/v5"
-)
-
-type jwt struct {
- bsecret []byte
-}
-
-func NewJWTRepo(cfg config.ServerConfigs) JWT {
- return &jwt{
- bsecret: []byte(cfg.JwtSecret),
- }
-}
-
-func (j *jwt) GenerateJWT(sub string, expiration time.Time) (string, error) {
- claims := &gojwt.RegisteredClaims{
- Subject: sub,
- IssuedAt: gojwt.NewNumericDate(time.Now()),
- ExpiresAt: gojwt.NewNumericDate(expiration),
- }
-
- jwtoken := gojwt.NewWithClaims(gojwt.SigningMethodHS256, claims)
- return jwtoken.SignedString(j.bsecret)
-}
-
-func (j *jwt) ParseJWT(token string) (string, error) {
- claims := gojwt.RegisteredClaims{}
-
- _, err := gojwt.ParseWithClaims(token, &claims, func(token *gojwt.Token) (interface{}, error) {
- return j.bsecret, nil
- })
-
- if err != nil {
- return "", err
- }
-
- if claims.Subject == "" {
- return "", gojwt.ErrInvalidKey
- }
-
- return claims.Subject, nil
-}
diff --git a/internal/routes/bind.go b/internal/routes/bind.go
new file mode 100644
index 0000000..2e421e5
--- /dev/null
+++ b/internal/routes/bind.go
@@ -0,0 +1,15 @@
+package routes
+
+import (
+ "goth/internal/controllers"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+const cookieName = "goth:jwt"
+
+func controllerBind(controller *controllers.TaskController, handler func(*controllers.TaskController, *fiber.Ctx) error) fiber.Handler {
+ return func(ctx *fiber.Ctx) error {
+ return handler(controller, ctx)
+ }
+}
diff --git a/internal/routes/init.go b/internal/routes/init.go
index cf794a5..f6ced97 100644
--- a/internal/routes/init.go
+++ b/internal/routes/init.go
@@ -5,7 +5,6 @@ import (
"goth/internal/config"
"goth/internal/controllers"
"goth/internal/repositories/database"
- "goth/internal/repositories/jwt"
"github.com/gofiber/fiber/v2"
)
@@ -15,28 +14,17 @@ func healthzHandler(c *fiber.Ctx) error {
}
func Init(app *fiber.App, cfg config.ServerConfigs) error {
- jwtRepo := jwt.NewJWTRepo(cfg)
-
dbRepo, err := database.NewDatabaseRepo(cfg)
if err != nil {
return fmt.Errorf("[Init] failed to get database: %w", err)
}
- uc := controllers.NewUserController(dbRepo, jwtRepo)
tc := controllers.NewTaskController(dbRepo)
- app.Get("/auth/login", getLoginHandler)
- app.Post("/auth/login", postLoginHandler(uc))
-
- app.Get("/auth/register", getRegisterHandler)
- app.Post("/auth/register", postRegisterHandler(uc))
-
- app.Get("/auth/logout", getLogoutHandler)
-
- app.Get("/", withAuth(uc, tc, taskList))
- app.Get("/new", withAuth(uc, tc, taskNew))
- app.Get("/edit/:id", withAuth(uc, tc, taskEdit))
- app.Post("/edit/:id", withAuth(uc, tc, taskSave))
+ app.Get("/", controllerBind(tc, taskList))
+ app.Get("/new", controllerBind(tc, taskNew))
+ app.Get("/edit/:id", controllerBind(tc, taskEdit))
+ app.Post("/edit/:id", controllerBind(tc, taskSave))
app.Use("/statics", staticsHandler)
app.Use("/healthz", healthzHandler)
diff --git a/internal/routes/tasks.go b/internal/routes/tasks.go
index 02f33d5..f6ce150 100644
--- a/internal/routes/tasks.go
+++ b/internal/routes/tasks.go
@@ -3,13 +3,12 @@ package routes
import (
"goth/internal/components"
"goth/internal/controllers"
- "goth/internal/models"
"github.com/gofiber/fiber/v2"
)
-func taskList(tc *controllers.TaskController, c *fiber.Ctx, user models.User) error {
- tasks, err := tc.ListTasks(user.ID)
+func taskList(tc *controllers.TaskController, c *fiber.Ctx) error {
+ tasks, err := tc.ListTasks()
if err != nil {
return err
}
@@ -17,8 +16,8 @@ func taskList(tc *controllers.TaskController, c *fiber.Ctx, user models.User) er
return sendPage(c, components.TaskListPage(tasks))
}
-func taskNew(tc *controllers.TaskController, c *fiber.Ctx, user models.User) error {
- task, err := tc.CreateTask(user.ID)
+func taskNew(tc *controllers.TaskController, c *fiber.Ctx) error {
+ task, err := tc.CreateTask()
if err != nil {
return err
}
@@ -26,9 +25,9 @@ func taskNew(tc *controllers.TaskController, c *fiber.Ctx, user models.User) err
return c.Redirect("/edit/" + task.Id)
}
-func taskEdit(tc *controllers.TaskController, c *fiber.Ctx, user models.User) error {
+func taskEdit(tc *controllers.TaskController, c *fiber.Ctx) error {
taskId := c.Params("id")
- task, err := tc.RetrieveTask(user.ID, taskId)
+ task, err := tc.RetrieveTask(taskId)
if err != nil {
return err
@@ -37,7 +36,7 @@ func taskEdit(tc *controllers.TaskController, c *fiber.Ctx, user models.User) er
return sendPage(c, components.TaskEditPage(task))
}
-func taskSave(tc *controllers.TaskController, c *fiber.Ctx, user models.User) error {
+func taskSave(tc *controllers.TaskController, c *fiber.Ctx) error {
var taskId = c.Params("id")
var taskChange controllers.TaskChange
err := c.BodyParser(&taskChange)
@@ -45,7 +44,7 @@ func taskSave(tc *controllers.TaskController, c *fiber.Ctx, user models.User) er
return err
}
- if err := tc.UpdateTask(user.ID, taskId, taskChange); err != nil {
+ if err := tc.UpdateTask(taskId, taskChange); err != nil {
return err
}
diff --git a/internal/routes/users.go b/internal/routes/users.go
deleted file mode 100644
index aa30857..0000000
--- a/internal/routes/users.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package routes
-
-import (
- "goth/internal/components"
- "goth/internal/controllers"
- "goth/internal/models"
- "goth/internal/utils"
-
- "github.com/gofiber/fiber/v2"
-)
-
-const cookieName = "goth:jwt"
-
-func withAuth[C controllers.Controllers](uController *controllers.UserController, controller *C, handler func(*C, *fiber.Ctx, models.User) error) fiber.Handler {
- return func(ctx *fiber.Ctx) error {
- jwt := ctx.Cookies(cookieName)
- if jwt == "" {
- return ctx.Redirect("/auth/login")
- }
-
- user, err := uController.VerifyJWTCookie(jwt)
- if err != nil {
- return ctx.Redirect("/auth/login")
- }
-
- return handler(controller, ctx, user)
- }
-}
-
-func getLogoutHandler(c *fiber.Ctx) error {
- utils.ClearCookie(c, cookieName)
- return sendPage(c, components.PostLogoutPage())
-}
-
-func getRegisterHandler(c *fiber.Ctx) error {
- utils.ClearCookie(c, cookieName)
- return sendPage(c, components.RegisterPage())
-}
-
-func getLoginHandler(c *fiber.Ctx) error {
- utils.ClearCookie(c, cookieName)
- return sendPage(c, components.LoginPage())
-}
-
-func postLoginHandler(uc *controllers.UserController) fiber.Handler {
- return func(c *fiber.Ctx) error {
- var req controllers.UserRequest
- err := c.BodyParser(&req)
- if err != nil {
- return err
- }
-
- cookie, err := uc.Login(req, cookieName)
- if err != nil {
- return err
- }
-
- c.Cookie(cookie)
- c.Set("HX-Redirect", "/")
- return c.SendStatus(fiber.StatusOK)
- }
-}
-
-func postRegisterHandler(uc *controllers.UserController) fiber.Handler {
- return func(c *fiber.Ctx) error {
- var req controllers.UserRequest
- err := c.BodyParser(&req)
- if err != nil {
- return err
- }
-
- cookie, err := uc.Register(req, cookieName)
- if err != nil {
- return err
- }
-
- c.Cookie(cookie)
- c.Set("HX-Redirect", "/")
- return c.SendStatus(fiber.StatusOK)
- }
-}