| @@ -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" /> | |||
| @@ -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)) | |||
| } | |||
| @@ -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) | |||
| } | |||
| @@ -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) | |||
| } | |||
| } | |||
| @@ -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) | |||
| } | |||
| @@ -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) | |||
| } | |||
| } | |||
| @@ -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"] | |||
| @@ -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) | |||
| } | |||
| } | |||
| @@ -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}, | |||
| } | |||
| @@ -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 | |||
| } | |||