From 1d57f0d64fcd9aec16b4003d5664f31ea748da03 Mon Sep 17 00:00:00 2001 From: Unknwon Date: Fri, 13 Nov 2015 17:10:25 -0500 Subject: Show custom avatars in commits --- README.md | 2 +- cmd/web.go | 6 +- gogs.go | 2 +- models/action.go | 46 ++++- models/update.go | 9 +- models/user.go | 2 +- modules/base/template.go | 313 -------------------------------- modules/base/tool.go | 18 ++ modules/template/template.go | 285 +++++++++++++++++++++++++++++ routers/repo/view.go | 3 +- templates/.VERSION | 2 +- templates/user/dashboard/dashboard.tmpl | 8 +- templates/user/dashboard/feeds.tmpl | 2 +- 13 files changed, 364 insertions(+), 334 deletions(-) delete mode 100644 modules/base/template.go create mode 100644 modules/template/template.go diff --git a/README.md b/README.md index df8fa611..a01b83cc 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra ![](public/img/gogs-large-resize.png) -##### Current version: 0.7.7 Beta +##### Current version: 0.7.8 Beta diff --git a/cmd/web.go b/cmd/web.go index 9ed9d567..e51b1bb9 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -7,7 +7,7 @@ package cmd import ( "crypto/tls" "fmt" - "html/template" + gotmpl "html/template" "io/ioutil" "net/http" "net/http/fcgi" @@ -35,11 +35,11 @@ import ( "github.com/gogits/gogs/modules/auth" "github.com/gogits/gogs/modules/auth/apiv1" "github.com/gogits/gogs/modules/avatar" - "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/bindata" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/middleware" "github.com/gogits/gogs/modules/setting" + "github.com/gogits/gogs/modules/template" "github.com/gogits/gogs/routers" "github.com/gogits/gogs/routers/admin" "github.com/gogits/gogs/routers/api/v1" @@ -124,7 +124,7 @@ func newMacaron() *macaron.Macaron { )) m.Use(macaron.Renderer(macaron.RenderOptions{ Directory: path.Join(setting.StaticRootPath, "templates"), - Funcs: []template.FuncMap{base.TemplateFuncs}, + Funcs: []gotmpl.FuncMap{template.Funcs}, IndentJSON: macaron.Env != macaron.PROD, })) diff --git a/gogs.go b/gogs.go index 67b1cc08..65571c06 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.7.7.1113 Beta" +const APP_VER = "0.7.8.1113 Beta" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/action.go b/models/action.go index 536476d7..bb15d4a3 100644 --- a/models/action.go +++ b/models/action.go @@ -208,8 +208,48 @@ func issueIndexTrimRight(c rune) bool { return !unicode.IsDigit(c) } +type PushCommit struct { + Sha1 string + Message string + AuthorEmail string + AuthorName string +} + +type PushCommits struct { + Len int + Commits []*PushCommit + CompareUrl string + + avatars map[string]string +} + +func NewPushCommits() *PushCommits { + return &PushCommits{ + avatars: make(map[string]string), + } +} + +// AvatarLink tries to match user in database with e-mail +// in order to show custom avatar, and falls back to general avatar link. +func (push *PushCommits) AvatarLink(email string) string { + _, ok := push.avatars[email] + if !ok { + u, err := GetUserByEmail(email) + if err != nil { + push.avatars[email] = base.AvatarLink(email) + if !IsErrUserNotExist(err) { + log.Error(4, "GetUserByEmail: %v", err) + } + } else { + push.avatars[email] = u.AvatarLink() + } + } + + return push.avatars[email] +} + // updateIssuesCommit checks if issues are manipulated by commit message. -func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string, commits []*base.PushCommit) error { +func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string, commits []*PushCommit) error { // Commits are appended in the reverse order. for i := len(commits) - 1; i >= 0; i-- { c := commits[i] @@ -343,7 +383,7 @@ func CommitRepoAction( repoID int64, repoUserName, repoName string, refFullName string, - commit *base.PushCommits, + commit *PushCommits, oldCommitID string, newCommitID string) error { u, err := GetUserByID(userID) @@ -369,7 +409,7 @@ func CommitRepoAction( // Check it's tag push or branch. if strings.HasPrefix(refFullName, "refs/tags/") { opType = PUSH_TAG - commit = &base.PushCommits{} + commit = &PushCommits{} } else { // if not the first commit, set the compareUrl if !strings.HasPrefix(oldCommitID, "0000000") { diff --git a/models/update.go b/models/update.go index 7992313a..14e56ce8 100644 --- a/models/update.go +++ b/models/update.go @@ -10,7 +10,6 @@ import ( "os/exec" "strings" - "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/git" "github.com/gogits/gogs/modules/log" ) @@ -100,7 +99,7 @@ func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName actEmail = cmt.Committer.Email } - commit := &base.PushCommits{} + commit := &PushCommits{} if err = CommitRepoAction(userID, user.Id, userName, actEmail, repo.ID, repoUserName, repoName, refName, commit, oldCommitID, newCommitID); err != nil { @@ -133,7 +132,7 @@ func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName } // Push commits. - commits := make([]*base.PushCommit, 0) + commits := make([]*PushCommit, 0) var actEmail string for e := l.Front(); e != nil; e = e.Next() { commit := e.Value.(*git.Commit) @@ -141,7 +140,7 @@ func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName actEmail = commit.Committer.Email } commits = append(commits, - &base.PushCommit{commit.ID.String(), + &PushCommit{commit.ID.String(), commit.Message(), commit.Author.Email, commit.Author.Name, @@ -149,7 +148,7 @@ func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName } if err = CommitRepoAction(userID, user.Id, userName, actEmail, - repo.ID, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits, ""}, oldCommitID, newCommitID); err != nil { + repo.ID, repoUserName, repoName, refName, &PushCommits{l.Len(), commits, "", nil}, oldCommitID, newCommitID); err != nil { return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) } return nil diff --git a/models/user.go b/models/user.go index 628a50f7..5aaf630f 100644 --- a/models/user.go +++ b/models/user.go @@ -991,7 +991,7 @@ func GetUserByEmail(email string) (*User, error) { return GetUserByID(emailAddress.UID) } - return nil, ErrUserNotExist{0, "email"} + return nil, ErrUserNotExist{0, email} } // SearchUserByName returns given number of users whose name contains keyword. diff --git a/modules/base/template.go b/modules/base/template.go deleted file mode 100644 index ff743e95..00000000 --- a/modules/base/template.go +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright 2014 The Gogs 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 base - -import ( - "container/list" - "encoding/json" - "fmt" - "html/template" - "runtime" - "strings" - "time" - - "golang.org/x/net/html/charset" - "golang.org/x/text/transform" - - "github.com/gogits/chardet" - "github.com/gogits/gogs/modules/setting" -) - -func Safe(raw string) template.HTML { - return template.HTML(raw) -} - -func Str2html(raw string) template.HTML { - return template.HTML(Sanitizer.Sanitize(raw)) -} - -func Range(l int) []int { - return make([]int, l) -} - -func List(l *list.List) chan interface{} { - e := l.Front() - c := make(chan interface{}) - go func() { - for e != nil { - c <- e.Value - e = e.Next() - } - close(c) - }() - return c -} - -func Sha1(str string) string { - return EncodeSha1(str) -} - -func ShortSha(sha1 string) string { - if len(sha1) == 40 { - return sha1[:10] - } - return sha1 -} - -func DetectEncoding(content []byte) (string, error) { - detector := chardet.NewTextDetector() - result, err := detector.DetectBest(content) - if result.Charset != "UTF-8" && len(setting.Repository.AnsiCharset) > 0 { - return setting.Repository.AnsiCharset, err - } - return result.Charset, err -} - -func ToUtf8WithErr(content []byte) (error, string) { - charsetLabel, err := DetectEncoding(content) - if err != nil { - return err, "" - } - - if charsetLabel == "UTF-8" { - return nil, string(content) - } - - encoding, _ := charset.Lookup(charsetLabel) - if encoding == nil { - return fmt.Errorf("unknown char decoder %s", charsetLabel), string(content) - } - - result, n, err := transform.String(encoding.NewDecoder(), string(content)) - - // If there is an error, we concatenate the nicely decoded part and the - // original left over. This way we won't loose data. - if err != nil { - result = result + string(content[n:]) - } - - return err, result -} - -func ToUtf8(content string) string { - _, res := ToUtf8WithErr([]byte(content)) - return res -} - -// Replaces all prefixes 'old' in 's' with 'new'. -func ReplaceLeft(s, old, new string) string { - old_len, new_len, i, n := len(old), len(new), 0, 0 - for ; i < len(s) && strings.HasPrefix(s[i:], old); n += 1 { - i += old_len - } - - // simple optimization - if n == 0 { - return s - } - - // allocating space for the new string - newLen := n*new_len + len(s[i:]) - replacement := make([]byte, newLen, newLen) - - j := 0 - for ; j < n*new_len; j += new_len { - copy(replacement[j:j+new_len], new) - } - - copy(replacement[j:], s[i:]) - return string(replacement) -} - -// RenderCommitMessage renders commit message with XSS-safe and special links. -func RenderCommitMessage(msg, urlPrefix string) template.HTML { - cleanMsg := template.HTMLEscapeString(msg) - fullMessage := string(RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix)) - msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n") - for i := range msgLines { - msgLines[i] = ReplaceLeft(msgLines[i], " ", " ") - } - - fullMessage = strings.Join(msgLines, "
") - return template.HTML(fullMessage) -} - -var TemplateFuncs template.FuncMap = map[string]interface{}{ - "GoVer": func() string { - return strings.Title(runtime.Version()) - }, - "AppName": func() string { - return setting.AppName - }, - "AppSubUrl": func() string { - return setting.AppSubUrl - }, - "AppVer": func() string { - return setting.AppVer - }, - "AppDomain": func() string { - return setting.Domain - }, - "DisableGravatar": func() bool { - return setting.DisableGravatar - }, - "LoadTimes": func(startTime time.Time) string { - return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms" - }, - "AvatarLink": AvatarLink, - "Safe": Safe, - "Str2html": Str2html, - "TimeSince": TimeSince, - "RawTimeSince": RawTimeSince, - "FileSize": FileSize, - "Subtract": Subtract, - "Add": func(a, b int) int { - return a + b - }, - "ActionIcon": ActionIcon, - "DateFmtLong": func(t time.Time) string { - return t.Format(time.RFC1123Z) - }, - "DateFmtShort": func(t time.Time) string { - return t.Format("Jan 02, 2006") - }, - "List": List, - "Mail2Domain": func(mail string) string { - if !strings.Contains(mail, "@") { - return "try.gogs.io" - } - - return strings.SplitN(mail, "@", 2)[1] - }, - "SubStr": func(str string, start, length int) string { - if len(str) == 0 { - return "" - } - end := start + length - if length == -1 { - end = len(str) - } - if len(str) < end { - return str - } - return str[start:end] - }, - "DiffTypeToStr": DiffTypeToStr, - "DiffLineTypeToStr": DiffLineTypeToStr, - "Sha1": Sha1, - "ShortSha": ShortSha, - "Md5": EncodeMd5, - "ActionContent2Commits": ActionContent2Commits, - "Oauth2Icon": Oauth2Icon, - "Oauth2Name": Oauth2Name, - "ToUtf8": ToUtf8, - "EscapePound": func(str string) string { - return strings.Replace(strings.Replace(str, "%", "%25", -1), "#", "%23", -1) - }, - "RenderCommitMessage": RenderCommitMessage, -} - -type Actioner interface { - GetOpType() int - GetActUserName() string - GetActEmail() string - GetRepoUserName() string - GetRepoName() string - GetRepoPath() string - GetRepoLink() string - GetBranch() string - GetContent() string - GetCreate() time.Time - GetIssueInfos() []string -} - -// ActionIcon accepts a int that represents action operation type -// and returns a icon class name. -func ActionIcon(opType int) string { - switch opType { - case 1, 8: // Create, transfer repository. - return "repo" - case 5, 9: // Commit repository. - return "git-commit" - case 6: // Create issue. - return "issue-opened" - case 10: // Comment issue. - return "comment" - default: - return "invalid type" - } -} - -type PushCommit struct { - Sha1 string - Message string - AuthorEmail string - AuthorName string -} - -type PushCommits struct { - Len int - Commits []*PushCommit - CompareUrl string -} - -func ActionContent2Commits(act Actioner) *PushCommits { - var push *PushCommits - if err := json.Unmarshal([]byte(act.GetContent()), &push); err != nil { - return nil - } - return push -} - -func DiffTypeToStr(diffType int) string { - diffTypes := map[int]string{ - 1: "add", 2: "modify", 3: "del", 4: "rename", - } - return diffTypes[diffType] -} - -func DiffLineTypeToStr(diffType int) string { - switch diffType { - case 2: - return "add" - case 3: - return "del" - case 4: - return "tag" - } - return "same" -} - -func Oauth2Icon(t int) string { - switch t { - case 1: - return "fa-github-square" - case 2: - return "fa-google-plus-square" - case 3: - return "fa-twitter-square" - case 4: - return "fa-qq" - case 5: - return "fa-weibo" - } - return "" -} - -func Oauth2Name(t int) string { - switch t { - case 1: - return "GitHub" - case 2: - return "Google+" - case 3: - return "Twitter" - case 4: - return "腾讯 QQ" - case 5: - return "Weibo" - } - return "" -} diff --git a/modules/base/tool.go b/modules/base/tool.go index b9a97c9c..78983b36 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -23,6 +23,8 @@ import ( "github.com/Unknwon/i18n" "github.com/microcosm-cc/bluemonday" + "github.com/gogits/chardet" + "github.com/gogits/gogs/modules/avatar" "github.com/gogits/gogs/modules/setting" ) @@ -43,6 +45,22 @@ func EncodeSha1(str string) string { return hex.EncodeToString(h.Sum(nil)) } +func ShortSha(sha1 string) string { + if len(sha1) == 40 { + return sha1[:10] + } + return sha1 +} + +func DetectEncoding(content []byte) (string, error) { + detector := chardet.NewTextDetector() + result, err := detector.DetectBest(content) + if result.Charset != "UTF-8" && len(setting.Repository.AnsiCharset) > 0 { + return setting.Repository.AnsiCharset, err + } + return result.Charset, err +} + func BasicAuthDecode(encoded string) (string, string, error) { s, err := base64.StdEncoding.DecodeString(encoded) if err != nil { diff --git a/modules/template/template.go b/modules/template/template.go new file mode 100644 index 00000000..d56b10d7 --- /dev/null +++ b/modules/template/template.go @@ -0,0 +1,285 @@ +// Copyright 2014 The Gogs 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 template + +import ( + "container/list" + "encoding/json" + "fmt" + "html/template" + "runtime" + "strings" + "time" + + "golang.org/x/net/html/charset" + "golang.org/x/text/transform" + + "github.com/gogits/gogs/models" + "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/setting" +) + +func Safe(raw string) template.HTML { + return template.HTML(raw) +} + +func Str2html(raw string) template.HTML { + return template.HTML(base.Sanitizer.Sanitize(raw)) +} + +func Range(l int) []int { + return make([]int, l) +} + +func List(l *list.List) chan interface{} { + e := l.Front() + c := make(chan interface{}) + go func() { + for e != nil { + c <- e.Value + e = e.Next() + } + close(c) + }() + return c +} + +func Sha1(str string) string { + return base.EncodeSha1(str) +} + +func ToUtf8WithErr(content []byte) (error, string) { + charsetLabel, err := base.DetectEncoding(content) + if err != nil { + return err, "" + } + + if charsetLabel == "UTF-8" { + return nil, string(content) + } + + encoding, _ := charset.Lookup(charsetLabel) + if encoding == nil { + return fmt.Errorf("unknown char decoder %s", charsetLabel), string(content) + } + + result, n, err := transform.String(encoding.NewDecoder(), string(content)) + + // If there is an error, we concatenate the nicely decoded part and the + // original left over. This way we won't loose data. + if err != nil { + result = result + string(content[n:]) + } + + return err, result +} + +func ToUtf8(content string) string { + _, res := ToUtf8WithErr([]byte(content)) + return res +} + +// Replaces all prefixes 'old' in 's' with 'new'. +func ReplaceLeft(s, old, new string) string { + old_len, new_len, i, n := len(old), len(new), 0, 0 + for ; i < len(s) && strings.HasPrefix(s[i:], old); n += 1 { + i += old_len + } + + // simple optimization + if n == 0 { + return s + } + + // allocating space for the new string + newLen := n*new_len + len(s[i:]) + replacement := make([]byte, newLen, newLen) + + j := 0 + for ; j < n*new_len; j += new_len { + copy(replacement[j:j+new_len], new) + } + + copy(replacement[j:], s[i:]) + return string(replacement) +} + +// RenderCommitMessage renders commit message with XSS-safe and special links. +func RenderCommitMessage(msg, urlPrefix string) template.HTML { + cleanMsg := template.HTMLEscapeString(msg) + fullMessage := string(base.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix)) + msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n") + for i := range msgLines { + msgLines[i] = ReplaceLeft(msgLines[i], " ", " ") + } + + fullMessage = strings.Join(msgLines, "
") + return template.HTML(fullMessage) +} + +var Funcs template.FuncMap = map[string]interface{}{ + "GoVer": func() string { + return strings.Title(runtime.Version()) + }, + "AppName": func() string { + return setting.AppName + }, + "AppSubUrl": func() string { + return setting.AppSubUrl + }, + "AppVer": func() string { + return setting.AppVer + }, + "AppDomain": func() string { + return setting.Domain + }, + "DisableGravatar": func() bool { + return setting.DisableGravatar + }, + "LoadTimes": func(startTime time.Time) string { + return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms" + }, + "AvatarLink": base.AvatarLink, + "Safe": Safe, + "Str2html": Str2html, + "TimeSince": base.TimeSince, + "RawTimeSince": base.RawTimeSince, + "FileSize": base.FileSize, + "Subtract": base.Subtract, + "Add": func(a, b int) int { + return a + b + }, + "ActionIcon": ActionIcon, + "DateFmtLong": func(t time.Time) string { + return t.Format(time.RFC1123Z) + }, + "DateFmtShort": func(t time.Time) string { + return t.Format("Jan 02, 2006") + }, + "List": List, + "Mail2Domain": func(mail string) string { + if !strings.Contains(mail, "@") { + return "try.gogs.io" + } + + return strings.SplitN(mail, "@", 2)[1] + }, + "SubStr": func(str string, start, length int) string { + if len(str) == 0 { + return "" + } + end := start + length + if length == -1 { + end = len(str) + } + if len(str) < end { + return str + } + return str[start:end] + }, + "DiffTypeToStr": DiffTypeToStr, + "DiffLineTypeToStr": DiffLineTypeToStr, + "Sha1": Sha1, + "ShortSha": base.ShortSha, + "Md5": base.EncodeMd5, + "ActionContent2Commits": ActionContent2Commits, + "Oauth2Icon": Oauth2Icon, + "Oauth2Name": Oauth2Name, + "ToUtf8": ToUtf8, + "EscapePound": func(str string) string { + return strings.Replace(strings.Replace(str, "%", "%25", -1), "#", "%23", -1) + }, + "RenderCommitMessage": RenderCommitMessage, +} + +type Actioner interface { + GetOpType() int + GetActUserName() string + GetActEmail() string + GetRepoUserName() string + GetRepoName() string + GetRepoPath() string + GetRepoLink() string + GetBranch() string + GetContent() string + GetCreate() time.Time + GetIssueInfos() []string +} + +// ActionIcon accepts a int that represents action operation type +// and returns a icon class name. +func ActionIcon(opType int) string { + switch opType { + case 1, 8: // Create, transfer repository. + return "repo" + case 5, 9: // Commit repository. + return "git-commit" + case 6: // Create issue. + return "issue-opened" + case 10: // Comment issue. + return "comment" + default: + return "invalid type" + } +} + +func ActionContent2Commits(act Actioner) *models.PushCommits { + push := models.NewPushCommits() + if err := json.Unmarshal([]byte(act.GetContent()), push); err != nil { + return nil + } + return push +} + +func DiffTypeToStr(diffType int) string { + diffTypes := map[int]string{ + 1: "add", 2: "modify", 3: "del", 4: "rename", + } + return diffTypes[diffType] +} + +func DiffLineTypeToStr(diffType int) string { + switch diffType { + case 2: + return "add" + case 3: + return "del" + case 4: + return "tag" + } + return "same" +} + +func Oauth2Icon(t int) string { + switch t { + case 1: + return "fa-github-square" + case 2: + return "fa-google-plus-square" + case 3: + return "fa-twitter-square" + case 4: + return "fa-qq" + case 5: + return "fa-weibo" + } + return "" +} + +func Oauth2Name(t int) string { + switch t { + case 1: + return "GitHub" + case 2: + return "Google+" + case 3: + return "Twitter" + case 4: + return "腾讯 QQ" + case 5: + return "Weibo" + } + return "" +} diff --git a/routers/repo/view.go b/routers/repo/view.go index 6a3e0cb3..1d9f1f3d 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -16,6 +16,7 @@ import ( "github.com/gogits/gogs/modules/git" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/middleware" + "github.com/gogits/gogs/modules/template" ) const ( @@ -105,7 +106,7 @@ func Home(ctx *middleware.Context) { if readmeExist { ctx.Data["FileContent"] = string(base.RenderMarkdown(buf, path.Dir(treeLink))) } else { - if err, content := base.ToUtf8WithErr(buf); err != nil { + if err, content := template.ToUtf8WithErr(buf); err != nil { if err != nil { log.Error(4, "Convert content encoding: %s", err) } diff --git a/templates/.VERSION b/templates/.VERSION index e6ef9167..0c08e60d 100644 --- a/templates/.VERSION +++ b/templates/.VERSION @@ -1 +1 @@ -0.7.7.1113 Beta \ No newline at end of file +0.7.8.1113 Beta \ No newline at end of file diff --git a/templates/user/dashboard/dashboard.tmpl b/templates/user/dashboard/dashboard.tmpl index d8791241..eed5b407 100644 --- a/templates/user/dashboard/dashboard.tmpl +++ b/templates/user/dashboard/dashboard.tmpl @@ -26,7 +26,7 @@ {{range .Repos}}
  • - + {{.Name}} {{.NumStars}} @@ -46,7 +46,7 @@ {{range .CollaborativeRepos}}
  • - + {{.Owner.Name}} / {{.Name}} {{.NumStars}} @@ -72,7 +72,7 @@ {{range .ContextUser.Orgs}}
  • - + {{.Name}} {{.NumRepos}} @@ -94,7 +94,7 @@ {{range .Mirrors}}
  • - + {{.Name}} {{.Interval}}H diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl index c814a283..70142f9a 100644 --- a/templates/user/dashboard/feeds.tmpl +++ b/templates/user/dashboard/feeds.tmpl @@ -39,7 +39,7 @@ {{ $repoLink := .GetRepoLink}} {{if $push.Commits}} {{range $push.Commits}} -
  • {{ShortSha .Sha1}} {{.Message}}
  • +
  • {{ShortSha .Sha1}} {{.Message}}
  • {{end}} {{end}} {{if $push.CompareUrl}}
  • {{$.i18n.Tr "action.compare_2_commits"}} »
  • {{end}} -- cgit v1.2.3