Skip to content

Commit f2d03cd

Browse files
6543zeripath
authored andcommitted
[API] Extend times API (#9200)
Extensively extend the times API. close #8833; close #8513; close #8559
1 parent 0bcf644 commit f2d03cd

19 files changed

+914
-192
lines changed
+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2019 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package integrations
6+
7+
import (
8+
"fmt"
9+
"net/http"
10+
"testing"
11+
"time"
12+
13+
"code.gitea.io/gitea/models"
14+
api "code.gitea.io/gitea/modules/structs"
15+
16+
"github.com/stretchr/testify/assert"
17+
)
18+
19+
func TestAPIGetTrackedTimes(t *testing.T) {
20+
defer prepareTestEnv(t)()
21+
22+
user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
23+
issue2 := models.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
24+
assert.NoError(t, issue2.LoadRepo())
25+
26+
session := loginUser(t, user2.Name)
27+
token := getTokenForLoggedInUser(t, session)
28+
29+
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/times?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, token)
30+
resp := session.MakeRequest(t, req, http.StatusOK)
31+
var apiTimes api.TrackedTimeList
32+
DecodeJSON(t, resp, &apiTimes)
33+
expect, err := models.GetTrackedTimes(models.FindTrackedTimesOptions{IssueID: issue2.ID})
34+
assert.NoError(t, err)
35+
assert.Len(t, apiTimes, 3)
36+
37+
for i, time := range expect {
38+
assert.Equal(t, time.ID, apiTimes[i].ID)
39+
assert.EqualValues(t, issue2.Title, apiTimes[i].Issue.Title)
40+
assert.EqualValues(t, issue2.ID, apiTimes[i].IssueID)
41+
assert.Equal(t, time.Created.Unix(), apiTimes[i].Created.Unix())
42+
assert.Equal(t, time.Time, apiTimes[i].Time)
43+
user, err := models.GetUserByID(time.UserID)
44+
assert.NoError(t, err)
45+
assert.Equal(t, user.Name, apiTimes[i].UserName)
46+
}
47+
}
48+
49+
func TestAPIDeleteTrackedTime(t *testing.T) {
50+
defer prepareTestEnv(t)()
51+
52+
time6 := models.AssertExistsAndLoadBean(t, &models.TrackedTime{ID: 6}).(*models.TrackedTime)
53+
issue2 := models.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
54+
assert.NoError(t, issue2.LoadRepo())
55+
user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
56+
57+
session := loginUser(t, user2.Name)
58+
token := getTokenForLoggedInUser(t, session)
59+
60+
//Deletion not allowed
61+
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time6.ID, token)
62+
session.MakeRequest(t, req, http.StatusForbidden)
63+
/* Delete own time <-- ToDo: timout without reason
64+
time3 := models.AssertExistsAndLoadBean(t, &models.TrackedTime{ID: 3}).(*models.TrackedTime)
65+
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time3.ID, token)
66+
session.MakeRequest(t, req, http.StatusNoContent)
67+
//Delete non existing time
68+
session.MakeRequest(t, req, http.StatusInternalServerError) */
69+
70+
//Reset time of user 2 on issue 2
71+
trackedSeconds, err := models.GetTrackedSeconds(models.FindTrackedTimesOptions{IssueID: 2, UserID: 2})
72+
assert.NoError(t, err)
73+
assert.Equal(t, int64(3662), trackedSeconds)
74+
75+
req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, token)
76+
session.MakeRequest(t, req, http.StatusNoContent)
77+
session.MakeRequest(t, req, http.StatusNotFound)
78+
79+
trackedSeconds, err = models.GetTrackedSeconds(models.FindTrackedTimesOptions{IssueID: 2, UserID: 2})
80+
assert.NoError(t, err)
81+
assert.Equal(t, int64(0), trackedSeconds)
82+
}
83+
84+
func TestAPIAddTrackedTimes(t *testing.T) {
85+
defer prepareTestEnv(t)()
86+
87+
issue2 := models.AssertExistsAndLoadBean(t, &models.Issue{ID: 2}).(*models.Issue)
88+
assert.NoError(t, issue2.LoadRepo())
89+
user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
90+
admin := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User)
91+
92+
session := loginUser(t, admin.Name)
93+
token := getTokenForLoggedInUser(t, session)
94+
95+
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/times?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, token)
96+
97+
req := NewRequestWithJSON(t, "POST", urlStr, &api.AddTimeOption{
98+
Time: 33,
99+
User: user2.Name,
100+
Created: time.Unix(947688818, 0),
101+
})
102+
resp := session.MakeRequest(t, req, http.StatusOK)
103+
var apiNewTime api.TrackedTime
104+
DecodeJSON(t, resp, &apiNewTime)
105+
106+
assert.EqualValues(t, 33, apiNewTime.Time)
107+
assert.EqualValues(t, user2.ID, apiNewTime.UserID)
108+
assert.EqualValues(t, 947688818, apiNewTime.Created.Unix())
109+
}

models/fixtures/tracked_time.yml

+39-2
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,68 @@
44
issue_id: 1
55
time: 400
66
created_unix: 946684800
7+
deleted: false
78

89
-
910
id: 2
1011
user_id: 2
1112
issue_id: 2
1213
time: 3661
1314
created_unix: 946684801
15+
deleted: false
1416

1517
-
1618
id: 3
1719
user_id: 2
1820
issue_id: 2
1921
time: 1
2022
created_unix: 946684802
23+
deleted: false
2124

2225
-
2326
id: 4
2427
user_id: -1
2528
issue_id: 4
2629
time: 1
27-
created_unix: 946684802
30+
created_unix: 946684803
31+
deleted: false
2832

2933
-
3034
id: 5
3135
user_id: 2
3236
issue_id: 5
3337
time: 1
34-
created_unix: 946684802
38+
created_unix: 946684804
39+
deleted: false
40+
41+
-
42+
id: 6
43+
user_id: 1
44+
issue_id: 2
45+
time: 20
46+
created_unix: 946684812
47+
deleted: false
48+
49+
-
50+
id: 7
51+
user_id: 2
52+
issue_id: 4
53+
time: 3
54+
created_unix: 946684813
55+
deleted: false
56+
57+
-
58+
id: 8
59+
user_id: 1
60+
issue_id: 4
61+
time: 71
62+
created_unix: 947688814
63+
deleted: false
64+
65+
-
66+
id: 9
67+
user_id: 2
68+
issue_id: 2
69+
time: 100000
70+
created_unix: 947688815
71+
deleted: true

models/issue_comment.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ const (
8484
CommentTypeUnlock
8585
// Change pull request's target branch
8686
CommentTypeChangeTargetBranch
87+
// Delete time manual for time tracking
88+
CommentTypeDeleteTimeManual
8789
)
8890

8991
// CommentTag defines comment tag type
@@ -100,7 +102,7 @@ const (
100102
// Comment represents a comment in commit and issue page.
101103
type Comment struct {
102104
ID int64 `xorm:"pk autoincr"`
103-
Type CommentType `xorm:"index"`
105+
Type CommentType `xorm:"INDEX"`
104106
PosterID int64 `xorm:"INDEX"`
105107
Poster *User `xorm:"-"`
106108
OriginalAuthor string

models/issue_list.go

+1
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ func (issues IssueList) loadTotalTrackedTimes(e Engine) (err error) {
429429

430430
// select issue_id, sum(time) from tracked_time where issue_id in (<issue ids in current page>) group by issue_id
431431
rows, err := e.Table("tracked_time").
432+
Where("deleted = ?", false).
432433
Select("issue_id, sum(time) as time").
433434
In("issue_id", ids[:limit]).
434435
GroupBy("issue_id").

models/issue_list_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func TestIssueList_LoadAttributes(t *testing.T) {
6666
if issue.ID == int64(1) {
6767
assert.Equal(t, int64(400), issue.TotalTrackedTime)
6868
} else if issue.ID == int64(2) {
69-
assert.Equal(t, int64(3662), issue.TotalTrackedTime)
69+
assert.Equal(t, int64(3682), issue.TotalTrackedTime)
7070
}
7171
}
7272
}

models/issue_milestone.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import (
1010
"code.gitea.io/gitea/modules/setting"
1111
api "code.gitea.io/gitea/modules/structs"
1212
"code.gitea.io/gitea/modules/timeutil"
13-
"xorm.io/builder"
1413

14+
"xorm.io/builder"
1515
"xorm.io/xorm"
1616
)
1717

@@ -153,6 +153,7 @@ func (milestones MilestoneList) loadTotalTrackedTimes(e Engine) error {
153153
rows, err := e.Table("issue").
154154
Join("INNER", "milestone", "issue.milestone_id = milestone.id").
155155
Join("LEFT", "tracked_time", "tracked_time.issue_id = issue.id").
156+
Where("tracked_time.deleted = ?", false).
156157
Select("milestone_id, sum(time) as time").
157158
In("milestone_id", milestones.getMilestoneIDs()).
158159
GroupBy("milestone_id").
@@ -187,6 +188,7 @@ func (m *Milestone) loadTotalTrackedTime(e Engine) error {
187188
has, err := e.Table("issue").
188189
Join("INNER", "milestone", "issue.milestone_id = milestone.id").
189190
Join("LEFT", "tracked_time", "tracked_time.issue_id = issue.id").
191+
Where("tracked_time.deleted = ?", false).
190192
Select("milestone_id, sum(time) as time").
191193
Where("milestone_id = ?", m.ID).
192194
GroupBy("milestone_id").

models/issue_milestone_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) {
287287

288288
assert.NoError(t, miles.LoadTotalTrackedTimes())
289289

290-
assert.Equal(t, miles[0].TotalTrackedTime, int64(3662))
290+
assert.Equal(t, int64(3682), miles[0].TotalTrackedTime)
291291
}
292292

293293
func TestCountMilestonesByRepoIDs(t *testing.T) {
@@ -361,7 +361,7 @@ func TestLoadTotalTrackedTime(t *testing.T) {
361361

362362
assert.NoError(t, milestone.LoadTotalTrackedTime())
363363

364-
assert.Equal(t, milestone.TotalTrackedTime, int64(3662))
364+
assert.Equal(t, int64(3682), milestone.TotalTrackedTime)
365365
}
366366

367367
func TestGetMilestonesStats(t *testing.T) {

models/issue_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ func TestIssue_loadTotalTimes(t *testing.T) {
259259
ms, err := GetIssueByID(2)
260260
assert.NoError(t, err)
261261
assert.NoError(t, ms.loadTotalTimes(x))
262-
assert.Equal(t, int64(3662), ms.TotalTrackedTime)
262+
assert.Equal(t, int64(3682), ms.TotalTrackedTime)
263263
}
264264

265265
func TestIssue_SearchIssueIDsByKeyword(t *testing.T) {

0 commit comments

Comments
 (0)