@@ -13,6 +13,26 @@ import (
13
13
"code.gitea.io/gitea/modules/timeutil"
14
14
)
15
15
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 doesn't 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 already exists[uid: %d, issue_id: %d" , err .UserID , err .IssueID )
34
+ }
35
+
16
36
// Stopwatch represents a stopwatch for time tracking.
17
37
type Stopwatch struct {
18
38
ID int64 `xorm:"pk autoincr"`
@@ -35,9 +55,9 @@ func (s Stopwatch) Duration() string {
35
55
return SecToTime (s .Seconds ())
36
56
}
37
57
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 ) {
39
59
sw = new (Stopwatch )
40
- exists , err = e .
60
+ exists , err = db . GetEngine ( ctx ) .
41
61
Where ("user_id = ?" , userID ).
42
62
And ("issue_id = ?" , issueID ).
43
63
Get (sw )
@@ -66,7 +86,7 @@ func CountUserStopwatches(userID int64) (int64, error) {
66
86
67
87
// StopwatchExists returns true if the stopwatch exists
68
88
func StopwatchExists (userID , issueID int64 ) bool {
69
- _ , exists , _ := getStopwatch (db .GetEngine ( db . DefaultContext ) , userID , issueID )
89
+ _ , exists , _ := getStopwatch (db .DefaultContext , userID , issueID )
70
90
return exists
71
91
}
72
92
@@ -83,93 +103,122 @@ func hasUserStopwatch(e db.Engine, userID int64) (exists bool, sw *Stopwatch, er
83
103
return
84
104
}
85
105
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 )
89
109
if err != nil {
90
110
return err
91
111
}
92
- defer committer .Close ()
93
- if err := createOrStopIssueStopwatch (ctx , user , issue ); err != nil {
112
+ if ! exists {
113
+ return nil
114
+ }
115
+ return FinishIssueStopwatch (ctx , user , issue )
116
+ }
117
+
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 )
121
+ if err != nil {
94
122
return err
95
123
}
96
- return committer .Commit ()
124
+ if exists {
125
+ return FinishIssueStopwatch (db .DefaultContext , user , issue )
126
+ }
127
+ return CreateIssueStopwatch (db .DefaultContext , user , issue )
97
128
}
98
129
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 )
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 )
102
133
if err != nil {
103
134
return err
104
135
}
105
- if err := issue .loadRepo (e ); err != nil {
136
+ if ! exists {
137
+ return ErrIssueStopwatchNotExist {
138
+ UserID : user .ID ,
139
+ IssueID : issue .ID ,
140
+ }
141
+ }
142
+
143
+ // Create tracked time out of the time difference between start date and actual date
144
+ timediff := time .Now ().Unix () - int64 (sw .CreatedUnix )
145
+
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 {
106
155
return err
107
156
}
108
157
109
- 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 )
158
+ if err := issue . loadRepo ( db . GetEngine ( ctx )); err != nil {
159
+ return err
160
+ }
112
161
113
- // Create TrackedTime
114
- tt := & TrackedTime {
115
- Created : time .Now (),
116
- IssueID : issue .ID ,
117
- UserID : user .ID ,
118
- Time : timediff ,
119
- }
162
+ if _ , err := createComment (ctx , & CreateCommentOptions {
163
+ Doer : user ,
164
+ Issue : issue ,
165
+ Repo : issue .Repo ,
166
+ Content : SecToTime (timediff ),
167
+ Type : CommentTypeStopTracking ,
168
+ TimeID : tt .ID ,
169
+ }); err != nil {
170
+ return err
171
+ }
172
+ _ , err = db .GetEngine (ctx ).Delete (sw )
173
+ return err
174
+ }
120
175
121
- if _ , err := e .Insert (tt ); err != nil {
122
- return err
123
- }
176
+ // CreateIssueStopwatch creates a stopwatch if not exist, otherwise return an error
177
+ func CreateIssueStopwatch (ctx context.Context , user * User , issue * Issue ) error {
178
+ e := db .GetEngine (ctx )
179
+ if err := issue .loadRepo (e ); err != nil {
180
+ return err
181
+ }
124
182
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 )
183
+ // if another stopwatch is running: stop it
184
+ exists , sw , err := hasUserStopwatch (e , user .ID )
185
+ if err != nil {
186
+ return err
187
+ }
188
+ if exists {
189
+ issue , err := getIssueByID (e , sw .IssueID )
141
190
if err != nil {
142
191
return err
143
192
}
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
- }
153
193
154
- // Create stopwatch
155
- sw = & Stopwatch {
156
- UserID : user .ID ,
157
- IssueID : issue .ID ,
158
- }
159
-
160
- if err := db .Insert (ctx , sw ); err != nil {
194
+ if err := FinishIssueStopwatch (ctx , user , issue ); err != nil {
161
195
return err
162
196
}
197
+ }
163
198
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
- }
199
+ // Create stopwatch
200
+ sw = & Stopwatch {
201
+ UserID : user . ID ,
202
+ IssueID : issue .ID ,
203
+ }
204
+
205
+ if err := db . Insert ( ctx , sw ); err != nil {
206
+ return err
172
207
}
208
+
209
+ if err := issue .loadRepo (db .GetEngine (ctx )); err != nil {
210
+ return err
211
+ }
212
+
213
+ if _ , err := createComment (ctx , & CreateCommentOptions {
214
+ Doer : user ,
215
+ Issue : issue ,
216
+ Repo : issue .Repo ,
217
+ Type : CommentTypeStartTracking ,
218
+ }); err != nil {
219
+ return err
220
+ }
221
+
173
222
return nil
174
223
}
175
224
@@ -188,7 +237,7 @@ func CancelStopwatch(user *User, issue *Issue) error {
188
237
189
238
func cancelStopwatch (ctx context.Context , user * User , issue * Issue ) error {
190
239
e := db .GetEngine (ctx )
191
- sw , exists , err := getStopwatch (e , user .ID , issue .ID )
240
+ sw , exists , err := getStopwatch (ctx , user .ID , issue .ID )
192
241
if err != nil {
193
242
return err
194
243
}
@@ -202,6 +251,10 @@ func cancelStopwatch(ctx context.Context, user *User, issue *Issue) error {
202
251
return err
203
252
}
204
253
254
+ if err := issue .loadRepo (db .GetEngine (ctx )); err != nil {
255
+ return err
256
+ }
257
+
205
258
if _ , err := createComment (ctx , & CreateCommentOptions {
206
259
Doer : user ,
207
260
Issue : issue ,
0 commit comments