refactor(api): expose project identity DTOs
This commit is contained in:
@@ -105,14 +105,6 @@ type ProjectWorkspace struct {
|
||||
CronPlans []CronPlan `json:"cronPlans"`
|
||||
}
|
||||
|
||||
type CreateProjectInput struct {
|
||||
Name string
|
||||
Identifier string
|
||||
Icon string
|
||||
Background string
|
||||
Description string
|
||||
}
|
||||
|
||||
type CreateTaskInput struct {
|
||||
Title string
|
||||
Description string
|
||||
@@ -147,18 +139,27 @@ func NewService() *Service {
|
||||
}
|
||||
|
||||
func (s *Service) CreateProject(ownerID uint, name string, description string) (*models.SenlinAgentProject, error) {
|
||||
return s.CreateProjectWithInput(ownerID, CreateProjectInput{Name: name, Description: description})
|
||||
return s.CreateProjectWithInput(ownerID, CreateProjectRequest{Name: name, Description: description})
|
||||
}
|
||||
|
||||
func (s *Service) CreateProjectWithInput(ownerID uint, input CreateProjectInput) (*models.SenlinAgentProject, error) {
|
||||
func (s *Service) CreateProjectWithInput(ownerID uint, input CreateProjectRequest) (*models.SenlinAgentProject, error) {
|
||||
name := strings.TrimSpace(input.Name)
|
||||
if name == "" {
|
||||
return nil, errors.New("project name is required")
|
||||
return nil, ErrProjectNameRequired
|
||||
}
|
||||
identifier := strings.TrimSpace(input.Identifier)
|
||||
if identifier == "" {
|
||||
identifier = projectInitials(name)
|
||||
}
|
||||
var count int64
|
||||
if err := models.DBService.Model(&models.SenlinAgentProject{}).
|
||||
Where("owner_id = ? AND identifier = ?", ownerID, identifier).
|
||||
Count(&count).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if count > 0 {
|
||||
return nil, ErrProjectIdentifierConflict
|
||||
}
|
||||
project := &models.SenlinAgentProject{
|
||||
OwnerID: ownerID,
|
||||
Name: name,
|
||||
@@ -170,10 +171,78 @@ func (s *Service) CreateProjectWithInput(ownerID uint, input CreateProjectInput)
|
||||
return project, models.DBService.Create(project).Error
|
||||
}
|
||||
|
||||
func (s *Service) ListProjects(ownerID uint) ([]models.SenlinAgentProject, error) {
|
||||
// ListProjects 只返回当前所有者的公开 DTO,不让 handler 接触或序列化数据库模型。
|
||||
func (s *Service) ListProjects(ownerID uint) ([]ProjectDTO, error) {
|
||||
var projects []models.SenlinAgentProject
|
||||
err := models.DBService.Where("owner_id = ?", ownerID).Order("updated_at desc").Find(&projects).Error
|
||||
return projects, err
|
||||
if err := models.DBService.Where("owner_id = ?", ownerID).Order("updated_at desc").Find(&projects).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]ProjectDTO, 0, len(projects))
|
||||
for _, project := range projects {
|
||||
result = append(result, projectDTO(project))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetProject 使用公开 identity 和所有权边界读取单个项目。
|
||||
func (s *Service) GetProject(ownerID uint, identity string) (ProjectDTO, error) {
|
||||
project, err := FindOwnedProject(ownerID, identity)
|
||||
if err != nil {
|
||||
return ProjectDTO{}, err
|
||||
}
|
||||
return projectDTO(*project), nil
|
||||
}
|
||||
|
||||
var (
|
||||
ErrProjectNameRequired = errors.New("project name is required")
|
||||
ErrProjectIdentifierRequired = errors.New("project identifier is required")
|
||||
ErrProjectIdentifierConflict = errors.New("project identifier already exists")
|
||||
)
|
||||
|
||||
// UpdateProject 仅更新项目设置白名单字段,查询和冲突检查均限定在当前所有者内。
|
||||
func (s *Service) UpdateProject(ownerID uint, identity string, input UpdateProjectRequest) error {
|
||||
project, err := FindOwnedProject(ownerID, identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updates := make(map[string]any, 5)
|
||||
if input.Name != nil {
|
||||
name := strings.TrimSpace(*input.Name)
|
||||
if name == "" {
|
||||
return ErrProjectNameRequired
|
||||
}
|
||||
updates["name"] = name
|
||||
}
|
||||
if input.Identifier != nil {
|
||||
identifier := strings.TrimSpace(*input.Identifier)
|
||||
if identifier == "" {
|
||||
return ErrProjectIdentifierRequired
|
||||
}
|
||||
var count int64
|
||||
if err := models.DBService.Model(&models.SenlinAgentProject{}).
|
||||
Where("owner_id = ? AND identifier = ? AND id <> ?", ownerID, identifier, project.ID).
|
||||
Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return ErrProjectIdentifierConflict
|
||||
}
|
||||
updates["identifier"] = identifier
|
||||
}
|
||||
if input.Icon != nil {
|
||||
updates["icon"] = strings.TrimSpace(*input.Icon)
|
||||
}
|
||||
if input.Background != nil {
|
||||
updates["background"] = strings.TrimSpace(*input.Background)
|
||||
}
|
||||
if input.Description != nil {
|
||||
updates["description"] = strings.TrimSpace(*input.Description)
|
||||
}
|
||||
if len(updates) == 0 {
|
||||
return nil
|
||||
}
|
||||
return models.DBService.Model(project).Updates(updates).Error
|
||||
}
|
||||
|
||||
func (s *Service) CreateTask(ownerID uint, projectID uint, input CreateTaskInput) (*models.SenlinAgentTask, error) {
|
||||
|
||||
Reference in New Issue
Block a user