Merge pull request #955 from eikek/set-tags-api

Set tags api
This commit is contained in:
mergify[bot] 2021-07-25 21:37:47 +00:00 committed by GitHub
commit c4b86fdf70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 61 additions and 21 deletions

View File

@ -24,7 +24,7 @@ import org.log4s.getLogger
trait OItem[F[_]] { trait OItem[F[_]] {
/** Sets the given tags (removing all existing ones). */ /** Sets the given tags (removing all existing ones). */
def setTags(item: Ident, tagIds: List[Ident], collective: Ident): F[UpdateResult] def setTags(item: Ident, tagIds: List[String], collective: Ident): F[UpdateResult]
/** Sets tags for multiple items. The tags of the items will be /** Sets tags for multiple items. The tags of the items will be
* replaced with the given ones. Same as `setTags` but for multiple * replaced with the given ones. Same as `setTags` but for multiple
@ -32,7 +32,7 @@ trait OItem[F[_]] {
*/ */
def setTagsMultipleItems( def setTagsMultipleItems(
items: NonEmptyList[Ident], items: NonEmptyList[Ident],
tags: List[Ident], tags: List[String],
collective: Ident collective: Ident
): F[UpdateResult] ): F[UpdateResult]
@ -304,19 +304,20 @@ object OItem {
def setTags( def setTags(
item: Ident, item: Ident,
tagIds: List[Ident], tagIds: List[String],
collective: Ident collective: Ident
): F[UpdateResult] = ): F[UpdateResult] =
setTagsMultipleItems(NonEmptyList.of(item), tagIds, collective) setTagsMultipleItems(NonEmptyList.of(item), tagIds, collective)
def setTagsMultipleItems( def setTagsMultipleItems(
items: NonEmptyList[Ident], items: NonEmptyList[Ident],
tags: List[Ident], tags: List[String],
collective: Ident collective: Ident
): F[UpdateResult] = ): F[UpdateResult] =
UpdateResult.fromUpdate(store.transact(for { UpdateResult.fromUpdate(store.transact(for {
k <- RTagItem.deleteItemTags(items, collective) k <- RTagItem.deleteItemTags(items, collective)
res <- items.traverse(i => RTagItem.setAllTags(i, tags)) rtags <- RTag.findAllByNameOrId(tags, collective)
res <- items.traverse(i => RTagItem.setAllTags(i, rtags.map(_.tagId)))
n = res.fold n = res.fold
} yield k + n)) } yield k + n))

View File

@ -1628,6 +1628,8 @@ paths:
Update the tags associated to an item. This will remove all Update the tags associated to an item. This will remove all
existing ones and sets the given tags, such that after this existing ones and sets the given tags, such that after this
returns, the item has exactly the tags as given. returns, the item has exactly the tags as given.
Tags may be specified as names or ids.
security: security:
- authTokenHeader: [] - authTokenHeader: []
parameters: parameters:
@ -1636,7 +1638,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/ReferenceList" $ref: "#/components/schemas/StringList"
responses: responses:
200: 200:
description: Ok description: Ok
@ -1672,7 +1674,7 @@ paths:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/taglink: /sec/item/{id}/taglink:
post: put:
operationId: "sec-item-link-tags" operationId: "sec-item-link-tags"
tags: [Item] tags: [Item]
summary: Link existing tags to an item. summary: Link existing tags to an item.
@ -1725,6 +1727,31 @@ paths:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/tagsremove:
post:
operationId: "sec-item-remove-tags"
tags: [ Item ]
summary: Remove tags from an item
description: |
Remove the given tags from the item. The tags can be specified
via ids or names.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/StringList"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/direction: /sec/item/{id}/direction:
put: put:
operationId: "sec-item-set-direction" operationId: "sec-item-set-direction"

View File

@ -59,8 +59,11 @@ object ItemMultiRoutes extends MultiIdSupport {
for { for {
json <- req.as[ItemsAndRefs] json <- req.as[ItemsAndRefs]
items <- readIds[F](json.items) items <- readIds[F](json.items)
tags <- json.refs.traverse(readId[F]) res <- backend.item.setTagsMultipleItems(
res <- backend.item.setTagsMultipleItems(items, tags, user.account.collective) items,
json.refs,
user.account.collective
)
resp <- Ok(Conversions.basicResult(res, "Tags updated")) resp <- Ok(Conversions.basicResult(res, "Tags updated"))
} yield resp } yield resp

View File

@ -146,8 +146,8 @@ object ItemRoutes {
case req @ PUT -> Root / Ident(id) / "tags" => case req @ PUT -> Root / Ident(id) / "tags" =>
for { for {
tags <- req.as[ReferenceList].map(_.items) tags <- req.as[StringList].map(_.items)
res <- backend.item.setTags(id, tags.map(_.id), user.account.collective) res <- backend.item.setTags(id, tags, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Tags updated")) resp <- Ok(Conversions.basicResult(res, "Tags updated"))
} yield resp } yield resp
@ -173,6 +173,17 @@ object ItemRoutes {
resp <- Ok(Conversions.basicResult(res, "Tags linked")) resp <- Ok(Conversions.basicResult(res, "Tags linked"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "tagsremove" =>
for {
json <- req.as[StringList]
res <- backend.item.removeTagsMultipleItems(
NonEmptyList.of(id),
json.items,
user.account.collective
)
resp <- Ok(Conversions.basicResult(res, "Tags removed"))
} yield resp
case req @ PUT -> Root / Ident(id) / "direction" => case req @ PUT -> Root / Ident(id) / "direction" =>
for { for {
dir <- req.as[DirectionValue] dir <- req.as[DirectionValue]

View File

@ -1783,12 +1783,12 @@ itemDetail flags id receive =
} }
setTags : Flags -> String -> ReferenceList -> (Result Http.Error BasicResult -> msg) -> Cmd msg setTags : Flags -> String -> StringList -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setTags flags item tags receive = setTags flags item tags receive =
Http2.authPut Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/tags" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/tags"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.ReferenceList.encode tags) , body = Http.jsonBody (Api.Model.StringList.encode tags)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder , expect = Http.expectJson receive Api.Model.BasicResult.decoder
} }

View File

@ -19,11 +19,9 @@ import Api.Model.MoveAttachment exposing (MoveAttachment)
import Api.Model.OptionalDate exposing (OptionalDate) import Api.Model.OptionalDate exposing (OptionalDate)
import Api.Model.OptionalId exposing (OptionalId) import Api.Model.OptionalId exposing (OptionalId)
import Api.Model.OptionalText exposing (OptionalText) import Api.Model.OptionalText exposing (OptionalText)
import Api.Model.ReferenceList exposing (ReferenceList) import Api.Model.StringList exposing (StringList)
import Api.Model.Tag exposing (Tag)
import Browser.Navigation as Nav import Browser.Navigation as Nav
import Comp.AttachmentMeta import Comp.AttachmentMeta
import Comp.ConfirmModal
import Comp.CustomFieldMultiInput import Comp.CustomFieldMultiInput
import Comp.DatePicker import Comp.DatePicker
import Comp.DetailEdit import Comp.DetailEdit
@ -1628,8 +1626,8 @@ saveTags flags model =
tags = tags =
Comp.Dropdown.getSelected model.tagModel Comp.Dropdown.getSelected model.tagModel
|> Util.List.distinct |> Util.List.distinct
|> List.map (\t -> IdName t.id t.name) |> List.map (\t -> t.id)
|> ReferenceList |> StringList
in in
Api.setTags flags model.item.id tags SaveResp Api.setTags flags model.item.id tags SaveResp
@ -1762,7 +1760,7 @@ resetField : Flags -> String -> (Field -> Result Http.Error BasicResult -> msg)
resetField flags item tagger field = resetField flags item tagger field =
case field of case field of
Data.Fields.Tag -> Data.Fields.Tag ->
Api.setTags flags item Api.Model.ReferenceList.empty (tagger Data.Fields.Tag) Api.setTags flags item Api.Model.StringList.empty (tagger Data.Fields.Tag)
Data.Fields.Folder -> Data.Fields.Folder ->
Api.setFolder flags item Api.Model.OptionalId.empty (tagger Data.Fields.Folder) Api.setFolder flags item Api.Model.OptionalId.empty (tagger Data.Fields.Folder)