Update state and proposals only on invalid items

Invalid items are those that are not ready, and not shown to the user.
When changing metadata, it should only be changed, if the item was not
already shown to the user.
This commit is contained in:
Eike Kettner 2020-05-23 15:46:24 +02:00
parent 855d4eefa8
commit 25d089da6c
6 changed files with 48 additions and 23 deletions

View File

@ -1,11 +1,18 @@
package docspell.common package docspell.common
import io.circe.{Decoder, Encoder} import io.circe.{Decoder, Encoder}
import cats.data.NonEmptyList
sealed trait ItemState { self: Product => sealed trait ItemState { self: Product =>
final def name: String = final def name: String =
productPrefix.toLowerCase productPrefix.toLowerCase
def isValid: Boolean =
ItemState.validStates.exists(_ == this)
def isInvalid: Boolean =
ItemState.invalidStates.exists(_ == this)
} }
object ItemState { object ItemState {
@ -24,8 +31,11 @@ object ItemState {
case _ => Left(s"Invalid item state: $str") case _ => Left(s"Invalid item state: $str")
} }
val validStates: Seq[ItemState] = val validStates: NonEmptyList[ItemState] =
Seq(Created, Confirmed) NonEmptyList.of(Created, Confirmed)
val invalidStates: NonEmptyList[ItemState] =
NonEmptyList.of(Premature, Processing)
def unsafe(str: String): ItemState = def unsafe(str: String): ItemState =
fromString(str).fold(sys.error, identity) fromString(str).fold(sys.error, identity)

View File

@ -71,7 +71,7 @@ object NotifyDueItemsTask {
QItem.Query QItem.Query
.empty(ctx.args.account.collective) .empty(ctx.args.account.collective)
.copy( .copy(
states = ItemState.validStates, states = ItemState.validStates.toList,
tagsInclude = ctx.args.tagsInclude, tagsInclude = ctx.args.tagsInclude,
tagsExclude = ctx.args.tagsExclude, tagsExclude = ctx.args.tagsExclude,
dueDateFrom = ctx.args.daysBack.map(back => now - Duration.days(back.toLong)), dueDateFrom = ctx.args.daysBack.map(back => now - Duration.days(back.toLong)),

View File

@ -25,7 +25,11 @@ object ItemHandler {
def itemStateTask[F[_]: Sync, A]( def itemStateTask[F[_]: Sync, A](
state: ItemState state: ItemState
)(data: ItemData): Task[F, A, ItemData] = )(data: ItemData): Task[F, A, ItemData] =
Task(ctx => ctx.store.transact(RItem.updateState(data.item.id, state)).map(_ => data)) Task(ctx =>
ctx.store
.transact(RItem.updateState(data.item.id, state, ItemState.invalidStates))
.map(_ => data)
)
def isLastRetry[F[_]: Sync, A](ctx: Context[F, A]): F[Boolean] = def isLastRetry[F[_]: Sync, A](ctx: Context[F, A]): F[Boolean] =
for { for {

View File

@ -9,6 +9,11 @@ import docspell.store.records.RItem
object LinkProposal { object LinkProposal {
def apply[F[_]: Sync](data: ItemData): Task[F, ProcessItemArgs, ItemData] = def apply[F[_]: Sync](data: ItemData): Task[F, ProcessItemArgs, ItemData] =
if (data.item.state.isValid)
Task
.log[F, ProcessItemArgs](_.debug(s"Not linking proposals on existing item"))
.map(_ => data)
else
Task { ctx => Task { ctx =>
// sort by weight; order of equal weights is not important, just // sort by weight; order of equal weights is not important, just
// choose one others are then suggestions // choose one others are then suggestions
@ -40,8 +45,9 @@ object LinkProposal {
Result.single(mpt) Result.single(mpt)
) )
case Some(a) => case Some(a) =>
val ids = a.values.map(_.ref.id.id)
ctx.logger.info( ctx.logger.info(
s"Found many (${a.size}, ${a.values.map(_.ref.id.id)}) candidates for ${a.proposalType}. Setting first." s"Found many (${a.size}, ${ids}) candidates for ${a.proposalType}. Setting first."
) *> ) *>
setItemMeta(data.item.id, ctx, a.proposalType, a.values.head.ref.id).map(_ => setItemMeta(data.item.id, ctx, a.proposalType, a.values.head.ref.id).map(_ =>
Result.multiple(mpt) Result.multiple(mpt)

View File

@ -109,7 +109,7 @@ trait Conversions {
coll, coll,
m.name, m.name,
if (m.inbox) Seq(ItemState.Created) if (m.inbox) Seq(ItemState.Created)
else ItemState.validStates, else ItemState.validStates.toList,
m.direction, m.direction,
m.corrPerson, m.corrPerson,
m.corrOrg, m.corrOrg,

View File

@ -1,7 +1,8 @@
package docspell.store.records package docspell.store.records
import cats.implicits._ import cats.data.NonEmptyList
import cats.effect.Sync import cats.effect.Sync
import cats.implicits._
import doobie._ import doobie._
import doobie.implicits._ import doobie.implicits._
import docspell.common._ import docspell.common._
@ -110,12 +111,16 @@ object RItem {
def getCollective(itemId: Ident): ConnectionIO[Option[Ident]] = def getCollective(itemId: Ident): ConnectionIO[Option[Ident]] =
selectSimple(List(cid), table, id.is(itemId)).query[Ident].option selectSimple(List(cid), table, id.is(itemId)).query[Ident].option
def updateState(itemId: Ident, itemState: ItemState): ConnectionIO[Int] = def updateState(
itemId: Ident,
itemState: ItemState,
existing: NonEmptyList[ItemState]
): ConnectionIO[Int] =
for { for {
t <- currentTime t <- currentTime
n <- updateRow( n <- updateRow(
table, table,
id.is(itemId), and(id.is(itemId), state.isIn(existing)),
commas(state.setTo(itemState), updated.setTo(t)) commas(state.setTo(itemState), updated.setTo(t))
).update.run ).update.run
} yield n } yield n