Check for an existing item before attempting to add files

This commit is contained in:
Eike Kettner 2020-05-24 10:58:50 +02:00
parent 075b665c68
commit f519a8effa
2 changed files with 58 additions and 17 deletions

View File

@ -1,7 +1,8 @@
package docspell.backend.ops package docspell.backend.ops
import bitpeace.MimetypeHint import bitpeace.MimetypeHint
import cats.data.OptionT import cats.Functor
import cats.data.{EitherT, OptionT}
import cats.effect._ import cats.effect._
import cats.implicits._ import cats.implicits._
import docspell.backend.Config import docspell.backend.Config
@ -10,7 +11,7 @@ import docspell.common._
import docspell.common.syntax.all._ import docspell.common.syntax.all._
import docspell.store.Store import docspell.store.Store
import docspell.store.queue.JobQueue import docspell.store.queue.JobQueue
import docspell.store.records.{RCollective, RJob, RSource} import docspell.store.records._
import org.log4s._ import org.log4s._
trait OUpload[F[_]] { trait OUpload[F[_]] {
@ -55,11 +56,32 @@ object OUpload {
sealed trait UploadResult sealed trait UploadResult
object UploadResult { object UploadResult {
case object Success extends UploadResult
case object NoFiles extends UploadResult /** File(s) have been successfully submitted. */
case object Success extends UploadResult
def success: UploadResult = Success
/** There were no files to submit. */
case object NoFiles extends UploadResult
def noFiles: UploadResult = NoFiles
/** A source (`RSource') could not be found for a given source-id. */
case object NoSource extends UploadResult case object NoSource extends UploadResult
def noSource: UploadResult = NoSource
/** When adding files to an item, no item was found using the given
* item-id. */
case object NoItem extends UploadResult
def noItem: UploadResult = NoItem
} }
private def right[F[_]: Functor, A](a: F[A]): EitherT[F, UploadResult, A] =
EitherT.right(a)
def apply[F[_]: Sync]( def apply[F[_]: Sync](
store: Store[F], store: Store[F],
queue: JobQueue[F], queue: JobQueue[F],
@ -74,10 +96,11 @@ object OUpload {
notifyJoex: Boolean, notifyJoex: Boolean,
itemId: Option[Ident] itemId: Option[Ident]
): F[OUpload.UploadResult] = ): F[OUpload.UploadResult] =
for { (for {
files <- data.files.traverse(saveFile).map(_.flatten) _ <- checkExistingItem(itemId, account.collective)
pred <- checkFileList(files) files <- right(data.files.traverse(saveFile).map(_.flatten))
lang <- store.transact(RCollective.findLanguage(account.collective)) _ <- checkFileList(files)
lang <- right(store.transact(RCollective.findLanguage(account.collective)))
meta = ProcessItemArgs.ProcessMeta( meta = ProcessItemArgs.ProcessMeta(
account.collective, account.collective,
itemId, itemId,
@ -89,13 +112,15 @@ object OUpload {
args = args =
if (data.multiple) files.map(f => ProcessItemArgs(meta, List(f))) if (data.multiple) files.map(f => ProcessItemArgs(meta, List(f)))
else Vector(ProcessItemArgs(meta, files.toList)) else Vector(ProcessItemArgs(meta, files.toList))
job <- pred.traverse(_ => makeJobs(args, account, data.priority, data.tracker)) jobs <- right(makeJobs(args, account, data.priority, data.tracker))
_ <- logger.fdebug(s"Storing jobs: $job") _ <- right(logger.fdebug(s"Storing jobs: $jobs"))
res <- job.traverse(submitJobs(notifyJoex)) res <- right(submitJobs(notifyJoex)(jobs))
_ <- store.transact( _ <- right(
RSource.incrementCounter(data.meta.sourceAbbrev, account.collective) store.transact(
RSource.incrementCounter(data.meta.sourceAbbrev, account.collective)
)
) )
} yield res.fold(identity, identity) } yield res).fold(identity, identity)
def submit( def submit(
data: OUpload.UploadData[F], data: OUpload.UploadData[F],
@ -111,7 +136,7 @@ object OUpload {
) )
accId = AccountId(src.cid, src.sid) accId = AccountId(src.cid, src.sid)
result <- OptionT.liftF(submit(updata, accId, notifyJoex, itemId)) result <- OptionT.liftF(submit(updata, accId, notifyJoex, itemId))
} yield result).getOrElse(UploadResult.NoSource) } yield result).getOrElse(UploadResult.noSource)
private def submitJobs( private def submitJobs(
notifyJoex: Boolean notifyJoex: Boolean
@ -122,6 +147,7 @@ object OUpload {
_ <- if (notifyJoex) joex.notifyAllNodes else ().pure[F] _ <- if (notifyJoex) joex.notifyAllNodes else ().pure[F]
} yield UploadResult.Success } yield UploadResult.Success
/** Saves the file into the database. */
private def saveFile(file: File[F]): F[Option[ProcessItemArgs.File]] = private def saveFile(file: File[F]): F[Option[ProcessItemArgs.File]] =
logger.finfo(s"Receiving file $file") *> logger.finfo(s"Receiving file $file") *>
store.bitpeace store.bitpeace
@ -140,10 +166,24 @@ object OUpload {
) )
) )
private def checkExistingItem(
itemId: Option[Ident],
coll: Ident
): EitherT[F, UploadResult, Unit] =
itemId match {
case None =>
right(().pure[F])
case Some(id) =>
OptionT(store.transact(RItem.findByIdAndCollective(id, coll)))
.toRight(UploadResult.noItem)
.map(_ => ())
}
private def checkFileList( private def checkFileList(
files: Seq[ProcessItemArgs.File] files: Seq[ProcessItemArgs.File]
): F[Either[UploadResult, Unit]] = ): EitherT[F, UploadResult, Unit] =
Sync[F].pure(if (files.isEmpty) Left(UploadResult.NoFiles) else Right(())) if (files.isEmpty) EitherT.left(UploadResult.noFiles.pure[F])
else right(().pure[F])
private def makeJobs( private def makeJobs(
args: Vector[ProcessItemArgs], args: Vector[ProcessItemArgs],

View File

@ -470,6 +470,7 @@ trait Conversions {
case UploadResult.Success => BasicResult(true, "Files submitted.") case UploadResult.Success => BasicResult(true, "Files submitted.")
case UploadResult.NoFiles => BasicResult(false, "There were no files to submit.") case UploadResult.NoFiles => BasicResult(false, "There were no files to submit.")
case UploadResult.NoSource => BasicResult(false, "The source id is not valid.") case UploadResult.NoSource => BasicResult(false, "The source id is not valid.")
case UploadResult.NoItem => BasicResult(false, "The item could not be found.")
} }
def basicResult(cr: PassChangeResult): BasicResult = def basicResult(cr: PassChangeResult): BasicResult =