|
- package main
-
- import (
- "biukop.com/sfm/loan"
- "crypto/sha256"
- "errors"
- "fmt"
- log "github.com/sirupsen/logrus"
- "io"
- "io/ioutil"
- "net/http"
- "os"
- "strconv"
- "strings"
- "time"
- )
-
- func apiV1UploadMetaGet(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
- id := r.URL.Path[len(apiV1Prefix+"upload-meta/"):] //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
- }
-
- ulmeta := loan.Uploads{}
- e = ulmeta.Read(int64(intId))
- if e != nil {
- log.Println("upload not found", id, e)
- apiV1Client404Error(w, r, ss) // bad request
- return
- }
- apiV1SendJson(ulmeta, 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)
- if e != nil {
- log.Println("invalid id for upload get", id, e)
- apiV1Client403Error(w, r, ss) // bad request
- return
- }
-
- ul := uploadsOnDisk{}
- e = ul.Upload.Read(int64(intId))
- if e != nil {
- log.Println("no file uploaded", intId, e)
- apiV1Client404Error(w, r, ss) // bad request
- return
- }
-
- //check local file first
- path := ul.filePath()
- if fileExists(path) {
- http.ServeFile(w, r, path)
- return
- }
-
- log.Error("Upload file not found on disk", ul)
- apiV1Server500Error(w, r) // bad request
- }
-
- func apiV1UploadsPost(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
- id := r.URL.Path[len(apiV1Prefix+"lender-upload/"):] //remove prefix
-
- filepath, e := saveUploadToFile(r)
- if e != nil {
- log.Println("no file uploaded", filepath, e)
- apiV1Client404Error(w, r, ss) // bad request
- return
- }
-
- intId, e := strconv.Atoi(id)
- if id != "" {
- if e != nil {
- log.Println("Error Getting File", e)
- apiV1Client404Error(w, r, ss) // bad request
- return
- }
- updateUploads(int64(intId), filepath, w, r, ss)
- } else {
- createUploads(filepath, w, r, ss)
- }
- }
-
- func sha256File(input io.Reader) string {
- hash := sha256.New()
- if _, err := io.Copy(hash, input); err != nil {
- log.Fatal(err)
- }
- sum := hash.Sum(nil)
-
- return fmt.Sprintf("%x", sum)
- }
-
- func updateUploads(id int64, filePath string, w http.ResponseWriter, r *http.Request, ss *loan.Session) {
- ul := uploadsOnDisk{}
- e := ul.Upload.Read(int64(id))
- if e != nil {
- log.Println("bad upload id is given ", id, e)
- apiV1Client404Error(w, r, ss) // bad request
- return
- }
-
- ul1, isDuplicate, e := saveUploadsMetaToDB(id, filePath, r, ss)
- ul.Upload.IsDuplicate = isDuplicate
- if e != nil {
- os.Remove(ul.filePath())
- ul1.Delete()
- log.Println("cannot save file info to db ", e)
- apiV1Server500Error(w, r) // bad request
- return
- }
-
- apiV1SendJson(ul1, w, r, ss)
- }
-
- func createUploads(filePath string, w http.ResponseWriter, r *http.Request, ss *loan.Session) {
- ul := uploadsOnDisk{}
- ulMeta, isDuplicate, e := saveUploadsMetaToDB(0, filePath, r, ss)
- ul.Upload = ulMeta
- ul.Upload.IsDuplicate = isDuplicate
- if e != nil {
- log.Println("cannot save file info to db ", e)
- e = ulMeta.Delete() // delete the newly created, if failed, db will clean it
- if e != nil {
- log.Error("failed to remove unused uploads", ul)
- }
-
- e = os.Remove(ul.filePath())
- if e != nil {
- log.Error("failed to remove unused temp file", filePath)
- }
-
- apiV1Server500Error(w, r) // bad request
- return
- }
- apiV1SendJson(ulMeta, w, r, ss)
- }
-
- func saveUploadsMetaToDB(id int64, filePath string,
- r *http.Request, ss *loan.Session) (ulMeta loan.Uploads, duplicate bool, e error) {
- duplicate = false
- e = r.ParseMultipartForm(10 << 20) // we should have ready parsed this, just in case
- if e != nil {
- return
- }
- file, header, e := r.FormFile("files")
-
- file.Seek(0, 0) //seek to beginning
- checksum := sha256File(file)
- ulMeta.Id = id
- ulMeta.Ts = time.Now()
- ulMeta.FileName = header.Filename
- file.Seek(0, 0) //seek to beginning
- ulMeta.Format = header.Header.Get("Content-type")
- ulMeta.Size = header.Size // necessary to prevent duplicate
- ulMeta.LastModified = 0
- ulMeta.Sha256 = checksum // necessary to prevent duplicate
- ulMeta.By = ss.User
- e = ulMeta.Write() // this Id will have the real Id if there is duplicates
-
- if e != nil {
- log.Error("Fail to update db ", ulMeta, e)
- } else {
- if (id > 0 && ulMeta.Id != id) || (id == 0 && ulMeta.IsDuplicate) {
- duplicate = true
- }
- ul := uploadsOnDisk{}
- ul.Upload = ulMeta
- e = os.Rename(filePath, ul.filePath())
- if e != nil {
- os.Remove(filePath)
- log.Error("fail to move file from ", filePath, "to", ul.filePath())
- }
- }
- return
- }
-
- func saveUploadToFile(r *http.Request) (filename string, e error) {
- e = r.ParseMultipartForm(10 << 20)
- if e != nil {
- return
- }
- file, header, e := r.FormFile("files")
- if e != nil {
- log.Println("Error Getting File", e)
- return
- }
-
- out, pathError := ioutil.TempFile(config.UploadsDir.FileDir, "can-del-upload-*.tmp")
- if pathError != nil {
- log.Println("Error Creating a file for writing", pathError)
- return
- }
-
- out.Seek(0, 0) //seek to beginning
- size, e := io.Copy(out, file)
- if e != nil {
- os.Remove(out.Name()) //remove on failure
- log.Println("Error copying", e)
- return
- }
-
- if size != header.Size {
- e = errors.New("written file with incorrect size")
- }
- return out.Name(), e
- }
-
- func getRequestedUpload(strId string, w http.ResponseWriter, r *http.Request, ss *loan.Session) (ret uploadsOnDisk, e error) {
-
- 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
- }
-
- ret.Upload = ul
- 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
- }
-
- // 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.filePath(), 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"]
-
- if !ok || len(keys[0]) < 1 {
- return false
- }
- key := keys[0]
- return key == "force"
- }
|