package main import ( "biukop.com/sfm/loan" "crypto/sha256" "errors" "fmt" log "github.com/sirupsen/logrus" "io" "io/ioutil" "net/http" "os" "strconv" "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 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) 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 } if forceHttpDownload(r) { w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName) } //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 forceHttpDownload(r *http.Request) bool { return httpQueryParamHas(r, "download", "force") //keys, ok := r.URL.Query()["download"] // //if !ok || len(keys[0]) < 1 { // return false //} //key := keys[0] //return key == "force" } func httpQueryParamHas(r *http.Request, key string, expectedValue string) (has bool) { keys, ok := r.URL.Query()[key] if !ok || len(keys[0]) < 1 { return false } k := keys[0] return k == expectedValue }