選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

376 行
9.2KB

  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. //time.Sleep(5* time.Second);
  215. // if this is image itself, serve it directly
  216. if strings.Contains(strings.ToLower(ul.Upload.Format), "image") {
  217. f, e := os.Open(ul.filePath())
  218. if e == nil {
  219. defer f.Close()
  220. fi, e := f.Stat()
  221. if e == nil {
  222. //w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName)
  223. http.ServeContent(w, r, ul.filePath(), fi.ModTime(), f)
  224. return
  225. }
  226. }
  227. // if we reach here, some err has happened
  228. log.Error("failed to serve image file ", ul, e)
  229. apiV1Server500Error(w, r)
  230. return
  231. }
  232. // see if a converted image exist, if not convert it and then send
  233. if !fileExists(ul.jpgPath()) {
  234. e = ul.convertUploadsToJpg()
  235. if e != nil {
  236. // serve a default no preview is available
  237. http.ServeFile(w, r, config.UploadsDir.JpgDefault)
  238. log.Error("error creating preview image", ul, e)
  239. return
  240. }
  241. }
  242. if fileExists(ul.jpgPath()) {
  243. http.ServeFile(w, r, ul.jpgPath())
  244. return
  245. } else {
  246. apiV1Client404Error(w, r, ss)
  247. }
  248. }
  249. func apiV1UploadAsThumbnail(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  250. strId := r.URL.Path[len(apiV1Prefix+"upload-as-thumbnail/"):] //remove prefix
  251. if strId == "default" {
  252. http.ServeFile(w, r, config.UploadsDir.ThumbDefault)
  253. return
  254. }
  255. ul, e := getRequestedUpload(strId, w, r, ss)
  256. if e != nil {
  257. return
  258. }
  259. // see if a thumbnail is available already
  260. if !fileExists(ul.thumbPath()) {
  261. e = ul.convertUploadsToThumb()
  262. if e != nil {
  263. // serve a default no preview is available
  264. http.ServeFile(w, r, config.UploadsDir.ThumbDefault)
  265. log.Error("error creating preview image", ul, e)
  266. return
  267. }
  268. }
  269. if fileExists(ul.thumbPath()) {
  270. http.ServeFile(w, r, ul.thumbPath())
  271. return
  272. } else {
  273. apiV1Client404Error(w, r, ss)
  274. }
  275. }
  276. func apiV1UploadAsPDF(w http.ResponseWriter, r *http.Request, ss *loan.Session) {
  277. strId := r.URL.Path[len(apiV1Prefix+"upload-as-pdf/"):] //remove prefix
  278. if strId == "default" {
  279. http.ServeFile(w, r, config.UploadsDir.PdfDefault)
  280. return
  281. }
  282. ul, e := getRequestedUpload(strId, w, r, ss)
  283. if e != nil {
  284. return
  285. }
  286. //get file type
  287. fileType, e := ul.GetFileType()
  288. if e != nil {
  289. apiV1Client403Error(w, r, ss)
  290. return
  291. }
  292. // if its ready pdf, no need to convert
  293. if fileType == "pdf" {
  294. f, e := os.Open(ul.filePath())
  295. if e == nil {
  296. defer f.Close()
  297. fi, e := f.Stat()
  298. if e == nil {
  299. if forceHttpDownload(r) {
  300. w.Header().Set("Content-Disposition", "attachment; filename="+ul.Upload.FileName)
  301. }
  302. http.ServeContent(w, r, ul.Upload.FileName, fi.ModTime(), f)
  303. return
  304. }
  305. }
  306. // if we reach here, some err has happened
  307. log.Error("failed to serve pdf file ", ul, e)
  308. apiV1Server500Error(w, r)
  309. return
  310. }
  311. // see if a converted pdf exist, if not convert it and then send
  312. if !fileExists(ul.pdfPath()) {
  313. e = ul.convertUploadsToPDF()
  314. if e != nil {
  315. // serve a default no preview is available
  316. http.ServeFile(w, r, config.UploadsDir.PdfDefault)
  317. log.Error("error creating preview image", ul, e)
  318. return
  319. }
  320. }
  321. if fileExists(ul.pdfPath()) {
  322. http.ServeFile(w, r, ul.pdfPath())
  323. return
  324. } else {
  325. apiV1Client404Error(w, r, ss)
  326. }
  327. }
  328. func forceHttpDownload(r *http.Request) bool {
  329. keys, ok := r.URL.Query()["download"]
  330. if !ok || len(keys[0]) < 1 {
  331. return false
  332. }
  333. key := keys[0]
  334. return key == "force"
  335. }