PageRenderTime 26ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/web-core/app/core/storage/FileStorage.scala

https://github.com/delving/culture-hub
Scala | 186 lines | 137 code | 25 blank | 24 comment | 7 complexity | 0795b02c51a763c7317601933d0013f5 MD5 | raw file
  1. package core.storage
  2. import models.OrganizationConfiguration
  3. import com.mongodb.casbah.Imports._
  4. import com.mongodb.casbah.gridfs.Imports._
  5. import models.HubMongoContext._
  6. import java.io.{ FileOutputStream, File, InputStream }
  7. import core.{ CultureHubPlugin, FileStoreService }
  8. import org.bson.types.ObjectId
  9. import core.messages.FileStored
  10. import org.apache.commons.io.IOUtils
  11. /**
  12. * Collection of methods for dealing with files and file uploads.
  13. * These methods have been savagly ripped out of the DoS because they are needed in web-core as well.
  14. *
  15. * TODO method to retrieve parameters that are not mongoDB params into StoredFile
  16. * TODO use fileStore method in other places when it makes sense
  17. * TODO replace / inline all old method calls
  18. * TODO decouple cleanup of file derivates (thumbnails) from deletion of a file here. Perhaps via event broadcasting
  19. *
  20. * @author Manuel Bernhardt <bernhardt.manuel@gmail.com>
  21. */
  22. object FileStorage extends FileStoreService {
  23. def listFiles(bucketId: String, fileType: Option[String] = None)(implicit configuration: OrganizationConfiguration): List[StoredFile] = {
  24. val query = MongoDBObject(ITEM_POINTER_FIELD -> bucketId) ++ fileType.map(t => MongoDBObject(ITEM_TYPE -> t)).getOrElse(MongoDBObject())
  25. fileStore(configuration).
  26. find(query).
  27. map(f => fileToStoredFile(f)).toList
  28. }
  29. def deleteFiles(bucketId: String, fileType: Option[String] = None)(implicit configuration: OrganizationConfiguration) {
  30. val files = listFiles(bucketId, fileType)
  31. files.foreach { f =>
  32. FileStorage.deleteFile(f.id.toString)
  33. }
  34. }
  35. def storeFile(file: File, contentType: String, fileName: String, bucketId: String, fileType: Option[String] = None,
  36. params: Map[String, AnyRef] = Map.empty, advertise: Boolean = true)(implicit configuration: OrganizationConfiguration): Option[StoredFile] = {
  37. val f = fileStore(configuration).createFile(file)
  38. f.filename = fileName
  39. f.contentType = contentType
  40. f.put(ITEM_POINTER_FIELD, bucketId)
  41. fileType.foreach { t =>
  42. f.put(ITEM_TYPE, t)
  43. }
  44. f.save()
  45. if (advertise) {
  46. CultureHubPlugin.broadcastMessage(
  47. FileStored(bucketId, f.id.toString, fileType, fileName, contentType, configuration)
  48. )
  49. }
  50. fileStore(configuration).findOne(f._id.get).map { f =>
  51. fileToStoredFile(f)
  52. }
  53. }
  54. def retrieveFile(fileIdentifier: String)(implicit configuration: OrganizationConfiguration): Option[StoredFile] = {
  55. if (ObjectId.isValid(fileIdentifier)) {
  56. fileStore(configuration).findOne(new ObjectId(fileIdentifier)).map { file =>
  57. StoredFile(file._id.get, file.filename.getOrElse(""), file.contentType.getOrElse("unknown/unknown"), file.size, file.inputStream)
  58. }
  59. } else {
  60. None
  61. }
  62. }
  63. def deleteFile(fileIdentifier: String)(implicit configuration: OrganizationConfiguration) {
  64. if (ObjectId.isValid(fileIdentifier)) {
  65. val id = new ObjectId(fileIdentifier)
  66. fileStore(configuration).find(id) foreach { toDelete =>
  67. // remove thumbnails
  68. fileStore(configuration).find(MongoDBObject(FILE_POINTER_FIELD -> id)) foreach { t =>
  69. fileStore(configuration).remove(t.getId.asInstanceOf[ObjectId])
  70. }
  71. // remove the file itself
  72. fileStore(configuration).remove(id)
  73. }
  74. }
  75. }
  76. def renameBucket(oldBucketId: String, newBucketId: String)(implicit configuration: OrganizationConfiguration) {
  77. val files: Seq[com.mongodb.gridfs.GridFSDBFile] = fileStore(configuration).find(MongoDBObject(ITEM_POINTER_FIELD -> oldBucketId))
  78. files.foreach { file =>
  79. file.put(ITEM_POINTER_FIELD, newBucketId.asInstanceOf[AnyRef])
  80. file.save()
  81. }
  82. }
  83. def renameBucketForFile(fileId: ObjectId, newBucketId: String)(implicit configuration: OrganizationConfiguration) {
  84. fileStore(configuration).findOne(fileId).map { file =>
  85. file.put(ITEM_POINTER_FIELD, newBucketId.asInstanceOf[AnyRef])
  86. file.save()
  87. }
  88. }
  89. def setFileType(newFileType: Option[String], files: Seq[StoredFile])(implicit configuration: OrganizationConfiguration) {
  90. files.foreach { f =>
  91. fileStore(configuration).findOne(f.id).map { file =>
  92. newFileType.map { t =>
  93. file.put(ITEM_TYPE, t)
  94. }.getOrElse {
  95. // can't remove this because it throws an UnsupportedOperationException
  96. file.put(ITEM_TYPE, "")
  97. }
  98. file.save()
  99. }
  100. }
  101. }
  102. /**
  103. * Attaches all files to an object, given the upload UID
  104. *
  105. * TODO this method is now part of controllers.dos.FileUpload and needs to be removed here once we are done with refactoring
  106. */
  107. def markFilesAttached(uid: String, objectIdentifier: String)(implicit configuration: OrganizationConfiguration) {
  108. val files = FileStorage.listFiles(uid, Some(FILE_TYPE_UNATTACHED))
  109. FileStorage.renameBucket(uid, objectIdentifier)
  110. FileStorage.setFileType(None, files)
  111. }
  112. private def fileToStoredFile(f: GridFSDBFile)(implicit configuration: OrganizationConfiguration) = {
  113. val id = f._id.get
  114. StoredFile(id, f.filename.getOrElse(""), f.contentType.getOrElse("unknown/unknown"), f.size, f.inputStream)
  115. }
  116. }
  117. case class StoredFile(id: ObjectId, name: String, contentType: String, length: Long, content: InputStream) {
  118. def writeTo(file: File) {
  119. val os = new FileOutputStream(file)
  120. try {
  121. IOUtils.copy(content, os)
  122. os.flush()
  123. } finally {
  124. os.close()
  125. }
  126. }
  127. }
  128. /**
  129. * Represents a response to a file upload via the jQuery File Upload widget
  130. *
  131. * http://blueimp.github.com/jQuery-File-Upload/
  132. */
  133. case class FileUploadResponse(
  134. name: String,
  135. size: Long,
  136. url: String = "",
  137. thumbnail_url: String = "",
  138. delete_url: String = "",
  139. delete_type: String = "DELETE",
  140. error: String = "",
  141. id: String = "")
  142. object FileUploadResponse {
  143. def apply(file: StoredFile)(implicit configuration: OrganizationConfiguration): FileUploadResponse = {
  144. def hasThumbnail(f: StoredFile) = file.contentType.contains("image") || file.contentType.contains("pdf")
  145. def thumbnailUrl(implicit configuration: OrganizationConfiguration): Option[String] = {
  146. if (hasThumbnail(file)) {
  147. Some("/thumbnail/" + file.id.toString + "/80")
  148. } else {
  149. None
  150. }
  151. }
  152. FileUploadResponse(
  153. name = file.name,
  154. size = file.length,
  155. url = "/file/" + file.id,
  156. thumbnail_url = thumbnailUrl.getOrElse("/assets/common/images/dummy-object.png"),
  157. delete_url = "/file/" + file.id,
  158. id = file.id.toString
  159. )
  160. }
  161. }