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 65c00771..fd3e5344 100644 --- a/modules/backend/src/main/scala/docspell/backend/ops/OItem.scala +++ b/modules/backend/src/main/scala/docspell/backend/ops/OItem.scala @@ -130,6 +130,8 @@ trait OItem[F[_]] { def deleteItem(itemId: Ident, collective: Ident): F[Int] + def deleteItemMultiple(items: NonEmptyList[Ident], collective: Ident): F[Int] + def deleteAttachment(id: Ident, collective: Ident): F[Int] def moveAttachmentBefore(itemId: Ident, source: Ident, target: Ident): F[AddResult] @@ -547,6 +549,13 @@ object OItem { .delete(store)(itemId, collective) .flatTap(_ => fts.removeItem(logger, itemId)) + def deleteItemMultiple(items: NonEmptyList[Ident], collective: Ident): F[Int] = + for { + itemIds <- store.transact(RItem.filterItems(items, collective)) + results <- itemIds.traverse(item => deleteItem(item, collective)) + n = results.fold(0)(_ + _) + } yield n + def getProposals(item: Ident, collective: Ident): F[MetaProposalList] = store.transact(QAttachment.getMetaProposals(item, collective)) 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 9865e71f..3cb50f6e 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/routes/ItemMultiRoutes.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/routes/ItemMultiRoutes.scala @@ -151,18 +151,23 @@ object ItemMultiRoutes { case req @ POST -> Root / "reprocess" => for { - json <- req.as[IdList] + json <- req.as[IdList] items <- readIds[F](json.ids) - res <- backend.item.reprocessAll(items, user.account, true) - resp <- Ok(Conversions.basicResult(res, "Re-process task(s) submitted.")) + res <- backend.item.reprocessAll(items, user.account, true) + resp <- Ok(Conversions.basicResult(res, "Re-process task(s) submitted.")) } yield resp - // case POST -> Root / "deleteAll" => - // for { - // n <- backend.item.deleteItem(id, user.account.collective) - // res = BasicResult(n > 0, if (n > 0) "Item deleted" else "Item deletion failed.") - // resp <- Ok(res) - // } yield resp + case req @ POST -> Root / "deleteAll" => + for { + json <- req.as[IdList] + items <- readIds[F](json.ids) + n <- backend.item.deleteItemMultiple(items, user.account.collective) + res = BasicResult( + n > 0, + if (n > 0) "Item(s) deleted" else "Item deletion failed." + ) + resp <- Ok(res) + } yield resp } } diff --git a/modules/webapp/src/main/elm/Api.elm b/modules/webapp/src/main/elm/Api.elm index d6a8edbb..77ee3c20 100644 --- a/modules/webapp/src/main/elm/Api.elm +++ b/modules/webapp/src/main/elm/Api.elm @@ -15,6 +15,7 @@ module Api exposing , createNewFolder , createNotifyDueItems , createScanMailbox + , deleteAllItems , deleteAttachment , deleteEquip , deleteFolder @@ -130,6 +131,7 @@ import Api.Model.EquipmentList exposing (EquipmentList) import Api.Model.FolderDetail exposing (FolderDetail) import Api.Model.FolderList exposing (FolderList) import Api.Model.GenInvite exposing (GenInvite) +import Api.Model.IdList exposing (IdList) import Api.Model.IdResult exposing (IdResult) import Api.Model.ImapSettings exposing (ImapSettings) import Api.Model.ImapSettingsList exposing (ImapSettingsList) @@ -182,6 +184,7 @@ import Data.Priority exposing (Priority) import File exposing (File) import Http import Json.Encode as JsonEncode +import Set exposing (Set) import Task import Url import Util.File @@ -1435,6 +1438,20 @@ setConcEquipmentMultiple flags data receive = } +deleteAllItems : + Flags + -> Set String + -> (Result Http.Error BasicResult -> msg) + -> Cmd msg +deleteAllItems flags ids receive = + Http2.authPost + { url = flags.config.baseUrl ++ "/api/v1/sec/items/deleteAll" + , account = getAccount flags + , body = Http.jsonBody (Api.Model.IdList.encode (IdList (Set.toList ids))) + , expect = Http.expectJson receive Api.Model.BasicResult.decoder + } + + --- Item diff --git a/modules/webapp/src/main/elm/Page/Home/Data.elm b/modules/webapp/src/main/elm/Page/Home/Data.elm index 27a64671..2c6909a8 100644 --- a/modules/webapp/src/main/elm/Page/Home/Data.elm +++ b/modules/webapp/src/main/elm/Page/Home/Data.elm @@ -169,6 +169,7 @@ type Msg | EditMenuMsg Comp.ItemDetail.EditMenu.Msg | MultiUpdateResp (Result Http.Error BasicResult) | ReplaceChangedItemsResp (Result Http.Error ItemLightList) + | DeleteAllResp (Result Http.Error BasicResult) type SearchType diff --git a/modules/webapp/src/main/elm/Page/Home/Update.elm b/modules/webapp/src/main/elm/Page/Home/Update.elm index 9d0884ea..b9c3684f 100644 --- a/modules/webapp/src/main/elm/Page/Home/Update.elm +++ b/modules/webapp/src/main/elm/Page/Home/Update.elm @@ -346,7 +346,7 @@ update mId key flags settings msg model = cmd = if confirmed then - Cmd.none + Api.deleteAllItems flags svm.ids DeleteAllResp else Cmd.none @@ -373,6 +373,20 @@ update mId key flags settings msg model = _ -> noSub ( model, Cmd.none ) + DeleteAllResp (Ok res) -> + if res.success then + let + nm = + { model | viewMode = SearchView } + in + doSearch flags settings False nm + + else + noSub ( model, Cmd.none ) + + DeleteAllResp (Err _) -> + noSub ( model, Cmd.none ) + RequestDeleteSelected -> case model.viewMode of SelectView svm ->