From 18e9a2aa4a42c8683989dc0eaa4ed8026101ee54 Mon Sep 17 00:00:00 2001 From: kyy Date: Wed, 22 Apr 2026 11:41:01 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B0=9C=EB=B0=9C=EC=9E=90=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=20=EC=8B=A0=EC=B2=AD=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=EB=B0=8F=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=96=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/bootstrap/bootstrap.go | 1 + backend/internal/domain/developer_request.go | 25 +++++++ backend/internal/service/developer_service.go | 73 +++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 backend/internal/domain/developer_request.go create mode 100644 backend/internal/service/developer_service.go diff --git a/backend/internal/bootstrap/bootstrap.go b/backend/internal/bootstrap/bootstrap.go index 647bea2c..c1376494 100644 --- a/backend/internal/bootstrap/bootstrap.go +++ b/backend/internal/bootstrap/bootstrap.go @@ -42,6 +42,7 @@ func migrateSchemas(db *gorm.DB) error { &domain.ClientConsent{}, &domain.KetoOutbox{}, &domain.SharedLink{}, + &domain.DeveloperRequest{}, // &domain.RelyingParty{}, // Removed: SSOT is Hydra + Keto ) } diff --git a/backend/internal/domain/developer_request.go b/backend/internal/domain/developer_request.go new file mode 100644 index 00000000..73c8b5c5 --- /dev/null +++ b/backend/internal/domain/developer_request.go @@ -0,0 +1,25 @@ +package domain + +import ( + "time" +) + +const ( + DeveloperRequestStatusPending = "pending" + DeveloperRequestStatusApproved = "approved" + DeveloperRequestStatusRejected = "rejected" +) + +// DeveloperRequest represents a user's application to become a developer. +type DeveloperRequest struct { + ID uint `gorm:"primaryKey" json:"id"` + UserID string `gorm:"index;not null" json:"userId"` // Kratos User ID + TenantID string `gorm:"index;not null" json:"tenantId"` + Name string `gorm:"not null" json:"name"` + Organization string `json:"organization"` + Reason string `json:"reason"` + Status string `gorm:"default:'pending';not null" json:"status"` // pending, approved, rejected + AdminNotes string `json:"adminNotes"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} diff --git a/backend/internal/service/developer_service.go b/backend/internal/service/developer_service.go new file mode 100644 index 00000000..8097b023 --- /dev/null +++ b/backend/internal/service/developer_service.go @@ -0,0 +1,73 @@ +package service + +import ( + "baron-sso-backend/internal/domain" + "context" + "errors" + + "gorm.io/gorm" +) + +type DeveloperService struct { + db *gorm.DB +} + +func NewDeveloperService(db *gorm.DB) *DeveloperService { + return &DeveloperService{db: db} +} + +func (s *DeveloperService) RequestAccess(ctx context.Context, req domain.DeveloperRequest) error { + // Check if there is already a pending request + var existing domain.DeveloperRequest + err := s.db.WithContext(ctx).Where("user_id = ? AND tenant_id = ? AND status = ?", req.UserID, req.TenantID, domain.DeveloperRequestStatusPending).First(&existing).Error + if err == nil { + return errors.New("already has a pending request") + } + + return s.db.WithContext(ctx).Create(&req).Error +} + +func (s *DeveloperService) GetRequestStatus(ctx context.Context, userID, tenantID string) (*domain.DeveloperRequest, error) { + var req domain.DeveloperRequest + err := s.db.WithContext(ctx).Where("user_id = ? AND tenant_id = ?", userID, tenantID).Order("created_at DESC").First(&req).Error + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, nil + } + return nil, err + } + return &req, nil +} + +func (s *DeveloperService) GetRequestByID(ctx context.Context, id uint) (*domain.DeveloperRequest, error) { + var req domain.DeveloperRequest + err := s.db.WithContext(ctx).First(&req, id).Error + if err != nil { + return nil, err + } + return &req, nil +} + +func (s *DeveloperService) ListRequests(ctx context.Context, status string) ([]domain.DeveloperRequest, error) { + var requests []domain.DeveloperRequest + query := s.db.WithContext(ctx) + if status != "" { + query = query.Where("status = ?", status) + } + err := query.Order("created_at DESC").Find(&requests).Error + return requests, err +} + +func (s *DeveloperService) ApproveRequest(ctx context.Context, id uint, adminNotes string) error { + return s.db.WithContext(ctx).Model(&domain.DeveloperRequest{}).Where("id = ?", id).Updates(map[string]interface{}{ + "status": domain.DeveloperRequestStatusApproved, + "admin_notes": adminNotes, + }).Error +} + +func (s *DeveloperService) RejectRequest(ctx context.Context, id uint, adminNotes string) error { + return s.db.WithContext(ctx).Model(&domain.DeveloperRequest{}).Where("id = ?", id).Updates(map[string]interface{}{ + "status": domain.DeveloperRequestStatusRejected, + "admin_notes": adminNotes, + }).Error +}