mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-05 22:55:58 +00:00
Return member count and if current user is owner or member
This commit is contained in:
parent
ea4ab11195
commit
60a08fc786
@ -10,12 +10,12 @@ import docspell.store.queries.QSpace
|
|||||||
trait OSpace[F[_]] {
|
trait OSpace[F[_]] {
|
||||||
|
|
||||||
def findAll(
|
def findAll(
|
||||||
collective: Ident,
|
account: AccountId,
|
||||||
ownerLogin: Option[Ident],
|
ownerLogin: Option[Ident],
|
||||||
nameQuery: Option[String]
|
nameQuery: Option[String]
|
||||||
): F[Vector[OSpace.SpaceItem]]
|
): F[Vector[OSpace.SpaceItem]]
|
||||||
|
|
||||||
def findById(id: Ident, collective: Ident): F[Option[OSpace.SpaceDetail]]
|
def findById(id: Ident, account: AccountId): F[Option[OSpace.SpaceDetail]]
|
||||||
|
|
||||||
/** Adds a new space. If `login` is non-empty, the `space.user`
|
/** Adds a new space. If `login` is non-empty, the `space.user`
|
||||||
* property is ignored and the user-id is determined by the given
|
* property is ignored and the user-id is determined by the given
|
||||||
@ -58,14 +58,14 @@ object OSpace {
|
|||||||
def apply[F[_]: Effect](store: Store[F]): Resource[F, OSpace[F]] =
|
def apply[F[_]: Effect](store: Store[F]): Resource[F, OSpace[F]] =
|
||||||
Resource.pure[F, OSpace[F]](new OSpace[F] {
|
Resource.pure[F, OSpace[F]](new OSpace[F] {
|
||||||
def findAll(
|
def findAll(
|
||||||
collective: Ident,
|
account: AccountId,
|
||||||
ownerLogin: Option[Ident],
|
ownerLogin: Option[Ident],
|
||||||
nameQuery: Option[String]
|
nameQuery: Option[String]
|
||||||
): F[Vector[SpaceItem]] =
|
): F[Vector[SpaceItem]] =
|
||||||
store.transact(QSpace.findAll(collective, None, ownerLogin, nameQuery))
|
store.transact(QSpace.findAll(account, None, ownerLogin, nameQuery))
|
||||||
|
|
||||||
def findById(id: Ident, collective: Ident): F[Option[SpaceDetail]] =
|
def findById(id: Ident, account: AccountId): F[Option[SpaceDetail]] =
|
||||||
store.transact(QSpace.findById(id, collective))
|
store.transact(QSpace.findById(id, account))
|
||||||
|
|
||||||
def add(space: RSpace, login: Option[Ident]): F[AddResult] = {
|
def add(space: RSpace, login: Option[Ident]): F[AddResult] = {
|
||||||
val insert = login match {
|
val insert = login match {
|
||||||
|
@ -2510,6 +2510,8 @@ components:
|
|||||||
- name
|
- name
|
||||||
- owner
|
- owner
|
||||||
- created
|
- created
|
||||||
|
- isMember
|
||||||
|
- memberCount
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
@ -2521,6 +2523,11 @@ components:
|
|||||||
created:
|
created:
|
||||||
type: integer
|
type: integer
|
||||||
format: date-time
|
format: date-time
|
||||||
|
isMember:
|
||||||
|
type: boolean
|
||||||
|
memberCount:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
NewSpace:
|
NewSpace:
|
||||||
description: |
|
description: |
|
||||||
Data required to create a new space.
|
Data required to create a new space.
|
||||||
@ -2537,6 +2544,8 @@ components:
|
|||||||
- name
|
- name
|
||||||
- owner
|
- owner
|
||||||
- created
|
- created
|
||||||
|
- isMember
|
||||||
|
- memberCount
|
||||||
- members
|
- members
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
@ -2549,6 +2558,11 @@ components:
|
|||||||
created:
|
created:
|
||||||
type: integer
|
type: integer
|
||||||
format: date-time
|
format: date-time
|
||||||
|
isMember:
|
||||||
|
type: boolean
|
||||||
|
memberCount:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
members:
|
members:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
@ -15,8 +15,8 @@ import docspell.common.syntax.all._
|
|||||||
import docspell.ftsclient.FtsResult
|
import docspell.ftsclient.FtsResult
|
||||||
import docspell.restapi.model._
|
import docspell.restapi.model._
|
||||||
import docspell.restserver.conv.Conversions._
|
import docspell.restserver.conv.Conversions._
|
||||||
import docspell.store.{AddResult, UpdateResult}
|
|
||||||
import docspell.store.records._
|
import docspell.store.records._
|
||||||
|
import docspell.store.{AddResult, UpdateResult}
|
||||||
|
|
||||||
import bitpeace.FileMeta
|
import bitpeace.FileMeta
|
||||||
import org.http4s.headers.`Content-Type`
|
import org.http4s.headers.`Content-Type`
|
||||||
|
@ -8,10 +8,10 @@ import docspell.backend.BackendApp
|
|||||||
import docspell.backend.auth.AuthToken
|
import docspell.backend.auth.AuthToken
|
||||||
import docspell.backend.ops.OSpace
|
import docspell.backend.ops.OSpace
|
||||||
import docspell.common._
|
import docspell.common._
|
||||||
import docspell.store.records.RSpace
|
|
||||||
import docspell.restapi.model._
|
import docspell.restapi.model._
|
||||||
import docspell.restserver.conv.Conversions
|
import docspell.restserver.conv.Conversions
|
||||||
import docspell.restserver.http4s._
|
import docspell.restserver.http4s._
|
||||||
|
import docspell.store.records.RSpace
|
||||||
|
|
||||||
import org.http4s.HttpRoutes
|
import org.http4s.HttpRoutes
|
||||||
import org.http4s.circe.CirceEntityDecoder._
|
import org.http4s.circe.CirceEntityDecoder._
|
||||||
@ -29,7 +29,7 @@ object SpaceRoutes {
|
|||||||
val login =
|
val login =
|
||||||
owning.filter(identity).map(_ => user.account.user)
|
owning.filter(identity).map(_ => user.account.user)
|
||||||
for {
|
for {
|
||||||
all <- backend.space.findAll(user.account.collective, login, q.map(_.q))
|
all <- backend.space.findAll(user.account, login, q.map(_.q))
|
||||||
resp <- Ok(SpaceList(all.map(mkSpace).toList))
|
resp <- Ok(SpaceList(all.map(mkSpace).toList))
|
||||||
} yield resp
|
} yield resp
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ object SpaceRoutes {
|
|||||||
|
|
||||||
case GET -> Root / Ident(id) =>
|
case GET -> Root / Ident(id) =>
|
||||||
(for {
|
(for {
|
||||||
space <- OptionT(backend.space.findById(id, user.account.collective))
|
space <- OptionT(backend.space.findById(id, user.account))
|
||||||
resp <- OptionT.liftF(Ok(mkSpaceDetail(space)))
|
resp <- OptionT.liftF(Ok(mkSpaceDetail(space)))
|
||||||
} yield resp).getOrElseF(NotFound())
|
} yield resp).getOrElseF(NotFound())
|
||||||
|
|
||||||
@ -82,7 +82,9 @@ object SpaceRoutes {
|
|||||||
item.id,
|
item.id,
|
||||||
item.name,
|
item.name,
|
||||||
Conversions.mkIdName(item.owner),
|
Conversions.mkIdName(item.owner),
|
||||||
item.created
|
item.created,
|
||||||
|
item.member,
|
||||||
|
item.memberCount
|
||||||
)
|
)
|
||||||
|
|
||||||
private def mkSpaceDetail(item: OSpace.SpaceDetail): SpaceDetail =
|
private def mkSpaceDetail(item: OSpace.SpaceDetail): SpaceDetail =
|
||||||
@ -91,6 +93,8 @@ object SpaceRoutes {
|
|||||||
item.name,
|
item.name,
|
||||||
Conversions.mkIdName(item.owner),
|
Conversions.mkIdName(item.owner),
|
||||||
item.created,
|
item.created,
|
||||||
|
item.member,
|
||||||
|
item.memberCount,
|
||||||
item.members.map(Conversions.mkIdName)
|
item.members.map(Conversions.mkIdName)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,10 +16,12 @@ object QSpace {
|
|||||||
id: Ident,
|
id: Ident,
|
||||||
name: String,
|
name: String,
|
||||||
owner: IdRef,
|
owner: IdRef,
|
||||||
created: Timestamp
|
created: Timestamp,
|
||||||
|
member: Boolean,
|
||||||
|
memberCount: Int
|
||||||
) {
|
) {
|
||||||
def withMembers(members: List[IdRef]): SpaceDetail =
|
def withMembers(members: List[IdRef]): SpaceDetail =
|
||||||
SpaceDetail(id, name, owner, created, members)
|
SpaceDetail(id, name, owner, created, member, memberCount, members)
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class SpaceDetail(
|
final case class SpaceDetail(
|
||||||
@ -27,6 +29,8 @@ object QSpace {
|
|||||||
name: String,
|
name: String,
|
||||||
owner: IdRef,
|
owner: IdRef,
|
||||||
created: Timestamp,
|
created: Timestamp,
|
||||||
|
member: Boolean,
|
||||||
|
memberCount: Int,
|
||||||
members: List[IdRef]
|
members: List[IdRef]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -130,7 +134,7 @@ object QSpace {
|
|||||||
} yield res).getOrElse(SpaceChangeResult.notFound)
|
} yield res).getOrElse(SpaceChangeResult.notFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
def findById(id: Ident, collective: Ident): ConnectionIO[Option[SpaceDetail]] = {
|
def findById(id: Ident, account: AccountId): ConnectionIO[Option[SpaceDetail]] = {
|
||||||
val mUserId = RSpaceMember.Columns.user.prefix("m")
|
val mUserId = RSpaceMember.Columns.user.prefix("m")
|
||||||
val mSpaceId = RSpaceMember.Columns.space.prefix("m")
|
val mSpaceId = RSpaceMember.Columns.space.prefix("m")
|
||||||
val uId = RUser.Columns.uid.prefix("u")
|
val uId = RUser.Columns.uid.prefix("u")
|
||||||
@ -145,44 +149,99 @@ object QSpace {
|
|||||||
val memberQ = selectSimple(
|
val memberQ = selectSimple(
|
||||||
Seq(uId, uLogin),
|
Seq(uId, uLogin),
|
||||||
from,
|
from,
|
||||||
and(mSpaceId.is(id), sColl.is(collective))
|
and(mSpaceId.is(id), sColl.is(account.collective))
|
||||||
).query[IdRef].to[Vector]
|
).query[IdRef].to[Vector]
|
||||||
|
|
||||||
(for {
|
(for {
|
||||||
space <- OptionT(findAll(collective, Some(id), None, None).map(_.headOption))
|
space <- OptionT(findAll(account, Some(id), None, None).map(_.headOption))
|
||||||
memb <- OptionT.liftF(memberQ)
|
memb <- OptionT.liftF(memberQ)
|
||||||
} yield space.withMembers(memb.toList)).value
|
} yield space.withMembers(memb.toList)).value
|
||||||
}
|
}
|
||||||
|
|
||||||
def findAll(
|
def findAll(
|
||||||
collective: Ident,
|
account: AccountId,
|
||||||
idQ: Option[Ident],
|
idQ: Option[Ident],
|
||||||
ownerLogin: Option[Ident],
|
ownerLogin: Option[Ident],
|
||||||
nameQ: Option[String]
|
nameQ: Option[String]
|
||||||
): ConnectionIO[Vector[SpaceItem]] = {
|
): ConnectionIO[Vector[SpaceItem]] = {
|
||||||
|
// with memberlogin as
|
||||||
|
// (select m.space_id,u.login
|
||||||
|
// from space_member m
|
||||||
|
// inner join user_ u on u.uid = m.user_id
|
||||||
|
// inner join space s on s.id = m.space_id
|
||||||
|
// where s.cid = 'eike'
|
||||||
|
// union all
|
||||||
|
// select s.id,u.login
|
||||||
|
// from space s
|
||||||
|
// inner join user_ u on u.uid = s.owner
|
||||||
|
// where s.cid = 'eike')
|
||||||
|
// select s.id
|
||||||
|
// ,s.name
|
||||||
|
// ,s.owner
|
||||||
|
// ,u.login
|
||||||
|
// ,s.created
|
||||||
|
// ,(select count(*) > 0 from memberlogin where space_id = s.id and login = 'eike') as member
|
||||||
|
// ,(select count(*) - 1 from memberlogin where space_id = s.id) as member_count
|
||||||
|
// from space s
|
||||||
|
// inner join user_ u on u.uid = s.owner
|
||||||
|
// where s.cid = 'eike';
|
||||||
|
|
||||||
val uId = RUser.Columns.uid.prefix("u")
|
val uId = RUser.Columns.uid.prefix("u")
|
||||||
val uLogin = RUser.Columns.login.prefix("u")
|
val uLogin = RUser.Columns.login.prefix("u")
|
||||||
val sId = RSpace.Columns.id.prefix("s")
|
val sId = RSpace.Columns.id.prefix("s")
|
||||||
val sOwner = RSpace.Columns.owner.prefix("s")
|
val sOwner = RSpace.Columns.owner.prefix("s")
|
||||||
val sName = RSpace.Columns.name.prefix("s")
|
val sName = RSpace.Columns.name.prefix("s")
|
||||||
val sColl = RSpace.Columns.collective.prefix("s")
|
val sColl = RSpace.Columns.collective.prefix("s")
|
||||||
|
val mUser = RSpaceMember.Columns.user.prefix("m")
|
||||||
|
val mSpace = RSpaceMember.Columns.space.prefix("m")
|
||||||
|
|
||||||
|
//CTE
|
||||||
|
val cte: Fragment = {
|
||||||
|
val from1 = RSpaceMember.table ++ fr"m INNER JOIN" ++
|
||||||
|
RUser.table ++ fr"u ON" ++ uId.is(mUser) ++ fr"INNER JOIN" ++
|
||||||
|
RSpace.table ++ fr"s ON" ++ sId.is(mSpace)
|
||||||
|
|
||||||
|
val from2 = RSpace.table ++ fr"s INNER JOIN" ++
|
||||||
|
RUser.table ++ fr"u ON" ++ uId.is(sOwner)
|
||||||
|
|
||||||
|
withCTE(
|
||||||
|
"memberlogin" ->
|
||||||
|
(selectSimple(Seq(mSpace, uLogin), from1, sColl.is(account.collective)) ++
|
||||||
|
fr"UNION ALL" ++
|
||||||
|
selectSimple(Seq(sId, uLogin), from2, sColl.is(account.collective)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val isMember =
|
||||||
|
fr"SELECT COUNT(*) > 0 FROM memberlogin WHERE" ++ mSpace.prefix("").is(sId) ++
|
||||||
|
fr"AND" ++ uLogin.prefix("").is(account.user)
|
||||||
|
|
||||||
|
val memberCount =
|
||||||
|
fr"SELECT COUNT(*) - 1 FROM memberlogin WHERE" ++ mSpace.prefix("").is(sId)
|
||||||
|
|
||||||
|
//Query
|
||||||
val cols = Seq(
|
val cols = Seq(
|
||||||
sId,
|
sId.f,
|
||||||
sName,
|
sName.f,
|
||||||
uId,
|
sOwner.f,
|
||||||
RUser.Columns.login.prefix("u"),
|
uLogin.f,
|
||||||
RSpace.Columns.created.prefix("s")
|
RSpace.Columns.created.prefix("s").f,
|
||||||
|
fr"(" ++ isMember ++ fr") as mem",
|
||||||
|
fr"(" ++ memberCount ++ fr") as cnt"
|
||||||
)
|
)
|
||||||
|
|
||||||
val from = RSpace.table ++ fr"s INNER JOIN" ++
|
val from = RSpace.table ++ fr"s INNER JOIN" ++
|
||||||
RUser.table ++ fr"u ON" ++ uId.is(sOwner)
|
RUser.table ++ fr"u ON" ++ uId.is(sOwner)
|
||||||
|
|
||||||
val where =
|
val where =
|
||||||
sColl.is(collective) :: idQ.toList.map(id => sId.is(id)) ::: nameQ.toList.map(q =>
|
sColl.is(account.collective) :: idQ.toList
|
||||||
|
.map(id => sId.is(id)) ::: nameQ.toList.map(q =>
|
||||||
sName.lowerLike(s"%${q.toLowerCase}%")
|
sName.lowerLike(s"%${q.toLowerCase}%")
|
||||||
) ::: ownerLogin.toList.map(login => uLogin.is(login))
|
) ::: ownerLogin.toList.map(login => uLogin.is(login))
|
||||||
|
|
||||||
selectSimple(cols, from, and(where) ++ orderBy(sName.asc)).query[SpaceItem].to[Vector]
|
(cte ++ selectSimple(commas(cols), from, and(where) ++ orderBy(sName.asc)))
|
||||||
|
.query[SpaceItem]
|
||||||
|
.to[Vector]
|
||||||
}
|
}
|
||||||
|
|
||||||
private def findUserId(account: AccountId): ConnectionIO[Option[Ident]] =
|
private def findUserId(account: AccountId): ConnectionIO[Option[Ident]] =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user