feat: login service and implement database storage

This commit is contained in:
ericprd
2025-02-23 22:34:26 +08:00
parent a95a5ca521
commit 5fcb5c2cd5
24 changed files with 576 additions and 8 deletions
+10
View File
@@ -0,0 +1,10 @@
package repository
import (
staffrepository "github.com/ardeman/project-legalgo-go/internal/accessor/staff"
"go.uber.org/fx"
)
var Module = fx.Module("repository", fx.Provide(
staffrepository.New,
))
+25
View File
@@ -0,0 +1,25 @@
package staffrepository
import (
"errors"
staffmodel "github.com/ardeman/project-legalgo-go/database/staff"
"gorm.io/gorm"
)
func (sr *StaffRepository) GetStaff(email string) (*staffmodel.Staff, error) {
var staff staffmodel.Staff
if email == "" {
return nil, errors.New("email is empty")
}
if err := sr.DB.Where("email = ?", email).First(&staff).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("staff not found")
}
return nil, err
}
return &staff, nil
}
+18
View File
@@ -0,0 +1,18 @@
package staffrepository
import (
"github.com/ardeman/project-legalgo-go/database"
staffmodel "github.com/ardeman/project-legalgo-go/database/staff"
)
type StaffRepository struct {
DB *database.DB
}
type StaffInterface interface {
GetStaff(string) (*staffmodel.Staff, error)
}
func New(db *database.DB) StaffInterface {
return &StaffRepository{db}
}
+67
View File
@@ -0,0 +1,67 @@
package authhttp
import (
"net/http"
domain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
serviceauth "github.com/ardeman/project-legalgo-go/internal/services/auth"
"github.com/ardeman/project-legalgo-go/internal/utilities/response"
"github.com/ardeman/project-legalgo-go/internal/utilities/utils"
"github.com/go-chi/chi/v5"
"github.com/go-playground/validator/v10"
)
func LoginStaff(
router chi.Router,
authSvc serviceauth.LoginStaffIntf,
validate *validator.Validate,
) {
router.Post("/staff/login", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var request domain.StaffLoginReq
if err := utils.UnmarshalBody(r, &request); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"failed to unmarshal request",
)
return
}
if err := validate.Struct(request); err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.(validator.ValidationErrors).Error(),
)
return
}
token, err := authSvc.LoginAsStaff(request.Email)
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
responsePayload := &domain.StaffLoginResponse{
Token: token,
}
response.RespondJsonSuccess(ctx, w, responsePayload)
})
}
+9
View File
@@ -0,0 +1,9 @@
package authhttp
import "go.uber.org/fx"
var Module = fx.Module("auth-api",
fx.Invoke(
LoginStaff,
),
)
+7 -1
View File
@@ -1,15 +1,21 @@
package internalhttp
import (
authhttp "github.com/ardeman/project-legalgo-go/internal/api/http/auth"
"github.com/go-chi/chi/v5"
"github.com/go-chi/cors"
"github.com/go-playground/validator/v10"
"go.uber.org/fx"
chimware "github.com/go-chi/chi/v5/middleware"
)
var Module = fx.Module("router",
fx.Provide(initRouter),
fx.Provide(
initRouter,
validator.New,
),
authhttp.Module,
)
func initRouter() chi.Router {
+10
View File
@@ -0,0 +1,10 @@
package domain
type StaffLoginReq struct {
Email string `json:"email" validate:"required"`
Password string `json:"password" validate:"required"`
}
type StaffLoginResponse struct {
Token string `json:"token"`
}
+19
View File
@@ -0,0 +1,19 @@
package serviceauth
import staffrepository "github.com/ardeman/project-legalgo-go/internal/accessor/staff"
type LoginStaffSvc struct {
staffAcs staffrepository.StaffInterface
}
type LoginStaffIntf interface {
LoginAsStaff(string) (string, error)
}
func New(
staffAcs staffrepository.StaffInterface,
) LoginStaffIntf {
return &LoginStaffSvc{
staffAcs: staffAcs,
}
}
+21
View File
@@ -0,0 +1,21 @@
package serviceauth
import (
"errors"
"github.com/ardeman/project-legalgo-go/internal/utilities/utils"
)
func (sv *LoginStaffSvc) LoginAsStaff(email string) (string, error) {
staff, err := sv.staffAcs.GetStaff(email)
if err != nil {
return "", errors.New(err.Error())
}
token, err := utils.GenerateToken2(staff.Email)
if err != nil {
return "", errors.New(err.Error())
}
return token, nil
}
+12
View File
@@ -0,0 +1,12 @@
package services
import (
serviceauth "github.com/ardeman/project-legalgo-go/internal/services/auth"
"go.uber.org/fx"
)
var Module = fx.Module("services",
fx.Provide(
serviceauth.New,
),
)
+15
View File
@@ -0,0 +1,15 @@
package response
import "net/http"
type ErrorCode struct {
Code string
Message string
HttpCode int
}
var (
// 4xx
ErrBadRequest = ErrorCode{Code: "BAD_REQUEST", Message: "BAD_REQUEST", HttpCode: http.StatusBadRequest}
ErrDBRequest = ErrorCode{Code: "BAD_DB_REQUEST", Message: "DB_ERROR", HttpCode: http.StatusBadRequest}
)
@@ -0,0 +1,23 @@
package response
import (
"context"
"encoding/json"
"net/http"
)
func ResponseWithErrorCode(ctx context.Context, w http.ResponseWriter,
err error, code string, statusCode int, message string) {
setDefaultHeaders(ctx, w.Header())
w.WriteHeader(statusCode)
b, _ := json.Marshal(ErrorResponse{
Error: ErrorResponseData{
Code: code,
Message: message,
},
})
w.Write(b)
}
@@ -0,0 +1,19 @@
package response
import (
"context"
"net/http"
)
type ErrorResponseData struct {
Code string `json:"code"`
Message string `json:"message"`
}
type ErrorResponse struct {
Error ErrorResponseData `json:"error"`
}
func setDefaultHeaders(ctx context.Context, headers http.Header) {
headers.Set("Content-Type", "application/json")
}
+23
View File
@@ -0,0 +1,23 @@
package response
import (
"context"
"encoding/json"
"net/http"
)
type Response[T any] struct {
Data T `json:"data"`
}
func RespondJsonSuccess[T any](ctx context.Context, w http.ResponseWriter, data T) {
setDefaultHeaders(ctx, w.Header())
w.WriteHeader(http.StatusOK)
b, _ := json.Marshal(Response[T]{
Data: data,
})
w.Write(b)
}
+21
View File
@@ -0,0 +1,21 @@
package utils
import (
"encoding/json"
"io"
"net/http"
)
func UnmarshalBody(r *http.Request, v any) error {
body, err := io.ReadAll(r.Body)
if err != nil {
return err
}
err = json.Unmarshal(body, v)
if err != nil {
return err
}
return nil
}
+3 -3
View File
@@ -28,11 +28,11 @@ func GenerateToken(options ...ClaimOption) (string, error) {
return token.SignedString(jwtSecret)
}
func GenerateToken2(username string) (string, error) {
func GenerateToken2(email string) (string, error) {
now := timeutils.Now()
token := jwt.New(jwt.SigningMethodES256)
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["username"] = username
claims["email"] = email
claims["exp"] = now.Add(time.Hour).Unix()
return token.SignedString(jwtSecret)