Load a set of predefined labels (#3459)
* Can use a predefined set of labels * Change UI * Fix HTML file indentation * Avoid reading file from other directory (security issue) * Apply a better fix * Remove not used variable * Merge upstream/develop * Do modifications * Raname * remove binding + rename variable
This commit is contained in:
parent
9f44c26789
commit
92fb30c526
8 changed files with 841 additions and 925 deletions
|
@ -477,6 +477,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
|
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
|
||||||
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
|
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
|
||||||
m.Post("/delete", repo.DeleteLabel)
|
m.Post("/delete", repo.DeleteLabel)
|
||||||
|
m.Post("/initialize", bindIgnErr(auth.InitializeLabelsForm{}), repo.InitializeLabels)
|
||||||
}, repo.MustEnableIssues, reqRepoWriter, context.RepoRef())
|
}, repo.MustEnableIssues, reqRepoWriter, context.RepoRef())
|
||||||
m.Group("/milestones", func() {
|
m.Group("/milestones", func() {
|
||||||
m.Combo("/new").Get(repo.NewMilestone).
|
m.Combo("/new").Get(repo.NewMilestone).
|
||||||
|
|
7
conf/label/Default
Normal file
7
conf/label/Default
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#ee0701 bug
|
||||||
|
#cccccc duplicate
|
||||||
|
#84b6eb enhancement
|
||||||
|
#128a0c help wanted
|
||||||
|
#e6e6e6 invalid
|
||||||
|
#cc317c question
|
||||||
|
#ffffff wontfix
|
|
@ -489,6 +489,10 @@ issues.create = Create Issue
|
||||||
issues.new_label = New Label
|
issues.new_label = New Label
|
||||||
issues.new_label_placeholder = Label name...
|
issues.new_label_placeholder = Label name...
|
||||||
issues.create_label = Create Label
|
issues.create_label = Create Label
|
||||||
|
issues.label_templates.title=Load a set of labels
|
||||||
|
issues.label_templates.info=There aren’t any labels. You can click on the "New Label" button above to create one or use a predefined set below.
|
||||||
|
issues.label_templates.helper=Select a label set
|
||||||
|
issues.label_templates.use=Use this label set
|
||||||
issues.open_tab = %d Open
|
issues.open_tab = %d Open
|
||||||
issues.close_tab = %d Closed
|
issues.close_tab = %d Closed
|
||||||
issues.filter_label = Label
|
issues.filter_label = Label
|
||||||
|
|
|
@ -54,7 +54,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Gitignores, Licenses, Readmes []string
|
Gitignores, Licenses, Readmes, LabelTemplates []string
|
||||||
|
|
||||||
// Maximum items per page in forks, watchers and stars of a repo
|
// Maximum items per page in forks, watchers and stars of a repo
|
||||||
ItemsPerPage = 40
|
ItemsPerPage = 40
|
||||||
|
@ -62,9 +62,8 @@ var (
|
||||||
|
|
||||||
func LoadRepoConfig() {
|
func LoadRepoConfig() {
|
||||||
// Load .gitignore and license files and readme templates.
|
// Load .gitignore and license files and readme templates.
|
||||||
// TODO: should we allow custom files overwrite default ones?
|
types := []string{"gitignore", "license", "readme", "label"}
|
||||||
types := []string{"gitignore", "license", "readme"}
|
typeFiles := make([][]string, 4)
|
||||||
typeFiles := make([][]string, 3)
|
|
||||||
for i, t := range types {
|
for i, t := range types {
|
||||||
files, err := bindata.AssetDir("conf/" + t)
|
files, err := bindata.AssetDir("conf/" + t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -89,9 +88,11 @@ func LoadRepoConfig() {
|
||||||
Gitignores = typeFiles[0]
|
Gitignores = typeFiles[0]
|
||||||
Licenses = typeFiles[1]
|
Licenses = typeFiles[1]
|
||||||
Readmes = typeFiles[2]
|
Readmes = typeFiles[2]
|
||||||
|
LabelTemplates = typeFiles[3]
|
||||||
sort.Strings(Gitignores)
|
sort.Strings(Gitignores)
|
||||||
sort.Strings(Licenses)
|
sort.Strings(Licenses)
|
||||||
sort.Strings(Readmes)
|
sort.Strings(Readmes)
|
||||||
|
sort.Strings(LabelTemplates)
|
||||||
|
|
||||||
// Filter out invalid names and promote preferred licenses.
|
// Filter out invalid names and promote preferred licenses.
|
||||||
sortedLicenses := make([]string, 0, len(Licenses))
|
sortedLicenses := make([]string, 0, len(Licenses))
|
||||||
|
|
|
@ -220,6 +220,16 @@ func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Label templates
|
||||||
|
|
||||||
|
type InitializeLabelsForm struct {
|
||||||
|
TemplateName string `binding:"Required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *InitializeLabelsForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||||
|
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||||
|
}
|
||||||
|
|
||||||
// __________ .__
|
// __________ .__
|
||||||
// \______ \ ____ | | ____ _____ ______ ____
|
// \______ \ ____ | | ____ _____ ______ ____
|
||||||
// | _// __ \| | _/ __ \\__ \ / ___// __ \
|
// | _// __ \| | _/ __ \\__ \ / ___// __ \
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -11,6 +11,8 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ import (
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/auth"
|
"github.com/gogits/gogs/modules/auth"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
"github.com/gogits/gogs/modules/bindata"
|
||||||
"github.com/gogits/gogs/modules/context"
|
"github.com/gogits/gogs/modules/context"
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
"github.com/gogits/gogs/modules/markdown"
|
"github.com/gogits/gogs/modules/markdown"
|
||||||
|
@ -938,9 +941,58 @@ func Labels(ctx *context.Context) {
|
||||||
ctx.Data["PageIsIssueList"] = true
|
ctx.Data["PageIsIssueList"] = true
|
||||||
ctx.Data["PageIsLabels"] = true
|
ctx.Data["PageIsLabels"] = true
|
||||||
ctx.Data["RequireMinicolors"] = true
|
ctx.Data["RequireMinicolors"] = true
|
||||||
|
ctx.Data["LabelTemplates"] = models.LabelTemplates
|
||||||
ctx.HTML(200, LABELS)
|
ctx.HTML(200, LABELS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getLabelTemplateFile(name string) ([]byte, error) {
|
||||||
|
relPath := path.Join("conf/label", strings.TrimLeft(name, "./"))
|
||||||
|
|
||||||
|
// Use custom file when available.
|
||||||
|
customPath := path.Join(setting.CustomPath, relPath)
|
||||||
|
if com.IsFile(customPath) {
|
||||||
|
return ioutil.ReadFile(customPath)
|
||||||
|
}
|
||||||
|
return bindata.Asset(relPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) {
|
||||||
|
if ctx.HasError() {
|
||||||
|
ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := getLabelTemplateFile(form.TemplateName)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r, _ := regexp.Compile("#([a-fA-F0-9]{6})")
|
||||||
|
for i, line := range strings.Split(string(data), "\n") {
|
||||||
|
if len(line) > 0 {
|
||||||
|
line_x := strings.SplitN(strings.Trim(line, " \t"), " ", 2)
|
||||||
|
if len(line_x) == 2 && len(line_x[1]) > 0 {
|
||||||
|
if r.MatchString(line_x[0]) {
|
||||||
|
l := &models.Label{
|
||||||
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
Name: line_x[1],
|
||||||
|
Color: line_x[0],
|
||||||
|
}
|
||||||
|
if err := models.NewLabel(l); err != nil {
|
||||||
|
ctx.Handle(500, "InitializeLabelsFromTemplate", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warn("Line %d on the label template file '%s': Bad HTML color code", i+1, form.TemplateName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warn("Line %d on the label template file '%s': Line is malformed", i+1, form.TemplateName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
|
}
|
||||||
|
|
||||||
func NewLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
func NewLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.labels")
|
ctx.Data["Title"] = ctx.Tr("repo.labels")
|
||||||
ctx.Data["PageIsLabels"] = true
|
ctx.Data["PageIsLabels"] = true
|
||||||
|
|
|
@ -33,8 +33,43 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<div class="ui black label">{{.i18n.Tr "repo.issues.label_count" .NumLabels}}</div>
|
<div class="ui black label">{{.i18n.Tr "repo.issues.label_count" .NumLabels}}</div>
|
||||||
|
{{if $.IsRepositoryWriter}}
|
||||||
|
{{if eq .NumLabels 0}}
|
||||||
|
<div class="ui centered grid">
|
||||||
|
<div class="twelve wide column eight wide computer column">
|
||||||
|
<div class="ui attached left aligned segment" style="margin-top:30px">
|
||||||
|
<h4 class="ui header">
|
||||||
|
{{.i18n.Tr "repo.issues.label_templates.title"}}
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://github.com/gogits/go-gogs-client/wiki/Repositories#litte-notes-on-label-template">
|
||||||
|
<span class="octicon octicon-question"></span>
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
<p>{{.i18n.Tr "repo.issues.label_templates.info"}}</p>
|
||||||
|
<br/>
|
||||||
|
<form class="ui form center" action="{{.Link}}/initialize" method="post">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui selection dropdown">
|
||||||
|
<input type="hidden" name="template_name" id="templatename" value="Default">
|
||||||
|
<div class="default text">{{.i18n.Tr "repo.issues.label_templates.helper"}}</div>
|
||||||
|
<div class="menu">
|
||||||
|
{{range .LabelTemplates}}
|
||||||
|
<div class="item" data-value="{{.}}">{{.}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="ui blue button">{{.i18n.Tr "repo.issues.label_templates.use"}}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<div class="label list">
|
<div class="label list">
|
||||||
{{range .Labels}}
|
{{range .Labels}}
|
||||||
|
|
Reference in a new issue