Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

376 lines
9.1KB

  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. "strings"
  14. "time"
  15. )
  16. func apiV1UploadMetaGet(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  17. id := r.URL.Path[len(apiV1Prefix+"upload-meta/"):] //remove prefix
  18. intId, e := strconv.Atoi(id)
  19. if e != nil {
  20. log.Println("invalid id for upload get", id, e)
  21. apiV1Client403Error(w, r, ss) // bad request
  22. return
  23. }
  24. ulmeta := loan.Uploads{}
  25. e = ulmeta.Read(int64(intId))
  26. if e != nil {
  27. log.Println("upload not found", id, e)
  28. apiV1Client404Error(w, r, ss) // bad request
  29. return
  30. }
  31. apiV1SendJson(ulmeta, w, r, ss)
  32. }
  33. func apiV1UploadOriginalFileGet(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  34. id := r.URL.Path[len(apiV1Prefix+"upload-original/"):] //remove prefix
  35. intId, e := strconv.Atoi(id)
  36. if e != nil {
  37. log.Println("invalid id for upload get", id, e)
  38. apiV1Client403Error(w, r, ss) // bad request
  39. return
  40. }
  41. ul := uploadsOnDisk{}
  42. e = ul.Upload.Read(int64(intId))
  43. if e != nil {
  44. log.Println("no file uploaded", intId, e)
  45. apiV1Client404Error(w, r, ss) // bad request
  46. return
  47. }
  48. //check local file first
  49. path := ul.filePath()
  50. if fileExists(path) {
  51. http.ServeFile(w, r, path)
  52. return
  53. }
  54. log.Error("Upload file not found on disk", ul)
  55. apiV1Server500Error(w, r) // bad request
  56. }
  57. func apiV1UploadsPost(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  58. id := r.URL.Path[len(apiV1Prefix+"lender-upload/"):] //remove prefix
  59. filepath, e := saveUploadToFile(r)
  60. if e != nil {
  61. log.Println("no file uploaded", filepath, e)
  62. apiV1Client404Error(w, r, ss) // bad request
  63. return
  64. }
  65. intId, e := strconv.Atoi(id)
  66. if id != "" {
  67. if e != nil {
  68. log.Println("Error Getting File", e)
  69. apiV1Client404Error(w, r, ss) // bad request
  70. return
  71. }
  72. updateUploads(int64(intId), filepath, w, r, ss)
  73. } else {
  74. createUploads(filepath, w, r, ss)
  75. }
  76. }
  77. func sha256File(input io.Reader) string {
  78. hash := sha256.New()
  79. if _, err := io.Copy(hash, input); err != nil {
  80. log.Fatal(err)
  81. }
  82. sum := hash.Sum(nil)
  83. return fmt.Sprintf("%x", sum)
  84. }
  85. func updateUploads(id int64, filePath string, w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  86. ul := uploadsOnDisk{}
  87. e := ul.Upload.Read(int64(id))
  88. if e != nil {
  89. log.Println("bad upload id is given ", id, e)
  90. apiV1Client404Error(w, r, ss) // bad request
  91. return
  92. }
  93. ul1, isDuplicate, e := saveUploadsMetaToDB(id, filePath, r, ss)
  94. ul.Upload.IsDuplicate = isDuplicate
  95. if e != nil {
  96. os.Remove(ul.filePath())
  97. ul1.Delete()
  98. log.Println("cannot save file info to db ", e)
  99. apiV1Server500Error(w, r) // bad request
  100. return
  101. }
  102. apiV1SendJson(ul1, w, r, ss)
  103. }
  104. func createUploads(filePath string, w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  105. ul := uploadsOnDisk{}
  106. ulMeta, isDuplicate, e := saveUploadsMetaToDB(0, filePath, r, ss)
  107. ul.Upload = ulMeta
  108. ul.Upload.IsDuplicate = isDuplicate
  109. if e != nil {
  110. log.Println("cannot save file info to db ", e)
  111. e = ulMeta.Delete() // delete the newly created, if failed, db will clean it
  112. if e != nil {
  113. log.Error("failed to remove unused uploads", ul)
  114. }
  115. e = os.Remove(ul.filePath())
  116. if e != nil {
  117. log.Error("failed to remove unused temp file", filePath)
  118. }
  119. apiV1Server500Error(w, r) // bad request
  120. return
  121. }
  122. apiV1SendJson(ulMeta, w, r, ss)
  123. }
  124. func saveUploadsMetaToDB(id int64, filePath string,
  125. r *http.Request, ss *loan.Session) (ulMeta loan.Uploads, duplicate bool, e error) {
  126. duplicate = false
  127. e = r.ParseMultipartForm(10 << 20) // we should have ready parsed this, just in case
  128. if e != nil {
  129. return
  130. }
  131. file, header, e := r.FormFile("files")
  132. file.Seek(0, 0) //seek to beginning
  133. checksum := sha256File(file)
  134. ulMeta.Id = id
  135. ulMeta.Ts = time.Now()
  136. ulMeta.FileName = header.Filename
  137. file.Seek(0, 0) //seek to beginning
  138. ulMeta.Format = header.Header.Get("Content-type")
  139. ulMeta.Size = header.Size // necessary to prevent duplicate
  140. ulMeta.LastModified = 0
  141. ulMeta.Sha256 = checksum // necessary to prevent duplicate
  142. ulMeta.By = ss.User
  143. e = ulMeta.Write() // this Id will have the real Id if there is duplicates
  144. if e != nil {
  145. log.Error("Fail to update db ", ulMeta, e)
  146. } else {
  147. if (id > 0 && ulMeta.Id != id) || (id == 0 && ulMeta.IsDuplicate) {
  148. duplicate = true
  149. }
  150. ul := uploadsOnDisk{}
  151. ul.Upload = ulMeta
  152. e = os.Rename(filePath, ul.filePath())
  153. if e != nil {
  154. os.Remove(filePath)
  155. log.Error("fail to move file from ", filePath, "to", ul.filePath())
  156. }
  157. }
  158. return
  159. }
  160. func saveUploadToFile(r *http.Request) (filename string, e error) {
  161. e = r.ParseMultipartForm(10 << 20)
  162. if e != nil {
  163. return
  164. }
  165. file, header, e := r.FormFile("files")
  166. if e != nil {
  167. log.Println("Error Getting File", e)
  168. return
  169. }
  170. out, pathError := ioutil.TempFile(config.UploadsDir.FileDir, "can-del-upload-*.tmp")
  171. if pathError != nil {
  172. log.Println("Error Creating a file for writing", pathError)
  173. return
  174. }
  175. out.Seek(0, 0) //seek to beginning
  176. size, e := io.Copy(out, file)
  177. if e != nil {
  178. os.Remove(out.Name()) //remove on failure
  179. log.Println("Error copying", e)
  180. return
  181. }
  182. if size != header.Size {
  183. e = errors.New("written file with incorrect size")
  184. }
  185. return out.Name(), e
  186. }
  187. func getRequestedUpload(strId string, w http.ResponseWriter, r *http.Request, ss *loan.Session) (ret uploadsOnDisk, e error) {
  188. Id, e := strconv.Atoi(strId)
  189. if e != nil {
  190. log.Error("Invalid uploads Id cannot convert to integer", Id, e)
  191. apiV1Client403Error(w, r, ss)
  192. return
  193. }
  194. ul := loan.Uploads{}
  195. e = ul.Read(int64(Id))
  196. if e != nil {
  197. log.Error("Upload not found or read error from db", Id, e)
  198. apiV1Client404Error(w, r, ss)
  199. return
  200. }
  201. ret.Upload = ul
  202. return
  203. }
  204. func apiV1UploadAsImage(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  205. strId := r.URL.Path[len(apiV1Prefix+"upload-as-image/"):] //remove prefix
  206. if strId == "default" {
  207. http.ServeFile(w, r, config.UploadsDir.JpgDefault)
  208. return
  209. }
  210. ul, e := getRequestedUpload(strId, w, r, ss)
  211. if e != nil {
  212. return
  213. }
  214. // if this is image itself, serve it directly
  215. if strings.Contains(strings.ToLower(ul.Upload.Format), "image") {
  216. f, e := os.Open(ul.filePath())
  217. if e == nil {
  218. defer f.Close()
  219. fi, e := f.Stat()
  220. if e == nil {
  221. //w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName)
  222. http.ServeContent(w, r, ul.filePath(), fi.ModTime(), f)
  223. return
  224. }
  225. }
  226. // if we reach here, some err has happened
  227. log.Error("failed to serve image file ", ul, e)
  228. apiV1Server500Error(w, r)
  229. return
  230. }
  231. // see if a converted image exist, if not convert it and then send
  232. if !fileExists(ul.jpgPath()) {
  233. e = ul.convertUploadsToJpg()
  234. if e != nil {
  235. // serve a default no preview is available
  236. http.ServeFile(w, r, config.UploadsDir.JpgDefault)
  237. log.Error("error creating preview image", ul, e)
  238. return
  239. }
  240. }
  241. if fileExists(ul.jpgPath()) {
  242. http.ServeFile(w, r, ul.jpgPath())
  243. return
  244. } else {
  245. apiV1Client404Error(w, r, ss)
  246. }
  247. }
  248. func apiV1UploadAsThumbnail(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  249. strId := r.URL.Path[len(apiV1Prefix+"upload-as-thumbnail/"):] //remove prefix
  250. if strId == "default" {
  251. http.ServeFile(w, r, config.UploadsDir.ThumbDefault)
  252. return
  253. }
  254. ul, e := getRequestedUpload(strId, w, r, ss)
  255. if e != nil {
  256. return
  257. }
  258. // see if a thumbnail is available already
  259. if !fileExists(ul.thumbPath()) {
  260. e = ul.convertUploadsToThumb()
  261. if e != nil {
  262. // serve a default no preview is available
  263. http.ServeFile(w, r, config.UploadsDir.ThumbDefault)
  264. log.Error("error creating preview image", ul, e)
  265. return
  266. }
  267. }
  268. if fileExists(ul.thumbPath()) {
  269. http.ServeFile(w, r, ul.thumbPath())
  270. return
  271. } else {
  272. apiV1Client404Error(w, r, ss)
  273. }
  274. }
  275. func apiV1UploadAsPDF(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  276. strId := r.URL.Path[len(apiV1Prefix+"upload-as-pdf/"):] //remove prefix
  277. if strId == "default" {
  278. http.ServeFile(w, r, config.UploadsDir.PdfDefault)
  279. return
  280. }
  281. ul, e := getRequestedUpload(strId, w, r, ss)
  282. if e != nil {
  283. return
  284. }
  285. //get file type
  286. fileType, e := ul.GetFileType()
  287. if e != nil {
  288. apiV1Client403Error(w, r, ss)
  289. return
  290. }
  291. // if its ready pdf, no need to convert
  292. if fileType == "pdf" {
  293. f, e := os.Open(ul.filePath())
  294. if e == nil {
  295. defer f.Close()
  296. fi, e := f.Stat()
  297. if e == nil {
  298. if forceHttpDownload(r) {
  299. w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName)
  300. }
  301. http.ServeContent(w, r, ul.filePath(), fi.ModTime(), f)
  302. return
  303. }
  304. }
  305. // if we reach here, some err has happened
  306. log.Error("failed to serve pdf file ", ul, e)
  307. apiV1Server500Error(w, r)
  308. return
  309. }
  310. // see if a converted pdf exist, if not convert it and then send
  311. if !fileExists(ul.pdfPath()) {
  312. e = ul.convertUploadsToPDF()
  313. if e != nil {
  314. // serve a default no preview is available
  315. http.ServeFile(w, r, config.UploadsDir.PdfDefault)
  316. log.Error("error creating preview image", ul, e)
  317. return
  318. }
  319. }
  320. if fileExists(ul.pdfPath()) {
  321. http.ServeFile(w, r, ul.pdfPath())
  322. return
  323. } else {
  324. apiV1Client404Error(w, r, ss)
  325. }
  326. }
  327. func forceHttpDownload(r *http.Request) bool {
  328. keys, ok := r.URL.Query()["download"]
  329. if !ok || len(keys[0]) < 1 {
  330. return false
  331. }
  332. key := keys[0]
  333. return key == "force"
  334. }