@@ -5,7 +5,6 @@ package issues
55
66import (
77 "context"
8- "fmt"
98 "time"
109
1110 "code.gitea.io/gitea/models/db"
@@ -15,20 +14,6 @@ import (
1514 "code.gitea.io/gitea/modules/util"
1615)
1716
18- // ErrIssueStopwatchNotExist represents an error that stopwatch is not exist
19- type ErrIssueStopwatchNotExist struct {
20- UserID int64
21- IssueID int64
22- }
23-
24- func (err ErrIssueStopwatchNotExist ) Error () string {
25- return fmt .Sprintf ("issue stopwatch doesn't exist[uid: %d, issue_id: %d" , err .UserID , err .IssueID )
26- }
27-
28- func (err ErrIssueStopwatchNotExist ) Unwrap () error {
29- return util .ErrNotExist
30- }
31-
3217// Stopwatch represents a stopwatch for time tracking.
3318type Stopwatch struct {
3419 ID int64 `xorm:"pk autoincr"`
@@ -55,13 +40,11 @@ func getStopwatch(ctx context.Context, userID, issueID int64) (sw *Stopwatch, ex
5540 return sw , exists , err
5641}
5742
58- // UserIDCount is a simple coalition of UserID and Count
5943type UserStopwatch struct {
6044 UserID int64
6145 StopWatches []* Stopwatch
6246}
6347
64- // GetUIDsAndNotificationCounts between the two provided times
6548func GetUIDsAndStopwatch (ctx context.Context ) ([]* UserStopwatch , error ) {
6649 sws := []* Stopwatch {}
6750 if err := db .GetEngine (ctx ).Where ("issue_id != 0" ).Find (& sws ); err != nil {
@@ -87,7 +70,7 @@ func GetUIDsAndStopwatch(ctx context.Context) ([]*UserStopwatch, error) {
8770 return res , nil
8871}
8972
90- // GetUserStopwatches return list of all stopwatches of a user
73+ // GetUserStopwatches return list of the user's all stopwatches
9174func GetUserStopwatches (ctx context.Context , userID int64 , listOptions db.ListOptions ) ([]* Stopwatch , error ) {
9275 sws := make ([]* Stopwatch , 0 , 8 )
9376 sess := db .GetEngine (ctx ).Where ("stopwatch.user_id = ?" , userID )
@@ -102,7 +85,7 @@ func GetUserStopwatches(ctx context.Context, userID int64, listOptions db.ListOp
10285 return sws , nil
10386}
10487
105- // CountUserStopwatches return count of all stopwatches of a user
88+ // CountUserStopwatches return count of the user's all stopwatches
10689func CountUserStopwatches (ctx context.Context , userID int64 ) (int64 , error ) {
10790 return db .GetEngine (ctx ).Where ("user_id = ?" , userID ).Count (& Stopwatch {})
10891}
@@ -136,43 +119,21 @@ func HasUserStopwatch(ctx context.Context, userID int64) (exists bool, sw *Stopw
136119 return exists , sw , issue , err
137120}
138121
139- // FinishIssueStopwatchIfPossible if stopwatch exist then finish it otherwise ignore
140- func FinishIssueStopwatchIfPossible (ctx context.Context , user * user_model.User , issue * Issue ) error {
141- _ , exists , err := getStopwatch (ctx , user .ID , issue .ID )
142- if err != nil {
143- return err
144- }
145- if ! exists {
146- return nil
147- }
148- return FinishIssueStopwatch (ctx , user , issue )
149- }
150-
151- // CreateOrStopIssueStopwatch create an issue stopwatch if it's not exist, otherwise finish it
152- func CreateOrStopIssueStopwatch (ctx context.Context , user * user_model.User , issue * Issue ) error {
153- _ , exists , err := getStopwatch (ctx , user .ID , issue .ID )
154- if err != nil {
155- return err
156- }
157- if exists {
158- return FinishIssueStopwatch (ctx , user , issue )
159- }
160- return CreateIssueStopwatch (ctx , user , issue )
161- }
162-
163- // FinishIssueStopwatch if stopwatch exist then finish it otherwise return an error
164- func FinishIssueStopwatch (ctx context.Context , user * user_model.User , issue * Issue ) error {
122+ // FinishIssueStopwatch if stopwatch exists, then finish it.
123+ func FinishIssueStopwatch (ctx context.Context , user * user_model.User , issue * Issue ) (ok bool , err error ) {
165124 sw , exists , err := getStopwatch (ctx , user .ID , issue .ID )
166125 if err != nil {
167- return err
126+ return false , err
127+ } else if ! exists {
128+ return false , nil
168129 }
169- if ! exists {
170- return ErrIssueStopwatchNotExist {
171- UserID : user .ID ,
172- IssueID : issue .ID ,
173- }
130+ if err = finishIssueStopwatch (ctx , user , issue , sw ); err != nil {
131+ return false , err
174132 }
133+ return true , nil
134+ }
175135
136+ func finishIssueStopwatch (ctx context.Context , user * user_model.User , issue * Issue , sw * Stopwatch ) error {
176137 // Create tracked time out of the time difference between start date and actual date
177138 timediff := time .Now ().Unix () - int64 (sw .CreatedUnix )
178139
@@ -184,14 +145,12 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss
184145 Time : timediff ,
185146 }
186147
187- if err := db . Insert (ctx , tt ); err != nil {
148+ if err := issue . LoadRepo (ctx ); err != nil {
188149 return err
189150 }
190-
191- if err := issue .LoadRepo (ctx ); err != nil {
151+ if err := db .Insert (ctx , tt ); err != nil {
192152 return err
193153 }
194-
195154 if _ , err := CreateComment (ctx , & CreateCommentOptions {
196155 Doer : user ,
197156 Issue : issue ,
@@ -202,90 +161,74 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss
202161 }); err != nil {
203162 return err
204163 }
205- _ , err = db .DeleteByBean (ctx , sw )
164+ _ , err : = db .DeleteByBean (ctx , sw )
206165 return err
207166}
208167
209- // CreateIssueStopwatch creates a stopwatch if not exist, otherwise return an error
210- func CreateIssueStopwatch (ctx context.Context , user * user_model.User , issue * Issue ) error {
211- if err := issue .LoadRepo (ctx ); err != nil {
212- return err
213- }
214-
215- // if another stopwatch is running: stop it
216- exists , _ , otherIssue , err := HasUserStopwatch (ctx , user .ID )
217- if err != nil {
218- return err
219- }
220- if exists {
221- if err := FinishIssueStopwatch (ctx , user , otherIssue ); err != nil {
222- return err
168+ // CreateIssueStopwatch creates a stopwatch if the issue doesn't have the user's stopwatch.
169+ // It also stops any other stopwatch that might be running for the user.
170+ func CreateIssueStopwatch (ctx context.Context , user * user_model.User , issue * Issue ) (ok bool , err error ) {
171+ { // if another issue's stopwatch is running: stop it; if this issue has a stopwatch: return an error.
172+ exists , otherStopWatch , otherIssue , err := HasUserStopwatch (ctx , user .ID )
173+ if err != nil {
174+ return false , err
175+ }
176+ if exists {
177+ if otherStopWatch .IssueID == issue .ID {
178+ // don't allow starting stopwatch for the same issue
179+ return false , nil
180+ }
181+ // stop the other issue's stopwatch
182+ if err = finishIssueStopwatch (ctx , user , otherIssue , otherStopWatch ); err != nil {
183+ return false , err
184+ }
223185 }
224186 }
225187
226- // Create stopwatch
227- sw := & Stopwatch {
228- UserID : user .ID ,
229- IssueID : issue .ID ,
188+ if err = issue .LoadRepo (ctx ); err != nil {
189+ return false , err
230190 }
231-
232- if err := db .Insert (ctx , sw ); err != nil {
233- return err
191+ if err = db .Insert (ctx , & Stopwatch {UserID : user .ID , IssueID : issue .ID }); err != nil {
192+ return false , err
234193 }
235-
236- if err := issue .LoadRepo (ctx ); err != nil {
237- return err
238- }
239-
240- if _ , err := CreateComment (ctx , & CreateCommentOptions {
194+ if _ , err = CreateComment (ctx , & CreateCommentOptions {
241195 Doer : user ,
242196 Issue : issue ,
243197 Repo : issue .Repo ,
244198 Type : CommentTypeStartTracking ,
245199 }); err != nil {
246- return err
200+ return false , err
247201 }
248-
249- return nil
202+ return true , nil
250203}
251204
252205// CancelStopwatch removes the given stopwatch and logs it into issue's timeline.
253- func CancelStopwatch (ctx context.Context , user * user_model.User , issue * Issue ) error {
254- ctx , committer , err := db .TxContext (ctx )
255- if err != nil {
256- return err
257- }
258- defer committer .Close ()
259- if err := cancelStopwatch (ctx , user , issue ); err != nil {
260- return err
261- }
262- return committer .Commit ()
263- }
264-
265- func cancelStopwatch (ctx context.Context , user * user_model.User , issue * Issue ) error {
266- e := db .GetEngine (ctx )
267- sw , exists , err := getStopwatch (ctx , user .ID , issue .ID )
268- if err != nil {
269- return err
270- }
271-
272- if exists {
273- if _ , err := e .Delete (sw ); err != nil {
206+ func CancelStopwatch (ctx context.Context , user * user_model.User , issue * Issue ) (ok bool , err error ) {
207+ err = db .WithTx (ctx , func (ctx context.Context ) error {
208+ e := db .GetEngine (ctx )
209+ sw , exists , err := getStopwatch (ctx , user .ID , issue .ID )
210+ if err != nil {
274211 return err
212+ } else if ! exists {
213+ return nil
275214 }
276215
277- if err : = issue .LoadRepo (ctx ); err != nil {
216+ if err = issue .LoadRepo (ctx ); err != nil {
278217 return err
279218 }
280-
281- if _ , err := CreateComment (ctx , & CreateCommentOptions {
219+ if _ , err = e .Delete (sw ); err != nil {
220+ return err
221+ }
222+ if _ , err = CreateComment (ctx , & CreateCommentOptions {
282223 Doer : user ,
283224 Issue : issue ,
284225 Repo : issue .Repo ,
285226 Type : CommentTypeCancelTracking ,
286227 }); err != nil {
287228 return err
288229 }
289- }
290- return nil
230+ ok = true
231+ return nil
232+ })
233+ return ok , err
291234}
0 commit comments