Compare commits
2 Commits
ae5b2cb975
...
bd305f0edf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd305f0edf | ||
|
|
cb3d06fa02 |
@ -3,3 +3,10 @@ DB_USER=
|
|||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
DB_NAME=
|
DB_NAME=
|
||||||
DB_PORT=
|
DB_PORT=
|
||||||
|
|
||||||
|
REDIS_HOST=
|
||||||
|
REDIS_USERNAME=
|
||||||
|
REDIS_PORT=
|
||||||
|
REDIS_PASSWORD=
|
||||||
|
REDIS_TTL=
|
||||||
|
REDIS_DB=
|
||||||
|
|||||||
24
README.md
24
README.md
@ -76,6 +76,30 @@ Run the following command to download and resolve all dependencies specified in
|
|||||||
go mod tidy
|
go mod tidy
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Setup Database
|
||||||
|
|
||||||
|
In your Go application, you'll need to set the following environment variables to connect to your database:
|
||||||
|
```bash
|
||||||
|
DB_HOST: The hostname or IP address of your database server (e.g., localhost, 127.0.0.1, or the actual DB server URL).
|
||||||
|
DB_USER: The username for your database connection.
|
||||||
|
DB_PASSWORD: The password associated with the DB_USER.
|
||||||
|
DB_NAME: The name of the database you want to connect to.
|
||||||
|
DB_PORT: The port number your database server is running on (default MySQL port is 3306, default PostgreSQL port is 5432).
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create `.env` File
|
||||||
|
|
||||||
|
It's best practice to keep sensitive information like database credentials in an environment file. Create or edit the .env file in the root directory of your project and add the following lines:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_USER=your_db_user
|
||||||
|
DB_PASSWORD=your_db_password
|
||||||
|
DB_NAME=your_db_name
|
||||||
|
DB_PORT=3306 # or 5432, depending on your DB type
|
||||||
|
Make sure to replace the values with your actual database details.
|
||||||
|
```
|
||||||
|
|
||||||
## Build the Binary Using `make build`
|
## Build the Binary Using `make build`
|
||||||
|
|
||||||
Run the following command to build your project. The binary will be placed in the `bin` folder.
|
Run the following command to build your project. The binary will be placed in the `bin` folder.
|
||||||
|
|||||||
@ -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