mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 10:28:27 +00:00
Prevent duplicate bookmark names
This commit is contained in:
@ -6,7 +6,8 @@ CREATE TABLE "query_bookmark" (
|
||||
"cid" varchar(254) not null,
|
||||
"query" varchar(2000) not null,
|
||||
"created" timestamp,
|
||||
"__user_id" varchar(254) not null,
|
||||
foreign key ("user_id") references "user_"("uid") on delete cascade,
|
||||
foreign key ("cid") references "collective"("cid") on delete cascade,
|
||||
unique("cid", "user_id", "name")
|
||||
unique("cid", "__user_id", "name")
|
||||
)
|
||||
|
@ -6,7 +6,8 @@ CREATE TABLE `query_bookmark` (
|
||||
`cid` varchar(254) not null,
|
||||
`query` varchar(2000) not null,
|
||||
`created` timestamp,
|
||||
`__user_id` varchar(254) not null,
|
||||
foreign key (`user_id`) references `user_`(`uid`) on delete cascade,
|
||||
foreign key (`cid`) references `collective`(`cid`) on delete cascade,
|
||||
unique(`cid`, `user_id`, `name`)
|
||||
unique(`cid`, `__user_id`, `name`)
|
||||
)
|
||||
|
@ -6,7 +6,8 @@ CREATE TABLE "query_bookmark" (
|
||||
"cid" varchar(254) not null,
|
||||
"query" varchar(2000) not null,
|
||||
"created" timestamp,
|
||||
"__user_id" varchar(254) not null,
|
||||
foreign key ("user_id") references "user_"("uid") on delete cascade,
|
||||
foreign key ("cid") references "collective"("cid") on delete cascade,
|
||||
unique("cid", "user_id", "name")
|
||||
unique("cid", "__user_id", "name")
|
||||
)
|
||||
|
@ -7,7 +7,7 @@
|
||||
package docspell.store.records
|
||||
|
||||
import cats.data.NonEmptyList
|
||||
import cats.syntax.option._
|
||||
import cats.syntax.all._
|
||||
|
||||
import docspell.common._
|
||||
import docspell.query.ItemQuery
|
||||
@ -16,6 +16,7 @@ import docspell.store.qb._
|
||||
|
||||
import doobie._
|
||||
import doobie.implicits._
|
||||
import docspell.store.AddResult
|
||||
|
||||
final case class RQueryBookmark(
|
||||
id: Ident,
|
||||
@ -48,6 +49,8 @@ object RQueryBookmark {
|
||||
val query = Column[ItemQuery]("query", this)
|
||||
val created = Column[Timestamp]("created", this)
|
||||
|
||||
val internUserId = Column[String]("__user_id", this)
|
||||
|
||||
val all: NonEmptyList[Column[_]] =
|
||||
NonEmptyList.of(id, name, label, userId, cid, query, created)
|
||||
}
|
||||
@ -76,12 +79,14 @@ object RQueryBookmark {
|
||||
curTime
|
||||
)
|
||||
|
||||
def insert(r: RQueryBookmark): ConnectionIO[Int] =
|
||||
def insert(r: RQueryBookmark): ConnectionIO[Int] = {
|
||||
val userIdDummy = r.userId.getOrElse(Ident.unsafe("-"))
|
||||
DML.insert(
|
||||
T,
|
||||
T.all,
|
||||
sql"${r.id},${r.name},${r.label},${r.userId},${r.cid},${r.query},${r.created}"
|
||||
T.all.append(T.internUserId),
|
||||
sql"${r.id},${r.name},${r.label},${r.userId},${r.cid},${r.query},${r.created},$userIdDummy"
|
||||
)
|
||||
}
|
||||
|
||||
def update(r: RQueryBookmark): ConnectionIO[Int] =
|
||||
DML.update(
|
||||
@ -97,6 +102,42 @@ object RQueryBookmark {
|
||||
def deleteById(cid: Ident, id: Ident): ConnectionIO[Int] =
|
||||
DML.delete(T, T.id === id && T.cid === cid)
|
||||
|
||||
def nameExists(account: AccountId, name: String): ConnectionIO[Boolean] = {
|
||||
val user = RUser.as("u")
|
||||
val bm = RQueryBookmark.as("bm")
|
||||
|
||||
val users = Select(
|
||||
user.uid.s,
|
||||
from(user),
|
||||
user.cid === account.collective && user.login === account.user
|
||||
)
|
||||
Select(
|
||||
select(count(bm.id)),
|
||||
from(bm),
|
||||
bm.name === name && bm.cid === account.collective && (bm.userId.isNull || bm.userId
|
||||
.in(users))
|
||||
).build.query[Int].unique.map(_ > 0)
|
||||
}
|
||||
|
||||
// impl note: store.add doesn't work, because it checks for duplicate
|
||||
// after trying to insert the check is necessary because a name
|
||||
// should be unique across personal *and* collective bookmarks
|
||||
def insertIfNotExists(
|
||||
account: AccountId,
|
||||
r: ConnectionIO[RQueryBookmark]
|
||||
): ConnectionIO[AddResult] =
|
||||
for {
|
||||
bm <- r
|
||||
res <-
|
||||
nameExists(account, bm.name).flatMap {
|
||||
case true =>
|
||||
AddResult
|
||||
.entityExists(s"A bookmark '${bm.name}' already exists.")
|
||||
.pure[ConnectionIO]
|
||||
case false => insert(bm).attempt.map(AddResult.fromUpdate)
|
||||
}
|
||||
} yield res
|
||||
|
||||
def allForUser(account: AccountId): ConnectionIO[Vector[RQueryBookmark]] = {
|
||||
val user = RUser.as("u")
|
||||
val bm = RQueryBookmark.as("bm")
|
||||
|
Reference in New Issue
Block a user