* 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 variabletags/v1.21.12.1
@@ -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). | ||||
@@ -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"} | |||||
typeFiles := make([][]string, 3) | |||||
types := []string{"gitignore", "license", "readme", "label"} | |||||
typeFiles := make([][]string, 4) | |||||
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) | |||||
} | |||||
// __________ .__ | // __________ .__ | ||||
// \______ \ ____ | | ____ _____ ______ ____ | // \______ \ ____ | | ____ _____ ______ ____ | ||||
// | _// __ \| | _/ __ \\__ \ / ___// __ \ | // | _// __ \| | _/ __ \\__ \ / ___// __ \ | ||||
@@ -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}} | ||||