mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-04-04 10:29:34 +00:00
Allow to start a user task once
This commit is contained in:
parent
af5b62c057
commit
bbfd694b45
@ -54,7 +54,7 @@ object BackendApp {
|
||||
jobImpl <- OJob(store, joexImpl)
|
||||
itemImpl <- OItem(store)
|
||||
mailImpl <- OMail(store, JavaMailEmil(blocker))
|
||||
userTaskImpl <- OUserTask(utStore, joexImpl)
|
||||
userTaskImpl <- OUserTask(utStore, queue, joexImpl)
|
||||
} yield new BackendApp[F] {
|
||||
val login: Login[F] = loginImpl
|
||||
val signup: OSignup[F] = signupImpl
|
||||
|
@ -2,26 +2,54 @@ package docspell.backend.ops
|
||||
|
||||
import cats.implicits._
|
||||
import cats.effect._
|
||||
import com.github.eikek.calev.CalEvent
|
||||
import io.circe.Encoder
|
||||
import docspell.store.queue.JobQueue
|
||||
import docspell.store.usertask._
|
||||
import docspell.common._
|
||||
import com.github.eikek.calev.CalEvent
|
||||
|
||||
trait OUserTask[F[_]] {
|
||||
|
||||
/** Return the settings for the notify-due-items task of the current
|
||||
* user. There is at most one such task per user.
|
||||
*/
|
||||
def getNotifyDueItems(account: AccountId): F[UserTask[NotifyDueItemsArgs]]
|
||||
|
||||
/** Updates the notify-due-items tasks and notifies the joex nodes.
|
||||
*/
|
||||
def submitNotifyDueItems(
|
||||
account: AccountId,
|
||||
task: UserTask[NotifyDueItemsArgs]
|
||||
): F[Unit]
|
||||
|
||||
/** Discards the schedule and immediately submits the task to the job
|
||||
* executor's queue. It will not update the corresponding periodic
|
||||
* task.
|
||||
*/
|
||||
def executeNow[A](account: AccountId, task: UserTask[A])(
|
||||
implicit E: Encoder[A]
|
||||
): F[Unit]
|
||||
}
|
||||
|
||||
object OUserTask {
|
||||
|
||||
def apply[F[_]: Effect](store: UserTaskStore[F], joex: OJoex[F]): Resource[F, OUserTask[F]] =
|
||||
def apply[F[_]: Effect](
|
||||
store: UserTaskStore[F],
|
||||
queue: JobQueue[F],
|
||||
joex: OJoex[F]
|
||||
): Resource[F, OUserTask[F]] =
|
||||
Resource.pure[F, OUserTask[F]](new OUserTask[F] {
|
||||
|
||||
def executeNow[A](account: AccountId, task: UserTask[A])(
|
||||
implicit E: Encoder[A]
|
||||
): F[Unit] =
|
||||
for {
|
||||
ptask <- task.encode.toPeriodicTask(account)
|
||||
job <- ptask.toJob
|
||||
_ <- queue.insert(job)
|
||||
_ <- joex.notifyAllNodes
|
||||
} yield ()
|
||||
|
||||
def getNotifyDueItems(account: AccountId): F[UserTask[NotifyDueItemsArgs]] =
|
||||
store
|
||||
.getOneByName[NotifyDueItemsArgs](account, NotifyDueItemsArgs.taskName)
|
||||
|
@ -1583,7 +1583,7 @@ paths:
|
||||
$ref: "#/components/schemas/CalEventCheckResult"
|
||||
/sec/usertask/notifydueitems:
|
||||
get:
|
||||
tags: [ Notification ]
|
||||
tags: [ User Tasks ]
|
||||
summary: Get settings for "Notify Due Items" task
|
||||
description: |
|
||||
Return the current notification settings of the authenticated
|
||||
@ -1599,7 +1599,7 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/NotificationSettings"
|
||||
post:
|
||||
tags: [ Notification ]
|
||||
tags: [ User Tasks ]
|
||||
summary: Change current settings for "Notify Due Items" task
|
||||
description: |
|
||||
Change the current notification settings of the authenticated
|
||||
@ -1618,6 +1618,27 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BasicResult"
|
||||
/sec/usertask/notifydueitems/startonce:
|
||||
post:
|
||||
tags: [ User Tasks ]
|
||||
summary: Start the "Notify Due Items" task once
|
||||
description: |
|
||||
Starts the notify-due-items task just once, discarding the
|
||||
schedule and not updating the periodic task.
|
||||
security:
|
||||
- authTokenHeader: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/NotificationSettings"
|
||||
responses:
|
||||
200:
|
||||
description: Ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BasicResult"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
|
@ -22,6 +22,17 @@ object NotifyDueItemsRoutes {
|
||||
import dsl._
|
||||
|
||||
HttpRoutes.of {
|
||||
case req @ POST -> Root / "startonce" =>
|
||||
for {
|
||||
data <- req.as[NotificationSettings]
|
||||
task = makeTask(user.account, data)
|
||||
res <- ut
|
||||
.executeNow(user.account, task)
|
||||
.attempt
|
||||
.map(Conversions.basicResult(_, "Submitted successfully."))
|
||||
resp <- Ok(res)
|
||||
} yield resp
|
||||
|
||||
case GET -> Root =>
|
||||
for {
|
||||
task <- ut.getNotifyDueItems(user.account)
|
||||
@ -36,7 +47,7 @@ object NotifyDueItemsRoutes {
|
||||
res <- ut
|
||||
.submitNotifyDueItems(user.account, task)
|
||||
.attempt
|
||||
.map(Conversions.basicResult(_, "Update ok."))
|
||||
.map(Conversions.basicResult(_, "Saved successfully."))
|
||||
resp <- Ok(res)
|
||||
} yield resp
|
||||
}
|
||||
@ -61,7 +72,6 @@ object NotifyDueItemsRoutes {
|
||||
)
|
||||
)
|
||||
|
||||
// TODO this should be inside the backend code and not here
|
||||
def taskToSettings[F[_]: Sync](
|
||||
account: AccountId,
|
||||
backend: BackendApp[F],
|
||||
|
@ -33,13 +33,13 @@ object QUserTask {
|
||||
|
||||
def insert(account: AccountId, task: UserTask[String]): ConnectionIO[Int] =
|
||||
for {
|
||||
r <- makePeriodicTask(account, task)
|
||||
r <- task.toPeriodicTask[ConnectionIO](account)
|
||||
n <- RPeriodicTask.insert(r)
|
||||
} yield n
|
||||
|
||||
def update(account: AccountId, task: UserTask[String]): ConnectionIO[Int] =
|
||||
for {
|
||||
r <- makePeriodicTask(account, task)
|
||||
r <- task.toPeriodicTask[ConnectionIO](account)
|
||||
n <- RPeriodicTask.update(r)
|
||||
} yield n
|
||||
|
||||
@ -69,21 +69,4 @@ object QUserTask {
|
||||
def makeUserTask(r: RPeriodicTask): UserTask[String] =
|
||||
UserTask(r.id, r.task, r.enabled, r.timer, r.args)
|
||||
|
||||
def makePeriodicTask(
|
||||
account: AccountId,
|
||||
t: UserTask[String]
|
||||
): ConnectionIO[RPeriodicTask] =
|
||||
RPeriodicTask
|
||||
.create[ConnectionIO](
|
||||
t.enabled,
|
||||
t.name,
|
||||
account.collective,
|
||||
t.args,
|
||||
s"${account.user.id}: ${t.name.id}",
|
||||
account.user,
|
||||
Priority.Low,
|
||||
t.timer
|
||||
)
|
||||
.map(r => r.copy(id = t.id))
|
||||
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ trait PeriodicTaskStore[F[_]] {
|
||||
*/
|
||||
def add(task: RPeriodicTask): F[AddResult]
|
||||
|
||||
/** Find all joex nodes as registered in the database.
|
||||
*/
|
||||
def findJoexNodes: F[Vector[RNode]]
|
||||
}
|
||||
|
||||
|
@ -1,33 +1,53 @@
|
||||
package docspell.store.usertask
|
||||
|
||||
import cats.effect._
|
||||
import cats.implicits._
|
||||
import com.github.eikek.calev.CalEvent
|
||||
import io.circe.Decoder
|
||||
import io.circe.Encoder
|
||||
|
||||
import docspell.common._
|
||||
import docspell.common.syntax.all._
|
||||
import docspell.store.records.RPeriodicTask
|
||||
|
||||
case class UserTask[A](
|
||||
id: Ident,
|
||||
name: Ident,
|
||||
enabled: Boolean,
|
||||
timer: CalEvent,
|
||||
args: A
|
||||
id: Ident,
|
||||
name: Ident,
|
||||
enabled: Boolean,
|
||||
timer: CalEvent,
|
||||
args: A
|
||||
) {
|
||||
|
||||
def encode(implicit E: Encoder[A]): UserTask[String] =
|
||||
copy(args = E(args).noSpaces)
|
||||
|
||||
}
|
||||
|
||||
object UserTask {
|
||||
|
||||
|
||||
implicit final class UserTaskCodec(ut: UserTask[String]) {
|
||||
|
||||
def decode[A](implicit D: Decoder[A]): Either[String, UserTask[A]] =
|
||||
ut.args.parseJsonAs[A]
|
||||
.left.map(_.getMessage)
|
||||
ut.args
|
||||
.parseJsonAs[A]
|
||||
.left
|
||||
.map(_.getMessage)
|
||||
.map(a => ut.copy(args = a))
|
||||
|
||||
def toPeriodicTask[F[_]: Sync](
|
||||
account: AccountId
|
||||
): F[RPeriodicTask] =
|
||||
RPeriodicTask
|
||||
.create[F](
|
||||
ut.enabled,
|
||||
ut.name,
|
||||
account.collective,
|
||||
ut.args,
|
||||
s"${account.user.id}: ${ut.name.id}",
|
||||
account.user,
|
||||
Priority.Low,
|
||||
ut.timer
|
||||
)
|
||||
.map(r => r.copy(id = ut.id))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ module Api exposing
|
||||
, setItemNotes
|
||||
, setTags
|
||||
, setUnconfirmed
|
||||
, startOnceNotifyDueItems
|
||||
, submitNotifyDueItems
|
||||
, upload
|
||||
, uploadSingle
|
||||
@ -123,6 +124,20 @@ import Util.Http as Http2
|
||||
--- NotifyDueItems
|
||||
|
||||
|
||||
startOnceNotifyDueItems :
|
||||
Flags
|
||||
-> NotificationSettings
|
||||
-> (Result Http.Error BasicResult -> msg)
|
||||
-> Cmd msg
|
||||
startOnceNotifyDueItems flags settings receive =
|
||||
Http2.authPost
|
||||
{ url = flags.config.baseUrl ++ "/api/v1/sec/usertask/notifydueitems/startonce"
|
||||
, account = getAccount flags
|
||||
, body = Http.jsonBody (Api.Model.NotificationSettings.encode settings)
|
||||
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
|
||||
}
|
||||
|
||||
|
||||
submitNotifyDueItems :
|
||||
Flags
|
||||
-> NotificationSettings
|
||||
|
@ -59,6 +59,7 @@ type Msg
|
||||
| CalEventMsg Comp.CalEventInput.Msg
|
||||
| SetNotificationSettings (Result Http.Error NotificationSettings)
|
||||
| SubmitResp (Result Http.Error BasicResult)
|
||||
| StartOnce
|
||||
|
||||
|
||||
initCmd : Flags -> Cmd Msg
|
||||
@ -149,6 +150,27 @@ makeSettings model =
|
||||
model.schedule
|
||||
|
||||
|
||||
withValidSettings : (NotificationSettings -> Cmd Msg) -> Model -> ( Model, Cmd Msg )
|
||||
withValidSettings mkcmd model =
|
||||
case makeSettings model of
|
||||
Valid set ->
|
||||
( { model | formMsg = Nothing }
|
||||
, mkcmd set
|
||||
)
|
||||
|
||||
Invalid errs _ ->
|
||||
let
|
||||
errMsg =
|
||||
String.join ", " errs
|
||||
in
|
||||
( { model | formMsg = Just (BasicResult False errMsg) }, Cmd.none )
|
||||
|
||||
Unknown _ ->
|
||||
( { model | formMsg = Just (BasicResult False "An unknown error occured") }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update flags msg model =
|
||||
case msg of
|
||||
@ -341,23 +363,14 @@ update flags msg model =
|
||||
)
|
||||
|
||||
Submit ->
|
||||
case makeSettings model of
|
||||
Valid set ->
|
||||
( { model | formMsg = Nothing }
|
||||
, Api.submitNotifyDueItems flags set SubmitResp
|
||||
)
|
||||
withValidSettings
|
||||
(\set -> Api.submitNotifyDueItems flags set SubmitResp)
|
||||
model
|
||||
|
||||
Invalid errs _ ->
|
||||
let
|
||||
errMsg =
|
||||
String.join ", " errs
|
||||
in
|
||||
( { model | formMsg = Just (BasicResult False errMsg) }, Cmd.none )
|
||||
|
||||
Unknown _ ->
|
||||
( { model | formMsg = Just (BasicResult False "An unknown error occured") }
|
||||
, Cmd.none
|
||||
)
|
||||
StartOnce ->
|
||||
withValidSettings
|
||||
(\set -> Api.startOnceNotifyDueItems flags set SubmitResp)
|
||||
model
|
||||
|
||||
SubmitResp (Ok res) ->
|
||||
( { model | formMsg = Just res }
|
||||
@ -484,18 +497,28 @@ view extraClasses model =
|
||||
]
|
||||
]
|
||||
, div [ class "ui divider" ] []
|
||||
, div [ class "ui error message" ]
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui message", True )
|
||||
, ( "success", isFormSuccess model )
|
||||
, ( "error", isFormError model )
|
||||
, ( "hidden", model.formMsg == Nothing )
|
||||
]
|
||||
]
|
||||
[ Maybe.map .message model.formMsg
|
||||
|> Maybe.withDefault ""
|
||||
|> text
|
||||
]
|
||||
, div [ class "ui success message" ]
|
||||
[ text "Successfully saved."
|
||||
]
|
||||
, button
|
||||
[ class "ui primary button"
|
||||
, onClick Submit
|
||||
]
|
||||
[ text "Submit"
|
||||
]
|
||||
, button
|
||||
[ class "ui right floated button"
|
||||
, onClick StartOnce
|
||||
]
|
||||
[ text "Start Once"
|
||||
]
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user