From 36a83bdb16955cd41f2e6c42ce1790a08bc4ded4 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Mon, 7 Oct 2019 21:55:33 +0800 Subject: [PATCH 01/15] Enable adding and edting attachments for issues and comments --- models/issue.go | 23 ++++ models/issue_comment.go | 24 ++++ modules/util/compare.go | 10 ++ public/js/index.js | 116 +++++++++++++++--- routers/repo/attachment.go | 19 +++ routers/repo/issue.go | 104 +++++++++++++++- routers/routes/routes.go | 3 + templates/repo/issue/view_content.tmpl | 25 ++-- .../repo/issue/view_content/attachments.tmpl | 9 ++ .../repo/issue/view_content/comments.tmpl | 12 +- 10 files changed, 308 insertions(+), 37 deletions(-) create mode 100644 templates/repo/issue/view_content/attachments.tmpl diff --git a/models/issue.go b/models/issue.go index da98fac7df367..f3d22f9486bfb 100644 --- a/models/issue.go +++ b/models/issue.go @@ -939,6 +939,29 @@ func AddDeletePRBranchComment(doer *User, repo *Repository, issueID int64, branc return sess.Commit() } +// UpdateAttachments update attachments by UUIDs for the issue +func (issue *Issue) UpdateAttachments(uuids []string) (err error) { + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + attachments, err := getAttachmentsByUUIDs(sess, uuids) + if err != nil { + return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %v", uuids, err) + } + for i := 0; i < len(attachments); i++ { + attachments[i].IssueID = issue.ID + if err := updateAttachment(sess, attachments[i]); err != nil { + return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err) + } + } + if err = sess.Commit(); err != nil { + return err + } + return nil +} + // ChangeContent changes issue content, as the given user. func (issue *Issue) ChangeContent(doer *User, content string) (err error) { oldContent := issue.Content diff --git a/models/issue_comment.go b/models/issue_comment.go index e8043c1ec7f3a..27b39154fe095 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -355,6 +355,30 @@ func (c *Comment) LoadAttachments() error { return nil } +// UpdateAttachments update attachments by UUIDs for the comment +func (c *Comment) UpdateAttachments(uuids []string) error { + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + attachments, err := getAttachmentsByUUIDs(sess, uuids) + if err != nil { + return fmt.Errorf("getAttachmentsByUUIDs [uuids: %v]: %v", uuids, err) + } + for i := 0; i < len(attachments); i++ { + attachments[i].IssueID = c.IssueID + attachments[i].CommentID = c.ID + if err := updateAttachment(sess, attachments[i]); err != nil { + return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err) + } + } + if err = sess.Commit(); err != nil { + return err + } + return nil +} + // LoadAssigneeUser if comment.Type is CommentTypeAssignees, then load assignees func (c *Comment) LoadAssigneeUser() error { var err error diff --git a/modules/util/compare.go b/modules/util/compare.go index c61e7965ae612..9b047b13171c9 100644 --- a/modules/util/compare.go +++ b/modules/util/compare.go @@ -35,6 +35,16 @@ func ExistsInSlice(target string, slice []string) bool { return i < len(slice) } +// IsStringInSlice sequential searchs if string exists in slice. +func IsStringInSlice(target string, slice []string) bool { + for i := 0; i < len(slice); i++ { + if slice[i] == target { + return true + } + } + return false +} + // IsEqualSlice returns true if slices are equal. func IsEqualSlice(target []string, source []string) bool { if len(target) != len(source) { diff --git a/public/js/index.js b/public/js/index.js index 8a85ad91579e5..a291af0168ffa 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -830,6 +830,70 @@ function initRepository() { issuesTribute.attach($textarea.get()); emojiTribute.attach($textarea.get()); + const $dropzone = $editContentZone.find('.dropzone'); + $dropzone.data("saved", false); + const $files = $editContentZone.find('.comment-files'); + if ($dropzone.length > 0) { + const filenameDict = {}; + $dropzone.dropzone({ + url: $dropzone.data('upload-url'), + headers: {"X-Csrf-Token": csrf}, + maxFiles: $dropzone.data('max-file'), + maxFilesize: $dropzone.data('max-size'), + acceptedFiles: ($dropzone.data('accepts') === '*/*') ? null : $dropzone.data('accepts'), + addRemoveLinks: true, + dictDefaultMessage: $dropzone.data('default-message'), + dictInvalidFileType: $dropzone.data('invalid-input-type'), + dictFileTooBig: $dropzone.data('file-too-big'), + dictRemoveFile: $dropzone.data('remove-file'), + init: function () { + this.on("success", function (file, data) { + filenameDict[file.name] = { + "uuid": data.uuid, + "submitted": false + } + const input = $('').val(data.uuid); + $files.append(input); + }); + this.on("removedfile", function (file) { + if (file.name in filenameDict) { + $('#' + file.uuid).remove(); + } + if ($dropzone.data('remove-url') && $dropzone.data('csrf') && !filenameDict[file.name].submitted) { + $.post($dropzone.data('remove-url'), { + file: file.uuid, + _csrf: $dropzone.data('csrf') + }); + } + }); + this.on("submit", function () { + $.each(filenameDict, function(name){ + filenameDict[name].submitted = true; + }); + }); + this.on("reload", function (){ + $.getJSON($editContentZone.data('attachment-url'), function(data){ + let drop = $dropzone.get(0).dropzone; + drop.removeAllFiles(true); + $files.empty(); + $.each(data, function(){ + drop.emit("addedfile", this); + drop.emit("thumbnail", this, `${$dropzone.data('upload-url')}/${this.uuid}`); + drop.emit("complete", this); + drop.files.push(this); + filenameDict[this.name] = { + "submitted": true, + "uuid": this.uuid + } + const input = $('').val(this.uuid); + $files.append(input); + }); + }); + }); + }, + }); + $dropzone.get(0).dropzone.emit("reload"); + } // Give new write/preview data-tab name to distinguish from others const $editContentForm = $editContentZone.find('.ui.comment.form'); const $tabMenu = $editContentForm.find('.tabular.menu'); @@ -845,27 +909,49 @@ function initRepository() { $editContentZone.find('.cancel.button').click(function () { $renderContent.show(); $editContentZone.hide(); + $dropzone.get(0).dropzone.emit("reload"); }); $editContentZone.find('.save.button').click(function () { $renderContent.show(); $editContentZone.hide(); - + let $attachments = $files.find("[name=files]").map(function(){ + return $(this).val(); + }).get(); $.post($editContentZone.data('update-url'), { - "_csrf": csrf, - "content": $textarea.val(), - "context": $editContentZone.data('context') - }, - function (data) { - if (data.length == 0) { - $renderContent.html($('#no-content').html()); - } else { - $renderContent.html(data.content); - emojify.run($renderContent[0]); - $('pre code', $renderContent[0]).each(function () { - hljs.highlightBlock(this); - }); + "_csrf": csrf, + "content": $textarea.val(), + "context": $editContentZone.data('context'), + "files": $attachments + }, + function (data) { + if (data.length == 0) { + $renderContent.html($('#no-content').html()); + } else { + $renderContent.html(data.content); + emojify.run($renderContent[0]); + $('pre code', $renderContent[0]).each(function () { + hljs.highlightBlock(this); + }); + } + let $content = $segment.parent(); + if(!$content.find(".ui.small.images").length){ + if(data.attachments != ""){ + $content.append(` +
+
+
+
+ `); + $content.find(".ui.small.images").html(data.attachments); } - }); + }else if(data.attachments == ""){ + $content.find(".ui.small.images").parent().remove(); + }else{ + $content.find(".ui.small.images").html(data.attachments); + } + $dropzone.get(0).dropzone.emit("submit"); + $dropzone.get(0).dropzone.emit("reload"); + }); }); } else { $textarea = $segment.find('textarea'); diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index a07a2a8ace9c5..4b73cf08df256 100644 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -63,3 +63,22 @@ func UploadAttachment(ctx *context.Context) { "uuid": attach.UUID, }) } + +// DeleteAttachment response for deleting issue's attachment +func DeleteAttachment(ctx *context.Context) { + file := ctx.Query("file") + fmt.Printf("file %s", file) + attach, err := models.GetAttachmentByUUID(file) + if err != nil { + ctx.Error(400, err.Error()) + return + } + err = models.DeleteAttachment(attach, true) + if err != nil { + ctx.Error(500, fmt.Sprintf("DeleteAttachment: %v", err)) + return + } + ctx.JSON(200, map[string]string{ + "uuid": attach.UUID, + }) +} diff --git a/routers/repo/issue.go b/routers/repo/issue.go index e4ef3b1dbb033..498faa253d722 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -34,6 +34,8 @@ 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" @@ -1074,8 +1076,38 @@ func UpdateIssueContent(ctx *context.Context) { return } + files := ctx.QueryStrings("files[]") + for i := 0; i < len(issue.Attachments); i++ { + if !util.IsStringInSlice(issue.Attachments[i].UUID, files) { + if err := models.DeleteAttachment(issue.Attachments[i], true); err != nil { + ctx.ServerError("DeleteAttachment", err) + return + } + } + } + if len(files) > 0 { + if err := issue.UpdateAttachments(files); err != nil { + ctx.ServerError("UpdateAttachments", err) + return + } + } + var err error + issue.Attachments, err = models.GetAttachmentsByIssueID(issue.ID) + if err != nil { + ctx.ServerError("GetAttachmentsByIssueID", err) + return + } + attachHTML, err := ctx.HTMLString(string(tplAttachment), map[string]interface{}{ + "ctx": ctx.Data, + "Attachments": issue.Attachments, + }) + if err != nil { + ctx.ServerError("UpdateIssueContent.HTMLString", err) + return + } ctx.JSON(200, map[string]interface{}{ - "content": string(markdown.Render([]byte(issue.Content), ctx.Query("context"), ctx.Repo.Repository.ComposeMetas())), + "content": string(markdown.Render([]byte(issue.Content), ctx.Query("context"), ctx.Repo.Repository.ComposeMetas())), + "attachments": attachHTML, }) } @@ -1325,6 +1357,13 @@ func UpdateCommentContent(ctx *context.Context) { return } + if comment.Type == models.CommentTypeComment { + if err := comment.LoadAttachments(); err != nil { + ctx.ServerError("LoadAttachments", err) + return + } + } + if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) { ctx.Error(403) return @@ -1346,10 +1385,41 @@ func UpdateCommentContent(ctx *context.Context) { return } + files := ctx.QueryStrings("files[]") + for i := 0; i < len(comment.Attachments); i++ { + if !util.IsStringInSlice(comment.Attachments[i].UUID, files) { + if err := models.DeleteAttachment(comment.Attachments[i], true); err != nil { + ctx.ServerError("DeleteAttachment", err) + return + } + } + } + if len(files) > 0 { + if err := comment.UpdateAttachments(files); err != nil { + ctx.ServerError("UpdateAttachments", err) + return + } + } + + comment.Attachments, err = models.GetAttachmentsByCommentID(comment.ID) + if err != nil { + ctx.ServerError("GetAttachmentsByCommentID", err) + return + } + attachHTML, err := ctx.HTMLString(string(tplAttachment), map[string]interface{}{ + "ctx": ctx.Data, + "Attachments": comment.Attachments, + }) + if err != nil { + ctx.ServerError("UpdateCommentContent.HTMLString", err) + return + } + notification.NotifyUpdateComment(ctx.User, comment, oldContent) ctx.JSON(200, map[string]interface{}{ - "content": string(markdown.Render([]byte(comment.Content), ctx.Query("context"), ctx.Repo.Repository.ComposeMetas())), + "content": string(markdown.Render([]byte(comment.Content), ctx.Query("context"), ctx.Repo.Repository.ComposeMetas())), + "attachments": attachHTML, }) } @@ -1603,3 +1673,33 @@ func filterXRefComments(ctx *context.Context, issue *models.Issue) error { } return nil } + +// GetIssueAttachments returns attachments for the issue +func GetIssueAttachments(ctx *context.Context) { + issue := GetActionIssue(ctx) + var attachments = make([]*api.Attachment, len(issue.Attachments)) + for i := 0; i < len(issue.Attachments); i++ { + attachments[i] = issue.Attachments[i].APIFormat() + } + ctx.JSON(200, attachments) +} + +// GetCommentAttachments returns attachments for the comment +func GetCommentAttachments(ctx *context.Context) { + comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + if err != nil { + ctx.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err) + return + } + var attachments = make([]*api.Attachment, 0) + if comment.Type == models.CommentTypeComment { + if err := comment.LoadAttachments(); err != nil { + ctx.ServerError("LoadAttachments", err) + return + } + for i := 0; i < len(comment.Attachments); i++ { + attachments = append(attachments, comment.Attachments[i].APIFormat()) + } + } + ctx.JSON(200, attachments) +} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 5262d4ad5cf7f..1a65ee6348c8a 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -515,6 +515,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("", func() { m.Post("/attachments", repo.UploadAttachment) + m.Post("/attachments-remove", repo.DeleteAttachment) }, reqSignIn) m.Group("/:username", func() { @@ -710,6 +711,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/reactions/:action", bindIgnErr(auth.ReactionForm{}), repo.ChangeIssueReaction) m.Post("/lock", reqRepoIssueWriter, bindIgnErr(auth.IssueLockForm{}), repo.LockIssue) m.Post("/unlock", reqRepoIssueWriter, repo.UnlockIssue) + m.Get("/attachments", repo.GetIssueAttachments) }, context.RepoMustNotBeArchived()) m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel) @@ -721,6 +723,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("", repo.UpdateCommentContent) m.Post("/delete", repo.DeleteComment) m.Post("/reactions/:action", bindIgnErr(auth.ReactionForm{}), repo.ChangeCommentReaction) + m.Get("/attachments", repo.GetCommentAttachments) }, context.RepoMustNotBeArchived()) m.Group("/labels", func() { m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel) diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index acabe34782fc4..922558a5d0ce6 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -46,7 +46,7 @@ {{end}}
{{.Issue.Content}}
-
+
{{$reactions := .Issue.Reactions.GroupByType}} {{if $reactions}} @@ -57,15 +57,7 @@ {{if .Issue.Attachments}}
- {{range .Issue.Attachments}} - - {{if FilenameIsImage .Name}} - - {{else}} - - {{end}} - - {{end}} + {{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Issue.Attachments}}
{{end}} @@ -182,6 +174,19 @@
{{$.i18n.Tr "loading"}}
+ {{if .IsAttachmentEnabled}} +
+
+
+ {{end}}
{{.i18n.Tr "repo.issues.cancel"}}
{{.i18n.Tr "repo.issues.save"}}
diff --git a/templates/repo/issue/view_content/attachments.tmpl b/templates/repo/issue/view_content/attachments.tmpl new file mode 100644 index 0000000000000..e2d7d1b9de679 --- /dev/null +++ b/templates/repo/issue/view_content/attachments.tmpl @@ -0,0 +1,9 @@ +{{range .Attachments}} + + {{if FilenameIsImage .Name}} + + {{else}} + + {{end}} + +{{end}} \ No newline at end of file diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index a5f25954c7f97..e3ea9ba822bc6 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -55,7 +55,7 @@ {{end}}
{{.Content}}
-
+
{{$reactions := .Reactions.GroupByType}} {{if $reactions}} @@ -66,15 +66,7 @@ {{if .Attachments}}
- {{range .Attachments}} - - {{if FilenameIsImage .Name}} - - {{else}} - - {{end}} - - {{end}} + {{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Attachments}}
{{end}} From 687c880a251e65d165449f0a3da7beb41c4d24e3 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Mon, 7 Oct 2019 23:23:33 +0800 Subject: [PATCH 02/15] fix lint error --- public/js/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/js/index.js b/public/js/index.js index a291af0168ffa..58dfd450821db 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -873,7 +873,7 @@ function initRepository() { }); this.on("reload", function (){ $.getJSON($editContentZone.data('attachment-url'), function(data){ - let drop = $dropzone.get(0).dropzone; + const drop = $dropzone.get(0).dropzone; drop.removeAllFiles(true); $files.empty(); $.each(data, function(){ @@ -914,7 +914,7 @@ function initRepository() { $editContentZone.find('.save.button').click(function () { $renderContent.show(); $editContentZone.hide(); - let $attachments = $files.find("[name=files]").map(function(){ + const $attachments = $files.find("[name=files]").map(function(){ return $(this).val(); }).get(); $.post($editContentZone.data('update-url'), { @@ -933,7 +933,7 @@ function initRepository() { hljs.highlightBlock(this); }); } - let $content = $segment.parent(); + const $content = $segment.parent(); if(!$content.find(".ui.small.images").length){ if(data.attachments != ""){ $content.append(` From 95f23935ca80ee69b1b8de9f498949e58ed98aeb Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Tue, 8 Oct 2019 19:23:20 +0800 Subject: [PATCH 03/15] fix golint error --- modules/util/compare.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/util/compare.go b/modules/util/compare.go index 9b047b13171c9..f1d1e5718e462 100644 --- a/modules/util/compare.go +++ b/modules/util/compare.go @@ -35,7 +35,7 @@ func ExistsInSlice(target string, slice []string) bool { return i < len(slice) } -// IsStringInSlice sequential searchs if string exists in slice. +// IsStringInSlice sequential searches if string exists in slice. func IsStringInSlice(target string, slice []string) bool { for i := 0; i < len(slice); i++ { if slice[i] == target { From 1ec28ce2e743dce069c19ee59aac528cfb2faed9 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Tue, 8 Oct 2019 19:29:56 +0800 Subject: [PATCH 04/15] fix golint error --- models/issue_comment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/issue_comment.go b/models/issue_comment.go index 27b39154fe095..958e875ff81bb 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -373,7 +373,7 @@ func (c *Comment) UpdateAttachments(uuids []string) error { return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err) } } - if err = sess.Commit(); err != nil { + if err := sess.Commit(); err != nil { return err } return nil From 8007fc5a07c5031aa0a5844cd33a3d8fdbb60ef9 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Tue, 8 Oct 2019 19:37:08 +0800 Subject: [PATCH 05/15] fix golint error --- models/issue_comment.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/models/issue_comment.go b/models/issue_comment.go index 958e875ff81bb..cf808d7974950 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -373,10 +373,7 @@ func (c *Comment) UpdateAttachments(uuids []string) error { return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err) } } - if err := sess.Commit(); err != nil { - return err - } - return nil + return sess.Commit() } // LoadAssigneeUser if comment.Type is CommentTypeAssignees, then load assignees From 7c544501053e10fba99a93324e4eb06480bc4c73 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Tue, 8 Oct 2019 19:46:43 +0800 Subject: [PATCH 06/15] fix golint error --- models/issue.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/models/issue.go b/models/issue.go index f3d22f9486bfb..b9f3237877ab8 100644 --- a/models/issue.go +++ b/models/issue.go @@ -956,10 +956,7 @@ func (issue *Issue) UpdateAttachments(uuids []string) (err error) { return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err) } } - if err = sess.Commit(); err != nil { - return err - } - return nil + return sess.Commit() } // ChangeContent changes issue content, as the given user. From f53dbb4d85aabdabeec8cc313b2118b46e8d1464 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Tue, 8 Oct 2019 22:55:11 +0800 Subject: [PATCH 07/15] fix uuid undefined error --- public/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/index.js b/public/js/index.js index 58dfd450821db..e5c721713eb9b 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -857,7 +857,7 @@ function initRepository() { }); this.on("removedfile", function (file) { if (file.name in filenameDict) { - $('#' + file.uuid).remove(); + $('#' + filenameDict[file.name].uuid).remove(); } if ($dropzone.data('remove-url') && $dropzone.data('csrf') && !filenameDict[file.name].submitted) { $.post($dropzone.data('remove-url'), { From dd561e753b57b606636a4f1f5355420b5fb44bba Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Tue, 8 Oct 2019 23:19:08 +0800 Subject: [PATCH 08/15] fix image size --- public/js/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/js/index.js b/public/js/index.js index e5c721713eb9b..6433c856886bd 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -885,6 +885,7 @@ function initRepository() { "submitted": true, "uuid": this.uuid } + $dropzone.find(`img[src='${$dropzone.data('upload-url')}/${this.uuid}']`).css("max-width", "100%"); const input = $('').val(this.uuid); $files.append(input); }); From 640b9581ae1bcde896f72d809d83963fe6091b68 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Wed, 9 Oct 2019 00:05:34 +0800 Subject: [PATCH 09/15] update #8426 rewrite route --- routers/routes/routes.go | 6 +++--- templates/repo/issue/view_content.tmpl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 0557c9532c2a2..c5a94dbafdb6d 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -513,9 +513,9 @@ func RegisterRoutes(m *macaron.Macaron) { }) }, ignSignIn) - m.Group("", func() { - m.Post("/attachments", repo.UploadAttachment) - m.Post("/attachments-remove", repo.DeleteAttachment) + m.Group("/attachments", func() { + m.Post("", repo.UploadAttachment) + m.Post("/delete", repo.DeleteAttachment) }, reqSignIn) m.Group("/:username", func() { diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index 922558a5d0ce6..29d48d70891d4 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -178,7 +178,7 @@
Date: Wed, 9 Oct 2019 07:05:47 +0800 Subject: [PATCH 10/15] update #8426 fix coding style error --- public/js/index.js | 6 +++--- routers/repo/attachment.go | 1 - routers/repo/issue.go | 22 ++++++++++++---------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/public/js/index.js b/public/js/index.js index 6433c856886bd..e314174ce10c3 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -891,7 +891,7 @@ function initRepository() { }); }); }); - }, + } }); $dropzone.get(0).dropzone.emit("reload"); } @@ -945,9 +945,9 @@ function initRepository() { `); $content.find(".ui.small.images").html(data.attachments); } - }else if(data.attachments == ""){ + } else if (data.attachments == ""){ $content.find(".ui.small.images").parent().remove(); - }else{ + } else { $content.find(".ui.small.images").html(data.attachments); } $dropzone.get(0).dropzone.emit("submit"); diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index 4b73cf08df256..88fcf945d03b8 100644 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -67,7 +67,6 @@ func UploadAttachment(ctx *context.Context) { // DeleteAttachment response for deleting issue's attachment func DeleteAttachment(ctx *context.Context) { file := ctx.Query("file") - fmt.Printf("file %s", file) attach, err := models.GetAttachmentByUUID(file) if err != nil { ctx.Error(400, err.Error()) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 498faa253d722..b9b93993f9efc 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -1078,11 +1078,12 @@ func UpdateIssueContent(ctx *context.Context) { files := ctx.QueryStrings("files[]") for i := 0; i < len(issue.Attachments); i++ { - if !util.IsStringInSlice(issue.Attachments[i].UUID, files) { - if err := models.DeleteAttachment(issue.Attachments[i], true); err != nil { - ctx.ServerError("DeleteAttachment", err) - return - } + if util.IsStringInSlice(issue.Attachments[i].UUID, files) { + continue + } + if err := models.DeleteAttachment(issue.Attachments[i], true); err != nil { + ctx.ServerError("DeleteAttachment", err) + return } } if len(files) > 0 { @@ -1387,11 +1388,12 @@ func UpdateCommentContent(ctx *context.Context) { files := ctx.QueryStrings("files[]") for i := 0; i < len(comment.Attachments); i++ { - if !util.IsStringInSlice(comment.Attachments[i].UUID, files) { - if err := models.DeleteAttachment(comment.Attachments[i], true); err != nil { - ctx.ServerError("DeleteAttachment", err) - return - } + if util.IsStringInSlice(comment.Attachments[i].UUID, files) { + continue + } + if err := models.DeleteAttachment(comment.Attachments[i], true); err != nil { + ctx.ServerError("DeleteAttachment", err) + return } } if len(files) > 0 { From 96cad218e8ec8011911415d68962739a91ec3321 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Wed, 9 Oct 2019 07:06:45 +0800 Subject: [PATCH 11/15] fix lint error --- public/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/index.js b/public/js/index.js index e314174ce10c3..beb406fecb65d 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -945,7 +945,7 @@ function initRepository() { `); $content.find(".ui.small.images").html(data.attachments); } - } else if (data.attachments == ""){ + } else if (data.attachments == "") { $content.find(".ui.small.images").parent().remove(); } else { $content.find(".ui.small.images").html(data.attachments); From 94cfed7f3a8866662c64ec211b431e67bca7995b Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Thu, 10 Oct 2019 01:33:32 +0800 Subject: [PATCH 12/15] refactoring codes for updating attachments --- routers/repo/issue.go | 120 ++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 58 deletions(-) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index b9b93993f9efc..e5bcf7927066c 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -1077,38 +1077,13 @@ func UpdateIssueContent(ctx *context.Context) { } files := ctx.QueryStrings("files[]") - for i := 0; i < len(issue.Attachments); i++ { - if util.IsStringInSlice(issue.Attachments[i].UUID, files) { - continue - } - if err := models.DeleteAttachment(issue.Attachments[i], true); err != nil { - ctx.ServerError("DeleteAttachment", err) - return - } - } - if len(files) > 0 { - if err := issue.UpdateAttachments(files); err != nil { - ctx.ServerError("UpdateAttachments", err) - return - } - } - var err error - issue.Attachments, err = models.GetAttachmentsByIssueID(issue.ID) - if err != nil { - ctx.ServerError("GetAttachmentsByIssueID", err) - return - } - attachHTML, err := ctx.HTMLString(string(tplAttachment), map[string]interface{}{ - "ctx": ctx.Data, - "Attachments": issue.Attachments, - }) - if err != nil { - ctx.ServerError("UpdateIssueContent.HTMLString", err) - return + if err := updateAttachments(issue, files); err != nil { + ctx.ServerError("UpdateAttachments", err) } + ctx.JSON(200, map[string]interface{}{ "content": string(markdown.Render([]byte(issue.Content), ctx.Query("context"), ctx.Repo.Repository.ComposeMetas())), - "attachments": attachHTML, + "attachments": attachmentsHTML(ctx, issue.Attachments), }) } @@ -1387,41 +1362,15 @@ func UpdateCommentContent(ctx *context.Context) { } files := ctx.QueryStrings("files[]") - for i := 0; i < len(comment.Attachments); i++ { - if util.IsStringInSlice(comment.Attachments[i].UUID, files) { - continue - } - if err := models.DeleteAttachment(comment.Attachments[i], true); err != nil { - ctx.ServerError("DeleteAttachment", err) - return - } - } - if len(files) > 0 { - if err := comment.UpdateAttachments(files); err != nil { - ctx.ServerError("UpdateAttachments", err) - return - } - } - - comment.Attachments, err = models.GetAttachmentsByCommentID(comment.ID) - if err != nil { - ctx.ServerError("GetAttachmentsByCommentID", err) - return - } - attachHTML, err := ctx.HTMLString(string(tplAttachment), map[string]interface{}{ - "ctx": ctx.Data, - "Attachments": comment.Attachments, - }) - if err != nil { - ctx.ServerError("UpdateCommentContent.HTMLString", err) - return + if err := updateAttachments(comment, files); err != nil { + ctx.ServerError("UpdateAttachments", err) } notification.NotifyUpdateComment(ctx.User, comment, oldContent) ctx.JSON(200, map[string]interface{}{ "content": string(markdown.Render([]byte(comment.Content), ctx.Query("context"), ctx.Repo.Repository.ComposeMetas())), - "attachments": attachHTML, + "attachments": attachmentsHTML(ctx, comment.Attachments), }) } @@ -1705,3 +1654,58 @@ func GetCommentAttachments(ctx *context.Context) { } ctx.JSON(200, attachments) } + +func updateAttachments(item interface{}, files []string) error { + var attachments []*models.Attachment + switch content := item.(type) { + case *models.Issue: + attachments = content.Attachments + case *models.Comment: + attachments = content.Attachments + default: + return fmt.Errorf("Unknow Type") + } + for i := 0; i < len(attachments); i++ { + if util.IsStringInSlice(attachments[i].UUID, files) { + continue + } + if err := models.DeleteAttachment(attachments[i], true); err != nil { + return err + } + } + var err error + if len(files) > 0 { + switch content := item.(type) { + case *models.Issue: + err = content.UpdateAttachments(files) + case *models.Comment: + err = content.UpdateAttachments(files) + default: + return fmt.Errorf("Unknow Type") + } + if err != nil { + return err + } + } + switch content := item.(type) { + case *models.Issue: + content.Attachments, err = models.GetAttachmentsByIssueID(content.ID) + case *models.Comment: + content.Attachments, err = models.GetAttachmentsByCommentID(content.ID) + default: + return fmt.Errorf("Unknow Type") + } + return err +} + +func attachmentsHTML(ctx *context.Context, attachments []*models.Attachment) string { + attachHTML, err := ctx.HTMLString(string(tplAttachment), map[string]interface{}{ + "ctx": ctx.Data, + "Attachments": attachments, + }) + if err != nil { + ctx.ServerError("attachmentsHTML.HTMLString", err) + return "" + } + return attachHTML +} From 2a9c18ee30505c6b703e4399e460e3749cc59f00 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Thu, 10 Oct 2019 01:34:16 +0800 Subject: [PATCH 13/15] Remove template string --- public/js/index.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/public/js/index.js b/public/js/index.js index beb406fecb65d..5ee05f2c6a8c2 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -877,15 +877,16 @@ function initRepository() { drop.removeAllFiles(true); $files.empty(); $.each(data, function(){ + const imgSrc = $dropzone.data('upload-url') + "/" + this.uuid; drop.emit("addedfile", this); - drop.emit("thumbnail", this, `${$dropzone.data('upload-url')}/${this.uuid}`); + drop.emit("thumbnail", this, imgSrc); drop.emit("complete", this); drop.files.push(this); filenameDict[this.name] = { "submitted": true, "uuid": this.uuid } - $dropzone.find(`img[src='${$dropzone.data('upload-url')}/${this.uuid}']`).css("max-width", "100%"); + $dropzone.find("img[src='" + imgSrc + "']").css("max-width", "100%"); const input = $('').val(this.uuid); $files.append(input); }); @@ -937,12 +938,12 @@ function initRepository() { const $content = $segment.parent(); if(!$content.find(".ui.small.images").length){ if(data.attachments != ""){ - $content.append(` -
-
-
-
- `); + $content.append( + '
' + + '
' + + '
' + + '
' + ); $content.find(".ui.small.images").html(data.attachments); } } else if (data.attachments == "") { From 427d9c4a833fd0fde70e727261ffb3fd84d4771b Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Sat, 12 Oct 2019 14:51:40 +0800 Subject: [PATCH 14/15] fix filenameDict undefined problem --- public/js/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/js/index.js b/public/js/index.js index 5ee05f2c6a8c2..d875d2b3d096c 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -856,9 +856,10 @@ function initRepository() { $files.append(input); }); this.on("removedfile", function (file) { - if (file.name in filenameDict) { - $('#' + filenameDict[file.name].uuid).remove(); + if (!(file.name in filenameDict)) { + return; } + $('#' + filenameDict[file.name].uuid).remove(); if ($dropzone.data('remove-url') && $dropzone.data('csrf') && !filenameDict[file.name].submitted) { $.post($dropzone.data('remove-url'), { file: file.uuid, From ce3bdf024ffd6dd357c2c520de5aec9c1cfdbf20 Mon Sep 17 00:00:00 2001 From: Benno Lin Date: Sat, 12 Oct 2019 16:18:01 +0800 Subject: [PATCH 15/15] fix remove wrong file and add file delete permission checking --- public/js/index.js | 2 +- routers/repo/attachment.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/js/index.js b/public/js/index.js index d875d2b3d096c..f063638b30c95 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -862,7 +862,7 @@ function initRepository() { $('#' + filenameDict[file.name].uuid).remove(); if ($dropzone.data('remove-url') && $dropzone.data('csrf') && !filenameDict[file.name].submitted) { $.post($dropzone.data('remove-url'), { - file: file.uuid, + file: filenameDict[file.name].uuid, _csrf: $dropzone.data('csrf') }); } diff --git a/routers/repo/attachment.go b/routers/repo/attachment.go index 88fcf945d03b8..0d496230e16a1 100644 --- a/routers/repo/attachment.go +++ b/routers/repo/attachment.go @@ -68,6 +68,10 @@ func UploadAttachment(ctx *context.Context) { func DeleteAttachment(ctx *context.Context) { file := ctx.Query("file") attach, err := models.GetAttachmentByUUID(file) + if !ctx.IsSigned || (ctx.User.ID != attach.UploaderID) { + ctx.Error(403) + return + } if err != nil { ctx.Error(400, err.Error()) return