mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-06 15:15:58 +00:00
Check for an existing item before attempting to add files
This commit is contained in:
parent
075b665c68
commit
f519a8effa
@ -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 {
|
||||||
|
|
||||||
|
/** File(s) have been successfully submitted. */
|
||||||
case object Success extends UploadResult
|
case object Success extends UploadResult
|
||||||
|
|
||||||
|
def success: UploadResult = Success
|
||||||
|
|
||||||
|
/** There were no files to submit. */
|
||||||
case object NoFiles extends UploadResult
|
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(
|
||||||
|
store.transact(
|
||||||
RSource.incrementCounter(data.meta.sourceAbbrev, account.collective)
|
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],
|
||||||
|
@ -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 =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user