| @@ -238,9 +238,14 @@ func runWeb(*cli.Context) { | |||
| r.Post("/:index/label", repo.UpdateIssueLabel) | |||
| r.Post("/:index/milestone", repo.UpdateIssueMilestone) | |||
| r.Post("/:index/assignee", repo.UpdateAssignee) | |||
| r.Post("/:index/attachment", repo.IssuePostAttachment) | |||
| r.Post("/:index/attachment/:id", repo.IssuePostAttachment) | |||
| r.Get("/:index/attachment/:id", repo.IssueGetAttachment) | |||
| m.Group("/:index/attachment", func(r martini.Router) { | |||
| r.Get("/:id", repo.IssueGetAttachment) | |||
| r.Post("/", repo.IssuePostAttachment) | |||
| r.Post("/:comment", repo.IssuePostAttachment) | |||
| r.Delete("/:comment/:id", repo.IssueDeleteAttachment) | |||
| }) | |||
| r.Post("/labels/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel) | |||
| r.Post("/labels/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel) | |||
| r.Post("/labels/delete", repo.DeleteLabel) | |||
| @@ -868,6 +868,14 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType int, c | |||
| return comment, sess.Commit() | |||
| } | |||
| // GetCommentById returns the comment with the given id | |||
| func GetCommentById(commentId int64) (*Comment, error) { | |||
| c := &Comment{Id: commentId} | |||
| _, err := x.Get(c) | |||
| return c, err | |||
| } | |||
| // GetIssueComments returns list of comment by given issue id. | |||
| func GetIssueComments(issueId int64) ([]Comment, error) { | |||
| comments := make([]Comment, 0, 10) | |||
| @@ -936,14 +944,14 @@ func GetAttachmentById(id int64) (*Attachment, error) { | |||
| func GetAttachmentsForIssue(issueId int64) ([]*Attachment, error) { | |||
| attachments := make([]*Attachment, 0, 10) | |||
| err := x.Where("issue_id = ?", issueId).Where("comment_id = 0").Find(&attachments) | |||
| err := x.Where("issue_id = ?", issueId).And("comment_id = 0").Find(&attachments) | |||
| return attachments, err | |||
| } | |||
| // GetAttachmentsByIssue returns a list of attachments for the given issue | |||
| func GetAttachmentsByIssue(issueId int64) ([]*Attachment, error) { | |||
| attachments := make([]*Attachment, 0, 10) | |||
| err := x.Where("issue_id = ?", issueId).Where("comment_id > 0").Find(&attachments) | |||
| err := x.Where("issue_id = ?", issueId).And("comment_id > 0").Find(&attachments) | |||
| return attachments, err | |||
| } | |||
| @@ -1018,13 +1018,17 @@ func IssuePostAttachment(ctx *middleware.Context, params martini.Params) { | |||
| issueId, _ := base.StrTo(params["index"]).Int64() | |||
| if issueId == 0 { | |||
| ctx.Handle(400, "issue.IssuePostAttachment", nil) | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "invalid issue id", | |||
| }) | |||
| return | |||
| } | |||
| commentId, err := base.StrTo(params["id"]).Int64() | |||
| commentId, err := base.StrTo(params["comment"]).Int64() | |||
| if err != nil && len(params["id"]) > 0 { | |||
| if err != nil && len(params["comment"]) > 0 { | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "invalid comment id", | |||
| @@ -1132,3 +1136,102 @@ func IssueGetAttachment(ctx *middleware.Context, params martini.Params) { | |||
| ctx.ServeFile(attachment.Path, attachment.Name) | |||
| } | |||
| func IssueDeleteAttachment(ctx *middleware.Context, params martini.Params) { | |||
| issueId, _ := base.StrTo(params["index"]).Int64() | |||
| if issueId == 0 { | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "invalid issue id", | |||
| }) | |||
| return | |||
| } | |||
| commentId, err := base.StrTo(params["comment"]).Int64() | |||
| if err != nil || commentId < 0 { | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "invalid comment id", | |||
| }) | |||
| return | |||
| } | |||
| comment, err := models.GetCommentById(commentId) | |||
| if err != nil { | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "invalid issue id", | |||
| }) | |||
| return | |||
| } | |||
| if comment.PosterId != ctx.User.Id { | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "no permissions", | |||
| }) | |||
| return | |||
| } | |||
| attachmentId, err := base.StrTo(params["id"]).Int64() | |||
| if err != nil { | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "invalid attachment id", | |||
| }) | |||
| return | |||
| } | |||
| attachment, err := models.GetAttachmentById(attachmentId) | |||
| if err != nil { | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "wrong attachment id", | |||
| }) | |||
| return | |||
| } | |||
| if attachment.IssueId != issueId { | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "attachment not associated with the given issue", | |||
| }) | |||
| return | |||
| } | |||
| if attachment.CommentId != commentId { | |||
| ctx.JSON(400, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "attachment not associated with the given comment", | |||
| }) | |||
| return | |||
| } | |||
| err = models.DeleteAttachment(attachment, true) | |||
| if err != nil { | |||
| ctx.JSON(500, map[string]interface{}{ | |||
| "ok": false, | |||
| "error": "could not delete attachment", | |||
| }) | |||
| return | |||
| } | |||
| ctx.JSON(200, map[string]interface{}{ | |||
| "ok": true, | |||
| }) | |||
| } | |||
| @@ -101,13 +101,17 @@ | |||
| <div class="tab-pane issue-preview-content" id="issue-preview">loading...</div> | |||
| </div> | |||
| </div> | |||
| <!-- | |||
| <div> | |||
| <div id="attached"></div> | |||
| </div> | |||
| --> | |||
| <div class="text-right panel-body"> | |||
| <div class="form-group"> | |||
| <!-- | |||
| <input type="hidden" name="attachments" value="" /> | |||
| <button data-accept="{{AllowedTypes}}" data-comment-id="0" class="btn-default btn attachment-add" id="attachments-button">Add Attachments...</button> | |||
| --> | |||
| <input type="hidden" value="id" name="repo-id"/> | |||
| <button class="btn-success btn">Create new issue</button> | |||
| @@ -113,13 +113,17 @@ | |||
| <div class="tab-pane issue-preview-content" id="issue-preview">Loading...</div> | |||
| </div> | |||
| </div> | |||
| <!-- | |||
| <div> | |||
| <div id="attached"></div> | |||
| </div> | |||
| --> | |||
| <div class="text-right"> | |||
| <div class="form-group"> | |||
| <!-- | |||
| <input type="hidden" name="attachments" value="" /> | |||
| <button data-accept="{{AllowedTypes}}" class="btn-default btn attachment-add" id="attachments-button">Add Attachments...</button> | |||
| --> | |||
| {{if .IsIssueOwner}}{{if .Issue.IsClosed}} | |||
| <input type="submit" class="btn-default btn issue-open" id="issue-open-btn" data-origin="Reopen" data-text="Reopen & Comment" name="change_status" value="Reopen"/>{{else}} | |||