mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-04-04 10:29:34 +00:00
Add routes to manage spaces
This commit is contained in:
parent
7ec0fc2593
commit
c12201c4a5
@ -35,6 +35,7 @@ trait BackendApp[F[_]] {
|
||||
def mail: OMail[F]
|
||||
def joex: OJoex[F]
|
||||
def userTask: OUserTask[F]
|
||||
def space: OSpace[F]
|
||||
}
|
||||
|
||||
object BackendApp {
|
||||
@ -67,6 +68,7 @@ object BackendApp {
|
||||
JavaMailEmil(blocker, Settings.defaultSettings.copy(debug = cfg.mailDebug))
|
||||
mailImpl <- OMail(store, javaEmil)
|
||||
userTaskImpl <- OUserTask(utStore, queue, joexImpl)
|
||||
spaceImpl <- OSpace(store)
|
||||
} yield new BackendApp[F] {
|
||||
val login: Login[F] = loginImpl
|
||||
val signup: OSignup[F] = signupImpl
|
||||
@ -84,6 +86,7 @@ object BackendApp {
|
||||
val mail = mailImpl
|
||||
val joex = joexImpl
|
||||
val userTask = userTaskImpl
|
||||
val space = spaceImpl
|
||||
}
|
||||
|
||||
def apply[F[_]: ConcurrentEffect: ContextShift](
|
||||
|
@ -0,0 +1,84 @@
|
||||
package docspell.backend.ops
|
||||
|
||||
import cats.effect._
|
||||
|
||||
import docspell.common._
|
||||
import docspell.store.{AddResult, Store}
|
||||
import docspell.store.records.RSpace
|
||||
|
||||
trait OSpace[F[_]] {
|
||||
|
||||
def findAll(account: AccountId, nameQuery: Option[String]): F[Vector[OSpace.SpaceItem]]
|
||||
|
||||
def findById(id: Ident, collective: Ident): F[Option[OSpace.SpaceDetail]]
|
||||
|
||||
def delete(id: Ident, collective: Ident): F[Int]
|
||||
|
||||
def add(space: RSpace): F[AddResult]
|
||||
|
||||
def changeName(space: Ident, account: AccountId, name: String): F[AddResult]
|
||||
|
||||
def addMember(
|
||||
space: Ident,
|
||||
account: AccountId,
|
||||
member: Ident
|
||||
): F[OSpace.MemberChangeResult]
|
||||
def removeMember(
|
||||
space: Ident,
|
||||
account: AccountId,
|
||||
member: Ident
|
||||
): F[OSpace.MemberChangeResult]
|
||||
}
|
||||
|
||||
object OSpace {
|
||||
|
||||
sealed trait MemberChangeResult
|
||||
object MemberChangeResult {
|
||||
case object Success extends MemberChangeResult
|
||||
case object NotFound extends MemberChangeResult
|
||||
case object Forbidden extends MemberChangeResult
|
||||
}
|
||||
|
||||
final case class SpaceItem(
|
||||
id: Ident,
|
||||
name: String,
|
||||
owner: IdRef,
|
||||
created: Timestamp,
|
||||
members: Int
|
||||
)
|
||||
|
||||
final case class SpaceDetail(
|
||||
id: Ident,
|
||||
name: String,
|
||||
owner: IdRef,
|
||||
created: Timestamp,
|
||||
members: List[IdRef]
|
||||
)
|
||||
|
||||
def apply[F[_]: Effect](store: Store[F]): Resource[F, OSpace[F]] =
|
||||
Resource.pure[F, OSpace[F]](new OSpace[F] {
|
||||
println(s"$store")
|
||||
def findAll(
|
||||
account: AccountId,
|
||||
nameQuery: Option[String]
|
||||
): F[Vector[OSpace.SpaceItem]] = ???
|
||||
|
||||
def findById(id: Ident, collective: Ident): F[Option[OSpace.SpaceDetail]] = ???
|
||||
def add(space: RSpace): F[AddResult] = ???
|
||||
def changeName(space: Ident, account: AccountId, name: String): F[AddResult] = ???
|
||||
def delete(id: Ident, collective: Ident): F[Int] = ???
|
||||
def addMember(
|
||||
space: Ident,
|
||||
account: AccountId,
|
||||
member: Ident
|
||||
): F[MemberChangeResult] =
|
||||
???
|
||||
def removeMember(
|
||||
space: Ident,
|
||||
account: AccountId,
|
||||
member: Ident
|
||||
): F[MemberChangeResult] =
|
||||
???
|
||||
|
||||
})
|
||||
}
|
@ -81,7 +81,8 @@ object RestServer {
|
||||
"usertask/notifydueitems" -> NotifyDueItemsRoutes(cfg, restApp.backend, token),
|
||||
"usertask/scanmailbox" -> ScanMailboxRoutes(restApp.backend, token),
|
||||
"calevent/check" -> CalEventCheckRoutes(),
|
||||
"fts" -> FullTextIndexRoutes.secured(cfg, restApp.backend, token)
|
||||
"fts" -> FullTextIndexRoutes.secured(cfg, restApp.backend, token),
|
||||
"space" -> SpaceRoutes(restApp.backend, token)
|
||||
)
|
||||
|
||||
def openRoutes[F[_]: Effect](cfg: Config, restApp: RestApp[F]): HttpRoutes[F] =
|
||||
|
@ -0,0 +1,108 @@
|
||||
package docspell.restserver.routes
|
||||
|
||||
import cats.data.OptionT
|
||||
import cats.effect._
|
||||
import cats.implicits._
|
||||
|
||||
import docspell.backend.BackendApp
|
||||
import docspell.backend.auth.AuthToken
|
||||
import docspell.backend.ops.OSpace
|
||||
import docspell.common._
|
||||
import docspell.store.records.RSpace
|
||||
import docspell.restapi.model._
|
||||
import docspell.restserver.conv.Conversions
|
||||
import docspell.restserver.http4s._
|
||||
|
||||
import org.http4s.HttpRoutes
|
||||
import org.http4s.circe.CirceEntityDecoder._
|
||||
import org.http4s.circe.CirceEntityEncoder._
|
||||
import org.http4s.dsl.Http4sDsl
|
||||
|
||||
object SpaceRoutes {
|
||||
|
||||
def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = {
|
||||
val dsl = new Http4sDsl[F] with ResponseGenerator[F] {}
|
||||
import dsl._
|
||||
|
||||
HttpRoutes.of {
|
||||
case GET -> Root :? QueryParam.QueryOpt(q) =>
|
||||
for {
|
||||
all <- backend.space.findAll(user.account, q.map(_.q))
|
||||
resp <- Ok(SpaceList(all.map(mkSpace).toList))
|
||||
} yield resp
|
||||
|
||||
case req @ POST -> Root =>
|
||||
for {
|
||||
data <- req.as[NewSpace]
|
||||
tag <- newSpace(data, user.account)
|
||||
res <- backend.space.add(tag)
|
||||
resp <- Ok(Conversions.basicResult(res, "Space successfully created."))
|
||||
} yield resp
|
||||
|
||||
case GET -> Root / Ident(id) =>
|
||||
(for {
|
||||
space <- OptionT(backend.space.findById(id, user.account.collective))
|
||||
resp <- OptionT.liftF(Ok(mkSpaceDetail(space)))
|
||||
} yield resp).getOrElseF(NotFound())
|
||||
|
||||
case req @ PUT -> Root / Ident(id) =>
|
||||
for {
|
||||
data <- req.as[NewSpace]
|
||||
res <- backend.space.changeName(id, user.account, data.name)
|
||||
resp <- Ok(Conversions.basicResult(res, "Space successfully updated."))
|
||||
} yield resp
|
||||
|
||||
case DELETE -> Root / Ident(id) =>
|
||||
for {
|
||||
del <- backend.space.delete(id, user.account.collective)
|
||||
resp <- Ok(
|
||||
if (del > 0) BasicResult(true, "Successfully deleted space")
|
||||
else BasicResult(false, "Could not delete space")
|
||||
)
|
||||
} yield resp
|
||||
|
||||
case PUT -> Root / Ident(id) / "member" / Ident(userId) =>
|
||||
for {
|
||||
res <- backend.space.addMember(id, user.account, userId)
|
||||
resp <- Ok(mkMemberResult(res))
|
||||
} yield resp
|
||||
|
||||
case DELETE -> Root / Ident(id) / "member" / Ident(userId) =>
|
||||
for {
|
||||
res <- backend.space.removeMember(id, user.account, userId)
|
||||
resp <- Ok(mkMemberResult(res))
|
||||
} yield resp
|
||||
}
|
||||
}
|
||||
|
||||
private def newSpace[F[_]: Sync](ns: NewSpace, account: AccountId): F[RSpace] =
|
||||
RSpace.newSpace(ns.name, account)
|
||||
|
||||
private def mkSpace(item: OSpace.SpaceItem): SpaceItem =
|
||||
SpaceItem(
|
||||
item.id,
|
||||
item.name,
|
||||
Conversions.mkIdName(item.owner),
|
||||
item.created,
|
||||
item.members
|
||||
)
|
||||
|
||||
private def mkSpaceDetail(item: OSpace.SpaceDetail): SpaceDetail =
|
||||
SpaceDetail(
|
||||
item.id,
|
||||
item.name,
|
||||
Conversions.mkIdName(item.owner),
|
||||
item.created,
|
||||
item.members.map(Conversions.mkIdName)
|
||||
)
|
||||
|
||||
private def mkMemberResult(r: OSpace.MemberChangeResult): BasicResult =
|
||||
r match {
|
||||
case OSpace.MemberChangeResult.Success =>
|
||||
BasicResult(true, "Successfully changed space")
|
||||
case OSpace.MemberChangeResult.NotFound =>
|
||||
BasicResult(false, "Space or user not found")
|
||||
case OSpace.MemberChangeResult.Forbidden =>
|
||||
BasicResult(false, "Not allowed to edit space")
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user