/app/controllers/dos/FileUpload.scala

https://github.com/delving/dos · Scala · 165 lines · 94 code · 25 blank · 46 comment · 11 complexity · 6ac353cb7c3fb9e0037e0514d0d56b38 MD5 · raw file

  1. /*
  2. * Copyright 2011 Delving B.V.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package controllers.dos
  17. import com.mongodb.casbah.Imports._
  18. import play.mvc.results.Result
  19. import collection.JavaConversions._
  20. import com.mongodb.gridfs.GridFSFile
  21. import java.util.List
  22. import play.data.Upload
  23. import play.mvc.{Controller, Util}
  24. import org.bson.types.ObjectId
  25. import extensions.Extensions
  26. /**
  27. *
  28. * @author Manuel Bernhardt <bernhardt.manuel@gmail.com>
  29. */
  30. object FileUpload extends Controller with Extensions with Thumbnail {
  31. // ~~ public HTTP API
  32. /**
  33. * POST handler for uploading a file, given an UID that will be attached to it.
  34. * If the uploaded file is an image, thumbnails are created for it.
  35. * The response contains a JSON-Encoded array of objects representing the uploaded file.
  36. */
  37. def uploadFile(uid: String): Result = {
  38. val uploads: List[Upload] = request.args.get("__UPLOADS").asInstanceOf[java.util.List[play.data.Upload]]
  39. uploadFileInternal(uid, asScalaIterable(uploads))
  40. }
  41. /**
  42. * DELETE handler for removing a file given an ID
  43. */
  44. def deleteFile(id: String): Result = {
  45. val oid = if (ObjectId.isValid(id)) new ObjectId(id) else (return Error("Invalid file ID " + id))
  46. fileStore.find(oid) foreach {
  47. toDelete =>
  48. // remove thumbnails
  49. fileStore.find(MongoDBObject(FILE_POINTER_FIELD -> oid)) foreach {
  50. t =>
  51. fileStore.remove(t.getId.asInstanceOf[ObjectId])
  52. }
  53. // remove the file itself
  54. fileStore.remove(oid)
  55. }
  56. Ok
  57. }
  58. // ~~ public Scala API
  59. @Util def getFilesForUID(uid: String): Seq[StoredFile] = fileStore.find(MongoDBObject(UPLOAD_UID_FIELD -> uid)) map {
  60. f => {
  61. val id = f.getId.asInstanceOf[ObjectId]
  62. val thumbnail = if (isImage(f)) {
  63. fileStore.findOne(MongoDBObject(FILE_POINTER_FIELD -> id)) match {
  64. case Some(t) => Some(t.id.asInstanceOf[ObjectId])
  65. case None => None
  66. }
  67. } else {
  68. None
  69. }
  70. StoredFile(id, f.getFilename, f.getContentType, f.getLength, thumbnail)
  71. }
  72. }
  73. /**
  74. * Attaches all files to an object, given the upload UID
  75. */
  76. @Util def markFilesAttached(uid: String, objectId: ObjectId) {
  77. fileStore.find(MongoDBObject(UPLOAD_UID_FIELD -> uid)) map {
  78. f =>
  79. // yo listen up, this ain't implemented in the mongo driver and throws an UnsupportedOperationException
  80. // f.removeField("uid")
  81. f.put(UPLOAD_UID_FIELD, "")
  82. f.put(ITEM_POINTER_FIELD, objectId)
  83. f.save()
  84. }
  85. }
  86. /**
  87. * For all thumbnails and images of a particular file, sets their pointer to a given item, thus enabling direct lookup
  88. * using the item id.
  89. */
  90. @Util def activateThumbnails(fileId: ObjectId, itemId: ObjectId) {
  91. val thumbnails = fileStore.find(MongoDBObject(FILE_POINTER_FIELD -> fileId))
  92. // deactive old thumbnails
  93. fileStore.find(MongoDBObject(THUMBNAIL_ITEM_POINTER_FIELD -> itemId)) foreach {
  94. theOldOne =>
  95. theOldOne.put(THUMBNAIL_ITEM_POINTER_FIELD, "")
  96. theOldOne.save()
  97. }
  98. // activate new thumbnails
  99. thumbnails foreach {
  100. thumb =>
  101. thumb.put(THUMBNAIL_ITEM_POINTER_FIELD, itemId)
  102. thumb.save()
  103. }
  104. // deactivate old image
  105. fileStore.findOne(MongoDBObject(IMAGE_ITEM_POINTER_FIELD -> itemId)) foreach {
  106. theOldOne =>
  107. theOldOne.put(IMAGE_ITEM_POINTER_FIELD, "")
  108. theOldOne.save
  109. }
  110. // activate new default image
  111. fileStore.findOne(fileId) foreach {
  112. theNewOne =>
  113. theNewOne.put(IMAGE_ITEM_POINTER_FIELD, itemId)
  114. theNewOne.save
  115. }
  116. }
  117. @Util def isImage(f: GridFSFile) = f.getContentType.contains("image")
  118. // ~~~ PRIVATE
  119. @Util def uploadFileInternal(uid: String, uploads: Iterable[Upload]): Result = {
  120. val uploadedFiles = for (upload: play.data.Upload <- uploads) yield {
  121. val f = fileStore.createFile(upload.asStream())
  122. f.filename = upload.getFileName
  123. f.contentType = upload.getContentType
  124. f.put(UPLOAD_UID_FIELD, uid)
  125. f.save
  126. if (f._id == None) return Error("Error saving uploaded file")
  127. // if this is an image, create a thumbnail for it so we can display it on the fly
  128. val thumbnailUrl: String = if (f.contentType.contains("image")) {
  129. fileStore.findOne(f._id.get) match {
  130. case Some(storedFile) =>
  131. val thumbnails = createThumbnails(storedFile, fileStore)
  132. if (thumbnails.size > 0) "/file/" + thumbnails.get(80).getOrElse(emptyThumbnail) else emptyThumbnail
  133. case None => ""
  134. }
  135. } else ""
  136. FileUploadResponse(upload.getFileName, upload.getSize.longValue(), "/file/" + f._id.get, thumbnailUrl, "/file/" + f._id.get)
  137. }
  138. Json(uploadedFiles)
  139. }
  140. }