feat: login service and implement database storage
This commit is contained in:
@@ -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,
|
||||
))
|
||||
@@ -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
|
||||
}
|
||||
@@ -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}
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package authhttp
|
||||
|
||||
import "go.uber.org/fx"
|
||||
|
||||
var Module = fx.Module("auth-api",
|
||||
fx.Invoke(
|
||||
LoginStaff,
|
||||
),
|
||||
)
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
)
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user