coverage.out
/modules/public/bindata.go
+/modules/templates/bindata.go
*.db
*.log
import (
"crypto/tls"
"fmt"
- "io/ioutil"
"net"
"net/http"
"net/http/fcgi"
"path"
"strings"
- "code.gitea.io/git"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/bindata"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/public"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/template"
+ "code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/admin"
apiv1 "code.gitea.io/gitea/routers/api/v1"
"github.com/go-macaron/i18n"
"github.com/go-macaron/session"
"github.com/go-macaron/toolbox"
- "github.com/go-xorm/xorm"
- version "github.com/mcuadros/go-version"
"github.com/urfave/cli"
- ini "gopkg.in/ini.v1"
macaron "gopkg.in/macaron.v1"
)
Expected string
}
-// checkVersion checks if binary matches the version of templates files.
-func checkVersion() {
- // Templates.
- data, err := ioutil.ReadFile(setting.StaticRootPath + "/templates/.VERSION")
- if err != nil {
- log.Fatal(4, "Fail to read 'templates/.VERSION': %v", err)
- }
- tplVer := string(data)
- if tplVer != setting.AppVer {
- if version.Compare(tplVer, setting.AppVer, ">") {
- log.Fatal(4, "Binary version is lower than template file version, did you forget to recompile Gogs?")
- } else {
- log.Fatal(4, "Binary version is higher than template file version, did you forget to update template files?")
- }
- }
-
- // Check dependency version.
- checkers := []VerChecker{
- {"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.5.5"},
- {"github.com/go-macaron/binding", binding.Version, "0.3.2"},
- {"github.com/go-macaron/cache", cache.Version, "0.1.2"},
- {"github.com/go-macaron/csrf", csrf.Version, "0.1.0"},
- {"github.com/go-macaron/i18n", i18n.Version, "0.3.0"},
- {"github.com/go-macaron/session", session.Version, "0.1.6"},
- {"github.com/go-macaron/toolbox", toolbox.Version, "0.1.0"},
- {"gopkg.in/ini.v1", ini.Version, "1.8.4"},
- {"gopkg.in/macaron.v1", macaron.Version, "1.1.7"},
- {"code.gitea.io/git", git.Version, "0.4.1"},
- }
- for _, c := range checkers {
- if !version.Compare(c.Version(), c.Expected, ">=") {
- log.Fatal(4, `Dependency outdated!
-Package '%s' current version (%s) is below requirement (%s),
-please use following command to update this package and recompile Gogs:
-go get -u %[1]s`, c.ImportPath, c.Version(), c.Expected)
- }
- }
-}
-
// newMacaron initializes Macaron instance.
func newMacaron() *macaron.Macaron {
m := macaron.New()
},
))
- funcMap := template.NewFuncMap()
- m.Use(macaron.Renderer(macaron.RenderOptions{
- Directory: path.Join(setting.StaticRootPath, "templates"),
- AppendDirectories: []string{path.Join(setting.CustomPath, "templates")},
- Funcs: funcMap,
- IndentJSON: macaron.Env != macaron.PROD,
- }))
- models.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"),
- path.Join(setting.CustomPath, "templates/mail"), funcMap)
+ m.Use(templates.Renderer())
+ models.InitMailRender(templates.Mailer())
localeNames, err := bindata.AssetDir("conf/locale")
if err != nil {
setting.CustomConf = ctx.String("config")
}
routers.GlobalInit()
- checkVersion()
m := newMacaron()
"code.gitea.io/git"
"code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/template/highlight"
"github.com/Unknwon/com"
"github.com/sergi/go-diff/diffmatchpatch"
"golang.org/x/net/html/charset"
package models
import (
+ "bytes"
"fmt"
"html/template"
"path"
- "gopkg.in/gomail.v2"
- "gopkg.in/macaron.v1"
-
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/mailer"
"code.gitea.io/gitea/modules/markdown"
"code.gitea.io/gitea/modules/setting"
+ "gopkg.in/gomail.v2"
+ "gopkg.in/macaron.v1"
)
const (
mailNotifyCollaborator base.TplName = "notify/collaborator"
)
-type mailRenderInterface interface {
- HTMLString(string, interface{}, ...macaron.HTMLOptions) (string, error)
-}
-
-var mailRender mailRenderInterface
+var templates *template.Template
// InitMailRender initializes the macaron mail renderer
-func InitMailRender(dir, appendDir string, funcMap []template.FuncMap) {
- opt := &macaron.RenderOptions{
- Directory: dir,
- AppendDirectories: []string{appendDir},
- Funcs: funcMap,
- Extensions: []string{".tmpl", ".html"},
- }
- ts := macaron.NewTemplateSet()
- ts.Set(macaron.DEFAULT_TPL_SET_NAME, opt)
-
- mailRender = &macaron.TplRender{
- TemplateSet: ts,
- Opt: opt,
- }
+func InitMailRender(tmpls *template.Template) {
+ templates = tmpls
}
// SendTestMail sends a test mail
"ResetPwdCodeLives": setting.Service.ResetPwdCodeLives / 60,
"Code": code,
}
- body, err := mailRender.HTMLString(string(tpl), data)
- if err != nil {
- log.Error(3, "HTMLString: %v", err)
+
+ var content bytes.Buffer
+
+ if err := templates.ExecuteTemplate(&content, string(tpl), data); err != nil {
+ log.Error(3, "Template: %v", err)
return
}
- msg := mailer.NewMessage([]string{u.Email}, subject, body)
+ msg := mailer.NewMessage([]string{u.Email}, subject, content.String())
msg.Info = fmt.Sprintf("UID: %d, %s", u.ID, info)
mailer.SendAsync(msg)
"Code": u.GenerateEmailActivateCode(email.Email),
"Email": email.Email,
}
- body, err := mailRender.HTMLString(string(mailAuthActivateEmail), data)
- if err != nil {
- log.Error(3, "HTMLString: %v", err)
+
+ var content bytes.Buffer
+
+ if err := templates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil {
+ log.Error(3, "Template: %v", err)
return
}
- msg := mailer.NewMessage([]string{email.Email}, c.Tr("mail.activate_email"), body)
+ msg := mailer.NewMessage([]string{email.Email}, c.Tr("mail.activate_email"), content.String())
msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID)
mailer.SendAsync(msg)
data := map[string]interface{}{
"Username": u.DisplayName(),
}
- body, err := mailRender.HTMLString(string(mailAuthRegisterNotify), data)
- if err != nil {
- log.Error(3, "HTMLString: %v", err)
+
+ var content bytes.Buffer
+
+ if err := templates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil {
+ log.Error(3, "Template: %v", err)
return
}
- msg := mailer.NewMessage([]string{u.Email}, c.Tr("mail.register_notify"), body)
+ msg := mailer.NewMessage([]string{u.Email}, c.Tr("mail.register_notify"), content.String())
msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID)
mailer.SendAsync(msg)
"RepoName": repoName,
"Link": repo.HTMLURL(),
}
- body, err := mailRender.HTMLString(string(mailNotifyCollaborator), data)
- if err != nil {
- log.Error(3, "HTMLString: %v", err)
+
+ var content bytes.Buffer
+
+ if err := templates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
+ log.Error(3, "Template: %v", err)
return
}
- msg := mailer.NewMessage([]string{u.Email}, subject, body)
+ msg := mailer.NewMessage([]string{u.Email}, subject, content.String())
msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID)
mailer.SendAsync(msg)
body := string(markdown.RenderSpecialLink([]byte(issue.Content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas()))
data := composeTplData(subject, body, issue.HTMLURL())
data["Doer"] = doer
- content, err := mailRender.HTMLString(string(tplName), data)
- if err != nil {
- log.Error(3, "HTMLString (%s): %v", tplName, err)
+
+ var content bytes.Buffer
+
+ if err := templates.ExecuteTemplate(&content, string(tplName), data); err != nil {
+ log.Error(3, "Template: %v", err)
}
- msg := mailer.NewMessageFrom(tos, fmt.Sprintf(`"%s" <%s>`, doer.DisplayName(), setting.MailService.FromEmail), subject, content)
+
+ msg := mailer.NewMessageFrom(tos, fmt.Sprintf(`"%s" <%s>`, doer.DisplayName(), setting.MailService.FromEmail), subject, content.String())
msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info)
return msg
}
--- /dev/null
+// Copyright 2015 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 highlight
+
+import (
+ "path"
+ "strings"
+
+ "code.gitea.io/gitea/modules/setting"
+)
+
+var (
+ // File name should ignore highlight.
+ ignoreFileNames = map[string]bool{
+ "license": true,
+ "copying": true,
+ }
+
+ // File names that are representing highlight classes.
+ highlightFileNames = map[string]bool{
+ "dockerfile": true,
+ "makefile": true,
+ }
+
+ // Extensions that are same as highlight classes.
+ highlightExts = map[string]bool{
+ ".arm": true,
+ ".as": true,
+ ".sh": true,
+ ".cs": true,
+ ".cpp": true,
+ ".c": true,
+ ".css": true,
+ ".cmake": true,
+ ".bat": true,
+ ".dart": true,
+ ".patch": true,
+ ".elixir": true,
+ ".erlang": true,
+ ".go": true,
+ ".html": true,
+ ".xml": true,
+ ".hs": true,
+ ".ini": true,
+ ".json": true,
+ ".java": true,
+ ".js": true,
+ ".less": true,
+ ".lua": true,
+ ".php": true,
+ ".py": true,
+ ".rb": true,
+ ".scss": true,
+ ".sql": true,
+ ".scala": true,
+ ".swift": true,
+ ".ts": true,
+ ".vb": true,
+ }
+
+ // Extensions that are not same as highlight classes.
+ highlightMapping = map[string]string{}
+)
+
+// NewContext loads highlight map
+func NewContext() {
+ keys := setting.Cfg.Section("highlight.mapping").Keys()
+ for i := range keys {
+ highlightMapping[keys[i].Name()] = keys[i].Value()
+ }
+}
+
+// FileNameToHighlightClass returns the best match for highlight class name
+// based on the rule of highlight.js.
+func FileNameToHighlightClass(fname string) string {
+ fname = strings.ToLower(fname)
+ if ignoreFileNames[fname] {
+ return "nohighlight"
+ }
+
+ if highlightFileNames[fname] {
+ return fname
+ }
+
+ ext := path.Ext(fname)
+ if highlightExts[ext] {
+ return ext[1:]
+ }
+
+ name, ok := highlightMapping[ext]
+ if ok {
+ return name
+ }
+
+ return ""
+}
//go:generate go-bindata -tags "bindata" -ignore "\\.go|\\.less" -pkg "public" -o "bindata.go" ../../public/...
//go:generate go fmt bindata.go
+//go:generate sed -i.bak s/..\/..\/public\/// bindata.go
+//go:generate rm -f bindata.go.bak
// Options represents the available options to configure the macaron handler.
type Options struct {
AssetDir: AssetDir,
AssetInfo: AssetInfo,
AssetNames: AssetNames,
- Prefix: "../../public",
+ Prefix: "",
}),
},
)
+++ /dev/null
-// Copyright 2015 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 highlight
-
-import (
- "path"
- "strings"
-
- "code.gitea.io/gitea/modules/setting"
-)
-
-var (
- // File name should ignore highlight.
- ignoreFileNames = map[string]bool{
- "license": true,
- "copying": true,
- }
-
- // File names that are representing highlight classes.
- highlightFileNames = map[string]bool{
- "dockerfile": true,
- "makefile": true,
- }
-
- // Extensions that are same as highlight classes.
- highlightExts = map[string]bool{
- ".arm": true,
- ".as": true,
- ".sh": true,
- ".cs": true,
- ".cpp": true,
- ".c": true,
- ".css": true,
- ".cmake": true,
- ".bat": true,
- ".dart": true,
- ".patch": true,
- ".elixir": true,
- ".erlang": true,
- ".go": true,
- ".html": true,
- ".xml": true,
- ".hs": true,
- ".ini": true,
- ".json": true,
- ".java": true,
- ".js": true,
- ".less": true,
- ".lua": true,
- ".php": true,
- ".py": true,
- ".rb": true,
- ".scss": true,
- ".sql": true,
- ".scala": true,
- ".swift": true,
- ".ts": true,
- ".vb": true,
- }
-
- // Extensions that are not same as highlight classes.
- highlightMapping = map[string]string{}
-)
-
-// NewContext loads highlight map
-func NewContext() {
- keys := setting.Cfg.Section("highlight.mapping").Keys()
- for i := range keys {
- highlightMapping[keys[i].Name()] = keys[i].Value()
- }
-}
-
-// FileNameToHighlightClass returns the best match for highlight class name
-// based on the rule of highlight.js.
-func FileNameToHighlightClass(fname string) string {
- fname = strings.ToLower(fname)
- if ignoreFileNames[fname] {
- return "nohighlight"
- }
-
- if highlightFileNames[fname] {
- return fname
- }
-
- ext := path.Ext(fname)
- if highlightExts[ext] {
- return ext[1:]
- }
-
- name, ok := highlightMapping[ext]
- if ok {
- return name
- }
-
- return ""
-}
+++ /dev/null
-// 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"
- "mime"
- "path/filepath"
- "runtime"
- "strings"
- "time"
-
- "golang.org/x/net/html/charset"
- "golang.org/x/text/transform"
- "gopkg.in/editorconfig/editorconfig-core-go.v1"
-
- "code.gitea.io/gitea/models"
- "code.gitea.io/gitea/modules/base"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/markdown"
- "code.gitea.io/gitea/modules/setting"
-)
-
-// NewFuncMap returns functions for injecting to templates
-func NewFuncMap() []template.FuncMap {
- return []template.FuncMap{map[string]interface{}{
- "GoVer": func() string {
- return strings.Title(runtime.Version())
- },
- "UseHTTPS": func() bool {
- return strings.HasPrefix(setting.AppURL, "https")
- },
- "AppName": func() string {
- return setting.AppName
- },
- "AppSubUrl": func() string {
- return setting.AppSubURL
- },
- "AppUrl": func() string {
- return setting.AppURL
- },
- "AppVer": func() string {
- return setting.AppVer
- },
- "AppDomain": func() string {
- return setting.Domain
- },
- "DisableGravatar": func() bool {
- return setting.DisableGravatar
- },
- "ShowFooterTemplateLoadTime": func() bool {
- return setting.ShowFooterTemplateLoadTime
- },
- "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,
- "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]
- },
- "EllipsisString": base.EllipsisString,
- "DiffTypeToStr": DiffTypeToStr,
- "DiffLineTypeToStr": DiffLineTypeToStr,
- "Sha1": Sha1,
- "ShortSha": base.ShortSha,
- "MD5": base.EncodeMD5,
- "ActionContent2Commits": ActionContent2Commits,
- "EscapePound": func(str string) string {
- return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str)
- },
- "RenderCommitMessage": RenderCommitMessage,
- "ThemeColorMetaTag": func() string {
- return setting.UI.ThemeColorMetaTag
- },
- "FilenameIsImage": func(filename string) bool {
- mimeType := mime.TypeByExtension(filepath.Ext(filename))
- return strings.HasPrefix(mimeType, "image/")
- },
- "TabSizeClass": func(ec *editorconfig.Editorconfig, filename string) string {
- if ec != nil {
- def := ec.GetDefinitionForFilename(filename)
- if def.TabWidth > 0 {
- return fmt.Sprintf("tab-size-%d", def.TabWidth)
- }
- }
- return "tab-size-8"
- },
- }}
-}
-
-// Safe render raw as HTML
-func Safe(raw string) template.HTML {
- return template.HTML(raw)
-}
-
-// Str2html render Markdown text to HTML
-func Str2html(raw string) template.HTML {
- return template.HTML(markdown.Sanitizer.Sanitize(raw))
-}
-
-// List traversings the list
-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
-}
-
-// Sha1 returns sha1 sum of string
-func Sha1(str string) string {
- return base.EncodeSha1(str)
-}
-
-// ToUTF8WithErr converts content to UTF8 encoding
-func ToUTF8WithErr(content []byte) (string, error) {
- charsetLabel, err := base.DetectEncoding(content)
- if err != nil {
- return "", err
- } else if charsetLabel == "UTF-8" {
- return string(content), nil
- }
-
- encoding, _ := charset.Lookup(charsetLabel)
- if encoding == nil {
- return string(content), fmt.Errorf("Unknown encoding: %s", charsetLabel)
- }
-
- // If there is an error, we concatenate the nicely decoded part and the
- // original left over. This way we won't loose data.
- result, n, err := transform.String(encoding.NewDecoder(), string(content))
- if err != nil {
- result = result + string(content[n:])
- }
-
- return result, err
-}
-
-// ToUTF8 converts content to UTF8 encoding and ignore error
-func ToUTF8(content string) string {
- res, _ := ToUTF8WithErr([]byte(content))
- return res
-}
-
-// ReplaceLeft replaces all prefixes 'old' in 's' with 'new'.
-func ReplaceLeft(s, old, new string) string {
- oldLen, newLen, i, n := len(old), len(new), 0, 0
- for ; i < len(s) && strings.HasPrefix(s[i:], old); n++ {
- i += oldLen
- }
-
- // simple optimization
- if n == 0 {
- return s
- }
-
- // allocating space for the new string
- curLen := n*newLen + len(s[i:])
- replacement := make([]byte, curLen, curLen)
-
- j := 0
- for ; j < n*newLen; j += newLen {
- copy(replacement[j:j+newLen], new)
- }
-
- copy(replacement[j:], s[i:])
- return string(replacement)
-}
-
-// RenderCommitMessage renders commit message with XSS-safe and special links.
-func RenderCommitMessage(full bool, msg, urlPrefix string, metas map[string]string) template.HTML {
- cleanMsg := template.HTMLEscapeString(msg)
- fullMessage := string(markdown.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix, metas))
- msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n")
- numLines := len(msgLines)
- if numLines == 0 {
- return template.HTML("")
- } else if !full {
- return template.HTML(msgLines[0])
- } else if numLines == 1 || (numLines >= 2 && len(msgLines[1]) == 0) {
- // First line is a header, standalone or followed by empty line
- header := fmt.Sprintf("<h3>%s</h3>", msgLines[0])
- if numLines >= 2 {
- fullMessage = header + fmt.Sprintf("\n<pre>%s</pre>", strings.Join(msgLines[2:], "\n"))
- } else {
- fullMessage = header
- }
- } else {
- // Non-standard git message, there is no header line
- fullMessage = fmt.Sprintf("<h4>%s</h4>", strings.Join(msgLines, "<br>"))
- }
- return template.HTML(fullMessage)
-}
-
-// Actioner describes an action
-type Actioner interface {
- GetOpType() int
- GetActUserName() 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 and transfer repository
- return "repo"
- case 5, 9: // Commit repository
- return "git-commit"
- case 6: // Create issue
- return "issue-opened"
- case 7: // New pull request
- return "git-pull-request"
- case 10: // Comment issue
- return "comment-discussion"
- case 11: // Merge pull request
- return "git-merge"
- case 12, 14: // Close issue or pull request
- return "issue-closed"
- case 13, 15: // Reopen issue or pull request
- return "issue-reopened"
- default:
- return "invalid type"
- }
-}
-
-// ActionContent2Commits converts action content to push commits
-func ActionContent2Commits(act Actioner) *models.PushCommits {
- push := models.NewPushCommits()
- if err := json.Unmarshal([]byte(act.GetContent()), push); err != nil {
- log.Error(4, "json.Unmarshal:\n%s\nERROR: %v", act.GetContent(), err)
- }
- return push
-}
-
-// DiffTypeToStr returns diff type name
-func DiffTypeToStr(diffType int) string {
- diffTypes := map[int]string{
- 1: "add", 2: "modify", 3: "del", 4: "rename",
- }
- return diffTypes[diffType]
-}
-
-// DiffLineTypeToStr returns diff line type name
-func DiffLineTypeToStr(diffType int) string {
- switch diffType {
- case 2:
- return "add"
- case 3:
- return "del"
- case 4:
- return "tag"
- }
- return "same"
-}
--- /dev/null
+// +build !bindata
+
+// Copyright 2016 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 templates
+
+import (
+ "html/template"
+ "io/ioutil"
+ "path"
+ "strings"
+
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "github.com/Unknwon/com"
+ "gopkg.in/macaron.v1"
+)
+
+var (
+ templates = template.New("")
+)
+
+// Renderer implements the macaron handler for serving the templates.
+func Renderer() macaron.Handler {
+ return macaron.Renderer(macaron.RenderOptions{
+ Funcs: NewFuncMap(),
+ Directory: path.Join(setting.StaticRootPath, "templates"),
+ AppendDirectories: []string{
+ path.Join(setting.CustomPath, "templates"),
+ },
+ })
+}
+
+// Mailer provides the templates required for sending notification mails.
+func Mailer() *template.Template {
+ for _, funcs := range NewFuncMap() {
+ templates.Funcs(funcs)
+ }
+
+ staticDir := path.Join(setting.StaticRootPath, "templates", "mail")
+
+ if com.IsDir(staticDir) {
+ files, err := com.StatDir(staticDir)
+
+ if err != nil {
+ log.Warn("Failed to read %s templates dir. %v", staticDir, err)
+ } else {
+ for _, filePath := range files {
+ if !strings.HasSuffix(filePath, ".tmpl") {
+ continue
+ }
+
+ content, err := ioutil.ReadFile(path.Join(staticDir, filePath))
+
+ if err != nil {
+ log.Warn("Failed to read static %s template. %v", filePath, err)
+ continue
+ }
+
+ templates.New(
+ strings.TrimSuffix(
+ filePath,
+ ".tmpl",
+ ),
+ ).Parse(string(content))
+ }
+ }
+ }
+
+ customDir := path.Join(setting.CustomPath, "templates", "mail")
+
+ if com.IsDir(customDir) {
+ files, err := com.StatDir(customDir)
+
+ if err != nil {
+ log.Warn("Failed to read %s templates dir. %v", customDir, err)
+ } else {
+ for _, filePath := range files {
+ if !strings.HasSuffix(filePath, ".tmpl") {
+ continue
+ }
+
+ content, err := ioutil.ReadFile(path.Join(customDir, filePath))
+
+ if err != nil {
+ log.Warn("Failed to read custom %s template. %v", filePath, err)
+ continue
+ }
+
+ templates.New(
+ strings.TrimSuffix(
+ filePath,
+ ".tmpl",
+ ),
+ ).Parse(string(content))
+ }
+ }
+ }
+
+ return templates
+}
--- /dev/null
+// 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 templates
+
+import (
+ "container/list"
+ "encoding/json"
+ "fmt"
+ "html/template"
+ "mime"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "time"
+
+ "golang.org/x/net/html/charset"
+ "golang.org/x/text/transform"
+ "gopkg.in/editorconfig/editorconfig-core-go.v1"
+
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/markdown"
+ "code.gitea.io/gitea/modules/setting"
+)
+
+// NewFuncMap returns functions for injecting to templates
+func NewFuncMap() []template.FuncMap {
+ return []template.FuncMap{map[string]interface{}{
+ "GoVer": func() string {
+ return strings.Title(runtime.Version())
+ },
+ "UseHTTPS": func() bool {
+ return strings.HasPrefix(setting.AppURL, "https")
+ },
+ "AppName": func() string {
+ return setting.AppName
+ },
+ "AppSubUrl": func() string {
+ return setting.AppSubURL
+ },
+ "AppUrl": func() string {
+ return setting.AppURL
+ },
+ "AppVer": func() string {
+ return setting.AppVer
+ },
+ "AppDomain": func() string {
+ return setting.Domain
+ },
+ "DisableGravatar": func() bool {
+ return setting.DisableGravatar
+ },
+ "ShowFooterTemplateLoadTime": func() bool {
+ return setting.ShowFooterTemplateLoadTime
+ },
+ "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,
+ "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]
+ },
+ "EllipsisString": base.EllipsisString,
+ "DiffTypeToStr": DiffTypeToStr,
+ "DiffLineTypeToStr": DiffLineTypeToStr,
+ "Sha1": Sha1,
+ "ShortSha": base.ShortSha,
+ "MD5": base.EncodeMD5,
+ "ActionContent2Commits": ActionContent2Commits,
+ "EscapePound": func(str string) string {
+ return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str)
+ },
+ "RenderCommitMessage": RenderCommitMessage,
+ "ThemeColorMetaTag": func() string {
+ return setting.UI.ThemeColorMetaTag
+ },
+ "FilenameIsImage": func(filename string) bool {
+ mimeType := mime.TypeByExtension(filepath.Ext(filename))
+ return strings.HasPrefix(mimeType, "image/")
+ },
+ "TabSizeClass": func(ec *editorconfig.Editorconfig, filename string) string {
+ if ec != nil {
+ def := ec.GetDefinitionForFilename(filename)
+ if def.TabWidth > 0 {
+ return fmt.Sprintf("tab-size-%d", def.TabWidth)
+ }
+ }
+ return "tab-size-8"
+ },
+ }}
+}
+
+// Safe render raw as HTML
+func Safe(raw string) template.HTML {
+ return template.HTML(raw)
+}
+
+// Str2html render Markdown text to HTML
+func Str2html(raw string) template.HTML {
+ return template.HTML(markdown.Sanitizer.Sanitize(raw))
+}
+
+// List traversings the list
+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
+}
+
+// Sha1 returns sha1 sum of string
+func Sha1(str string) string {
+ return base.EncodeSha1(str)
+}
+
+// ToUTF8WithErr converts content to UTF8 encoding
+func ToUTF8WithErr(content []byte) (string, error) {
+ charsetLabel, err := base.DetectEncoding(content)
+ if err != nil {
+ return "", err
+ } else if charsetLabel == "UTF-8" {
+ return string(content), nil
+ }
+
+ encoding, _ := charset.Lookup(charsetLabel)
+ if encoding == nil {
+ return string(content), fmt.Errorf("Unknown encoding: %s", charsetLabel)
+ }
+
+ // If there is an error, we concatenate the nicely decoded part and the
+ // original left over. This way we won't loose data.
+ result, n, err := transform.String(encoding.NewDecoder(), string(content))
+ if err != nil {
+ result = result + string(content[n:])
+ }
+
+ return result, err
+}
+
+// ToUTF8 converts content to UTF8 encoding and ignore error
+func ToUTF8(content string) string {
+ res, _ := ToUTF8WithErr([]byte(content))
+ return res
+}
+
+// ReplaceLeft replaces all prefixes 'old' in 's' with 'new'.
+func ReplaceLeft(s, old, new string) string {
+ oldLen, newLen, i, n := len(old), len(new), 0, 0
+ for ; i < len(s) && strings.HasPrefix(s[i:], old); n++ {
+ i += oldLen
+ }
+
+ // simple optimization
+ if n == 0 {
+ return s
+ }
+
+ // allocating space for the new string
+ curLen := n*newLen + len(s[i:])
+ replacement := make([]byte, curLen, curLen)
+
+ j := 0
+ for ; j < n*newLen; j += newLen {
+ copy(replacement[j:j+newLen], new)
+ }
+
+ copy(replacement[j:], s[i:])
+ return string(replacement)
+}
+
+// RenderCommitMessage renders commit message with XSS-safe and special links.
+func RenderCommitMessage(full bool, msg, urlPrefix string, metas map[string]string) template.HTML {
+ cleanMsg := template.HTMLEscapeString(msg)
+ fullMessage := string(markdown.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix, metas))
+ msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n")
+ numLines := len(msgLines)
+ if numLines == 0 {
+ return template.HTML("")
+ } else if !full {
+ return template.HTML(msgLines[0])
+ } else if numLines == 1 || (numLines >= 2 && len(msgLines[1]) == 0) {
+ // First line is a header, standalone or followed by empty line
+ header := fmt.Sprintf("<h3>%s</h3>", msgLines[0])
+ if numLines >= 2 {
+ fullMessage = header + fmt.Sprintf("\n<pre>%s</pre>", strings.Join(msgLines[2:], "\n"))
+ } else {
+ fullMessage = header
+ }
+ } else {
+ // Non-standard git message, there is no header line
+ fullMessage = fmt.Sprintf("<h4>%s</h4>", strings.Join(msgLines, "<br>"))
+ }
+ return template.HTML(fullMessage)
+}
+
+// Actioner describes an action
+type Actioner interface {
+ GetOpType() int
+ GetActUserName() 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 and transfer repository
+ return "repo"
+ case 5, 9: // Commit repository
+ return "git-commit"
+ case 6: // Create issue
+ return "issue-opened"
+ case 7: // New pull request
+ return "git-pull-request"
+ case 10: // Comment issue
+ return "comment-discussion"
+ case 11: // Merge pull request
+ return "git-merge"
+ case 12, 14: // Close issue or pull request
+ return "issue-closed"
+ case 13, 15: // Reopen issue or pull request
+ return "issue-reopened"
+ default:
+ return "invalid type"
+ }
+}
+
+// ActionContent2Commits converts action content to push commits
+func ActionContent2Commits(act Actioner) *models.PushCommits {
+ push := models.NewPushCommits()
+ if err := json.Unmarshal([]byte(act.GetContent()), push); err != nil {
+ log.Error(4, "json.Unmarshal:\n%s\nERROR: %v", act.GetContent(), err)
+ }
+ return push
+}
+
+// DiffTypeToStr returns diff type name
+func DiffTypeToStr(diffType int) string {
+ diffTypes := map[int]string{
+ 1: "add", 2: "modify", 3: "del", 4: "rename",
+ }
+ return diffTypes[diffType]
+}
+
+// DiffLineTypeToStr returns diff line type name
+func DiffLineTypeToStr(diffType int) string {
+ switch diffType {
+ case 2:
+ return "add"
+ case 3:
+ return "del"
+ case 4:
+ return "tag"
+ }
+ return "same"
+}
--- /dev/null
+// +build bindata
+
+// Copyright 2016 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 templates
+
+import (
+ "html/template"
+ "io/ioutil"
+ "path"
+ "strings"
+
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "github.com/Unknwon/com"
+ "github.com/go-macaron/bindata"
+ "gopkg.in/macaron.v1"
+)
+
+var (
+ templates = template.New("")
+)
+
+// Renderer implements the macaron handler for serving the templates.
+func Renderer() macaron.Handler {
+ return macaron.Renderer(macaron.RenderOptions{
+ Funcs: NewFuncMap(),
+ AppendDirectories: []string{
+ path.Join(setting.CustomPath, "templates"),
+ },
+ TemplateFileSystem: bindata.Templates(
+ bindata.Options{
+ Asset: Asset,
+ AssetDir: AssetDir,
+ AssetInfo: AssetInfo,
+ AssetNames: AssetNames,
+ Prefix: "",
+ },
+ ),
+ })
+}
+
+// Mailer provides the templates required for sending notification mails.
+func Mailer() *template.Template {
+ for _, funcs := range NewFuncMap() {
+ templates.Funcs(funcs)
+ }
+
+ for _, assetPath := range AssetNames() {
+ if !strings.HasPrefix(assetPath, "mail/") {
+ continue
+ }
+
+ if !strings.HasSuffix(assetPath, ".tmpl") {
+ continue
+ }
+
+ content, err := Asset(assetPath)
+
+ if err != nil {
+ log.Warn("Failed to read embedded %s template. %v", assetPath, err)
+ continue
+ }
+
+ templates.New(
+ strings.TrimPrefix(
+ strings.TrimSuffix(
+ assetPath,
+ ".tmpl",
+ ),
+ "mail/",
+ ),
+ ).Parse(string(content))
+ }
+
+ customDir := path.Join(setting.CustomPath, "templates", "mail")
+
+ if com.IsDir(customDir) {
+ files, err := com.StatDir(customDir)
+
+ if err != nil {
+ log.Warn("Failed to read %s templates dir. %v", customDir, err)
+ } else {
+ for _, filePath := range files {
+ if !strings.HasSuffix(filePath, ".tmpl") {
+ continue
+ }
+
+ content, err := ioutil.ReadFile(path.Join(customDir, filePath))
+
+ if err != nil {
+ log.Warn("Failed to read custom %s template. %v", filePath, err)
+ continue
+ }
+
+ templates.New(
+ strings.TrimSuffix(
+ filePath,
+ ".tmpl",
+ ),
+ ).Parse(string(content))
+ }
+ }
+ }
+
+ return templates
+}
--- /dev/null
+// Copyright 2016 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 templates
+
+//go:generate go-bindata -tags "bindata" -ignore "\\.go" -pkg "templates" -o "bindata.go" ../../templates/...
+//go:generate go fmt bindata.go
+//go:generate sed -i.bak s/..\/..\/templates\/// bindata.go
+//go:generate rm -f bindata.go.bak
"code.gitea.io/git"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cron"
+ "code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/mailer"
"code.gitea.io/gitea/modules/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/ssh"
- "code.gitea.io/gitea/modules/template/highlight"
macaron "gopkg.in/macaron.v1"
)
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/template"
+ "code.gitea.io/gitea/modules/templates"
)
const (
d, _ := ioutil.ReadAll(dataRc)
buf = append(buf, d...)
- if content, err := template.ToUTF8WithErr(buf); err != nil {
+ if content, err := templates.ToUTF8WithErr(buf); err != nil {
if err != nil {
log.Error(4, "ToUTF8WithErr: %v", err)
}
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markdown"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/template"
- "code.gitea.io/gitea/modules/template/highlight"
+ "code.gitea.io/gitea/modules/templates"
"github.com/Unknwon/paginater"
)
} else {
// Building code view blocks with line number on server side.
var fileContent string
- if content, err := template.ToUTF8WithErr(buf); err != nil {
+ if content, err := templates.ToUTF8WithErr(buf); err != nil {
if err != nil {
log.Error(4, "ToUTF8WithErr: %s", err)
}
+++ /dev/null
-0.9.99.0915
\ No newline at end of file