diff options
Diffstat (limited to 'routers/repo/issue.go')
-rw-r--r-- | routers/repo/issue.go | 115 |
1 files changed, 113 insertions, 2 deletions
diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 2d1c23d4b9..c033e0f31c 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -5,7 +5,11 @@ package repo import ( + "errors" "fmt" + "io" + "io/ioutil" + "mime" "net/url" "strings" "time" @@ -32,6 +36,11 @@ const ( MILESTONE_EDIT base.TplName = "repo/issue/milestone_edit" ) +var ( + ErrFileTypeForbidden = errors.New("File type is not allowed") + ErrTooManyFiles = errors.New("Maximum number of files to upload exceeded") +) + func Issues(ctx *middleware.Context) { ctx.Data["Title"] = "Issues" ctx.Data["IsRepoToolbarIssues"] = true @@ -151,6 +160,7 @@ func CreateIssue(ctx *middleware.Context, params martini.Params) { ctx.Data["Title"] = "Create issue" ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["IsRepoToolbarIssuesList"] = false + ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled var err error // Get all milestones. @@ -170,7 +180,10 @@ func CreateIssue(ctx *middleware.Context, params martini.Params) { ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err) return } + + ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes ctx.Data["Collaborators"] = us + ctx.HTML(200, ISSUE_CREATE) } @@ -178,6 +191,7 @@ func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.C ctx.Data["Title"] = "Create issue" ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["IsRepoToolbarIssuesList"] = false + ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled var err error // Get all milestones. @@ -227,6 +241,10 @@ func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.C return } + if setting.AttachmentEnabled { + uploadFiles(ctx, issue.Id, 0) + } + // Update mentions. ms := base.MentionPattern.FindAllString(issue.Content, -1) if len(ms) > 0 { @@ -299,6 +317,8 @@ func checkLabels(labels, allLabels []*models.Label) { } func ViewIssue(ctx *middleware.Context, params martini.Params) { + ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled + idx, _ := base.StrTo(params["index"]).Int64() if idx == 0 { ctx.Handle(404, "issue.ViewIssue", nil) @@ -399,6 +419,8 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) { } } + ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes + ctx.Data["Title"] = issue.Name ctx.Data["Issue"] = issue ctx.Data["Comments"] = comments @@ -611,6 +633,71 @@ func UpdateAssignee(ctx *middleware.Context) { }) } +func uploadFiles(ctx *middleware.Context, issueId, commentId int64) { + if !setting.AttachmentEnabled { + return + } + + allowedTypes := strings.Split(setting.AttachmentAllowedTypes, "|") + attachments := ctx.Req.MultipartForm.File["attachments"] + + if len(attachments) > setting.AttachmentMaxFiles { + ctx.Handle(400, "issue.Comment", ErrTooManyFiles) + return + } + + for _, header := range attachments { + file, err := header.Open() + + if err != nil { + ctx.Handle(500, "issue.Comment(header.Open)", err) + return + } + + defer file.Close() + + allowed := false + fileType := mime.TypeByExtension(header.Filename) + + for _, t := range allowedTypes { + t := strings.Trim(t, " ") + + if t == "*/*" || t == fileType { + allowed = true + break + } + } + + if !allowed { + ctx.Handle(400, "issue.Comment", ErrFileTypeForbidden) + return + } + + out, err := ioutil.TempFile(setting.AttachmentPath, "attachment_") + + if err != nil { + ctx.Handle(500, "issue.Comment(ioutil.TempFile)", err) + return + } + + defer out.Close() + + _, err = io.Copy(out, file) + + if err != nil { + ctx.Handle(500, "issue.Comment(io.Copy)", err) + return + } + + _, err = models.CreateAttachment(issueId, commentId, header.Filename, out.Name()) + + if err != nil { + ctx.Handle(500, "issue.Comment(io.Copy)", err) + return + } + } +} + func Comment(ctx *middleware.Context, params martini.Params) { index, err := base.StrTo(ctx.Query("issueIndex")).Int64() if err != nil { @@ -657,7 +744,7 @@ func Comment(ctx *middleware.Context, params martini.Params) { cmtType = models.REOPEN } - if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, ""); err != nil { + if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, "", nil); err != nil { ctx.Handle(200, "issue.Comment(create status change comment)", err) return } @@ -665,12 +752,14 @@ func Comment(ctx *middleware.Context, params martini.Params) { } } + var comment *models.Comment + var ms []string content := ctx.Query("content") if len(content) > 0 { switch params["action"] { case "new": - if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.COMMENT, content); err != nil { + if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.COMMENT, content, nil); err != nil { ctx.Handle(500, "issue.Comment(create comment)", err) return } @@ -696,6 +785,10 @@ func Comment(ctx *middleware.Context, params martini.Params) { } } + if comment != nil { + uploadFiles(ctx, issue.Id, comment.Id) + } + // Notify watchers. act := &models.Action{ ActUserId: ctx.User.Id, @@ -972,3 +1065,21 @@ func UpdateMilestonePost(ctx *middleware.Context, params martini.Params, form au ctx.Redirect(ctx.Repo.RepoLink + "/issues/milestones") } + +func IssueGetAttachment(ctx *middleware.Context, params martini.Params) { + id, err := base.StrTo(params["id"]).Int64() + + if err != nil { + ctx.Handle(400, "issue.IssueGetAttachment(base.StrTo.Int64)", err) + return + } + + attachment, err := models.GetAttachmentById(id) + + if err != nil { + ctx.Handle(404, "issue.IssueGetAttachment(models.GetAttachmentById)", err) + return + } + + ctx.ServeFile(attachment.Path, attachment.Name) +} |