diff options
author | John Olheiser <john.olheiser@gmail.com> | 2020-09-11 09:48:39 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-11 10:48:39 -0400 |
commit | 26c4a049da178993e5ccddcb50e7edc70a6bde5d (patch) | |
tree | 494106117720ff3ad5f9e77a380c9397c3cfe10b /routers | |
parent | dd1a651b5895cfdb8a141a56aa824ed4d082c41a (diff) | |
download | gitea-26c4a049da178993e5ccddcb50e7edc70a6bde5d.tar.gz gitea-26c4a049da178993e5ccddcb50e7edc70a6bde5d.zip |
Issue templates directory (#11450)
* Issue templates
Signed-off-by: jolheiser <john.olheiser@gmail.com>
* Add some comments, appease the linter
Signed-off-by: jolheiser <john.olheiser@gmail.com>
* Add docs and re-use dir candidates
Signed-off-by: jolheiser <john.olheiser@gmail.com>
* Add default labels to issue templates
Signed-off-by: jolheiser <john.olheiser@gmail.com>
* Generate swagger
Signed-off-by: jolheiser <john.olheiser@gmail.com>
* Suggested changes
Signed-off-by: jolheiser <john.olheiser@gmail.com>
* Update issue.go
* Suggestions
Signed-off-by: jolheiser <john.olheiser@gmail.com>
* Extract metadata from legacy if possible
Signed-off-by: jolheiser <john.olheiser@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Diffstat (limited to 'routers')
-rw-r--r-- | routers/api/v1/api.go | 1 | ||||
-rw-r--r-- | routers/api/v1/repo/repo.go | 25 | ||||
-rw-r--r-- | routers/api/v1/swagger/issue.go | 7 | ||||
-rw-r--r-- | routers/repo/compare.go | 2 | ||||
-rw-r--r-- | routers/repo/issue.go | 70 | ||||
-rw-r--r-- | routers/repo/milestone.go | 1 | ||||
-rw-r--r-- | routers/routes/routes.go | 7 |
7 files changed, 101 insertions, 12 deletions
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 9e85625770..8b3a7545c6 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -866,6 +866,7 @@ func RegisterRoutes(m *macaron.Macaron) { Delete(reqToken(), repo.DeleteTopic) }, reqAdmin()) }, reqAnyRepoReader()) + m.Get("/issue_templates", context.ReferencesGitRepo(false), repo.GetIssueTemplates) m.Get("/languages", reqRepoReader(models.UnitTypeCode), repo.GetLanguages) }, repoAssignment()) }) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 5ebc7f251b..35062500f7 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -812,3 +812,28 @@ func Delete(ctx *context.APIContext) { log.Trace("Repository deleted: %s/%s", owner.Name, repo.Name) ctx.Status(http.StatusNoContent) } + +// GetIssueTemplates returns the issue templates for a repository +func GetIssueTemplates(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/issue_templates repository repoGetIssueTemplates + // --- + // summary: Get available issue templates for a repository + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/IssueTemplates" + + ctx.JSON(http.StatusOK, ctx.IssueTemplatesFromDefaultBranch()) +} diff --git a/routers/api/v1/swagger/issue.go b/routers/api/v1/swagger/issue.go index b12ea0096a..0f2f572020 100644 --- a/routers/api/v1/swagger/issue.go +++ b/routers/api/v1/swagger/issue.go @@ -85,6 +85,13 @@ type swaggerIssueDeadline struct { Body api.IssueDeadline `json:"body"` } +// IssueTemplates +// swagger:response IssueTemplates +type swaggerIssueTemplates struct { + // in:body + Body []api.IssueTemplate `json:"body"` +} + // StopWatch // swagger:response StopWatch type swaggerResponseStopWatch struct { diff --git a/routers/repo/compare.go b/routers/repo/compare.go index f8a18f0696..9329b5a1d2 100644 --- a/routers/repo/compare.go +++ b/routers/repo/compare.go @@ -577,7 +577,7 @@ func CompareDiff(ctx *context.Context) { ctx.Data["RequireTribute"] = true ctx.Data["RequireSimpleMDE"] = true ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes - setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates) + setTemplateIfExists(ctx, pullRequestTemplateKey, nil, pullRequestTemplateCandidates) renderAttachmentSettings(ctx) ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(models.UnitTypePullRequests) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 71c0488972..7c4f2cea9b 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -11,6 +11,7 @@ import ( "fmt" "io/ioutil" "net/http" + "path" "strconv" "strings" @@ -36,13 +37,15 @@ import ( const ( tplAttachment base.TplName = "repo/issue/view_content/attachments" - tplIssues base.TplName = "repo/issue/list" - tplIssueNew base.TplName = "repo/issue/new" - tplIssueView base.TplName = "repo/issue/view" + tplIssues base.TplName = "repo/issue/list" + tplIssueNew base.TplName = "repo/issue/new" + tplIssueChoose base.TplName = "repo/issue/choose" + tplIssueView base.TplName = "repo/issue/view" tplReactions base.TplName = "repo/issue/view_content/reactions" - issueTemplateKey = "IssueTemplate" + issueTemplateKey = "IssueTemplate" + issueTemplateTitleKey = "IssueTemplateTitle" ) var ( @@ -356,6 +359,7 @@ func Issues(ctx *context.Context) { } ctx.Data["Title"] = ctx.Tr("repo.issues") ctx.Data["PageIsIssueList"] = true + ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0 } issues(ctx, ctx.QueryInt64("milestone"), ctx.QueryInt64("project"), util.OptionalBoolOf(isPullList)) @@ -515,11 +519,41 @@ func getFileContentFromDefaultBranch(ctx *context.Context, filename string) (str return string(bytes), true } -func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles []string) { - for _, filename := range possibleFiles { - content, found := getFileContentFromDefaultBranch(ctx, filename) +func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleDirs []string, possibleFiles []string) { + templateCandidates := make([]string, 0, len(possibleFiles)) + if ctx.Query("template") != "" { + for _, dirName := range possibleDirs { + templateCandidates = append(templateCandidates, path.Join(dirName, ctx.Query("template"))) + } + } + templateCandidates = append(templateCandidates, possibleFiles...) // Append files to the end because they should be fallback + for _, filename := range templateCandidates { + templateContent, found := getFileContentFromDefaultBranch(ctx, filename) if found { - ctx.Data[ctxDataKey] = content + var meta api.IssueTemplate + templateBody, err := markdown.ExtractMetadata(templateContent, &meta) + if err != nil { + log.Debug("could not extract metadata from %s [%s]: %v", filename, ctx.Repo.Repository.FullName(), err) + ctx.Data[ctxDataKey] = templateContent + return + } + ctx.Data[issueTemplateTitleKey] = meta.Title + ctx.Data[ctxDataKey] = templateBody + labelIDs := make([]string, 0, len(meta.Labels)) + if repoLabels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID, "", models.ListOptions{}); err == nil { + for _, metaLabel := range meta.Labels { + for _, repoLabel := range repoLabels { + if strings.EqualFold(repoLabel.Name, metaLabel) { + repoLabel.IsChecked = true + labelIDs = append(labelIDs, fmt.Sprintf("%d", repoLabel.ID)) + break + } + } + } + ctx.Data["Labels"] = repoLabels + } + ctx.Data["HasSelectedLabel"] = len(labelIDs) > 0 + ctx.Data["label_ids"] = strings.Join(labelIDs, ",") return } } @@ -529,10 +563,13 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles func NewIssue(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.issues.new") ctx.Data["PageIsIssueList"] = true + ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0 ctx.Data["RequireHighlightJS"] = true ctx.Data["RequireSimpleMDE"] = true ctx.Data["RequireTribute"] = true ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes + title := ctx.Query("title") + ctx.Data["TitleQuery"] = title body := ctx.Query("body") ctx.Data["BodyQuery"] = body ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(models.UnitTypeProjects) @@ -562,10 +599,10 @@ func NewIssue(ctx *context.Context) { } - setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates) renderAttachmentSettings(ctx) RetrieveRepoMetas(ctx, ctx.Repo.Repository, false) + setTemplateIfExists(ctx, issueTemplateKey, context.IssueTemplateDirCandidates, IssueTemplateCandidates) if ctx.Written() { return } @@ -575,6 +612,19 @@ func NewIssue(ctx *context.Context) { ctx.HTML(200, tplIssueNew) } +// NewIssueChooseTemplate render creating issue from template page +func NewIssueChooseTemplate(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("repo.issues.new") + ctx.Data["PageIsIssueList"] = true + ctx.Data["milestone"] = ctx.QueryInt64("milestone") + + issueTemplates := ctx.IssueTemplatesFromDefaultBranch() + ctx.Data["NewIssueChooseTemplate"] = len(issueTemplates) > 0 + ctx.Data["IssueTemplates"] = issueTemplates + + ctx.HTML(200, tplIssueChoose) +} + // ValidateRepoMetas check and returns repository's meta informations func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull bool) ([]int64, []int64, int64, int64) { var ( @@ -676,6 +726,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull b func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) { ctx.Data["Title"] = ctx.Tr("repo.issues.new") ctx.Data["PageIsIssueList"] = true + ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0 ctx.Data["RequireHighlightJS"] = true ctx.Data["RequireSimpleMDE"] = true ctx.Data["ReadOnly"] = false @@ -814,6 +865,7 @@ func ViewIssue(ctx *context.Context) { return } ctx.Data["PageIsIssueList"] = true + ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0 } if issue.IsPull && !ctx.Repo.CanRead(models.UnitTypeIssues) { diff --git a/routers/repo/milestone.go b/routers/repo/milestone.go index f48c5de12e..96f5b4e5f0 100644 --- a/routers/repo/milestone.go +++ b/routers/repo/milestone.go @@ -264,6 +264,7 @@ func MilestoneIssuesAndPulls(ctx *context.Context) { ctx.Data["Milestone"] = milestone issues(ctx, milestoneID, 0, util.OptionalBoolNone) + ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0 ctx.Data["CanWriteIssues"] = ctx.Repo.CanWriteIssuesOrPulls(false) ctx.Data["CanWritePulls"] = ctx.Repo.CanWriteIssuesOrPulls(true) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 779e8614b3..247835c062 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -723,8 +723,11 @@ func RegisterRoutes(m *macaron.Macaron) { // Grouping for those endpoints that do require authentication m.Group("/:username/:reponame", func() { m.Group("/issues", func() { - m.Combo("/new").Get(context.RepoRef(), repo.NewIssue). - Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost) + m.Group("/new", func() { + m.Combo("").Get(context.RepoRef(), repo.NewIssue). + Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost) + m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate) + }) }, context.RepoMustNotBeArchived(), reqRepoIssueReader) // FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest. // So they can apply their own enable/disable logic on routers. |