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
|
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"time"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"github.com/go-xorm/xorm"
"xorm.io/builder"
)
// TrackedTime represents a time that was spent for a specific issue.
type TrackedTime struct {
ID int64 `xorm:"pk autoincr" json:"id"`
IssueID int64 `xorm:"INDEX" json:"issue_id"`
UserID int64 `xorm:"INDEX" json:"user_id"`
Created time.Time `xorm:"-" json:"created"`
CreatedUnix int64 `xorm:"created" json:"-"`
Time int64 `json:"time"`
}
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
func (t *TrackedTime) AfterLoad() {
t.Created = time.Unix(t.CreatedUnix, 0).In(setting.UILocation)
}
// APIFormat converts TrackedTime to API format
func (t *TrackedTime) APIFormat() *api.TrackedTime {
return &api.TrackedTime{
ID: t.ID,
IssueID: t.IssueID,
UserID: t.UserID,
Time: t.Time,
Created: t.Created,
}
}
// FindTrackedTimesOptions represent the filters for tracked times. If an ID is 0 it will be ignored.
type FindTrackedTimesOptions struct {
IssueID int64
UserID int64
RepositoryID int64
MilestoneID int64
}
// ToCond will convert each condition into a xorm-Cond
func (opts *FindTrackedTimesOptions) ToCond() builder.Cond {
cond := builder.NewCond()
if opts.IssueID != 0 {
cond = cond.And(builder.Eq{"issue_id": opts.IssueID})
}
if opts.UserID != 0 {
cond = cond.And(builder.Eq{"user_id": opts.UserID})
}
if opts.RepositoryID != 0 {
cond = cond.And(builder.Eq{"issue.repo_id": opts.RepositoryID})
}
if opts.MilestoneID != 0 {
cond = cond.And(builder.Eq{"issue.milestone_id": opts.MilestoneID})
}
return cond
}
// ToSession will convert the given options to a xorm Session by using the conditions from ToCond and joining with issue table if required
func (opts *FindTrackedTimesOptions) ToSession(e Engine) *xorm.Session {
if opts.RepositoryID > 0 || opts.MilestoneID > 0 {
return e.Join("INNER", "issue", "issue.id = tracked_time.issue_id").Where(opts.ToCond())
}
return x.Where(opts.ToCond())
}
// GetTrackedTimes returns all tracked times that fit to the given options.
func GetTrackedTimes(options FindTrackedTimesOptions) (trackedTimes []*TrackedTime, err error) {
err = options.ToSession(x).Find(&trackedTimes)
return
}
// AddTime will add the given time (in seconds) to the issue
func AddTime(user *User, issue *Issue, time int64) (*TrackedTime, error) {
tt := &TrackedTime{
IssueID: issue.ID,
UserID: user.ID,
Time: time,
}
if _, err := x.Insert(tt); err != nil {
return nil, err
}
if err := issue.loadRepo(x); err != nil {
return nil, err
}
if _, err := CreateComment(&CreateCommentOptions{
Issue: issue,
Repo: issue.Repo,
Doer: user,
Content: SecToTime(time),
Type: CommentTypeAddTimeManual,
}); err != nil {
return nil, err
}
return tt, nil
}
// TotalTimes returns the spent time for each user by an issue
func TotalTimes(options FindTrackedTimesOptions) (map[*User]string, error) {
trackedTimes, err := GetTrackedTimes(options)
if err != nil {
return nil, err
}
//Adding total time per user ID
totalTimesByUser := make(map[int64]int64)
for _, t := range trackedTimes {
totalTimesByUser[t.UserID] += t.Time
}
totalTimes := make(map[*User]string)
//Fetching User and making time human readable
for userID, total := range totalTimesByUser {
user, err := GetUserByID(userID)
if err != nil {
if IsErrUserNotExist(err) {
continue
}
return nil, err
}
totalTimes[user] = SecToTime(total)
}
return totalTimes, nil
}
|