|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- 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
- }
|