refactor(backend): isolate workspace aggregation
This commit is contained in:
198
backend/internal/logic/projects/object_crud.go
Normal file
198
backend/internal/logic/projects/object_crud.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package projects
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"senlinai-agent/backend/internal/models"
|
||||
)
|
||||
|
||||
func (s *Service) CreateTask(ownerID uint, projectID uint, input CreateTaskInput) (*models.SenlinAgentTask, error) {
|
||||
if err := ensureProjectOwner(ownerID, projectID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
title := strings.TrimSpace(input.Title)
|
||||
if title == "" {
|
||||
return nil, errors.New("task title is required")
|
||||
}
|
||||
status := strings.TrimSpace(input.Status)
|
||||
if status == "" {
|
||||
status = "open"
|
||||
}
|
||||
tagID, err := s.findOrCreateTagID(projectID, input.Tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
task := &models.SenlinAgentTask{
|
||||
ProjectID: projectID, CreatedBy: ownerID, TagID: tagID, Title: title,
|
||||
Description: strings.TrimSpace(input.Description), Status: status, DueAt: input.DueAt,
|
||||
}
|
||||
return task, models.DBService.Create(task).Error
|
||||
}
|
||||
|
||||
func (s *Service) UpdateTask(ownerID uint, projectID uint, taskID uint, input UpdateTaskInput) (*models.SenlinAgentTask, error) {
|
||||
if err := ensureProjectOwner(ownerID, projectID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var task models.SenlinAgentTask
|
||||
if err := models.DBService.Where("id = ? AND project_id = ?", taskID, projectID).First(&task).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nextProjectID := input.NextProjectID
|
||||
if nextProjectID == 0 {
|
||||
nextProjectID = task.ProjectID
|
||||
}
|
||||
if err := ensureProjectOwner(ownerID, nextProjectID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
title := strings.TrimSpace(input.Title)
|
||||
if title == "" {
|
||||
return nil, errors.New("task title is required")
|
||||
}
|
||||
tagID, err := s.findOrCreateTagID(nextProjectID, input.Tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectIdentity, err := projectIdentity(nextProjectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tagIdentity, err := optionalTagIdentity(tagID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
status := strings.TrimSpace(input.Status)
|
||||
if status == "" {
|
||||
if input.Completed {
|
||||
status = "done"
|
||||
} else {
|
||||
status = "open"
|
||||
}
|
||||
}
|
||||
task.ProjectID = nextProjectID
|
||||
task.ProjectIdentity = projectIdentity
|
||||
task.Title = title
|
||||
task.Description = strings.TrimSpace(input.Description)
|
||||
task.Status = status
|
||||
task.TagID = tagID
|
||||
task.TagIdentity = tagIdentity
|
||||
if err := models.DBService.Save(&task).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &task, nil
|
||||
}
|
||||
|
||||
func (s *Service) CreateFileSource(ownerID uint, projectID uint, input CreateFileSourceInput) (*models.SenlinAgentSource, error) {
|
||||
if err := ensureProjectOwner(ownerID, projectID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
title := strings.TrimSpace(input.Title)
|
||||
if title == "" {
|
||||
return nil, errors.New("source title is required")
|
||||
}
|
||||
filePath := strings.TrimSpace(input.FilePath)
|
||||
if filePath == "" {
|
||||
return nil, errors.New("source file path is required")
|
||||
}
|
||||
source := &models.SenlinAgentSource{ProjectID: projectID, CreatedBy: ownerID, Kind: "file", Title: title, FilePath: filePath}
|
||||
return source, models.DBService.Create(source).Error
|
||||
}
|
||||
|
||||
func (s *Service) CreateCronPlan(ownerID uint, projectID uint, input CreateCronPlanInput) (*models.SenlinAgentCronPlan, error) {
|
||||
if err := ensureProjectOwner(ownerID, projectID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
title := strings.TrimSpace(input.Title)
|
||||
if title == "" {
|
||||
return nil, errors.New("cron plan title is required")
|
||||
}
|
||||
schedule := strings.TrimSpace(input.Schedule)
|
||||
if schedule == "" {
|
||||
return nil, errors.New("cron schedule is required")
|
||||
}
|
||||
plan := &models.SenlinAgentCronPlan{
|
||||
ProjectID: projectID, CreatedBy: ownerID, Title: title, Schedule: schedule,
|
||||
Enabled: input.Enabled, NextRunAt: input.NextRunAt, LastResult: "Not run yet",
|
||||
}
|
||||
return plan, models.DBService.Create(plan).Error
|
||||
}
|
||||
|
||||
func (s *Service) CreateProjectTag(ownerID uint, projectID uint, name string) (*models.SenlinAgentTag, error) {
|
||||
if err := ensureProjectOwner(ownerID, projectID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.CreateTag(projectID, name)
|
||||
}
|
||||
|
||||
func (s *Service) CreateTag(projectID uint, name string) (*models.SenlinAgentTag, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return nil, errors.New("tag name is required")
|
||||
}
|
||||
var existing models.SenlinAgentTag
|
||||
err := models.DBService.Where("project_id = ? AND name = ?", projectID, name).First(&existing).Error
|
||||
if err == nil {
|
||||
return &existing, nil
|
||||
}
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
tag := &models.SenlinAgentTag{ProjectID: projectID, Name: name}
|
||||
return tag, models.DBService.Create(tag).Error
|
||||
}
|
||||
|
||||
func (s *Service) ListProjectTags(ownerID uint, projectID uint) ([]models.SenlinAgentTag, error) {
|
||||
if err := ensureProjectOwner(ownerID, projectID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.ListTags(projectID)
|
||||
}
|
||||
|
||||
func (s *Service) ListTags(projectID uint) ([]models.SenlinAgentTag, error) {
|
||||
var tags []models.SenlinAgentTag
|
||||
err := models.DBService.Where("project_id = ?", projectID).Order("name asc").Find(&tags).Error
|
||||
return tags, err
|
||||
}
|
||||
|
||||
func (s *Service) findOrCreateTagID(projectID uint, name string) (*uint, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return nil, nil
|
||||
}
|
||||
tag, err := s.CreateTag(projectID, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tag.ID, nil
|
||||
}
|
||||
|
||||
func ensureProjectOwner(ownerID uint, projectID uint) error {
|
||||
var count int64
|
||||
if err := models.DBService.Model(&models.SenlinAgentProject{}).Where("id = ? AND owner_id = ?", projectID, ownerID).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return errors.New("project not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func projectIdentity(projectID uint) (string, error) {
|
||||
var project models.SenlinAgentProject
|
||||
if err := models.DBService.Select("identity").First(&project, projectID).Error; err != nil {
|
||||
return "", err
|
||||
}
|
||||
return project.Identity, nil
|
||||
}
|
||||
|
||||
func optionalTagIdentity(tagID *uint) (*string, error) {
|
||||
if tagID == nil {
|
||||
return nil, nil
|
||||
}
|
||||
var tag models.SenlinAgentTag
|
||||
if err := models.DBService.Select("identity").First(&tag, *tagID).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tag.Identity, nil
|
||||
}
|
||||
Reference in New Issue
Block a user