main / internal/app/issue_service.go
2.8 KB · Go Raw
1package app
2
3import (
4 "context"
5 "fmt"
6 "strings"
7
8 "gitgud/internal/domain"
9)
10
11type IssueService struct {
12 issues domain.IssueRepository
13}
14
15func NewIssueService(issues domain.IssueRepository) *IssueService {
16 return &IssueService{issues: issues}
17}
18
19func (s *IssueService) Open(ctx context.Context, repo *domain.Repository, author *domain.User, title, body string) (*domain.Issue, error) {
20 if author == nil {
21 return nil, domain.ErrUnauthorized
22 }
23 title = strings.TrimSpace(title)
24 if title == "" {
25 return nil, fmt.Errorf("title is required: %w", domain.ErrValidation)
26 }
27
28 issue := &domain.Issue{
29 RepoID: repo.ID,
30 AuthorID: author.ID,
31 Title: title,
32 Body: strings.TrimSpace(body),
33 State: domain.IssueOpen,
34 }
35 if err := s.issues.Create(ctx, issue); err != nil {
36 return nil, err
37 }
38 return issue, nil
39}
40
41func (s *IssueService) Comment(ctx context.Context, issue *domain.Issue, author *domain.User, body string) error {
42 if author == nil {
43 return domain.ErrUnauthorized
44 }
45 body = strings.TrimSpace(body)
46 if body == "" {
47 return fmt.Errorf("comment is required: %w", domain.ErrValidation)
48 }
49 return s.issues.AddComment(ctx, &domain.IssueComment{
50 IssueID: issue.ID,
51 AuthorID: author.ID,
52 Body: body,
53 })
54}
55
56func (s *IssueService) Close(ctx context.Context, repo *domain.Repository, issue *domain.Issue, actor *domain.User) error {
57 if !canModifyIssue(repo, issue, actor) {
58 return domain.ErrPermission
59 }
60 return s.issues.SetState(ctx, issue.ID, domain.IssueClosed)
61}
62
63func (s *IssueService) Reopen(ctx context.Context, repo *domain.Repository, issue *domain.Issue, actor *domain.User) error {
64 if !canModifyIssue(repo, issue, actor) {
65 return domain.ErrPermission
66 }
67 return s.issues.SetState(ctx, issue.ID, domain.IssueOpen)
68}
69
70func (s *IssueService) List(ctx context.Context, repoID int64, state domain.IssueState) ([]*domain.Issue, error) {
71 return s.issues.List(ctx, repoID, state)
72}
73
74func (s *IssueService) Get(ctx context.Context, repoID int64, number int) (*domain.Issue, []*domain.IssueComment, error) {
75 issue, err := s.issues.ByNumber(ctx, repoID, number)
76 if err != nil {
77 return nil, nil, err
78 }
79 comments, err := s.issues.Comments(ctx, issue.ID)
80 if err != nil {
81 return nil, nil, err
82 }
83 return issue, comments, nil
84}
85
86func (s *IssueService) Comments(ctx context.Context, issueID int64) ([]*domain.IssueComment, error) {
87 return s.issues.Comments(ctx, issueID)
88}
89
90func (s *IssueService) Counts(ctx context.Context, repoID int64) (open, closed int, err error) {
91 return s.issues.CountByState(ctx, repoID)
92}
93
94func CanModifyIssue(repo *domain.Repository, issue *domain.Issue, actor *domain.User) bool {
95 return canModifyIssue(repo, issue, actor)
96}
97
98func canModifyIssue(repo *domain.Repository, issue *domain.Issue, actor *domain.User) bool {
99 return actor != nil && (actor.ID == issue.AuthorID || actor.ID == repo.OwnerID)
100}