|
|
|
@ -27,23 +27,25 @@ import ( |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
ISSUES base.TplName = "repo/issue/list" |
|
|
|
|
ISSUE_NEW base.TplName = "repo/issue/new" |
|
|
|
|
ISSUE_VIEW base.TplName = "repo/issue/view" |
|
|
|
|
tplIssues base.TplName = "repo/issue/list" |
|
|
|
|
tplIssueNew base.TplName = "repo/issue/new" |
|
|
|
|
tplIssueView base.TplName = "repo/issue/view" |
|
|
|
|
|
|
|
|
|
LABELS base.TplName = "repo/issue/labels" |
|
|
|
|
tplLabels base.TplName = "repo/issue/labels" |
|
|
|
|
|
|
|
|
|
MILESTONE base.TplName = "repo/issue/milestones" |
|
|
|
|
MILESTONE_NEW base.TplName = "repo/issue/milestone_new" |
|
|
|
|
MILESTONE_EDIT base.TplName = "repo/issue/milestone_edit" |
|
|
|
|
tplMilestone base.TplName = "repo/issue/milestones" |
|
|
|
|
tplMilestoneNew base.TplName = "repo/issue/milestone_new" |
|
|
|
|
tplMilestoneEdit base.TplName = "repo/issue/milestone_edit" |
|
|
|
|
|
|
|
|
|
ISSUE_TEMPLATE_KEY = "IssueTemplate" |
|
|
|
|
issueTemplateKey = "IssueTemplate" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
// ErrFileTypeForbidden not allowed file type error
|
|
|
|
|
ErrFileTypeForbidden = errors.New("File type is not allowed") |
|
|
|
|
ErrTooManyFiles = errors.New("Maximum number of files to upload exceeded") |
|
|
|
|
|
|
|
|
|
// ErrTooManyFiles upload too many files
|
|
|
|
|
ErrTooManyFiles = errors.New("Maximum number of files to upload exceeded") |
|
|
|
|
// IssueTemplateCandidates issue templates
|
|
|
|
|
IssueTemplateCandidates = []string{ |
|
|
|
|
"ISSUE_TEMPLATE.md", |
|
|
|
|
".gogs/ISSUE_TEMPLATE.md", |
|
|
|
@ -51,6 +53,7 @@ var ( |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// MustEnableIssues check if repository enable internal issues
|
|
|
|
|
func MustEnableIssues(ctx *context.Context) { |
|
|
|
|
if !ctx.Repo.Repository.EnableIssues { |
|
|
|
|
ctx.Handle(404, "MustEnableIssues", nil) |
|
|
|
@ -63,6 +66,7 @@ func MustEnableIssues(ctx *context.Context) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MustAllowPulls check if repository enable pull requests
|
|
|
|
|
func MustAllowPulls(ctx *context.Context) { |
|
|
|
|
if !ctx.Repo.Repository.AllowsPulls() { |
|
|
|
|
ctx.Handle(404, "MustAllowPulls", nil) |
|
|
|
@ -76,6 +80,7 @@ func MustAllowPulls(ctx *context.Context) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// RetrieveLabels find all the labels of a repository
|
|
|
|
|
func RetrieveLabels(ctx *context.Context) { |
|
|
|
|
labels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID) |
|
|
|
|
if err != nil { |
|
|
|
@ -89,6 +94,7 @@ func RetrieveLabels(ctx *context.Context) { |
|
|
|
|
ctx.Data["NumLabels"] = len(labels) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Issues render issues page
|
|
|
|
|
func Issues(ctx *context.Context) { |
|
|
|
|
isPullList := ctx.Params(":type") == "pulls" |
|
|
|
|
if isPullList { |
|
|
|
@ -244,7 +250,7 @@ func Issues(ctx *context.Context) { |
|
|
|
|
ctx.Data["State"] = "open" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ctx.HTML(200, ISSUES) |
|
|
|
|
ctx.HTML(200, tplIssues) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func renderAttachmentSettings(ctx *context.Context) { |
|
|
|
@ -255,6 +261,7 @@ func renderAttachmentSettings(ctx *context.Context) { |
|
|
|
|
ctx.Data["AttachmentMaxFiles"] = setting.AttachmentMaxFiles |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// RetrieveRepoMilestonesAndAssignees find all the milestones and assignees of a repository
|
|
|
|
|
func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repository) { |
|
|
|
|
var err error |
|
|
|
|
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false) |
|
|
|
@ -275,6 +282,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repos |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// RetrieveRepoMetas find all the meta information of a repository
|
|
|
|
|
func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository) []*models.Label { |
|
|
|
|
if !ctx.Repo.IsWriter() { |
|
|
|
|
return nil |
|
|
|
@ -332,12 +340,13 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewIssue render createing issue page
|
|
|
|
|
func NewIssue(ctx *context.Context) { |
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.issues.new") |
|
|
|
|
ctx.Data["PageIsIssueList"] = true |
|
|
|
|
ctx.Data["RequireHighlightJS"] = true |
|
|
|
|
ctx.Data["RequireSimpleMDE"] = true |
|
|
|
|
setTemplateIfExists(ctx, ISSUE_TEMPLATE_KEY, IssueTemplateCandidates) |
|
|
|
|
setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates) |
|
|
|
|
renderAttachmentSettings(ctx) |
|
|
|
|
|
|
|
|
|
RetrieveRepoMetas(ctx, ctx.Repo.Repository) |
|
|
|
@ -345,9 +354,10 @@ func NewIssue(ctx *context.Context) { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ctx.HTML(200, ISSUE_NEW) |
|
|
|
|
ctx.HTML(200, tplIssueNew) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ValidateRepoMetas check and returns repository's meta informations
|
|
|
|
|
func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64, int64, int64) { |
|
|
|
|
var ( |
|
|
|
|
repo = ctx.Repo.Repository |
|
|
|
@ -402,6 +412,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64 |
|
|
|
|
return labelIDs, milestoneID, assigneeID |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewIssuePost response for creating new issue
|
|
|
|
|
func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) { |
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.issues.new") |
|
|
|
|
ctx.Data["PageIsIssueList"] = true |
|
|
|
@ -424,7 +435,7 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ctx.HasError() { |
|
|
|
|
ctx.HTML(200, ISSUE_NEW) |
|
|
|
|
ctx.HTML(200, tplIssueNew) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -446,6 +457,7 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) { |
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UploadIssueAttachment response for uploading issue's attachment
|
|
|
|
|
func UploadIssueAttachment(ctx *context.Context) { |
|
|
|
|
if !setting.AttachmentEnabled { |
|
|
|
|
ctx.Error(404, "attachment is not enabled") |
|
|
|
@ -493,6 +505,7 @@ func UploadIssueAttachment(ctx *context.Context) { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ViewIssue render issue view page
|
|
|
|
|
func ViewIssue(ctx *context.Context) { |
|
|
|
|
ctx.Data["RequireHighlightJS"] = true |
|
|
|
|
ctx.Data["RequireDropzone"] = true |
|
|
|
@ -639,7 +652,7 @@ func ViewIssue(ctx *context.Context) { |
|
|
|
|
ctx.Data["Issue"] = issue |
|
|
|
|
ctx.Data["IsIssueOwner"] = ctx.Repo.IsWriter() || (ctx.IsSigned && issue.IsPoster(ctx.User.ID)) |
|
|
|
|
ctx.Data["SignInLink"] = setting.AppSubUrl + "/user/login?redirect_to=" + ctx.Data["Link"].(string) |
|
|
|
|
ctx.HTML(200, ISSUE_VIEW) |
|
|
|
|
ctx.HTML(200, tplIssueView) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func getActionIssue(ctx *context.Context) *models.Issue { |
|
|
|
@ -655,6 +668,7 @@ func getActionIssue(ctx *context.Context) *models.Issue { |
|
|
|
|
return issue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UpdateIssueTitle change issue's title
|
|
|
|
|
func UpdateIssueTitle(ctx *context.Context) { |
|
|
|
|
issue := getActionIssue(ctx) |
|
|
|
|
if ctx.Written() { |
|
|
|
@ -682,6 +696,7 @@ func UpdateIssueTitle(ctx *context.Context) { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UpdateIssueContent change issue's content
|
|
|
|
|
func UpdateIssueContent(ctx *context.Context) { |
|
|
|
|
issue := getActionIssue(ctx) |
|
|
|
|
if ctx.Written() { |
|
|
|
@ -704,6 +719,7 @@ func UpdateIssueContent(ctx *context.Context) { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UpdateIssueLabel change issue's labels
|
|
|
|
|
func UpdateIssueLabel(ctx *context.Context) { |
|
|
|
|
issue := getActionIssue(ctx) |
|
|
|
|
if ctx.Written() { |
|
|
|
@ -745,6 +761,7 @@ func UpdateIssueLabel(ctx *context.Context) { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UpdateIssueMilestone change issue's milestone
|
|
|
|
|
func UpdateIssueMilestone(ctx *context.Context) { |
|
|
|
|
issue := getActionIssue(ctx) |
|
|
|
|
if ctx.Written() { |
|
|
|
@ -772,6 +789,7 @@ func UpdateIssueMilestone(ctx *context.Context) { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UpdateIssueAssignee change issue's assignee
|
|
|
|
|
func UpdateIssueAssignee(ctx *context.Context) { |
|
|
|
|
issue := getActionIssue(ctx) |
|
|
|
|
if ctx.Written() { |
|
|
|
@ -796,6 +814,7 @@ func UpdateIssueAssignee(ctx *context.Context) { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewComment create a comment for issue
|
|
|
|
|
func NewComment(ctx *context.Context, form auth.CreateCommentForm) { |
|
|
|
|
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) |
|
|
|
|
if err != nil { |
|
|
|
@ -882,6 +901,7 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) { |
|
|
|
|
log.Trace("Comment created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UpdateCommentContent change comment of issue's content
|
|
|
|
|
func UpdateCommentContent(ctx *context.Context) { |
|
|
|
|
comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) |
|
|
|
|
if err != nil { |
|
|
|
@ -914,6 +934,7 @@ func UpdateCommentContent(ctx *context.Context) { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// DeleteComment delete comment of issue
|
|
|
|
|
func DeleteComment(ctx *context.Context) { |
|
|
|
|
comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) |
|
|
|
|
if err != nil { |
|
|
|
@ -937,15 +958,17 @@ func DeleteComment(ctx *context.Context) { |
|
|
|
|
ctx.Status(200) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Labels render issue's labels page
|
|
|
|
|
func Labels(ctx *context.Context) { |
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.labels") |
|
|
|
|
ctx.Data["PageIsIssueList"] = true |
|
|
|
|
ctx.Data["PageIsLabels"] = true |
|
|
|
|
ctx.Data["RequireMinicolors"] = true |
|
|
|
|
ctx.Data["LabelTemplates"] = models.LabelTemplates |
|
|
|
|
ctx.HTML(200, LABELS) |
|
|
|
|
ctx.HTML(200, tplLabels) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// InitializeLabels init labels for a repository
|
|
|
|
|
func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) { |
|
|
|
|
if ctx.HasError() { |
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels") |
|
|
|
@ -973,6 +996,7 @@ func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) { |
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewLabel create new label for repository
|
|
|
|
|
func NewLabel(ctx *context.Context, form auth.CreateLabelForm) { |
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.labels") |
|
|
|
|
ctx.Data["PageIsLabels"] = true |
|
|
|
@ -995,6 +1019,7 @@ func NewLabel(ctx *context.Context, form auth.CreateLabelForm) { |
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UpdateLabel update a label's name and color
|
|
|
|
|
func UpdateLabel(ctx *context.Context, form auth.CreateLabelForm) { |
|
|
|
|
l, err := models.GetLabelByID(form.ID) |
|
|
|
|
if err != nil { |
|
|
|
@ -1016,6 +1041,7 @@ func UpdateLabel(ctx *context.Context, form auth.CreateLabelForm) { |
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// DeleteLabel delete a label
|
|
|
|
|
func DeleteLabel(ctx *context.Context) { |
|
|
|
|
if err := models.DeleteLabel(ctx.Repo.Repository.ID, ctx.QueryInt64("id")); err != nil { |
|
|
|
|
ctx.Flash.Error("DeleteLabel: " + err.Error()) |
|
|
|
@ -1029,6 +1055,7 @@ func DeleteLabel(ctx *context.Context) { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Milestones render milestones page
|
|
|
|
|
func Milestones(ctx *context.Context) { |
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.milestones") |
|
|
|
|
ctx.Data["PageIsIssueList"] = true |
|
|
|
@ -1069,18 +1096,20 @@ func Milestones(ctx *context.Context) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ctx.Data["IsShowClosed"] = isShowClosed |
|
|
|
|
ctx.HTML(200, MILESTONE) |
|
|
|
|
ctx.HTML(200, tplMilestone) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewMilestone render creating milestone page
|
|
|
|
|
func NewMilestone(ctx *context.Context) { |
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.milestones.new") |
|
|
|
|
ctx.Data["PageIsIssueList"] = true |
|
|
|
|
ctx.Data["PageIsMilestones"] = true |
|
|
|
|
ctx.Data["RequireDatetimepicker"] = true |
|
|
|
|
ctx.Data["DateLang"] = setting.DateLang(ctx.Locale.Language()) |
|
|
|
|
ctx.HTML(200, MILESTONE_NEW) |
|
|
|
|
ctx.HTML(200, tplMilestoneNew) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewMilestonePost response for creating milestone
|
|
|
|
|
func NewMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) { |
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.milestones.new") |
|
|
|
|
ctx.Data["PageIsIssueList"] = true |
|
|
|
@ -1089,7 +1118,7 @@ func NewMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) { |
|
|
|
|
ctx.Data["DateLang"] = setting.DateLang(ctx.Locale.Language()) |
|
|
|
|
|
|
|
|
|
if ctx.HasError() { |
|
|
|
|
ctx.HTML(200, MILESTONE_NEW) |
|
|
|
|
ctx.HTML(200, tplMilestoneNew) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1099,7 +1128,7 @@ func NewMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) { |
|
|
|
|
deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local) |
|
|
|
|
if err != nil { |
|
|
|
|
ctx.Data["Err_Deadline"] = true |
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), MILESTONE_NEW, &form) |
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1117,6 +1146,7 @@ func NewMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) { |
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/milestones") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// EditMilestone render edting milestone page
|
|
|
|
|
func EditMilestone(ctx *context.Context) { |
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.milestones.edit") |
|
|
|
|
ctx.Data["PageIsMilestones"] = true |
|
|
|
@ -1138,9 +1168,10 @@ func EditMilestone(ctx *context.Context) { |
|
|
|
|
if len(m.DeadlineString) > 0 { |
|
|
|
|
ctx.Data["deadline"] = m.DeadlineString |
|
|
|
|
} |
|
|
|
|
ctx.HTML(200, MILESTONE_NEW) |
|
|
|
|
ctx.HTML(200, tplMilestoneNew) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// EditMilestonePost response for edting milestone
|
|
|
|
|
func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) { |
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.milestones.edit") |
|
|
|
|
ctx.Data["PageIsMilestones"] = true |
|
|
|
@ -1149,7 +1180,7 @@ func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) { |
|
|
|
|
ctx.Data["DateLang"] = setting.DateLang(ctx.Locale.Language()) |
|
|
|
|
|
|
|
|
|
if ctx.HasError() { |
|
|
|
|
ctx.HTML(200, MILESTONE_NEW) |
|
|
|
|
ctx.HTML(200, tplMilestoneNew) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1159,7 +1190,7 @@ func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) { |
|
|
|
|
deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local) |
|
|
|
|
if err != nil { |
|
|
|
|
ctx.Data["Err_Deadline"] = true |
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), MILESTONE_NEW, &form) |
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1184,6 +1215,7 @@ func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) { |
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/milestones") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ChangeMilestonStatus response for change a milestone's status
|
|
|
|
|
func ChangeMilestonStatus(ctx *context.Context) { |
|
|
|
|
m, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")) |
|
|
|
|
if err != nil { |
|
|
|
@ -1218,6 +1250,7 @@ func ChangeMilestonStatus(ctx *context.Context) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// DeleteMilestone delete a milestone
|
|
|
|
|
func DeleteMilestone(ctx *context.Context) { |
|
|
|
|
if err := models.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.QueryInt64("id")); err != nil { |
|
|
|
|
ctx.Flash.Error("DeleteMilestoneByRepoID: " + err.Error()) |
|
|
|
|