app/models/FileEntry.scala (101 lines of code) (raw):

package models import java.io.{File, FileInputStream} import java.nio.file.{Path, Paths} import slick.jdbc.PostgresProfile.api._ import java.sql.Timestamp import akka.stream.Materializer import akka.stream.scaladsl.Source import drivers.StorageDriver import org.slf4j.LoggerFactory import play.api.Logger import play.api.inject.Injector import play.api.libs.functional.syntax._ import play.api.libs.json._ import play.api.mvc.{RawBuffer, Result} import slick.lifted.TableQuery import scala.concurrent.ExecutionContext.Implicits.global import scala.util.{Failure, Success, Try} import scala.concurrent.{Await, Future} /** * This class represents a file that exists on some [[models.StorageEntry]] * @param id - database ID. Could be None * @param filepath - [[String]] path of the file on storage, relative to storage root * @param storageId - [[Int]] database ID of the storage that this lives on. Has a foreign key relation to [[models.StorageEntry]] * @param user - [[String]] person who owns this * @param version - [[Int]] number that increments with every update * @param ctime - [[Timestamp]] creation time * @param mtime - [[Timestamp]] modification time * @param atime - [[Timestamp]] access time * @param hasContent - boolean flag representing whether this entity has any data in it yet * @param hasLink - boolean flag representing whether this entitiy is linked to anything (i.e. a project) yet. */ case class FileEntry(id: Option[Int], filepath: String, storageId: Int, user:String, version:Int, ctime: Timestamp, mtime: Timestamp, atime: Timestamp, hasContent:Boolean, hasLink:Boolean, backupOf:Option[Int], maybePremiereVersion:Option[Int]) extends PlutoModel { private lazy val logger = LoggerFactory.getLogger(getClass) /** * writes this model into the database, inserting if id is None and returning a fresh object with id set. If an id * was set, then returns the same object. */ @deprecated("Use FileEntryDAO.save()") def save(implicit dao:FileEntryDAO):Future[Try[FileEntry]] = dao.save(this) @deprecated("Use FileEntryDAO.saveSimple") def saveSimple(implicit dao:FileEntryDAO):Future[FileEntry] = dao.saveSimple(this) /** * returns a StorageEntry object for the id of the storage of this FileEntry */ @deprecated("Use FileEntryDAO.storage") def storage(implicit dao:FileEntryDAO):Future[Option[StorageEntry]] = dao.storage(this) /** * Get a full path of the file, including the root path of the storage * @param dao implicitly provided FileEntryDAO instance * @return Future containing a string */ @deprecated("Use FileEntryDAO.getFullPath") def getFullPath(implicit dao:FileEntryDAO):Future[String] = dao.getFullPath(this) /** * Gets a java.io.File pointing to the given file * @param db * @return */ @deprecated("Use FileEntryDAO.getJavaFile") def getJavaFile(implicit dao:FileEntryDAO):Future[File] = dao.getJavaFile(this) /** * this attempts to delete the file from disk, using the configured storage driver * * @param db implicitly provided [[slick.jdbc.PostgresProfile#Backend#Database]] * @return A future containing either a Right() containing a Boolean indicating whether the delete happened, or a Left with an error string */ @deprecated("Use FileEntryDAO.deleteFromDisk") def deleteFromDisk(implicit dao:FileEntryDAO, injector:Injector):Future[Either[String,Boolean]] = dao.deleteFromDisk(this) /** * attempt to delete the underlying record from the database * @param db implicitly provided database object * @return a Future with no value on success. On failure, the future fails; pick this up with .recover() or .onComplete */ @deprecated("Use FileEntryDAO.deleteSelf") def deleteSelf(implicit dao:FileEntryDAO):Future[Unit] = dao.deleteRecord(this) /** * Update the hasContent flag * @param db implicitly provided [[slick.jdbc.PostgresProfile#Backend#Database]] * @return a Future containing a Try, which contains an updated [[models.FileEntry]] instance */ @deprecated("Use FileEntryDAO.updateFileHasContent") def updateFileHasContent(implicit dao:FileEntryDAO) = dao.updateFileHasContent(this) /* Asynchronously writes the given buffer to this file*/ @deprecated("Use FileEntryDAO.writeToFile") def writeToFile(buffer: RawBuffer)(implicit dao:FileEntryDAO, injector:Injector):Future[Try[Unit]] = dao .writeToFile(this, buffer) .map(_=>Success( () )) .recover({ case err:Throwable=> Failure(err) }) /** * check if this FileEntry points to something real on disk * @param db - implicitly provided database object * @return a Future, containing a Left with a string if there was an error, or a Right with a Boolean flag indicating if the * pointed object exists on the storage */ @deprecated("Use FileEntryDAO.validateFileExists") def validatePathExists(implicit dao:FileEntryDAO) = dao.validatePathExists(this) /** * check if this FileEntry points to something real on disk. * intended to be used in streaming/looping contexts, this expects a StorageDriver for the relevant storage * to be provided externally rather than provisioning one internally * * @param db * @param driver * @return */ @deprecated("Use FileEntryDAO.validateFileExistsDirect") def validatePathExistsDirect(implicit dao:FileEntryDAO, driver:StorageDriver) = dao.validatePathExistsDirect(this) /** * returns some of the backups for this file. Results are sorted by most recent version first. * * If the storage does not support versioning you would expect only one result. * * @param drop start iterating at this entry * @param take only return this many results max * @param db implicitly provided database object * @return a Future containing a sequence of FileEntry objects. This fails if there is a problem. */ @deprecated("Use FileEntryDAO.backups") def backups(forStorage:Option[Int]=None, drop:Int=0, take:Int=100)(implicit dao:FileEntryDAO) = dao.backups(this, forStorage, drop, take) @deprecated("Use FileEntryDAO.backupsCount") def backupsCount(forStorage:Option[Int]=None)(implicit dao:FileEntryDAO) = dao.backupsCount(this, forStorage) } /** * Table definition for [[FileEntry]] in Slick * @param tag */ class FileEntryRow(tag:Tag) extends Table[FileEntry](tag, "FileEntry") { def id = column[Int]("id",O.PrimaryKey, O.AutoInc) def filepath = column[String]("s_filepath") def storage = column[Int]("k_storage_id") def version = column[Int]("i_version") def user = column[String]("s_user") def ctime = column[Timestamp]("t_ctime") def mtime = column[Timestamp]("t_mtime") def atime = column[Timestamp]("t_atime") def hasContent = column[Boolean]("b_has_content") def hasLink = column[Boolean]("b_has_link") def backupOf = column[Option[Int]]("k_backup_of") def maybePremiereVersion = column[Option[Int]]("i_premiere_version") def storageFk = foreignKey("fk_storage",storage,TableQuery[StorageEntryRow])(_.id) def backupFk = foreignKey("fk_backup_of", backupOf, TableQuery[FileEntryRow])(_.id) def * = (id.?,filepath,storage,user,version,ctime,mtime,atime, hasContent, hasLink, backupOf, maybePremiereVersion) <> (FileEntry.tupled, FileEntry.unapply) } /** * JSON serialize/deserialize functions. This trait can be mixed into a View to easily process JSON representations of * [[FileEntry]] */ trait FileEntrySerializer extends TimestampSerialization { /*https://www.playframework.com/documentation/2.5.x/ScalaJson*/ implicit val fileWrites: Writes[FileEntry] = ( (JsPath \ "id").writeNullable[Int] and (JsPath \ "filepath").write[String] and (JsPath \ "storage").write[Int] and (JsPath \ "user").write[String] and (JsPath \ "version").write[Int] and (JsPath \ "ctime").write[Timestamp] and (JsPath \ "mtime").write[Timestamp] and (JsPath \ "atime").write[Timestamp] and (JsPath \ "hasContent").write[Boolean] and (JsPath \ "hasLink").write[Boolean] and (JsPath \ "backupOf").writeNullable[Int] and (JsPath \ "premiereVersion").writeNullable[Int] )(unlift(FileEntry.unapply)) implicit val fileReads: Reads[FileEntry] = ( (JsPath \ "id").readNullable[Int] and (JsPath \ "filepath").read[String] and (JsPath \ "storage").read[Int] and (JsPath \ "user").read[String] and (JsPath \ "version").read[Int] and (JsPath \ "ctime").read[Timestamp] and (JsPath \ "mtime").read[Timestamp] and (JsPath \ "atime").read[Timestamp] and (JsPath \ "hasContent").read[Boolean] and (JsPath \ "hasLink").read[Boolean] and (JsPath \ "backupOf").readNullable[Int] and (JsPath \ "premiereVersion").readNullable[Int] )(FileEntry.apply _) }