You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
6.6KB

  1. package main
  2. import (
  3. "biukop.com/sfm/loan"
  4. "crypto/sha256"
  5. "errors"
  6. "fmt"
  7. log "github.com/sirupsen/logrus"
  8. "io"
  9. "io/ioutil"
  10. "net/http"
  11. "os"
  12. "strconv"
  13. "time"
  14. )
  15. func apiV1UploadMetaGet(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  16. id := r.URL.Path[len(apiV1Prefix+"upload-meta/"):] //remove prefix
  17. intId, e := strconv.Atoi(id)
  18. if e != nil {
  19. log.Println("invalid id for upload get", id, e)
  20. apiV1Client403Error(w, r, ss) // bad request
  21. return
  22. }
  23. ulmeta := loan.Uploads{}
  24. e = ulmeta.Read(int64(intId))
  25. if e != nil {
  26. log.Println("upload not found", id, e)
  27. apiV1Client404Error(w, r, ss) // bad request
  28. return
  29. }
  30. apiV1SendJson(ulmeta, w, r, ss)
  31. }
  32. func apiV1UploadDelete(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  33. id := r.URL.Path[len(apiV1Prefix+"upload/"):] //remove prefix
  34. intId, e := strconv.Atoi(id)
  35. if e != nil {
  36. log.Println("invalid id for upload get", id, e)
  37. apiV1Client403Error(w, r, ss) // bad request
  38. return
  39. }
  40. ul := uploadsOnDisk{}
  41. ul.Upload = loan.Uploads{}
  42. e = ul.Upload.Read(int64(intId))
  43. if e != nil {
  44. log.Println("upload not found", id, e)
  45. apiV1Client404Error(w, r, ss) // bad request
  46. return
  47. }
  48. e = ul.DeleteAll()
  49. if e != nil {
  50. log.Println("upload cannot be deleted", id, e)
  51. apiV1Server500Error(w, r) // bad operation
  52. return
  53. }
  54. apiV1SendJson(ul.Upload, w, r, ss)
  55. }
  56. func apiV1UploadOriginalFileGet(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  57. id := r.URL.Path[len(apiV1Prefix+"upload-original/"):] //remove prefix
  58. intId, e := strconv.Atoi(id)
  59. if e != nil {
  60. log.Println("invalid id for upload get", id, e)
  61. apiV1Client403Error(w, r, ss) // bad request
  62. return
  63. }
  64. ul := uploadsOnDisk{}
  65. e = ul.Upload.Read(int64(intId))
  66. if e != nil {
  67. log.Println("no file uploaded", intId, e)
  68. apiV1Client404Error(w, r, ss) // bad request
  69. return
  70. }
  71. if forceHttpDownload(r) {
  72. w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName)
  73. }
  74. //check local file first
  75. path := ul.filePath()
  76. if fileExists(path) {
  77. http.ServeFile(w, r, path)
  78. return
  79. }
  80. log.Error("Upload file not found on disk", ul)
  81. apiV1Server500Error(w, r) // bad request
  82. }
  83. func apiV1UploadsPost(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  84. id := r.URL.Path[len(apiV1Prefix+"lender-upload/"):] //remove prefix
  85. filepath, e := saveUploadToFile(r)
  86. if e != nil {
  87. log.Println("no file uploaded", filepath, e)
  88. apiV1Client404Error(w, r, ss) // bad request
  89. return
  90. }
  91. intId, e := strconv.Atoi(id)
  92. if id != "" {
  93. if e != nil {
  94. log.Println("Error Getting File", e)
  95. apiV1Client404Error(w, r, ss) // bad request
  96. return
  97. }
  98. updateUploads(int64(intId), filepath, w, r, ss)
  99. } else {
  100. createUploads(filepath, w, r, ss)
  101. }
  102. }
  103. func sha256File(input io.Reader) string {
  104. hash := sha256.New()
  105. if _, err := io.Copy(hash, input); err != nil {
  106. log.Fatal(err)
  107. }
  108. sum := hash.Sum(nil)
  109. return fmt.Sprintf("%x", sum)
  110. }
  111. func updateUploads(id int64, filePath string, w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  112. ul := uploadsOnDisk{}
  113. e := ul.Upload.Read(int64(id))
  114. if e != nil {
  115. log.Println("bad upload id is given ", id, e)
  116. apiV1Client404Error(w, r, ss) // bad request
  117. return
  118. }
  119. ul1, isDuplicate, e := saveUploadsMetaToDB(id, filePath, r, ss)
  120. ul.Upload.IsDuplicate = isDuplicate
  121. if e != nil {
  122. os.Remove(ul.filePath())
  123. ul1.Delete()
  124. log.Println("cannot save file info to db ", e)
  125. apiV1Server500Error(w, r) // bad request
  126. return
  127. }
  128. apiV1SendJson(ul1, w, r, ss)
  129. }
  130. func createUploads(filePath string, w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  131. ul := uploadsOnDisk{}
  132. ulMeta, isDuplicate, e := saveUploadsMetaToDB(0, filePath, r, ss)
  133. ul.Upload = ulMeta
  134. ul.Upload.IsDuplicate = isDuplicate
  135. if e != nil {
  136. log.Println("cannot save file info to db ", e)
  137. e = ulMeta.Delete() // delete the newly created, if failed, db will clean it
  138. if e != nil {
  139. log.Error("failed to remove unused uploads", ul)
  140. }
  141. e = os.Remove(ul.filePath())
  142. if e != nil {
  143. log.Error("failed to remove unused temp file", filePath)
  144. }
  145. apiV1Server500Error(w, r) // bad request
  146. return
  147. }
  148. apiV1SendJson(ulMeta, w, r, ss)
  149. }
  150. func saveUploadsMetaToDB(id int64, filePath string,
  151. r *http.Request, ss *loan.Session) (ulMeta loan.Uploads, duplicate bool, e error) {
  152. duplicate = false
  153. e = r.ParseMultipartForm(10 << 20) // we should have ready parsed this, just in case
  154. if e != nil {
  155. return
  156. }
  157. file, header, e := r.FormFile("files")
  158. file.Seek(0, 0) //seek to beginning
  159. checksum := sha256File(file)
  160. ulMeta.Id = id
  161. ulMeta.Ts = time.Now()
  162. ulMeta.FileName = header.Filename
  163. file.Seek(0, 0) //seek to beginning
  164. ulMeta.Format = header.Header.Get("Content-type")
  165. ulMeta.Size = header.Size // necessary to prevent duplicate
  166. ulMeta.LastModified = 0
  167. ulMeta.Sha256 = checksum // necessary to prevent duplicate
  168. ulMeta.By = ss.User
  169. e = ulMeta.Write() // this Id will have the real Id if there is duplicates
  170. if e != nil {
  171. log.Error("Fail to update db ", ulMeta, e)
  172. } else {
  173. if (id > 0 && ulMeta.Id != id) || (id == 0 && ulMeta.IsDuplicate) {
  174. duplicate = true
  175. }
  176. ul := uploadsOnDisk{}
  177. ul.Upload = ulMeta
  178. e = os.Rename(filePath, ul.filePath())
  179. if e != nil {
  180. os.Remove(filePath)
  181. log.Error("fail to move file from ", filePath, "to", ul.filePath())
  182. }
  183. }
  184. return
  185. }
  186. func saveUploadToFile(r *http.Request) (filename string, e error) {
  187. e = r.ParseMultipartForm(10 << 20)
  188. if e != nil {
  189. return
  190. }
  191. file, header, e := r.FormFile("files")
  192. if e != nil {
  193. log.Println("Error Getting File", e)
  194. return
  195. }
  196. out, pathError := ioutil.TempFile(config.UploadsDir.FileDir, "can-del-upload-*.tmp")
  197. if pathError != nil {
  198. log.Println("Error Creating a file for writing", pathError)
  199. return
  200. }
  201. out.Seek(0, 0) //seek to beginning
  202. size, e := io.Copy(out, file)
  203. if e != nil {
  204. os.Remove(out.Name()) //remove on failure
  205. log.Println("Error copying", e)
  206. return
  207. }
  208. if size != header.Size {
  209. e = errors.New("written file with incorrect size")
  210. }
  211. return out.Name(), e
  212. }
  213. func getRequestedUpload(strId string, w http.ResponseWriter, r *http.Request, ss *loan.Session) (ret uploadsOnDisk, e error) {
  214. Id, e := strconv.Atoi(strId)
  215. if e != nil {
  216. log.Error("Invalid uploads Id cannot convert to integer", Id, e)
  217. apiV1Client403Error(w, r, ss)
  218. return
  219. }
  220. ul := loan.Uploads{}
  221. e = ul.Read(int64(Id))
  222. if e != nil {
  223. log.Error("Upload not found or read error from db", Id, e)
  224. apiV1Client404Error(w, r, ss)
  225. return
  226. }
  227. ret.Upload = ul
  228. return
  229. }
  230. func forceHttpDownload(r *http.Request) bool {
  231. keys, ok := r.URL.Query()["download"]
  232. if !ok || len(keys[0]) < 1 {
  233. return false
  234. }
  235. key := keys[0]
  236. return key == "force"
  237. }