| <module type="WEB_MODULE" version="4"> | <module type="WEB_MODULE" version="4"> | ||||
| <component name="Go" enabled="true" /> | <component name="Go" enabled="true" /> | ||||
| <component name="NewModuleRootManager"> | <component name="NewModuleRootManager"> | ||||
| <content url="file://$USER_HOME$/GolandProjects/SFM-loan" /> | |||||
| <content url="file://$MODULE_DIR$" /> | <content url="file://$MODULE_DIR$" /> | ||||
| <orderEntry type="inheritedJdk" /> | <orderEntry type="inheritedJdk" /> | ||||
| <orderEntry type="sourceFolder" forTests="false" /> | <orderEntry type="sourceFolder" forTests="false" /> |
| import ( | import ( | ||||
| "biukop.com/sfm/loan" | "biukop.com/sfm/loan" | ||||
| "context" | |||||
| "errors" | "errors" | ||||
| log "github.com/sirupsen/logrus" | log "github.com/sirupsen/logrus" | ||||
| "io/ioutil" | "io/ioutil" | ||||
| "path/filepath" | "path/filepath" | ||||
| "strconv" | "strconv" | ||||
| "strings" | "strings" | ||||
| "sync" | |||||
| "time" | |||||
| ) | ) | ||||
| type uploadsOnDisk struct { | type uploadsOnDisk struct { | ||||
| return m.convertExcelTo("jpg") | 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) { | func (m *uploadsOnDisk) convertExcelTo(format string) (e error) { | ||||
| if format != "pdf" && format != "jpg" { | if format != "pdf" && format != "jpg" { | ||||
| e = errors.New("unsupported format") | |||||
| e = errors.New("convert excel to unsupported format " + format) | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| defer os.RemoveAll(dir) | 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() | 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 { | if e != nil { | ||||
| log.Error("cannot converting Excel to "+format+":", m.Upload, e) | 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 | return | ||||
| } else { // success | } else { // success | ||||
| log.Info("convert to "+format, m.Upload, " output: ", string(out)) | log.Info("convert to "+format, m.Upload, " output: ", string(out)) | ||||
| out, e := cmd.Output() | out, e := cmd.Output() | ||||
| if e != nil { | if e != nil { | ||||
| log.Error("cannot create png file for PDF", m.Upload, e) | log.Error("cannot create png file for PDF", m.Upload, e) | ||||
| _, e = copyFile(config.UploadsDir.JpgDefault, m.jpgPath()) | |||||
| return | return | ||||
| } else { | } else { | ||||
| log.Info("convert ", m.Upload, " output: ", string(out)) | log.Info("convert ", m.Upload, " output: ", string(out)) | ||||
| // montage -mode concatenate -tile 1x 30*png 30.jpg | // montage -mode concatenate -tile 1x 30*png 30.jpg | ||||
| if fileExists(target) { // single file, | if fileExists(target) { // single file, | ||||
| e = os.Rename(target, m.jpgPath()) // there should be only one jpg | |||||
| _ = ConvertImageToThumbnail(target, m.thumbPath(), 256) | _ = 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 | } else { // multi-page, we have -0 -1 -2 -3 -4 files | ||||
| firstPage := dir + string(os.PathSeparator) + "result-0.jpg" | firstPage := dir + string(os.PathSeparator) + "result-0.jpg" | ||||
| _ = ConvertImageToThumbnail(firstPage, m.thumbPath(), 256) | _ = ConvertImageToThumbnail(firstPage, m.thumbPath(), 256) | ||||
| return "", nil | 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. | // tested, not accurate with xls, xlsx, it becomes zip and octstream sometime. | ||||
| func GetFileContentType(filename string) (contentType string, e error) { | func GetFileContentType(filename string) (contentType string, e error) { | ||||
| contentType = "" | contentType = "" | ||||
| return | 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. | // content-type by returning "application/octet-stream" if no others seemed to match. | ||||
| contentType = http.DetectContentType(buffer) | contentType = http.DetectContentType(buffer) | ||||
| return | return | ||||
| log.Info("skip converting thumbnail it exists", dstPath) | log.Info("skip converting thumbnail it exists", dstPath) | ||||
| return | return | ||||
| } | } | ||||
| if size <= 0 { | |||||
| if size <= 0 { //thumb nail width | |||||
| size = 256 | size = 256 | ||||
| } | } | ||||
| // convert -thumbnail 200 abc.png thumb.abc.png | // convert -thumbnail 200 abc.png thumb.abc.png | ||||
| out, e := cmd.Output() | out, e := cmd.Output() | ||||
| if e != nil { | if e != nil { | ||||
| log.Error("Failed to convert thumbnail", e) | |||||
| _, e = copyFile(config.UploadsDir.ThumbDefault, dstPath) | |||||
| return | return | ||||
| } else { // success | } else { // success | ||||
| log.Info("success output: \n: ", string(out)) | log.Info("success output: \n: ", string(out)) | ||||
| } | } | ||||
| return | return | ||||
| } | } | ||||
| func fileNameWithoutExtTrimSuffix(fileName string) string { | |||||
| return strings.TrimSuffix(fileName, filepath.Ext(fileName)) | |||||
| } |
| log "github.com/sirupsen/logrus" | log "github.com/sirupsen/logrus" | ||||
| "net/http" | "net/http" | ||||
| "strconv" | "strconv" | ||||
| "time" | |||||
| ) | ) | ||||
| func apiV1UploadAnalysis(w http.ResponseWriter, r *http.Request, ss *loan.Session) { | func apiV1UploadAnalysis(w http.ResponseWriter, r *http.Request, ss *loan.Session) { | ||||
| } | } | ||||
| apiV1SendJson(ai, w, r, ss) | 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) | |||||
| } |
| 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) | |||||
| } | |||||
| } |
| 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) | |||||
| } |
| 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) | |||||
| } | |||||
| } |
| "net/http" | "net/http" | ||||
| "os" | "os" | ||||
| "strconv" | "strconv" | ||||
| "strings" | |||||
| "time" | "time" | ||||
| ) | ) | ||||
| apiV1SendJson(ulmeta, w, r, ss) | 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) { | func apiV1UploadOriginalFileGet(w http.ResponseWriter, r *http.Request, ss *loan.Session) { | ||||
| id := r.URL.Path[len(apiV1Prefix+"upload-original/"):] //remove prefix | id := r.URL.Path[len(apiV1Prefix+"upload-original/"):] //remove prefix | ||||
| intId, e := strconv.Atoi(id) | intId, e := strconv.Atoi(id) | ||||
| return | 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 { | func forceHttpDownload(r *http.Request) bool { | ||||
| keys, ok := r.URL.Query()["download"] | keys, ok := r.URL.Query()["download"] | ||||
| 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) | |||||
| } | |||||
| } |
| {"GET", "lender-upload/", apiV1UploadOriginalFileGet}, | {"GET", "lender-upload/", apiV1UploadOriginalFileGet}, | ||||
| {"GET", "upload-analysis/", apiV1UploadAnalysis}, | {"GET", "upload-analysis/", apiV1UploadAnalysis}, | ||||
| {"PUT", "upload-analysis/", apiV1UploadCreateAnalysis}, | |||||
| {"GET", "upload-as-image/", apiV1UploadAsImage}, | {"GET", "upload-as-image/", apiV1UploadAsImage}, | ||||
| {"PUT", "upload-as-image/", apiV1UploadCreateImage}, | |||||
| {"GET", "upload-as-thumbnail/", apiV1UploadAsThumbnail}, | {"GET", "upload-as-thumbnail/", apiV1UploadAsThumbnail}, | ||||
| {"PUT", "upload-as-thumbnail/", apiV1UploadCreateThumbnail}, | |||||
| {"GET", "upload-as-pdf/", apiV1UploadAsPDF}, | {"GET", "upload-as-pdf/", apiV1UploadAsPDF}, | ||||
| {"PUT", "upload-as-pdf/", apiV1UploadCreatePDF}, | |||||
| {"GET", "upload-original/", apiV1UploadOriginalFileGet}, | {"GET", "upload-original/", apiV1UploadOriginalFileGet}, | ||||
| {"GET", "upload/", apiV1UploadMetaGet}, | {"GET", "upload/", apiV1UploadMetaGet}, | ||||
| {"DELETE", "upload/", apiV1UploadDelete}, | |||||
| {"POST", "upload-meta-list/", apiV1UploadMetaList}, | |||||
| {"GET", "login", apiV1DumpRequest}, | {"GET", "login", apiV1DumpRequest}, | ||||
| } | } | ||||
| {"GET", "lender-upload/", apiV1UploadOriginalFileGet}, | {"GET", "lender-upload/", apiV1UploadOriginalFileGet}, | ||||
| {"GET", "upload-analysis/", apiV1UploadAnalysis}, | {"GET", "upload-analysis/", apiV1UploadAnalysis}, | ||||
| {"PUT", "upload-analysis/", apiV1UploadCreateAnalysis}, | |||||
| {"GET", "upload-as-image/", apiV1UploadAsImage}, | {"GET", "upload-as-image/", apiV1UploadAsImage}, | ||||
| {"PUT", "upload-as-image/", apiV1UploadCreateImage}, | |||||
| {"GET", "upload-as-thumbnail/", apiV1UploadAsThumbnail}, | {"GET", "upload-as-thumbnail/", apiV1UploadAsThumbnail}, | ||||
| {"PUT", "upload-as-thumbnail/", apiV1UploadCreateThumbnail}, | |||||
| {"GET", "upload-as-pdf/", apiV1UploadAsPDF}, | {"GET", "upload-as-pdf/", apiV1UploadAsPDF}, | ||||
| {"PUT", "upload-as-pdf/", apiV1UploadCreatePDF}, | |||||
| {"GET", "upload-original/", apiV1UploadOriginalFileGet}, | {"GET", "upload-original/", apiV1UploadOriginalFileGet}, | ||||
| {"GET", "upload-meta/", apiV1UploadMetaGet}, | {"GET", "upload-meta/", apiV1UploadMetaGet}, | ||||
| {"DELETE", "upload/", apiV1UploadDelete}, | |||||
| {"POST", "upload-meta-list/", apiV1UploadMetaList}, | |||||
| {"GET", "login", apiV1EmptyResponse}, | {"GET", "login", apiV1EmptyResponse}, | ||||
| } | } |
| 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 | |||||
| } |