From 17472fa4caca7135a74760eabae0c513e4d415ef Mon Sep 17 00:00:00 2001 From: Eike Kettner Date: Mon, 26 Oct 2020 12:17:55 +0100 Subject: [PATCH] Edit name of multiple items --- .../scala/docspell/backend/ops/OItem.scala | 87 +++++++++++++------ .../restserver/routes/ItemMultiRoutes.scala | 28 +++--- modules/webapp/src/main/elm/Api.elm | 16 ++++ .../main/elm/Comp/ItemDetail/FormChange.elm | 8 ++ 4 files changed, 100 insertions(+), 39 deletions(-) diff --git a/modules/backend/src/main/scala/docspell/backend/ops/OItem.scala b/modules/backend/src/main/scala/docspell/backend/ops/OItem.scala index 0e855320..ed235531 100644 --- a/modules/backend/src/main/scala/docspell/backend/ops/OItem.scala +++ b/modules/backend/src/main/scala/docspell/backend/ops/OItem.scala @@ -51,7 +51,7 @@ trait OItem[F[_]] { def setDirection(item: Ident, direction: Direction, collective: Ident): F[AddResult] - def setFolder(item: Ident, folder: Option[Ident], collective: Ident): F[AddResult] + def setFolder(item: Ident, folder: Option[Ident], collective: Ident): F[UpdateResult] def setCorrOrg(item: Ident, org: Option[Ident], collective: Ident): F[AddResult] @@ -69,9 +69,15 @@ trait OItem[F[_]] { def addConcEquip(item: Ident, equip: REquipment): F[AddResult] - def setNotes(item: Ident, notes: Option[String], collective: Ident): F[AddResult] + def setNotes(item: Ident, notes: Option[String], collective: Ident): F[UpdateResult] - def setName(item: Ident, name: String, collective: Ident): F[AddResult] + def setName(item: Ident, name: String, collective: Ident): F[UpdateResult] + + def setNameMultiple( + items: NonEmptyList[Ident], + name: String, + collective: Ident + ): F[UpdateResult] def setState(item: Ident, state: ItemState, collective: Ident): F[AddResult] = setStates(NonEmptyList.of(item), state, collective) @@ -102,7 +108,7 @@ trait OItem[F[_]] { attachId: Ident, name: Option[String], collective: Ident - ): F[AddResult] + ): F[UpdateResult] /** Submits the item for re-processing. The list of attachment ids can * be used to only re-process a subset of the item's attachments. @@ -253,11 +259,12 @@ object OItem { item: Ident, folder: Option[Ident], collective: Ident - ): F[AddResult] = - store - .transact(RItem.updateFolder(item, collective, folder)) - .attempt - .map(AddResult.fromUpdate) + ): F[UpdateResult] = + UpdateResult + .fromUpdate( + store + .transact(RItem.updateFolder(item, collective, folder)) + ) .flatTap( onSuccessIgnoreError(fts.updateFolder(logger, item, collective, folder)) ) @@ -390,24 +397,47 @@ object OItem { item: Ident, notes: Option[String], collective: Ident - ): F[AddResult] = - store - .transact(RItem.updateNotes(item, collective, notes)) - .attempt - .map(AddResult.fromUpdate) + ): F[UpdateResult] = + UpdateResult + .fromUpdate( + store + .transact(RItem.updateNotes(item, collective, notes)) + ) .flatTap( onSuccessIgnoreError(fts.updateItemNotes(logger, item, collective, notes)) ) - def setName(item: Ident, name: String, collective: Ident): F[AddResult] = - store - .transact(RItem.updateName(item, collective, name)) - .attempt - .map(AddResult.fromUpdate) + def setName(item: Ident, name: String, collective: Ident): F[UpdateResult] = + UpdateResult + .fromUpdate( + store + .transact(RItem.updateName(item, collective, name)) + ) .flatTap( onSuccessIgnoreError(fts.updateItemName(logger, item, collective, name)) ) + def setNameMultiple( + items: NonEmptyList[Ident], + name: String, + collective: Ident + ): F[UpdateResult] = + for { + results <- items.traverse(i => setName(i, name, collective)) + err <- results.traverse { + case UpdateResult.NotFound => + logger.info("An item was not found when updating the name") *> 0.pure[F] + case UpdateResult.Failure(err) => + logger.error(err)("An item failed to update its name") *> 1.pure[F] + case UpdateResult.Success => + 0.pure[F] + } + res = + if (results.size == err.fold) + UpdateResult.failure(new Exception("All items failed to update")) + else UpdateResult.success + } yield res + def setStates( items: NonEmptyList[Ident], state: ItemState, @@ -455,11 +485,12 @@ object OItem { attachId: Ident, name: Option[String], collective: Ident - ): F[AddResult] = - store - .transact(RAttachment.updateName(attachId, collective, name)) - .attempt - .map(AddResult.fromUpdate) + ): F[UpdateResult] = + UpdateResult + .fromUpdate( + store + .transact(RAttachment.updateName(attachId, collective, name)) + ) .flatTap( onSuccessIgnoreError( OptionT(store.transact(RAttachment.findItemId(attachId))) @@ -499,17 +530,17 @@ object OItem { _ <- if (notifyJoex) joex.notifyAllNodes else ().pure[F] } yield UpdateResult.success - private def onSuccessIgnoreError(update: F[Unit])(ar: AddResult): F[Unit] = + private def onSuccessIgnoreError(update: F[Unit])(ar: UpdateResult): F[Unit] = ar match { - case AddResult.Success => + case UpdateResult.Success => update.attempt.flatMap { case Right(()) => ().pure[F] case Left(ex) => logger.warn(s"Error updating full-text index: ${ex.getMessage}") } - case AddResult.Failure(_) => + case UpdateResult.Failure(_) => ().pure[F] - case AddResult.EntityExists(_) => + case UpdateResult.NotFound => ().pure[F] } }) diff --git a/modules/restserver/src/main/scala/docspell/restserver/routes/ItemMultiRoutes.scala b/modules/restserver/src/main/scala/docspell/restserver/routes/ItemMultiRoutes.scala index e064c18b..9b4a0441 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/routes/ItemMultiRoutes.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/routes/ItemMultiRoutes.scala @@ -74,6 +74,19 @@ object ItemMultiRoutes { resp <- Ok(Conversions.basicResult(res, "Tags added.")) } yield resp + case req @ PUT -> Root / "name" => + for { + json <- req.as[ItemsAndName] + items <- readIds[F](json.items) + res <- backend.item.setNameMultiple( + items, + json.name.notEmpty.getOrElse(""), + user.account.collective + ) + resp <- Ok(Conversions.basicResult(res, "Name updated")) + } yield resp + + // case req @ PUT -> Root / "direction" => // for { // dir <- req.as[DirectionValue] @@ -116,17 +129,6 @@ object ItemMultiRoutes { // resp <- Ok(Conversions.basicResult(res, "Concerned equipment updated")) // } yield resp - // case req @ PUT -> Root / "name" => - // for { - // text <- req.as[OptionalText] - // res <- backend.item.setName( - // id, - // text.text.notEmpty.getOrElse(""), - // user.account.collective - // ) - // resp <- Ok(Conversions.basicResult(res, "Name updated")) - // } yield resp - // case req @ PUT -> Root / "duedate" => // for { // date <- req.as[OptionalDate] @@ -165,6 +167,10 @@ object ItemMultiRoutes { def notEmpty: Option[String] = opt.map(_.trim).filter(_.nonEmpty) } + implicit final class StringOps(str: String) { + def notEmpty: Option[String] = + Option(str).notEmpty + } private def readId[F[_]]( id: String diff --git a/modules/webapp/src/main/elm/Api.elm b/modules/webapp/src/main/elm/Api.elm index dc648f75..6811a90f 100644 --- a/modules/webapp/src/main/elm/Api.elm +++ b/modules/webapp/src/main/elm/Api.elm @@ -88,6 +88,7 @@ module Api exposing , setItemName , setItemNotes , setJobPrio + , setNameMultiple , setTags , setTagsMultiple , setUnconfirmed @@ -132,6 +133,7 @@ import Api.Model.ItemLightList exposing (ItemLightList) import Api.Model.ItemProposals exposing (ItemProposals) import Api.Model.ItemSearch exposing (ItemSearch) import Api.Model.ItemUploadMeta exposing (ItemUploadMeta) +import Api.Model.ItemsAndName exposing (ItemsAndName) import Api.Model.ItemsAndRefs exposing (ItemsAndRefs) import Api.Model.JobPriority exposing (JobPriority) import Api.Model.JobQueueState exposing (JobQueueState) @@ -1296,6 +1298,20 @@ addTagsMultiple flags data receive = } +setNameMultiple : + Flags + -> ItemsAndName + -> (Result Http.Error BasicResult -> msg) + -> Cmd msg +setNameMultiple flags data receive = + Http2.authPut + { url = flags.config.baseUrl ++ "/api/v1/sec/items/name" + , account = getAccount flags + , body = Http.jsonBody (Api.Model.ItemsAndName.encode data) + , expect = Http.expectJson receive Api.Model.BasicResult.decoder + } + + --- Item diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/FormChange.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/FormChange.elm index 4a483c44..1768f310 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/FormChange.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/FormChange.elm @@ -6,6 +6,7 @@ module Comp.ItemDetail.FormChange exposing import Api import Api.Model.BasicResult exposing (BasicResult) import Api.Model.IdName exposing (IdName) +import Api.Model.ItemsAndName exposing (ItemsAndName) import Api.Model.ItemsAndRefs exposing (ItemsAndRefs) import Api.Model.ReferenceList exposing (ReferenceList) import Data.Direction exposing (Direction) @@ -47,5 +48,12 @@ multiUpdate flags ids change receive = in Api.setTagsMultiple flags data receive + NameChange name -> + let + data = + ItemsAndName items name + in + Api.setNameMultiple flags data receive + _ -> Cmd.none