feat: CR login, register, subscribe
This commit is contained in:
parent
ae5b2cb975
commit
cb3d06fa02
@ -5,6 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
staffmodel "github.com/ardeman/project-legalgo-go/database/staff"
|
staffmodel "github.com/ardeman/project-legalgo-go/database/staff"
|
||||||
|
subsmodel "github.com/ardeman/project-legalgo-go/database/subscribe"
|
||||||
|
usermodel "github.com/ardeman/project-legalgo-go/database/user"
|
||||||
"gorm.io/driver/postgres"
|
"gorm.io/driver/postgres"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -39,5 +41,10 @@ func NewDB() (*DB, error) {
|
|||||||
|
|
||||||
func (db *DB) Migrate() error {
|
func (db *DB) Migrate() error {
|
||||||
// Auto Migrate the User model
|
// Auto Migrate the User model
|
||||||
return db.AutoMigrate(&staffmodel.Staff{})
|
return db.AutoMigrate(
|
||||||
|
&staffmodel.Staff{},
|
||||||
|
&subsmodel.SubscribePlan{},
|
||||||
|
&subsmodel.Subscribe{},
|
||||||
|
&usermodel.User{},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
package staffmodel
|
package staffmodel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Staff struct {
|
type Staff struct {
|
||||||
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
|
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
|
||||||
Email string `gorm:"unique,not null" json:"email"`
|
Email string `gorm:"unique,not null" json:"email"`
|
||||||
Password string `gorm:"not null" json:"password"`
|
Password string `gorm:"not null" json:"password"`
|
||||||
|
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||||
|
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|||||||
27
database/subscribe/model.go
Normal file
27
database/subscribe/model.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package subsmodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Subscribe struct {
|
||||||
|
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
|
||||||
|
SubscribePlanID uuid.UUID `gorm:"type:uuid;not null" json:"subscribe_plan_id"`
|
||||||
|
StartDate time.Time `gorm:"default:CURRENT_TIMESTAMP"`
|
||||||
|
EndDate time.Time `gorm:"default:null"`
|
||||||
|
Status string `gorm:"default:'inactive'"`
|
||||||
|
AutoRenew bool `gorm:"default:true"`
|
||||||
|
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
|
||||||
|
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
|
||||||
|
|
||||||
|
SubscribePlan SubscribePlan `gorm:"foreignKey:SubscribePlanID;constraint:OnDelete:CASCADE"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubscribePlan struct {
|
||||||
|
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
|
||||||
|
Code string `gorm:"not null" json:"code"`
|
||||||
|
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
|
||||||
|
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
|
||||||
|
}
|
||||||
19
database/user/model.go
Normal file
19
database/user/model.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package usermodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
subsmodel "github.com/ardeman/project-legalgo-go/database/subscribe"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
|
||||||
|
SubscribeID string `gorm:"not null" json:"subscribe_id"`
|
||||||
|
Email string `gorm:"unique,not null" json:"email"`
|
||||||
|
Password string `gorm:"not null" json:"password"`
|
||||||
|
Phone string `gorm:"default:null" json:"phone"`
|
||||||
|
Subscribe subsmodel.Subscribe `gorm:"foreignKey:SubscribeID;constraint:OnDelete:CASCADE"`
|
||||||
|
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
|
||||||
|
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
|
||||||
|
}
|
||||||
@ -1,10 +1,18 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
redisaccessor "github.com/ardeman/project-legalgo-go/internal/accessor/redis"
|
||||||
staffrepository "github.com/ardeman/project-legalgo-go/internal/accessor/staff"
|
staffrepository "github.com/ardeman/project-legalgo-go/internal/accessor/staff"
|
||||||
|
subscriberepository "github.com/ardeman/project-legalgo-go/internal/accessor/subscribe"
|
||||||
|
subscribeplanrepository "github.com/ardeman/project-legalgo-go/internal/accessor/subscribeplan"
|
||||||
|
userrepository "github.com/ardeman/project-legalgo-go/internal/accessor/user_repository"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Module = fx.Module("repository", fx.Provide(
|
var Module = fx.Module("repository", fx.Provide(
|
||||||
staffrepository.New,
|
staffrepository.New,
|
||||||
|
userrepository.New,
|
||||||
|
redisaccessor.New,
|
||||||
|
subscribeplanrepository.New,
|
||||||
|
subscriberepository.New,
|
||||||
))
|
))
|
||||||
|
|||||||
32
internal/accessor/redis/impl.go
Normal file
32
internal/accessor/redis/impl.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package redisaccessor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
var redisClient *redis.Client
|
||||||
|
|
||||||
|
func Get() *redis.Client {
|
||||||
|
return redisClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *redis.Client {
|
||||||
|
var (
|
||||||
|
username = os.Getenv("REDIS_USERNAME")
|
||||||
|
addr = fmt.Sprintf("%s:%s", os.Getenv("REDIS_HOST"), os.Getenv("REDIS_PORT"))
|
||||||
|
password = os.Getenv("REDIS_PASSWORD")
|
||||||
|
db = 2 // TODO: change later
|
||||||
|
)
|
||||||
|
|
||||||
|
redisClient = redis.NewClient(&redis.Options{
|
||||||
|
Username: username,
|
||||||
|
Addr: addr,
|
||||||
|
Password: password,
|
||||||
|
DB: db,
|
||||||
|
})
|
||||||
|
|
||||||
|
return redisClient
|
||||||
|
}
|
||||||
11
internal/accessor/staff/create_staff.go
Normal file
11
internal/accessor/staff/create_staff.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package staffrepository
|
||||||
|
|
||||||
|
import authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
|
|
||||||
|
func (ur *StaffRepository) Create(spec *authdomain.Staff) (*authdomain.Staff, error) {
|
||||||
|
if err := ur.DB.Create(&spec).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec, nil
|
||||||
|
}
|
||||||
@ -3,12 +3,12 @@ package staffrepository
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
staffmodel "github.com/ardeman/project-legalgo-go/database/staff"
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (sr *StaffRepository) GetStaff(email string) (*staffmodel.Staff, error) {
|
func (sr *StaffRepository) GetStaffByEmail(email string) (*authdomain.LoginRepoResponse, error) {
|
||||||
var staff staffmodel.Staff
|
var staff authdomain.LoginRepoResponse
|
||||||
|
|
||||||
if email == "" {
|
if email == "" {
|
||||||
return nil, errors.New("email is empty")
|
return nil, errors.New("email is empty")
|
||||||
|
|||||||
@ -2,17 +2,18 @@ package staffrepository
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ardeman/project-legalgo-go/database"
|
"github.com/ardeman/project-legalgo-go/database"
|
||||||
staffmodel "github.com/ardeman/project-legalgo-go/database/staff"
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StaffRepository struct {
|
type StaffRepository struct {
|
||||||
DB *database.DB
|
DB *database.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
type StaffInterface interface {
|
type StaffIntf interface {
|
||||||
GetStaff(string) (*staffmodel.Staff, error)
|
GetStaffByEmail(string) (*authdomain.LoginRepoResponse, error)
|
||||||
|
Create(*authdomain.Staff) (*authdomain.Staff, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(db *database.DB) StaffInterface {
|
func New(db *database.DB) StaffIntf {
|
||||||
return &StaffRepository{db}
|
return &StaffRepository{db}
|
||||||
}
|
}
|
||||||
|
|||||||
19
internal/accessor/subscribe/create.go
Normal file
19
internal/accessor/subscribe/create.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package subscriberepository
|
||||||
|
|
||||||
|
import (
|
||||||
|
subscribedomain "github.com/ardeman/project-legalgo-go/internal/domain/subscribe"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *SubsAccs) Create(subsPlanId string) (string, error) {
|
||||||
|
spec := &subscribedomain.Subscribe{
|
||||||
|
ID: uuid.New(),
|
||||||
|
SubscribePlanID: subsPlanId,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.DB.Create(&spec).Error; err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec.ID.String(), nil
|
||||||
|
}
|
||||||
15
internal/accessor/subscribe/impl.go
Normal file
15
internal/accessor/subscribe/impl.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package subscriberepository
|
||||||
|
|
||||||
|
import "github.com/ardeman/project-legalgo-go/database"
|
||||||
|
|
||||||
|
type SubsAccs struct {
|
||||||
|
DB *database.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubsIntf interface {
|
||||||
|
Create(string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(db *database.DB) SubsIntf {
|
||||||
|
return &SubsAccs{db}
|
||||||
|
}
|
||||||
19
internal/accessor/subscribeplan/create.go
Normal file
19
internal/accessor/subscribeplan/create.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package subscribeplanrepository
|
||||||
|
|
||||||
|
import (
|
||||||
|
subscribeplandomain "github.com/ardeman/project-legalgo-go/internal/domain/subscribe_plan"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *SubsPlan) Create(code string) error {
|
||||||
|
spec := &subscribeplandomain.SubscribePlan{
|
||||||
|
ID: uuid.New(),
|
||||||
|
Code: code,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.DB.Create(&spec).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
17
internal/accessor/subscribeplan/impl.go
Normal file
17
internal/accessor/subscribeplan/impl.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package subscribeplanrepository
|
||||||
|
|
||||||
|
import "github.com/ardeman/project-legalgo-go/database"
|
||||||
|
|
||||||
|
type SubsPlan struct {
|
||||||
|
DB *database.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubsPlanIntf interface {
|
||||||
|
Create(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(
|
||||||
|
db *database.DB,
|
||||||
|
) SubsPlanIntf {
|
||||||
|
return &SubsPlan{db}
|
||||||
|
}
|
||||||
13
internal/accessor/user_repository/create_user.go
Normal file
13
internal/accessor/user_repository/create_user.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package userrepository
|
||||||
|
|
||||||
|
import (
|
||||||
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ur *UserRepository) CreateUser(spec *authdomain.User) (*authdomain.User, error) {
|
||||||
|
if err := ur.DB.Create(&spec).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec, nil
|
||||||
|
}
|
||||||
25
internal/accessor/user_repository/get_user.go
Normal file
25
internal/accessor/user_repository/get_user.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package userrepository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
usermodel "github.com/ardeman/project-legalgo-go/database/user"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ur *UserRepository) GetUserByEmail(email string) (*usermodel.User, error) {
|
||||||
|
var user usermodel.User
|
||||||
|
|
||||||
|
if email == "" {
|
||||||
|
return nil, errors.New("email is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ur.DB.Where("email = ?", email).First(&user).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, errors.New("user not found")
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
22
internal/accessor/user_repository/impl.go
Normal file
22
internal/accessor/user_repository/impl.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package userrepository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ardeman/project-legalgo-go/database"
|
||||||
|
usermodel "github.com/ardeman/project-legalgo-go/database/user"
|
||||||
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserRepository struct {
|
||||||
|
DB *database.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserIntf interface {
|
||||||
|
GetUserByEmail(string) (*usermodel.User, error)
|
||||||
|
CreateUser(*authdomain.User) (*authdomain.User, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(
|
||||||
|
db *database.DB,
|
||||||
|
) UserIntf {
|
||||||
|
return &UserRepository{db}
|
||||||
|
}
|
||||||
@ -3,8 +3,8 @@ package authhttp
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
domain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
serviceauth "github.com/ardeman/project-legalgo-go/internal/services/auth"
|
authsvc "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/response"
|
||||||
"github.com/ardeman/project-legalgo-go/internal/utilities/utils"
|
"github.com/ardeman/project-legalgo-go/internal/utilities/utils"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
@ -13,15 +13,15 @@ import (
|
|||||||
|
|
||||||
func LoginStaff(
|
func LoginStaff(
|
||||||
router chi.Router,
|
router chi.Router,
|
||||||
authSvc serviceauth.LoginStaffIntf,
|
authSvc authsvc.AuthIntf,
|
||||||
validate *validator.Validate,
|
validate *validator.Validate,
|
||||||
) {
|
) {
|
||||||
router.Post("/staff/login", func(w http.ResponseWriter, r *http.Request) {
|
router.Post("/staff/login", func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
var request domain.StaffLoginReq
|
var spec authdomain.LoginReq
|
||||||
|
|
||||||
if err := utils.UnmarshalBody(r, &request); err != nil {
|
if err := utils.UnmarshalBody(r, &spec); err != nil {
|
||||||
response.ResponseWithErrorCode(
|
response.ResponseWithErrorCode(
|
||||||
ctx,
|
ctx,
|
||||||
w,
|
w,
|
||||||
@ -33,7 +33,7 @@ func LoginStaff(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validate.Struct(request); err != nil {
|
if err := validate.Struct(spec); err != nil {
|
||||||
response.ResponseWithErrorCode(
|
response.ResponseWithErrorCode(
|
||||||
ctx,
|
ctx,
|
||||||
w,
|
w,
|
||||||
@ -45,7 +45,7 @@ func LoginStaff(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := authSvc.LoginAsStaff(request.Email)
|
token, err := authSvc.LoginAsStaff(spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.ResponseWithErrorCode(
|
response.ResponseWithErrorCode(
|
||||||
ctx,
|
ctx,
|
||||||
@ -58,7 +58,62 @@ func LoginStaff(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
responsePayload := &domain.StaffLoginResponse{
|
responsePayload := &authdomain.LoginResponse{
|
||||||
|
Token: token,
|
||||||
|
}
|
||||||
|
|
||||||
|
response.RespondJsonSuccess(ctx, w, responsePayload)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoginUser(
|
||||||
|
router chi.Router,
|
||||||
|
authSvc authsvc.AuthIntf,
|
||||||
|
validate *validator.Validate,
|
||||||
|
) {
|
||||||
|
router.Post("/user/login", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
var spec authdomain.LoginReq
|
||||||
|
|
||||||
|
if err := utils.UnmarshalBody(r, &spec); err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
"failed to unmarshal request",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(spec); err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
err.(validator.ValidationErrors).Error(),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := authSvc.LoginAsUser(spec)
|
||||||
|
if err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
responsePayload := &authdomain.LoginResponse{
|
||||||
Token: token,
|
Token: token,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,5 +5,8 @@ import "go.uber.org/fx"
|
|||||||
var Module = fx.Module("auth-api",
|
var Module = fx.Module("auth-api",
|
||||||
fx.Invoke(
|
fx.Invoke(
|
||||||
LoginStaff,
|
LoginStaff,
|
||||||
|
LoginUser,
|
||||||
|
RegisterUser,
|
||||||
|
RegisterStaff,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
114
internal/api/http/auth/register.go
Normal file
114
internal/api/http/auth/register.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package authhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
|
authsvc "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 RegisterUser(
|
||||||
|
router chi.Router,
|
||||||
|
validate *validator.Validate,
|
||||||
|
authSvc authsvc.AuthIntf,
|
||||||
|
) {
|
||||||
|
router.Post("/user/register", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
var spec authdomain.RegisterUserReq
|
||||||
|
|
||||||
|
if err := utils.UnmarshalBody(r, &spec); err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
"failed to unmarshal request",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(spec); err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
err.(validator.ValidationErrors).Error(),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := authSvc.RegisterUser(spec)
|
||||||
|
if err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.RespondJsonSuccess(ctx, w, token)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterStaff(
|
||||||
|
router chi.Router,
|
||||||
|
validate *validator.Validate,
|
||||||
|
authSvc authsvc.AuthIntf,
|
||||||
|
) {
|
||||||
|
router.Post("/staff/register", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
var spec authdomain.RegisterStaffReq
|
||||||
|
|
||||||
|
if err := utils.UnmarshalBody(r, &spec); err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
"failed to unmarshal request",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(spec); err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
err.(validator.ValidationErrors).Error(),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := authSvc.RegisterStaff(spec)
|
||||||
|
if err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.RespondJsonSuccess(ctx, w, token)
|
||||||
|
})
|
||||||
|
}
|
||||||
138
internal/api/http/middleware/auth/authorize.go
Normal file
138
internal/api/http/middleware/auth/authorize.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package authmiddleware
|
||||||
|
|
||||||
|
// import (
|
||||||
|
// "context"
|
||||||
|
// "fmt"
|
||||||
|
// "net/http"
|
||||||
|
// "strings"
|
||||||
|
|
||||||
|
// redisaccessor "github.com/ardeman/project-legalgo-go/internal/accessor/redis"
|
||||||
|
// contextkeyenum "github.com/ardeman/project-legalgo-go/internal/enums/context_key"
|
||||||
|
// jwtclaimenum "github.com/ardeman/project-legalgo-go/internal/enums/jwt"
|
||||||
|
// resourceenum "github.com/ardeman/project-legalgo-go/internal/enums/resource"
|
||||||
|
// "github.com/ardeman/project-legalgo-go/internal/services/auth"
|
||||||
|
// "github.com/golang-jwt/jwt/v5"
|
||||||
|
// )
|
||||||
|
|
||||||
|
// const SessionHeader = "Authorization"
|
||||||
|
|
||||||
|
// func Authorization() func(next http.Handler) http.Handler {
|
||||||
|
// return func(next http.Handler) http.Handler {
|
||||||
|
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ctx := r.Context()
|
||||||
|
|
||||||
|
// tokenString, err := GetToken(r)
|
||||||
|
// if err != nil {
|
||||||
|
// RespondWithError(w, r, err, "Invalid auth header")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// token, err := ValidateToken(ctx, tokenString)
|
||||||
|
// if err != nil {
|
||||||
|
// RespondWithError(w, r, err, err.Error())
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if isAuthorized, ctx := VerifyClaims(ctx, token, nil); !isAuthorized {
|
||||||
|
// RespondWithError(w, r, errorcode.ErrCodeUnauthorized, errorcode.ErrCodeUnauthorized.Message)
|
||||||
|
// return
|
||||||
|
// } else {
|
||||||
|
// next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func GetToken(r *http.Request) (string, error) {
|
||||||
|
// tokenString := GetTokenFromHeader(r)
|
||||||
|
// if tokenString == "" {
|
||||||
|
// tokenString = getTokenFromQuery(r)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if tokenString == "" {
|
||||||
|
// return "", fmt.Errorf("token not found")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return tokenString, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func GetTokenFromHeader(r *http.Request) string {
|
||||||
|
// session := r.Header.Get(SessionHeader)
|
||||||
|
// arr := strings.Split(session, " ")
|
||||||
|
|
||||||
|
// if len(arr) != 2 || strings.ToUpper(arr[0]) != "BEARER" {
|
||||||
|
// return ""
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return arr[1]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func getTokenFromQuery(r *http.Request) string {
|
||||||
|
// token := r.URL.Query().Get("token")
|
||||||
|
// return token
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func VerifyClaims(ctx context.Context, token *jwt.Token,
|
||||||
|
// requiredResources []resourceenum.Resource) (bool, context.Context) {
|
||||||
|
// if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||||
|
// rawResources := []interface{}{}
|
||||||
|
// if claimValue, exist := claims[string(jwtclaimenum.RESOURCES)]; exist {
|
||||||
|
// rawResources = claimValue.([]interface{})
|
||||||
|
// }
|
||||||
|
|
||||||
|
// resources := []resourceenum.Resource{}
|
||||||
|
// resourceMap := map[string]bool{}
|
||||||
|
|
||||||
|
// for _, v := range rawResources {
|
||||||
|
// value := v.(string)
|
||||||
|
// resources = append(resources, resourceenum.Resource(value))
|
||||||
|
// resourceMap[value] = true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ctx = context.WithValue(ctx, contextkeyenum.Authorization, UserAuthorization{
|
||||||
|
// Type: claims[string(jwtclaimenum.TYPE)].(string),
|
||||||
|
// UserId: claims[string(jwtclaimenum.AUDIENCE)].(string),
|
||||||
|
// Username: claims[string(jwtclaimenum.USERNAME)].(string),
|
||||||
|
// Resources: resources,
|
||||||
|
// })
|
||||||
|
|
||||||
|
// isResourceFulfilled := false
|
||||||
|
|
||||||
|
// for _, v := range requiredResources {
|
||||||
|
// if _, ok := resourceMap[string(v)]; ok {
|
||||||
|
// isResourceFulfilled = true
|
||||||
|
// ctx = context.WithValue(ctx, contextkeyenum.Resource, v)
|
||||||
|
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if isResourceFulfilled || len(requiredResources) == 0 {
|
||||||
|
// return true, ctx
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return false, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func ValidateToken(ctx context.Context, tokenString string) (*jwt.Token, error) {
|
||||||
|
// redisClient := redisaccessor.Get()
|
||||||
|
// redisToken, err := redisClient.Exists(ctx, fmt.Sprintf("%s:%s", auth.BLACKLISTED_TOKEN_KEY, tokenString)).Result()
|
||||||
|
|
||||||
|
// if err != nil || redisToken > 0 {
|
||||||
|
// return nil, fmt.Errorf("session already expired")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// token, err := jwt.Parse(tokenString, authsvc.VerifyToken(conf.JWTAccessToken))
|
||||||
|
// if err != nil {
|
||||||
|
// if ve, ok := err.(*jwt.ValidationError); ok {
|
||||||
|
// if ve.Errors&jwt.ValidationErrorExpired != 0 {
|
||||||
|
// err = errorcode.ErrCodeExpiredToken
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return token, nil
|
||||||
|
// }
|
||||||
@ -2,6 +2,7 @@ package internalhttp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
authhttp "github.com/ardeman/project-legalgo-go/internal/api/http/auth"
|
authhttp "github.com/ardeman/project-legalgo-go/internal/api/http/auth"
|
||||||
|
subscribeplanhttp "github.com/ardeman/project-legalgo-go/internal/api/http/subscribe_plan"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/cors"
|
"github.com/go-chi/cors"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
@ -16,6 +17,7 @@ var Module = fx.Module("router",
|
|||||||
validator.New,
|
validator.New,
|
||||||
),
|
),
|
||||||
authhttp.Module,
|
authhttp.Module,
|
||||||
|
subscribeplanhttp.Module,
|
||||||
)
|
)
|
||||||
|
|
||||||
func initRouter() chi.Router {
|
func initRouter() chi.Router {
|
||||||
|
|||||||
66
internal/api/http/subscribe_plan/create.go
Normal file
66
internal/api/http/subscribe_plan/create.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package subscribeplanhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
subscribeplandomain "github.com/ardeman/project-legalgo-go/internal/domain/subscribe_plan"
|
||||||
|
subscribeplansvc "github.com/ardeman/project-legalgo-go/internal/services/subscribe_plan"
|
||||||
|
"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 CreateSubscribePlan(
|
||||||
|
router chi.Router,
|
||||||
|
validate *validator.Validate,
|
||||||
|
subsSvc subscribeplansvc.SubsPlanIntf,
|
||||||
|
) {
|
||||||
|
router.Post("/subscribe-plan/create", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
var spec subscribeplandomain.SubscribePlanReq
|
||||||
|
|
||||||
|
if err := utils.UnmarshalBody(r, &spec); err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
"failed to unmarshal request",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(spec); err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrBadRequest.Code,
|
||||||
|
response.ErrBadRequest.HttpCode,
|
||||||
|
err.(validator.ValidationErrors).Error(),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := subsSvc.CreatePlan(spec.Code); err != nil {
|
||||||
|
response.ResponseWithErrorCode(
|
||||||
|
ctx,
|
||||||
|
w,
|
||||||
|
err,
|
||||||
|
response.ErrCreateEntity.Code,
|
||||||
|
response.ErrCreateEntity.HttpCode,
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.RespondJsonSuccess(ctx, w, struct {
|
||||||
|
Message string
|
||||||
|
}{
|
||||||
|
Message: "success",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
9
internal/api/http/subscribe_plan/module.go
Normal file
9
internal/api/http/subscribe_plan/module.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package subscribeplanhttp
|
||||||
|
|
||||||
|
import "go.uber.org/fx"
|
||||||
|
|
||||||
|
var Module = fx.Module("subscribe-plan",
|
||||||
|
fx.Invoke(
|
||||||
|
CreateSubscribePlan,
|
||||||
|
),
|
||||||
|
)
|
||||||
@ -16,7 +16,7 @@ import (
|
|||||||
func Router(apiRouter chi.Router) {
|
func Router(apiRouter chi.Router) {
|
||||||
mainRouter := chi.NewRouter()
|
mainRouter := chi.NewRouter()
|
||||||
|
|
||||||
mainRouter.Mount("/", apiRouter)
|
mainRouter.Mount("/api", apiRouter)
|
||||||
mainCtx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
mainCtx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
defer stop()
|
defer stop()
|
||||||
|
|
||||||
|
|||||||
18
internal/domain/auth/login.go
Normal file
18
internal/domain/auth/login.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package authdomain
|
||||||
|
|
||||||
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
|
type LoginReq struct {
|
||||||
|
Email string `json:"email" validate:"required"`
|
||||||
|
Password string `json:"password" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginResponse struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginRepoResponse struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
29
internal/domain/auth/register.go
Normal file
29
internal/domain/auth/register.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package authdomain
|
||||||
|
|
||||||
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
|
type RegisterUserReq struct {
|
||||||
|
Email string `json:"email" validate:"required"`
|
||||||
|
Password string `json:"password" validate:"required"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
SubscribePlanID string `json:"subscribe_plan_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
SubscribeID string `json:"subscribe_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegisterStaffReq struct {
|
||||||
|
Email string `json:"email" validate:"required"`
|
||||||
|
Password string `json:"password" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Staff struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
Email string `json:"email" validate:"required"`
|
||||||
|
Password string `json:"password" validate:"required"`
|
||||||
|
}
|
||||||
@ -1,10 +0,0 @@
|
|||||||
package domain
|
|
||||||
|
|
||||||
type StaffLoginReq struct {
|
|
||||||
Email string `json:"email" validate:"required"`
|
|
||||||
Password string `json:"password" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type StaffLoginResponse struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
}
|
|
||||||
9
internal/domain/caching/spec.go
Normal file
9
internal/domain/caching/spec.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package cachingdomain
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type CacheSpec struct {
|
||||||
|
Key string
|
||||||
|
TTL time.Duration
|
||||||
|
Data any
|
||||||
|
}
|
||||||
8
internal/domain/subscribe/spec.go
Normal file
8
internal/domain/subscribe/spec.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package subscribedomain
|
||||||
|
|
||||||
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
|
type Subscribe struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
SubscribePlanID string `json:"subscribe_plan_id"`
|
||||||
|
}
|
||||||
12
internal/domain/subscribe_plan/spec.go
Normal file
12
internal/domain/subscribe_plan/spec.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package subscribeplandomain
|
||||||
|
|
||||||
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
|
type SubscribePlanReq struct {
|
||||||
|
Code string `json:"code" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubscribePlan struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
}
|
||||||
8
internal/enums/context_key/context_key.go
Normal file
8
internal/enums/context_key/context_key.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package contextkeyenum
|
||||||
|
|
||||||
|
type ContextKey string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Authorization ContextKey = "AUTHORIZATION_CONTEXT"
|
||||||
|
Resource ContextKey = "RESOURCE_CONTEXT"
|
||||||
|
)
|
||||||
@ -8,4 +8,5 @@ const (
|
|||||||
EXPIRED_AT JWTClaim = "exp"
|
EXPIRED_AT JWTClaim = "exp"
|
||||||
SESSION_ID JWTClaim = "sid"
|
SESSION_ID JWTClaim = "sid"
|
||||||
ISSUED_AT JWTClaim = "iat"
|
ISSUED_AT JWTClaim = "iat"
|
||||||
|
RESOURCES JWTClaim = "resources"
|
||||||
)
|
)
|
||||||
|
|||||||
3
internal/enums/resource/resource.go
Normal file
3
internal/enums/resource/resource.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package resourceenum
|
||||||
|
|
||||||
|
type Resource string
|
||||||
@ -1,19 +1,33 @@
|
|||||||
package serviceauth
|
package authsvc
|
||||||
|
|
||||||
import staffrepository "github.com/ardeman/project-legalgo-go/internal/accessor/staff"
|
import (
|
||||||
|
staffrepository "github.com/ardeman/project-legalgo-go/internal/accessor/staff"
|
||||||
|
subscriberepository "github.com/ardeman/project-legalgo-go/internal/accessor/subscribe"
|
||||||
|
userrepository "github.com/ardeman/project-legalgo-go/internal/accessor/user_repository"
|
||||||
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
|
)
|
||||||
|
|
||||||
type LoginStaffSvc struct {
|
type AuthSvc struct {
|
||||||
staffAcs staffrepository.StaffInterface
|
staffRepo staffrepository.StaffIntf
|
||||||
|
userRepo userrepository.UserIntf
|
||||||
|
subsRepo subscriberepository.SubsIntf
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginStaffIntf interface {
|
type AuthIntf interface {
|
||||||
LoginAsStaff(string) (string, error)
|
LoginAsStaff(authdomain.LoginReq) (string, error)
|
||||||
|
LoginAsUser(authdomain.LoginReq) (string, error)
|
||||||
|
RegisterUser(authdomain.RegisterUserReq) (string, error)
|
||||||
|
RegisterStaff(authdomain.RegisterStaffReq) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
staffAcs staffrepository.StaffInterface,
|
staffRepo staffrepository.StaffIntf,
|
||||||
) LoginStaffIntf {
|
userRepo userrepository.UserIntf,
|
||||||
return &LoginStaffSvc{
|
subsRepo subscriberepository.SubsIntf,
|
||||||
staffAcs: staffAcs,
|
) AuthIntf {
|
||||||
|
return &AuthSvc{
|
||||||
|
staffRepo: staffRepo,
|
||||||
|
userRepo: userRepo,
|
||||||
|
subsRepo: subsRepo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,24 @@
|
|||||||
package serviceauth
|
package authsvc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
"github.com/ardeman/project-legalgo-go/internal/utilities/utils"
|
"github.com/ardeman/project-legalgo-go/internal/utilities/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (sv *LoginStaffSvc) LoginAsStaff(email string) (string, error) {
|
func (sv *AuthSvc) LoginAsStaff(spec authdomain.LoginReq) (string, error) {
|
||||||
staff, err := sv.staffAcs.GetStaff(email)
|
staff, err := sv.staffRepo.GetStaffByEmail(spec.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New(err.Error())
|
return "", errors.New(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := utils.GenerateToken2(staff.Email)
|
matchPassword := ComparePassword(staff.Password, spec.Password)
|
||||||
|
if !matchPassword {
|
||||||
|
return "", errors.New("wrong password")
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := utils.GenerateToken(staff.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New(err.Error())
|
return "", errors.New(err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
27
internal/services/auth/login_as_user.go
Normal file
27
internal/services/auth/login_as_user.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package authsvc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
|
"github.com/ardeman/project-legalgo-go/internal/utilities/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (sv *AuthSvc) LoginAsUser(spec authdomain.LoginReq) (string, error) {
|
||||||
|
user, err := sv.userRepo.GetUserByEmail(spec.Email)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
matchPassword := ComparePassword(user.Password, spec.Password)
|
||||||
|
if !matchPassword {
|
||||||
|
return "", errors.New("wrong password")
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := utils.GenerateToken(user.Email)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
33
internal/services/auth/register_staff.go
Normal file
33
internal/services/auth/register_staff.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package authsvc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
|
"github.com/ardeman/project-legalgo-go/internal/utilities/utils"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *AuthSvc) RegisterStaff(spec authdomain.RegisterStaffReq) (string, error) {
|
||||||
|
hashedPwd, err := HashPassword(spec.Password)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
user := authdomain.Staff{
|
||||||
|
ID: uuid.New(),
|
||||||
|
Email: spec.Email,
|
||||||
|
Password: hashedPwd,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = a.staffRepo.Create(&user)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := utils.GenerateToken(spec.Email)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New(err.Error())
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
40
internal/services/auth/register_user.go
Normal file
40
internal/services/auth/register_user.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package authsvc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
authdomain "github.com/ardeman/project-legalgo-go/internal/domain/auth"
|
||||||
|
"github.com/ardeman/project-legalgo-go/internal/utilities/utils"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *AuthSvc) RegisterUser(spec authdomain.RegisterUserReq) (string, error) {
|
||||||
|
subsId, err := a.subsRepo.Create(spec.SubscribePlanID)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hashedPwd, err := HashPassword(spec.Password)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
user := authdomain.User{
|
||||||
|
ID: uuid.New(),
|
||||||
|
Email: spec.Email,
|
||||||
|
SubscribeID: subsId,
|
||||||
|
Password: hashedPwd,
|
||||||
|
Phone: spec.Phone,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = a.userRepo.CreateUser(&user)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := utils.GenerateToken(spec.Email)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New(err.Error())
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
32
internal/services/auth/utils.go
Normal file
32
internal/services/auth/utils.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package authsvc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func VerifyToken(signature string) jwt.Keyfunc {
|
||||||
|
return func(token *jwt.Token) (any, error) {
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(signature), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HashPassword(password string) (string, error) {
|
||||||
|
// Hashing the password with a cost of 14 (default)
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(hash), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ComparePassword(storedPassword, inputPassword string) bool {
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(storedPassword), []byte(inputPassword))
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
20
internal/services/caching/impl.go
Normal file
20
internal/services/caching/impl.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package cachingsvc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
cachingdomain "github.com/ardeman/project-legalgo-go/internal/domain/caching"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
type impl struct {
|
||||||
|
redisClient *redis.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type implIntf interface {
|
||||||
|
Set(context.Context, cachingdomain.CacheSpec) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() implIntf {
|
||||||
|
return &impl{}
|
||||||
|
}
|
||||||
31
internal/services/caching/set.go
Normal file
31
internal/services/caching/set.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package cachingsvc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
cachingdomain "github.com/ardeman/project-legalgo-go/internal/domain/caching"
|
||||||
|
"github.com/ardeman/project-legalgo-go/internal/utilities/response"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i *impl) Set(ctx context.Context, spec cachingdomain.CacheSpec) error {
|
||||||
|
redisClient := i.redisClient
|
||||||
|
|
||||||
|
if redisClient == nil {
|
||||||
|
logrus.WithContext(ctx).Errorf("redis not found")
|
||||||
|
|
||||||
|
return response.ErrRedisConnNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
dataBytes, err := json.Marshal(spec.Data)
|
||||||
|
if err != nil {
|
||||||
|
return response.ErrMarshal
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := redisClient.Set(ctx, spec.Key, string(dataBytes), spec.TTL); err != nil {
|
||||||
|
return response.ErrRedisSet
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -2,11 +2,15 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
serviceauth "github.com/ardeman/project-legalgo-go/internal/services/auth"
|
serviceauth "github.com/ardeman/project-legalgo-go/internal/services/auth"
|
||||||
|
subscribesvc "github.com/ardeman/project-legalgo-go/internal/services/subscribe"
|
||||||
|
subscribeplansvc "github.com/ardeman/project-legalgo-go/internal/services/subscribe_plan"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Module = fx.Module("services",
|
var Module = fx.Module("services",
|
||||||
fx.Provide(
|
fx.Provide(
|
||||||
serviceauth.New,
|
serviceauth.New,
|
||||||
|
subscribeplansvc.New,
|
||||||
|
subscribesvc.New,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
9
internal/services/subscribe/create.go
Normal file
9
internal/services/subscribe/create.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package subscribesvc
|
||||||
|
|
||||||
|
func (s *SubsSvc) Create(subsPlanId string) (string, error) {
|
||||||
|
subsId, err := s.subsRepo.Create(subsPlanId)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return subsId, nil
|
||||||
|
}
|
||||||
15
internal/services/subscribe/impl.go
Normal file
15
internal/services/subscribe/impl.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package subscribesvc
|
||||||
|
|
||||||
|
import subscriberepository "github.com/ardeman/project-legalgo-go/internal/accessor/subscribe"
|
||||||
|
|
||||||
|
type SubsSvc struct {
|
||||||
|
subsRepo subscriberepository.SubsIntf
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubsIntf interface {
|
||||||
|
Create(string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(subsRepo subscriberepository.SubsIntf) SubsIntf {
|
||||||
|
return &SubsSvc{subsRepo}
|
||||||
|
}
|
||||||
5
internal/services/subscribe_plan/create_plan.go
Normal file
5
internal/services/subscribe_plan/create_plan.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package subscribeplansvc
|
||||||
|
|
||||||
|
func (sb *SubsPlanSvc) CreatePlan(code string) error {
|
||||||
|
return sb.subsAccs.Create(code)
|
||||||
|
}
|
||||||
17
internal/services/subscribe_plan/impl.go
Normal file
17
internal/services/subscribe_plan/impl.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package subscribeplansvc
|
||||||
|
|
||||||
|
import subscribeplanrepository "github.com/ardeman/project-legalgo-go/internal/accessor/subscribeplan"
|
||||||
|
|
||||||
|
type SubsPlanSvc struct {
|
||||||
|
subsAccs subscribeplanrepository.SubsPlanIntf
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubsPlanIntf interface {
|
||||||
|
CreatePlan(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(
|
||||||
|
subsAccs subscribeplanrepository.SubsPlanIntf,
|
||||||
|
) SubsPlanIntf {
|
||||||
|
return &SubsPlanSvc{subsAccs}
|
||||||
|
}
|
||||||
@ -8,8 +8,20 @@ type ErrorCode struct {
|
|||||||
HttpCode int
|
HttpCode int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e ErrorCode) Error() string {
|
||||||
|
return e.Code
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// 4xx
|
// 4xx
|
||||||
ErrBadRequest = ErrorCode{Code: "BAD_REQUEST", Message: "BAD_REQUEST", HttpCode: http.StatusBadRequest}
|
ErrBadRequest = &ErrorCode{Code: "BAD_REQUEST", Message: "BAD_REQUEST", HttpCode: http.StatusBadRequest}
|
||||||
ErrDBRequest = ErrorCode{Code: "BAD_DB_REQUEST", Message: "DB_ERROR", HttpCode: http.StatusBadRequest}
|
ErrDBRequest = &ErrorCode{Code: "BAD_DB_REQUEST", Message: "DB_ERROR", HttpCode: http.StatusBadRequest}
|
||||||
|
|
||||||
|
// 5xx
|
||||||
|
ErrMarshal = &ErrorCode{Code: "FAILED_MARSHAL", Message: "FAILED_MARSHAL_BODY", HttpCode: http.StatusInternalServerError}
|
||||||
|
ErrCreateEntity = &ErrorCode{Code: "FAILED_CREATE_ENTITY", Message: "FAILED_CREATE_ENTITY", HttpCode: http.StatusInternalServerError}
|
||||||
|
|
||||||
|
// redis
|
||||||
|
ErrRedisConnNotFound = &ErrorCode{Code: "FAILED_CONNECT_REDIS", Message: "REDIS_NOT_FOUND", HttpCode: http.StatusInternalServerError}
|
||||||
|
ErrRedisSet = &ErrorCode{Code: "FAILED_SET_REDIS", Message: "FAILED_CACHING", HttpCode: http.StatusInternalServerError}
|
||||||
)
|
)
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
jwtclaimenum "github.com/ardeman/project-legalgo-go/internal/enums/jwt"
|
|
||||||
timeutils "github.com/ardeman/project-legalgo-go/internal/utilities/time_utils"
|
timeutils "github.com/ardeman/project-legalgo-go/internal/utilities/time_utils"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
)
|
)
|
||||||
@ -12,23 +11,23 @@ var jwtSecret = []byte("secret jwt key") // TODO: change later from env
|
|||||||
|
|
||||||
type ClaimOption func(options jwt.MapClaims)
|
type ClaimOption func(options jwt.MapClaims)
|
||||||
|
|
||||||
func GenerateToken(options ...ClaimOption) (string, error) {
|
// func GenerateToken(options ...ClaimOption) (string, error) {
|
||||||
now := timeutils.Now()
|
// now := timeutils.Now()
|
||||||
|
|
||||||
claims := jwt.MapClaims{
|
// claims := jwt.MapClaims{
|
||||||
string(jwtclaimenum.ISSUED_AT): now.Unix(),
|
// string(jwtclaimenum.ISSUED_AT): now.Unix(),
|
||||||
}
|
// }
|
||||||
|
|
||||||
for _, o := range options {
|
// for _, o := range options {
|
||||||
o(claims)
|
// o(claims)
|
||||||
}
|
// }
|
||||||
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
// token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
|
||||||
return token.SignedString(jwtSecret)
|
// return token.SignedString(jwtSecret)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func GenerateToken2(email string) (string, error) {
|
func GenerateToken(email string) (string, error) {
|
||||||
now := timeutils.Now()
|
now := timeutils.Now()
|
||||||
token := jwt.New(jwt.SigningMethodHS256)
|
token := jwt.New(jwt.SigningMethodHS256)
|
||||||
claims := token.Claims.(jwt.MapClaims)
|
claims := token.Claims.(jwt.MapClaims)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user