diff --git a/modules/backend/src/main/scala/docspell/backend/ops/OCollective.scala b/modules/backend/src/main/scala/docspell/backend/ops/OCollective.scala index 79f41d2b..715e8110 100644 --- a/modules/backend/src/main/scala/docspell/backend/ops/OCollective.scala +++ b/modules/backend/src/main/scala/docspell/backend/ops/OCollective.scala @@ -27,6 +27,8 @@ trait OCollective[F[_]] { def insights(collective: Ident): F[InsightData] + def tagCloud(collective: Ident): F[List[TagCount]] + def changePassword( accountId: AccountId, current: Password, @@ -116,6 +118,9 @@ object OCollective { def insights(collective: Ident): F[InsightData] = store.transact(QCollective.getInsights(collective)) + def tagCloud(collective: Ident): F[List[TagCount]] = + store.transact(QCollective.tagCloud(collective)) + def changePassword( accountId: AccountId, current: Password, diff --git a/modules/restapi/src/main/resources/docspell-openapi.yml b/modules/restapi/src/main/resources/docspell-openapi.yml index 10bd2488..b14b28d4 100644 --- a/modules/restapi/src/main/resources/docspell-openapi.yml +++ b/modules/restapi/src/main/resources/docspell-openapi.yml @@ -460,6 +460,7 @@ paths: responses: 200: description: Ok + /sec/tag: get: tags: [ Tags ] @@ -1011,6 +1012,22 @@ paths: application/json: schema: $ref: "#/components/schemas/ItemInsights" + /sec/collective/cloud: + get: + tags: [ Collective ] + summary: Summary of used tags. + description: | + Returns all tags and how often each has been applied. + security: + - authTokenHeader: [] + responses: + 200: + description: Ok + content: + application/json: + schema: + $ref: "#/components/schemas/TagCloud" + /sec/collective/contacts: get: tags: [ Collective ] @@ -3059,24 +3076,10 @@ components: - count properties: tag: - $ref: "#/components/schemas/TagLight" + $ref: "#/components/schemas/Tag" count: type: integer format: int32 - TagLight: - description: | - A subset of tag properties. - required: - - id - - name - properties: - id: - type: string - format: ident - name: - type: string - category: - type: string AttachmentMeta: description: | Extracted meta data of an attachment. diff --git a/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala b/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala index fc05d14b..f2f131f0 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala @@ -31,11 +31,11 @@ trait Conversions { d.incoming, d.outgoing, d.bytes, - TagCloud(d.tags.map(tc => TagCount(mkTagLight(tc), tc.count))) + mkTagCloud(d.tags) ) - def mkTagLight(t: OCollective.TagCount): TagLight = - TagLight(t.id, t.name, t.category) + def mkTagCloud(tags: List[OCollective.TagCount]) = + TagCloud(tags.map(tc => TagCount(mkTag(tc.tag), tc.count))) // attachment meta def mkAttachmentMeta(rm: RAttachmentMeta): AttachmentMeta = diff --git a/modules/restserver/src/main/scala/docspell/restserver/routes/CollectiveRoutes.scala b/modules/restserver/src/main/scala/docspell/restserver/routes/CollectiveRoutes.scala index 5294e8a6..6163b48b 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/routes/CollectiveRoutes.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/routes/CollectiveRoutes.scala @@ -28,6 +28,12 @@ object CollectiveRoutes { resp <- Ok(Conversions.mkItemInsights(ins)) } yield resp + case GET -> Root / "cloud" => + for { + cloud <- backend.collective.tagCloud(user.account.collective) + resp <- Ok(Conversions.mkTagCloud(cloud)) + } yield resp + case req @ POST -> Root / "settings" => for { settings <- req.as[CollectiveSettings] diff --git a/modules/store/src/main/scala/docspell/store/queries/QCollective.scala b/modules/store/src/main/scala/docspell/store/queries/QCollective.scala index fbe814dc..2dc94e05 100644 --- a/modules/store/src/main/scala/docspell/store/queries/QCollective.scala +++ b/modules/store/src/main/scala/docspell/store/queries/QCollective.scala @@ -11,7 +11,7 @@ import doobie._ import doobie.implicits._ object QCollective { - case class TagCount(id: Ident, name: String, category: Option[String], count: Int) + case class TagCount(tag: RTag, count: Int) case class InsightData( incoming: Int, @@ -22,8 +22,6 @@ object QCollective { def getInsights(coll: Ident): ConnectionIO[InsightData] = { val IC = RItem.Columns - val TC = RTag.Columns - val RC = RTagItem.Columns val q0 = selectCount( IC.id, RItem.table, @@ -52,25 +50,33 @@ object QCollective { inner join filemeta m on m.id = a.file_id where a.id in (select aid from attachs) ) as t""".query[Option[Long]].unique + for { + n0 <- q0 + n1 <- q1 + n2 <- fileSize + n3 <- tagCloud(coll) + } yield InsightData(n0, n1, n2.getOrElse(0L), n3) + } + + def tagCloud(coll: Ident): ConnectionIO[List[TagCount]] = { + val TC = RTag.Columns + val RC = RTagItem.Columns + val q3 = fr"SELECT" ++ commas( - TC.tid.prefix("t").f, - TC.name.prefix("t").f, - TC.category.prefix("t").f, - fr"count(" ++ RC.itemId.prefix("r").f ++ fr")" + TC.all.map(_.prefix("t").f) ++ Seq(fr"count(" ++ RC.itemId.prefix("r").f ++ fr")") ) ++ fr"FROM" ++ RTagItem.table ++ fr"r" ++ fr"INNER JOIN" ++ RTag.table ++ fr"t ON" ++ RC.tagId .prefix("r") .is(TC.tid.prefix("t")) ++ fr"WHERE" ++ TC.cid.prefix("t").is(coll) ++ - fr"GROUP BY" ++ commas(TC.name.prefix("t").f, TC.tid.prefix("t").f, TC.category.prefix("t").f) + fr"GROUP BY" ++ commas( + TC.name.prefix("t").f, + TC.tid.prefix("t").f, + TC.category.prefix("t").f + ) - for { - n0 <- q0 - n1 <- q1 - n2 <- fileSize - n3 <- q3.query[TagCount].to[List] - } yield InsightData(n0, n1, n2.getOrElse(0L), n3) + q3.query[TagCount].to[List] } def getContacts(