Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

380 lines
9.3KB

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