diff --git a/database/category_model.go b/database/category_model.go new file mode 100644 index 0000000..21596c6 --- /dev/null +++ b/database/category_model.go @@ -0,0 +1,11 @@ +package database + +import "time" + +type Category struct { + ID string `gorm:"primaryKey;not null" json:"id"` + Code string `gorm:"not null" 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"` +} diff --git a/database/new_db.go b/database/new_db.go index 522b423..a539202 100644 --- a/database/new_db.go +++ b/database/new_db.go @@ -43,5 +43,7 @@ func (db *DB) Migrate() error { &SubscribePlan{}, &Subscribe{}, &User{}, + &Tag{}, + &Category{}, ) } diff --git a/database/tags_module.go b/database/tag_module.go similarity index 94% rename from database/tags_module.go rename to database/tag_module.go index cc1d07b..61498a9 100644 --- a/database/tags_module.go +++ b/database/tag_module.go @@ -4,7 +4,7 @@ import ( "time" ) -type Tags struct { +type Tag struct { ID string `gorm:"primaryKey;not null" json:"id"` Code string `gorm:"not null" json:"code"` Name string `gorm:"not null" json:"name"` diff --git a/internal/accessor/module.go b/internal/accessor/module.go index 6eee042..8c1638a 100644 --- a/internal/accessor/module.go +++ b/internal/accessor/module.go @@ -5,6 +5,7 @@ import ( staffrepository "legalgo-BE-go/internal/accessor/staff" subscriberepository "legalgo-BE-go/internal/accessor/subscribe" subscribeplanrepository "legalgo-BE-go/internal/accessor/subscribeplan" + tagrepository "legalgo-BE-go/internal/accessor/tag" userrepository "legalgo-BE-go/internal/accessor/user_repository" "go.uber.org/fx" @@ -16,4 +17,5 @@ var Module = fx.Module("repository", fx.Provide( redisaccessor.New, subscribeplanrepository.New, subscriberepository.New, + tagrepository.New, )) diff --git a/internal/accessor/tag/create.go b/internal/accessor/tag/create.go new file mode 100644 index 0000000..6097ba6 --- /dev/null +++ b/internal/accessor/tag/create.go @@ -0,0 +1,21 @@ +package tagrepository + +import ( + tagdomain "legalgo-BE-go/internal/domain/tag" + + "github.com/google/uuid" +) + +func (acc *accessor) Create(spec tagdomain.TagReq) error { + data := &tagdomain.Tag{ + ID: uuid.NewString(), + Code: spec.Code, + Name: spec.Name, + } + + if err := acc.DB.Create(&data).Error; err != nil { + return err + } + + return nil +} diff --git a/internal/accessor/tag/get_all.go b/internal/accessor/tag/get_all.go new file mode 100644 index 0000000..5306f79 --- /dev/null +++ b/internal/accessor/tag/get_all.go @@ -0,0 +1,15 @@ +package tagrepository + +import ( + tagdomain "legalgo-BE-go/internal/domain/tag" +) + +func (acc *accessor) GetAll() ([]tagdomain.Tag, error) { + var tags []tagdomain.Tag + + if err := acc.DB.Find(&tags).Error; err != nil { + return nil, err + } + + return tags, nil +} diff --git a/internal/accessor/tag/impl.go b/internal/accessor/tag/impl.go new file mode 100644 index 0000000..49987cb --- /dev/null +++ b/internal/accessor/tag/impl.go @@ -0,0 +1,21 @@ +package tagrepository + +import ( + "legalgo-BE-go/database" + tagdomain "legalgo-BE-go/internal/domain/tag" +) + +type accessor struct { + DB *database.DB +} + +type TagAccessor interface { + Create(tagdomain.TagReq) error + GetAll() ([]tagdomain.Tag, error) +} + +func New( + db *database.DB, +) TagAccessor { + return &accessor{db} +} diff --git a/internal/api/http/router.go b/internal/api/http/router.go index b98dfc1..6b8aa47 100644 --- a/internal/api/http/router.go +++ b/internal/api/http/router.go @@ -3,6 +3,7 @@ package internalhttp import ( authhttp "legalgo-BE-go/internal/api/http/auth" subscribeplanhttp "legalgo-BE-go/internal/api/http/subscribe_plan" + taghttp "legalgo-BE-go/internal/api/http/tag" "github.com/go-chi/chi/v5" "github.com/go-chi/cors" @@ -19,6 +20,7 @@ var Module = fx.Module("router", ), authhttp.Module, subscribeplanhttp.Module, + taghttp.Module, ) func initRouter() chi.Router { diff --git a/internal/api/http/tag/create.go b/internal/api/http/tag/create.go new file mode 100644 index 0000000..c059f2e --- /dev/null +++ b/internal/api/http/tag/create.go @@ -0,0 +1,67 @@ +package taghttp + +import ( + "net/http" + + tagdomain "legalgo-BE-go/internal/domain/tag" + tagsvc "legalgo-BE-go/internal/services/tag" + "legalgo-BE-go/internal/utilities/response" + "legalgo-BE-go/internal/utilities/utils" + + "github.com/go-chi/chi/v5" + "github.com/go-playground/validator/v10" +) + +func Create( + router chi.Router, + validate *validator.Validate, + tagSvc tagsvc.TagIntf, +) { + router.Post("/tag/create", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + 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 := 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 + } + + response.RespondJsonSuccess(ctx, w, struct { + Message string + }{ + Message: "tag created successfully.", + }) + }) +} diff --git a/internal/api/http/tag/get.go b/internal/api/http/tag/get.go new file mode 100644 index 0000000..7a81762 --- /dev/null +++ b/internal/api/http/tag/get.go @@ -0,0 +1,32 @@ +package taghttp + +import ( + tagsvc "legalgo-BE-go/internal/services/tag" + "legalgo-BE-go/internal/utilities/response" + "net/http" + + "github.com/go-chi/chi/v5" +) + +func Get( + router chi.Router, + tagSvc tagsvc.TagIntf, +) { + router.Get("/tag", func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + subsPlan, err := tagSvc.GetAll() + if err != nil { + response.ResponseWithErrorCode( + ctx, + w, + err, + response.ErrBadRequest.Code, + response.ErrBadRequest.HttpCode, + err.Error(), + ) + return + } + + response.RespondJsonSuccess(ctx, w, subsPlan) + }) +} diff --git a/internal/api/http/tag/module.go b/internal/api/http/tag/module.go new file mode 100644 index 0000000..4da5f50 --- /dev/null +++ b/internal/api/http/tag/module.go @@ -0,0 +1,8 @@ +package taghttp + +import "go.uber.org/fx" + +var Module = fx.Module("tag", fx.Invoke( + Create, + Get, +)) diff --git a/internal/domain/auth/register.go b/internal/domain/auth/register.go index 80f57e3..6306bfb 100644 --- a/internal/domain/auth/register.go +++ b/internal/domain/auth/register.go @@ -3,7 +3,7 @@ package authdomain type RegisterUserReq struct { Email string `json:"email" validate:"required"` Password string `json:"password" validate:"required"` - Phone string `json:"phone"` + Phone string `json:"phone" validate:"required"` SubscribePlanID string `json:"subscribe_plan_id"` } diff --git a/internal/domain/tag/spec.go b/internal/domain/tag/spec.go new file mode 100644 index 0000000..e766e1d --- /dev/null +++ b/internal/domain/tag/spec.go @@ -0,0 +1,12 @@ +package tagdomain + +type TagReq struct { + Code string `json:"code" validate:"required"` + Name string `json:"name" validate:"required"` +} + +type Tag struct { + ID string `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} diff --git a/internal/services/module.go b/internal/services/module.go index db66a28..00f84b1 100644 --- a/internal/services/module.go +++ b/internal/services/module.go @@ -4,6 +4,7 @@ import ( serviceauth "legalgo-BE-go/internal/services/auth" subscribesvc "legalgo-BE-go/internal/services/subscribe" subscribeplansvc "legalgo-BE-go/internal/services/subscribe_plan" + tagsvc "legalgo-BE-go/internal/services/tag" "go.uber.org/fx" ) @@ -13,5 +14,6 @@ var Module = fx.Module("services", serviceauth.New, subscribeplansvc.New, subscribesvc.New, + tagsvc.New, ), ) diff --git a/internal/services/subscribe_plan/get_all_plan.go b/internal/services/subscribe_plan/get_all_plan.go index 8d2cfe8..287a5af 100644 --- a/internal/services/subscribe_plan/get_all_plan.go +++ b/internal/services/subscribe_plan/get_all_plan.go @@ -5,10 +5,5 @@ import ( ) func (s *SubsPlanSvc) GetAllPlan() ([]subscribeplandomain.SubscribePlan, error) { - subsPlan, err := s.subsAccs.GetAll() - if err != nil { - return nil, err - } - - return subsPlan, nil + return s.subsAccs.GetAll() } diff --git a/internal/services/tag/create.go b/internal/services/tag/create.go new file mode 100644 index 0000000..2055cf9 --- /dev/null +++ b/internal/services/tag/create.go @@ -0,0 +1,7 @@ +package tagsvc + +import tagdomain "legalgo-BE-go/internal/domain/tag" + +func (i *impl) Create(spec tagdomain.TagReq) error { + return i.TagRepo.Create(spec) +} diff --git a/internal/services/tag/get_all.go b/internal/services/tag/get_all.go new file mode 100644 index 0000000..1709e39 --- /dev/null +++ b/internal/services/tag/get_all.go @@ -0,0 +1,7 @@ +package tagsvc + +import tagdomain "legalgo-BE-go/internal/domain/tag" + +func (i *impl) GetAll() ([]tagdomain.Tag, error) { + return i.TagRepo.GetAll() +} diff --git a/internal/services/tag/impl.go b/internal/services/tag/impl.go new file mode 100644 index 0000000..adbd901 --- /dev/null +++ b/internal/services/tag/impl.go @@ -0,0 +1,23 @@ +package tagsvc + +import ( + tagrepository "legalgo-BE-go/internal/accessor/tag" + tagdomain "legalgo-BE-go/internal/domain/tag" +) + +type impl struct { + TagRepo tagrepository.TagAccessor +} + +type TagIntf interface { + Create(tagdomain.TagReq) error + GetAll() ([]tagdomain.Tag, error) +} + +func New( + tagRepo tagrepository.TagAccessor, +) TagIntf { + return &impl{ + TagRepo: tagRepo, + } +} diff --git a/openapi.yml b/openapi.yml index 2fbb2c6..b0ce6db 100644 --- a/openapi.yml +++ b/openapi.yml @@ -429,3 +429,104 @@ paths: type: string message: type: string + + /tag: + get: + summary: Get all tags + tags: + - Tags + responses: + "200": + description: Successfully retrieved all tags + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + type: object + properties: + id: + type: string + code: + type: string + name: + type: string + "400": + description: Bad request + content: + application/json: + schema: + type: object + properties: + error: + type: object + properties: + code: + type: string + message: + type: string + + /tag/create: + post: + summary: Create a new tag + tags: + - Tags + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + code: + type: string + required: + - code + - name + responses: + "201": + description: Tag created + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + message: + type: string + example: "tag created successfully." + "400": + description: Bad request + content: + application/json: + schema: + type: object + properties: + error: + type: object + properties: + code: + type: string + message: + type: string + "409": + description: Conflict (tag code already exists) + content: + application/json: + schema: + type: object + properties: + error: + type: object + properties: + code: + type: string + message: + type: string