/
service_work_item.go
146 lines (122 loc) · 4.54 KB
/
service_work_item.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package services
import (
"context"
"errors"
"strconv"
"github.com/danicc097/openapi-go-gin-postgres-sqlc/internal"
"github.com/danicc097/openapi-go-gin-postgres-sqlc/internal/models"
"github.com/danicc097/openapi-go-gin-postgres-sqlc/internal/repos"
"github.com/danicc097/openapi-go-gin-postgres-sqlc/internal/repos/postgresql/gen/db"
"go.uber.org/zap"
)
/**
*
* TODO: generic logic here, eg
AssignTags
RemoveTags
AssignUsers
RemoveAssignedUsers
it will accept projectName (tags) and teamID (members) if necessary, e.g. to ensure asigntag called with
tag belonging to project and a member that belongs to the team
(notice how seeming redundancy between repo/service starts to lose strength)
*/
type WorkItem struct {
logger *zap.SugaredLogger
projectRepo repos.Project
wiTagRepo repos.WorkItemTag
wiRepo repos.WorkItem
userRepo repos.User
}
// NewWorkItem returns a new WorkItem service with common logic for all project workitems.
func NewWorkItem(logger *zap.SugaredLogger, wiTagRepo repos.WorkItemTag, wiRepo repos.WorkItem, userRepo repos.User, projectRepo repos.Project) *WorkItem {
return &WorkItem{
logger: logger,
projectRepo: projectRepo,
wiTagRepo: wiTagRepo,
wiRepo: wiRepo,
userRepo: userRepo,
}
}
func (w *WorkItem) AssignUsers(ctx context.Context, d db.DBTX, workItem *db.WorkItem, members []Member) error {
for idx, member := range members {
user, err := w.userRepo.ByID(ctx, d, member.UserID, db.WithUserJoin(db.UserJoins{TeamsMember: true}))
if err != nil {
return internal.WrapErrorWithLocf(err, models.ErrorCodeNotFound, []string{strconv.Itoa(idx)}, "user with id %s not found", member.UserID)
}
var userInTeam bool
for _, team := range *user.MemberTeamsJoin {
if team.TeamID == workItem.TeamID {
userInTeam = true
}
}
if !userInTeam {
return internal.WrapErrorWithLocf(nil, models.ErrorCodeUnauthorized, []string{strconv.Itoa(idx)}, "user %q does not belong to team %q", user.Email, workItem.TeamID)
}
err = w.wiRepo.AssignUser(ctx, d, &db.WorkItemAssignedUserCreateParams{
AssignedUser: member.UserID,
WorkItemID: workItem.WorkItemID,
Role: member.Role,
})
var ierr *internal.Error
if err != nil {
if errors.As(err, &ierr) && ierr.Code() == models.ErrorCodeAlreadyExists {
continue
}
return internal.WrapErrorWithLocf(err, "", []string{strconv.Itoa(idx)}, "could not assign member %s", member.UserID)
}
}
return nil
}
func (w *WorkItem) RemoveAssignedUsers(ctx context.Context, d db.DBTX, workItem *db.WorkItem, members []db.UserID) error {
for idx, member := range members {
lookup := &db.WorkItemAssignedUser{
AssignedUser: member,
WorkItemID: workItem.WorkItemID,
}
err := lookup.Delete(ctx, d)
if err != nil {
return internal.WrapErrorWithLocf(err, "", []string{strconv.Itoa(idx)}, "could not remove member %s", member)
}
}
return nil
}
func (w *WorkItem) AssignTags(ctx context.Context, d db.DBTX, projectName models.Project, workItem *db.WorkItem, tagIDs []db.WorkItemTagID) error {
project, err := w.projectRepo.ByName(ctx, d, projectName, db.WithProjectJoin(db.ProjectJoins{Teams: true}))
if err != nil {
return internal.WrapErrorWithLocf(err, models.ErrorCodeNotFound, []string{}, "project %s not found", projectName)
}
for idx, tagID := range tagIDs {
tag, err := w.wiTagRepo.ByID(ctx, d, tagID)
if err != nil {
return internal.WrapErrorWithLocf(err, models.ErrorCodeNotFound, []string{strconv.Itoa(idx)}, "tag with id %d not found", tagID)
}
if project.ProjectID != tag.ProjectID {
return internal.WrapErrorWithLocf(nil, models.ErrorCodeUnauthorized, []string{strconv.Itoa(idx)}, "tag %q does not belong to project %q", tag.Name, tag.ProjectJoin.Name)
}
err = w.wiRepo.AssignTag(ctx, d, &db.WorkItemWorkItemTagCreateParams{
WorkItemTagID: tagID,
WorkItemID: workItem.WorkItemID,
})
var ierr *internal.Error
if err != nil {
if errors.As(err, &ierr) && ierr.Code() == models.ErrorCodeAlreadyExists {
continue
}
return internal.WrapErrorWithLocf(err, "", []string{strconv.Itoa(idx)}, "could not assign tag %s", tag.Name)
}
}
return nil
}
func (w *WorkItem) RemoveTags(ctx context.Context, d db.DBTX, workItem *db.WorkItem, tagIDs []db.WorkItemTagID) error {
for idx, tagID := range tagIDs {
lookup := &db.WorkItemWorkItemTag{
WorkItemTagID: tagID,
WorkItemID: workItem.WorkItemID,
}
err := lookup.Delete(ctx, d)
if err != nil {
return internal.WrapErrorWithLocf(err, "", []string{strconv.Itoa(idx)}, "could not remove tag %d", tagID)
}
}
return nil
}