Abstract db handling into repositories

This commit is contained in:
2025-01-05 22:22:00 +01:00
parent 2eadad9135
commit 4e48e87f6c
5 changed files with 303 additions and 105 deletions

View File

@@ -6,9 +6,9 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"example.com/gin/test/models"
"example.com/gin/test/repositories"
)
type CRUDController interface {
@@ -25,21 +25,16 @@ type RoomController interface {
AddUser(*gin.Context)
}
type roomController struct {
DB *gorm.DB
}
type roomController struct {}
func NewRoomController(db *gorm.DB) RoomController {
return &roomController{
DB: db,
}
func NewRoomController() RoomController {
return &roomController{}
}
func (rc *roomController) GetAll(c *gin.Context) {
var rooms []models.Room
result := rc.DB.Find(&rooms)
rooms, err := repositories.Rooms.GetAll()
if result.Error != nil {
if err != nil {
ReplyError(c, fmt.Errorf("Could not query rooms"))
return
}
@@ -48,18 +43,10 @@ func (rc *roomController) GetAll(c *gin.Context) {
}
func (rc *roomController) GetById(c *gin.Context) {
roomId, err := strconv.Atoi(c.Param("id"))
room, err := repositories.Rooms.GetById(c.Param("id"))
if err != nil {
ReplyError(c, fmt.Errorf("Room with Id '%s' does not exist", c.Param("id")))
return
}
var room models.Room
result := rc.DB.First(&room, uint(roomId))
if result.Error != nil {
ReplyError(c, fmt.Errorf("Could not query room: %v", result.Error))
ReplyError(c, fmt.Errorf("Could not query room: %v", err))
return
}
@@ -80,9 +67,9 @@ func (rc *roomController) Create(c *gin.Context) {
ReplyError(c, err)
}
result := rc.DB.Create(&room)
if result.Error != nil {
ReplyError(c, fmt.Errorf("Room creation failed: %s", result.Error))
_, err = repositories.Rooms.Create(room)
if err != nil {
ReplyError(c, fmt.Errorf("Room creation failed: %s", err))
return
}
@@ -114,9 +101,10 @@ func (rc *roomController) Update(c *gin.Context) {
}
room.ID = uint(roomId)
result := rc.DB.Save(&room)
if result.Error != nil {
ReplyError(c, fmt.Errorf("Room creation failed: %s", result.Error))
_, err = repositories.Rooms.Update(room)
if err != nil {
ReplyError(c, fmt.Errorf("Room creation failed: %s", err))
return
}
@@ -124,17 +112,10 @@ func (rc *roomController) Update(c *gin.Context) {
}
func (rc *roomController) Delete(c *gin.Context) {
roomId, err := strconv.Atoi(c.Param("id"))
err := repositories.Rooms.DeleteById(c.Param("id"))
if err != nil {
ReplyError(c, fmt.Errorf("Room with Id '%s' does not exist", c.Param("id")))
return
}
result := rc.DB.Delete(&models.Room{}, roomId)
if result.Error != nil {
ReplyError(c, fmt.Errorf("Room deletion failed: %s", result.Error))
ReplyError(c, fmt.Errorf("Room deletion failed: %s", err))
return
}
@@ -144,24 +125,13 @@ func (rc *roomController) Delete(c *gin.Context) {
func (rc *roomController) GetUsers(c *gin.Context) {
//only allow room admin
roomId, err := strconv.Atoi(c.Param("id"))
users, err := repositories.Rooms.GetRoomUsersById(c.Param("id"))
if err != nil {
ReplyError(c, fmt.Errorf("Room with Id '%s' does not exist", c.Param("id")))
ReplyError(c, fmt.Errorf("Could not get users for room '%s'", c.Param("id")))
return
}
var room models.Room
result := rc.DB.First(&room, uint(roomId))
if result.Error != nil {
ReplyError(c, fmt.Errorf("Could not query room: %v", result.Error))
return
}
var users []models.User
rc.DB.Model(&room).Association("Users").Find(&users)
var emails []string
for _, user := range users {
emails = append(emails, user.Email)
@@ -188,10 +158,9 @@ func (rc *roomController) AddUser(c *gin.Context) {
}
//lookup requested user
var user models.User
result := rc.DB.First(&user, "email = ?", body.Email)
user, err := repositories.Users.GetByEmail(body.Email)
if result.Error != nil {
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Invalid user",
})
@@ -199,22 +168,13 @@ func (rc *roomController) AddUser(c *gin.Context) {
return
}
roomId, err := strconv.Atoi(c.Param("id"))
err = repositories.Rooms.AddRoomUserById(c.Param("id"), user)
if err != nil {
ReplyError(c, fmt.Errorf("Room with Id '%s' does not exist", c.Param("id")))
ReplyError(c, fmt.Errorf("Could not add user to room."))
return
}
var room models.Room
result = rc.DB.First(&room, uint(roomId))
if result.Error != nil {
ReplyError(c, fmt.Errorf("Could not query room: %v", result.Error))
return
}
rc.DB.Model(&room).Association("Users").Append(&user)
ReplyOK(c, "Added User to Room")
}

View File

@@ -9,20 +9,16 @@ import(
"github.com/golang-jwt/jwt/v5"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"example.com/gin/test/models"
"example.com/gin/test/repositories"
)
type UserController struct {
DB *gorm.DB
}
type UserController struct {}
func NewUserController(db *gorm.DB) UserController {
return UserController{
DB: db,
}
func NewUserController() UserController {
return UserController{}
}
@@ -57,10 +53,10 @@ func (uc *UserController) Register(c *gin.Context) {
//create user
user := models.User{Name: body.Name, Email: body.Email, Password: string(hash)}
result := uc.DB.Create(&user)
_, err = repositories.Users.Create(user)
if result.Error != nil {
fmt.Println("Error: ", result.Error)
if err != nil {
fmt.Println("Error: ", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "Failed to create user",
})
@@ -92,10 +88,9 @@ func (uc *UserController) Login(c *gin.Context) {
}
//lookup requested user
var user models.User
result := uc.DB.First(&user, "email = ?", body.Email)
user, err := repositories.Users.GetByEmail(body.Email)
if result.Error != nil {
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Invalid email or password",
})
@@ -151,3 +146,48 @@ func (uc *UserController) Validate(c *gin.Context) {
})
}
}
func (rc *UserController) LoginView(c *gin.Context) {
rooms, _ := repositories.Rooms.GetAll()
data := gin.H{
"title": "Room Page",
"rooms": rooms,
}
c.HTML(http.StatusOK, "login.html", data)
}
func (rc *UserController) RegisterView(c *gin.Context) {
rooms, _ := repositories.Rooms.GetAll()
data := gin.H{
"title": "Room Page",
"rooms": rooms,
}
c.HTML(http.StatusOK, "register.html", data)
}
func (rc *UserController) ResetView(c *gin.Context) {
rooms, _ := repositories.Rooms.GetAll()
data := gin.H{
"title": "Room Page",
"rooms": rooms,
}
c.HTML(http.StatusOK, "passwordreset.html", data)
}
func (rc *UserController) MainView(c *gin.Context) {
rooms, _ := repositories.Rooms.GetAll()
data := gin.H{
"title": "Room Page",
"rooms": rooms,
}
c.HTML(http.StatusOK, "index.html", data)
}

32
main.go
View File

@@ -6,20 +6,18 @@ import(
"net/http"
"fmt"
"gorm.io/gorm"
"gorm.io/driver/sqlite"
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
"example.com/gin/test/controllers"
"example.com/gin/test/models"
"example.com/gin/test/repositories"
"example.com/gin/test/middlewares"
)
var(
roomController controllers.RoomController
userController controllers.UserController
autoValidator middlewares.AuthValidator
roomController controllers.RoomController = controllers.NewRoomController()
userController controllers.UserController = controllers.UserController{}
authValidator middlewares.AuthValidator = middlewares.AuthValidator{}
)
func LoadEnvVariables() {
@@ -46,19 +44,8 @@ func SetReply(ctx *gin.Context, err error, message any) {
func main() {
LoadEnvVariables()
db, err := gorm.Open(sqlite.Open(os.Getenv("SQLITE_DB")), &gorm.Config{})
if err != nil {
panic("failed to connect to database")
}
repositories.InitRepositories()
err = db.AutoMigrate(&models.Room{}, &models.User{}, &models.Booking{})
if err != nil {
panic("failed to migrate database")
}
roomController = controllers.NewRoomController(db)
userController = controllers.NewUserController(db)
authValidator := middlewares.AuthValidator{ DB: db, }
server := gin.New()
server.Use(gin.Recovery())
@@ -84,5 +71,14 @@ func main() {
apiRoutes.GET("/users/validate", authValidator.OptionalAuth, userController.Validate)
}
viewRoutes := server.Group("/")
{
viewRoutes.GET("/", userController.MainView)
viewRoutes.GET("/login", userController.LoginView)
viewRoutes.GET("/register", userController.RegisterView)
viewRoutes.GET("/passwordreset", userController.ResetView)
}
server.Run(":"+os.Getenv("PORT"))
}

View File

@@ -8,13 +8,12 @@ import(
"net/http"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
"gorm.io/gorm"
"example.com/gin/test/models"
"example.com/gin/test/repositories"
)
type AuthValidator struct {
DB *gorm.DB
}
func (av *AuthValidator) RequireRoomAdmin(c *gin.Context) {
@@ -30,8 +29,12 @@ func (av *AuthValidator) RequireRoomAdmin(c *gin.Context) {
return
}
var rooms []models.Room
av.DB.Model(&user).Association("OwnedRooms").Find(&rooms)
rooms, err := repositories.Users.GetOwnedRooms(user.(models.User))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{ "message": "Could not querie owend rooms"})
return
}
for _, room := range rooms {
if room.ID == uint(roomId) {
@@ -77,10 +80,9 @@ func (av *AuthValidator) RequireAuth(c *gin.Context) {
}
//Find user
var user models.User
result := av.DB.First(&user, claims["sub"])
user, err := repositories.Users.GetById(claims["sub"])
if result.Error != nil {
if err != nil {
c.AbortWithStatus(http.StatusUnauthorized)
return
}
@@ -124,10 +126,9 @@ func (av *AuthValidator) OptionalAuth(c *gin.Context) {
}
//Find user
var user models.User
result := av.DB.First(&user, claims["sub"])
user, err := repositories.Users.GetById(claims["sub"])
if result.Error != nil {
if err != nil {
return
}

201
repositories/repository.go Normal file
View File

@@ -0,0 +1,201 @@
package repositories
import(
"os"
"strconv"
"gorm.io/gorm"
"gorm.io/driver/sqlite"
"example.com/gin/test/models"
)
var(
Rooms RoomRepository
Users UserRepository
)
type RoomRepository interface {
Create(models.Room) (models.Room, error)
GetAll() ([]models.Room, error)
GetById(string) (models.Room, error)
Update(models.Room) (models.Room, error)
DeleteById(string) error
GetRoomUsersById(string) ([]models.User, error)
AddRoomUserById(string, models.User) error
}
type UserRepository interface {
Create(models.User) (models.User, error)
GetByEmail(string) (models.User, error)
GetById(interface{}) (models.User, error)
GetOwnedRooms(models.User) ([]models.Room, error)
}
func InitRepositories() {
db, err := gorm.Open(sqlite.Open(os.Getenv("SQLITE_DB")), &gorm.Config{})
if err != nil {
panic("failed to connect to database")
}
err = db.AutoMigrate(&models.Room{}, &models.User{}, &models.Booking{})
if err != nil {
panic("failed to migrate database")
}
Rooms = NewGORMRoomRepository(db)
Users = NewGORMUserRepository(db)
}
type GORMUserRepository struct {
DB *gorm.DB
}
type GORMRoomRepository struct {
DB *gorm.DB
}
func NewGORMUserRepository(db *gorm.DB) UserRepository {
return &GORMUserRepository{
DB: db,
}
}
func NewGORMRoomRepository(db *gorm.DB) RoomRepository {
return &GORMRoomRepository{
DB: db,
}
}
func (r *GORMRoomRepository) Create(room models.Room) (models.Room, error) {
result := r.DB.Create(&room)
if result.Error != nil {
return models.Room{}, result.Error
}
return room, nil
}
func (r *GORMRoomRepository) GetAll() ([]models.Room, error){
var rooms []models.Room
result := r.DB.Find(&rooms)
return rooms, result.Error
}
func (r *GORMRoomRepository) GetById(id string) (models.Room, error) {
roomId, err := strconv.Atoi(id)
if err != nil {
return models.Room{}, err
}
var room models.Room
result := r.DB.First(&room, uint(roomId))
if result.Error != nil {
return models.Room{}, result.Error
}
return room, nil
}
func (r *GORMRoomRepository) Update(room models.Room) (models.Room, error) {
result := r.DB.Save(&room)
if result.Error != nil {
return models.Room{}, result.Error
}
return room, nil
}
func (r *GORMRoomRepository) DeleteById(id string) error {
roomId, err := strconv.Atoi(id)
if err != nil {
return err
}
result := r.DB.Delete(&models.Room{}, roomId)
return result.Error
}
func (r *GORMRoomRepository) GetRoomUsersById(id string) ([]models.User, error) {
roomId, err := strconv.Atoi(id)
if err != nil {
return nil, err
}
var room models.Room
result := r.DB.First(&room, uint(roomId))
if result.Error != nil {
return nil, result.Error
}
var users []models.User
err = r.DB.Model(&room).Association("Users").Find(&users)
if err != nil {
return nil, err
}
return users, nil
}
func (r *GORMRoomRepository) AddRoomUserById(id string, user models.User) error {
roomId, err := strconv.Atoi(id)
if err != nil {
return err
}
var room models.Room
result := r.DB.First(&room, uint(roomId))
if result.Error != nil {
return result.Error
}
err = r.DB.Model(&room).Association("Users").Append(&user)
return err
}
func (u *GORMUserRepository) Create(user models.User) (models.User, error) {
result := u.DB.Create(&user)
if result.Error != nil {
return models.User{}, result.Error
}
return user, nil
}
func (u *GORMUserRepository) GetByEmail(email string) (models.User, error) {
var user models.User
result := u.DB.First(&user, "email = ?", email)
if result.Error != nil {
return models.User{}, result.Error
}
return user, nil
}
func (u *GORMUserRepository) GetById(id interface{}) (models.User, error) {
var user models.User
result := u.DB.First(&user, id)
if result.Error != nil {
return models.User{}, result.Error
}
return user, nil
}
func (u *GORMUserRepository) GetOwnedRooms(user models.User) ([]models.Room, error) {
var rooms []models.Room
err := u.DB.Model(&user).Association("OwnedRooms").Find(&rooms)
return rooms, err
}