Store and use seconds for timeline time comments (#25392)
this will allow us to fully localize it later PS: we can not migrate back as the old value was a one-way conversion prepare for #25213 --- *Sponsored by Kithara Software GmbH*
This commit is contained in:
parent
a954c93a68
commit
b0215c40cd
|
@ -6,6 +6,7 @@ package issues
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
@ -173,10 +174,12 @@ func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Tim
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
||||||
Issue: issue,
|
Issue: issue,
|
||||||
Repo: issue.Repo,
|
Repo: issue.Repo,
|
||||||
Doer: user,
|
Doer: user,
|
||||||
Content: util.SecToTime(amount),
|
// Content before v1.21 did store the formated string instead of seconds,
|
||||||
|
// so use "|" as delimeter to mark the new format
|
||||||
|
Content: fmt.Sprintf("|%d", amount),
|
||||||
Type: CommentTypeAddTimeManual,
|
Type: CommentTypeAddTimeManual,
|
||||||
TimeID: t.ID,
|
TimeID: t.ID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
@ -251,10 +254,12 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
||||||
Issue: issue,
|
Issue: issue,
|
||||||
Repo: issue.Repo,
|
Repo: issue.Repo,
|
||||||
Doer: user,
|
Doer: user,
|
||||||
Content: "- " + util.SecToTime(removedTime),
|
// Content before v1.21 did store the formated string instead of seconds,
|
||||||
|
// so use "|" as delimeter to mark the new format
|
||||||
|
Content: fmt.Sprintf("|%d", removedTime),
|
||||||
Type: CommentTypeDeleteTimeManual,
|
Type: CommentTypeDeleteTimeManual,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -280,10 +285,12 @@ func DeleteTime(t *TrackedTime) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
||||||
Issue: t.Issue,
|
Issue: t.Issue,
|
||||||
Repo: t.Issue.Repo,
|
Repo: t.Issue.Repo,
|
||||||
Doer: t.User,
|
Doer: t.User,
|
||||||
Content: "- " + util.SecToTime(t.Time),
|
// Content before v1.21 did store the formated string instead of seconds,
|
||||||
|
// so use "|" as delimeter to mark the new format
|
||||||
|
Content: fmt.Sprintf("|%d", t.Time),
|
||||||
Type: CommentTypeDeleteTimeManual,
|
Type: CommentTypeDeleteTimeManual,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -35,7 +35,7 @@ func TestAddTime(t *testing.T) {
|
||||||
assert.Equal(t, int64(3661), tt.Time)
|
assert.Equal(t, int64(3661), tt.Time)
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeAddTimeManual, PosterID: 3, IssueID: 1})
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeAddTimeManual, PosterID: 3, IssueID: 1})
|
||||||
assert.Equal(t, "1 hour 1 minute", comment.Content)
|
assert.Equal(t, "|3661", comment.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTrackedTimes(t *testing.T) {
|
func TestGetTrackedTimes(t *testing.T) {
|
||||||
|
|
|
@ -15,7 +15,9 @@ import (
|
||||||
// 1563418 -> 2 weeks 4 days
|
// 1563418 -> 2 weeks 4 days
|
||||||
// 3937125s -> 1 month 2 weeks
|
// 3937125s -> 1 month 2 weeks
|
||||||
// 45677465s -> 1 year 6 months
|
// 45677465s -> 1 year 6 months
|
||||||
func SecToTime(duration int64) string {
|
func SecToTime(durationVal any) string {
|
||||||
|
duration, _ := ToInt64(durationVal)
|
||||||
|
|
||||||
formattedTime := ""
|
formattedTime := ""
|
||||||
|
|
||||||
// The following four variables are calculated by taking
|
// The following four variables are calculated by taking
|
||||||
|
|
|
@ -1647,9 +1647,22 @@ func ViewIssue(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if comment.Type == issues_model.CommentTypeAddTimeManual ||
|
} else if comment.Type == issues_model.CommentTypeAddTimeManual ||
|
||||||
comment.Type == issues_model.CommentTypeStopTracking {
|
comment.Type == issues_model.CommentTypeStopTracking ||
|
||||||
|
comment.Type == issues_model.CommentTypeDeleteTimeManual {
|
||||||
// drop error since times could be pruned from DB..
|
// drop error since times could be pruned from DB..
|
||||||
_ = comment.LoadTime()
|
_ = comment.LoadTime()
|
||||||
|
if comment.Content != "" {
|
||||||
|
// Content before v1.21 did store the formated string instead of seconds,
|
||||||
|
// so "|" is used as delimeter to mark the new format
|
||||||
|
if comment.Content[0] != '|' {
|
||||||
|
// handle old time comments that have formatted text stored
|
||||||
|
comment.RenderedContent = comment.Content
|
||||||
|
comment.Content = ""
|
||||||
|
} else {
|
||||||
|
// else it's just a duration in seconds to pass on to the frontend
|
||||||
|
comment.Content = comment.Content[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if comment.Type == issues_model.CommentTypeClose || comment.Type == issues_model.CommentTypeMergePull {
|
if comment.Type == issues_model.CommentTypeClose || comment.Type == issues_model.CommentTypeMergePull {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToComment converts a issues_model.Comment to the api.Comment format
|
// ToComment converts a issues_model.Comment to the api.Comment format
|
||||||
|
@ -66,6 +67,17 @@ func ToTimelineComment(ctx context.Context, c *issues_model.Comment, doer *user_
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Content != "" {
|
||||||
|
if (c.Type == issues_model.CommentTypeAddTimeManual ||
|
||||||
|
c.Type == issues_model.CommentTypeStopTracking ||
|
||||||
|
c.Type == issues_model.CommentTypeDeleteTimeManual) &&
|
||||||
|
c.Content[0] == '|' {
|
||||||
|
// TimeTracking Comments from v1.21 on store the seconds instead of an formated string
|
||||||
|
// so we check for the "|" delimeter and convert new to legacy format on demand
|
||||||
|
c.Content = util.SecToTime(c.Content[1:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
comment := &api.TimelineComment{
|
comment := &api.TimelineComment{
|
||||||
ID: c.ID,
|
ID: c.ID,
|
||||||
Type: c.Type.String(),
|
Type: c.Type.String(),
|
||||||
|
|
|
@ -263,7 +263,12 @@
|
||||||
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
{{svg "octicon-clock"}}
|
{{svg "octicon-clock"}}
|
||||||
<span class="text grey muted-links">{{.Content}}</span>
|
{{if .RenderedContent}}
|
||||||
|
{{/* compatibility with time comments made before v1.21 */}}
|
||||||
|
<span class="text grey muted-links">{{.RenderedContent}}</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="text grey muted-links">{{.Content|Sec2Time}}</span>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{else if eq .Type 14}}
|
{{else if eq .Type 14}}
|
||||||
|
@ -277,7 +282,12 @@
|
||||||
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
{{template "repo/issue/view_content/comments_delete_time" dict "ctxData" $ "comment" .}}
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
{{svg "octicon-clock"}}
|
{{svg "octicon-clock"}}
|
||||||
<span class="text grey muted-links">{{.Content}}</span>
|
{{if .RenderedContent}}
|
||||||
|
{{/* compatibility with time comments made before v1.21 */}}
|
||||||
|
<span class="text grey muted-links">{{.RenderedContent}}</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="text grey muted-links">{{.Content|Sec2Time}}</span>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{else if eq .Type 15}}
|
{{else if eq .Type 15}}
|
||||||
|
@ -676,7 +686,12 @@
|
||||||
</span>
|
</span>
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
{{svg "octicon-clock"}}
|
{{svg "octicon-clock"}}
|
||||||
<span class="text grey muted-links">{{.Content}}</span>
|
{{if .RenderedContent}}
|
||||||
|
{{/* compatibility with time comments made before v1.21 */}}
|
||||||
|
<span class="text grey muted-links">{{.RenderedContent}}</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="text grey muted-links">- {{.Content|Sec2Time}}</span>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{else if eq .Type 27}}
|
{{else if eq .Type 27}}
|
||||||
|
|
Loading…
Reference in a new issue