Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/main/scala/com/particeep/api/ControlCapability.scala

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seul la méthode audit doit retourner un EventControl

Les autres méthodes : create / update / updateBlock / publish devrait retourner l'entité modifiée donc un control ou un ControlView

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Toutes les méthodes que tu cites retournent un EventControl.

Pour les méthodes que tu cites, si je veux respecter ta volonté, ma seule solution serait d'appeler byids pour chaque méthode. On aurait un truc comme ça :

  def update(id: String, timeout: Long = defaultTimeOut, control_update: ControlUpdate)(implicit exec: ExecutionContext): Future[Either[ErrorResult, ControlView]] = {
    for {
      _ <- ws.post[JsValue](s"$endPoint/$id", timeout, Json.toJson(control_update))
      controls <- this.byIds(id, timeout)
    } yield {
      val new_control: Either[ErrorResult, Option[ControlView]] = controls.map(_.find(_.id == id))
      new_control match {
        case Left(errors)         => Left(errors)
        case Right(Some(control)) => Right(control)
        case Right(None)          => Left(Errors(hasError = true, errors = List(Error(technicalCode = "control.not.found", message = "control.not.found"))))
      }
    }
  }

Pourquoi je dis que cela est impossible : je ne peux pas créer un contrôle ou un ContrôleView dynamiquement à partir des données de retour de mes appels à particeep API car particeep API me retourne à chaque fois un EventControl. Et EventControl retourne le delta entre les attributs modifiés et je ne peux pas par exemple déduire la valeur "assigned_to" dans updateBlock. La seule exception est la méthode create qui retourne le contrôle en entier dans le payload de EventControl.

Avec tout ça, que souhaites-tu que je fasse ? Ce que je t'ai dit via mon code ou as-tu une autre idée ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tu imagines trop compliqué

Il faut simplement changer les méthodes de l'API pour retourner un objet et pas un event

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Driox Qu'entends-tu par objet ?

Tu veux que Particeep API retourne un contrôle pour chaque méthode que tu as citées ? En conséquence changer ControlController ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oui c'est ca

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Driox Entendu, je vais créer le code nécessaire.

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.particeep.api

import com.particeep.api.core.{ ApiCredential, EntityClient, WSClient, WithCredentials, WithWS }
import com.particeep.api.models.{ ErrorResult, PaginatedSequence, TableSearch }
import com.particeep.api.models.control.{ Control, ControlBlockUpdate, ControlCreation, ControlUpdate, ControlView, ControlViewSearchCriteria, EventControl }
import com.particeep.api.utils.LangUtils
import play.api.libs.json.{ JsNull, Json }

import scala.concurrent.{ ExecutionContext, Future }

trait ControlCapability {
self: WSClient =>

val control = new ControlClient(this)

def control(credentials: ApiCredential): ControlClient = new ControlClient(this, Some(credentials))
}

object ControlClient {
private val endPoint: String = "/control"
}

class ControlClient(val ws: WSClient, val credentials: Option[ApiCredential] = None) extends WithWS
with WithCredentials
with EntityClient {

import ControlClient._

def byIds(ids: String, timeout: Long = defaultTimeOut)(implicit exec: ExecutionContext): Future[Either[ErrorResult, List[ControlView]]] = {
ws.get[List[ControlView]](s"$endPoint/", timeout, List("ids" -> ids))
}

def audit(id: String, entity_type: String, timeout: Long = defaultTimeOut)(implicit exec: ExecutionContext): Future[Either[ErrorResult, List[EventControl]]] = {
ws.get[List[EventControl]](s"$endPoint/$entity_type/$id/audit", timeout)
}

def create(user_id: String, timeout: Long = defaultTimeOut, control_creation: ControlCreation)(implicit exec: ExecutionContext): Future[Either[ErrorResult, Control]] = {
ws.put[Control](s"$endPoint/assign_to/$user_id", timeout, Json.toJson(control_creation))
}

def update(id: String, timeout: Long = defaultTimeOut, control_update: ControlUpdate)(implicit exec: ExecutionContext): Future[Either[ErrorResult, Control]] = {
ws.post[Control](s"$endPoint/$id", timeout, Json.toJson(control_update))
}

def updateBlock(
id: String,
block_id: String,
timeout: Long = defaultTimeOut,
control_block_update: ControlBlockUpdate
)(implicit exec: ExecutionContext): Future[Either[ErrorResult, Control]] = {
ws.post[Control](s"$endPoint/$id/block/$block_id", timeout, Json.toJson(control_block_update))
}

def publish(id: String, timeout: Long = defaultTimeOut)(implicit exec: ExecutionContext): Future[Either[ErrorResult, Control]] = {
ws.post[Control](s"$endPoint/$id/publish", timeout, JsNull)
}

def search(
criteria: ControlViewSearchCriteria,
table_criteria: TableSearch,
timeout: Long = defaultTimeOut
)(implicit exec: ExecutionContext): Future[Either[ErrorResult, PaginatedSequence[ControlView]]] = {
val params_query = LangUtils.productToQueryString(criteria) ++ LangUtils.productToQueryString(table_criteria)
ws.get[PaginatedSequence[ControlView]](s"$endPoint/search", timeout, params_query)
}
}
3 changes: 2 additions & 1 deletion src/main/scala/com/particeep/api/ParticeepApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ object ParticeepApi {
with WalletCapability
with WalletSepaCapability
with WebHookCapability
with PhoneMessagingCapability {
with PhoneMessagingCapability
with ControlCapability {
self: WSClient =>
}

Expand Down
24 changes: 24 additions & 0 deletions src/main/scala/com/particeep/api/models/control/Control.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.particeep.api.models.control

import com.particeep.api.models.enums.ControlStatus
import play.api.libs.json.{ JsObject, Json, OFormat }

import java.time.OffsetDateTime

final case class Control(
id: String,
created_at: OffsetDateTime,
created_by: String,
assigned_to: String,
level: Int,
target_id: String,
target_type: String,
target_entity: JsObject,
blocks: List[ControlBlock],
status: ControlStatus,
comment: Option[String]
)

object Control {
implicit val controlFormat: OFormat[Control] = Json.format[Control]
}
18 changes: 18 additions & 0 deletions src/main/scala/com/particeep/api/models/control/ControlBlock.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.particeep.api.models.control

import com.particeep.api.models.enums.{ ControlBlockStatus, ControlBlockType }
import play.api.libs.json.{ Json, OFormat }

final case class ControlBlock(
id: String,
block_type: ControlBlockType,
path: String,
status: ControlBlockStatus,
target_id: Option[String],
comment: Option[String],
doc_ids: Seq[String]
)

object ControlBlock {
implicit val control_block_format: OFormat[ControlBlock] = Json.format[ControlBlock]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.particeep.api.models.control

import com.particeep.api.models.enums.ControlBlockStatus
import play.api.libs.json.{ Json, OFormat }

final case class ControlBlockUpdate(
doc_ids: Seq[String],
status: Option[ControlBlockStatus],
comment: Option[String]
)

object ControlBlockUpdate {
implicit val control_block_update_format: OFormat[ControlBlockUpdate] = Json.format[ControlBlockUpdate]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.particeep.api.models.control

import play.api.libs.json.{ JsObject, Json, OFormat }

final case class ControlCreation(
target_id: String,
target_type: String,
target_entity: JsObject
)

object ControlCreation {
implicit val control_creation_format: OFormat[ControlCreation] = Json.format[ControlCreation]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.particeep.api.models.control

import play.api.libs.json.{ Json, OFormat }

final case class ControlUpdate(
comment: Option[String] = None
)

object ControlUpdate {
implicit val control_update_format: OFormat[ControlUpdate] = Json.format[ControlUpdate]
}
35 changes: 35 additions & 0 deletions src/main/scala/com/particeep/api/models/control/ControlView.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.particeep.api.models.control

import com.particeep.api.models.enums.ControlStatus
import play.api.libs.json.{ Json, OFormat }

import java.time.OffsetDateTime

final case class ControlView(
id: String,
created_at: OffsetDateTime,
updated_at: OffsetDateTime,
deleted_at: Option[OffsetDateTime],
created_by: String,
assigned_to: String,
level: Int,
target_id: String,
target_type: String,
blocks: List[ControlBlock],
status: ControlStatus,
comment: Option[String]
)

object ControlView {
implicit val control_view_format: OFormat[ControlView] = Json.format[ControlView]
}

final case class ControlViewSearchCriteria(
created_after: Option[OffsetDateTime],
created_before: Option[OffsetDateTime],
level: Option[Int],
target_id: Option[String],
target_type: Option[String],
status: Option[ControlStatus],
ids: Option[String]
)
17 changes: 17 additions & 0 deletions src/main/scala/com/particeep/api/models/control/EventControl.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.particeep.api.models.control

import play.api.libs.json.{ JsValue, Json, OFormat }

final case class EventControl(
id: String,
name: String,
created_at: Long,
created_by: String,
entity_id: String,
payload: JsValue,
tags: Set[String]
)

object EventControl {
implicit val eventFormat: OFormat[EventControl] = Json.format[EventControl]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.particeep.api.models.enums

sealed trait ControlBlockStatus extends Product with Serializable with Enum

object ControlBlockStatus extends EnumHelper[ControlBlockStatus] {

case object ONGOING extends ControlBlockStatus { val name: String = "ONGOING" }
case object VALIDATED extends ControlBlockStatus { val name: String = "VALIDATED" }
case object REJECTED extends ControlBlockStatus { val name: String = "REJECTED" }

val values: Set[ControlBlockStatus] = Set(ONGOING, VALIDATED, REJECTED)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.particeep.api.models.enums

import play.api.libs.json._

trait ControlBlockType extends Product with Serializable with Enum

object ControlBlockType {

private[this] def enumReads: Reads[ControlBlockType] = new Reads[ControlBlockType] {
def reads(json: JsValue): JsResult[ControlBlockType] = {
json
.validate[ControlControlBlockType]
.orElse(json.validate[TransactionControlBlockType])
.orElse(JsError(s"Can't parse json into ControlBlockType, no implementation found for $json"))
}
}

private[this] def enumWrites: Writes[ControlBlockType] = new Writes[ControlBlockType] {
def writes(v: ControlBlockType): JsValue = v match {
case blockType: ControlControlBlockType => Json.toJson(blockType)
case blockType: TransactionControlBlockType => Json.toJson(blockType)
case _ => throw new IllegalStateException(s"Can't serialize case class to json, no implementation found for $v")
}
}

implicit val controlBlockTypeFormat: Format[ControlBlockType] = Format(enumReads, enumWrites)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.particeep.api.models.enums

sealed trait ControlControlBlockType extends ControlBlockType

object ControlControlBlockType extends EnumHelper[ControlControlBlockType] {
case object COMMENT extends ControlControlBlockType { val name: String = "COMMENT" }

override def values: Set[ControlControlBlockType] = Set(COMMENT)
}
13 changes: 13 additions & 0 deletions src/main/scala/com/particeep/api/models/enums/ControlStatus.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.particeep.api.models.enums

sealed trait ControlStatus extends Product with Serializable with Enum

object ControlStatus extends EnumHelper[ControlStatus] {

case object ONGOING extends ControlStatus { val name: String = "ONGOING" }
case object VALIDATED extends ControlStatus { val name: String = "VALIDATED" }
case object REJECTED extends ControlStatus { val name: String = "REJECTED" }
case object SUCCEED extends ControlStatus { val name: String = "SUCCEED" }

val values: Set[ControlStatus] = Set(ONGOING, VALIDATED, REJECTED, SUCCEED)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.particeep.api.models.enums

sealed trait TransactionControlBlockType extends ControlBlockType

object TransactionControlBlockType extends EnumHelper[TransactionControlBlockType] {

case object INVESTOR extends TransactionControlBlockType { val name: String = "INVESTOR" }
case object CO_ISSUER extends TransactionControlBlockType { val name: String = "CO_ISSUER" }
case object PARTNER extends TransactionControlBlockType { val name: String = "PARTNER" }
case object USUFRUCTUARY extends TransactionControlBlockType { val name: String = "USUFRUCTUARY" }
case object BANK_ACCOUNT extends TransactionControlBlockType { val name: String = "BANK_ACCOUNT" }
case object TRANSACTION extends TransactionControlBlockType { val name: String = "TRANSACTION" }
case object DOCUMENTS extends TransactionControlBlockType { val name: String = "DOCUMENTS" }
case object QUESTION extends TransactionControlBlockType { val name: String = "QUESTION" }

val values: Set[TransactionControlBlockType] = {
Set(
INVESTOR,
CO_ISSUER,
PARTNER,
USUFRUCTUARY,
BANK_ACCOUNT,
TRANSACTION,
DOCUMENTS,
QUESTION
)
}

}