first commit
This commit is contained in:
		
							
								
								
									
										67
									
								
								internal/controllers/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								internal/controllers/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"studioj/boilerplate_go/internal/models"
 | 
			
		||||
	"studioj/boilerplate_go/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AuthController interface {
 | 
			
		||||
	Register(*gin.Context)
 | 
			
		||||
	Login(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type authController struct {
 | 
			
		||||
	service services.AuthService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewAuthController(service services.AuthService) AuthController {
 | 
			
		||||
	return &authController{
 | 
			
		||||
		service: service,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (controller *authController) Register(c *gin.Context) {
 | 
			
		||||
	var params models.RegisterRequest
 | 
			
		||||
	if c.BindJSON(¶ms) != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user, err := controller.service.Register(¶ms)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	token, err := controller.service.CreateToken(user.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{"user": user, "token": token.Token, "refresh_token": token.RefreshToken})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (controller *authController) Login(c *gin.Context) {
 | 
			
		||||
	var params models.LoginRequest
 | 
			
		||||
	if c.BindJSON(¶ms) != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user, err := controller.service.Login(¶ms)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	token, err := controller.service.CreateToken(user.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{"user": user, "token": token.Token, "refresh_token": token.RefreshToken})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								internal/controllers/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								internal/controllers/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"studioj/boilerplate_go/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TokenController interface {
 | 
			
		||||
	Find(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type tokenController struct {
 | 
			
		||||
	service services.TokenService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTokenController(service services.TokenService) TokenController {
 | 
			
		||||
	return &tokenController{
 | 
			
		||||
		service: service,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (controller *tokenController) Find(c *gin.Context) {
 | 
			
		||||
	id := c.Param("id")
 | 
			
		||||
	user_id := c.GetString("user_id")
 | 
			
		||||
 | 
			
		||||
	if user_id != id {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": "Wrong user"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (controller *tokenController) List(c *gin.Context) {
 | 
			
		||||
	id := c.Param("id")
 | 
			
		||||
	user_id := c.GetString("user_id")
 | 
			
		||||
 | 
			
		||||
	if user_id != id {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": "Wrong user"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.Find(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								internal/controllers/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								internal/controllers/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
package controllers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"studioj/boilerplate_go/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UserController interface {
 | 
			
		||||
	Find(*gin.Context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type userController struct {
 | 
			
		||||
	service      services.UserService
 | 
			
		||||
	tokenService services.TokenService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserController(service services.UserService, tokenService services.TokenService) UserController {
 | 
			
		||||
	return &userController{
 | 
			
		||||
		service:      service,
 | 
			
		||||
		tokenService: tokenService,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (controller *userController) Find(c *gin.Context) {
 | 
			
		||||
	id := c.Param("id")
 | 
			
		||||
	user_id := c.GetString("sub")
 | 
			
		||||
	fmt.Println("id", id)
 | 
			
		||||
	fmt.Println("user_id", user_id)
 | 
			
		||||
 | 
			
		||||
	if user_id != id {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": "Wrong user"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := controller.service.FindByID(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.JSON(http.StatusOK, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								internal/database/database.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								internal/database/database.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
package database
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	config "studioj/boilerplate_go/configs"
 | 
			
		||||
	"studioj/boilerplate_go/internal/models"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/driver/mysql"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
	"gorm.io/gorm/schema"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Database struct {
 | 
			
		||||
	*gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var DB *gorm.DB
 | 
			
		||||
 | 
			
		||||
func Init() {
 | 
			
		||||
	DB = ConnectDB((config.DATABASE_URL))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ConnectDB(url string) *gorm.DB {
 | 
			
		||||
	gorm_config := gorm.Config{NamingStrategy: schema.NamingStrategy{SingularTable: true}}
 | 
			
		||||
	db, err := gorm.Open(mysql.Open(url), &gorm_config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	return db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetDB() *gorm.DB {
 | 
			
		||||
	return DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AutoMigrate() {
 | 
			
		||||
	DB.AutoMigrate(
 | 
			
		||||
		&models.User{},
 | 
			
		||||
		&models.Token{},
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								internal/helpers/helpers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								internal/helpers/helpers.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
package helpers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InLambda() bool {
 | 
			
		||||
	if lambdaTaskRoot := os.Getenv("LAMBDA_TASK_ROOT"); lambdaTaskRoot != "" {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RandomPin() string {
 | 
			
		||||
	min := 100000
 | 
			
		||||
	max := 999999
 | 
			
		||||
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
 | 
			
		||||
	pin := r.Intn(max-min) + min
 | 
			
		||||
	return strconv.Itoa(pin)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Datetime(timeString string) (time.Time, error) {
 | 
			
		||||
	layout := "2006-01-02T15:04:05.000Z"
 | 
			
		||||
	result, err := time.Parse(layout, timeString)
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								internal/middleware/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								internal/middleware/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
package middleware
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	config "studioj/boilerplate_go/configs"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"github.com/golang-jwt/jwt/v5"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Auth() gin.HandlerFunc {
 | 
			
		||||
	return func(c *gin.Context) {
 | 
			
		||||
		sub, err := UserID(c.Request)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
 | 
			
		||||
			c.Abort()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fmt.Println("token", extract(c.Request))
 | 
			
		||||
		fmt.Println("sub", *sub)
 | 
			
		||||
 | 
			
		||||
		c.Set("token", extract(c.Request))
 | 
			
		||||
		c.Set("sub", *sub)
 | 
			
		||||
		c.Next()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func extract(r *http.Request) string {
 | 
			
		||||
	authorization := r.Header.Get("Authorization")
 | 
			
		||||
	strArr := strings.Split(authorization, " ")
 | 
			
		||||
	if len(strArr) == 2 {
 | 
			
		||||
		return strArr[1]
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func verify(r *http.Request) (*jwt.Token, error) {
 | 
			
		||||
	tokenString := extract(r)
 | 
			
		||||
	jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
 | 
			
		||||
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
		return []byte(config.SECRET_KEY), nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return jwtToken, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UserID(r *http.Request) (*string, error) {
 | 
			
		||||
	jwtToken, err := verify(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	claims, ok := jwtToken.Claims.(jwt.MapClaims)
 | 
			
		||||
	if !ok || !jwtToken.Valid {
 | 
			
		||||
		return nil, errors.New("refresh token is invalid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sub := claims["sub"].(string)
 | 
			
		||||
 | 
			
		||||
	return &sub, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								internal/middleware/transaction.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								internal/middleware/transaction.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
package middleware
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func StatusInList(status int, statusList []int) bool {
 | 
			
		||||
	for _, i := range statusList {
 | 
			
		||||
		for i == status {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Transaction(db *gorm.DB) gin.HandlerFunc {
 | 
			
		||||
	return func(c *gin.Context) {
 | 
			
		||||
		txHandle := db.Begin()
 | 
			
		||||
		log.Print("begining database transaction")
 | 
			
		||||
 | 
			
		||||
		defer func() {
 | 
			
		||||
			if r := recover(); r != nil {
 | 
			
		||||
				txHandle.Rollback()
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
		c.Set("db_trx", txHandle)
 | 
			
		||||
		c.Next()
 | 
			
		||||
 | 
			
		||||
		if StatusInList(c.Writer.Status(), []int{http.StatusOK, http.StatusCreated}) {
 | 
			
		||||
			log.Print("committing transactions")
 | 
			
		||||
			if err := txHandle.Commit().Error; err != nil {
 | 
			
		||||
				log.Print("transaction commit error: ", err)
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Print("rollback transaction due to status code: ", c.Writer.Status())
 | 
			
		||||
				txHandle.Rollback()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								internal/models/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								internal/models/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
type LoginRequest struct {
 | 
			
		||||
	Username string `json:"username"`
 | 
			
		||||
	Password string `json:"password"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RegisterRequest struct {
 | 
			
		||||
	Username string `json:"username"`
 | 
			
		||||
	Password string `json:"password"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								internal/models/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								internal/models/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type Token struct {
 | 
			
		||||
	ID           string    `json:"id" db:"id" gorm:"column:id;size:255;primary_key;"`
 | 
			
		||||
	UserID       string    `json:"user_id" db:"user_id" gorm:"column:user_id;size:255;index;"`
 | 
			
		||||
	Token        string    `json:"token" gorm:"column:token;size:255;index;"`
 | 
			
		||||
	RefreshToken string    `json:"refresh_token" gorm:"column:token;size:255;index;"`
 | 
			
		||||
	Status       string    `json:"status" gorm:"column:status;size:10;index;"`
 | 
			
		||||
	ExpireAt     time.Time `json:"expire_at" gorm:"column:expire_at;index;"`
 | 
			
		||||
	UpdatedAt    time.Time `json:"updated_at" gorm:"column:updated_at;index;"`
 | 
			
		||||
	CreatedAt    time.Time `json:"created_at" gorm:"column:created_at;index;"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TokenResponse struct {
 | 
			
		||||
	Token     string    `json:"token"`
 | 
			
		||||
	TokenBody TokenBody `json:"tokenBody"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TokenBody struct {
 | 
			
		||||
	ExpireAt  time.Time `json:"tokenExpiredDate"`
 | 
			
		||||
	TokenIdx  int       `json:"tokenIdx"`
 | 
			
		||||
	TokenType int       `json:"tokenType"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								internal/models/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								internal/models/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
type User struct {
 | 
			
		||||
	ID       string `json:"id" db:"id" gorm:"column:id;size:255;primary_key;"`
 | 
			
		||||
	Username string `json:"username" db:"username" gorm:"column:username;size:50;uniqueIndex;"`
 | 
			
		||||
	Score    int32  `json:"score" db:"score" gorm:"column:score;"`
 | 
			
		||||
	Money    int32  `json:"money" db:"money" gorm:"column:money;"`
 | 
			
		||||
	Password string `json:"-" db:"password" gorm:"column:password;size:255;not null;"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								internal/repositories/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								internal/repositories/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
package repositories
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	config "studioj/boilerplate_go/configs"
 | 
			
		||||
	"studioj/boilerplate_go/internal/models"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang-jwt/jwt/v5"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type tokenRepository struct {
 | 
			
		||||
	DB *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTokenRepository(db *gorm.DB) TokenRepository {
 | 
			
		||||
	return &tokenRepository{
 | 
			
		||||
		DB: db,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TokenRepository interface {
 | 
			
		||||
	Generate(string, int64) (string, error)
 | 
			
		||||
	Find(string) (*models.Token, error)
 | 
			
		||||
	Create(*models.Token) (*models.Token, error)
 | 
			
		||||
	Update(*models.Token) (*models.Token, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenRepository) Generate(sub string, expire_at int64) (string, error) {
 | 
			
		||||
	claims := jwt.MapClaims{}
 | 
			
		||||
	claims["authorized"] = true
 | 
			
		||||
	claims["sub"] = sub
 | 
			
		||||
	claims["exp"] = expire_at
 | 
			
		||||
	at := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 | 
			
		||||
	token, err := at.SignedString([]byte(config.SECRET_KEY))
 | 
			
		||||
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRepository) Find(id string) (*models.Token, error) {
 | 
			
		||||
	var token *models.Token
 | 
			
		||||
	err := r.DB.Where("id = ?", id).First(&token).Error
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRepository) Create(token *models.Token) (*models.Token, error) {
 | 
			
		||||
	err := r.DB.Create(&token).Error
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRepository) Update(token *models.Token) (*models.Token, error) {
 | 
			
		||||
	var row *models.Token
 | 
			
		||||
	if err := r.DB.Where("id=?", token.ID).First(&row).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.DB.Model(&row).Select("*").Updates(&token).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRepository) Delete(id string) error {
 | 
			
		||||
	var token *models.Token
 | 
			
		||||
	if err := r.DB.Where("id=?", id).First(&token).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := r.DB.Delete(&token).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								internal/repositories/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								internal/repositories/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
package repositories
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"studioj/boilerplate_go/internal/models"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type userRepository struct {
 | 
			
		||||
	DB *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserRepository(db *gorm.DB) UserRepository {
 | 
			
		||||
	return &userRepository{
 | 
			
		||||
		DB: db,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserRepository interface {
 | 
			
		||||
	List() (*[]models.User, error)
 | 
			
		||||
	FindByID(string) (*models.User, error)
 | 
			
		||||
	FindByUsername(string) (*models.User, error)
 | 
			
		||||
	Create(*models.User) (*models.User, error)
 | 
			
		||||
	Update(*models.User) (*models.User, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) List() (*[]models.User, error) {
 | 
			
		||||
	var users *[]models.User
 | 
			
		||||
	err := r.DB.Find(&users).Error
 | 
			
		||||
	return users, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) FindByID(id string) (*models.User, error) {
 | 
			
		||||
	var user *models.User
 | 
			
		||||
	err := r.DB.Where("id = ?", id).First(&user).Error
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) FindByUsername(username string) (*models.User, error) {
 | 
			
		||||
	var user *models.User
 | 
			
		||||
	err := r.DB.Where("username = ?", username).First(&user).Error
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) Create(user *models.User) (*models.User, error) {
 | 
			
		||||
	err := r.DB.Create(&user).Error
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) Update(user *models.User) (*models.User, error) {
 | 
			
		||||
	var row *models.User
 | 
			
		||||
	if err := r.DB.Where("id=?", user.ID).First(&row).Error; err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.DB.Model(&row).Select("*").Updates(&user).Error
 | 
			
		||||
	return row, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRepository) Delete(id string) error {
 | 
			
		||||
	var user *models.User
 | 
			
		||||
	if err := r.DB.Where("id=?", id).First(&user).Error; err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err := r.DB.Delete(&user).Error
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								internal/routers/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								internal/routers/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"studioj/boilerplate_go/internal/controllers"
 | 
			
		||||
	"studioj/boilerplate_go/internal/repositories"
 | 
			
		||||
	"studioj/boilerplate_go/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AuthRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type authRouter struct {
 | 
			
		||||
	db              *gorm.DB
 | 
			
		||||
	userRepository  repositories.UserRepository
 | 
			
		||||
	tokenRepository repositories.TokenRepository
 | 
			
		||||
	service         services.AuthService
 | 
			
		||||
	tokenService    services.TokenService
 | 
			
		||||
	controller      controllers.AuthController
 | 
			
		||||
	router          *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InitAuthRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewAuthRouter(db, router)
 | 
			
		||||
	r.SetAuthRouter(db, router)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewAuthRouter(db *gorm.DB, router *gin.Engine) *authRouter {
 | 
			
		||||
	userRepository := repositories.NewUserRepository(db)
 | 
			
		||||
	tokenRepository := repositories.NewTokenRepository(db)
 | 
			
		||||
	service := services.NewAuthService(userRepository, tokenRepository)
 | 
			
		||||
	tokenService := services.NewTokenService(tokenRepository)
 | 
			
		||||
	controller := controllers.NewAuthController(service)
 | 
			
		||||
 | 
			
		||||
	return &authRouter{
 | 
			
		||||
		db:              db,
 | 
			
		||||
		userRepository:  userRepository,
 | 
			
		||||
		tokenRepository: tokenRepository,
 | 
			
		||||
		service:         service,
 | 
			
		||||
		tokenService:    tokenService,
 | 
			
		||||
		controller:      controller,
 | 
			
		||||
		router:          router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *authRouter) SetAuthRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	group := router.Group("/auth")
 | 
			
		||||
	group.POST("login", r.controller.Login)
 | 
			
		||||
	group.POST("register", r.controller.Register)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								internal/routers/router.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								internal/routers/router.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
 | 
			
		||||
	"studioj/boilerplate_go/internal/database"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var Router *gin.Engine
 | 
			
		||||
 | 
			
		||||
func Init() {
 | 
			
		||||
	gin.SetMode(gin.ReleaseMode)
 | 
			
		||||
	Router = gin.Default()
 | 
			
		||||
	maindb := database.GetDB()
 | 
			
		||||
 | 
			
		||||
	InitAuthRouter(maindb, Router)
 | 
			
		||||
	InitTokenRouter(maindb, Router)
 | 
			
		||||
	InitUserRouter(maindb, Router)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								internal/routers/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								internal/routers/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"studioj/boilerplate_go/internal/controllers"
 | 
			
		||||
	"studioj/boilerplate_go/internal/repositories"
 | 
			
		||||
	"studioj/boilerplate_go/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TokenRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type tokenRouter struct {
 | 
			
		||||
	db         *gorm.DB
 | 
			
		||||
	repository repositories.TokenRepository
 | 
			
		||||
	service    services.TokenService
 | 
			
		||||
	controller controllers.TokenController
 | 
			
		||||
	router     *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InitTokenRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewTokenRouter(db, router)
 | 
			
		||||
	r.SetTokenRouter(db, router)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTokenRouter(db *gorm.DB, router *gin.Engine) *tokenRouter {
 | 
			
		||||
	repository := repositories.NewTokenRepository(db)
 | 
			
		||||
	service := services.NewTokenService(repository)
 | 
			
		||||
	controller := controllers.NewTokenController(service)
 | 
			
		||||
 | 
			
		||||
	return &tokenRouter{
 | 
			
		||||
		db:         db,
 | 
			
		||||
		repository: repository,
 | 
			
		||||
		service:    service,
 | 
			
		||||
		controller: controller,
 | 
			
		||||
		router:     router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *tokenRouter) SetTokenRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	// group := router.Group("/token")
 | 
			
		||||
	// group.GET("refresh", middleware.Auth(), r.controller.Refresh)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								internal/routers/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								internal/routers/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"studioj/boilerplate_go/internal/controllers"
 | 
			
		||||
	"studioj/boilerplate_go/internal/middleware"
 | 
			
		||||
	"studioj/boilerplate_go/internal/repositories"
 | 
			
		||||
	"studioj/boilerplate_go/internal/services"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UserRouter interface {
 | 
			
		||||
	SetRouter(db *gorm.DB, router *gin.Engine)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type userRouter struct {
 | 
			
		||||
	db         *gorm.DB
 | 
			
		||||
	repository repositories.UserRepository
 | 
			
		||||
	service    services.UserService
 | 
			
		||||
	controller controllers.UserController
 | 
			
		||||
	router     *gin.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InitUserRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	r := NewUserRouter(db, router)
 | 
			
		||||
	r.SetUserRouter(db, router)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserRouter(db *gorm.DB, router *gin.Engine) *userRouter {
 | 
			
		||||
	repository := repositories.NewUserRepository(db)
 | 
			
		||||
	tokenRepository := repositories.NewTokenRepository(db)
 | 
			
		||||
	service := services.NewUserService(repository, tokenRepository)
 | 
			
		||||
 | 
			
		||||
	tokenService := services.NewTokenService(tokenRepository)
 | 
			
		||||
	controller := controllers.NewUserController(service, tokenService)
 | 
			
		||||
 | 
			
		||||
	return &userRouter{
 | 
			
		||||
		db:         db,
 | 
			
		||||
		repository: repository,
 | 
			
		||||
		service:    service,
 | 
			
		||||
		controller: controller,
 | 
			
		||||
		router:     router,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *userRouter) SetUserRouter(db *gorm.DB, router *gin.Engine) {
 | 
			
		||||
	group := router.Group("/user")
 | 
			
		||||
	group.GET("/:id", middleware.Auth(), r.controller.Find)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								internal/services/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								internal/services/auth.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"studioj/boilerplate_go/internal/models"
 | 
			
		||||
	"studioj/boilerplate_go/internal/repositories"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"golang.org/x/crypto/bcrypt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type authService struct {
 | 
			
		||||
	userRepository  repositories.UserRepository
 | 
			
		||||
	tokenRepository repositories.TokenRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AuthService interface {
 | 
			
		||||
	Register(*models.RegisterRequest) (*models.User, error)
 | 
			
		||||
	Login(*models.LoginRequest) (*models.User, error)
 | 
			
		||||
	CreateToken(string) (*models.Token, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewAuthService(userRepository repositories.UserRepository, tokenRepository repositories.TokenRepository) AuthService {
 | 
			
		||||
	return &authService{
 | 
			
		||||
		userRepository:  userRepository,
 | 
			
		||||
		tokenRepository: tokenRepository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *authService) Register(request *models.RegisterRequest) (*models.User, error) {
 | 
			
		||||
	hash, err := bcrypt.GenerateFromPassword([]byte(request.Password), 10)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("fail to hash password")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create the user
 | 
			
		||||
	newUser := models.User{
 | 
			
		||||
		ID:       uuid.NewString(),
 | 
			
		||||
		Username: request.Username,
 | 
			
		||||
		Password: string(hash),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user, err := s.userRepository.Create(&newUser)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("fail to create user")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *authService) Login(request *models.LoginRequest) (*models.User, error) {
 | 
			
		||||
	user, err := s.userRepository.FindByUsername(request.Username)
 | 
			
		||||
	if err != nil || user == nil {
 | 
			
		||||
		return nil, errors.New("invalid user or password")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(request.Password))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("invalid user or password")
 | 
			
		||||
	}
 | 
			
		||||
	return user, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *authService) CreateToken(user_id string) (*models.Token, error) {
 | 
			
		||||
	tokenExpiredAt := time.Now().Add(time.Hour * 24 * 30)
 | 
			
		||||
	accessToken, err := s.tokenRepository.Generate(user_id, tokenExpiredAt.Unix())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	refreshExpiredAt := time.Now().Add(time.Hour * 24 * 90)
 | 
			
		||||
	refreshToken, err := s.tokenRepository.Generate(user_id, refreshExpiredAt.Unix())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newToken := &models.Token{
 | 
			
		||||
		ID:           uuid.NewString(),
 | 
			
		||||
		UserID:       user_id,
 | 
			
		||||
		Token:        accessToken,
 | 
			
		||||
		RefreshToken: refreshToken,
 | 
			
		||||
		Status:       "valid",
 | 
			
		||||
		ExpireAt:     tokenExpiredAt,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	token, err := s.tokenRepository.Create(newToken)
 | 
			
		||||
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										115
									
								
								internal/services/token.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								internal/services/token.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	config "studioj/boilerplate_go/configs"
 | 
			
		||||
	"studioj/boilerplate_go/internal/models"
 | 
			
		||||
	"studioj/boilerplate_go/internal/repositories"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang-jwt/jwt/v5"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type tokenService struct {
 | 
			
		||||
	repository repositories.TokenRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TokenService interface {
 | 
			
		||||
	Find(string) (*models.Token, error)
 | 
			
		||||
	Create(*models.Token) (*models.Token, error)
 | 
			
		||||
	Update(*models.Token) (*models.Token, error)
 | 
			
		||||
	Delete(string) error
 | 
			
		||||
 | 
			
		||||
	Generate(string, int64) (string, error)
 | 
			
		||||
	Verify(tokenString string) (*jwt.Token, error)
 | 
			
		||||
 | 
			
		||||
	GetJwtToken(string) (*jwt.Token, error)
 | 
			
		||||
	ExtractTokenString(string) string
 | 
			
		||||
	VerifyTokenString(string) (*jwt.Token, error)
 | 
			
		||||
	ValidToken(*jwt.Token) (bool, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTokenService(repository repositories.TokenRepository) TokenService {
 | 
			
		||||
	return &tokenService{
 | 
			
		||||
		repository: repository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Find(id string) (*models.Token, error) {
 | 
			
		||||
	return s.repository.Find(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Create(token *models.Token) (*models.Token, error) {
 | 
			
		||||
	return s.repository.Create(token)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Update(token *models.Token) (*models.Token, error) {
 | 
			
		||||
	return s.repository.Update(token)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Delete(id string) error {
 | 
			
		||||
	return s.repository.Delete(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Verify(tokenString string) (*jwt.Token, error) {
 | 
			
		||||
	jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
 | 
			
		||||
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
		return []byte(config.SECRET_KEY), nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return jwtToken, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) Generate(user_id string, expire_at int64) (string, error) {
 | 
			
		||||
	claims := jwt.MapClaims{}
 | 
			
		||||
	claims["authorized"] = true
 | 
			
		||||
	claims["sub"] = user_id
 | 
			
		||||
	claims["exp"] = expire_at
 | 
			
		||||
	at := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 | 
			
		||||
	token, err := at.SignedString([]byte(config.SECRET_KEY))
 | 
			
		||||
 | 
			
		||||
	return token, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) GetJwtToken(tokenString string) (*jwt.Token, error) {
 | 
			
		||||
	jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
 | 
			
		||||
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
		return []byte(config.SECRET_KEY), nil
 | 
			
		||||
	})
 | 
			
		||||
	return jwtToken, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) ExtractTokenString(authorization string) string {
 | 
			
		||||
	strArr := strings.Split(authorization, " ")
 | 
			
		||||
	if len(strArr) == 2 {
 | 
			
		||||
		return strArr[1]
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) VerifyTokenString(tokenString string) (*jwt.Token, error) {
 | 
			
		||||
	jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
 | 
			
		||||
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
 | 
			
		||||
			return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
 | 
			
		||||
		}
 | 
			
		||||
		return []byte(config.SECRET_KEY), nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return jwtToken, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *tokenService) ValidToken(jwtToken *jwt.Token) (bool, error) {
 | 
			
		||||
	if jwtToken == nil {
 | 
			
		||||
		return false, fmt.Errorf("no token")
 | 
			
		||||
	}
 | 
			
		||||
	return jwtToken.Valid, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								internal/services/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								internal/services/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
package services
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"studioj/boilerplate_go/internal/models"
 | 
			
		||||
	"studioj/boilerplate_go/internal/repositories"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type userService struct {
 | 
			
		||||
	repository      repositories.UserRepository
 | 
			
		||||
	tokenRepository repositories.TokenRepository
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserService interface {
 | 
			
		||||
	FindByID(string) (*models.User, error)
 | 
			
		||||
	FindByUsername(string) (*models.User, error)
 | 
			
		||||
	Create(*models.User) (*models.User, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUserService(repository repositories.UserRepository, tokenRepository repositories.TokenRepository) UserService {
 | 
			
		||||
	return &userService{
 | 
			
		||||
		repository:      repository,
 | 
			
		||||
		tokenRepository: tokenRepository,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userService) FindByID(id string) (*models.User, error) {
 | 
			
		||||
	return s.repository.FindByID(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userService) FindByUsername(username string) (*models.User, error) {
 | 
			
		||||
	return s.repository.FindByUsername(username)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *userService) Create(user *models.User) (*models.User, error) {
 | 
			
		||||
	result, err := s.repository.Create(user)
 | 
			
		||||
 | 
			
		||||
	return result, err
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user