Skip to content

Commit 9ffe61c

Browse files
feat: owner delete endpoint
1 parent e748c68 commit 9ffe61c

File tree

6 files changed

+159
-5
lines changed

6 files changed

+159
-5
lines changed

backend/cms-sys/internal/handler/owner_handler.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type OwnerHandle interface {
1313
Update(c *fiber.Ctx) error
1414
GetAll(c *fiber.Ctx) error
1515
GetOwnerByID(c *fiber.Ctx) error
16+
Delete(c *fiber.Ctx) error
1617
}
1718
type OwnerHandler struct {
1819
service service.OwnerService
@@ -69,6 +70,7 @@ func (o OwnerHandler) GetAll(c *fiber.Ctx) error {
6970
}
7071

7172
return utils.SuccessResponse(c, "Owners fetched", owners)
73+
}
7274

7375
func (o OwnerHandler) GetOwnerByID(c *fiber.Ctx) error {
7476
id := c.Params("id")
@@ -80,3 +82,23 @@ func (o OwnerHandler) GetOwnerByID(c *fiber.Ctx) error {
8082

8183
return utils.SuccessResponse(c, "Fetched owner", ownerResponse)
8284
}
85+
86+
func (o OwnerHandler) Delete(c *fiber.Ctx) error {
87+
var req types.OwnerDeleteRequest
88+
89+
if err := c.BodyParser(&req); err != nil {
90+
return utils.BadRequestResponse(c, "Invalid request", err.Error())
91+
}
92+
93+
if err := o.validator.Struct(req); err != nil {
94+
return utils.BadRequestResponse(c, "Validation failed", err.Error())
95+
}
96+
97+
err := o.service.BulkDeleteOwners(req.IDs, req.ForceDelete)
98+
if err != nil {
99+
return utils.InternalServerErrorResponse(c, "Failed to delete owners", err.Error())
100+
}
101+
102+
return utils.SuccessResponse(c, "Owner(s) deleted", nil)
103+
}
104+

backend/cms-sys/internal/repository/owner_repo.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ type OwnerRepository interface {
1212
GetById(id string) (*types.CMSUser, error)
1313
UpdateOwner(owner *types.CMSUser) error
1414
GetOwnerByID(id string) (*types.CMSUser, error)
15+
DeleteOwnerByID(id string) error
16+
OwnerHasAssociations(id string) bool
17+
ForceDeleteOwner(id string) error
1518
}
1619

1720
type OwnerRepositoryImpl struct {
@@ -52,6 +55,7 @@ func (r *OwnerRepositoryImpl) GetAllOwners() ([]types.CMSUser, error) {
5255
return nil, err
5356
}
5457
return owners, nil
58+
}
5559

5660
func (r *OwnerRepositoryImpl) GetOwnerByID(id string) (*types.CMSUser, error) {
5761
var owner types.CMSUser
@@ -60,3 +64,82 @@ func (r *OwnerRepositoryImpl) GetOwnerByID(id string) (*types.CMSUser, error) {
6064
Find(&owner).Error
6165
return &owner, err
6266
}
67+
68+
func (r *OwnerRepositoryImpl) DeleteOwnerByID(id string) error {
69+
if err := r.db.Where("cms_user_id = ?", id).Delete(&types.CMSUser{}).Error; err != nil {
70+
r.logger.WithError(err).Error("Failed to delete owner by ID")
71+
return err
72+
}
73+
return nil
74+
}
75+
76+
func (r *OwnerRepositoryImpl) OwnerHasAssociations(id string) bool {
77+
var count int64
78+
79+
rawSQL := `
80+
SELECT 1 FROM cms_page WHERE owner_id = ? LIMIT 1
81+
UNION ALL
82+
SELECT 1 FROM cms_page_request WHERE owner_id = ? LIMIT 1
83+
UNION ALL
84+
SELECT 1 FROM cms_cus_purchase WHERE cms_cus_id = ? LIMIT 1
85+
UNION ALL
86+
SELECT 1 FROM user_page_request WHERE user_id = ? LIMIT 1
87+
LIMIT 1
88+
`
89+
if err := r.db.Raw(rawSQL, id, id, id, id).Scan(&count).Error; err != nil {
90+
r.logger.WithError(err).Error("Failed to check owner associations")
91+
return true
92+
}
93+
return count > 0
94+
}
95+
96+
func (r *OwnerRepositoryImpl) ForceDeleteOwner(id string) error {
97+
return r.db.Transaction(func(tx *gorm.DB) error {
98+
// Delete Pages owned by user
99+
if err := tx.Where("owner_id = ?", id).Delete(&types.Page{}).Error; err != nil {
100+
r.logger.WithError(err).Error("Failed to delete owned pages")
101+
return err
102+
}
103+
104+
// Set Null staff publication
105+
if err := tx.Model(&types.Page{}).Where("published_by_staff_id = ?", id).
106+
Update("published_by_staff_id", nil).Error; err != nil {
107+
r.logger.WithError(err).Error("Failed to nullify published_by_staff_id")
108+
return err
109+
}
110+
111+
// Delete Page Requests
112+
if err := tx.Where("owner_id = ?", id).Delete(&types.PageRequest{}).Error; err != nil {
113+
r.logger.WithError(err).Error("Failed to delete page requests")
114+
return err
115+
}
116+
117+
// Set Null admin from page requests
118+
if err := tx.Model(&types.PageRequest{}).Where("admin_id = ?", id).
119+
Update("admin_id", nil).Error; err != nil {
120+
r.logger.WithError(err).Error("Failed to nullify admin_id")
121+
return err
122+
}
123+
124+
// Delete purchases
125+
if err := tx.Where("cms_cus_id = ?", id).Delete(&types.CMSCusPurchase{}).Error; err != nil {
126+
r.logger.WithError(err).Error("Failed to delete purchases")
127+
return err
128+
}
129+
130+
// Delete user_page_request
131+
if err := tx.Where("user_id = ?", id).Delete(&types.UserPageRequest{}).Error; err != nil {
132+
r.logger.WithError(err).Error("Failed to delete user page requests")
133+
return err
134+
}
135+
136+
// Delete the user
137+
if err := tx.Where("cms_user_id = ?", id).Delete(&types.CMSUser{}).Error; err != nil {
138+
r.logger.WithError(err).Error("Failed to delete CMS user")
139+
return err
140+
}
141+
142+
return nil
143+
})
144+
}
145+

backend/cms-sys/internal/routes/owner_route.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import (
77

88
func SetupOwnerRoutes(app *fiber.App, handler handler.OwnerHandle) {
99
ownerRoute := app.Group("/owners")
10-
ownerRoute.Post("/create", handler.Create)
11-
ownerRoute.Put("/update/:id", handler.Update)
12-
ownerRoute.Get("/getAllOwners", handler.GetAll)
10+
ownerRoute.Post("/", handler.Create)
11+
ownerRoute.Put("/:id", handler.Update)
12+
ownerRoute.Get("/", handler.GetAll)
1313
ownerRoute.Get("/:id", handler.GetOwnerByID)
14+
ownerRoute.Delete("/", handler.Delete)
1415
}

backend/cms-sys/internal/service/owner_service.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ import (
99
"github.com/multi-tenants-cms-golang/cms-sys/internal/types"
1010
"github.com/multi-tenants-cms-golang/cms-sys/pkg/utils"
1111
"github.com/sirupsen/logrus"
12+
"gorm.io/gorm"
1213
)
1314

1415
type OwnerService interface {
1516
Create(req types.OwnerCreateRequest) (*types.OwnerResponse, error)
1617
Update(id string, req types.OwnerUpdateRequest) (*types.OwnerResponse, error)
1718
GetAllOwners() ([]types.CMSUser, error)
1819
GetOwnerByID(id string) (*types.OwnerResponse, error)
20+
BulkDeleteOwners(ids []string, force bool) error
1921
}
2022

2123
type OwnerServiceImpl struct {
@@ -112,12 +114,47 @@ func (os *OwnerServiceImpl) GetOwnerByID(id string) (*types.OwnerResponse, error
112114
return nil, errors.New("failed to fetch owner")
113115
}
114116

117+
var nameSpace string
118+
if owner.CMSNameSpace != nil {
119+
nameSpace = *owner.CMSNameSpace
120+
}
121+
115122
return &types.OwnerResponse{
116123
ID: owner.CMSUserID,
117124
Name: owner.CMSUserName,
118125
Email: owner.CMSUserEmail,
119126
Role: owner.CMSUserRole,
120-
NameSpace: *owner.CMSNameSpace,
127+
NameSpace: nameSpace,
121128
Verified: owner.Verified,
122129
}, nil
123130
}
131+
132+
func (os *OwnerServiceImpl) BulkDeleteOwners(ids []string, force bool) error {
133+
for _, id := range ids {
134+
owner, err := os.repo.GetById(id)
135+
if err != nil {
136+
if errors.Is(err, gorm.ErrRecordNotFound) {
137+
return errors.New("owner not found: " + id)
138+
}
139+
return err
140+
}
141+
142+
if !force {
143+
hasAssociations := os.repo.OwnerHasAssociations(id)
144+
if hasAssociations {
145+
return errors.New("owner " + owner.CMSUserName + " has associated records")
146+
}
147+
}
148+
149+
if force {
150+
if err := os.repo.ForceDeleteOwner(id); err != nil {
151+
return err
152+
}
153+
} else {
154+
if err := os.repo.DeleteOwnerByID(id); err != nil {
155+
return err
156+
}
157+
}
158+
}
159+
return nil
160+
}

backend/cms-sys/internal/types/request.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,8 @@ type CreatePageRequest struct {
4848
PageUrl *string `json:"pageUrl"`
4949
Logo *string `json:"logo"`
5050
}
51+
52+
type OwnerDeleteRequest struct {
53+
IDs []string `json:"ids" validate:"required"`
54+
ForceDelete bool `json:"forceDelete"`
55+
}

infra/schema/cms/cms.sql

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,9 @@ ORDER BY p.purchase_date DESC;
166166
SELECT 'd69e2e9e-65ea-47e7-9fe7-7f5b661f069b'::uuid = 'd69e2e9e-65ea-47e7-9fe7-7f5b661f069b'::uuid;
167167

168168
-- Create Page Table
169-
CREATE TABLE Page (
169+
CREATE TABLE cms_page (
170170
page_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
171+
page_request_id UUID NOT NULL,
171172
title VARCHAR(255) NOT NULL,
172173
content TEXT,
173174
image_url VARCHAR(255),
@@ -182,6 +183,9 @@ CREATE TABLE Page (
182183
CONSTRAINT fk_page_staff
183184
FOREIGN KEY (published_by_staff_id)
184185
REFERENCES cms_user(cms_user_id) ON DELETE SET NULL
186+
CONSTRAINT fk_page_request
187+
FOREIGN KEY (page_request_id)
188+
REFERENCES cms_page_request(request_id) ON DELETE CASCADE
185189
);
186190

187191
-- Create PageRequest Table
@@ -191,6 +195,8 @@ CREATE TABLE PageRequest (
191195
request_type VARCHAR(100) NOT NULL,
192196
title VARCHAR(100) NOT NULL,
193197
description TEXT,
198+
page_url VARCHAR(100),
199+
logo_url TEXT,
194200
status VARCHAR(50) DEFAULT 'pending',
195201
admin_id UUID,
196202
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

0 commit comments

Comments
 (0)