Add endpoints for managing spaces to openapi spec

This commit is contained in:
Eike Kettner 2020-07-02 23:11:42 +02:00
parent 13ad5e3219
commit 7ec0fc2593
5 changed files with 262 additions and 54 deletions
modules
restapi/src/main/resources
store/src/main
resources/db/migration/postgresql
scala/docspell/store/records

@ -795,6 +795,139 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/space:
get:
tags: [ Space ]
summary: Get a list of spaces.
description: |
Return a list of spaces for the current collective.
All spaces are returned, including those not owned by the
current user.
It is possible to restrict the results by a substring match of
the name.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/q"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/SpaceList"
post:
tags: [ Space ]
summary: Create a new space
description: |
Create a new space owned by the current user. If a space with
the same name already exists, an error is thrown.
security:
- authTokenHeader: []
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/NewSpace"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/space/{id}:
get:
tags: [ Space ]
summary: Get space details.
description: |
Return details about a space.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/SpaceDetail"
put:
tags: [ Space ]
summary: Change the name of a space
description: |
Changes the name of a space. The new name must not exists.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/NewSpace"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
delete:
tags: [ Space ]
summary: Delete a space by its id.
description: |
Deletes a space.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/space/{id}/member/{userId}:
put:
tags: [ Space ]
summary: Add a member to this space
description: |
Adds a member to this space (identified by `id`).
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
- $ref: "#/components/parameters/userId"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
delete:
tags: [ Space ]
summary: Removes a member from this space.
description: |
Removes a member from this space.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
- $ref: "#/components/parameters/userId"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/collective:
get:
tags: [ Collective ]
@ -2358,6 +2491,80 @@ paths:
components:
schemas:
SpaceList:
description: |
A list of spaces with their member counts.
required:
- items
properties:
items:
type: array
items:
$ref: "#/components/schemas/SpaceItem"
SpaceItem:
description: |
An item in a space list.
required:
- id
- name
- owner
- created
- members
properties:
id:
type: string
format: ident
name:
type: string
owner:
$ref: "#/components/schemas/IdName"
created:
type: integer
format: date-time
members:
type: integer
format: int32
NewSpace:
description: |
Data required to create a new space.
required:
- name
properties:
name:
type: string
SpaceDetail:
description: |
Details about a space.
required:
- id
- name
- owner
- created
- members
properties:
id:
type: string
format: ident
name:
type: string
owner:
$ref: "#/components/schemas/IdName"
created:
type: integer
format: date-time
members:
type: array
items:
$ref: "#/components/schemas/IdName"
SpaceMember:
description: |
Information to add or remove a space member.
required:
- userId
properties:
userId:
type: string
format: ident
ItemFtsSearch:
description: |
Query description for a full-text only search.
@ -3739,6 +3946,13 @@ components:
required: true
schema:
type: string
userId:
name: userId
in: path
description: An identifier
required: true
schema:
type: string
itemId:
name: itemId
in: path

@ -19,12 +19,5 @@ CREATE TABLE "space_member" (
foreign key ("user_id") references "user_"("uid")
);
CREATE TABLE "space_item" (
"id" varchar(254) not null primary key,
"space_id" varchar(254) not null,
"item_id" varchar(254) not null,
"created" timestamp not null,
unique ("space_id", "item_id"),
foreign key ("space_id") references "space"("id"),
foreign key ("item_id") references "item"("itemid")
);
ALTER TABLE "item"
ADD COLUMN "space_id" varchar(254) NULL;

@ -27,7 +27,8 @@ case class RItem(
dueDate: Option[Timestamp],
created: Timestamp,
updated: Timestamp,
notes: Option[String]
notes: Option[String],
spaceId: Option[Ident]
) {}
object RItem {
@ -58,6 +59,7 @@ object RItem {
None,
now,
now,
None,
None
)
@ -80,6 +82,7 @@ object RItem {
val created = Column("created")
val updated = Column("updated")
val notes = Column("notes")
val space = Column("space_id")
val all = List(
id,
cid,
@ -96,7 +99,8 @@ object RItem {
dueDate,
created,
updated,
notes
notes,
space
)
}
import Columns._
@ -107,7 +111,7 @@ object RItem {
all,
fr"${v.id},${v.cid},${v.name},${v.itemDate},${v.source},${v.direction},${v.state}," ++
fr"${v.corrOrg},${v.corrPerson},${v.concPerson},${v.concEquipment},${v.inReplyTo},${v.dueDate}," ++
fr"${v.created},${v.updated},${v.notes}"
fr"${v.created},${v.updated},${v.notes},${v.spaceId}"
).update.run
def getCollective(itemId: Ident): ConnectionIO[Option[Ident]] =

@ -1,5 +1,7 @@
package docspell.store.records
import cats.effect._
import cats.implicits._
import docspell.common._
import docspell.store.impl.Column
import docspell.store.impl.Implicits._
@ -17,6 +19,12 @@ case class RSpace(
object RSpace {
def newSpace[F[_]: Sync](name: String, account: AccountId): F[RSpace] =
for {
nId <- Ident.randomId[F]
now <- Timestamp.current[F]
} yield RSpace(nId, name, account.collective, account.user, now)
val table = fr"space"
object Columns {
@ -41,4 +49,35 @@ object RSpace {
sql.update.run
}
def update(v: RSpace): ConnectionIO[Int] =
updateRow(
table,
and(id.is(v.id), collective.is(v.collectiveId), owner.is(v.owner)),
name.setTo(v.name)
).update.run
def existsByName(coll: Ident, spaceName: String): ConnectionIO[Boolean] =
selectCount(id, table, and(collective.is(coll), name.is(spaceName)))
.query[Int]
.unique
.map(_ > 0)
def findById(spaceId: Ident): ConnectionIO[Option[RSpace]] = {
val sql = selectSimple(all, table, id.is(spaceId))
sql.query[RSpace].option
}
def findAll(
coll: Ident,
nameQ: Option[String],
order: Columns.type => Column
): ConnectionIO[Vector[RSpace]] = {
val q = Seq(collective.is(coll)) ++ (nameQ match {
case Some(str) => Seq(name.lowerLike(s"%${str.toLowerCase}%"))
case None => Seq.empty
})
val sql = selectSimple(all, table, and(q)) ++ orderBy(order(Columns).f)
sql.query[RSpace].to[Vector]
}
}

@ -1,42 +0,0 @@
package docspell.store.records
import docspell.common._
import docspell.store.impl.Column
import docspell.store.impl.Implicits._
import doobie._
import doobie.implicits._
case class RSpaceItem(
id: Ident,
spaceId: Ident,
itemId: Ident,
created: Timestamp
)
object RSpaceItem {
val table = fr"space"
object Columns {
val id = Column("id")
val space = Column("space_id")
val item = Column("user_id")
val created = Column("created")
val all = List(id, space, user, created)
}
import Columns._
def insert(value: RSpaceItem): ConnectionIO[Int] = {
val sql = insertRow(
table,
all,
fr"${value.id},${value.spaceId},${value.itemId},${value.created}"
)
sql.update.run
}
}