Adopt restserver to new collective-id

This commit is contained in:
eikek 2022-08-04 12:44:09 +02:00
parent 53d92c4a26
commit eabcffe71a
48 changed files with 539 additions and 293 deletions

View File

@ -28,7 +28,6 @@ trait OCollective[F[_]] {
def updateSettings(
collective: CollectiveId,
collectiveName: Ident,
settings: OCollective.Settings
): F[AddResult]
@ -147,7 +146,6 @@ object OCollective {
def updateSettings(
collectiveId: CollectiveId,
collectiveName: Ident,
sett: Settings
): F[AddResult] =
store

View File

@ -40,10 +40,10 @@ trait ODownloadAll[F[_]] {
def submit(accountId: AccountInfo, req: DownloadRequest): F[DownloadSummary]
/** Given the id from the summary, cancels a running job. */
def cancelDownload(accountId: AccountId, id: Ident): F[OJob.JobCancelResult]
def cancelDownload(cid: CollectiveId, id: Ident): F[OJob.JobCancelResult]
/** Returns the file if it is present, given a summary id. */
def getFile(collective: Ident, id: Ident): F[Option[DownloadAllFile[F]]]
def getFile(collective: CollectiveId, id: Ident): F[Option[DownloadAllFile[F]]]
/** Deletes a download archive given it's id. */
def deleteFile(id: Ident): F[Unit]
@ -122,7 +122,7 @@ object ODownloadAll {
else DownloadState.NotPresent
} yield state
def getFile(collective: Ident, id: Ident) =
def getFile(collective: CollectiveId, id: Ident) =
OptionT(store.transact(RDownloadQuery.findById(id)))
.map(_._2)
.map(md =>
@ -156,10 +156,10 @@ object ODownloadAll {
_ <- store.fileRepo.delete(fkey)
} yield ()
def cancelDownload(accountId: AccountId, id: Ident) =
def cancelDownload(cid: CollectiveId, id: Ident) =
OptionT(store.transact(RDownloadQuery.findById(id)))
.flatMap(t => OptionT(store.transact(RJob.findNonFinalByTracker(t._1.id))))
.semiflatMap(job => jobs.cancelJob(job.id, accountId.collective))
.semiflatMap(job => jobs.cancelJob(job.id, UserTaskScope.collective(cid)))
.getOrElse(JobCancelResult.jobNotFound)
}

View File

@ -30,10 +30,10 @@ trait OFolder[F[_]] {
userId: Ident
): F[Option[OFolder.FolderDetail]]
/** Adds a new folder. If `login` is non-empty, the `folder.user` property is ignored
* and the user-id is determined by the given login name.
/** Adds a new folder. If `login` is non-empty, the `folder.owner` property is ignored
* and its value is determined by the given login name.
*/
def add(folder: RFolder, userId: Option[Ident]): F[AddResult]
def add(folder: RFolder, login: Option[Ident]): F[AddResult]
def changeName(
folder: Ident,
@ -123,11 +123,11 @@ object OFolder {
): F[Option[FolderDetail]] =
store.transact(QFolder.findById(id, collectiveId, userId))
def add(folder: RFolder, userId: Option[Ident]): F[AddResult] = {
val insert = userId match {
case Some(uid) =>
def add(folder: RFolder, login: Option[Ident]): F[AddResult] = {
val insert = login match {
case Some(userLogin) =>
for {
user <- RUser.findById(uid, folder.collectiveId.some)
user <- RUser.findByLogin(userLogin, folder.collectiveId.some)
s = user.map(u => folder.copy(owner = u.uid)).getOrElse(folder)
n <- RFolder.insert(s)
} yield n

View File

@ -9,11 +9,11 @@ package docspell.backend.ops
import cats.data.OptionT
import cats.effect._
import cats.implicits._
import docspell.backend.ops.OJob.{CollectiveQueueState, JobCancelResult}
import docspell.common._
import docspell.pubsub.api.PubSubT
import docspell.scheduler.msg.JobDone
import docspell.scheduler.usertask.UserTaskScope
import docspell.store.Store
import docspell.store.UpdateResult
import docspell.store.queries.QJobQueue
@ -21,13 +21,13 @@ import docspell.store.records.{RJob, RJobLog}
trait OJob[F[_]] {
def queueState(collective: Ident, maxResults: Int): F[CollectiveQueueState]
def queueState(collective: UserTaskScope, maxResults: Int): F[CollectiveQueueState]
def cancelJob(id: Ident, collective: Ident): F[JobCancelResult]
def cancelJob(id: Ident, collective: UserTaskScope): F[JobCancelResult]
def setPriority(id: Ident, collective: Ident, prio: Priority): F[UpdateResult]
def setPriority(id: Ident, collective: UserTaskScope, prio: Priority): F[UpdateResult]
def getUnfinishedJobCount(collective: Ident): F[Int]
def getUnfinishedJobCount(collective: UserTaskScope): F[Int]
}
object OJob {
@ -61,20 +61,34 @@ object OJob {
Resource.pure[F, OJob[F]](new OJob[F] {
private[this] val logger = docspell.logging.getLogger[F]
def queueState(collective: Ident, maxResults: Int): F[CollectiveQueueState] =
private def scopeToGroup(s: UserTaskScope) =
s.collectiveId
.map(_.valueAsIdent)
.getOrElse(DocspellSystem.taskGroup)
def queueState(
collective: UserTaskScope,
maxResults: Int
): F[CollectiveQueueState] =
store
.transact(
QJobQueue.queueStateSnapshot(collective, maxResults.toLong)
QJobQueue.queueStateSnapshot(scopeToGroup(collective), maxResults.toLong)
)
.map(t => JobDetail(t._1, t._2))
.compile
.toVector
.map(CollectiveQueueState)
def setPriority(id: Ident, collective: Ident, prio: Priority): F[UpdateResult] =
UpdateResult.fromUpdate(store.transact(RJob.setPriority(id, collective, prio)))
def setPriority(
id: Ident,
collective: UserTaskScope,
prio: Priority
): F[UpdateResult] =
UpdateResult.fromUpdate(
store.transact(RJob.setPriority(id, scopeToGroup(collective), prio))
)
def cancelJob(id: Ident, collective: Ident): F[JobCancelResult] = {
def cancelJob(id: Ident, collective: UserTaskScope): F[JobCancelResult] = {
def remove(job: RJob): F[JobCancelResult] =
for {
n <- store.transact(RJob.delete(job.id))
@ -99,7 +113,9 @@ object OJob {
}
(for {
job <- OptionT(store.transact(RJob.findByIdAndGroup(id, collective)))
job <- OptionT(
store.transact(RJob.findByIdAndGroup(id, scopeToGroup(collective)))
)
result <- OptionT.liftF(
if (job.isInProgress) tryCancel(job)
else remove(job)
@ -108,7 +124,7 @@ object OJob {
.getOrElse(JobCancelResult.jobNotFound)
}
def getUnfinishedJobCount(collective: Ident): F[Int] =
store.transact(RJob.getUnfinishedCount(collective))
def getUnfinishedJobCount(collective: UserTaskScope): F[Int] =
store.transact(RJob.getUnfinishedCount(scopeToGroup(collective)))
})
}

View File

@ -20,7 +20,7 @@ import io.circe.generic.semiauto._
*/
case class ScanMailboxArgs(
// the docspell user account
account: AccountId,
account: AccountInfo,
// the configured imap connection
imapConnection: Ident,
// scan folders recursively

View File

@ -21,7 +21,7 @@ import io.circe.{Decoder, Encoder}
* the json data of the corresponding task.
*/
final case class PeriodicDueItemsArgs(
account: AccountId,
account: AccountInfo,
channels: NonEmptyList[ChannelRef],
remindDays: Int,
daysBack: Option[Int],

View File

@ -14,7 +14,7 @@ import io.circe.generic.semiauto
import io.circe.{Decoder, Encoder}
final case class PeriodicQueryArgs(
account: AccountId,
account: AccountInfo,
channels: NonEmptyList[ChannelRef],
query: Option[ItemQueryString],
bookmark: Option[String],

View File

@ -7,14 +7,12 @@
package docspell.restserver.auth
import docspell.backend.auth._
import docspell.common.AccountId
import docspell.common.LenientUri
import docspell.common.{AccountInfo, LenientUri}
import org.http4s._
import org.typelevel.ci.CIString
case class CookieData(auth: AuthToken) {
def accountId: AccountId = auth.account
def accountInfo: AccountInfo = auth.account
def asString: String = auth.asString
def asCookie(baseUrl: LenientUri): ResponseCookie = {

View File

@ -371,7 +371,10 @@ trait Conversions {
)
}
def newOrg[F[_]: Sync](v: Organization, cid: Ident): F[OOrganization.OrgAndContacts] = {
def newOrg[F[_]: Sync](
v: Organization,
cid: CollectiveId
): F[OOrganization.OrgAndContacts] = {
def contacts(oid: Ident) =
v.contacts.traverse(c => newContact(c, oid.some, None))
for {
@ -397,7 +400,7 @@ trait Conversions {
def changeOrg[F[_]: Sync](
v: Organization,
cid: Ident
cid: CollectiveId
): F[OOrganization.OrgAndContacts] = {
def contacts(oid: Ident) =
v.contacts.traverse(c => newContact(c, oid.some, None))
@ -435,7 +438,10 @@ trait Conversions {
)
}
def newPerson[F[_]: Sync](v: Person, cid: Ident): F[OOrganization.PersonAndContacts] = {
def newPerson[F[_]: Sync](
v: Person,
cid: CollectiveId
): F[OOrganization.PersonAndContacts] = {
def contacts(pid: Ident) =
v.contacts.traverse(c => newContact(c, None, pid.some))
for {
@ -461,7 +467,7 @@ trait Conversions {
def changePerson[F[_]: Sync](
v: Person,
cid: Ident
cid: CollectiveId
): F[OOrganization.PersonAndContacts] = {
def contacts(pid: Ident) =
v.contacts.traverse(c => newContact(c, None, pid.some))
@ -512,7 +518,7 @@ trait Conversions {
ru.created
)
def newUser[F[_]: Sync](u: User, cid: Ident): F[RUser] =
def newUser[F[_]: Sync](u: User, cid: CollectiveId): F[RUser] =
Conversions.timeId.map { case (id, now) =>
RUser(
id,
@ -528,7 +534,7 @@ trait Conversions {
)
}
def changeUser(u: User, cid: Ident): RUser =
def changeUser(u: User, cid: CollectiveId): RUser =
RUser(
u.id,
u.login,
@ -547,12 +553,12 @@ trait Conversions {
def mkTag(rt: RTag): Tag =
Tag(rt.tagId, rt.name, rt.category, rt.created)
def newTag[F[_]: Sync](t: Tag, cid: Ident): F[RTag] =
def newTag[F[_]: Sync](t: Tag, cid: CollectiveId): F[RTag] =
Conversions.timeId.map { case (id, now) =>
RTag(id, cid, t.name.trim, t.category.map(_.trim), now)
}
def changeTag(t: Tag, cid: Ident): RTag =
def changeTag(t: Tag, cid: CollectiveId): RTag =
RTag(t.id, cid, t.name.trim, t.category.map(_.trim), t.created)
// sources
@ -575,7 +581,7 @@ trait Conversions {
TagList(s.tags.length, s.tags.map(mkTag).toList)
)
def newSource[F[_]: Sync](s: Source, cid: Ident): F[RSource] =
def newSource[F[_]: Sync](s: Source, cid: CollectiveId): F[RSource] =
Conversions.timeId.map { case (id, now) =>
RSource(
id,
@ -593,10 +599,10 @@ trait Conversions {
)
}
def changeSource[F[_]](s: Source, coll: Ident): RSource =
def changeSource(s: Source, cid: CollectiveId): RSource =
RSource(
s.id,
coll,
cid,
s.abbrev.trim,
s.description,
s.counter,
@ -613,12 +619,12 @@ trait Conversions {
def mkEquipment(re: REquipment): Equipment =
Equipment(re.eid, re.name, re.created, re.notes, re.use)
def newEquipment[F[_]: Sync](e: Equipment, cid: Ident): F[REquipment] =
def newEquipment[F[_]: Sync](e: Equipment, cid: CollectiveId): F[REquipment] =
Conversions.timeId.map { case (id, now) =>
REquipment(id, cid, e.name.trim, now, now, e.notes, e.use)
}
def changeEquipment[F[_]: Sync](e: Equipment, cid: Ident): F[REquipment] =
def changeEquipment[F[_]: Sync](e: Equipment, cid: CollectiveId): F[REquipment] =
Timestamp
.current[F]
.map(now => REquipment(e.id, cid, e.name.trim, e.created, now, e.notes, e.use))
@ -681,6 +687,8 @@ trait Conversions {
case UploadResult.NoFiles => BasicResult(false, "There were no files to submit.")
case UploadResult.NoSource => BasicResult(false, "The source id is not valid.")
case UploadResult.NoItem => BasicResult(false, "The item could not be found.")
case UploadResult.NoCollective =>
BasicResult(false, "The collective could not be found.")
}
def basicResult(cr: PassChangeResult): BasicResult =

View File

@ -39,7 +39,7 @@ object AddonArchiveRoutes extends AddonValidationSupport {
HttpRoutes.of {
case GET -> Root =>
for {
all <- backend.addons.getAllAddons(token.account.collective)
all <- backend.addons.getAllAddons(token.account.collectiveId)
resp <- Ok(
AddonList(
all.map(r =>
@ -62,7 +62,7 @@ object AddonArchiveRoutes extends AddonValidationSupport {
for {
input <- req.as[AddonRegister]
install = backend.addons.registerAddon(
token.account.collective,
token.account.collectiveId,
input.url,
None
)
@ -82,7 +82,7 @@ object AddonArchiveRoutes extends AddonValidationSupport {
s"Addon updated: ${m.nameAndVersion}"
)
)
val update = backend.addons.refreshAddon(token.account.collective, id)
val update = backend.addons.refreshAddon(token.account.collectiveId, id)
for {
resp <-
if (sync)
@ -97,7 +97,7 @@ object AddonArchiveRoutes extends AddonValidationSupport {
case DELETE -> Root / Ident(id) =>
for {
flag <- backend.addons.deleteAddon(token.account.collective, id)
flag <- backend.addons.deleteAddon(token.account.collectiveId, id)
resp <-
if (flag) Ok(BasicResult(true, "Addon deleted"))
else NotFound(BasicResult(false, "Addon not found"))

View File

@ -29,7 +29,7 @@ object AddonRunConfigRoutes {
HttpRoutes.of {
case GET -> Root =>
for {
all <- backend.addons.getAllAddonRunConfigs(token.account.collective)
all <- backend.addons.getAllAddonRunConfigs(token.account.collectiveId)
resp <- Ok(AddonRunConfigList(all.map(convertInfoTask)))
} yield resp
@ -39,7 +39,7 @@ object AddonRunConfigRoutes {
data = convertInsertTask(Ident.unsafe(""), input)
res <- data.flatTraverse(in =>
backend.addons
.upsertAddonRunConfig(token.account.collective, in)
.upsertAddonRunConfig(token.account.collectiveId, in)
.map(_.leftMap(_.message))
)
resp <- res.fold(
@ -54,7 +54,7 @@ object AddonRunConfigRoutes {
data = convertInsertTask(id, input)
res <- data.flatTraverse(in =>
backend.addons
.upsertAddonRunConfig(token.account.collective, in)
.upsertAddonRunConfig(token.account.collectiveId, in)
.map(_.leftMap(_.message))
)
resp <- res.fold(
@ -65,7 +65,7 @@ object AddonRunConfigRoutes {
case DELETE -> Root / Ident(id) =>
for {
flag <- backend.addons.deleteAddonRunConfig(token.account.collective, id)
flag <- backend.addons.deleteAddonRunConfig(token.account.collectiveId, id)
resp <-
if (flag) Ok(BasicResult(true, "Addon task deleted"))
else NotFound(BasicResult(false, "Addon task not found"))

View File

@ -9,12 +9,11 @@ package docspell.restserver.routes
import cats.data.NonEmptyList
import cats.effect._
import cats.syntax.all._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.restapi.model._
import docspell.restserver.http4s.ThrowableResponseMapper
import docspell.scheduler.usertask.UserTaskScope
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityCodec._
import org.http4s.dsl.Http4sDsl
@ -29,9 +28,10 @@ object AddonRunRoutes {
for {
input <- req.as[AddonRunExistingItem]
_ <- backend.addons.runAddonForItem(
token.account,
token.account.collectiveId,
NonEmptyList(input.itemId, input.additionalItems),
input.addonRunConfigIds.toSet
input.addonRunConfigIds.toSet,
UserTaskScope(token.account)
)
resp <- Ok(BasicResult(true, "Job for running addons submitted."))
} yield resp

View File

@ -33,7 +33,7 @@ object AttachmentMultiRoutes extends NonEmptyListSupport {
for {
json <- req.as[IdList]
attachments <- requireNonEmpty(json.ids)
n <- backend.item.deleteAttachmentMultiple(attachments, user.account.collective)
n <- backend.item.deleteAttachmentMultiple(attachments, user.account.collectiveId)
res = BasicResult(
n > 0,
if (n > 0) "Attachment(s) deleted" else "Attachment deletion failed."

View File

@ -8,7 +8,6 @@ package docspell.restserver.routes
import cats.effect._
import cats.implicits._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.backend.ops._
@ -18,7 +17,7 @@ import docspell.restapi.model._
import docspell.restserver.conv.Conversions
import docspell.restserver.http4s.BinaryUtil
import docspell.restserver.webapp.Webjars
import docspell.scheduler.usertask.UserTaskScope
import org.http4s._
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
@ -45,19 +44,22 @@ object AttachmentRoutes {
HttpRoutes.of {
case HEAD -> Root / Ident(id) =>
for {
fileData <- backend.itemSearch.findAttachment(id, user.account.collective)
fileData <- backend.itemSearch.findAttachment(id, user.account.collectiveId)
resp <- BinaryUtil.respondHead(dsl)(fileData)
} yield resp
case req @ GET -> Root / Ident(id) =>
for {
fileData <- backend.itemSearch.findAttachment(id, user.account.collective)
fileData <- backend.itemSearch.findAttachment(id, user.account.collectiveId)
resp <- BinaryUtil.respond[F](dsl, req)(fileData)
} yield resp
case HEAD -> Root / Ident(id) / "original" =>
for {
fileData <- backend.itemSearch.findAttachmentSource(id, user.account.collective)
fileData <- backend.itemSearch.findAttachmentSource(
id,
user.account.collectiveId
)
resp <-
fileData
.map(data => withResponseHeaders(Ok())(data))
@ -66,7 +68,10 @@ object AttachmentRoutes {
case req @ GET -> Root / Ident(id) / "original" =>
for {
fileData <- backend.itemSearch.findAttachmentSource(id, user.account.collective)
fileData <- backend.itemSearch.findAttachmentSource(
id,
user.account.collectiveId
)
inm = req.headers.get[`If-None-Match`].flatMap(_.tags)
matches = BinaryUtil.matchETag(fileData.map(_.meta), inm)
resp <-
@ -81,7 +86,7 @@ object AttachmentRoutes {
case HEAD -> Root / Ident(id) / "archive" =>
for {
fileData <-
backend.itemSearch.findAttachmentArchive(id, user.account.collective)
backend.itemSearch.findAttachmentArchive(id, user.account.collectiveId)
resp <-
fileData
.map(data => withResponseHeaders(Ok())(data))
@ -91,7 +96,7 @@ object AttachmentRoutes {
case req @ GET -> Root / Ident(id) / "archive" =>
for {
fileData <-
backend.itemSearch.findAttachmentArchive(id, user.account.collective)
backend.itemSearch.findAttachmentArchive(id, user.account.collectiveId)
inm = req.headers.get[`If-None-Match`].flatMap(_.tags)
matches = BinaryUtil.matchETag(fileData.map(_.meta), inm)
resp <-
@ -106,14 +111,14 @@ object AttachmentRoutes {
case req @ GET -> Root / Ident(id) / "preview" =>
for {
fileData <-
backend.itemSearch.findAttachmentPreview(id, user.account.collective)
backend.itemSearch.findAttachmentPreview(id, user.account.collectiveId)
resp <- BinaryUtil.respondPreview(dsl, req)(fileData)
} yield resp
case HEAD -> Root / Ident(id) / "preview" =>
for {
fileData <-
backend.itemSearch.findAttachmentPreview(id, user.account.collective)
backend.itemSearch.findAttachmentPreview(id, user.account.collectiveId)
resp <- BinaryUtil.respondPreviewHead(dsl)(fileData)
} yield resp
@ -121,7 +126,7 @@ object AttachmentRoutes {
for {
res <- backend.item.generatePreview(
MakePreviewArgs.replace(id),
user.account
UserTaskScope(user.account)
)
resp <- Ok(
Conversions.basicResult(res, "Generating preview image task submitted.")
@ -138,7 +143,7 @@ object AttachmentRoutes {
case GET -> Root / Ident(id) / "meta" =>
for {
rm <- backend.itemSearch.findAttachmentMeta(id, user.account.collective)
rm <- backend.itemSearch.findAttachmentMeta(id, user.account.collectiveId)
md = rm.map(Conversions.mkAttachmentMeta)
resp <- md.map(Ok(_)).getOrElse(NotFound(BasicResult(false, "Not found.")))
} yield resp
@ -146,13 +151,13 @@ object AttachmentRoutes {
case req @ POST -> Root / Ident(id) / "name" =>
for {
nn <- req.as[OptionalText]
res <- backend.item.setAttachmentName(id, nn.text, user.account.collective)
res <- backend.item.setAttachmentName(id, nn.text, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Name updated."))
} yield resp
case DELETE -> Root / Ident(id) =>
for {
n <- backend.item.deleteAttachment(id, user.account.collective)
n <- backend.item.deleteAttachment(id, user.account.collectiveId)
res =
if (n == 0) BasicResult(false, "Attachment not found")
else BasicResult(true, "Attachment deleted.")
@ -177,10 +182,9 @@ object AttachmentRoutes {
case POST -> Root / "convertallpdfs" =>
for {
res <-
backend.item.convertAllPdf(None, None)
backend.item.convertAllPdf(None, UserTaskScope.system)
resp <- Ok(Conversions.basicResult(res, "Convert all PDFs task submitted"))
} yield resp
}
}
}

View File

@ -29,7 +29,7 @@ object CheckFileRoutes {
HttpRoutes.of { case GET -> Root / checksum =>
for {
items <-
backend.itemSearch.findByFileCollective(checksum, user.account.collective)
backend.itemSearch.findByFileCollective(checksum, user.account.collectiveId)
resp <- Ok(convert(items))
} yield resp

View File

@ -36,7 +36,7 @@ object ClientSettingsRoutes {
_ <- OptionT.liftF(logger.debug(s"Get client settings for share ${token.id}"))
share <- backend.share.findActiveById(token.id)
sett <- OptionT(
backend.clientSettings.loadCollective(clientId, share.user.accountId)
backend.clientSettings.loadCollective(clientId, share.account.collectiveId)
)
res <- OptionT.liftF(Ok(sett.settingsData))
} yield res)
@ -51,7 +51,11 @@ object ClientSettingsRoutes {
HttpRoutes.of {
case GET -> Root / Ident(clientId) =>
for {
mergedData <- backend.clientSettings.loadMerged(clientId, user.account)
mergedData <- backend.clientSettings.loadMerged(
clientId,
user.account.collectiveId,
user.account.userId
)
res <- mergedData match {
case Some(j) => Ok(j)
case None => Ok(Map.empty[String, String])
@ -61,13 +65,13 @@ object ClientSettingsRoutes {
case req @ PUT -> Root / "user" / Ident(clientId) =>
for {
data <- req.as[Json]
_ <- backend.clientSettings.saveUser(clientId, user.account, data)
_ <- backend.clientSettings.saveUser(clientId, user.account.userId, data)
res <- Ok(BasicResult(true, "Settings stored"))
} yield res
case GET -> Root / "user" / Ident(clientId) =>
for {
data <- backend.clientSettings.loadUser(clientId, user.account)
data <- backend.clientSettings.loadUser(clientId, user.account.userId)
res <- data match {
case Some(d) => Ok(d.settingsData)
case None => Ok(Map.empty[String, String])
@ -76,7 +80,7 @@ object ClientSettingsRoutes {
case DELETE -> Root / "user" / Ident(clientId) =>
for {
flag <- backend.clientSettings.deleteUser(clientId, user.account)
flag <- backend.clientSettings.deleteUser(clientId, user.account.userId)
res <- Ok(
BasicResult(
flag,
@ -88,13 +92,20 @@ object ClientSettingsRoutes {
case req @ PUT -> Root / "collective" / Ident(clientId) =>
for {
data <- req.as[Json]
_ <- backend.clientSettings.saveCollective(clientId, user.account, data)
_ <- backend.clientSettings.saveCollective(
clientId,
user.account.collectiveId,
data
)
res <- Ok(BasicResult(true, "Settings stored"))
} yield res
case GET -> Root / "collective" / Ident(clientId) =>
for {
data <- backend.clientSettings.loadCollective(clientId, user.account)
data <- backend.clientSettings.loadCollective(
clientId,
user.account.collectiveId
)
res <- data match {
case Some(d) => Ok(d.settingsData)
case None => Ok(Map.empty[String, String])
@ -103,7 +114,10 @@ object ClientSettingsRoutes {
case DELETE -> Root / "collective" / Ident(clientId) =>
for {
flag <- backend.clientSettings.deleteCollective(clientId, user.account)
flag <- backend.clientSettings.deleteCollective(
clientId,
user.account.collectiveId
)
res <- Ok(
BasicResult(
flag,

View File

@ -33,19 +33,19 @@ object CollectiveRoutes {
case GET -> Root =>
for {
collDb <- backend.collective.find(user.account.collective)
coll = collDb.map(c => Collective(c.id, c.state, c.created))
coll = collDb.map(c => Collective(c.name, c.state, c.created))
resp <- coll.toResponse()
} yield resp
case GET -> Root / "insights" =>
for {
ins <- backend.collective.insights(user.account.collective)
ins <- backend.collective.insights(user.account.collectiveId)
resp <- Ok(Conversions.mkItemInsights(ins))
} yield resp
case GET -> Root / "tagcloud" =>
for {
cloud <- backend.collective.tagCloud(user.account.collective)
cloud <- backend.collective.tagCloud(user.account.collectiveId)
resp <- Ok(Conversions.mkTagCloud(cloud))
} yield resp
@ -73,13 +73,13 @@ object CollectiveRoutes {
)
res <-
backend.collective
.updateSettings(user.account.collective, sett)
.updateSettings(user.account.collectiveId, sett)
resp <- Ok(Conversions.basicResult(res, "Settings updated."))
} yield resp
case GET -> Root / "settings" =>
for {
settDb <- backend.collective.findSettings(user.account.collective)
settDb <- backend.collective.findSettings(user.account.collectiveId)
trash = settDb.flatMap(_.emptyTrash).getOrElse(OCollective.EmptyTrash.default)
sett = settDb.map(c =>
CollectiveSettings(
@ -108,8 +108,8 @@ object CollectiveRoutes {
for {
res <-
backend.collective
.getContacts(user.account.collective, q.map(_.q), kind)
.take(50)
.getContacts(user.account.collectiveId, q.map(_.q), kind)
.take(100)
.compile
.toList
resp <- Ok(ContactList(res.map(Conversions.mkContact)))
@ -117,7 +117,7 @@ object CollectiveRoutes {
case POST -> Root / "classifier" / "startonce" =>
for {
_ <- backend.collective.startLearnClassifier(user.account.collective)
_ <- backend.collective.startLearnClassifier(user.account.collectiveId)
resp <- Ok(BasicResult(true, "Task submitted"))
} yield resp
@ -125,11 +125,10 @@ object CollectiveRoutes {
for {
data <- req.as[EmptyTrashSetting]
_ <- backend.collective.startEmptyTrash(
EmptyTrashArgs(user.account.collective, data.minAge)
EmptyTrashArgs(user.account.collectiveId, data.minAge)
)
resp <- Ok(BasicResult(true, "Task submitted"))
} yield resp
}
}
}

View File

@ -38,7 +38,7 @@ object CustomFieldRoutes {
val order = sort.getOrElse(CustomFieldOrder.NameAsc)
for {
fs <- backend.customFields.findAll(
user.account.collective,
user.account.collectiveId,
param.map(_.q),
order
)
@ -54,7 +54,7 @@ object CustomFieldRoutes {
case GET -> Root / Ident(id) =>
(for {
field <- OptionT(backend.customFields.findById(user.account.collective, id))
field <- OptionT(backend.customFields.findById(user.account.collectiveId, id))
res <- OptionT.liftF(Ok(convertField(field)))
} yield res).getOrElseF(NotFound(BasicResult(false, "Not found")))
@ -67,7 +67,7 @@ object CustomFieldRoutes {
case DELETE -> Root / Ident(id) =>
for {
res <- backend.customFields.delete(user.account.collective, id)
res <- backend.customFields.delete(user.account.collectiveId, id)
resp <- Ok(convertResult(res))
} yield resp
}
@ -88,7 +88,7 @@ object CustomFieldRoutes {
id,
in.name,
in.label,
user.account.collective,
user.account.collectiveId,
in.ftype,
Timestamp.Epoch
)
@ -101,7 +101,7 @@ object CustomFieldRoutes {
in.name,
in.label,
in.ftype,
user.account.collective
user.account.collectiveId
)
private def convertField(f: CustomFieldData): CustomField =

View File

@ -75,7 +75,7 @@ object DownloadAllRoutes {
case req @ GET -> Root / "file" / Ident(id) =>
for {
data <- backend.downloadAll.getFile(share.account.collective, id)
data <- backend.downloadAll.getFile(share.account.collectiveId, id)
resp <- BinaryUtil.respond(dsl, req)(data)
} yield resp
}
@ -113,13 +113,13 @@ object DownloadAllRoutes {
case req @ GET -> Root / "file" / Ident(id) =>
for {
data <- backend.downloadAll.getFile(token.account.collective, id)
data <- backend.downloadAll.getFile(token.account.collectiveId, id)
resp <- BinaryUtil.respond(dsl, req)(data)
} yield resp
case HEAD -> Root / "file" / Ident(id) =>
for {
data <- backend.downloadAll.getFile(token.account.collective, id)
data <- backend.downloadAll.getFile(token.account.collectiveId, id)
resp <- BinaryUtil.respondHead(dsl)(data)
} yield resp
@ -131,7 +131,7 @@ object DownloadAllRoutes {
case PUT -> Root / "cancel" / Ident(id) =>
for {
res <- backend.downloadAll.cancelDownload(token.account, id)
res <- backend.downloadAll.cancelDownload(token.account.collectiveId, id)
resp <- Ok(Conversions.basicResult(res))
} yield resp
}

View File

@ -33,7 +33,7 @@ object EquipmentRoutes {
case GET -> Root :? QueryParam.QueryOpt(q) :? QueryParam.EquipSort(sort) =>
for {
data <- backend.equipment.findAll(
user.account,
user.account.collectiveId,
q.map(_.q),
sort.getOrElse(OEquipment.EquipmentOrder.NameAsc)
)
@ -43,7 +43,7 @@ object EquipmentRoutes {
case req @ POST -> Root =>
for {
data <- req.as[Equipment]
equip <- newEquipment(data, user.account.collective)
equip <- newEquipment(data, user.account.collectiveId)
res <- backend.equipment.add(equip)
resp <- Ok(basicResult(res, "Equipment created"))
} yield resp
@ -51,20 +51,20 @@ object EquipmentRoutes {
case req @ PUT -> Root =>
for {
data <- req.as[Equipment]
equip <- changeEquipment(data, user.account.collective)
equip <- changeEquipment(data, user.account.collectiveId)
res <- backend.equipment.update(equip)
resp <- Ok(basicResult(res, "Equipment updated."))
} yield resp
case DELETE -> Root / Ident(id) =>
for {
del <- backend.equipment.delete(id, user.account.collective)
del <- backend.equipment.delete(id, user.account.collectiveId)
resp <- Ok(basicResult(del, "Equipment deleted."))
} yield resp
case GET -> Root / Ident(id) =>
(for {
equip <- OptionT(backend.equipment.find(user.account, id))
equip <- OptionT(backend.equipment.find(user.account.collectiveId, id))
resp <- OptionT.liftF(Ok(mkEquipment(equip)))
} yield resp).getOrElseF(NotFound())
}

View File

@ -35,9 +35,15 @@ object FolderRoutes {
QueryParam.OwningOpt(owning) +& QueryParam.FolderSort(sort) =>
val order = sort.getOrElse(OFolder.FolderOrder.NameAsc)
val login =
owning.filter(identity).map(_ => user.account.user)
owning.filter(identity).map(_ => user.account.login)
for {
all <- backend.folder.findAll(user.account, login, q.map(_.q), order)
all <- backend.folder.findAll(
user.account.collectiveId,
user.account.userId,
login,
q.map(_.q),
order
)
resp <- Ok(FolderList(all.map(mkFolder).toList))
} yield resp
@ -45,46 +51,48 @@ object FolderRoutes {
for {
data <- req.as[NewFolder]
nfolder <- newFolder(data, user.account)
res <- backend.folder.add(nfolder, Some(user.account.user))
res <- backend.folder.add(nfolder, None)
resp <-
Ok(Conversions.idResult(res, nfolder.id, "Folder successfully created."))
} yield resp
case GET -> Root / Ident(id) =>
(for {
folder <- OptionT(backend.folder.findById(id, user.account))
folder <- OptionT(
backend.folder.findById(id, user.account.collectiveId, user.account.userId)
)
resp <- OptionT.liftF(Ok(mkFolderDetail(folder)))
} yield resp).getOrElseF(NotFound())
case req @ PUT -> Root / Ident(id) =>
for {
data <- req.as[NewFolder]
res <- backend.folder.changeName(id, user.account, data.name)
res <- backend.folder.changeName(id, user.account.userId, data.name)
resp <- Ok(mkFolderChangeResult(res))
} yield resp
case DELETE -> Root / Ident(id) =>
for {
res <- backend.folder.delete(id, user.account)
res <- backend.folder.delete(id, user.account.userId)
resp <- Ok(mkFolderChangeResult(res))
} yield resp
case PUT -> Root / Ident(id) / "member" / Ident(userId) =>
for {
res <- backend.folder.addMember(id, user.account, userId)
res <- backend.folder.addMember(id, user.account.userId, userId)
resp <- Ok(mkFolderChangeResult(res))
} yield resp
case DELETE -> Root / Ident(id) / "member" / Ident(userId) =>
for {
res <- backend.folder.removeMember(id, user.account, userId)
res <- backend.folder.removeMember(id, user.account.userId, userId)
resp <- Ok(mkFolderChangeResult(res))
} yield resp
}
}
private def newFolder[F[_]: Sync](ns: NewFolder, account: AccountId): F[RFolder] =
RFolder.newFolder(ns.name, account)
private def newFolder[F[_]: Sync](ns: NewFolder, account: AccountInfo): F[RFolder] =
RFolder.newFolder(ns.name, account.collectiveId, account.userId)
private def mkFolder(item: OFolder.FolderItem): FolderItem =
FolderItem(

View File

@ -33,7 +33,9 @@ object FullTextIndexRoutes {
HttpRoutes.of { case POST -> Root / "reIndex" =>
for {
res <- backend.fulltext.reindexCollective(user.account).attempt
res <- backend.fulltext
.reindexCollective(user.account.collectiveId, user.account.userId.some)
.attempt
resp <- Ok(Conversions.basicResult(res, "Full-text index will be re-created."))
} yield resp
}

View File

@ -9,14 +9,12 @@ package docspell.restserver.routes
import cats.data.{EitherT, OptionT}
import cats.effect._
import cats.implicits._
import docspell.backend.BackendApp
import docspell.common._
import docspell.restserver.Config
import docspell.restserver.conv.Conversions._
import docspell.restserver.http4s.Responses
import docspell.store.records.RItem
import docspell.store.records.{RCollective, RItem}
import org.http4s._
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl
@ -36,15 +34,15 @@ object IntegrationEndpointRoutes {
for {
_ <- authRequest(req, cfg.integrationEndpoint)
_ <- checkEnabled(cfg.integrationEndpoint)
_ <- lookupCollective(collective, backend)
} yield ()
c <- lookupCollective(collective, backend)
} yield c
HttpRoutes.of {
case req @ POST -> Root / "item" / Ident(collective) =>
(for {
_ <- validate(req, collective)
coll <- validate(req, collective)
res <- EitherT.liftF[F, Response[F], Response[F]](
uploadFile(collective, backend, cfg, dsl)(req)
uploadFile(coll.id, backend, cfg, dsl)(req)
)
} yield res).fold(identity, identity)
@ -56,9 +54,9 @@ object IntegrationEndpointRoutes {
case req @ GET -> Root / "checkfile" / Ident(collective) / checksum =>
(for {
_ <- validate(req, collective)
coll <- validate(req, collective)
items <- EitherT.liftF[F, Response[F], Vector[RItem]](
backend.itemSearch.findByFileCollective(checksum, collective)
backend.itemSearch.findByFileCollective(checksum, coll.id)
)
resp <-
EitherT.liftF[F, Response[F], Response[F]](Ok(CheckFileRoutes.convert(items)))
@ -86,14 +84,13 @@ object IntegrationEndpointRoutes {
def lookupCollective[F[_]: Async](
coll: Ident,
backend: BackendApp[F]
): EitherT[F, Response[F], Unit] =
for {
opt <- EitherT.liftF(backend.collective.find(coll))
res <- EitherT.cond[F](opt.exists(_.integrationEnabled), (), Response.notFound[F])
} yield res
): EitherT[F, Response[F], RCollective] =
OptionT(backend.collective.find(coll))
.filter(_.integrationEnabled)
.toRight(Response.notFound[F])
def uploadFile[F[_]: Async](
coll: Ident,
cid: CollectiveId,
backend: BackendApp[F],
cfg: Config,
dsl: Http4sDsl[F]
@ -110,8 +107,7 @@ object IntegrationEndpointRoutes {
cfg.integrationEndpoint.priority,
cfg.backend.files.validMimeTypes
)
account = AccountId(coll, DocspellSystem.user)
result <- backend.upload.submit(updata, account, None)
result <- backend.upload.submit(updata, cid, None, None)
res <- Ok(basicResult(result))
} yield res
}

View File

@ -22,7 +22,7 @@ import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityCodec._
import org.http4s.dsl.Http4sDsl
class ItemLinkRoutes[F[_]: Async](account: AccountId, backend: OItemLink[F])
class ItemLinkRoutes[F[_]: Async](account: AccountInfo, backend: OItemLink[F])
extends Http4sDsl[F] {
def get: HttpRoutes[F] =
HttpRoutes.of {
@ -36,7 +36,7 @@ class ItemLinkRoutes[F[_]: Async](account: AccountId, backend: OItemLink[F])
case DELETE -> Root / Ident(target) / Ident(id) =>
for {
_ <- backend.removeAll(account.collective, target, NonEmptyList.of(id))
_ <- backend.removeAll(account.collectiveId, target, NonEmptyList.of(id))
resp <- Ok(BasicResult(true, "Related items removed"))
} yield resp
@ -46,7 +46,7 @@ class ItemLinkRoutes[F[_]: Async](account: AccountId, backend: OItemLink[F])
related = NonEmptyList.fromList(input.related)
res <- OptionT
.fromOption[F](related)
.semiflatMap(backend.addAll(account.collective, input.item, _))
.semiflatMap(backend.addAll(account.collectiveId, input.item, _))
.value
resp <- Ok(convertResult(res))
} yield resp
@ -56,7 +56,7 @@ class ItemLinkRoutes[F[_]: Async](account: AccountId, backend: OItemLink[F])
input <- req.as[ItemLinkData]
related = NonEmptyList.fromList(input.related)
_ <- related
.map(backend.removeAll(account.collective, input.item, _))
.map(backend.removeAll(account.collectiveId, input.item, _))
.getOrElse(
BadRequest(BasicResult(false, "List of related items must not be empty"))
)
@ -77,6 +77,6 @@ class ItemLinkRoutes[F[_]: Async](account: AccountId, backend: OItemLink[F])
object ItemLinkRoutes {
def apply[F[_]: Async](account: AccountId, itemLink: OItemLink[F]): HttpRoutes[F] =
def apply[F[_]: Async](account: AccountInfo, itemLink: OItemLink[F]): HttpRoutes[F] =
new ItemLinkRoutes[F](account, itemLink).get
}

View File

@ -8,7 +8,6 @@ package docspell.restserver.routes
import cats.effect._
import cats.implicits._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.backend.ops.OCustomFields.{RemoveValue, SetValue}
@ -17,7 +16,7 @@ import docspell.restapi.model._
import docspell.restserver.Config
import docspell.restserver.conv.{Conversions, MultiIdSupport, NonEmptyListSupport}
import docspell.restserver.http4s.ClientRequestInfo
import docspell.scheduler.usertask.UserTaskScope
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
@ -42,7 +41,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
res <- backend.item.setStates(
data,
ItemState.Confirmed,
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Item data confirmed"))
} yield resp
@ -54,7 +53,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
res <- backend.item.setStates(
data,
ItemState.Created,
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Item back to created."))
} yield resp
@ -66,7 +65,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
res <- backend.item.setTagsMultipleItems(
items,
json.refs,
user.account.collective
user.account.collectiveId
)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
@ -80,7 +79,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
res <- backend.item.linkTagsMultipleItems(
items,
json.refs,
user.account.collective
user.account.collectiveId
)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
@ -94,7 +93,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
res <- backend.item.removeTagsMultipleItems(
items,
json.refs,
user.account.collective
user.account.collectiveId
)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
@ -108,7 +107,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
res <- backend.item.setNameMultiple(
items,
json.name.notEmpty.getOrElse(""),
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Name updated"))
} yield resp
@ -120,7 +119,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
res <- backend.item.setFolderMultiple(
items,
json.ref.map(_.id),
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Folder updated"))
} yield resp
@ -129,7 +128,11 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[ItemsAndDirection]
items <- requireNonEmpty(json.items)
res <- backend.item.setDirection(items, json.direction, user.account.collective)
res <- backend.item.setDirection(
items,
json.direction,
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Direction updated"))
} yield resp
@ -137,7 +140,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[ItemsAndDate]
items <- requireNonEmpty(json.items)
res <- backend.item.setItemDate(items, json.date, user.account.collective)
res <- backend.item.setItemDate(items, json.date, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Item date updated"))
} yield resp
@ -145,7 +148,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[ItemsAndDate]
items <- requireNonEmpty(json.items)
res <- backend.item.setItemDueDate(items, json.date, user.account.collective)
res <- backend.item.setItemDueDate(items, json.date, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Item due date updated"))
} yield resp
@ -153,7 +156,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[ItemsAndRef]
items <- requireNonEmpty(json.items)
res <- backend.item.setCorrOrg(items, json.ref, user.account.collective)
res <- backend.item.setCorrOrg(items, json.ref, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Correspondent organization updated"))
} yield resp
@ -161,7 +164,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[ItemsAndRef]
items <- requireNonEmpty(json.items)
res <- backend.item.setCorrPerson(items, json.ref, user.account.collective)
res <- backend.item.setCorrPerson(items, json.ref, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Correspondent person updated"))
} yield resp
@ -169,7 +172,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[ItemsAndRef]
items <- requireNonEmpty(json.items)
res <- backend.item.setConcPerson(items, json.ref, user.account.collective)
res <- backend.item.setConcPerson(items, json.ref, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Concerned person updated"))
} yield resp
@ -177,7 +180,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[ItemsAndRef]
items <- requireNonEmpty(json.items)
res <- backend.item.setConcEquip(items, json.ref, user.account.collective)
res <- backend.item.setConcEquip(items, json.ref, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Concerned equipment updated"))
} yield resp
@ -185,7 +188,11 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[IdList]
items <- requireNonEmpty(json.ids)
res <- backend.item.reprocessAll(items, user.account)
res <- backend.item.reprocessAll(
user.account.collectiveId,
items,
UserTaskScope(user.account)
)
resp <- Ok(Conversions.basicResult(res, "Re-process task(s) submitted."))
} yield resp
@ -193,7 +200,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[IdList]
items <- requireNonEmpty(json.ids)
n <- backend.item.setDeletedState(items, user.account.collective)
n <- backend.item.setDeletedState(items, user.account.collectiveId)
res = BasicResult(
n > 0,
if (n > 0) "Item(s) deleted" else "Item deletion failed."
@ -205,7 +212,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[IdList]
items <- requireNonEmpty(json.ids)
res <- backend.item.restore(items, user.account.collective)
res <- backend.item.restore(items, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Item(s) deleted"))
} yield resp
@ -215,7 +222,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
items <- requireNonEmpty(json.items)
res <- backend.customFields.setValueMultiple(
items,
SetValue(json.field.field, json.field.value, user.account.collective)
SetValue(json.field.field, json.field.value, user.account.collectiveId)
)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
@ -228,7 +235,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
items <- requireNonEmpty(json.items)
field <- readId[F](json.name)
res <- backend.customFields.deleteValue(
RemoveValue(field, items, user.account.collective)
RemoveValue(field, items, user.account.collectiveId)
)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
@ -239,7 +246,7 @@ object ItemMultiRoutes extends NonEmptyListSupport with MultiIdSupport {
for {
json <- req.as[IdList]
items <- requireNonEmpty(json.ids)
res <- backend.item.merge(logger, items, user.account.collective)
res <- backend.item.merge(logger, items, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Items merged"))
} yield resp
}

View File

@ -9,7 +9,6 @@ package docspell.restserver.routes
import cats.data.NonEmptyList
import cats.effect._
import cats.implicits._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.backend.ops.OCustomFields.{RemoveValue, SetValue}
@ -21,7 +20,7 @@ import docspell.restserver.http4s.BinaryUtil
import docspell.restserver.http4s.ClientRequestInfo
import docspell.restserver.http4s.Responses
import docspell.restserver.http4s.{QueryParam => QP}
import docspell.scheduler.usertask.UserTaskScope
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
@ -43,7 +42,7 @@ object ItemRoutes {
HttpRoutes.of {
case GET -> Root / Ident(id) =>
for {
item <- backend.itemSearch.findItem(id, user.account.collective)
item <- backend.itemSearch.findItem(id, user.account.collectiveId)
result = item.map(Conversions.mkItemDetail)
resp <-
result
@ -53,26 +52,30 @@ object ItemRoutes {
case POST -> Root / Ident(id) / "confirm" =>
for {
res <- backend.item.setState(id, ItemState.Confirmed, user.account.collective)
res <- backend.item.setState(
id,
ItemState.Confirmed,
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Item data confirmed"))
} yield resp
case POST -> Root / Ident(id) / "unconfirm" =>
for {
res <- backend.item.setState(id, ItemState.Created, user.account.collective)
res <- backend.item.setState(id, ItemState.Created, user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Item back to created."))
} yield resp
case POST -> Root / Ident(id) / "restore" =>
for {
res <- backend.item.restore(NonEmptyList.of(id), user.account.collective)
res <- backend.item.restore(NonEmptyList.of(id), user.account.collectiveId)
resp <- Ok(Conversions.basicResult(res, "Item restored."))
} yield resp
case req @ PUT -> Root / Ident(id) / "tags" =>
for {
tags <- req.as[StringList].map(_.items)
res <- backend.item.setTags(id, tags, user.account.collective)
res <- backend.item.setTags(id, tags, user.account.collectiveId)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
resp <- Ok(Conversions.basicResult(res.value, "Tags updated"))
@ -81,8 +84,8 @@ object ItemRoutes {
case req @ POST -> Root / Ident(id) / "tags" =>
for {
data <- req.as[Tag]
rtag <- Conversions.newTag(data, user.account.collective)
res <- backend.item.addNewTag(user.account.collective, id, rtag)
rtag <- Conversions.newTag(data, user.account.collectiveId)
res <- backend.item.addNewTag(user.account.collectiveId, id, rtag)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
resp <- Ok(Conversions.basicResult(res.value, "Tag added."))
@ -91,7 +94,7 @@ object ItemRoutes {
case req @ PUT -> Root / Ident(id) / "taglink" =>
for {
tags <- req.as[StringList]
res <- backend.item.linkTags(id, tags.items, user.account.collective)
res <- backend.item.linkTags(id, tags.items, user.account.collectiveId)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
resp <- Ok(Conversions.basicResult(res.value, "Tags linked"))
@ -100,7 +103,7 @@ object ItemRoutes {
case req @ POST -> Root / Ident(id) / "tagtoggle" =>
for {
tags <- req.as[StringList]
res <- backend.item.toggleTags(id, tags.items, user.account.collective)
res <- backend.item.toggleTags(id, tags.items, user.account.collectiveId)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
resp <- Ok(Conversions.basicResult(res.value, "Tags linked"))
@ -112,7 +115,7 @@ object ItemRoutes {
res <- backend.item.removeTagsMultipleItems(
NonEmptyList.of(id),
json.items,
user.account.collective
user.account.collectiveId
)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
@ -125,7 +128,7 @@ object ItemRoutes {
res <- backend.item.setDirection(
NonEmptyList.of(id),
dir.direction,
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Direction updated"))
} yield resp
@ -133,7 +136,11 @@ object ItemRoutes {
case req @ PUT -> Root / Ident(id) / "folder" =>
for {
idref <- req.as[OptionalId]
res <- backend.item.setFolder(id, idref.id.map(_.id), user.account.collective)
res <- backend.item.setFolder(
id,
idref.id.map(_.id),
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Folder updated"))
} yield resp
@ -143,7 +150,7 @@ object ItemRoutes {
res <- backend.item.setCorrOrg(
NonEmptyList.of(id),
idref.id,
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Correspondent organization updated"))
} yield resp
@ -151,7 +158,7 @@ object ItemRoutes {
case req @ POST -> Root / Ident(id) / "corrOrg" =>
for {
data <- req.as[Organization]
org <- Conversions.newOrg(data, user.account.collective)
org <- Conversions.newOrg(data, user.account.collectiveId)
res <- backend.item.addCorrOrg(id, org)
resp <- Ok(Conversions.basicResult(res, "Correspondent organization updated"))
} yield resp
@ -162,7 +169,7 @@ object ItemRoutes {
res <- backend.item.setCorrPerson(
NonEmptyList.of(id),
idref.id,
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Correspondent person updated"))
} yield resp
@ -170,7 +177,7 @@ object ItemRoutes {
case req @ POST -> Root / Ident(id) / "corrPerson" =>
for {
data <- req.as[Person]
pers <- Conversions.newPerson(data, user.account.collective)
pers <- Conversions.newPerson(data, user.account.collectiveId)
res <- backend.item.addCorrPerson(id, pers)
resp <- Ok(Conversions.basicResult(res, "Correspondent person updated"))
} yield resp
@ -181,7 +188,7 @@ object ItemRoutes {
res <- backend.item.setConcPerson(
NonEmptyList.of(id),
idref.id,
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Concerned person updated"))
} yield resp
@ -189,7 +196,7 @@ object ItemRoutes {
case req @ POST -> Root / Ident(id) / "concPerson" =>
for {
data <- req.as[Person]
pers <- Conversions.newPerson(data, user.account.collective)
pers <- Conversions.newPerson(data, user.account.collectiveId)
res <- backend.item.addConcPerson(id, pers)
resp <- Ok(Conversions.basicResult(res, "Concerned person updated"))
} yield resp
@ -200,7 +207,7 @@ object ItemRoutes {
res <- backend.item.setConcEquip(
NonEmptyList.of(id),
idref.id,
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Concerned equipment updated"))
} yield resp
@ -208,7 +215,7 @@ object ItemRoutes {
case req @ POST -> Root / Ident(id) / "concEquipment" =>
for {
data <- req.as[Equipment]
equip <- Conversions.newEquipment(data, user.account.collective)
equip <- Conversions.newEquipment(data, user.account.collectiveId)
res <- backend.item.addConcEquip(id, equip)
resp <- Ok(Conversions.basicResult(res, "Concerned equipment updated"))
} yield resp
@ -216,7 +223,11 @@ object ItemRoutes {
case req @ PUT -> Root / Ident(id) / "notes" =>
for {
text <- req.as[OptionalText]
res <- backend.item.setNotes(id, text.text.notEmpty, user.account.collective)
res <- backend.item.setNotes(
id,
text.text.notEmpty,
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Notes updated"))
} yield resp
@ -226,7 +237,7 @@ object ItemRoutes {
res <- backend.item.setName(
id,
text.text.notEmpty.getOrElse(""),
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Name updated"))
} yield resp
@ -238,7 +249,7 @@ object ItemRoutes {
res <- backend.item.setItemDueDate(
NonEmptyList.of(id),
date.date,
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Item due date updated"))
} yield resp
@ -250,14 +261,14 @@ object ItemRoutes {
res <- backend.item.setItemDate(
NonEmptyList.of(id),
date.date,
user.account.collective
user.account.collectiveId
)
resp <- Ok(Conversions.basicResult(res, "Item date updated"))
} yield resp
case GET -> Root / Ident(id) / "proposals" =>
for {
ml <- backend.item.getProposals(id, user.account.collective)
ml <- backend.item.getProposals(id, user.account.collectiveId)
ip = Conversions.mkItemProposals(ml)
resp <- Ok(ip)
} yield resp
@ -274,7 +285,7 @@ object ItemRoutes {
def notFound =
NotFound(BasicResult(false, "Not found"))
for {
preview <- backend.itemSearch.findItemPreview(id, user.account.collective)
preview <- backend.itemSearch.findItemPreview(id, user.account.collectiveId)
inm = req.headers.get[`If-None-Match`].flatMap(_.tags)
matches = BinaryUtil.matchETag(preview.map(_.meta), inm)
fallback = flag.getOrElse(false)
@ -292,7 +303,7 @@ object ItemRoutes {
case HEAD -> Root / Ident(id) / "preview" =>
for {
preview <- backend.itemSearch.findItemPreview(id, user.account.collective)
preview <- backend.itemSearch.findItemPreview(id, user.account.collectiveId)
resp <-
preview
.map(data => BinaryUtil.withResponseHeaders(dsl, Ok())(data))
@ -303,7 +314,12 @@ object ItemRoutes {
for {
data <- req.as[IdList]
_ <- logger.debug(s"Re-process item ${id.id}")
res <- backend.item.reprocess(id, data.ids, user.account)
res <- backend.item.reprocess(
user.account.collectiveId,
id,
data.ids,
UserTaskScope(user.account)
)
resp <- Ok(Conversions.basicResult(res, "Re-process task submitted."))
} yield resp
@ -312,7 +328,7 @@ object ItemRoutes {
data <- req.as[CustomFieldValue]
res <- backend.customFields.setValue(
id,
SetValue(data.field, data.value, user.account.collective)
SetValue(data.field, data.value, user.account.collectiveId)
)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
@ -322,7 +338,7 @@ object ItemRoutes {
case req @ DELETE -> Root / Ident(id) / "customfield" / Ident(fieldId) =>
for {
res <- backend.customFields.deleteValue(
RemoveValue(fieldId, NonEmptyList.of(id), user.account.collective)
RemoveValue(fieldId, NonEmptyList.of(id), user.account.collectiveId)
)
baseUrl = ClientRequestInfo.getBaseUrl(cfg, req)
_ <- backend.notification.offerEvents(res.event(user.account, baseUrl.some))
@ -333,7 +349,7 @@ object ItemRoutes {
for {
n <- backend.item.setDeletedState(
NonEmptyList.of(id),
user.account.collective
user.account.collectiveId
)
res = BasicResult(
n > 0,

View File

@ -8,13 +8,12 @@ package docspell.restserver.routes
import cats.effect._
import cats.implicits._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.common.Ident
import docspell.restapi.model.JobPriority
import docspell.restserver.conv.Conversions
import docspell.scheduler.usertask.UserTaskScope
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
@ -29,21 +28,21 @@ object JobQueueRoutes {
HttpRoutes.of {
case GET -> Root / "state" =>
for {
js <- backend.job.queueState(user.account.collective, 40)
js <- backend.job.queueState(UserTaskScope(user.account), 40)
res = Conversions.mkJobQueueState(js)
resp <- Ok(res)
} yield resp
case POST -> Root / Ident(id) / "cancel" =>
for {
result <- backend.job.cancelJob(id, user.account.collective)
result <- backend.job.cancelJob(id, UserTaskScope(user.account))
resp <- Ok(Conversions.basicResult(result))
} yield resp
case req @ POST -> Root / Ident(id) / "priority" =>
for {
prio <- req.as[JobPriority]
res <- backend.job.setPriority(id, user.account.collective, prio.priority)
res <- backend.job.setPriority(id, UserTaskScope(user.account), prio.priority)
resp <- Ok(Conversions.basicResult(res, "Job priority changed"))
} yield resp
}

View File

@ -96,7 +96,7 @@ object LoginRoutes {
resp <- Ok(
AuthResult(
token.account.collective.id,
token.account.user.id,
token.account.login.id,
true,
"Login successful",
Some(cd.asString),

View File

@ -32,7 +32,9 @@ object MailSendRoutes {
for {
in <- req.as[SimpleMail]
mail = convertIn(id, in)
res <- mail.traverse(m => backend.mail.sendMail(user.account, name, m))
res <- mail.traverse(m =>
backend.mail.sendMail(user.account.userId, user.account.collectiveId, name, m)
)
resp <- res.fold(
err => Ok(BasicResult(false, s"Invalid mail data: $err")),
res => Ok(convertOut(res))

View File

@ -35,27 +35,27 @@ object MailSettingsRoutes {
HttpRoutes.of {
case GET -> Root / "smtp" :? QueryParam.QueryOpt(q) =>
for {
list <- backend.mail.getSmtpSettings(user.account, q.map(_.q))
list <- backend.mail.getSmtpSettings(user.account.userId, q.map(_.q))
res = list.map(convert)
resp <- Ok(EmailSettingsList(res.toList))
} yield resp
case GET -> Root / "imap" :? QueryParam.QueryOpt(q) =>
for {
list <- backend.mail.getImapSettings(user.account, q.map(_.q))
list <- backend.mail.getImapSettings(user.account.userId, q.map(_.q))
res = list.map(convert)
resp <- Ok(ImapSettingsList(res.toList))
} yield resp
case GET -> Root / "smtp" / Ident(name) =>
(for {
ems <- backend.mail.findSmtpSettings(user.account, name)
ems <- backend.mail.findSmtpSettings(user.account.userId, name)
resp <- OptionT.liftF(Ok(convert(ems)))
} yield resp).getOrElseF(NotFound())
case GET -> Root / "imap" / Ident(name) =>
(for {
ems <- backend.mail.findImapSettings(user.account, name)
ems <- backend.mail.findImapSettings(user.account.userId, name)
resp <- OptionT.liftF(Ok(convert(ems)))
} yield resp).getOrElseF(NotFound())
@ -64,7 +64,7 @@ object MailSettingsRoutes {
in <- OptionT.liftF(req.as[EmailSettings])
ru = makeSmtpSettings(in)
up <- OptionT.liftF(
ru.traverse(r => backend.mail.createSmtpSettings(user.account, r))
ru.traverse(r => backend.mail.createSmtpSettings(user.account.userId, r))
)
resp <- OptionT.liftF(
Ok(
@ -81,7 +81,7 @@ object MailSettingsRoutes {
in <- OptionT.liftF(req.as[ImapSettings])
ru = makeImapSettings(in)
up <- OptionT.liftF(
ru.traverse(r => backend.mail.createImapSettings(user.account, r))
ru.traverse(r => backend.mail.createImapSettings(user.account.userId, r))
)
resp <- OptionT.liftF(
Ok(
@ -98,7 +98,9 @@ object MailSettingsRoutes {
in <- OptionT.liftF(req.as[EmailSettings])
ru = makeSmtpSettings(in)
up <- OptionT.liftF(
ru.traverse(r => backend.mail.updateSmtpSettings(user.account, name, r))
ru.traverse(r =>
backend.mail.updateSmtpSettings(user.account.userId, name, r)
)
)
resp <- OptionT.liftF(
Ok(
@ -117,7 +119,9 @@ object MailSettingsRoutes {
in <- OptionT.liftF(req.as[ImapSettings])
ru = makeImapSettings(in)
up <- OptionT.liftF(
ru.traverse(r => backend.mail.updateImapSettings(user.account, name, r))
ru.traverse(r =>
backend.mail.updateImapSettings(user.account.userId, name, r)
)
)
resp <- OptionT.liftF(
Ok(
@ -133,7 +137,7 @@ object MailSettingsRoutes {
case DELETE -> Root / "smtp" / Ident(name) =>
for {
n <- backend.mail.deleteSmtpSettings(user.account, name)
n <- backend.mail.deleteSmtpSettings(user.account.userId, name)
resp <- Ok(
if (n > 0) BasicResult(true, "Mail settings removed")
else BasicResult(false, "Mail settings could not be removed")
@ -142,7 +146,7 @@ object MailSettingsRoutes {
case DELETE -> Root / "imap" / Ident(name) =>
for {
n <- backend.mail.deleteImapSettings(user.account, name)
n <- backend.mail.deleteImapSettings(user.account.userId, name)
resp <- Ok(
if (n > 0) BasicResult(true, "Mail settings removed")
else BasicResult(false, "Mail settings could not be removed")

View File

@ -50,14 +50,14 @@ object NotificationRoutes extends NonEmptyListSupport {
HttpRoutes.of {
case GET -> Root =>
for {
list <- backend.notification.listChannels(user.account)
list <- backend.notification.listChannels(user.account.userId)
data = list.map(NotificationChannel.convert)
resp <- Ok(data)
} yield resp
case DELETE -> Root / Ident(id) =>
for {
res <- backend.notification.deleteChannel(id, user.account)
res <- backend.notification.deleteChannel(id, user.account.userId)
resp <- Ok(Conversions.basicResult(res, "Channel deleted"))
} yield resp
@ -69,7 +69,7 @@ object NotificationRoutes extends NonEmptyListSupport {
.fromEither[F](ch)
.semiflatMap { c =>
backend.notification
.createChannel(c, user.account)
.createChannel(c, user.account.userId)
.map(res => Conversions.basicResult(res, "Channel created"))
}
.foldF(ex => BadRequest(BasicResult(false, ex.getMessage)), Ok(_))
@ -83,7 +83,7 @@ object NotificationRoutes extends NonEmptyListSupport {
.fromEither[F](ch)
.semiflatMap { c =>
backend.notification
.updateChannel(c, user.account)
.updateChannel(c, user.account.userId)
.map(res => Conversions.basicResult(res, "Channel created"))
}
.foldF(ex => BadRequest(BasicResult(false, ex.getMessage)), Ok(_))
@ -102,14 +102,14 @@ object NotificationRoutes extends NonEmptyListSupport {
HttpRoutes.of {
case GET -> Root =>
for {
list <- backend.notification.listHooks(user.account)
list <- backend.notification.listHooks(user.account.userId)
data = list.map(Converters.convertHook)
resp <- Ok(data)
} yield resp
case DELETE -> Root / Ident(id) =>
for {
res <- backend.notification.deleteHook(id, user.account)
res <- backend.notification.deleteHook(id, user.account.userId)
resp <- Ok(Conversions.basicResult(res, "Hook deleted."))
} yield resp
@ -117,7 +117,7 @@ object NotificationRoutes extends NonEmptyListSupport {
for {
input <- req.as[NotificationHook]
hook <- Sync[F].pure(Converters.convertHook(input)).rethrow
res <- backend.notification.createHook(hook, user.account)
res <- backend.notification.createHook(hook, user.account.userId)
resp <- Ok(Conversions.basicResult(res, "Hook created"))
} yield resp
@ -125,7 +125,7 @@ object NotificationRoutes extends NonEmptyListSupport {
for {
input <- req.as[NotificationHook]
hook <- Sync[F].pure(Converters.convertHook(input)).rethrow
res <- backend.notification.updateHook(hook, user.account)
res <- backend.notification.updateHook(hook, user.account.userId)
resp <- Ok(Conversions.basicResult(res, "Hook updated"))
} yield resp
@ -187,7 +187,7 @@ object NotificationRoutes extends NonEmptyListSupport {
NotificationHook(
h.id,
h.enabled,
h.channels.map(c => NotificationChannelRef(c.id, c.channelType, c.name)).toList,
h.channels.map(c => NotificationChannelRef(c.id, c.channelType, c.name)),
h.allEvents,
h.eventFilter,
h.events

View File

@ -110,7 +110,7 @@ object NotifyDueItemsRoutes extends MailAddressCodec with NonEmptyListSupport {
def makeTask[F[_]: Sync](
id: Ident,
baseUrl: LenientUri,
user: AccountId,
user: AccountInfo,
settings: PeriodicDueItemsSettings
): F[UserTask[PeriodicDueItemsArgs]] =
requireNonEmpty(settings.channels).map { ch =>

View File

@ -36,7 +36,7 @@ object OrganizationRoutes {
if (full.getOrElse(false))
for {
data <- backend.organization.findAllOrg(
user.account,
user.account.collectiveId,
q.map(_.q),
order
)
@ -44,14 +44,18 @@ object OrganizationRoutes {
} yield resp
else
for {
data <- backend.organization.findAllOrgRefs(user.account, q.map(_.q), order)
data <- backend.organization.findAllOrgRefs(
user.account.collectiveId,
q.map(_.q),
order
)
resp <- Ok(ReferenceList(data.map(mkIdName).toList))
} yield resp
case req @ POST -> Root =>
for {
data <- req.as[Organization]
newOrg <- newOrg(data, user.account.collective)
newOrg <- newOrg(data, user.account.collectiveId)
added <- backend.organization.addOrg(newOrg)
resp <- Ok(basicResult(added, "New organization saved."))
} yield resp
@ -59,23 +63,22 @@ object OrganizationRoutes {
case req @ PUT -> Root =>
for {
data <- req.as[Organization]
upOrg <- changeOrg(data, user.account.collective)
upOrg <- changeOrg(data, user.account.collectiveId)
update <- backend.organization.updateOrg(upOrg)
resp <- Ok(basicResult(update, "Organization updated."))
} yield resp
case DELETE -> Root / Ident(id) =>
for {
delOrg <- backend.organization.deleteOrg(id, user.account.collective)
delOrg <- backend.organization.deleteOrg(id, user.account.collectiveId)
resp <- Ok(basicResult(delOrg, "Organization deleted."))
} yield resp
case GET -> Root / Ident(id) =>
(for {
org <- OptionT(backend.organization.findOrg(user.account, id))
org <- OptionT(backend.organization.findOrg(user.account.collectiveId, id))
resp <- OptionT.liftF(Ok(mkOrg(org)))
} yield resp).getOrElseF(NotFound())
}
}
}

View File

@ -112,7 +112,7 @@ object PeriodicQueryRoutes extends MailAddressCodec with NonEmptyListSupport {
def makeTask[F[_]: Sync](
id: Ident,
baseUrl: LenientUri,
user: AccountId,
user: AccountInfo,
settings: PeriodicQuerySettings
): F[UserTask[PeriodicQueryArgs]] =
Sync[F]

View File

@ -37,7 +37,7 @@ object PersonRoutes {
if (full.getOrElse(false))
for {
data <- backend.organization.findAllPerson(
user.account,
user.account.collectiveId,
q.map(_.q),
order
)
@ -46,7 +46,7 @@ object PersonRoutes {
else
for {
data <- backend.organization.findAllPersonRefs(
user.account,
user.account.collectiveId,
q.map(_.q),
order
)
@ -56,7 +56,7 @@ object PersonRoutes {
case req @ POST -> Root =>
for {
data <- req.as[Person]
newPer <- newPerson(data, user.account.collective)
newPer <- newPerson(data, user.account.collectiveId)
added <- backend.organization.addPerson(newPer)
resp <- Ok(basicResult(added, "New person saved."))
} yield resp
@ -64,7 +64,7 @@ object PersonRoutes {
case req @ PUT -> Root =>
for {
data <- req.as[Person]
upPer <- changePerson(data, user.account.collective)
upPer <- changePerson(data, user.account.collectiveId)
update <- backend.organization.updatePerson(upPer)
resp <- Ok(basicResult(update, "Person updated."))
} yield resp
@ -72,16 +72,15 @@ object PersonRoutes {
case DELETE -> Root / Ident(id) =>
for {
_ <- logger.debug(s"Deleting person ${id.id}")
delOrg <- backend.organization.deletePerson(id, user.account.collective)
delOrg <- backend.organization.deletePerson(id, user.account.collectiveId)
resp <- Ok(basicResult(delOrg, "Person deleted."))
} yield resp
case GET -> Root / Ident(id) =>
(for {
org <- OptionT(backend.organization.findPerson(user.account, id))
org <- OptionT(backend.organization.findPerson(user.account.collectiveId, id))
resp <- OptionT.liftF(Ok(mkPerson(org)))
} yield resp).getOrElseF(NotFound())
}
}
}

View File

@ -35,7 +35,7 @@ object ScanMailboxRoutes {
HttpRoutes.of {
case GET -> Root =>
ut.getScanMailbox(UserTaskScope(user.account))
.evalMap(task => taskToSettings(user.account, backend, task))
.evalMap(task => taskToSettings(user.account.userId, backend, task))
.compile
.toVector
.map(v => ScanMailboxSettingsList(v.toList))
@ -44,7 +44,7 @@ object ScanMailboxRoutes {
case GET -> Root / Ident(id) =>
(for {
task <- ut.findScanMailbox(id, UserTaskScope(user.account))
res <- OptionT.liftF(taskToSettings(user.account, backend, task))
res <- OptionT.liftF(taskToSettings(user.account.userId, backend, task))
resp <- OptionT.liftF(Ok(res))
} yield resp).getOrElseF(NotFound())
@ -102,7 +102,7 @@ object ScanMailboxRoutes {
def makeTask[F[_]: Sync](
id: Ident,
user: AccountId,
user: AccountInfo,
settings: ScanMailboxSettings
): F[UserTask[ScanMailboxArgs]] =
Sync[F].pure(
@ -133,14 +133,14 @@ object ScanMailboxRoutes {
)
def taskToSettings[F[_]: Sync](
account: AccountId,
userId: Ident,
backend: BackendApp[F],
task: UserTask[ScanMailboxArgs]
): F[ScanMailboxSettings] =
for {
conn <-
backend.mail
.getImapSettings(account, None)
.getImapSettings(userId, None)
.map(
_.find(_.name == task.args.imapConnection)
.map(_.name)

View File

@ -30,19 +30,19 @@ object SentMailRoutes {
HttpRoutes.of {
case GET -> Root / "item" / Ident(id) =>
for {
all <- backend.mail.getSentMailsForItem(user.account, id)
all <- backend.mail.getSentMailsForItem(user.account.collectiveId, id)
resp <- Ok(SentMails(all.map(convert).toList))
} yield resp
case GET -> Root / "mail" / Ident(mailId) =>
(for {
mail <- backend.mail.getSentMail(user.account, mailId)
mail <- backend.mail.getSentMail(user.account.collectiveId, mailId)
resp <- OptionT.liftF(Ok(convert(mail)))
} yield resp).getOrElseF(NotFound())
case DELETE -> Root / "mail" / Ident(mailId) =>
for {
n <- backend.mail.deleteSentMail(user.account, mailId)
n <- backend.mail.deleteSentMail(user.account.collectiveId, mailId)
resp <- Ok(BasicResult(n > 0, s"Mails deleted: $n"))
} yield resp
}

View File

@ -35,9 +35,9 @@ object ShareRoutes {
HttpRoutes.of {
case GET -> Root :? QP.Query(q) :? QP.OwningFlag(owning) =>
val login = if (owning) Some(user.account.user) else None
val login = if (owning) Some(user.account.login) else None
for {
all <- backend.share.findAll(user.account.collective, login, q)
all <- backend.share.findAll(user.account.collectiveId, login, q)
now <- Timestamp.current[F]
res <- Ok(ShareList(all.map(mkShareDetail(now))))
} yield res
@ -52,7 +52,7 @@ object ShareRoutes {
case GET -> Root / Ident(id) =>
(for {
share <- backend.share.findOne(id, user.account.collective)
share <- backend.share.findOne(id, user.account.collectiveId)
now <- OptionT.liftF(Timestamp.current[F])
resp <- OptionT.liftF(Ok(mkShareDetail(now)(share)))
} yield resp).getOrElseF(NotFound())
@ -67,7 +67,7 @@ object ShareRoutes {
case DELETE -> Root / Ident(id) =>
for {
del <- backend.share.delete(id, user.account.collective)
del <- backend.share.delete(id, user.account.collectiveId)
resp <- Ok(BasicResult(del, if (del) "Share deleted." else "Deleting failed."))
} yield resp
@ -75,7 +75,10 @@ object ShareRoutes {
for {
in <- req.as[SimpleShareMail]
mail = convertIn(in)
res <- mail.traverse(m => backend.share.sendMail(user.account, name, m))
res <- mail.traverse(m =>
backend.share
.sendMail(user.account.collectiveId, user.account.userId, name, m)
)
resp <- res.fold(
err => Ok(BasicResult(false, s"Invalid mail data: $err")),
res => Ok(convertOut(res))
@ -111,7 +114,7 @@ object ShareRoutes {
def mkNewShare(data: ShareData, user: AuthToken): OShare.NewShare =
OShare.NewShare(
user.account,
user.account.asAccountId,
data.name,
data.query,
data.enabled,
@ -159,7 +162,7 @@ object ShareRoutes {
ShareDetail(
r.share.id,
r.share.query,
IdName(r.user.uid, r.user.login.id),
IdName(r.account.userId, r.account.login.id),
r.share.name,
r.share.enabled,
r.share.publishAt,

View File

@ -30,14 +30,14 @@ object SourceRoutes {
HttpRoutes.of {
case GET -> Root =>
for {
all <- backend.source.findAll(user.account)
all <- backend.source.findAll(user.account.collectiveId)
res <- Ok(SourceList(all.map(mkSource).toList))
} yield res
case req @ POST -> Root =>
for {
data <- req.as[SourceTagIn]
src <- newSource(data.source, user.account.collective)
src <- newSource(data.source, user.account.collectiveId)
added <- backend.source.add(src, data.tags)
resp <- Ok(basicResult(added, "Source added."))
} yield resp
@ -45,14 +45,14 @@ object SourceRoutes {
case req @ PUT -> Root =>
for {
data <- req.as[SourceTagIn]
src = changeSource(data.source, user.account.collective)
src = changeSource(data.source, user.account.collectiveId)
updated <- backend.source.update(src, data.tags)
resp <- Ok(basicResult(updated, "Source updated."))
} yield resp
case DELETE -> Root / Ident(id) =>
for {
del <- backend.source.delete(id, user.account.collective)
del <- backend.source.delete(id, user.account.collectiveId)
resp <- Ok(basicResult(del, "Source deleted."))
} yield resp
}

View File

@ -32,7 +32,7 @@ object TagRoutes {
case GET -> Root :? QueryParam.QueryOpt(q) :? QueryParam.TagSort(sort) =>
for {
all <- backend.tag.findAll(
user.account,
user.account.collectiveId,
q.map(_.q),
sort.getOrElse(TagOrder.NameAsc)
)
@ -42,7 +42,7 @@ object TagRoutes {
case req @ POST -> Root =>
for {
data <- req.as[Tag]
tag <- newTag(data, user.account.collective)
tag <- newTag(data, user.account.collectiveId)
res <- backend.tag.add(tag)
resp <- Ok(basicResult(res, "Tag successfully created."))
} yield resp
@ -50,14 +50,14 @@ object TagRoutes {
case req @ PUT -> Root =>
for {
data <- req.as[Tag]
tag = changeTag(data, user.account.collective)
tag = changeTag(data, user.account.collectiveId)
res <- backend.tag.update(tag)
resp <- Ok(basicResult(res, "Tag successfully updated."))
} yield resp
case DELETE -> Root / Ident(id) =>
for {
del <- backend.tag.delete(id, user.account.collective)
del <- backend.tag.delete(id, user.account.collectiveId)
resp <- Ok(basicResult(del, "Tag successfully deleted."))
} yield resp
}

View File

@ -33,7 +33,13 @@ object UploadRoutes {
val dsl = new Http4sDsl[F] with ResponseGenerator[F] {}
import dsl._
val submitting = submitFiles[F](backend, cfg, Right(user.account)) _
val submitting =
submitFiles[F](
backend,
cfg,
Right(user.account.collectiveId),
user.account.userId.some
) _
HttpRoutes.of {
case req @ POST -> Root / "item" =>
@ -53,7 +59,7 @@ object UploadRoutes {
(for {
_ <- OptionT(backend.collective.findEnabledSource(srcId))
res <- OptionT.liftF(
submitFiles(backend, cfg, Left(srcId))(req, None, Priority.Low, dsl)
submitFiles(backend, cfg, Left(srcId), None)(req, None, Priority.Low, dsl)
)
} yield res).getOrElseF(NotFound())
@ -61,7 +67,12 @@ object UploadRoutes {
(for {
_ <- OptionT(backend.collective.findEnabledSource(srcId))
res <- OptionT.liftF(
submitFiles(backend, cfg, Left(srcId))(req, Some(itemId), Priority.Low, dsl)
submitFiles(backend, cfg, Left(srcId), None)(
req,
Some(itemId),
Priority.Low,
dsl
)
)
} yield res).getOrElseF(NotFound())
}
@ -70,7 +81,8 @@ object UploadRoutes {
private def submitFiles[F[_]: Async](
backend: BackendApp[F],
cfg: Config,
accOrSrc: Either[Ident, AccountId]
accOrSrc: Either[Ident, CollectiveId],
userId: Option[Ident]
)(
req: Request[F],
itemId: Option[Ident],
@ -96,7 +108,7 @@ object UploadRoutes {
prio,
cfg.backend.files.validMimeTypes
)
result <- backend.upload.submitEither(updata, accOrSrc, itemId)
result <- backend.upload.submitEither(updata, accOrSrc, userId, itemId)
res <- Ok(basicResult(result))
} yield res
}

View File

@ -8,14 +8,13 @@ package docspell.restserver.routes
import cats.effect._
import cats.implicits._
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.backend.ops.OCollective
import docspell.common._
import docspell.restapi.model._
import docspell.restserver.conv.Conversions._
import docspell.store.UpdateResult
import org.http4s.HttpRoutes
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
@ -32,7 +31,8 @@ object UserRoutes {
for {
data <- req.as[PasswordChange]
res <- backend.collective.changePassword(
user.account,
user.account.collectiveId,
user.account.userId,
data.currentPassword,
data.newPassword
)
@ -41,14 +41,14 @@ object UserRoutes {
case GET -> Root =>
for {
all <- backend.collective.listUser(user.account.collective)
all <- backend.collective.listUser(user.account.collectiveId)
res <- Ok(UserList(all.map(mkUser).toList))
} yield res
case req @ POST -> Root =>
for {
data <- req.as[User]
nuser <- newUser(data, user.account.collective)
nuser <- newUser(data, user.account.collectiveId)
added <- backend.collective.add(nuser)
resp <- Ok(basicResult(added, "User created."))
} yield resp
@ -56,25 +56,35 @@ object UserRoutes {
case req @ PUT -> Root =>
for {
data <- req.as[User]
nuser = changeUser(data, user.account.collective)
nuser = changeUser(data, user.account.collectiveId)
update <- backend.collective.update(nuser)
resp <- Ok(basicResult(update, "User updated."))
} yield resp
case DELETE -> Root / Ident(id) =>
for {
ar <- backend.collective.deleteUser(id, user.account.collective)
users <- backend.collective.listUser(user.account.collectiveId)
ar <-
if (users.exists(_.uid == id)) backend.collective.deleteUser(id)
else UpdateResult.notFound.pure[F]
resp <- Ok(basicResult(ar, "User deleted."))
} yield resp
case GET -> Root / Ident(username) / "deleteData" =>
for {
data <- backend.collective.getDeleteUserData(
AccountId(user.account.collective, username)
)
resp <- Ok(
DeleteUserData(data.ownedFolders, data.sentMails, data.shares)
)
users <- backend.collective.listUser(user.account.collectiveId)
userToDelete = users.find(u => u.login == username || u.uid == username)
resp <- userToDelete match {
case Some(user) =>
backend.collective
.getDeleteUserData(user.cid, user.uid)
.flatMap(data =>
Ok(DeleteUserData(data.ownedFolders, data.sentMails, data.shares))
)
case None =>
NotFound(BasicResult(false, s"User '${username.id}' not found"))
}
} yield resp
}
}

View File

@ -10,10 +10,9 @@ import cats.effect.Async
import cats.implicits._
import fs2.concurrent.Topic
import fs2.{Pipe, Stream}
import docspell.backend.BackendApp
import docspell.backend.auth.AuthToken
import docspell.scheduler.usertask.UserTaskScope
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.server.websocket.WebSocketBuilder2
@ -34,7 +33,7 @@ object WebSocketRoutes {
HttpRoutes.of { case GET -> Root =>
val init =
for {
jc <- backend.job.getUnfinishedJobCount(user.account.collective)
jc <- backend.job.getUnfinishedJobCount(UserTaskScope(user.account))
msg = OutputEvent.JobsWaiting(user.account.collective, jc)
} yield Text(msg.encode)

View File

@ -16,7 +16,11 @@ import docspell.notification.api._
import docspell.store.queries.QLogin
import docspell.store.records._
import db.migration.data._
import db.migration.data.{
PeriodicDueItemsArgs => PeriodicDueItemsArgsLegacy,
PeriodicQueryArgs => PeriodicQueryArgsLegacy,
_
}
import doobie._
import doobie.implicits._
import doobie.util.transactor.Strategy
@ -75,8 +79,8 @@ trait MigrationTasks {
ref.flatMap(channelRef =>
RPeriodicTask.updateTask(
old.id,
PeriodicQueryArgs.taskName,
PeriodicQueryArgs(
PeriodicQueryArgsLegacy.taskName,
PeriodicQueryArgsLegacy(
oldArgs.account,
NonEmptyList.of(channelRef),
oldArgs.query,
@ -105,8 +109,8 @@ trait MigrationTasks {
ref.flatMap(channelRef =>
RPeriodicTask.updateTask(
old.id,
PeriodicDueItemsArgs.taskName,
PeriodicDueItemsArgs(
PeriodicDueItemsArgsLegacy.taskName,
PeriodicDueItemsArgsLegacy(
oldArgs.account,
NonEmptyList.of(channelRef),
oldArgs.remindDays,
@ -147,7 +151,7 @@ trait MigrationTasks {
RPeriodicTask
.updateTask(
old.id,
PeriodicDueItemsArgs.taskName,
PeriodicDueItemsArgsLegacy.taskName,
a.asJson.noSpaces
)
)
@ -163,7 +167,7 @@ trait MigrationTasks {
private def convertArgs(
old: NotifyDueItemsArgs
): OptionT[ConnectionIO, PeriodicDueItemsArgs] = {
): OptionT[ConnectionIO, PeriodicDueItemsArgsLegacy] = {
val recs = old.recipients
.map(MailAddress.parse)
.flatMap {
@ -188,7 +192,7 @@ trait MigrationTasks {
now
)
_ <- OptionT.liftF(RNotificationChannelMail.insert(ch))
args = PeriodicDueItemsArgs(
args = PeriodicDueItemsArgsLegacy(
old.account,
NonEmptyList.of(ChannelRef(ch.id, ChannelType.Mail, chName)),
old.remindDays,

View File

@ -0,0 +1,43 @@
/*
* Copyright 2020 Eike K. & Contributors
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package db.migration.data
import cats.data.NonEmptyList
import docspell.common._
import docspell.notification.api.ChannelRef
import io.circe.generic.semiauto
import io.circe.{Decoder, Encoder}
/** Arguments to the notification task.
*
* This tasks queries items with a due date and informs the user via mail.
*
* If the structure changes, there must be some database migration to update or remove
* the json data of the corresponding task.
*
* @deprecated
* replaced with a version using `AccountInfo`
*/
final case class PeriodicDueItemsArgs(
account: AccountId,
channels: NonEmptyList[ChannelRef],
remindDays: Int,
daysBack: Option[Int],
tagsInclude: List[Ident],
tagsExclude: List[Ident],
baseUrl: Option[LenientUri]
)
object PeriodicDueItemsArgs {
val taskName = Ident.unsafe("periodic-due-items-notify2")
implicit val jsonDecoder: Decoder[PeriodicDueItemsArgs] =
semiauto.deriveDecoder
implicit val jsonEncoder: Encoder[PeriodicDueItemsArgs] =
semiauto.deriveEncoder
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2020 Eike K. & Contributors
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package db.migration.data
import cats.data.NonEmptyList
import docspell.common._
import docspell.notification.api.ChannelRef
import io.circe.generic.semiauto
import io.circe.{Decoder, Encoder}
/** @deprecated replaced with a version using `AccountInfo` */
final case class PeriodicQueryArgs(
account: AccountId,
channels: NonEmptyList[ChannelRef],
query: Option[ItemQueryString],
bookmark: Option[String],
baseUrl: Option[LenientUri],
contentStart: Option[String]
)
object PeriodicQueryArgs {
val taskName = Ident.unsafe("periodic-query-notify2")
implicit val jsonDecoder: Decoder[PeriodicQueryArgs] =
semiauto.deriveDecoder
implicit def jsonEncoder: Encoder[PeriodicQueryArgs] =
semiauto.deriveEncoder
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2020 Eike K. & Contributors
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package db.migration.data
import docspell.common._
import docspell.common.syntax.all._
import io.circe._
import io.circe.generic.semiauto._
/** Arguments to the poll-mailbox task.
*
* This tasks queries user mailboxes and pushes found mails into docspell for processing.
*
* If the structure changes, there must be some database migration to update or remove
* the json data of the corresponding task.
*
* @deprecated
* replaced with a version using `AccountInfo`
*/
case class ScanMailboxArgs(
// the docspell user account
account: AccountId,
// the configured imap connection
imapConnection: Ident,
// scan folders recursively
scanRecursively: Option[Boolean],
// what folders to search
folders: List[String],
// only select mails received since then
receivedSince: Option[Duration],
// move submitted mails to another folder
targetFolder: Option[String],
// delete the after submitting (only if targetFolder is None)
deleteMail: Boolean,
// set the direction when submitting
direction: Option[Direction],
// set a folder for items
itemFolder: Option[Ident],
// set a filter for files when importing archives
fileFilter: Option[Glob],
// set a list of tags to apply to new item
tags: Option[List[String]],
// a glob filter for the mail subject
subjectFilter: Option[Glob],
// the language for extraction and analysis
language: Option[Language],
// apply additional filter to all mails or only imported
postHandleAll: Option[Boolean],
// Exclude the mail body when importing
attachmentsOnly: Option[Boolean]
)
object ScanMailboxArgs {
val taskName = Ident.unsafe("scan-mailbox")
implicit val jsonEncoder: Encoder[ScanMailboxArgs] =
deriveEncoder[ScanMailboxArgs]
implicit val jsonDecoder: Decoder[ScanMailboxArgs] =
deriveDecoder[ScanMailboxArgs]
def parse(str: String): Either[Throwable, ScanMailboxArgs] =
str.parseJsonAs[ScanMailboxArgs]
}

View File

@ -30,12 +30,12 @@ object RFolder {
def newFolder[F[_]: Sync](
name: String,
collective: CollectiveId,
user: Ident
ownerUserId: Ident
): F[RFolder] =
for {
nId <- Ident.randomId[F]
now <- Timestamp.current[F]
} yield RFolder(nId, name, collective, user, now)
} yield RFolder(nId, name, collective, ownerUserId, now)
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "folder"