gitea

Зеркало из https://github.com/go-gitea/gitea
Форк
0
/
stopwatch.go 
296 строк · 7.5 Кб
1
// Copyright 2017 The Gitea Authors. All rights reserved.
2
// SPDX-License-Identifier: MIT
3

4
package issues
5

6
import (
7
	"context"
8
	"fmt"
9
	"time"
10

11
	"code.gitea.io/gitea/models/db"
12
	"code.gitea.io/gitea/models/repo"
13
	user_model "code.gitea.io/gitea/models/user"
14
	"code.gitea.io/gitea/modules/timeutil"
15
	"code.gitea.io/gitea/modules/util"
16
)
17

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

32
// Stopwatch represents a stopwatch for time tracking.
33
type Stopwatch struct {
34
	ID          int64              `xorm:"pk autoincr"`
35
	IssueID     int64              `xorm:"INDEX"`
36
	UserID      int64              `xorm:"INDEX"`
37
	CreatedUnix timeutil.TimeStamp `xorm:"created"`
38
}
39

40
func init() {
41
	db.RegisterModel(new(Stopwatch))
42
}
43

44
// Seconds returns the amount of time passed since creation, based on local server time
45
func (s Stopwatch) Seconds() int64 {
46
	return int64(timeutil.TimeStampNow() - s.CreatedUnix)
47
}
48

49
// Duration returns a human-readable duration string based on local server time
50
func (s Stopwatch) Duration() string {
51
	return util.SecToTime(s.Seconds())
52
}
53

54
func getStopwatch(ctx context.Context, userID, issueID int64) (sw *Stopwatch, exists bool, err error) {
55
	sw = new(Stopwatch)
56
	exists, err = db.GetEngine(ctx).
57
		Where("user_id = ?", userID).
58
		And("issue_id = ?", issueID).
59
		Get(sw)
60
	return sw, exists, err
61
}
62

63
// UserIDCount is a simple coalition of UserID and Count
64
type UserStopwatch struct {
65
	UserID      int64
66
	StopWatches []*Stopwatch
67
}
68

69
// GetUIDsAndNotificationCounts between the two provided times
70
func GetUIDsAndStopwatch(ctx context.Context) ([]*UserStopwatch, error) {
71
	sws := []*Stopwatch{}
72
	if err := db.GetEngine(ctx).Where("issue_id != 0").Find(&sws); err != nil {
73
		return nil, err
74
	}
75
	if len(sws) == 0 {
76
		return []*UserStopwatch{}, nil
77
	}
78

79
	lastUserID := int64(-1)
80
	res := []*UserStopwatch{}
81
	for _, sw := range sws {
82
		if lastUserID == sw.UserID {
83
			lastUserStopwatch := res[len(res)-1]
84
			lastUserStopwatch.StopWatches = append(lastUserStopwatch.StopWatches, sw)
85
		} else {
86
			res = append(res, &UserStopwatch{
87
				UserID:      sw.UserID,
88
				StopWatches: []*Stopwatch{sw},
89
			})
90
		}
91
	}
92
	return res, nil
93
}
94

95
// GetUserStopwatches return list of all stopwatches of a user
96
func GetUserStopwatches(ctx context.Context, userID int64, listOptions db.ListOptions) ([]*Stopwatch, error) {
97
	sws := make([]*Stopwatch, 0, 8)
98
	sess := db.GetEngine(ctx).Where("stopwatch.user_id = ?", userID)
99
	if listOptions.Page != 0 {
100
		sess = db.SetSessionPagination(sess, &listOptions)
101
	}
102

103
	err := sess.Find(&sws)
104
	if err != nil {
105
		return nil, err
106
	}
107
	return sws, nil
108
}
109

110
// CountUserStopwatches return count of all stopwatches of a user
111
func CountUserStopwatches(ctx context.Context, userID int64) (int64, error) {
112
	return db.GetEngine(ctx).Where("user_id = ?", userID).Count(&Stopwatch{})
113
}
114

115
// StopwatchExists returns true if the stopwatch exists
116
func StopwatchExists(ctx context.Context, userID, issueID int64) bool {
117
	_, exists, _ := getStopwatch(ctx, userID, issueID)
118
	return exists
119
}
120

121
// HasUserStopwatch returns true if the user has a stopwatch
122
func HasUserStopwatch(ctx context.Context, userID int64) (exists bool, sw *Stopwatch, issue *Issue, err error) {
123
	type stopwatchIssueRepo struct {
124
		Stopwatch       `xorm:"extends"`
125
		Issue           `xorm:"extends"`
126
		repo.Repository `xorm:"extends"`
127
	}
128

129
	swIR := new(stopwatchIssueRepo)
130
	exists, err = db.GetEngine(ctx).
131
		Table("stopwatch").
132
		Where("user_id = ?", userID).
133
		Join("INNER", "issue", "issue.id = stopwatch.issue_id").
134
		Join("INNER", "repository", "repository.id = issue.repo_id").
135
		Get(swIR)
136
	if exists {
137
		sw = &swIR.Stopwatch
138
		issue = &swIR.Issue
139
		issue.Repo = &swIR.Repository
140
	}
141
	return exists, sw, issue, err
142
}
143

144
// FinishIssueStopwatchIfPossible if stopwatch exist then finish it otherwise ignore
145
func FinishIssueStopwatchIfPossible(ctx context.Context, user *user_model.User, issue *Issue) error {
146
	_, exists, err := getStopwatch(ctx, user.ID, issue.ID)
147
	if err != nil {
148
		return err
149
	}
150
	if !exists {
151
		return nil
152
	}
153
	return FinishIssueStopwatch(ctx, user, issue)
154
}
155

156
// CreateOrStopIssueStopwatch create an issue stopwatch if it's not exist, otherwise finish it
157
func CreateOrStopIssueStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error {
158
	_, exists, err := getStopwatch(ctx, user.ID, issue.ID)
159
	if err != nil {
160
		return err
161
	}
162
	if exists {
163
		return FinishIssueStopwatch(ctx, user, issue)
164
	}
165
	return CreateIssueStopwatch(ctx, user, issue)
166
}
167

168
// FinishIssueStopwatch if stopwatch exist then finish it otherwise return an error
169
func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error {
170
	sw, exists, err := getStopwatch(ctx, user.ID, issue.ID)
171
	if err != nil {
172
		return err
173
	}
174
	if !exists {
175
		return ErrIssueStopwatchNotExist{
176
			UserID:  user.ID,
177
			IssueID: issue.ID,
178
		}
179
	}
180

181
	// Create tracked time out of the time difference between start date and actual date
182
	timediff := time.Now().Unix() - int64(sw.CreatedUnix)
183

184
	// Create TrackedTime
185
	tt := &TrackedTime{
186
		Created: time.Now(),
187
		IssueID: issue.ID,
188
		UserID:  user.ID,
189
		Time:    timediff,
190
	}
191

192
	if err := db.Insert(ctx, tt); err != nil {
193
		return err
194
	}
195

196
	if err := issue.LoadRepo(ctx); err != nil {
197
		return err
198
	}
199

200
	if _, err := CreateComment(ctx, &CreateCommentOptions{
201
		Doer:    user,
202
		Issue:   issue,
203
		Repo:    issue.Repo,
204
		Content: util.SecToTime(timediff),
205
		Type:    CommentTypeStopTracking,
206
		TimeID:  tt.ID,
207
	}); err != nil {
208
		return err
209
	}
210
	_, err = db.DeleteByBean(ctx, sw)
211
	return err
212
}
213

214
// CreateIssueStopwatch creates a stopwatch if not exist, otherwise return an error
215
func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error {
216
	if err := issue.LoadRepo(ctx); err != nil {
217
		return err
218
	}
219

220
	// if another stopwatch is running: stop it
221
	exists, _, otherIssue, err := HasUserStopwatch(ctx, user.ID)
222
	if err != nil {
223
		return err
224
	}
225
	if exists {
226
		if err := FinishIssueStopwatch(ctx, user, otherIssue); err != nil {
227
			return err
228
		}
229
	}
230

231
	// Create stopwatch
232
	sw := &Stopwatch{
233
		UserID:  user.ID,
234
		IssueID: issue.ID,
235
	}
236

237
	if err := db.Insert(ctx, sw); err != nil {
238
		return err
239
	}
240

241
	if err := issue.LoadRepo(ctx); err != nil {
242
		return err
243
	}
244

245
	if _, err := CreateComment(ctx, &CreateCommentOptions{
246
		Doer:  user,
247
		Issue: issue,
248
		Repo:  issue.Repo,
249
		Type:  CommentTypeStartTracking,
250
	}); err != nil {
251
		return err
252
	}
253

254
	return nil
255
}
256

257
// CancelStopwatch removes the given stopwatch and logs it into issue's timeline.
258
func CancelStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error {
259
	ctx, committer, err := db.TxContext(ctx)
260
	if err != nil {
261
		return err
262
	}
263
	defer committer.Close()
264
	if err := cancelStopwatch(ctx, user, issue); err != nil {
265
		return err
266
	}
267
	return committer.Commit()
268
}
269

270
func cancelStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error {
271
	e := db.GetEngine(ctx)
272
	sw, exists, err := getStopwatch(ctx, user.ID, issue.ID)
273
	if err != nil {
274
		return err
275
	}
276

277
	if exists {
278
		if _, err := e.Delete(sw); err != nil {
279
			return err
280
		}
281

282
		if err := issue.LoadRepo(ctx); err != nil {
283
			return err
284
		}
285

286
		if _, err := CreateComment(ctx, &CreateCommentOptions{
287
			Doer:  user,
288
			Issue: issue,
289
			Repo:  issue.Repo,
290
			Type:  CommentTypeCancelTracking,
291
		}); err != nil {
292
			return err
293
		}
294
	}
295
	return nil
296
}
297

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.