Skip to content

Commit

Permalink
#1383 Use custom fields order from case template in case creation
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Jul 15, 2020
1 parent 6378c06 commit 25128c0
Show file tree
Hide file tree
Showing 11 changed files with 40 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class ActionOperationSrv @Inject() (
case AddCustomFields(name, _, value) =>
for {
c <- relatedCase.fold[Try[Case with Entity]](Failure(InternalError("Unable to apply action AddCustomFields without case")))(Success(_))
_ <- caseSrv.setOrCreateCustomField(c, name, Some(value))
_ <- caseSrv.setOrCreateCustomField(c, name, Some(value), None)
} yield updateOperation(operation)

case CloseTask() =>
Expand Down
26 changes: 13 additions & 13 deletions dto/src/main/scala/org/thp/thehive/dto/v1/CustomFieldValue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ object OutputCustomField {
implicit val format: OFormat[OutputCustomField] = Json.format[OutputCustomField]
}

case class InputCustomFieldValue(name: String, value: Option[Any])
case class InputCustomFieldValue(name: String, value: Option[Any], order: Option[Int])

object InputCustomFieldValue {

Expand All @@ -29,11 +29,11 @@ object InputCustomFieldValue {
fields
.toSeq
.validatedBy {
case (name, FString(value)) => Good(InputCustomFieldValue(name, Some(value)))
case (name, FNumber(value)) => Good(InputCustomFieldValue(name, Some(value)))
case (name, FBoolean(value)) => Good(InputCustomFieldValue(name, Some(value)))
case (name, FAny(value :: _)) => Good(InputCustomFieldValue(name, Some(value)))
case (name, FNull) => Good(InputCustomFieldValue(name, None))
case (name, FString(value)) => Good(InputCustomFieldValue(name, Some(value), None))
case (name, FNumber(value)) => Good(InputCustomFieldValue(name, Some(value), None))
case (name, FBoolean(value)) => Good(InputCustomFieldValue(name, Some(value), None))
case (name, FAny(value :: _)) => Good(InputCustomFieldValue(name, Some(value), None))
case (name, FNull) => Good(InputCustomFieldValue(name, None, None))
case (name, other) =>
Bad(
One(
Expand All @@ -46,13 +46,13 @@ object InputCustomFieldValue {
}
implicit val writes: Writes[Seq[InputCustomFieldValue]] = Writes[Seq[InputCustomFieldValue]] { icfv =>
val fields = icfv.map {
case InputCustomFieldValue(name, Some(s: String)) => name -> JsString(s)
case InputCustomFieldValue(name, Some(l: Long)) => name -> JsNumber(l)
case InputCustomFieldValue(name, Some(d: Double)) => name -> JsNumber(d)
case InputCustomFieldValue(name, Some(b: Boolean)) => name -> JsBoolean(b)
case InputCustomFieldValue(name, Some(d: Date)) => name -> JsNumber(d.getTime)
case InputCustomFieldValue(name, None) => name -> JsNull
case InputCustomFieldValue(name, other) => sys.error(s"The custom field $name has invalid value: $other (${other.getClass})")
case InputCustomFieldValue(name, Some(s: String), _) => name -> JsString(s)
case InputCustomFieldValue(name, Some(l: Long), _) => name -> JsNumber(l)
case InputCustomFieldValue(name, Some(d: Double), _) => name -> JsNumber(d)
case InputCustomFieldValue(name, Some(b: Boolean), _) => name -> JsBoolean(b)
case InputCustomFieldValue(name, Some(d: Date), _) => name -> JsNumber(d.getTime)
case InputCustomFieldValue(name, None, _) => name -> JsNull
case InputCustomFieldValue(name, other, _) => sys.error(s"The custom field $name has invalid value: $other (${other.getClass})")
}
JsObject(fields)
}
Expand Down
2 changes: 1 addition & 1 deletion thehive/app/org/thp/thehive/controllers/v0/CaseCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class CaseCtrl @Inject() (
val caseTemplateName: Option[String] = request.body("caseTemplate")
val inputCase: InputCase = request.body("case")
val inputTasks: Seq[InputTask] = request.body("tasks")
val customFields = inputCase.customFields.map(c => c.name -> c.value).toMap
val customFields = inputCase.customFields.map(c => (c.name, c.value, c.order))
for {
organisation <- userSrv
.current
Expand Down
4 changes: 2 additions & 2 deletions thehive/app/org/thp/thehive/controllers/v0/Properties.scala
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,12 @@ class Properties @Inject() (
for {
// v <- UniMapping.jsonNative.toGraphOpt(value).fold[Try[Any]](???)(Success.apply)
c <- caseSrv.getOrFail(vertex)(graph)
_ <- caseSrv.setOrCreateCustomField(c, name, Some(value))(graph, authContext)
_ <- caseSrv.setOrCreateCustomField(c, name, Some(value), None)(graph, authContext)
} yield Json.obj(s"customField.$name" -> value)
case (FPathElem(_, FPathEmpty), values: JsObject, vertex, _, graph, authContext) =>
for {
c <- caseSrv.get(vertex)(graph).getOrFail("Case")
cfv <- values.fields.toTry { case (n, v) => customFieldSrv.getOrFail(n)(graph).map(_ -> v) }
cfv <- values.fields.toTry { case (n, v) => customFieldSrv.getOrFail(n)(graph).map(cf => (cf, v, None)) }
_ <- caseSrv.updateCustomField(c, cfv)(graph, authContext)
} yield Json.obj("customFields" -> values)
case _ => Failure(BadRequestError("Invalid custom fields format"))
Expand Down
2 changes: 1 addition & 1 deletion thehive/app/org/thp/thehive/controllers/v1/CaseCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class CaseCtrl @Inject() (
val inputTasks: Seq[InputTask] = request.body("tasks")
for {
caseTemplate <- caseTemplateName.map(caseTemplateSrv.get(_).visible.richCaseTemplate.getOrFail("CaseTemplate")).flip
customFields = inputCase.customFieldValue.map(cf => cf.name -> cf.value).toMap
customFields = inputCase.customFieldValue.map(cf => (cf.name, cf.value, cf.order))
organisation <- userSrv.current.organisations(Permissions.manageCase).get(request.organisation).getOrFail("Organisation")
user <- inputCase.user.fold[Try[Option[User with Entity]]](Success(None))(u => userSrv.getOrFail(u).map(Some.apply))
tags <- inputCase.tags.toTry(tagSrv.getOrCreate)
Expand Down
2 changes: 1 addition & 1 deletion thehive/app/org/thp/thehive/services/AlertSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ class AlertSrv @Inject() (
.caseTemplate
.map(caseTemplateSrv.get(_).richCaseTemplate.getOrFail())
.flip
customField = alert.customFields.map(f => f.name -> f.value).toMap
customField = alert.customFields.map(f => (f.name, f.value, f.order))
case0 = Case(
number = 0,
title = caseTemplate.flatMap(_.titlePrefix).getOrElse("") + alert.title,
Expand Down
19 changes: 10 additions & 9 deletions thehive/app/org/thp/thehive/services/CaseSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class CaseSrv @Inject() (
user: Option[User with Entity],
organisation: Organisation with Entity,
tags: Set[Tag with Entity],
customFields: Map[String, Option[Any]],
customFields: Seq[(String, Option[Any], Option[Int])],
caseTemplate: Option[RichCaseTemplate],
additionalTasks: Seq[(Task, Option[User with Entity])]
)(implicit graph: Graph, authContext: AuthContext): Try[RichCase] =
Expand All @@ -73,8 +73,8 @@ class CaseSrv @Inject() (
_ <- createdTasks.toTry(t => shareSrv.shareTask(t, createdCase, organisation))
caseTemplateCustomFields = caseTemplate
.fold[Seq[RichCustomField]](Nil)(_.customFields)
.map(cf => cf.name -> cf.value)
cfs <- (caseTemplateCustomFields.toMap ++ customFields).toTry { case (name, value) => createCustomField(createdCase, name, value) }
.map(cf => (cf.name, cf.value, cf.order))
cfs <- (caseTemplateCustomFields ++ customFields).toTry { case (name, value, order) => createCustomField(createdCase, name, value, order) }
caseTemplateTags = caseTemplate.fold[Seq[Tag with Entity]](Nil)(_.tags)
allTags = tags ++ caseTemplateTags
_ <- allTags.toTry(t => caseTagSrv.create(CaseTag(), createdCase, t))
Expand Down Expand Up @@ -190,7 +190,7 @@ class CaseSrv @Inject() (

def updateCustomField(
`case`: Case with Entity,
customFieldValues: Seq[(CustomField, Any)]
customFieldValues: Seq[(CustomField, Any, Option[Int])]
)(implicit graph: Graph, authContext: AuthContext): Try[Unit] = {
val customFieldNames = customFieldValues.map(_._1.name)
get(`case`)
Expand All @@ -200,29 +200,30 @@ class CaseSrv @Inject() (
.filterNot(rcf => customFieldNames.contains(rcf.name))
.foreach(rcf => get(`case`).customFields(rcf.name).remove())
customFieldValues
.toTry { case (cf, v) => setOrCreateCustomField(`case`, cf.name, Some(v)) }
.toTry { case (cf, v, o) => setOrCreateCustomField(`case`, cf.name, Some(v), o) }
.map(_ => ())
}

def setOrCreateCustomField(`case`: Case with Entity, customFieldName: String, value: Option[Any])(
def setOrCreateCustomField(`case`: Case with Entity, customFieldName: String, value: Option[Any], order: Option[Int])(
implicit graph: Graph,
authContext: AuthContext
): Try[Unit] = {
val cfv = get(`case`).customFields(customFieldName)
if (cfv.newInstance().exists())
cfv.setValue(value)
else
createCustomField(`case`, customFieldName, value).map(_ => ())
createCustomField(`case`, customFieldName, value, order).map(_ => ())
}

def createCustomField(
`case`: Case with Entity,
customFieldName: String,
customFieldValue: Option[Any]
customFieldValue: Option[Any],
order: Option[Int]
)(implicit graph: Graph, authContext: AuthContext): Try[RichCustomField] =
for {
cf <- customFieldSrv.getOrFail(customFieldName)
ccf <- CustomFieldType.map(cf.`type`).setValue(CaseCustomField(), customFieldValue)
ccf <- CustomFieldType.map(cf.`type`).setValue(CaseCustomField(), customFieldValue).map(_.order_=(order))
ccfe <- caseCustomFieldSrv.create(ccf, `case`, cf)
} yield RichCustomField(cf, ccfe)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class AuditCtrlTest extends PlaySpecification with TestAppBuilder {
None,
app[OrganisationSrv].getOrFail("admin").get,
Set.empty,
Map.empty,
Seq.empty,
None,
Nil
)(graph, authContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class StreamCtrlTest extends PlaySpecification with TestAppBuilder {
None,
app[OrganisationSrv].getOrFail("cert").get,
Set.empty,
Map.empty,
Seq.empty,
None,
Nil
)
Expand Down
2 changes: 1 addition & 1 deletion thehive/test/org/thp/thehive/services/AuditSrvTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class AuditSrvTest extends PlaySpecification with TestAppBuilder {
None,
orgAdmin,
Set.empty,
Map.empty,
Seq.empty,
None,
Nil
)
Expand Down
16 changes: 8 additions & 8 deletions thehive/test/org/thp/thehive/services/CaseSrvTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,15 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {
"add custom field with wrong type" in testApp { app =>
app[Database].transaction { implicit graph =>
app[CaseSrv].getOrFail("#3") must beSuccessfulTry.which { `case`: Case with Entity =>
app[CaseSrv].setOrCreateCustomField(`case`, "boolean1", Some("plop")) must beFailedTry
app[CaseSrv].setOrCreateCustomField(`case`, "boolean1", Some("plop"), None) must beFailedTry
}
}
}

"add custom field" in testApp { app =>
app[Database].transaction { implicit graph =>
app[CaseSrv].getOrFail("#3") must beSuccessfulTry.which { `case`: Case with Entity =>
app[CaseSrv].setOrCreateCustomField(`case`, "boolean1", Some(true)) must beSuccessfulTry
app[CaseSrv].setOrCreateCustomField(`case`, "boolean1", Some(true), None) must beSuccessfulTry
app[CaseSrv].getCustomField(`case`, "boolean1").flatMap(_.value) must beSome.which(_ == true)
}
}
Expand All @@ -186,7 +186,7 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {
"update custom field" in testApp { app =>
app[Database].transaction { implicit graph =>
app[CaseSrv].getOrFail("#3") must beSuccessfulTry.which { `case`: Case with Entity =>
app[CaseSrv].setOrCreateCustomField(`case`, "boolean1", Some(false)) must beSuccessfulTry
app[CaseSrv].setOrCreateCustomField(`case`, "boolean1", Some(false), None) must beSuccessfulTry
app[CaseSrv].getCustomField(`case`, "boolean1").flatMap(_.value) must beSome.which(_ == false)
}
}
Expand Down Expand Up @@ -242,7 +242,7 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {
None,
app[OrganisationSrv].getOrFail("cert").get,
app[TagSrv].initSteps.toList.toSet,
Map.empty,
Seq.empty,
None,
Nil
)
Expand Down Expand Up @@ -299,7 +299,7 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {
None,
app[OrganisationSrv].getOrFail("cert").get,
Set[Tag with Entity](),
Map.empty,
Seq.empty,
None,
Nil
)
Expand All @@ -321,7 +321,7 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {
None,
app[OrganisationSrv].getOrFail("cert").get,
app[TagSrv].initSteps.toList.toSet,
Map.empty,
Seq.empty,
None,
Nil
)
Expand All @@ -344,7 +344,7 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {
None,
app[OrganisationSrv].getOrFail("cert").get,
app[TagSrv].initSteps.toList.toSet,
Map.empty,
Seq.empty,
None,
Nil
)
Expand All @@ -367,7 +367,7 @@ class CaseSrvTest extends PlaySpecification with TestAppBuilder {
Some(app[UserSrv].get("[email protected]").getOrFail().get),
app[OrganisationSrv].getOrFail("cert").get,
app[TagSrv].initSteps.toList.toSet,
Map.empty,
Seq.empty,
None,
Nil
)
Expand Down

0 comments on commit 25128c0

Please sign in to comment.