From af88388aa2ceaea34b872fe63b864859f9d00d01 Mon Sep 17 00:00:00 2001 From: 3xxx Date: Sun, 2 Jun 2024 21:57:50 +0800 Subject: [PATCH 1/2] update images upload --- controllers/DocumentController.go | 284 ++++++++++-------- .../plugins/image-dialog/image-dialog.js | 282 ++++++++--------- 2 files changed, 306 insertions(+), 260 deletions(-) diff --git a/controllers/DocumentController.go b/controllers/DocumentController.go index 777df65a4..bdfcd1ee7 100644 --- a/controllers/DocumentController.go +++ b/controllers/DocumentController.go @@ -6,6 +6,7 @@ import ( "fmt" "html/template" "image/png" + "io" "net/http" "net/url" "os" @@ -487,156 +488,211 @@ func (c *DocumentController) Upload() { name := "editormd-file-file" - file, moreFile, err := c.GetFile(name) - if err == http.ErrMissingFile || moreFile == nil { + // file, moreFile, err := c.GetFile(name) + // if err == http.ErrMissingFile || moreFile == nil { + // name = "editormd-image-file" + // file, moreFile, err = c.GetFile(name) + // if err == http.ErrMissingFile || moreFile == nil { + // c.JsonResult(6003, i18n.Tr(c.Lang, "message.upload_file_empty")) + // return + // } + // } + // ****3xxx + files, err := c.GetFiles(name) + if err == http.ErrMissingFile { name = "editormd-image-file" - file, moreFile, err = c.GetFile(name) - if err == http.ErrMissingFile || moreFile == nil { + files, err = c.GetFiles(name) + if err == http.ErrMissingFile { c.JsonResult(6003, i18n.Tr(c.Lang, "message.upload_file_empty")) return } } - if err != nil { - c.JsonResult(6002, err.Error()) - } - - defer file.Close() - - type Size interface { - Size() int64 - } + // if err != nil { + // http.Error(w, err.Error(), http.StatusNoContent) + // return + // } + // jMap := make(map[string]interface{}) + // s := []map[int]interface{}{} + result2 := []map[string]interface{}{} + for i, _ := range files { + //for each fileheader, get a handle to the actual file + file, err := files[i].Open() + + defer file.Close() + // if err != nil { + // http.Error(w, err.Error(), http.StatusInternalServerError) + // return + // } + // //create destination file making sure the path is writeable. + // dst, err := os.Create("upload/" + files[i].Filename) + // defer dst.Close() + // if err != nil { + // http.Error(w, err.Error(), http.StatusInternalServerError) + // return + // } + // //copy the uploaded file to the destination file + // if _, err := io.Copy(dst, file); err != nil { + // http.Error(w, err.Error(), http.StatusInternalServerError) + // return + // } + // } + // **** - if conf.GetUploadFileSize() > 0 && moreFile.Size > conf.GetUploadFileSize() { - c.JsonResult(6009, i18n.Tr(c.Lang, "message.upload_file_size_limit")) - } + if err != nil { + c.JsonResult(6002, err.Error()) + } - ext := filepath.Ext(moreFile.Filename) - //文件必须带有后缀名 - if ext == "" { - c.JsonResult(6003, i18n.Tr(c.Lang, "message.upload_file_type_error")) - } - //如果文件类型设置为 * 标识不限制文件类型 - if conf.IsAllowUploadFileExt(ext) == false { - c.JsonResult(6004, i18n.Tr(c.Lang, "message.upload_file_type_error")) - } + // defer file.Close() - bookId := 0 + type Size interface { + Size() int64 + } - // 如果是超级管理员,则不判断权限 - if c.Member.IsAdministrator() { - book, err := models.NewBook().FindByFieldFirst("identify", identify) + // if conf.GetUploadFileSize() > 0 && moreFile.Size > conf.GetUploadFileSize() { + if conf.GetUploadFileSize() > 0 && files[i].Size > conf.GetUploadFileSize() { + c.JsonResult(6009, i18n.Tr(c.Lang, "message.upload_file_size_limit")) + } - if err != nil { - c.JsonResult(6006, i18n.Tr(c.Lang, "message.doc_not_exist_or_no_permit")) + // ext := filepath.Ext(moreFile.Filename) + ext := filepath.Ext(files[i].Filename) + //文件必须带有后缀名 + if ext == "" { + c.JsonResult(6003, i18n.Tr(c.Lang, "message.upload_file_type_error")) + } + //如果文件类型设置为 * 标识不限制文件类型 + if conf.IsAllowUploadFileExt(ext) == false { + c.JsonResult(6004, i18n.Tr(c.Lang, "message.upload_file_type_error")) } - bookId = book.BookId - } else { - book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) + bookId := 0 - if err != nil { - logs.Error("DocumentController.Edit => ", err) - if err == orm.ErrNoRows { - c.JsonResult(6006, i18n.Tr(c.Lang, "message.no_permission")) + // 如果是超级管理员,则不判断权限 + if c.Member.IsAdministrator() { + book, err := models.NewBook().FindByFieldFirst("identify", identify) + + if err != nil { + c.JsonResult(6006, i18n.Tr(c.Lang, "message.doc_not_exist_or_no_permit")) } - c.JsonResult(6001, err.Error()) - } + bookId = book.BookId + } else { + book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) - // 如果没有编辑权限 - if book.RoleId != conf.BookEditor && book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder { - c.JsonResult(6006, i18n.Tr(c.Lang, "message.no_permission")) - } + if err != nil { + logs.Error("DocumentController.Edit => ", err) + if err == orm.ErrNoRows { + c.JsonResult(6006, i18n.Tr(c.Lang, "message.no_permission")) + } - bookId = book.BookId - } + c.JsonResult(6001, err.Error()) + } - if docId > 0 { - doc, err := models.NewDocument().Find(docId) - if err != nil { - c.JsonResult(6007, i18n.Tr(c.Lang, "message.doc_not_exist")) - } + // 如果没有编辑权限 + if book.RoleId != conf.BookEditor && book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder { + c.JsonResult(6006, i18n.Tr(c.Lang, "message.no_permission")) + } - if doc.BookId != bookId { - c.JsonResult(6008, i18n.Tr(c.Lang, "message.doc_not_belong_project")) + bookId = book.BookId } - } - fileName := "m_" + cryptil.UniqueId() + "_r" - filePath := filepath.Join(conf.WorkingDirectory, "uploads", identify) + if docId > 0 { + doc, err := models.NewDocument().Find(docId) + if err != nil { + c.JsonResult(6007, i18n.Tr(c.Lang, "message.doc_not_exist")) + } - //将图片和文件分开存放 - if filetil.IsImageExt(moreFile.Filename) { - filePath = filepath.Join(filePath, "images", fileName+ext) - } else { - filePath = filepath.Join(filePath, "files", fileName+ext) - } + if doc.BookId != bookId { + c.JsonResult(6008, i18n.Tr(c.Lang, "message.doc_not_belong_project")) + } + } - path := filepath.Dir(filePath) + fileName := "m_" + cryptil.UniqueId() + "_r" + filePath := filepath.Join(conf.WorkingDirectory, "uploads", identify) - _ = os.MkdirAll(path, os.ModePerm) + //将图片和文件分开存放 + // if filetil.IsImageExt(moreFile.Filename) { + if filetil.IsImageExt(files[i].Filename) { + filePath = filepath.Join(filePath, "images", fileName+ext) + } else { + filePath = filepath.Join(filePath, "files", fileName+ext) + } - err = c.SaveToFile(name, filePath) + path := filepath.Dir(filePath) - if err != nil { - logs.Error("保存文件失败 -> ", err) - c.JsonResult(6005, i18n.Tr(c.Lang, "message.failed")) - } + _ = os.MkdirAll(path, os.ModePerm) - attachment := models.NewAttachment() - attachment.BookId = bookId - attachment.FileName = moreFile.Filename - attachment.CreateAt = c.Member.MemberId - attachment.FileExt = ext - attachment.FilePath = strings.TrimPrefix(filePath, conf.WorkingDirectory) - attachment.DocumentId = docId + // err = c.SaveToFile(name, filePath) // frome beego controller.go: savetofile it only operates the first one of mutil-upload form file field. - if fileInfo, err := os.Stat(filePath); err == nil { - attachment.FileSize = float64(fileInfo.Size()) - } + //copy the uploaded file to the destination file + dst, err := os.Create(filePath) + defer dst.Close() + if _, err := io.Copy(dst, file); err != nil { + logs.Error("保存文件失败 -> ", err) + c.JsonResult(6005, i18n.Tr(c.Lang, "message.failed")) + } - if docId > 0 { + // if err != nil { + // logs.Error("保存文件失败 -> ", err) + // c.JsonResult(6005, i18n.Tr(c.Lang, "message.failed")) + // } + + attachment := models.NewAttachment() + attachment.BookId = bookId + // attachment.FileName = moreFile.Filename + attachment.FileName = files[i].Filename + attachment.CreateAt = c.Member.MemberId + attachment.FileExt = ext + attachment.FilePath = strings.TrimPrefix(filePath, conf.WorkingDirectory) attachment.DocumentId = docId - } - if filetil.IsImageExt(moreFile.Filename) { - attachment.HttpPath = "/" + strings.Replace(strings.TrimPrefix(filePath, conf.WorkingDirectory), "\\", "/", -1) - if strings.HasPrefix(attachment.HttpPath, "//") { - attachment.HttpPath = conf.URLForWithCdnImage(string(attachment.HttpPath[1:])) + if fileInfo, err := os.Stat(filePath); err == nil { + attachment.FileSize = float64(fileInfo.Size()) } - isAttach = false - } + if docId > 0 { + attachment.DocumentId = docId + } - err = attachment.Insert() + // if filetil.IsImageExt(moreFile.Filename) { + if filetil.IsImageExt(files[i].Filename) { + attachment.HttpPath = "/" + strings.Replace(strings.TrimPrefix(filePath, conf.WorkingDirectory), "\\", "/", -1) + if strings.HasPrefix(attachment.HttpPath, "//") { + attachment.HttpPath = conf.URLForWithCdnImage(string(attachment.HttpPath[1:])) + } - if err != nil { - os.Remove(filePath) - logs.Error("文件保存失败 ->", err) - c.JsonResult(6006, i18n.Tr(c.Lang, "message.failed")) - } + isAttach = false + } - if attachment.HttpPath == "" { - attachment.HttpPath = conf.URLForNotHost("DocumentController.DownloadAttachment", ":key", identify, ":attach_id", attachment.AttachmentId) + err = attachment.Insert() - if err := attachment.Update(); err != nil { - logs.Error("保存文件失败 ->", err) - c.JsonResult(6005, i18n.Tr(c.Lang, "message.failed")) + if err != nil { + os.Remove(filePath) + logs.Error("文件保存失败 ->", err) + c.JsonResult(6006, i18n.Tr(c.Lang, "message.failed")) } - } - result := map[string]interface{}{ - "errcode": 0, - "success": 1, - "message": "ok", - "url": attachment.HttpPath, - "alt": attachment.FileName, - "is_attach": isAttach, - "attach": attachment, + if attachment.HttpPath == "" { + attachment.HttpPath = conf.URLForNotHost("DocumentController.DownloadAttachment", ":key", identify, ":attach_id", attachment.AttachmentId) + + if err := attachment.Update(); err != nil { + logs.Error("保存文件失败 ->", err) + c.JsonResult(6005, i18n.Tr(c.Lang, "message.failed")) + } + } + result := map[string]interface{}{ + "errcode": 0, + "success": 1, + "message": "ok", + "url": attachment.HttpPath, + "alt": attachment.FileName, + "is_attach": isAttach, + "attach": attachment, + } + result2 = append(result2, result) } - c.Ctx.Output.JSON(result, true, false) + c.Ctx.Output.JSON(result2, true, false) c.StopRun() } @@ -946,23 +1002,18 @@ func (c *DocumentController) Export() { output := c.GetString("output") token := c.GetString("token") - logs.Info(identify) - logs.Info(output) - logs.Info(token) + // 如果没有开启匿名访问则跳转到登录 if !c.EnableAnonymous && !c.isUserLoggedIn() { - logs.Info(output) promptUserToLogIn(c) return } if !conf.GetEnableExport() { - logs.Info(output) c.ShowErrorPage(500, i18n.Tr(c.Lang, "export_func_disable")) } bookResult := models.NewBookResult() if c.Member != nil && c.Member.IsAdministrator() { - logs.Info(output) book, err := models.NewBook().FindByIdentify(identify) if err != nil { if err == orm.ErrNoRows { @@ -974,21 +1025,16 @@ func (c *DocumentController) Export() { } bookResult = models.NewBookResult().ToBookResult(*book) } else { - logs.Info(output) bookResult = c.isReadable(identify, token) } if !bookResult.IsDownload { - logs.Info(output) c.ShowErrorPage(200, i18n.Tr(c.Lang, "message.cur_project_export_func_disable")) } if !strings.HasPrefix(bookResult.Cover, "http:://") && !strings.HasPrefix(bookResult.Cover, "https:://") { - logs.Info(output) bookResult.Cover = conf.URLForWithCdnImage(bookResult.Cover) } - logs.Info(Markdown) if output == Markdown { - logs.Info("hah") if bookResult.Editor != EditorMarkdown && bookResult.Editor != EditorCherryMarkdown { c.ShowErrorPage(500, i18n.Tr(c.Lang, "message.cur_project_not_support_md")) } diff --git a/static/editor.md/plugins/image-dialog/image-dialog.js b/static/editor.md/plugins/image-dialog/image-dialog.js index 9909d6ed8..8fa5b45f9 100644 --- a/static/editor.md/plugins/image-dialog/image-dialog.js +++ b/static/editor.md/plugins/image-dialog/image-dialog.js @@ -46,149 +46,149 @@ action += "&callback=" + settings.uploadCallbackURL + "&dialog_id=editormd-image-dialog-" + guid; } - var dialogContent = ( (settings.imageUpload) ? "
" : "
" ) + - ( (settings.imageUpload) ? "" : "" ) + - "" + - "" + (function(){ - return (settings.imageUpload) ? "
" + - "" + - "" + - "
" : ""; - })() + - "
" + - "" + - "" + - "
" + - "" + - "" + - "
" + - ( (settings.imageUpload) ? "" : "
"); - - //var imageFooterHTML = ""; - - dialog = this.createDialog({ - title : imageLang.title, - width : (settings.imageUpload) ? 465 : 380, - height : 254, - name : dialogName, - content : dialogContent, - mask : settings.dialogShowMask, - drag : settings.dialogDraggable, - lockScreen : settings.dialogLockScreen, - maskStyle : { - opacity : settings.dialogMaskOpacity, - backgroundColor : settings.dialogMaskBgColor - }, - buttons : { - enter : [lang.buttons.enter, function() { - var url = this.find("[data-url]").val(); - var alt = this.find("[data-alt]").val(); - var link = this.find("[data-link]").val(); - - if (url === "") - { - alert(imageLang.imageURLEmpty); - return false; - } - - var altAttr = (alt !== "") ? " \"" + alt + "\"" : ""; - - if (link === "" || link === "http://") - { - cm.replaceSelection("![" + alt + "](" + url + altAttr + ")"); - } - else - { - cm.replaceSelection("[![" + alt + "](" + url + altAttr + ")](" + link + altAttr + ")"); - } - - if (alt === "") { - cm.setCursor(cursor.line, cursor.ch + 2); - } - - this.hide().lockScreen(false).hideMask(); - - return false; - }], - - cancel : [lang.buttons.cancel, function() { - this.hide().lockScreen(false).hideMask(); - - return false; - }] - } - }); - - dialog.attr("id", classPrefix + "image-dialog-" + guid); - - if (!settings.imageUpload) { - return ; + var dialogContent = ((settings.imageUpload) ? "
" : "
") + + ((settings.imageUpload) ? "" : "") + + "" + + "" + (function() { + return (settings.imageUpload) ? "
" + + // 3xxx multiple=\"multiple\" + "" + + "" + + "
" : ""; + })() + + "
" + + "" + + "" + + "
" + + "" + + "" + + "
" + + ((settings.imageUpload) ? "" : "
"); + //var imageFooterHTML = ""; + dialog = this.createDialog({ + title: imageLang.title, + width: (settings.imageUpload) ? 465 : 380, + height: 254, + name: dialogName, + content: dialogContent, + mask: settings.dialogShowMask, + drag: settings.dialogDraggable, + lockScreen: settings.dialogLockScreen, + maskStyle: { + opacity: settings.dialogMaskOpacity, + backgroundColor: settings.dialogMaskBgColor + }, + // ォͼƬַĵ + buttons: { + enter: [lang.buttons.enter, function() { + var url = this.find("[data-url]").val(); + var alt = this.find("[data-alt]").val(); + var link = this.find("[data-link]").val(); + if (url === "") { + alert(imageLang.imageURLEmpty); + return false; + } + // ѭ + let arr = url.split(";"); + var altAttr = (alt !== "") ? " \"" + alt + "\"" : ""; + for (let i = 0; i < arr.length; i++) { + if (link === "" || link === "http://") { + // cm.replaceSelection("![" + alt + "](" + url + altAttr + ")"); + cm.replaceSelection("![" + alt + "](" + arr[i] + altAttr + ")"); + } else { + // cm.replaceSelection("[![" + alt + "](" + url + altAttr + ")](" + link + altAttr + ")"); + cm.replaceSelection("[![" + alt + "](" + arr[i] + altAttr + ")](" + link + altAttr + ")"); } - - var fileInput = dialog.find("[name=\"" + classPrefix + "image-file\"]"); - - fileInput.bind("change", function() { - var fileName = fileInput.val(); - var isImage = new RegExp("(\\.(" + settings.imageFormats.join("|") + "))$"); // /(\.(webp|jpg|jpeg|gif|bmp|png))$/ - - if (fileName === "") - { - alert(imageLang.uploadFileEmpty); - - return false; - } - - if (!isImage.test(fileName)) - { - alert(imageLang.formatNotAllowed + settings.imageFormats.join(", ")); - - return false; - } - - loading(true); - - var submitHandler = function() { - - var uploadIframe = document.getElementById(iframeName); - - uploadIframe.onload = function() { - - loading(false); - - var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body; - var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null); - - json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")"); - - if (json.success === 1) - { - dialog.find("[data-url]").val(json.url); - } - else - { - alert(json.message); - } - - return false; - }; - }; - - dialog.find("[type=\"submit\"]").bind("click", submitHandler).trigger("click"); - }); + } + if (alt === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + this.hide().lockScreen(false).hideMask(); + return false; + }], + + cancel: [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + return false; + }] + } + }); + dialog.attr("id", classPrefix + "image-dialog-" + guid); + if (!settings.imageUpload) { + return; + } + var fileInput = dialog.find("[name=\"" + classPrefix + "image-file\"]"); + fileInput.bind("change", function() { + // 3xxx 20240602 + // let formData = new FormData(); + // ȡıdom + // var doc = document.getElementById('doc'); + // ȡϴؼdom + // var upload = document.getElementById('upload'); + // let files = upload.files; + //ļϢappendformData洢 + // for (let i = 0; i < files.length; i++) { + // let file = files[i] + // formData.append('files', file) + // } + // ȡļ + // var fileName = upload.files[0].name; + // ȡļ· + // var filePath = upload.value; + // doc.value = fileName; + // 3xxx + console.log(fileInput); + console.log(fileInput[0].files); + let files = fileInput[0].files; + for (let i = 0; i < files.length; i++) { + var fileName = files[i].name; + // var fileName = fileInput.val(); + var isImage = new RegExp("(\\.(" + settings.imageFormats.join("|") + "))$"); // /(\.(webp|jpg|jpeg|gif|bmp|png))$/ + if (fileName === "") { + alert(imageLang.uploadFileEmpty); + return false; } - - dialog = editor.find("." + dialogName); - dialog.find("[type=\"text\"]").val(""); - dialog.find("[type=\"file\"]").val(""); - dialog.find("[data-link]").val("http://"); - - this.dialogShowMask(dialog); - this.dialogLockScreen(); - dialog.show(); - - }; - - }; + if (!isImage.test(fileName)) { + alert(imageLang.formatNotAllowed + settings.imageFormats.join(", ")); + return false; + } + loading(true); + var submitHandler = function() { + var uploadIframe = document.getElementById(iframeName); + uploadIframe.onload = function() { + loading(false); + var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body; + var json = (body.innerText) ? body.innerText : ((body.textContent) ? body.textContent : null); + json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")"); + var url=""; + for (let i = 0; i < json.length; i++) { + if (json[i].success === 1) { + if (i==0){ + url=json[i].url; + }else{ + url=url+";"+json[i].url; + } + } else { + alert(json[i].message); + } + } + dialog.find("[data-url]").val(url) + return false; + }; + }; + dialog.find("[type=\"submit\"]").bind("click", submitHandler).trigger("click"); + } + }); + } + dialog = editor.find("." + dialogName); + dialog.find("[type=\"text\"]").val(""); + dialog.find("[type=\"file\"]").val(""); + dialog.find("[data-link]").val("http://"); + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + }; + }; // CommonJS/Node.js if (typeof require === "function" && typeof exports === "object" && typeof module === "object") From ec7faeec05eeab8632a32fcb87fd7f7e1b70988b Mon Sep 17 00:00:00 2001 From: 3xxx Date: Sun, 2 Jun 2024 23:58:15 +0800 Subject: [PATCH 2/2] modify js res.url --- static/js/blog.js | 6 ++++-- static/js/markdown.js | 7 +++++-- static/js/quill.js | 7 ++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/static/js/blog.js b/static/js/blog.js index 594806eae..de145ac46 100644 --- a/static/js/blog.js +++ b/static/js/blog.js @@ -53,8 +53,10 @@ $(function () { shade: [0.1, '#fff'] // 0.1 透明度的白色背景 }); } else if ($state === "success") { - if ($res.errcode === 0) { - var value = '![](' + $res.url + ')'; + // if ($res.errcode === 0) { + // var value = '![](' + $res.url + ')'; + if ($res[0].errcode === 0) { + var value = '![](' + $res[0].url + ')'; window.editor.insertValue(value); } } diff --git a/static/js/markdown.js b/static/js/markdown.js index c450e3ceb..778f06902 100644 --- a/static/js/markdown.js +++ b/static/js/markdown.js @@ -251,8 +251,11 @@ $(function () { shade: [0.1, '#fff'] // 0.1 透明度的白色背景 }); } else if ($state === "success") { - if ($res.errcode === 0) { - var value = '![](' + $res.url + ')'; + // if ($res.errcode === 0) { + // var value = '![](' + $res.url + ')'; + // 3xxx 20240602 + if ($res[0].errcode === 0) { + var value = '![](' + $res[0].url + ')'; window.editor.insertValue(value); } } diff --git a/static/js/quill.js b/static/js/quill.js index 4a4523aaf..7839c8864 100644 --- a/static/js/quill.js +++ b/static/js/quill.js @@ -77,10 +77,11 @@ $(function () { shade: [0.1, '#fff'] // 0.1 透明度的白色背景 }); } else if ($state === "success") { - if ($res.errcode === 0) { - + // if ($res.errcode === 0) { + if ($res[0].errcode === 0) { var range = window.editor.getSelection(); - window.editor.insertEmbed(range.index, 'image', $res.url); + // window.editor.insertEmbed(range.index, 'image', $res.url); + window.editor.insertEmbed(range.index, 'image', $res[0].url); } } });