Skip to content

Commit e0d082f

Browse files
committed
refactor stopwatch codes
1 parent 0f8a611 commit e0d082f

File tree

2 files changed

+114
-82
lines changed

2 files changed

+114
-82
lines changed

models/issue_stopwatch.go

Lines changed: 106 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,26 @@ import (
1313
"code.gitea.io/gitea/modules/timeutil"
1414
)
1515

16+
// ErrIssueStopwatchNotExist represents an error that stopwatch is not exist
17+
type ErrIssueStopwatchNotExist struct {
18+
UserID int64
19+
IssueID int64
20+
}
21+
22+
func (err ErrIssueStopwatchNotExist) Error() string {
23+
return fmt.Sprintf("issue stopwatch is not exist[uid: %d, issue_id: %d", err.UserID, err.IssueID)
24+
}
25+
26+
// ErrIssueStopwatchAlreadyExist represents an error that stopwatch is already exist
27+
type ErrIssueStopwatchAlreadyExist struct {
28+
UserID int64
29+
IssueID int64
30+
}
31+
32+
func (err ErrIssueStopwatchAlreadyExist) Error() string {
33+
return fmt.Sprintf("issue stopwatch is already exist[uid: %d, issue_id: %d", err.UserID, err.IssueID)
34+
}
35+
1636
// Stopwatch represents a stopwatch for time tracking.
1737
type Stopwatch struct {
1838
ID int64 `xorm:"pk autoincr"`
@@ -35,9 +55,9 @@ func (s Stopwatch) Duration() string {
3555
return SecToTime(s.Seconds())
3656
}
3757

38-
func getStopwatch(e db.Engine, userID, issueID int64) (sw *Stopwatch, exists bool, err error) {
58+
func getStopwatch(ctx context.Context, userID, issueID int64) (sw *Stopwatch, exists bool, err error) {
3959
sw = new(Stopwatch)
40-
exists, err = e.
60+
exists, err = db.GetEngine(ctx).
4161
Where("user_id = ?", userID).
4262
And("issue_id = ?", issueID).
4363
Get(sw)
@@ -66,7 +86,7 @@ func CountUserStopwatches(userID int64) (int64, error) {
6686

6787
// StopwatchExists returns true if the stopwatch exists
6888
func StopwatchExists(userID, issueID int64) bool {
69-
_, exists, _ := getStopwatch(db.GetEngine(db.DefaultContext), userID, issueID)
89+
_, exists, _ := getStopwatch(db.DefaultContext, userID, issueID)
7090
return exists
7191
}
7292

@@ -83,93 +103,110 @@ func hasUserStopwatch(e db.Engine, userID int64) (exists bool, sw *Stopwatch, er
83103
return
84104
}
85105

86-
// CreateOrStopIssueStopwatch will create or remove a stopwatch and will log it into issue's timeline.
87-
func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
88-
ctx, committer, err := db.TxContext()
106+
// FinishIssueStopwatchIfPossible if stopwatch exist then finish it otherwise ignore
107+
func FinishIssueStopwatchIfPossible(ctx context.Context, user *User, issue *Issue) error {
108+
_, exists, err := getStopwatch(ctx, user.ID, issue.ID)
89109
if err != nil {
90110
return err
91111
}
92-
defer committer.Close()
93-
if err := createOrStopIssueStopwatch(ctx, user, issue); err != nil {
94-
return err
112+
if !exists {
113+
return nil
95114
}
96-
return committer.Commit()
115+
return FinishIssueStopwatch(ctx, user, issue)
97116
}
98117

99-
func createOrStopIssueStopwatch(ctx context.Context, user *User, issue *Issue) error {
100-
e := db.GetEngine(ctx)
101-
sw, exists, err := getStopwatch(e, user.ID, issue.ID)
118+
// CreateOrStopIssueStopwatch create an issue stopwatch if it's not exist, otherwise finish it
119+
func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
120+
_, exists, err := getStopwatch(db.DefaultContext, user.ID, issue.ID)
102121
if err != nil {
103122
return err
104123
}
105-
if err := issue.loadRepo(e); err != nil {
106-
return err
107-
}
108-
109124
if exists {
110-
// Create tracked time out of the time difference between start date and actual date
111-
timediff := time.Now().Unix() - int64(sw.CreatedUnix)
125+
return FinishIssueStopwatch(db.DefaultContext, user, issue)
126+
}
127+
return CreateIssueStopwatch(db.DefaultContext, user, issue)
128+
}
112129

113-
// Create TrackedTime
114-
tt := &TrackedTime{
115-
Created: time.Now(),
116-
IssueID: issue.ID,
130+
// FinishIssueStopwatch if stopwatch exist then finish it otherwise return an error
131+
func FinishIssueStopwatch(ctx context.Context, user *User, issue *Issue) error {
132+
sw, exists, err := getStopwatch(ctx, user.ID, issue.ID)
133+
if err != nil {
134+
return err
135+
}
136+
if !exists {
137+
return ErrIssueStopwatchNotExist{
117138
UserID: user.ID,
118-
Time: timediff,
139+
IssueID: issue.ID,
119140
}
141+
}
120142

121-
if _, err := e.Insert(tt); err != nil {
122-
return err
123-
}
143+
// Create tracked time out of the time difference between start date and actual date
144+
timediff := time.Now().Unix() - int64(sw.CreatedUnix)
124145

125-
if _, err := createComment(ctx, &CreateCommentOptions{
126-
Doer: user,
127-
Issue: issue,
128-
Repo: issue.Repo,
129-
Content: SecToTime(timediff),
130-
Type: CommentTypeStopTracking,
131-
TimeID: tt.ID,
132-
}); err != nil {
133-
return err
134-
}
135-
if _, err := e.Delete(sw); err != nil {
136-
return err
137-
}
138-
} else {
139-
// if another stopwatch is running: stop it
140-
exists, sw, err := hasUserStopwatch(e, user.ID)
141-
if err != nil {
142-
return err
143-
}
144-
if exists {
145-
issue, err := getIssueByID(e, sw.IssueID)
146-
if err != nil {
147-
return err
148-
}
149-
if err := createOrStopIssueStopwatch(ctx, user, issue); err != nil {
150-
return err
151-
}
152-
}
146+
// Create TrackedTime
147+
tt := &TrackedTime{
148+
Created: time.Now(),
149+
IssueID: issue.ID,
150+
UserID: user.ID,
151+
Time: timediff,
152+
}
153+
154+
if err := db.Insert(ctx, tt); err != nil {
155+
return err
156+
}
157+
158+
if _, err := createComment(ctx, &CreateCommentOptions{
159+
Doer: user,
160+
Issue: issue,
161+
Repo: issue.Repo,
162+
Content: SecToTime(timediff),
163+
Type: CommentTypeStopTracking,
164+
TimeID: tt.ID,
165+
}); err != nil {
166+
return err
167+
}
168+
_, err = db.GetEngine(ctx).Delete(sw)
169+
return err
170+
}
153171

154-
// Create stopwatch
155-
sw = &Stopwatch{
172+
// CreateIssueStopwatch creates a stopwatch if not exist, otherwise return an error
173+
func CreateIssueStopwatch(ctx context.Context, user *User, issue *Issue) error {
174+
e := db.GetEngine(ctx)
175+
if err := issue.loadRepo(e); err != nil {
176+
return err
177+
}
178+
179+
// if another stopwatch is running: stop it
180+
exists, _, err := hasUserStopwatch(e, user.ID)
181+
if err != nil {
182+
return err
183+
}
184+
if exists {
185+
return ErrIssueStopwatchAlreadyExist{
156186
UserID: user.ID,
157187
IssueID: issue.ID,
158188
}
189+
}
159190

160-
if err := db.Insert(ctx, sw); err != nil {
161-
return err
162-
}
191+
// Create stopwatch
192+
var sw = &Stopwatch{
193+
UserID: user.ID,
194+
IssueID: issue.ID,
195+
}
163196

164-
if _, err := createComment(ctx, &CreateCommentOptions{
165-
Doer: user,
166-
Issue: issue,
167-
Repo: issue.Repo,
168-
Type: CommentTypeStartTracking,
169-
}); err != nil {
170-
return err
171-
}
197+
if err := db.Insert(ctx, sw); err != nil {
198+
return err
172199
}
200+
201+
if _, err := createComment(ctx, &CreateCommentOptions{
202+
Doer: user,
203+
Issue: issue,
204+
Repo: issue.Repo,
205+
Type: CommentTypeStartTracking,
206+
}); err != nil {
207+
return err
208+
}
209+
173210
return nil
174211
}
175212

@@ -188,7 +225,7 @@ func CancelStopwatch(user *User, issue *Issue) error {
188225

189226
func cancelStopwatch(ctx context.Context, user *User, issue *Issue) error {
190227
e := db.GetEngine(ctx)
191-
sw, exists, err := getStopwatch(e, user.ID, issue.ID)
228+
sw, exists, err := getStopwatch(ctx, user.ID, issue.ID)
192229
if err != nil {
193230
return err
194231
}

services/issue/status.go

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,27 @@ package issue
66

77
import (
88
"code.gitea.io/gitea/models"
9+
"code.gitea.io/gitea/models/db"
910
"code.gitea.io/gitea/modules/notification"
1011
)
1112

1213
// ChangeStatus changes issue status to open or closed.
1314
func ChangeStatus(issue *models.Issue, doer *models.User, closed bool) error {
14-
stopTimerIfAvailable := func(doer *models.User, issue *models.Issue) error {
15-
if models.StopwatchExists(doer.ID, issue.ID) {
16-
if err := models.CreateOrStopIssueStopwatch(doer, issue); err != nil {
17-
return err
18-
}
19-
}
20-
21-
return nil
22-
}
23-
2415
comment, err := issue.ChangeStatus(doer, closed)
2516
if err != nil {
2617
// Don't return an error when dependencies are open as this would let the push fail
2718
if models.IsErrDependenciesLeft(err) {
28-
return stopTimerIfAvailable(doer, issue)
19+
if closed {
20+
return models.FinishIssueStopwatchIfPossible(db.DefaultContext, doer, issue)
21+
}
2922
}
3023
return err
3124
}
3225

33-
if err := stopTimerIfAvailable(doer, issue); err != nil {
34-
return err
26+
if closed {
27+
if err := models.FinishIssueStopwatchIfPossible(db.DefaultContext, doer, issue); err != nil {
28+
return err
29+
}
3530
}
3631

3732
notification.NotifyIssueChangeStatus(doer, issue, comment, closed)

0 commit comments

Comments
 (0)