Ver código fonte

uploads seems working.

master
sp 4 anos atrás
pai
commit
5f47d33299
11 arquivos alterados com 506 adições e 145 exclusões
  1. +1
    -0
      .idea/SFM_Loan_RestApi.iml
  2. +99
    -11
      UploadsOnDisk.go
  3. +30
    -0
      apiV1UploadAnalysis.go
  4. +95
    -0
      apiV1UploadAsImage.go
  5. +31
    -0
      apiV1UploadList.go
  6. +63
    -0
      apiV1UploadThumb.go
  7. +28
    -134
      apiV1Uploads.go
  8. +109
    -0
      apiV1UploadsAsPdf.go
  9. +12
    -0
      apiv1.go
  10. BIN
      assets/thumb_file_icon.webp
  11. +38
    -0
      fileUtil.go

+ 1
- 0
.idea/SFM_Loan_RestApi.iml Ver arquivo

@@ -2,6 +2,7 @@
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$USER_HOME$/GolandProjects/SFM-loan" />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

+ 99
- 11
UploadsOnDisk.go Ver arquivo

@@ -2,6 +2,7 @@ package main

import (
"biukop.com/sfm/loan"
"context"
"errors"
log "github.com/sirupsen/logrus"
"io/ioutil"
@@ -11,6 +12,8 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"time"
)

type uploadsOnDisk struct {
@@ -114,9 +117,10 @@ func (m *uploadsOnDisk) convertExcelToJpg() (e error) {
return m.convertExcelTo("jpg")
}

var libreOfficeMutex sync.Mutex // make sure we only have one libreoffice running at a time
func (m *uploadsOnDisk) convertExcelTo(format string) (e error) {
if format != "pdf" && format != "jpg" {
e = errors.New("unsupported format")
e = errors.New("convert excel to unsupported format " + format)
return
}

@@ -132,12 +136,59 @@ func (m *uploadsOnDisk) convertExcelTo(format string) (e error) {
}
defer os.RemoveAll(dir)

cmd := exec.Command("libreoffice", "--convert-to", format, "--outdir", dir, m.filePath())
strCmd := cmd.String()
log.Debug("command is ", strCmd)
// Create a new context and add a timeout to it
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() // The cancel should be deferred so resources are cleaned up

// Create the command with our context
cmd := exec.CommandContext(ctx, "libreoffice", "--convert-to", format, "--outdir", dir, m.filePath())

libreOfficeMutex.Lock() //ensure only one libreoffice is running
// This time we can simply use Output() to get the result.
out, e := cmd.Output()
libreOfficeMutex.Unlock()

// We want to check the context error to see if the timeout was executed.
// The error returned by cmd.Output() will be OS specific based on what
// happens when a process is killed.
if ctx.Err() == context.DeadlineExceeded {
log.Error(cmd.String(), " timed out")

switch format {
case "pdf":
_, e = copyFile(config.UploadsDir.PdfDefault, m.pdfPath())
break
case "jpg":
_, e = copyFile(config.UploadsDir.JpgDefault, m.jpgPath())
break
}
return
}

// If there's no context error, we know the command completed (or errored).
//fmt.Println("Output:", string(out))
//if err != nil {
// fmt.Println("Non-zero exit code:", err)
//}

// ---------- for cases not using ctx
// for some unknown reason, libreoffice may just hung for ever
//cmd := exec.Command("libreoffice", "--convert-to", format, "--outdir", dir, m.filePath())
//strCmd := cmd.String()
//log.Debug("command is ", strCmd)
//out, e := cmd.Output()
// ------------ end of without ctx

if e != nil {
log.Error("cannot converting Excel to "+format+":", m.Upload, e)
switch format {
case "pdf":
_, e = copyFile(config.UploadsDir.PdfDefault, m.pdfPath())
break
case "jpg":
_, e = copyFile(config.UploadsDir.JpgDefault, m.jpgPath())
break
}
return
} else { // success
log.Info("convert to "+format, m.Upload, " output: ", string(out))
@@ -177,6 +228,7 @@ func (m *uploadsOnDisk) convertPDFToJpg() (e error) {
out, e := cmd.Output()
if e != nil {
log.Error("cannot create png file for PDF", m.Upload, e)
_, e = copyFile(config.UploadsDir.JpgDefault, m.jpgPath())
return
} else {
log.Info("convert ", m.Upload, " output: ", string(out))
@@ -184,8 +236,8 @@ func (m *uploadsOnDisk) convertPDFToJpg() (e error) {

// montage -mode concatenate -tile 1x 30*png 30.jpg
if fileExists(target) { // single file,
e = os.Rename(target, m.jpgPath()) // there should be only one jpg
_ = ConvertImageToThumbnail(target, m.thumbPath(), 256)
e = os.Rename(target, m.jpgPath()) // there should be only one jpg
} else { // multi-page, we have -0 -1 -2 -3 -4 files
firstPage := dir + string(os.PathSeparator) + "result-0.jpg"
_ = ConvertImageToThumbnail(firstPage, m.thumbPath(), 256)
@@ -245,6 +297,44 @@ func (m *uploadsOnDisk) GetFileType() (ret string, e error) {
return "", nil
}

func (m *uploadsOnDisk) DeleteAll() (e error) {
eJpg := os.Remove(m.jpgPath())
eFile := os.Remove(m.filePath())
ePdf := os.Remove(m.pdfPath())
eThumb := os.Remove(m.thumbPath())
eMeta := m.Upload.Delete()

strId := strconv.Itoa(int(m.Upload.Id))

errMsg := ""
if eJpg != nil {
errMsg += " jpg "
}

if eFile != nil {
errMsg += " original "
}

if ePdf != nil {
errMsg += " pdf "
}

if eThumb != nil {
errMsg += " thumb "
}

if eMeta != nil {
errMsg += " Meta in DB "
e = errors.New(errMsg + " cannot be deleted " + strId)
}

if errMsg != "" {
log.Error(errMsg, "files on disk cannot be deleted need disk cleaning ", m.Upload)
}
return
}

// GetFileContentType
// tested, not accurate with xls, xlsx, it becomes zip and octstream sometime.
func GetFileContentType(filename string) (contentType string, e error) {
contentType = ""
@@ -257,7 +347,7 @@ func GetFileContentType(filename string) (contentType string, e error) {
return
}

// Use the net/http package's handy DectectContentType function. Always returns a valid
// Use the net/http package's handy Detect ContentType function. Always returns a valid
// content-type by returning "application/octet-stream" if no others seemed to match.
contentType = http.DetectContentType(buffer)
return
@@ -268,7 +358,7 @@ func ConvertImageToThumbnail(srcPath string, dstPath string, size int) (e error)
log.Info("skip converting thumbnail it exists", dstPath)
return
}
if size <= 0 {
if size <= 0 { //thumb nail width
size = 256
}
// convert -thumbnail 200 abc.png thumb.abc.png
@@ -278,13 +368,11 @@ func ConvertImageToThumbnail(srcPath string, dstPath string, size int) (e error)

out, e := cmd.Output()
if e != nil {
log.Error("Failed to convert thumbnail", e)
_, e = copyFile(config.UploadsDir.ThumbDefault, dstPath)
return
} else { // success
log.Info("success output: \n: ", string(out))
}
return
}

func fileNameWithoutExtTrimSuffix(fileName string) string {
return strings.TrimSuffix(fileName, filepath.Ext(fileName))
}

+ 30
- 0
apiV1UploadAnalysis.go Ver arquivo

@@ -5,6 +5,7 @@ import (
log "github.com/sirupsen/logrus"
"net/http"
"strconv"
"time"
)

func apiV1UploadAnalysis(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
@@ -33,3 +34,32 @@ func apiV1UploadAnalysis(w http.ResponseWriter, r *http.Request, ss *loan.Sessio
}
apiV1SendJson(ai, w, r, ss)
}

func apiV1UploadCreateAnalysis(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
time.Sleep(1 * time.Second)

strId := r.URL.Path[len(apiV1Prefix+"upload-analysis/"):] //remove prefix
Id, e := strconv.Atoi(strId)
if e != nil {
log.Error("Invalid uploads Id cannot convert to integer", Id, e)
apiV1Client403Error(w, r, ss)
return
}

ul := loan.Uploads{}
e = ul.Read(int64(Id))
if e != nil {
log.Error("Upload not found or read error from db", Id, e)
apiV1Client404Error(w, r, ss)
return
}

ai := AiDecodeIncome{}
e = ai.decodeUploadToPayIn(ul)
if e != nil {
log.Error("Cannot decode upload", Id, e)
apiV1Server500Error(w, r)
return
}
apiV1SendJson(ai, w, r, ss)
}

+ 95
- 0
apiV1UploadAsImage.go Ver arquivo

@@ -0,0 +1,95 @@
package main

import (
"biukop.com/sfm/loan"
log "github.com/sirupsen/logrus"
"net/http"
"os"
"strings"
)

func apiV1UploadAsImage(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
// time.Sleep(5* time.Second)

strId := r.URL.Path[len(apiV1Prefix+"upload-as-image/"):] //remove prefix
if strId == "default" {
http.ServeFile(w, r, config.UploadsDir.JpgDefault)
return
}

ul, e := getRequestedUpload(strId, w, r, ss)
if e != nil {
return
}

// if this is image itself, serve it directly
if strings.Contains(strings.ToLower(ul.Upload.Format), "image") {
f, e := os.Open(ul.filePath())
if e == nil {
defer f.Close()
fi, e := f.Stat()
if e == nil {
//w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName)
http.ServeContent(w, r, ul.filePath(), fi.ModTime(), f)
return
}
}
// if we reach here, some err has happened
log.Error("failed to serve image file ", ul, e)
apiV1Server500Error(w, r)
return
}

// see if a converted image exist, if not convert it and then send
if !fileExists(ul.jpgPath()) {
e = ul.convertUploadsToJpg()
if e != nil {
// serve a default no preview is available
http.ServeFile(w, r, config.UploadsDir.JpgDefault)
log.Error("error creating preview image", ul, e)
return
}
}
if fileExists(ul.jpgPath()) {
http.ServeFile(w, r, ul.jpgPath())
return
} else {
apiV1Client404Error(w, r, ss)
}

}
func apiV1UploadCreateImage(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
//time.Sleep(1 * time.Second)

strId := r.URL.Path[len(apiV1Prefix+"upload-as-image/"):] //remove prefix
if strId == "" {
apiV1Client404Error(w, r, ss)
return
}

ul, e := getRequestedUpload(strId, w, r, ss)
if e != nil {
return
}

// if this is image itself, serve it directly
if strings.Contains(strings.ToLower(ul.Upload.Format), "image") {
apiV1SendJson(true, w, r, ss)
return
}

// see if a converted image exist, if not convert it and then send
if !fileExists(ul.jpgPath()) {
e = ul.convertUploadsToJpg()
if e != nil {
log.Error("error creating preview image", ul, e)
}
}

if fileExists(ul.jpgPath()) {
apiV1SendJson(true, w, r, ss)
return
} else {
apiV1SendJson(false, w, r, ss)
}
}

+ 31
- 0
apiV1UploadList.go Ver arquivo

@@ -0,0 +1,31 @@
package main

import (
"biukop.com/sfm/loan"
"encoding/json"
log "github.com/sirupsen/logrus"
"net/http"
)

func decodeUploadsMetaListFilter(r *http.Request) (ret loan.UploadListFilter, e error) {
decoder := json.NewDecoder(r.Body)
e = decoder.Decode(&ret)
if e != nil {
log.Error("failed decoding Upload Filter", e.Error())
return
}
return
}

func apiV1UploadMetaList(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
filter, e := decodeUploadsMetaListFilter(r)
if e != nil {
log.Println("invalid filter", e)
apiV1Client403Error(w, r, ss) // bad request
return
}

data := loan.GetUploadMetaList(filter)

apiV1SendJson(data, w, r, ss)
}

+ 63
- 0
apiV1UploadThumb.go Ver arquivo

@@ -0,0 +1,63 @@
package main

import (
"biukop.com/sfm/loan"
log "github.com/sirupsen/logrus"
"net/http"
)

func apiV1UploadAsThumbnail(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
strId := r.URL.Path[len(apiV1Prefix+"upload-as-thumbnail/"):] //remove prefix
if strId == "default" {
http.ServeFile(w, r, config.UploadsDir.ThumbDefault)
return
}
ul, e := getRequestedUpload(strId, w, r, ss)
if e != nil {
return
}

// see if a thumbnail is available already
if !fileExists(ul.thumbPath()) {
e = ul.convertUploadsToThumb()
if e != nil {
// serve a default no preview is available
http.ServeFile(w, r, config.UploadsDir.ThumbDefault)
log.Error("error creating preview image", ul, e)
return
}
}
if fileExists(ul.thumbPath()) {
http.ServeFile(w, r, ul.thumbPath())
return
} else {
apiV1Client404Error(w, r, ss)
}
}

func apiV1UploadCreateThumbnail(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
//time.Sleep(1 * time.Second)
strId := r.URL.Path[len(apiV1Prefix+"upload-as-thumbnail/"):] //remove prefix
if strId == "" {
apiV1Client404Error(w, r, ss)
return
}
ul, e := getRequestedUpload(strId, w, r, ss)
if e != nil {
return
}

// see if a thumbnail is available already
if !fileExists(ul.thumbPath()) {
e = ul.convertUploadsToThumb()
if e != nil {
log.Error("error creating thumbNail image", ul, e)
}
}
if fileExists(ul.thumbPath()) {
apiV1SendJson(true, w, r, ss)
return
} else {
apiV1SendJson(false, w, r, ss)
}
}

+ 28
- 134
apiV1Uploads.go Ver arquivo

@@ -11,7 +11,6 @@ import (
"net/http"
"os"
"strconv"
"strings"
"time"
)

@@ -34,6 +33,34 @@ func apiV1UploadMetaGet(w http.ResponseWriter, r *http.Request, ss *loan.Session
apiV1SendJson(ulmeta, w, r, ss)
}

func apiV1UploadDelete(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
id := r.URL.Path[len(apiV1Prefix+"upload/"):] //remove prefix
intId, e := strconv.Atoi(id)
if e != nil {
log.Println("invalid id for upload get", id, e)
apiV1Client403Error(w, r, ss) // bad request
return
}

ul := uploadsOnDisk{}
ul.Upload = loan.Uploads{}
e = ul.Upload.Read(int64(intId))
if e != nil {
log.Println("upload not found", id, e)
apiV1Client404Error(w, r, ss) // bad request
return
}

e = ul.DeleteAll()
if e != nil {
log.Println("upload cannot be deleted", id, e)
apiV1Server500Error(w, r) // bad operation
return
}

apiV1SendJson(ul.Upload, w, r, ss)
}

func apiV1UploadOriginalFileGet(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
id := r.URL.Path[len(apiV1Prefix+"upload-original/"):] //remove prefix
intId, e := strconv.Atoi(id)
@@ -235,139 +262,6 @@ func getRequestedUpload(strId string, w http.ResponseWriter, r *http.Request, ss
return
}

func apiV1UploadAsImage(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
strId := r.URL.Path[len(apiV1Prefix+"upload-as-image/"):] //remove prefix
if strId == "default" {
http.ServeFile(w, r, config.UploadsDir.JpgDefault)
return
}

ul, e := getRequestedUpload(strId, w, r, ss)
if e != nil {
return
}
//time.Sleep(5* time.Second);
// if this is image itself, serve it directly
if strings.Contains(strings.ToLower(ul.Upload.Format), "image") {
f, e := os.Open(ul.filePath())
if e == nil {
defer f.Close()
fi, e := f.Stat()
if e == nil {
//w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName)
http.ServeContent(w, r, ul.filePath(), fi.ModTime(), f)
return
}
}
// if we reach here, some err has happened
log.Error("failed to serve image file ", ul, e)
apiV1Server500Error(w, r)
return
}

// see if a converted image exist, if not convert it and then send
if !fileExists(ul.jpgPath()) {
e = ul.convertUploadsToJpg()
if e != nil {
// serve a default no preview is available
http.ServeFile(w, r, config.UploadsDir.JpgDefault)
log.Error("error creating preview image", ul, e)
return
}
}
if fileExists(ul.jpgPath()) {
http.ServeFile(w, r, ul.jpgPath())
return
} else {
apiV1Client404Error(w, r, ss)
}

}
func apiV1UploadAsThumbnail(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
strId := r.URL.Path[len(apiV1Prefix+"upload-as-thumbnail/"):] //remove prefix
if strId == "default" {
http.ServeFile(w, r, config.UploadsDir.ThumbDefault)
return
}
ul, e := getRequestedUpload(strId, w, r, ss)
if e != nil {
return
}

// see if a thumbnail is available already
if !fileExists(ul.thumbPath()) {
e = ul.convertUploadsToThumb()
if e != nil {
// serve a default no preview is available
http.ServeFile(w, r, config.UploadsDir.ThumbDefault)
log.Error("error creating preview image", ul, e)
return
}
}
if fileExists(ul.thumbPath()) {
http.ServeFile(w, r, ul.thumbPath())
return
} else {
apiV1Client404Error(w, r, ss)
}
}

func apiV1UploadAsPDF(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
strId := r.URL.Path[len(apiV1Prefix+"upload-as-pdf/"):] //remove prefix
if strId == "default" {
http.ServeFile(w, r, config.UploadsDir.PdfDefault)
return
}
ul, e := getRequestedUpload(strId, w, r, ss)
if e != nil {
return
}

//get file type
fileType, e := ul.GetFileType()
if e != nil {
apiV1Client403Error(w, r, ss)
return
}

// if its ready pdf, no need to convert
if fileType == "pdf" {
f, e := os.Open(ul.filePath())
if e == nil {
defer f.Close()
fi, e := f.Stat()
if e == nil {
if forceHttpDownload(r) {
w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName)
}
http.ServeContent(w, r, ul.Upload.FileName, fi.ModTime(), f)
return
}
}
// if we reach here, some err has happened
log.Error("failed to serve pdf file ", ul, e)
apiV1Server500Error(w, r)
return
}

// see if a converted pdf exist, if not convert it and then send
if !fileExists(ul.pdfPath()) {
e = ul.convertUploadsToPDF()
if e != nil {
// serve a default no preview is available
http.ServeFile(w, r, config.UploadsDir.PdfDefault)
log.Error("error creating preview image", ul, e)
return
}
}
if fileExists(ul.pdfPath()) {
http.ServeFile(w, r, ul.pdfPath())
return
} else {
apiV1Client404Error(w, r, ss)
}
}

func forceHttpDownload(r *http.Request) bool {
keys, ok := r.URL.Query()["download"]


+ 109
- 0
apiV1UploadsAsPdf.go Ver arquivo

@@ -0,0 +1,109 @@
package main

import (
"biukop.com/sfm/loan"
log "github.com/sirupsen/logrus"
"net/http"
"os"
)

func apiV1UploadAsPDF(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
strId := r.URL.Path[len(apiV1Prefix+"upload-as-pdf/"):] //remove prefix
if strId == "default" {
http.ServeFile(w, r, config.UploadsDir.PdfDefault)
return
}
ul, e := getRequestedUpload(strId, w, r, ss)
if e != nil {
return
}

//get file type
fileType, e := ul.GetFileType()
if e != nil {
apiV1Client403Error(w, r, ss)
return
}

// if its ready pdf, no need to convert
if fileType == "pdf" {
f, e := os.Open(ul.filePath())
if e == nil {
defer f.Close()
fi, e := f.Stat()
if e == nil {
if forceHttpDownload(r) {
w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName)
}
http.ServeContent(w, r, ul.Upload.FileName, fi.ModTime(), f)
return
}
}
// if we reach here, some err has happened
log.Error("failed to serve pdf file ", ul, e)
apiV1Server500Error(w, r)
return
}

// see if a converted pdf exist, if not convert it and then send
if !fileExists(ul.pdfPath()) {
e = ul.convertUploadsToPDF()
if e != nil {
// serve a default no preview is available
http.ServeFile(w, r, config.UploadsDir.PdfDefault)
log.Error("error creating preview image", ul, e)
return
}
}
if fileExists(ul.pdfPath()) {
http.ServeFile(w, r, ul.pdfPath())
return
} else {
apiV1Client404Error(w, r, ss)
}
}

func apiV1UploadCreatePDF(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
//time.Sleep(1* time.Second)

strId := r.URL.Path[len(apiV1Prefix+"upload-as-pdf/"):] //remove prefix
if strId == "" {
apiV1Client404Error(w, r, ss)
return
}
ul, e := getRequestedUpload(strId, w, r, ss)
if e != nil {
return
}

//get file type
fileType, e := ul.GetFileType()
if e != nil {
apiV1Client403Error(w, r, ss)
return
}

// if its ready pdf, no need to convert
if fileType == "pdf" {
apiV1SendJson(true, w, r, ss)
return
}

// see if a converted pdf exist, if not convert it and then send
if !fileExists(ul.pdfPath()) {
e = ul.convertUploadsToPDF()
if e != nil {
log.Error("error creating pdf", ul, e)
_, e = copyFile(config.UploadsDir.PdfDefault, ul.pdfPath())
if e != nil {
log.Error("failed copy default pdf", e)
}
}
}
if fileExists(ul.pdfPath()) {
apiV1SendJson(true, w, r, ss)
return
} else {
apiV1SendJson(false, w, r, ss)
}
}

+ 12
- 0
apiv1.go Ver arquivo

@@ -78,11 +78,17 @@ func setupApiV1Handler() []apiV1HandlerMap {
{"GET", "lender-upload/", apiV1UploadOriginalFileGet},

{"GET", "upload-analysis/", apiV1UploadAnalysis},
{"PUT", "upload-analysis/", apiV1UploadCreateAnalysis},
{"GET", "upload-as-image/", apiV1UploadAsImage},
{"PUT", "upload-as-image/", apiV1UploadCreateImage},
{"GET", "upload-as-thumbnail/", apiV1UploadAsThumbnail},
{"PUT", "upload-as-thumbnail/", apiV1UploadCreateThumbnail},
{"GET", "upload-as-pdf/", apiV1UploadAsPDF},
{"PUT", "upload-as-pdf/", apiV1UploadCreatePDF},
{"GET", "upload-original/", apiV1UploadOriginalFileGet},
{"GET", "upload/", apiV1UploadMetaGet},
{"DELETE", "upload/", apiV1UploadDelete},
{"POST", "upload-meta-list/", apiV1UploadMetaList},

{"GET", "login", apiV1DumpRequest},
}
@@ -139,11 +145,17 @@ func setupApiV1Handler() []apiV1HandlerMap {
{"GET", "lender-upload/", apiV1UploadOriginalFileGet},

{"GET", "upload-analysis/", apiV1UploadAnalysis},
{"PUT", "upload-analysis/", apiV1UploadCreateAnalysis},
{"GET", "upload-as-image/", apiV1UploadAsImage},
{"PUT", "upload-as-image/", apiV1UploadCreateImage},
{"GET", "upload-as-thumbnail/", apiV1UploadAsThumbnail},
{"PUT", "upload-as-thumbnail/", apiV1UploadCreateThumbnail},
{"GET", "upload-as-pdf/", apiV1UploadAsPDF},
{"PUT", "upload-as-pdf/", apiV1UploadCreatePDF},
{"GET", "upload-original/", apiV1UploadOriginalFileGet},
{"GET", "upload-meta/", apiV1UploadMetaGet},
{"DELETE", "upload/", apiV1UploadDelete},
{"POST", "upload-meta-list/", apiV1UploadMetaList},

{"GET", "login", apiV1EmptyResponse},
}

BIN
assets/thumb_file_icon.webp Ver arquivo

Antes Depois

+ 38
- 0
fileUtil.go Ver arquivo

@@ -0,0 +1,38 @@
package main

import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
)

func fileNameWithoutExtTrimSuffix(fileName string) string {
return strings.TrimSuffix(fileName, filepath.Ext(fileName))
}

func copyFile(src, dst string) (int64, error) {
sourceFileStat, err := os.Stat(src)
if err != nil {
return 0, err
}

if !sourceFileStat.Mode().IsRegular() {
return 0, fmt.Errorf("%s is not a regular file", src)
}

source, err := os.Open(src)
if err != nil {
return 0, err
}
defer source.Close()

destination, err := os.Create(dst)
if err != nil {
return 0, err
}
defer destination.Close()
nBytes, err := io.Copy(destination, source)
return nBytes, err
}

Carregando…
Cancelar
Salvar