From 567e0e32cade35120320de5bae4030b2c7cf3365 Mon Sep 17 00:00:00 2001 From: ericprd Date: Wed, 5 Mar 2025 21:21:44 +0800 Subject: [PATCH] chores: refactor struct and structure project --- .env.example | 1 + cmd/legalgo/main.go | 13 +- config/conf.go | 15 +- database/category_model.go | 9 +- database/new_db.go | 6 +- database/news_model.go | 26 +-- database/staff_model.go | 1 + database/subscribe_model.go | 3 +- database/tag_module.go | 9 +- database/user_model.go | 3 +- go.mod | 1 + go.sum | 2 + internal/accessor/category/create.go | 5 +- internal/accessor/category/create_model.go | 22 --- internal/accessor/category/get_all.go | 6 +- internal/accessor/category/get_all_model.go | 15 -- internal/accessor/category/get_bulk.go | 6 +- internal/accessor/category/get_bulk_model.go | 15 -- internal/accessor/category/impl.go | 9 +- internal/accessor/category/update.go | 19 ++ internal/accessor/news/create_model.go | 2 +- internal/accessor/news/get_all_model.go | 4 +- internal/accessor/news/impl.go | 4 +- internal/accessor/redis/impl.go | 18 +- internal/accessor/staff/create.go | 12 +- internal/accessor/staff/get_by_email.go | 8 +- internal/accessor/staff/get_by_id.go | 8 +- internal/accessor/staff/impl.go | 20 +- internal/accessor/staff/update.go | 6 +- internal/accessor/subscribe/get_by_id.go | 23 +++ internal/accessor/subscribe/impl.go | 2 + .../subscribe/update_subscribe_status.go | 19 ++ internal/accessor/subscribeplan/get_by_id.go | 6 +- .../accessor/subscribeplan/get_default.go | 8 +- internal/accessor/subscribeplan/impl.go | 4 +- internal/accessor/tag/create_model.go | 2 +- internal/accessor/tag/get_all_model.go | 4 +- internal/accessor/tag/get_bulk_model.go | 4 +- internal/accessor/tag/impl.go | 4 +- .../accessor/user_repository/create_user.go | 8 +- .../user_repository/get_user_by_email.go | 9 +- .../user_repository/get_user_by_id.go | 22 +-- .../user_repository/get_user_profile.go | 31 +-- internal/accessor/user_repository/impl.go | 10 +- .../http/auth/{login.go => login_staff.go} | 56 +----- internal/api/http/auth/login_user.go | 82 ++++++++ internal/api/http/auth/profile.go | 4 +- .../auth/{register.go => register_staff.go} | 79 ++------ internal/api/http/auth/register_user.go | 82 ++++++++ internal/api/http/auth/update.go | 8 +- internal/api/http/category/create.go | 85 +++++---- internal/api/http/category/get_all.go | 2 +- internal/api/http/category/module.go | 1 + internal/api/http/category/update.go | 82 ++++++++ .../api/http/middleware/auth/authorize.go | 176 ++++++------------ internal/api/http/news/create.go | 2 +- internal/api/http/subscribe/module.go | 5 + internal/api/http/subscribe/update.go | 77 ++++++++ internal/api/http/subscribe_plan/create.go | 87 ++++----- internal/api/http/subscribe_plan/get_all.go | 2 +- internal/api/http/tag/create.go | 87 ++++----- internal/api/http/tag/get_all.go | 2 +- internal/domain/auth/login.go | 32 ---- internal/domain/auth/register.go | 37 ---- internal/domain/auth/token.go | 1 + internal/domain/category/spec.go | 10 +- internal/domain/news/spec.go | 26 +-- internal/domain/reponse/spec.go | 5 + internal/domain/staff/spec.go | 28 +++ internal/domain/subscribe/spec.go | 24 ++- internal/domain/subscribe_model/response.go | 17 ++ .../domain/subscribe_plan_model/response.go | 8 + internal/domain/user/spec.go | 37 ++++ internal/services/auth/get_staff.go | 8 +- internal/services/auth/get_user.go | 6 +- internal/services/auth/impl.go | 29 +-- internal/services/auth/login_as_staff.go | 4 +- internal/services/auth/login_as_user.go | 4 +- internal/services/auth/register_staff.go | 8 +- internal/services/auth/register_user.go | 8 +- internal/services/auth/update_staff.go | 6 +- internal/services/category/get_all.go | 6 +- internal/services/category/get_all_model.go | 9 - internal/services/category/impl.go | 3 +- internal/services/category/update.go | 21 +++ internal/services/news/create_model.go | 4 +- internal/services/news/get_all_model.go | 2 +- internal/services/news/impl.go | 2 +- internal/services/subscribe/create.go | 2 +- internal/services/subscribe/impl.go | 14 +- internal/services/subscribe/update.go | 9 + .../services/subscribe_plan/create_plan.go | 2 +- .../services/subscribe_plan/get_all_plan.go | 2 +- internal/services/subscribe_plan/impl.go | 8 +- internal/services/tag/get_all_model.go | 2 +- internal/services/tag/impl.go | 6 +- internal/utilities/response/error_code.go | 6 +- .../utilities/response/response_json_error.go | 23 +++ .../utilities/response/response_with_error.go | 23 +++ internal/utilities/utils/get_token.go | 30 +++ internal/utilities/utils/get_token_detail.go | 2 +- internal/utilities/utils/jwt.go | 11 +- internal/utilities/utils/redis.go | 30 ++- 103 files changed, 1126 insertions(+), 732 deletions(-) delete mode 100644 internal/accessor/category/create_model.go delete mode 100644 internal/accessor/category/get_all_model.go delete mode 100644 internal/accessor/category/get_bulk_model.go create mode 100644 internal/accessor/category/update.go create mode 100644 internal/accessor/subscribe/get_by_id.go create mode 100644 internal/accessor/subscribe/update_subscribe_status.go rename internal/api/http/auth/{login.go => login_staff.go} (56%) create mode 100644 internal/api/http/auth/login_user.go rename internal/api/http/auth/{register.go => register_staff.go} (56%) create mode 100644 internal/api/http/auth/register_user.go create mode 100644 internal/api/http/category/update.go create mode 100644 internal/api/http/subscribe/module.go create mode 100644 internal/api/http/subscribe/update.go delete mode 100644 internal/domain/auth/login.go delete mode 100644 internal/domain/auth/register.go create mode 100644 internal/domain/reponse/spec.go create mode 100644 internal/domain/staff/spec.go create mode 100644 internal/domain/subscribe_model/response.go create mode 100644 internal/domain/subscribe_plan_model/response.go create mode 100644 internal/domain/user/spec.go delete mode 100644 internal/services/category/get_all_model.go create mode 100644 internal/services/category/update.go create mode 100644 internal/services/subscribe/update.go create mode 100644 internal/utilities/response/response_json_error.go create mode 100644 internal/utilities/response/response_with_error.go create mode 100644 internal/utilities/utils/get_token.go diff --git a/.env.example b/.env.example index b9f5260..0ee78ad 100644 --- a/.env.example +++ b/.env.example @@ -14,3 +14,4 @@ REDIS_PORT= REDIS_PASSWORD= REDIS_TTL= REDIS_DB= +REDIS_TIMEOUT= diff --git a/cmd/legalgo/main.go b/cmd/legalgo/main.go index 9c2a8e9..bc0b171 100644 --- a/cmd/legalgo/main.go +++ b/cmd/legalgo/main.go @@ -15,6 +15,7 @@ import ( "github.com/go-chi/chi/v5" "github.com/joho/godotenv" + "github.com/redis/go-redis/v9" "go.uber.org/fx" ) @@ -32,16 +33,26 @@ func init() { config.InitEnv() } -func run(lc fx.Lifecycle, db *database.DB, apiRouter chi.Router) { +func run( + lc fx.Lifecycle, + db *database.DB, + apiRouter chi.Router, + rdb *redis.Client, +) { lc.Append(fx.Hook{ OnStart: func(ctx context.Context) error { fmt.Println("Application has started...") + _, err := rdb.Ping(ctx).Result() + if err != nil { + log.Fatalf("Could not connect to Redis: %v", err) + } pkgconfig.Router(apiRouter) return nil }, OnStop: func(ctx context.Context) error { fmt.Println("Shutting down...") + rdb.Close() return nil }, }) diff --git a/config/conf.go b/config/conf.go index 30f53cf..57105ed 100644 --- a/config/conf.go +++ b/config/conf.go @@ -1,7 +1,11 @@ package config +import "fmt" + var ( - APP_PORT int + APP_PORT, + REDIS_DB, + REDIS_TIMEOUT, GRACEFULL_TIMEOUT int // DB @@ -10,6 +14,9 @@ var ( DB_PASSWORD, DB_NAME, DB_PORT, + REDIS_PASSWORD, + REDIS_ADDR, + REDIS_USERNAME, SALT_SECURITY string ) @@ -24,4 +31,10 @@ func InitEnv() { APP_PORT = GetOrDefault("APP_PORT", 3000) GRACEFULL_TIMEOUT = GetOrDefault("GRACEFULL_TIMEOUT", 10) + + REDIS_DB = GetOrDefault("REDIS_DB", 0) + REDIS_PASSWORD = GetOrDefault("REDIS_PASSWORD", "") + REDIS_ADDR = fmt.Sprintf("%s:%s", GetOrDefault("REDIS_HOST", "localhost"), GetOrDefault("REDIS_PORT", "6379")) + REDIS_USERNAME = GetOrDefault("REDIS_USERNAME", "") + REDIS_TIMEOUT = GetOrDefault("REDIS_TIMEOUT", 60) } diff --git a/database/category_model.go b/database/category_model.go index 8f43829..457ac50 100644 --- a/database/category_model.go +++ b/database/category_model.go @@ -5,17 +5,10 @@ import ( ) type Category struct { - ID string `gorm:"primaryKey" json:"id"` - Code string `gorm:"not null;unique" json:"code"` - Name string `gorm:"not null" json:"name"` - CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"` - UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"` -} - -type CategoryModel struct { ID string `gorm:"primaryKey" json:"id"` Name string `gorm:"not null;unique" json:"name"` Code string `gorm:"not null" json:"code"` CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"` UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"` + DeletedAt time.Time `gorm:"default:null" json:"deleted_at"` } diff --git a/database/new_db.go b/database/new_db.go index be0491d..c1200f7 100644 --- a/database/new_db.go +++ b/database/new_db.go @@ -58,8 +58,8 @@ func (db *DB) Migrate() error { // &Tag{}, // &Category{}, // &News{}, - &NewsModel{}, - &TagModel{}, - &CategoryModel{}, + &News{}, + &Tag{}, + &Category{}, ) } diff --git a/database/news_model.go b/database/news_model.go index fedff08..25e4f6a 100644 --- a/database/news_model.go +++ b/database/news_model.go @@ -6,30 +6,16 @@ import ( type News struct { ID string `gorm:"primaryKey" json:"id"` - Title string `gorm:"default:null" json:"title"` - Tags []Tag `gorm:"many2many:news_tags" json:"tags"` + Title string `json:"title"` + Content string `json:"content"` Categories []Category `gorm:"many2many:news_categories" json:"categories"` - Content string `gorm:"default:null" json:"content"` - LiveAt time.Time `gorm:"not null" json:"live_at"` - AuthorID string `gorm:"not null" json:"author_id"` + Tags []Tag `gorm:"many2many:news_tags" json:"tags"` IsPremium bool `gorm:"default:false" json:"is_premium"` Slug string `gorm:"default:null" json:"slug"` FeaturedImage string `gorm:"default:null" json:"featured_image"` + AuthorID string `gorm:"not null" json:"author_id"` + LiveAt time.Time `gorm:"not null" json:"live_at"` CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"` UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"` -} - -type NewsModel struct { - ID string `gorm:"primaryKey" json:"id"` - Title string `json:"title"` - Content string `json:"content"` - Categories []CategoryModel `gorm:"many2many:news_categories" json:"categories"` - Tags []TagModel `gorm:"many2many:news_tags" json:"tags"` - IsPremium bool `gorm:"default:false" json:"is_premium"` - Slug string `gorm:"default:null" json:"slug"` - FeaturedImage string `gorm:"default:null" json:"featured_image"` - AuthorID string `gorm:"not null" json:"author_id"` - LiveAt time.Time `gorm:"not null" json:"live_at"` - CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"` - UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"` + DeletedAt time.Time `gorm:"default:null" json:"deleted_at"` } diff --git a/database/staff_model.go b/database/staff_model.go index cedc068..db0e734 100644 --- a/database/staff_model.go +++ b/database/staff_model.go @@ -12,4 +12,5 @@ type Staff struct { 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"` + DeletedAt time.Time `gorm:"default:null" json:"deleted_at"` } diff --git a/database/subscribe_model.go b/database/subscribe_model.go index 20f1ebc..377aad0 100644 --- a/database/subscribe_model.go +++ b/database/subscribe_model.go @@ -13,8 +13,9 @@ type Subscribe struct { AutoRenew bool `gorm:"default:true"` CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"` + DeletedAt time.Time `gorm:"default:null" json:"deleted_at"` - SubscribePlan SubscribePlan `gorm:"foreignKey:SubscribePlanID;constraint:OnDelete:CASCADE"` + SubscribePlan SubscribePlan `gorm:"foreignKey:SubscribePlanID;constraint:OnDelete:CASCADE" json:"subscribe_plan"` } type SubscribePlan struct { diff --git a/database/tag_module.go b/database/tag_module.go index ae3aec0..0d00366 100644 --- a/database/tag_module.go +++ b/database/tag_module.go @@ -5,17 +5,10 @@ import ( ) type Tag struct { - ID string `gorm:"primaryKey" json:"id"` - Code string `gorm:"not null;unique" json:"code"` - Name string `gorm:"not null" json:"name"` - CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"` - UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"` -} - -type TagModel struct { ID string `gorm:"primaryKey" json:"id"` Name string `gorm:"not null;unique" json:"name"` Code string `gorm:"not null" json:"code"` CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"` UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"` + DeletedAt time.Time `gorm:"default:null" json:"deleted_at"` } diff --git a/database/user_model.go b/database/user_model.go index 6ad2454..23a942b 100644 --- a/database/user_model.go +++ b/database/user_model.go @@ -12,6 +12,7 @@ type User struct { Phone string `gorm:"default:not null;unique" json:"phone"` CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"` UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"` + DeletedAt time.Time `gorm:"default:null" json:"deleted_at"` - Subscribe Subscribe `gorm:"foreignKey:SubscribeID;constraint:OnDelete:CASCADE"` + Subscribe Subscribe `gorm:"foreignKey:SubscribeID;constraint:OnDelete:CASCADE" json:"subscribe"` } diff --git a/go.mod b/go.mod index 00986c9..53045b6 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( github.com/go-chi/chi/v5 v5.2.1 github.com/go-chi/cors v1.2.1 github.com/go-playground/validator/v10 v10.25.0 + github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.6.0 github.com/redis/go-redis/v9 v9.7.1 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index 482bf47..d8af3c1 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= diff --git a/internal/accessor/category/create.go b/internal/accessor/category/create.go index f9616fa..4460a09 100644 --- a/internal/accessor/category/create.go +++ b/internal/accessor/category/create.go @@ -1,13 +1,14 @@ package categoryrepository import ( + "legalgo-BE-go/database" categorydomain "legalgo-BE-go/internal/domain/category" "github.com/google/uuid" ) -func (a *accessor) Create(spec categorydomain.CategoryReq) error { - data := categorydomain.Category{ +func (a *accessor) CreateModel(spec categorydomain.CategoryReq) error { + data := database.Category{ ID: uuid.NewString(), Name: spec.Name, Code: spec.Code, diff --git a/internal/accessor/category/create_model.go b/internal/accessor/category/create_model.go deleted file mode 100644 index f6ce13f..0000000 --- a/internal/accessor/category/create_model.go +++ /dev/null @@ -1,22 +0,0 @@ -package categoryrepository - -import ( - "legalgo-BE-go/database" - categorydomain "legalgo-BE-go/internal/domain/category" - - "github.com/google/uuid" -) - -func (a *accessor) CreateModel(spec categorydomain.CategoryReq) error { - data := database.CategoryModel{ - ID: uuid.NewString(), - Name: spec.Name, - Code: spec.Code, - } - - if err := a.DB.Create(&data).Error; err != nil { - return err - } - - return nil -} diff --git a/internal/accessor/category/get_all.go b/internal/accessor/category/get_all.go index 74ae169..76e9e23 100644 --- a/internal/accessor/category/get_all.go +++ b/internal/accessor/category/get_all.go @@ -1,8 +1,10 @@ package categoryrepository -import categorydomain "legalgo-BE-go/internal/domain/category" +import ( + categorydomain "legalgo-BE-go/internal/domain/category" +) -func (a *accessor) GetAll() ([]categorydomain.Category, error) { +func (a *accessor) GetAllModel() ([]categorydomain.Category, error) { var categories []categorydomain.Category if err := a.DB.Find(&categories).Error; err != nil { diff --git a/internal/accessor/category/get_all_model.go b/internal/accessor/category/get_all_model.go deleted file mode 100644 index ac7b681..0000000 --- a/internal/accessor/category/get_all_model.go +++ /dev/null @@ -1,15 +0,0 @@ -package categoryrepository - -import ( - "legalgo-BE-go/database" -) - -func (a *accessor) GetAllModel() ([]database.CategoryModel, error) { - var categories []database.CategoryModel - - if err := a.DB.Find(&categories).Error; err != nil { - return nil, err - } - - return categories, nil -} diff --git a/internal/accessor/category/get_bulk.go b/internal/accessor/category/get_bulk.go index 501ec95..6e83b0f 100644 --- a/internal/accessor/category/get_bulk.go +++ b/internal/accessor/category/get_bulk.go @@ -1,11 +1,11 @@ package categoryrepository import ( - categorydomain "legalgo-BE-go/internal/domain/category" + "legalgo-BE-go/database" ) -func (a *accessor) GetByIDs(ids []string) ([]categorydomain.Category, error) { - var categories []categorydomain.Category +func (a *accessor) GetByIDs(ids []string) ([]database.Category, error) { + var categories []database.Category if err := a.DB.Find(&categories, "id IN ?", ids).Error; err != nil { return nil, err diff --git a/internal/accessor/category/get_bulk_model.go b/internal/accessor/category/get_bulk_model.go deleted file mode 100644 index 43477f6..0000000 --- a/internal/accessor/category/get_bulk_model.go +++ /dev/null @@ -1,15 +0,0 @@ -package categoryrepository - -import ( - "legalgo-BE-go/database" -) - -func (a *accessor) GetBulks(ids []string) ([]database.CategoryModel, error) { - var categories []database.CategoryModel - - if err := a.DB.Find(&categories, "id IN ?", ids).Error; err != nil { - return nil, err - } - - return categories, nil -} diff --git a/internal/accessor/category/impl.go b/internal/accessor/category/impl.go index 0b0ba62..3672e97 100644 --- a/internal/accessor/category/impl.go +++ b/internal/accessor/category/impl.go @@ -10,14 +10,11 @@ type accessor struct { } type Category interface { - Create(categorydomain.CategoryReq) error CreateModel(categorydomain.CategoryReq) error + Update(categorydomain.Category) error - GetAll() ([]categorydomain.Category, error) - GetAllModel() ([]database.CategoryModel, error) - - GetByIDs([]string) ([]categorydomain.Category, error) - GetBulks([]string) ([]database.CategoryModel, error) + GetAllModel() ([]categorydomain.Category, error) + GetByIDs([]string) ([]database.Category, error) } func New( diff --git a/internal/accessor/category/update.go b/internal/accessor/category/update.go new file mode 100644 index 0000000..8f23d26 --- /dev/null +++ b/internal/accessor/category/update.go @@ -0,0 +1,19 @@ +package categoryrepository + +import ( + "fmt" + categorydomain "legalgo-BE-go/internal/domain/category" + + "gorm.io/gorm/clause" +) + +func (a *accessor) Update(spec categorydomain.Category) error { + if err := a.DB.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "id"}}, + DoUpdates: clause.AssignmentColumns([]string{"name", "code", "updated_at"}), + }).Save(&spec).Error; err != nil { + return fmt.Errorf("failed to update category: %v", err) + } + + return nil +} diff --git a/internal/accessor/news/create_model.go b/internal/accessor/news/create_model.go index dbcf1e0..b70eb32 100644 --- a/internal/accessor/news/create_model.go +++ b/internal/accessor/news/create_model.go @@ -5,7 +5,7 @@ import ( "legalgo-BE-go/database" ) -func (a *accessor) CreateModel(spec database.NewsModel) error { +func (a *accessor) CreateModel(spec database.News) error { if err := a.db.Create(&spec).Error; err != nil { return fmt.Errorf("failed to create news: %w", err) } diff --git a/internal/accessor/news/get_all_model.go b/internal/accessor/news/get_all_model.go index 9cd8bf2..cbd4fab 100644 --- a/internal/accessor/news/get_all_model.go +++ b/internal/accessor/news/get_all_model.go @@ -2,8 +2,8 @@ package newsrepository import "legalgo-BE-go/database" -func (a *accessor) GetAllModel() ([]database.NewsModel, error) { - var news []database.NewsModel +func (a *accessor) GetAllModel() ([]database.News, error) { + var news []database.News if err := a.db.Preload("Tags").Preload("Categories").Find(&news).Error; err != nil { return nil, err diff --git a/internal/accessor/news/impl.go b/internal/accessor/news/impl.go index 11abb54..fbe0eab 100644 --- a/internal/accessor/news/impl.go +++ b/internal/accessor/news/impl.go @@ -11,9 +11,9 @@ type accessor struct { type News interface { GetAll() ([]newsdomain.News, error) - GetAllModel() ([]database.NewsModel, error) + GetAllModel() ([]database.News, error) Create(*newsdomain.News) error - CreateModel(database.NewsModel) error + CreateModel(database.News) error } func New(db *database.DB) News { diff --git a/internal/accessor/redis/impl.go b/internal/accessor/redis/impl.go index 532f00c..001ca98 100644 --- a/internal/accessor/redis/impl.go +++ b/internal/accessor/redis/impl.go @@ -1,8 +1,7 @@ package redisaccessor import ( - "fmt" - "os" + "legalgo-BE-go/config" "github.com/redis/go-redis/v9" ) @@ -14,18 +13,11 @@ func Get() *redis.Client { } 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, + Username: config.REDIS_USERNAME, + Addr: config.REDIS_ADDR, + Password: config.REDIS_PASSWORD, + DB: config.REDIS_DB, }) return redisClient diff --git a/internal/accessor/staff/create.go b/internal/accessor/staff/create.go index 857fc4d..14e2d95 100644 --- a/internal/accessor/staff/create.go +++ b/internal/accessor/staff/create.go @@ -1,11 +1,13 @@ package staffrepository -import authdomain "legalgo-BE-go/internal/domain/auth" +import ( + staffdomain "legalgo-BE-go/internal/domain/staff" +) -func (ur *StaffRepository) Create(spec *authdomain.Staff) (*authdomain.Staff, error) { - if err := ur.DB.Create(&spec).Error; err != nil { - return nil, err +func (ur *impl) Create(spec staffdomain.Staff) error { + if err := ur.db.Create(&spec).Error; err != nil { + return err } - return spec, nil + return nil } diff --git a/internal/accessor/staff/get_by_email.go b/internal/accessor/staff/get_by_email.go index d2d942a..2868741 100644 --- a/internal/accessor/staff/get_by_email.go +++ b/internal/accessor/staff/get_by_email.go @@ -3,19 +3,19 @@ package staffrepository import ( "errors" - authdomain "legalgo-BE-go/internal/domain/auth" + staffdomain "legalgo-BE-go/internal/domain/staff" "gorm.io/gorm" ) -func (sr *StaffRepository) GetStaffByEmail(email string) (*authdomain.Staff, error) { - var staff authdomain.Staff +func (sr *impl) GetStaffByEmail(email string) (*staffdomain.Staff, error) { + var staff staffdomain.Staff if email == "" { return nil, errors.New("email is required") } - if err := sr.DB.First(&staff, "email = ?", email).Error; err != nil { + if err := sr.db.First(&staff, "email = ?", email).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("staff not found") } diff --git a/internal/accessor/staff/get_by_id.go b/internal/accessor/staff/get_by_id.go index 4c23c15..5e52f7b 100644 --- a/internal/accessor/staff/get_by_id.go +++ b/internal/accessor/staff/get_by_id.go @@ -2,19 +2,19 @@ package staffrepository import ( "errors" - authdomain "legalgo-BE-go/internal/domain/auth" + staffdomain "legalgo-BE-go/internal/domain/staff" "gorm.io/gorm" ) -func (sr *StaffRepository) GetStaffByID(ID string) (*authdomain.Staff, error) { - var staff authdomain.Staff +func (sr *impl) GetStaffByID(ID string) (*staffdomain.Staff, error) { + var staff staffdomain.Staff if ID == "" { return nil, errors.New("id is required") } - if err := sr.DB.First(&staff, "id = ? ", ID).Error; err != nil { + if err := sr.db.First(&staff, "id = ? ", ID).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("staff not found") } diff --git a/internal/accessor/staff/impl.go b/internal/accessor/staff/impl.go index c8901aa..1c05d5c 100644 --- a/internal/accessor/staff/impl.go +++ b/internal/accessor/staff/impl.go @@ -2,20 +2,20 @@ package staffrepository import ( "legalgo-BE-go/database" - authdomain "legalgo-BE-go/internal/domain/auth" + staffdomain "legalgo-BE-go/internal/domain/staff" ) -type StaffRepository struct { - DB *database.DB +type impl struct { + db *database.DB } -type StaffIntf interface { - GetStaffByEmail(string) (*authdomain.Staff, error) - GetStaffByID(string) (*authdomain.Staff, error) - Create(*authdomain.Staff) (*authdomain.Staff, error) - Update(authdomain.Staff) error +type Staff interface { + GetStaffByEmail(string) (*staffdomain.Staff, error) + GetStaffByID(string) (*staffdomain.Staff, error) + Create(staffdomain.Staff) error + Update(staffdomain.Staff) error } -func New(db *database.DB) StaffIntf { - return &StaffRepository{db} +func New(db *database.DB) Staff { + return &impl{db} } diff --git a/internal/accessor/staff/update.go b/internal/accessor/staff/update.go index b0c6ae2..f5af3f8 100644 --- a/internal/accessor/staff/update.go +++ b/internal/accessor/staff/update.go @@ -1,17 +1,17 @@ package staffrepository import ( - authdomain "legalgo-BE-go/internal/domain/auth" + staffdomain "legalgo-BE-go/internal/domain/staff" "legalgo-BE-go/internal/utilities/utils" ) -func (ur *StaffRepository) Update(spec authdomain.Staff) error { +func (ur *impl) Update(spec staffdomain.Staff) error { val, err := utils.StructToMap(spec) if err != nil { return err } - if err := ur.DB.Model(&authdomain.Staff{}).Where("id = ?", spec.ID).Updates(val).Error; err != nil { + if err := ur.db.Model(&staffdomain.Staff{}).Where("id = ?", spec.ID).Updates(val).Error; err != nil { return err } diff --git a/internal/accessor/subscribe/get_by_id.go b/internal/accessor/subscribe/get_by_id.go new file mode 100644 index 0000000..b172408 --- /dev/null +++ b/internal/accessor/subscribe/get_by_id.go @@ -0,0 +1,23 @@ +package subscriberepository + +import ( + "errors" + "fmt" + "legalgo-BE-go/database" + + "gorm.io/gorm" +) + +func (s *SubsAccs) GetByID(id string) (database.Subscribe, error) { + var subscribe database.Subscribe + + if err := s.DB.First(&subscribe, "id = ?", id).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return subscribe, fmt.Errorf("subscribe data not found: %v", err) + } + + return subscribe, err + } + + return subscribe, nil +} diff --git a/internal/accessor/subscribe/impl.go b/internal/accessor/subscribe/impl.go index 6a34b32..e94ecbd 100644 --- a/internal/accessor/subscribe/impl.go +++ b/internal/accessor/subscribe/impl.go @@ -8,6 +8,8 @@ type SubsAccs struct { type SubsIntf interface { Create(string) (string, error) + GetByID(string) (database.Subscribe, error) + UpdateSubscribeStatus(database.Subscribe) error } func New(db *database.DB) SubsIntf { diff --git a/internal/accessor/subscribe/update_subscribe_status.go b/internal/accessor/subscribe/update_subscribe_status.go new file mode 100644 index 0000000..45ee75a --- /dev/null +++ b/internal/accessor/subscribe/update_subscribe_status.go @@ -0,0 +1,19 @@ +package subscriberepository + +import ( + "fmt" + "legalgo-BE-go/database" + + "gorm.io/gorm/clause" +) + +func (a *SubsAccs) UpdateSubscribeStatus(spec database.Subscribe) error { + if err := a.DB.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "id"}}, + DoUpdates: clause.AssignmentColumns([]string{"status"}), + }).Create(&spec).Error; err != nil { + return fmt.Errorf("failed to update status: %v", err) + } + + return nil +} diff --git a/internal/accessor/subscribeplan/get_by_id.go b/internal/accessor/subscribeplan/get_by_id.go index dd13446..0d8172b 100644 --- a/internal/accessor/subscribeplan/get_by_id.go +++ b/internal/accessor/subscribeplan/get_by_id.go @@ -2,13 +2,13 @@ package subscribeplanrepository import ( "errors" - subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan" + "legalgo-BE-go/database" "gorm.io/gorm" ) -func (s *SubsPlan) GetByID(id string) (subscribeplandomain.SubscribePlan, error) { - var subscribePlan subscribeplandomain.SubscribePlan +func (s *SubsPlan) GetByID(id string) (*database.SubscribePlan, error) { + var subscribePlan *database.SubscribePlan if err := s.DB.First(&subscribePlan, "id = ? ", id).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { diff --git a/internal/accessor/subscribeplan/get_default.go b/internal/accessor/subscribeplan/get_default.go index 290f26a..4fa9288 100644 --- a/internal/accessor/subscribeplan/get_default.go +++ b/internal/accessor/subscribeplan/get_default.go @@ -1,16 +1,16 @@ package subscribeplanrepository import ( - subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan" + "legalgo-BE-go/database" "github.com/google/uuid" ) -func (s *SubsPlan) GetDefault() (subscribeplandomain.SubscribePlan, error) { - var subscribePlan subscribeplandomain.SubscribePlan +func (s *SubsPlan) GetDefault() (*database.SubscribePlan, error) { + var subscribePlan *database.SubscribePlan if err := s.DB.First(&subscribePlan, "code = ?", "basic").Error; err != nil { - s.DB.Create(&subscribeplandomain.SubscribePlan{ + s.DB.Create(&database.SubscribePlan{ ID: uuid.NewString(), Code: "basic", Name: "Basic", diff --git a/internal/accessor/subscribeplan/impl.go b/internal/accessor/subscribeplan/impl.go index 373d996..c20836c 100644 --- a/internal/accessor/subscribeplan/impl.go +++ b/internal/accessor/subscribeplan/impl.go @@ -12,8 +12,8 @@ type SubsPlan struct { type SubsPlanIntf interface { Create(subscribeplandomain.SubscribePlanReq) error GetAll() ([]subscribeplandomain.SubscribePlan, error) - GetByID(string) (subscribeplandomain.SubscribePlan, error) - GetDefault() (subscribeplandomain.SubscribePlan, error) + GetByID(string) (*database.SubscribePlan, error) + GetDefault() (*database.SubscribePlan, error) } func New( diff --git a/internal/accessor/tag/create_model.go b/internal/accessor/tag/create_model.go index ce6e54c..77988c3 100644 --- a/internal/accessor/tag/create_model.go +++ b/internal/accessor/tag/create_model.go @@ -8,7 +8,7 @@ import ( ) func (acc *accessor) CreateModel(spec tagdomain.TagReq) error { - data := &database.TagModel{ + data := &database.Tag{ ID: uuid.NewString(), Code: spec.Code, Name: spec.Name, diff --git a/internal/accessor/tag/get_all_model.go b/internal/accessor/tag/get_all_model.go index 3fe5ad3..830b6b2 100644 --- a/internal/accessor/tag/get_all_model.go +++ b/internal/accessor/tag/get_all_model.go @@ -2,8 +2,8 @@ package tagrepository import "legalgo-BE-go/database" -func (acc *accessor) GetAllModel() ([]database.TagModel, error) { - var tags []database.TagModel +func (acc *accessor) GetAllModel() ([]database.Tag, error) { + var tags []database.Tag if err := acc.DB.Find(&tags).Error; err != nil { return nil, err diff --git a/internal/accessor/tag/get_bulk_model.go b/internal/accessor/tag/get_bulk_model.go index 0072eb1..5cb84c5 100644 --- a/internal/accessor/tag/get_bulk_model.go +++ b/internal/accessor/tag/get_bulk_model.go @@ -2,8 +2,8 @@ package tagrepository import "legalgo-BE-go/database" -func (a *accessor) GetBulks(ids []string) ([]database.TagModel, error) { - var tags []database.TagModel +func (a *accessor) GetBulks(ids []string) ([]database.Tag, error) { + var tags []database.Tag if err := a.DB.Find(&tags, "id IN ?", ids).Error; err != nil { return nil, err diff --git a/internal/accessor/tag/impl.go b/internal/accessor/tag/impl.go index 0d00149..dbfc93e 100644 --- a/internal/accessor/tag/impl.go +++ b/internal/accessor/tag/impl.go @@ -13,9 +13,9 @@ type TagAccessor interface { Create(tagdomain.TagReq) error CreateModel(tagdomain.TagReq) error GetAll() ([]tagdomain.Tag, error) - GetAllModel() ([]database.TagModel, error) + GetAllModel() ([]database.Tag, error) GetByIDs([]string) ([]tagdomain.Tag, error) - GetBulks(ids []string) ([]database.TagModel, error) + GetBulks(ids []string) ([]database.Tag, error) } func New( diff --git a/internal/accessor/user_repository/create_user.go b/internal/accessor/user_repository/create_user.go index 4a4166c..bbd0d6e 100644 --- a/internal/accessor/user_repository/create_user.go +++ b/internal/accessor/user_repository/create_user.go @@ -1,13 +1,13 @@ package userrepository import ( - authdomain "legalgo-BE-go/internal/domain/auth" + userdomain "legalgo-BE-go/internal/domain/user" ) -func (ur *UserRepository) CreateUser(spec *authdomain.User) (*authdomain.User, error) { +func (ur *UserRepository) CreateUser(spec userdomain.User) error { if err := ur.DB.Create(&spec).Error; err != nil { - return nil, err + return err } - return spec, nil + return nil } diff --git a/internal/accessor/user_repository/get_user_by_email.go b/internal/accessor/user_repository/get_user_by_email.go index 2239cc5..ada5ec5 100644 --- a/internal/accessor/user_repository/get_user_by_email.go +++ b/internal/accessor/user_repository/get_user_by_email.go @@ -2,14 +2,13 @@ package userrepository import ( "errors" - - authdomain "legalgo-BE-go/internal/domain/auth" + userdomain "legalgo-BE-go/internal/domain/user" "gorm.io/gorm" ) -func (ur *UserRepository) GetUserByEmail(email string) (*authdomain.User, error) { - var user authdomain.User +func (ur *UserRepository) GetUserByEmail(email string) (*userdomain.User, error) { + var user *userdomain.User if email == "" { return nil, errors.New("email is empty") @@ -22,5 +21,5 @@ func (ur *UserRepository) GetUserByEmail(email string) (*authdomain.User, error) return nil, err } - return &user, nil + return user, nil } diff --git a/internal/accessor/user_repository/get_user_by_id.go b/internal/accessor/user_repository/get_user_by_id.go index 695a35e..7c6c6f5 100644 --- a/internal/accessor/user_repository/get_user_by_id.go +++ b/internal/accessor/user_repository/get_user_by_id.go @@ -3,28 +3,22 @@ package userrepository import ( "errors" - authdomain "legalgo-BE-go/internal/domain/auth" - - "gorm.io/gorm" + userdomain "legalgo-BE-go/internal/domain/user" ) -func (ur *UserRepository) GetUserByID(email string) (*authdomain.UserProfile, error) { - var users []authdomain.UserProfile +func (ur *UserRepository) GetUserByID(email string) (*userdomain.User, error) { + var user userdomain.User if email == "" { return nil, errors.New("email is empty") } - if err := ur.DB.Table("users u"). - Select("u.email, u.id, s.status as subscribe_status, sp.code as subscribe_plan_code, sp.name as subscribe_plan_name"). - Joins("join subscribes s on s.id = u.subscribe_id"). - Joins("join subscribe_plans sp on s.subscribe_plan_id = sp.id"). - Scan(&users).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errors.New("user not found") - } + if err := ur.DB. + Preload("Subscribe"). + Preload("Subscribe.SubscribePlan"). + First(&user, "email = ?", email).Error; err != nil { return nil, err } - return &users[0], nil + return &user, nil } diff --git a/internal/accessor/user_repository/get_user_profile.go b/internal/accessor/user_repository/get_user_profile.go index bc5d4bc..2f18792 100644 --- a/internal/accessor/user_repository/get_user_profile.go +++ b/internal/accessor/user_repository/get_user_profile.go @@ -2,29 +2,30 @@ package userrepository import ( "errors" - authdomain "legalgo-BE-go/internal/domain/auth" - - "gorm.io/gorm" + userdomain "legalgo-BE-go/internal/domain/user" ) -func (ur *UserRepository) GetUserProfile(email string) (*authdomain.UserProfile, error) { - var users []authdomain.UserProfile +func (ur *UserRepository) GetUserProfile(email string) (*userdomain.UserProfile, error) { + var user *userdomain.User if email == "" { return nil, errors.New("email is empty") } - if err := ur.DB.Table("users u"). - Where("email = ?", email). - Select("u.email, u.id, s.status as subscribe_status, sp.code as subscribe_plan_code, sp.name as subscribe_plan_name"). - Joins("join subscribes s on s.id = u.subscribe_id"). - Joins("join subscribe_plans sp on s.subscribe_plan_id = sp.id"). - Scan(&users).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errors.New("user not found") - } + if err := ur.DB. + Preload("Subscribe"). + Preload("Subscribe.SubscribePlan"). + First(&user, "email = ?", email). + Error; err != nil { return nil, err } - return &users[0], nil + userProfile := &userdomain.UserProfile{ + ID: user.ID, + Email: user.Email, + Phone: user.Phone, + Subscribe: user.Subscribe, + } + + return userProfile, nil } diff --git a/internal/accessor/user_repository/impl.go b/internal/accessor/user_repository/impl.go index c4239bb..c0e428a 100644 --- a/internal/accessor/user_repository/impl.go +++ b/internal/accessor/user_repository/impl.go @@ -2,7 +2,7 @@ package userrepository import ( "legalgo-BE-go/database" - authdomain "legalgo-BE-go/internal/domain/auth" + userdomain "legalgo-BE-go/internal/domain/user" ) type UserRepository struct { @@ -10,10 +10,10 @@ type UserRepository struct { } type UserIntf interface { - GetUserByEmail(string) (*authdomain.User, error) - GetUserByID(string) (*authdomain.UserProfile, error) - GetUserProfile(string) (*authdomain.UserProfile, error) - CreateUser(*authdomain.User) (*authdomain.User, error) + GetUserByEmail(string) (*userdomain.User, error) + GetUserByID(string) (*userdomain.User, error) + GetUserProfile(string) (*userdomain.UserProfile, error) + CreateUser(userdomain.User) error } func New( diff --git a/internal/api/http/auth/login.go b/internal/api/http/auth/login_staff.go similarity index 56% rename from internal/api/http/auth/login.go rename to internal/api/http/auth/login_staff.go index 189dd01..498fb1c 100644 --- a/internal/api/http/auth/login.go +++ b/internal/api/http/auth/login_staff.go @@ -3,24 +3,27 @@ package authhttp import ( "net/http" - authdomain "legalgo-BE-go/internal/domain/auth" + responsedomain "legalgo-BE-go/internal/domain/reponse" + staffdomain "legalgo-BE-go/internal/domain/staff" authsvc "legalgo-BE-go/internal/services/auth" "legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/utils" "github.com/go-chi/chi/v5" "github.com/go-playground/validator/v10" + "github.com/redis/go-redis/v9" ) func LoginStaff( router chi.Router, - authSvc authsvc.AuthIntf, + authSvc authsvc.Auth, validate *validator.Validate, + rdb *redis.Client, ) { router.Post("/staff/login", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - var spec authdomain.LoginReq + var spec staffdomain.StaffLogin if err := utils.UnmarshalBody(r, &spec); err != nil { response.ResponseWithErrorCode( @@ -59,50 +62,7 @@ func LoginStaff( return } - responsePayload := &authdomain.AuthResponse{ - 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 { + if err := utils.StoreTokenRedis(ctx, rdb, token, spec.Email); err != nil { response.ResponseWithErrorCode( ctx, w, @@ -114,7 +74,7 @@ func LoginUser( return } - responsePayload := &authdomain.AuthResponse{ + responsePayload := &responsedomain.Auth{ Token: token, } diff --git a/internal/api/http/auth/login_user.go b/internal/api/http/auth/login_user.go new file mode 100644 index 0000000..c69c9df --- /dev/null +++ b/internal/api/http/auth/login_user.go @@ -0,0 +1,82 @@ +package authhttp + +import ( + responsedomain "legalgo-BE-go/internal/domain/reponse" + userdomain "legalgo-BE-go/internal/domain/user" + authsvc "legalgo-BE-go/internal/services/auth" + "legalgo-BE-go/internal/utilities/response" + "legalgo-BE-go/internal/utilities/utils" + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/go-playground/validator/v10" + "github.com/redis/go-redis/v9" +) + +func LoginUser( + router chi.Router, + authSvc authsvc.Auth, + validate *validator.Validate, + rdb *redis.Client, +) { + router.Post("/user/login", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var spec userdomain.UserLogin + + 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 + } + + if err := utils.StoreTokenRedis(ctx, rdb, token, spec.Email); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.Error(), + ) + return + } + + responsePayload := &responsedomain.Auth{ + Token: token, + } + + response.RespondJsonSuccess(ctx, w, responsePayload) + }) +} diff --git a/internal/api/http/auth/profile.go b/internal/api/http/auth/profile.go index bacea45..e6c8f9c 100644 --- a/internal/api/http/auth/profile.go +++ b/internal/api/http/auth/profile.go @@ -11,7 +11,7 @@ import ( func GetStaffProfile( router chi.Router, - authSvc authsvc.AuthIntf, + authSvc authsvc.Auth, ) { router.Get("/staff/profile", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -47,7 +47,7 @@ func GetStaffProfile( func GetUserProfile( router chi.Router, - authSvc authsvc.AuthIntf, + authSvc authsvc.Auth, ) { router.Get("/user/profile", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/internal/api/http/auth/register.go b/internal/api/http/auth/register_staff.go similarity index 56% rename from internal/api/http/auth/register.go rename to internal/api/http/auth/register_staff.go index 58d2201..1429838 100644 --- a/internal/api/http/auth/register.go +++ b/internal/api/http/auth/register_staff.go @@ -3,79 +3,27 @@ package authhttp import ( "net/http" - authdomain "legalgo-BE-go/internal/domain/auth" + responsedomain "legalgo-BE-go/internal/domain/reponse" + staffdomain "legalgo-BE-go/internal/domain/staff" authsvc "legalgo-BE-go/internal/services/auth" "legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/utils" "github.com/go-chi/chi/v5" "github.com/go-playground/validator/v10" + "github.com/redis/go-redis/v9" ) -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 - } - - responsePayload := &authdomain.AuthResponse{ - Token: token, - } - - response.RespondJsonSuccess(ctx, w, responsePayload) - }) -} - func RegisterStaff( router chi.Router, validate *validator.Validate, - authSvc authsvc.AuthIntf, + authSvc authsvc.Auth, + rdb *redis.Client, ) { router.Post("/staff/register", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - var spec authdomain.RegisterStaffReq + var spec staffdomain.StaffRegister if err := utils.UnmarshalBody(r, &spec); err != nil { response.ResponseWithErrorCode( @@ -113,7 +61,20 @@ func RegisterStaff( ) return } - responsePayload := &authdomain.AuthResponse{ + + if err := utils.StoreTokenRedis(ctx, rdb, token, spec.Email); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.Error(), + ) + return + } + + responsePayload := &responsedomain.Auth{ Token: token, } response.RespondJsonSuccess(ctx, w, responsePayload) diff --git a/internal/api/http/auth/register_user.go b/internal/api/http/auth/register_user.go new file mode 100644 index 0000000..01ea918 --- /dev/null +++ b/internal/api/http/auth/register_user.go @@ -0,0 +1,82 @@ +package authhttp + +import ( + responsedomain "legalgo-BE-go/internal/domain/reponse" + userdomain "legalgo-BE-go/internal/domain/user" + authsvc "legalgo-BE-go/internal/services/auth" + "legalgo-BE-go/internal/utilities/response" + "legalgo-BE-go/internal/utilities/utils" + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/go-playground/validator/v10" + "github.com/redis/go-redis/v9" +) + +func RegisterUser( + router chi.Router, + validate *validator.Validate, + authSvc authsvc.Auth, + rdb *redis.Client, +) { + router.Post("/user/register", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var spec userdomain.UserRegister + + 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 + } + + if err := utils.StoreTokenRedis(ctx, rdb, token, spec.Email); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.Error(), + ) + return + } + + responsePayload := &responsedomain.Auth{ + Token: token, + } + + response.RespondJsonSuccess(ctx, w, responsePayload) + }) +} diff --git a/internal/api/http/auth/update.go b/internal/api/http/auth/update.go index cef4f0d..a644358 100644 --- a/internal/api/http/auth/update.go +++ b/internal/api/http/auth/update.go @@ -2,7 +2,7 @@ package authhttp import ( "errors" - authdomain "legalgo-BE-go/internal/domain/auth" + staffdomain "legalgo-BE-go/internal/domain/staff" authsvc "legalgo-BE-go/internal/services/auth" "legalgo-BE-go/internal/utilities/response" "legalgo-BE-go/internal/utilities/utils" @@ -13,7 +13,7 @@ import ( func UpdateStaff( router chi.Router, - authSvc authsvc.AuthIntf, + authSvc authsvc.Auth, ) { router.Patch("/staff/{id}/update", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -31,7 +31,7 @@ func UpdateStaff( return } - var spec authdomain.RegisterStaffReq + var spec staffdomain.StaffRegister if err := utils.UnmarshalBody(r, &spec); err != nil { response.ResponseWithErrorCode( @@ -45,7 +45,7 @@ func UpdateStaff( return } - staff := authdomain.Staff{ + staff := staffdomain.Staff{ ID: id, Email: spec.Email, Password: spec.Password, diff --git a/internal/api/http/category/create.go b/internal/api/http/category/create.go index ecaec52..f5f3fd3 100644 --- a/internal/api/http/category/create.go +++ b/internal/api/http/category/create.go @@ -1,6 +1,7 @@ package categoryhttp import ( + authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth" categorydomain "legalgo-BE-go/internal/domain/category" categorysvc "legalgo-BE-go/internal/services/category" "legalgo-BE-go/internal/utilities/response" @@ -16,52 +17,54 @@ func Create( validate *validator.Validate, categorySvc categorysvc.Category, ) { - router.Post("/category/create", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() + router. + With(authmiddleware.Authorize()). + Post("/category/create", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() - var spec categorydomain.CategoryReq + var spec categorydomain.CategoryReq - if err := utils.UnmarshalBody(r, &spec); err != nil { - response.ResponseWithErrorCode( - ctx, - w, - err, - response.ErrBadRequest.Code, - response.ErrBadRequest.HttpCode, - err.Error(), - ) + if err := utils.UnmarshalBody(r, &spec); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.Error(), + ) - return - } + 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 := validate.Struct(spec); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.(validator.ValidationErrors).Error(), + ) + return + } - if err := categorySvc.Create(spec); err != nil { - response.ResponseWithErrorCode( - ctx, - w, - err, - response.ErrCreateEntity.Code, - response.ErrCreateEntity.HttpCode, - err.Error(), - ) - return - } + if err := categorySvc.Create(spec); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrCreateEntity.Code, + response.ErrCreateEntity.HttpCode, + err.Error(), + ) + return + } - response.RespondJsonSuccess(ctx, w, struct { - Message string - }{ - Message: "category created successfully", + response.RespondJsonSuccess(ctx, w, struct { + Message string + }{ + Message: "category created successfully", + }) }) - }) } diff --git a/internal/api/http/category/get_all.go b/internal/api/http/category/get_all.go index 935d385..64e9869 100644 --- a/internal/api/http/category/get_all.go +++ b/internal/api/http/category/get_all.go @@ -14,7 +14,7 @@ func GetAll( ) { router.Get("/category", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - subsPlan, err := categorySvc.GetAllModel() + subsPlan, err := categorySvc.GetAll() // subsPlan, err := categorySvc.GetAll() if err != nil { response.ResponseWithErrorCode( diff --git a/internal/api/http/category/module.go b/internal/api/http/category/module.go index 6b0e5a2..8e1a902 100644 --- a/internal/api/http/category/module.go +++ b/internal/api/http/category/module.go @@ -5,4 +5,5 @@ import "go.uber.org/fx" var Module = fx.Module("categories", fx.Invoke( Create, GetAll, + Update, )) diff --git a/internal/api/http/category/update.go b/internal/api/http/category/update.go new file mode 100644 index 0000000..a124abe --- /dev/null +++ b/internal/api/http/category/update.go @@ -0,0 +1,82 @@ +package categoryhttp + +import ( + "fmt" + authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth" + categorydomain "legalgo-BE-go/internal/domain/category" + categorysvc "legalgo-BE-go/internal/services/category" + "legalgo-BE-go/internal/utilities/response" + "legalgo-BE-go/internal/utilities/utils" + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/go-playground/validator/v10" +) + +func Update( + router chi.Router, + validate *validator.Validate, + categorySvc categorysvc.Category, +) { + router. + With(authmiddleware.Authorize()). + Put("/category/{category_id}/update", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + categoryID := chi.URLParam(r, "category_id") + + if categoryID == "" { + response.RespondJsonErrorWithCode( + ctx, + w, + fmt.Errorf("category id is not provided"), + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + "category id is not provided", + ) + return + } + + var spec categorydomain.CategoryReq + if err := utils.UnmarshalBody(r, &spec); err != nil { + response.RespondJsonErrorWithCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + "failed to unmarshal body", + ) + return + } + + if err := validate.Struct(spec); err != nil { + response.RespondJsonErrorWithCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.(validator.ValidationErrors).Error(), + ) + return + } + + if err := categorySvc.Update(categoryID, spec); err != nil { + response.RespondJsonErrorWithCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.Error(), + ) + return + } + + response.RespondJsonSuccess(ctx, w, struct { + Message string + }{ + Message: "update category success", + }) + }) +} diff --git a/internal/api/http/middleware/auth/authorize.go b/internal/api/http/middleware/auth/authorize.go index 3dc5320..95443b8 100644 --- a/internal/api/http/middleware/auth/authorize.go +++ b/internal/api/http/middleware/auth/authorize.go @@ -1,138 +1,76 @@ package authmiddleware -// import ( -// "context" -// "fmt" -// "net/http" -// "strings" +import ( + "context" + "fmt" + "net/http" + "time" -// redisaccessor "legalgo-BE-go/internal/accessor/redis" -// contextkeyenum "legalgo-BE-go/internal/enums/context_key" -// jwtclaimenum "legalgo-BE-go/internal/enums/jwt" -// resourceenum "legalgo-BE-go/internal/enums/resource" -// "legalgo-BE-go/internal/services/auth" -// "github.com/golang-jwt/jwt/v5" -// ) + redisaccessor "legalgo-BE-go/internal/accessor/redis" + "legalgo-BE-go/internal/utilities/response" + "legalgo-BE-go/internal/utilities/utils" -// const SessionHeader = "Authorization" + "github.com/golang-jwt/jwt/v5" +) -// 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() +const SessionHeader = "Authorization" -// tokenString, err := GetToken(r) -// if err != nil { -// RespondWithError(w, r, err, "Invalid auth header") -// return -// } +func Authorize() 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() -// token, err := ValidateToken(ctx, tokenString) -// if err != nil { -// RespondWithError(w, r, err, err.Error()) -// return -// } + tokenString, err := utils.GetToken(r) + if err != nil { + response.RespondWithError(w, r, err, "Invalid auth header") + 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 -// } -// }) -// } -// } + spec, err := utils.GetTokenDetail(r) -// func GetToken(r *http.Request) (string, error) { -// tokenString := GetTokenFromHeader(r) -// if tokenString == "" { -// tokenString = getTokenFromQuery(r) -// } + token, err := ValidateToken(ctx, spec.Email) + if err != nil { + response.RespondWithError(w, r, err, err.Error()) + return + } -// if tokenString == "" { -// return "", fmt.Errorf("token not found") -// } + isValid := token == tokenString -// return tokenString, nil -// } + if !isValid { + response.RespondWithError(w, r, err, "invalid token") + return + } -// func GetTokenFromHeader(r *http.Request) string { -// session := r.Header.Get(SessionHeader) -// arr := strings.Split(session, " ") + next.ServeHTTP(w, r.WithContext(ctx)) + }) + } +} -// if len(arr) != 2 || strings.ToUpper(arr[0]) != "BEARER" { -// return "" -// } +func ValidateToken(ctx context.Context, id string) (string, error) { + redisClient := redisaccessor.Get() + redisToken, err := utils.GetTokenRedis(ctx, redisClient, id) -// return arr[1] -// } + if err != nil { + return "", err + } -// func getTokenFromQuery(r *http.Request) string { -// token := r.URL.Query().Get("token") -// return token -// } + token, err := utils.ParseToken(redisToken) -// 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{}) -// } + if err != nil { + return "", fmt.Errorf("invalid token: %w", err) + } -// resources := []resourceenum.Resource{} -// resourceMap := map[string]bool{} + // Check if the token is valid + if !token.Valid { + return "", fmt.Errorf("invalid token: token is not valid") + } -// for _, v := range rawResources { -// value := v.(string) -// resources = append(resources, resourceenum.Resource(value)) -// resourceMap[value] = true -// } + if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { + expirationTime := claims["exp"].(float64) // Expiration time in Unix timestamp format + if time.Unix(int64(expirationTime), 0).Before(time.Now()) { + return "", fmt.Errorf("token has expired") + } + } -// 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 -// } + return redisToken, nil +} diff --git a/internal/api/http/news/create.go b/internal/api/http/news/create.go index affe248..f5fb5f8 100644 --- a/internal/api/http/news/create.go +++ b/internal/api/http/news/create.go @@ -15,7 +15,7 @@ import ( func Create( validate *validator.Validate, newsSvc newssvc.News, - staffRepo staffrepository.StaffIntf, + staffRepo staffrepository.Staff, router chi.Router, ) { router.Post("/news/create", func(w http.ResponseWriter, r *http.Request) { diff --git a/internal/api/http/subscribe/module.go b/internal/api/http/subscribe/module.go new file mode 100644 index 0000000..21b8de2 --- /dev/null +++ b/internal/api/http/subscribe/module.go @@ -0,0 +1,5 @@ +package subscribehttp + +import "go.uber.org/fx" + +var Module = fx.Module("subscribe", fx.Invoke()) diff --git a/internal/api/http/subscribe/update.go b/internal/api/http/subscribe/update.go new file mode 100644 index 0000000..2b653a9 --- /dev/null +++ b/internal/api/http/subscribe/update.go @@ -0,0 +1,77 @@ +package subscribehttp + +import ( + authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth" + userdomain "legalgo-BE-go/internal/domain/user" + authsvc "legalgo-BE-go/internal/services/auth" + subscribesvc "legalgo-BE-go/internal/services/subscribe" + "legalgo-BE-go/internal/utilities/response" + "legalgo-BE-go/internal/utilities/utils" + "net/http" + + "github.com/go-chi/chi/v5" +) + +func Update( + router chi.Router, + authSvc authsvc.Auth, + subSvc subscribesvc.Subscribe, +) { + router. + With(authmiddleware.Authorize()). + Patch("/subscribe/update", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + detail, err := utils.GetTokenDetail(r) + if err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.Error(), + ) + return + } + + if detail.Role != "user" { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrUnauthorized.Code, + response.ErrUnauthorized.HttpCode, + "unauthorized", + ) + return + } + var body userdomain.UserSubsUpdate + err = utils.UnmarshalBody(r, &body) + if err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.Error(), + ) + return + } + + user, err := authSvc.GetUserProfile(detail.Email) + + if err := subSvc.Update(user.ID, body); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.Error(), + ) + return + } + }) +} diff --git a/internal/api/http/subscribe_plan/create.go b/internal/api/http/subscribe_plan/create.go index dc0f4e4..cad4cfb 100644 --- a/internal/api/http/subscribe_plan/create.go +++ b/internal/api/http/subscribe_plan/create.go @@ -3,6 +3,7 @@ package subscribeplanhttp import ( "net/http" + authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth" subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan" subscribeplansvc "legalgo-BE-go/internal/services/subscribe_plan" "legalgo-BE-go/internal/utilities/response" @@ -15,53 +16,55 @@ import ( func CreateSubscribePlan( router chi.Router, validate *validator.Validate, - subsSvc subscribeplansvc.SubsPlanIntf, + subsSvc subscribeplansvc.SubscribePlan, ) { - router.Post("/subscribe-plan/create", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() + router. + With(authmiddleware.Authorize()). + Post("/subscribe-plan/create", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() - var spec subscribeplandomain.SubscribePlanReq + 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 := 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 := 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); err != nil { - response.ResponseWithErrorCode( - ctx, - w, - err, - response.ErrCreateEntity.Code, - response.ErrCreateEntity.HttpCode, - err.Error(), - ) - return - } + if err := subsSvc.CreatePlan(spec); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrCreateEntity.Code, + response.ErrCreateEntity.HttpCode, + err.Error(), + ) + return + } - response.RespondJsonSuccess(ctx, w, struct { - Message string - }{ - Message: "subscription plan created successfully.", + response.RespondJsonSuccess(ctx, w, struct { + Message string + }{ + Message: "subscription plan created successfully.", + }) }) - }) } diff --git a/internal/api/http/subscribe_plan/get_all.go b/internal/api/http/subscribe_plan/get_all.go index d1c5b93..c560f1d 100644 --- a/internal/api/http/subscribe_plan/get_all.go +++ b/internal/api/http/subscribe_plan/get_all.go @@ -11,7 +11,7 @@ import ( func GetAllPlan( router chi.Router, - subsPlanSvc subscribeplansvc.SubsPlanIntf, + subsPlanSvc subscribeplansvc.SubscribePlan, ) { router.Get("/subscribe-plan", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/internal/api/http/tag/create.go b/internal/api/http/tag/create.go index c059f2e..b5fe831 100644 --- a/internal/api/http/tag/create.go +++ b/internal/api/http/tag/create.go @@ -3,6 +3,7 @@ package taghttp import ( "net/http" + authmiddleware "legalgo-BE-go/internal/api/http/middleware/auth" tagdomain "legalgo-BE-go/internal/domain/tag" tagsvc "legalgo-BE-go/internal/services/tag" "legalgo-BE-go/internal/utilities/response" @@ -15,53 +16,55 @@ import ( func Create( router chi.Router, validate *validator.Validate, - tagSvc tagsvc.TagIntf, + tagSvc tagsvc.Tag, ) { - router.Post("/tag/create", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() + router. + With(authmiddleware.Authorize()). + Post("/tag/create", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() - var spec tagdomain.TagReq + var spec tagdomain.TagReq - 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 := 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 := validate.Struct(spec); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.(validator.ValidationErrors).Error(), + ) + return + } - if err := tagSvc.Create(spec); err != nil { - response.ResponseWithErrorCode( - ctx, - w, - err, - response.ErrCreateEntity.Code, - response.ErrCreateEntity.HttpCode, - err.Error(), - ) - return - } + if err := tagSvc.Create(spec); err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrCreateEntity.Code, + response.ErrCreateEntity.HttpCode, + err.Error(), + ) + return + } - response.RespondJsonSuccess(ctx, w, struct { - Message string - }{ - Message: "tag created successfully.", + response.RespondJsonSuccess(ctx, w, struct { + Message string + }{ + Message: "tag created successfully.", + }) }) - }) } diff --git a/internal/api/http/tag/get_all.go b/internal/api/http/tag/get_all.go index 2aecebf..34a9f7f 100644 --- a/internal/api/http/tag/get_all.go +++ b/internal/api/http/tag/get_all.go @@ -10,7 +10,7 @@ import ( func GetAll( router chi.Router, - tagSvc tagsvc.TagIntf, + tagSvc tagsvc.Tag, ) { router.Get("/tag", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/internal/domain/auth/login.go b/internal/domain/auth/login.go deleted file mode 100644 index 4a01c0f..0000000 --- a/internal/domain/auth/login.go +++ /dev/null @@ -1,32 +0,0 @@ -package authdomain - -type LoginReq struct { - Email string `json:"email" validate:"required"` - Password string `json:"password" validate:"required"` -} - -type AuthResponse struct { - Token string `json:"token"` -} - -type LoginRepoResponse struct { - ID string `json:"id"` - Email string `json:"email"` - Password string `json:"password"` - Username string `json:"username"` -} - -type StaffProfile struct { - ID string `json:"id"` - Email string `json:"email"` - Name string `json:"name"` - ProfilePicture string `json:"profile_picture"` -} - -type UserProfile struct { - ID string `json:"id"` - Email string `json:"email"` - SubscribePlanCode string `json:"subscribe_plan_code"` - SubscribePlanName string `json:"subscribe_plan_name"` - SubscribeStatus string `json:"subscribe_status"` -} diff --git a/internal/domain/auth/register.go b/internal/domain/auth/register.go deleted file mode 100644 index 3bff804..0000000 --- a/internal/domain/auth/register.go +++ /dev/null @@ -1,37 +0,0 @@ -package authdomain - -type RegisterUserReq struct { - Email string `json:"email" validate:"required"` - Password string `json:"password" validate:"required"` - Phone string `json:"phone" validate:"required"` - SubscribePlanID string `json:"subscribe_plan_id"` -} - -type User struct { - ID string `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"` - Name string `json:"name" validate:"required"` - ProfilePicture string `json:"profile_picture"` -} - -type UpdateStaffReq struct { - Email string `json:"email"` - Password string `json:"password"` - Name string `json:"name"` -} - -type Staff struct { - ID string `json:"id"` - Email string `json:"email"` - Password string `json:"password"` - Name string `json:"name"` - ProfilePicture string `json:"profile_picture"` -} diff --git a/internal/domain/auth/token.go b/internal/domain/auth/token.go index 55bab03..0bc17c2 100644 --- a/internal/domain/auth/token.go +++ b/internal/domain/auth/token.go @@ -3,4 +3,5 @@ package authdomain type AuthToken struct { Email string SessionID string + Role string } diff --git a/internal/domain/category/spec.go b/internal/domain/category/spec.go index 773fa4b..1594a8a 100644 --- a/internal/domain/category/spec.go +++ b/internal/domain/category/spec.go @@ -1,9 +1,13 @@ package categorydomain +import "time" + type Category struct { - ID string `json:"id" gorm:"primaryKey"` - Name string `json:"name"` - Code string `json:"code"` + ID string `json:"id"` + Name string `json:"name"` + Code string `json:"code"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } type CategoryReq struct { diff --git a/internal/domain/news/spec.go b/internal/domain/news/spec.go index d3a66e8..4d5a469 100644 --- a/internal/domain/news/spec.go +++ b/internal/domain/news/spec.go @@ -1,7 +1,7 @@ package newsdomain import ( - categorydomain "legalgo-BE-go/internal/domain/category" + "legalgo-BE-go/database" tagdomain "legalgo-BE-go/internal/domain/tag" "time" ) @@ -17,16 +17,16 @@ type NewsReq struct { } type News struct { - ID string `json:"id"` - Title string `json:"title"` - Content string `json:"content"` - FeaturedImage string `json:"featured_image"` - Tags []tagdomain.Tag `json:"tags"` - Categories []categorydomain.Category `json:"categories"` - IsPremium bool `json:"is_premium"` - Slug string `json:"slug"` - AuthorID string `json:"author_id"` - LiveAt time.Time `json:"live_at"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID string `json:"id"` + Title string `json:"title"` + Content string `json:"content"` + FeaturedImage string `json:"featured_image"` + Tags []tagdomain.Tag `json:"tags"` + Categories []database.Category `json:"categories"` + IsPremium bool `json:"is_premium"` + Slug string `json:"slug"` + AuthorID string `json:"author_id"` + LiveAt time.Time `json:"live_at"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } diff --git a/internal/domain/reponse/spec.go b/internal/domain/reponse/spec.go new file mode 100644 index 0000000..05c1ab4 --- /dev/null +++ b/internal/domain/reponse/spec.go @@ -0,0 +1,5 @@ +package responsedomain + +type Auth struct { + Token string `json:"token"` +} diff --git a/internal/domain/staff/spec.go b/internal/domain/staff/spec.go new file mode 100644 index 0000000..f174d1b --- /dev/null +++ b/internal/domain/staff/spec.go @@ -0,0 +1,28 @@ +package staffdomain + +type Staff struct { + ID string `json:"id"` + Name string `json:"name"` + ProfilePicture string `json:"profile_picture"` + Email string `json:"email"` + Password string `json:"password"` +} + +type StaffRegister struct { + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` + Name string `json:"name" validate:"required"` + ProfilePicture string `json:"profile_picture"` +} + +type StaffProfile struct { + ID string `json:"id"` + Name string `json:"name"` + ProfilePicture string `json:"profile_picture"` + Email string `json:"email"` +} + +type StaffLogin struct { + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` +} diff --git a/internal/domain/subscribe/spec.go b/internal/domain/subscribe/spec.go index 3fc2cfe..eb05bcb 100644 --- a/internal/domain/subscribe/spec.go +++ b/internal/domain/subscribe/spec.go @@ -1,6 +1,28 @@ package subscribedomain -type Subscribe struct { +import ( + subscribeplandm "legalgo-BE-go/internal/domain/subscribe_plan_model" + "time" +) + +type SubscribeDepecrate struct { ID string `json:"id"` SubscribePlanID string `json:"subscribe_plan_id"` } + +type SubscribeUpdateReqDepecrate struct { + ID string `json:"id"` + Status string `json:"status"` +} + +// refactored +type Subscribe struct { + ID string `gorm:"primaryKey" json:"id"` + SubscribePlanID string `gorm:"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"` + + SubscribePlan subscribeplandm.SubscribePlan `gorm:"foreignKey:SubscribePlanID;constraint:OnDelete:CASCADE" json:"subscribe_plan"` +} diff --git a/internal/domain/subscribe_model/response.go b/internal/domain/subscribe_model/response.go new file mode 100644 index 0000000..7403845 --- /dev/null +++ b/internal/domain/subscribe_model/response.go @@ -0,0 +1,17 @@ +package subscribedm + +import ( + subscribeplandm "legalgo-BE-go/internal/domain/subscribe_plan_model" + "time" +) + +type Subscribe struct { + ID string `json:"id"` + SubscribePlanID string `json:"subscribe_plan_id"` + StartDate time.Time `json:"start_date"` + EndDate *time.Time `json:"end_date"` + Status string `json:"status"` + AutoRenew bool `json:"auto_renew"` + + SubscribePlan subscribeplandm.SubscribePlan `gorm:"foreignKey:SubscribePlanID" json:"subscribe_plan"` +} diff --git a/internal/domain/subscribe_plan_model/response.go b/internal/domain/subscribe_plan_model/response.go new file mode 100644 index 0000000..e76937e --- /dev/null +++ b/internal/domain/subscribe_plan_model/response.go @@ -0,0 +1,8 @@ +package subscribeplandm + +// refactored +type SubscribePlan struct { + ID string `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} diff --git a/internal/domain/user/spec.go b/internal/domain/user/spec.go new file mode 100644 index 0000000..6450813 --- /dev/null +++ b/internal/domain/user/spec.go @@ -0,0 +1,37 @@ +package userdomain + +import subscribedm "legalgo-BE-go/internal/domain/subscribe_model" + +type User struct { + ID string `json:"id"` + SubscribeID string `json:"subscribe_id"` + Password string `json:"password"` + Email string `json:"email"` + Phone string `json:"phone"` + + Subscribe subscribedm.Subscribe `gorm:"foreignKey:SubscribeID" json:"subscribe"` +} + +type UserRegister struct { + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` + Phone string `json:"phone" validate:"required"` + SubscribePlanID string `json:"subscribe_plan_id"` +} + +type UserProfile struct { + ID string `json:"id"` + Email string `json:"email"` + Phone string `json:"phone"` + + Subscribe subscribedm.Subscribe `gorm:"foreignKey:SubscribeID" json:"subscribe"` +} + +type UserLogin struct { + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` +} + +type UserSubsUpdate struct { + Status string `json:"status"` +} diff --git a/internal/services/auth/get_staff.go b/internal/services/auth/get_staff.go index 621a513..d9f53e4 100644 --- a/internal/services/auth/get_staff.go +++ b/internal/services/auth/get_staff.go @@ -1,14 +1,16 @@ package authsvc -import authdomain "legalgo-BE-go/internal/domain/auth" +import ( + staffdomain "legalgo-BE-go/internal/domain/staff" +) -func (as *AuthSvc) GetStaffProfile(email string) (*authdomain.StaffProfile, error) { +func (as *impl) GetStaffProfile(email string) (*staffdomain.StaffProfile, error) { staff, err := as.staffRepo.GetStaffByEmail(email) if err != nil { return nil, err } - profile := &authdomain.StaffProfile{ + profile := &staffdomain.StaffProfile{ ID: staff.ID, Name: staff.Name, Email: staff.Email, diff --git a/internal/services/auth/get_user.go b/internal/services/auth/get_user.go index 9b407c4..1501948 100644 --- a/internal/services/auth/get_user.go +++ b/internal/services/auth/get_user.go @@ -1,8 +1,10 @@ package authsvc -import authdomain "legalgo-BE-go/internal/domain/auth" +import ( + userdomain "legalgo-BE-go/internal/domain/user" +) -func (as *AuthSvc) GetUserProfile(email string) (*authdomain.UserProfile, error) { +func (as *impl) GetUserProfile(email string) (*userdomain.UserProfile, error) { user, err := as.userRepo.GetUserProfile(email) if err != nil { return nil, err diff --git a/internal/services/auth/impl.go b/internal/services/auth/impl.go index 2fce25c..ef38806 100644 --- a/internal/services/auth/impl.go +++ b/internal/services/auth/impl.go @@ -5,34 +5,35 @@ import ( subscriberepository "legalgo-BE-go/internal/accessor/subscribe" subscribeplanrepository "legalgo-BE-go/internal/accessor/subscribeplan" userrepository "legalgo-BE-go/internal/accessor/user_repository" - authdomain "legalgo-BE-go/internal/domain/auth" + staffdomain "legalgo-BE-go/internal/domain/staff" + userdomain "legalgo-BE-go/internal/domain/user" ) -type AuthSvc struct { - staffRepo staffrepository.StaffIntf +type impl struct { + staffRepo staffrepository.Staff userRepo userrepository.UserIntf subsRepo subscriberepository.SubsIntf subsPlanRepo subscribeplanrepository.SubsPlanIntf } -type AuthIntf interface { - LoginAsStaff(authdomain.LoginReq) (string, error) - RegisterUser(authdomain.RegisterUserReq) (string, error) - GetUserProfile(string) (*authdomain.UserProfile, error) +type Auth interface { + LoginAsStaff(staffdomain.StaffLogin) (string, error) + RegisterStaff(staffdomain.StaffRegister) (string, error) + GetStaffProfile(string) (*staffdomain.StaffProfile, error) + UpdateStaff(staffdomain.Staff) error - LoginAsUser(authdomain.LoginReq) (string, error) - RegisterStaff(authdomain.RegisterStaffReq) (string, error) - UpdateStaff(authdomain.Staff) error - GetStaffProfile(string) (*authdomain.StaffProfile, error) + LoginAsUser(userdomain.UserLogin) (string, error) + RegisterUser(userdomain.UserRegister) (string, error) + GetUserProfile(string) (*userdomain.UserProfile, error) } func New( - staffRepo staffrepository.StaffIntf, + staffRepo staffrepository.Staff, userRepo userrepository.UserIntf, subsRepo subscriberepository.SubsIntf, subsPlanRepo subscribeplanrepository.SubsPlanIntf, -) AuthIntf { - return &AuthSvc{ +) Auth { + return &impl{ staffRepo: staffRepo, userRepo: userRepo, subsRepo: subsRepo, diff --git a/internal/services/auth/login_as_staff.go b/internal/services/auth/login_as_staff.go index 4f2cc8a..2fef1c9 100644 --- a/internal/services/auth/login_as_staff.go +++ b/internal/services/auth/login_as_staff.go @@ -4,12 +4,13 @@ import ( "errors" authdomain "legalgo-BE-go/internal/domain/auth" + staffdomain "legalgo-BE-go/internal/domain/staff" "legalgo-BE-go/internal/utilities/utils" "github.com/google/uuid" ) -func (sv *AuthSvc) LoginAsStaff(spec authdomain.LoginReq) (string, error) { +func (sv *impl) LoginAsStaff(spec staffdomain.StaffLogin) (string, error) { staff, err := sv.staffRepo.GetStaffByEmail(spec.Email) if err != nil { return "", errors.New(err.Error()) @@ -23,6 +24,7 @@ func (sv *AuthSvc) LoginAsStaff(spec authdomain.LoginReq) (string, error) { authToken := authdomain.AuthToken{ Email: staff.Email, SessionID: uuid.NewString(), + Role: "staff", } token, err := utils.GenerateToken(authToken) diff --git a/internal/services/auth/login_as_user.go b/internal/services/auth/login_as_user.go index e99c9c4..d553d5e 100644 --- a/internal/services/auth/login_as_user.go +++ b/internal/services/auth/login_as_user.go @@ -4,12 +4,13 @@ import ( "errors" authdomain "legalgo-BE-go/internal/domain/auth" + userdomain "legalgo-BE-go/internal/domain/user" "legalgo-BE-go/internal/utilities/utils" "github.com/google/uuid" ) -func (a *AuthSvc) LoginAsUser(spec authdomain.LoginReq) (string, error) { +func (a *impl) LoginAsUser(spec userdomain.UserLogin) (string, error) { user, err := a.userRepo.GetUserByEmail(spec.Email) if err != nil { return "", errors.New(err.Error()) @@ -23,6 +24,7 @@ func (a *AuthSvc) LoginAsUser(spec authdomain.LoginReq) (string, error) { authToken := authdomain.AuthToken{ Email: user.Email, SessionID: uuid.NewString(), + Role: "user", } token, err := utils.GenerateToken(authToken) diff --git a/internal/services/auth/register_staff.go b/internal/services/auth/register_staff.go index b10757e..82ccdd3 100644 --- a/internal/services/auth/register_staff.go +++ b/internal/services/auth/register_staff.go @@ -4,12 +4,13 @@ import ( "errors" authdomain "legalgo-BE-go/internal/domain/auth" + staffdomain "legalgo-BE-go/internal/domain/staff" "legalgo-BE-go/internal/utilities/utils" "github.com/google/uuid" ) -func (a *AuthSvc) RegisterStaff(spec authdomain.RegisterStaffReq) (string, error) { +func (a *impl) RegisterStaff(spec staffdomain.StaffRegister) (string, error) { _, err := a.staffRepo.GetStaffByEmail(spec.Email) if err == nil { return "", errors.New("this email address is already in use") @@ -19,7 +20,7 @@ func (a *AuthSvc) RegisterStaff(spec authdomain.RegisterStaffReq) (string, error return "", err } - staff := authdomain.Staff{ + staff := staffdomain.Staff{ ID: uuid.NewString(), Email: spec.Email, Password: hashedPwd, @@ -27,7 +28,7 @@ func (a *AuthSvc) RegisterStaff(spec authdomain.RegisterStaffReq) (string, error ProfilePicture: spec.ProfilePicture, } - _, err = a.staffRepo.Create(&staff) + err = a.staffRepo.Create(staff) if err != nil { return "", errors.New(err.Error()) } @@ -35,6 +36,7 @@ func (a *AuthSvc) RegisterStaff(spec authdomain.RegisterStaffReq) (string, error authToken := authdomain.AuthToken{ Email: staff.Email, SessionID: uuid.NewString(), + Role: "staff", } token, err := utils.GenerateToken(authToken) diff --git a/internal/services/auth/register_user.go b/internal/services/auth/register_user.go index 618da88..da1ec82 100644 --- a/internal/services/auth/register_user.go +++ b/internal/services/auth/register_user.go @@ -4,12 +4,13 @@ import ( "errors" authdomain "legalgo-BE-go/internal/domain/auth" + userdomain "legalgo-BE-go/internal/domain/user" "legalgo-BE-go/internal/utilities/utils" "github.com/google/uuid" ) -func (a *AuthSvc) RegisterUser(spec authdomain.RegisterUserReq) (string, error) { +func (a *impl) RegisterUser(spec userdomain.UserRegister) (string, error) { _, err := a.userRepo.GetUserByEmail(spec.Email) if err == nil { @@ -40,7 +41,7 @@ func (a *AuthSvc) RegisterUser(spec authdomain.RegisterUserReq) (string, error) return "", err } - user := authdomain.User{ + user := userdomain.User{ ID: uuid.NewString(), Email: spec.Email, SubscribeID: subsId, @@ -48,7 +49,7 @@ func (a *AuthSvc) RegisterUser(spec authdomain.RegisterUserReq) (string, error) Phone: spec.Phone, } - _, err = a.userRepo.CreateUser(&user) + err = a.userRepo.CreateUser(user) if err != nil { return "", errors.New(err.Error()) } @@ -56,6 +57,7 @@ func (a *AuthSvc) RegisterUser(spec authdomain.RegisterUserReq) (string, error) authToken := authdomain.AuthToken{ Email: user.Email, SessionID: uuid.NewString(), + Role: "user", } token, err := utils.GenerateToken(authToken) diff --git a/internal/services/auth/update_staff.go b/internal/services/auth/update_staff.go index 0e4ead1..fb147bc 100644 --- a/internal/services/auth/update_staff.go +++ b/internal/services/auth/update_staff.go @@ -1,8 +1,10 @@ package authsvc -import authdomain "legalgo-BE-go/internal/domain/auth" +import ( + staffdomain "legalgo-BE-go/internal/domain/staff" +) -func (as *AuthSvc) UpdateStaff(spec authdomain.Staff) error { +func (as *impl) UpdateStaff(spec staffdomain.Staff) error { if _, err := as.staffRepo.GetStaffByID(spec.ID); err != nil { return err } diff --git a/internal/services/category/get_all.go b/internal/services/category/get_all.go index 48419a6..82d8852 100644 --- a/internal/services/category/get_all.go +++ b/internal/services/category/get_all.go @@ -1,7 +1,9 @@ package categorysvc -import categorydomain "legalgo-BE-go/internal/domain/category" +import ( + categorydomain "legalgo-BE-go/internal/domain/category" +) func (i *impl) GetAll() ([]categorydomain.Category, error) { - return i.categoryRepo.GetAll() + return i.categoryRepo.GetAllModel() } diff --git a/internal/services/category/get_all_model.go b/internal/services/category/get_all_model.go deleted file mode 100644 index d44762a..0000000 --- a/internal/services/category/get_all_model.go +++ /dev/null @@ -1,9 +0,0 @@ -package categorysvc - -import ( - "legalgo-BE-go/database" -) - -func (i *impl) GetAllModel() ([]database.CategoryModel, error) { - return i.categoryRepo.GetAllModel() -} diff --git a/internal/services/category/impl.go b/internal/services/category/impl.go index 55ba775..7314470 100644 --- a/internal/services/category/impl.go +++ b/internal/services/category/impl.go @@ -1,7 +1,6 @@ package categorysvc import ( - "legalgo-BE-go/database" categoryrepository "legalgo-BE-go/internal/accessor/category" categorydomain "legalgo-BE-go/internal/domain/category" ) @@ -13,7 +12,7 @@ type impl struct { type Category interface { Create(categorydomain.CategoryReq) error GetAll() ([]categorydomain.Category, error) - GetAllModel() ([]database.CategoryModel, error) + Update(string, categorydomain.CategoryReq) error } func New( diff --git a/internal/services/category/update.go b/internal/services/category/update.go new file mode 100644 index 0000000..adea362 --- /dev/null +++ b/internal/services/category/update.go @@ -0,0 +1,21 @@ +package categorysvc + +import ( + categorydomain "legalgo-BE-go/internal/domain/category" + timeutils "legalgo-BE-go/internal/utilities/time_utils" +) + +func (i *impl) Update(categoryID string, spec categorydomain.CategoryReq) error { + updateData := categorydomain.Category{ + ID: categoryID, + Name: spec.Name, + Code: spec.Code, + UpdatedAt: timeutils.Now(), + } + + if err := i.categoryRepo.Update(updateData); err != nil { + return err + } + + return nil +} diff --git a/internal/services/news/create_model.go b/internal/services/news/create_model.go index 2dd5acd..40f4097 100644 --- a/internal/services/news/create_model.go +++ b/internal/services/news/create_model.go @@ -17,7 +17,7 @@ func (i *impl) CreateModel(spec newsdomain.NewsReq, staffId string) error { return err } - categories, err := i.categoryRepo.GetBulks(spec.Categories) + categories, err := i.categoryRepo.GetByIDs(spec.Categories) if err != nil { return err } @@ -27,7 +27,7 @@ func (i *impl) CreateModel(spec newsdomain.NewsReq, staffId string) error { return err } - newSpec := database.NewsModel{ + newSpec := database.News{ ID: uuid.NewString(), Title: spec.Title, Content: spec.Content, diff --git a/internal/services/news/get_all_model.go b/internal/services/news/get_all_model.go index cebb5fa..42e8b4e 100644 --- a/internal/services/news/get_all_model.go +++ b/internal/services/news/get_all_model.go @@ -4,6 +4,6 @@ import ( "legalgo-BE-go/database" ) -func (i *impl) GetAllModel() ([]database.NewsModel, error) { +func (i *impl) GetAllModel() ([]database.News, error) { return i.newsRepo.GetAllModel() } diff --git a/internal/services/news/impl.go b/internal/services/news/impl.go index ecdae09..92c4cce 100644 --- a/internal/services/news/impl.go +++ b/internal/services/news/impl.go @@ -16,7 +16,7 @@ type impl struct { type News interface { GetAll() ([]newsdomain.News, error) - GetAllModel() ([]database.NewsModel, error) + GetAllModel() ([]database.News, error) Create(newsdomain.NewsReq, string) error CreateModel(newsdomain.NewsReq, string) error } diff --git a/internal/services/subscribe/create.go b/internal/services/subscribe/create.go index 4a0b1e5..11c043c 100644 --- a/internal/services/subscribe/create.go +++ b/internal/services/subscribe/create.go @@ -1,6 +1,6 @@ package subscribesvc -func (s *SubsSvc) Create(subsPlanId string) (string, error) { +func (s *impl) Create(subsPlanId string) (string, error) { subsId, err := s.subsRepo.Create(subsPlanId) if err != nil { return "", err diff --git a/internal/services/subscribe/impl.go b/internal/services/subscribe/impl.go index 413003b..a2d6061 100644 --- a/internal/services/subscribe/impl.go +++ b/internal/services/subscribe/impl.go @@ -1,15 +1,19 @@ package subscribesvc -import subscriberepository "legalgo-BE-go/internal/accessor/subscribe" +import ( + subscriberepository "legalgo-BE-go/internal/accessor/subscribe" + userdomain "legalgo-BE-go/internal/domain/user" +) -type SubsSvc struct { +type impl struct { subsRepo subscriberepository.SubsIntf } -type SubsIntf interface { +type Subscribe interface { Create(string) (string, error) + Update(string, userdomain.UserSubsUpdate) error } -func New(subsRepo subscriberepository.SubsIntf) SubsIntf { - return &SubsSvc{subsRepo} +func New(subsRepo subscriberepository.SubsIntf) Subscribe { + return &impl{subsRepo} } diff --git a/internal/services/subscribe/update.go b/internal/services/subscribe/update.go new file mode 100644 index 0000000..5664353 --- /dev/null +++ b/internal/services/subscribe/update.go @@ -0,0 +1,9 @@ +package subscribesvc + +import ( + userdomain "legalgo-BE-go/internal/domain/user" +) + +func (i *impl) Update(id string, spec userdomain.UserSubsUpdate) error { + return nil +} diff --git a/internal/services/subscribe_plan/create_plan.go b/internal/services/subscribe_plan/create_plan.go index 5185f87..6b1992a 100644 --- a/internal/services/subscribe_plan/create_plan.go +++ b/internal/services/subscribe_plan/create_plan.go @@ -2,6 +2,6 @@ package subscribeplansvc import subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan" -func (sb *SubsPlanSvc) CreatePlan(spec subscribeplandomain.SubscribePlanReq) error { +func (sb *impl) CreatePlan(spec subscribeplandomain.SubscribePlanReq) error { return sb.subsAccs.Create(spec) } diff --git a/internal/services/subscribe_plan/get_all_plan.go b/internal/services/subscribe_plan/get_all_plan.go index 287a5af..819e1f7 100644 --- a/internal/services/subscribe_plan/get_all_plan.go +++ b/internal/services/subscribe_plan/get_all_plan.go @@ -4,6 +4,6 @@ import ( subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan" ) -func (s *SubsPlanSvc) GetAllPlan() ([]subscribeplandomain.SubscribePlan, error) { +func (s *impl) GetAllPlan() ([]subscribeplandomain.SubscribePlan, error) { return s.subsAccs.GetAll() } diff --git a/internal/services/subscribe_plan/impl.go b/internal/services/subscribe_plan/impl.go index a63f4a3..c1b6b41 100644 --- a/internal/services/subscribe_plan/impl.go +++ b/internal/services/subscribe_plan/impl.go @@ -5,17 +5,17 @@ import ( subscribeplandomain "legalgo-BE-go/internal/domain/subscribe_plan" ) -type SubsPlanSvc struct { +type impl struct { subsAccs subscribeplanrepository.SubsPlanIntf } -type SubsPlanIntf interface { +type SubscribePlan interface { CreatePlan(subscribeplandomain.SubscribePlanReq) error GetAllPlan() ([]subscribeplandomain.SubscribePlan, error) } func New( subsAccs subscribeplanrepository.SubsPlanIntf, -) SubsPlanIntf { - return &SubsPlanSvc{subsAccs} +) SubscribePlan { + return &impl{subsAccs} } diff --git a/internal/services/tag/get_all_model.go b/internal/services/tag/get_all_model.go index 8fa0e54..70e268a 100644 --- a/internal/services/tag/get_all_model.go +++ b/internal/services/tag/get_all_model.go @@ -4,6 +4,6 @@ import ( "legalgo-BE-go/database" ) -func (i *impl) GetAllModel() ([]database.TagModel, error) { +func (i *impl) GetAllModel() ([]database.Tag, error) { return i.tagRepo.GetAllModel() } diff --git a/internal/services/tag/impl.go b/internal/services/tag/impl.go index b0f6294..19fb506 100644 --- a/internal/services/tag/impl.go +++ b/internal/services/tag/impl.go @@ -10,14 +10,14 @@ type impl struct { tagRepo tagrepository.TagAccessor } -type TagIntf interface { +type Tag interface { Create(tagdomain.TagReq) error GetAll() ([]tagdomain.Tag, error) - GetAllModel() ([]database.TagModel, error) + GetAllModel() ([]database.Tag, error) } func New( tagRepo tagrepository.TagAccessor, -) TagIntf { +) Tag { return &impl{tagRepo} } diff --git a/internal/utilities/response/error_code.go b/internal/utilities/response/error_code.go index 958bd00..630b366 100644 --- a/internal/utilities/response/error_code.go +++ b/internal/utilities/response/error_code.go @@ -14,8 +14,10 @@ func (e ErrorCode) Error() string { var ( // 4xx - ErrBadRequest = &ErrorCode{Code: "BAD_REQUEST", Message: "BAD_REQUEST", HttpCode: http.StatusBadRequest} - ErrDBRequest = &ErrorCode{Code: "BAD_DB_REQUEST", Message: "DB_ERROR", HttpCode: http.StatusBadRequest} + ErrBadRequest = &ErrorCode{Code: "BAD_REQUEST", Message: "BAD_REQUEST", HttpCode: http.StatusBadRequest} + ErrUnauthorized = &ErrorCode{Code: "UNAUTHORIZED", Message: "UNAUTHORIZED", HttpCode: http.StatusUnauthorized} + ErrDBRequest = &ErrorCode{Code: "BAD_DB_REQUEST", Message: "DB_ERROR", HttpCode: http.StatusBadRequest} + ErrExpiryToken = &ErrorCode{Code: "EXPIRED_TOKEN", Message: "EXPIRED_TOKEN", HttpCode: http.StatusUnauthorized} // 5xx ErrMarshal = &ErrorCode{Code: "FAILED_MARSHAL", Message: "FAILED_MARSHAL_BODY", HttpCode: http.StatusInternalServerError} diff --git a/internal/utilities/response/response_json_error.go b/internal/utilities/response/response_json_error.go new file mode 100644 index 0000000..3e40ec0 --- /dev/null +++ b/internal/utilities/response/response_json_error.go @@ -0,0 +1,23 @@ +package response + +import ( + "context" + "encoding/json" + "net/http" +) + +func RespondJsonErrorWithCode(ctx context.Context, w http.ResponseWriter, + err error, code string, statusCode int, message string) { + setDefaultHeaders(ctx, w.Header()) + + w.WriteHeader(statusCode) + + b, _ := json.Marshal(ErrorResponse{ + Error: ErrorResponseData{ + Code: code, + Message: message, + }, + }) + + w.Write(b) +} diff --git a/internal/utilities/response/response_with_error.go b/internal/utilities/response/response_with_error.go new file mode 100644 index 0000000..5d93e84 --- /dev/null +++ b/internal/utilities/response/response_with_error.go @@ -0,0 +1,23 @@ +package response + +import ( + "errors" + "net/http" +) + +func RespondWithError(w http.ResponseWriter, r *http.Request, err error, msg string) { + if err != nil { + code := ErrUnauthorized.Code + status := http.StatusUnauthorized + + if errors.Is(err, ErrExpiryToken) { + code = ErrExpiryToken.Code + status = ErrExpiryToken.HttpCode + } + + RespondJsonErrorWithCode(r.Context(), w, err, code, status, msg) + } else { + RespondJsonErrorWithCode(r.Context(), w, nil, + ErrUnauthorized.Code, http.StatusUnauthorized, msg) + } +} diff --git a/internal/utilities/utils/get_token.go b/internal/utilities/utils/get_token.go new file mode 100644 index 0000000..0f6f28f --- /dev/null +++ b/internal/utilities/utils/get_token.go @@ -0,0 +1,30 @@ +package utils + +import ( + "fmt" + "net/http" + "strings" +) + +const SessionHeader = "Authorization" + +func GetToken(r *http.Request) (string, error) { + token := getTokenFromHeader(r) + + if token == "" { + return "", fmt.Errorf("token not found") + } + + return token, 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] +} diff --git a/internal/utilities/utils/get_token_detail.go b/internal/utilities/utils/get_token_detail.go index 82fefbd..22d8cea 100644 --- a/internal/utilities/utils/get_token_detail.go +++ b/internal/utilities/utils/get_token_detail.go @@ -24,8 +24,8 @@ func GetTokenDetail(r *http.Request) (authdomain.AuthToken, error) { if len(token) < 2 { return data, errors.New("invalid token") } - data, err := DestructToken(token[1]) + if err != nil { return data, err } diff --git a/internal/utilities/utils/jwt.go b/internal/utilities/utils/jwt.go index 7851e38..f8dd16a 100644 --- a/internal/utilities/utils/jwt.go +++ b/internal/utilities/utils/jwt.go @@ -33,11 +33,11 @@ type ClaimOption func(options jwt.MapClaims) func GenerateToken(data authdomain.AuthToken) (string, error) { now := timeutils.Now() - claims := jwt.MapClaims{ "email": data.Email, + "role": data.Role, "session_id": data.SessionID, - "exp": now.Add(1 * time.Hour).Unix(), + "exp": now.Add(time.Minute * time.Duration(config.REDIS_TIMEOUT)).Unix(), } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) @@ -45,11 +45,10 @@ func GenerateToken(data authdomain.AuthToken) (string, error) { return token.SignedString([]byte(config.SALT_SECURITY)) } -func parseToken(s string) (*jwt.Token, error) { +func ParseToken(s string) (*jwt.Token, error) { return jwt.Parse(s, func(t *jwt.Token) (any, error) { if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { - errMsg := fmt.Sprintf("unexpected signing method: %v", t.Header["alg"]) - return nil, errors.New(errMsg) + return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"]) } return []byte(config.SALT_SECURITY), nil @@ -59,7 +58,7 @@ func parseToken(s string) (*jwt.Token, error) { func DestructToken(s string) (authdomain.AuthToken, error) { var data authdomain.AuthToken - token, err := parseToken(s) + token, err := ParseToken(s) if err != nil { return data, err } diff --git a/internal/utilities/utils/redis.go b/internal/utilities/utils/redis.go index bfa3134..3e24f7f 100644 --- a/internal/utilities/utils/redis.go +++ b/internal/utilities/utils/redis.go @@ -2,12 +2,36 @@ package utils import ( "context" + "fmt" + "legalgo-BE-go/config" "time" "github.com/redis/go-redis/v9" ) -func StoreToken(ctx context.Context, rdb *redis.Client, token, username string) error { - // return rdb.Set(ctx context.Context, key string, value interface{}, expiration time.Duration) - return rdb.Set(ctx, "token"+username, token, time.Hour).Err() +func GetTokenRedis(ctx context.Context, rdb *redis.Client, id string) (string, error) { + val, err := rdb.Get(ctx, "token-"+id).Result() + + switch { + case err == redis.Nil: + return "", fmt.Errorf("token does not exist") + case err != nil: + return "", err + case val == "": + return "", fmt.Errorf("token does not exist") + } + + return val, nil +} + +func StoreTokenRedis(ctx context.Context, rdb *redis.Client, token, id string) error { + _, err := rdb.Get(ctx, "token-"+id).Result() + if err != redis.Nil { + // If there's an existing token, delete it (expire the previous session) + if err := rdb.Del(ctx, "token-"+id).Err(); err != nil { + return err + } + } + // return rdb.Set(ctx context.Context, key string, value interface{}, expiration time.Duration) + return rdb.Set(ctx, "token-"+id, token, time.Minute*time.Duration(config.REDIS_TIMEOUT)).Err() }