diff --git a/dto/src/main/scala/org/thp/thehive/dto/v1/Task.scala b/dto/src/main/scala/org/thp/thehive/dto/v1/Task.scala index 936d78fc74..f86f2fe42d 100644 --- a/dto/src/main/scala/org/thp/thehive/dto/v1/Task.scala +++ b/dto/src/main/scala/org/thp/thehive/dto/v1/Task.scala @@ -34,6 +34,7 @@ case class OutputTask( flag: Boolean, startDate: Option[Date], endDate: Option[Date], + assignee: Option[String], order: Int, dueDate: Option[Date] ) diff --git a/thehive/app/org/thp/thehive/controllers/v0/Conversion.scala b/thehive/app/org/thp/thehive/controllers/v0/Conversion.scala index 8053b9c525..8ea6715368 100644 --- a/thehive/app/org/thp/thehive/controllers/v0/Conversion.scala +++ b/thehive/app/org/thp/thehive/controllers/v0/Conversion.scala @@ -531,7 +531,7 @@ object Conversion { .withFieldComputed(_.status, _.status.toString) .withFieldConst(_._type, "case_task") .withFieldConst(_.`case`, None) - .withFieldComputed(_.owner, _.owner.map(_.login)) + .withFieldComputed(_.owner, _.assignee.map(_.login)) .withFieldRenamed(_._updatedAt, _.updatedAt) .withFieldRenamed(_._updatedBy, _.updatedBy) .withFieldRenamed(_._createdAt, _.createdAt) @@ -548,7 +548,7 @@ object Conversion { .withFieldComputed(_.status, _.status.toString) .withFieldConst(_._type, "case_task") .withFieldConst(_.`case`, richCase.map(_.toValue)) - .withFieldComputed(_.owner, _.owner.map(_.login)) + .withFieldComputed(_.owner, _.assignee.map(_.login)) .withFieldRenamed(_._updatedAt, _.updatedAt) .withFieldRenamed(_._updatedBy, _.updatedBy) .withFieldRenamed(_._createdAt, _.createdAt) diff --git a/thehive/app/org/thp/thehive/controllers/v0/Properties.scala b/thehive/app/org/thp/thehive/controllers/v0/Properties.scala index 81edf13ca0..88f0fab85f 100644 --- a/thehive/app/org/thp/thehive/controllers/v0/Properties.scala +++ b/thehive/app/org/thp/thehive/controllers/v0/Properties.scala @@ -395,7 +395,7 @@ class Properties @Inject() ( .property("dueDate", UniMapping.date.optional)(_.field.updatable) .property("group", UniMapping.string)(_.field.updatable) .property("owner", UniMapping.string.optional)( - _.select(_.user.login) + _.select(_.assignee.login) .custom { (_, login: Option[String], vertex, _, graph, authContext) => for { task <- taskSrv.get(vertex)(graph).getOrFail("Task") diff --git a/thehive/app/org/thp/thehive/controllers/v1/Conversion.scala b/thehive/app/org/thp/thehive/controllers/v1/Conversion.scala index 0047ef1c51..43aeb4709b 100644 --- a/thehive/app/org/thp/thehive/controllers/v1/Conversion.scala +++ b/thehive/app/org/thp/thehive/controllers/v1/Conversion.scala @@ -201,6 +201,7 @@ object Conversion { _.into[OutputTask] .withFieldConst(_._type, "Task") .withFieldComputed(_.status, _.status.toString) + .withFieldComputed(_.assignee, _.assignee.map(_.login)) .transform ) diff --git a/thehive/app/org/thp/thehive/controllers/v1/Properties.scala b/thehive/app/org/thp/thehive/controllers/v1/Properties.scala index 3ef274dfad..7279fddd73 100644 --- a/thehive/app/org/thp/thehive/controllers/v1/Properties.scala +++ b/thehive/app/org/thp/thehive/controllers/v1/Properties.scala @@ -20,6 +20,7 @@ import org.thp.thehive.services.{ ObservableSteps, OrganisationSteps, ProfileSteps, + TaskSrv, TaskSteps, UserSrv, UserSteps @@ -33,6 +34,7 @@ import scala.util.Failure class Properties @Inject() ( alertSrv: AlertSrv, caseSrv: CaseSrv, + taskSrv: TaskSrv, userSrv: UserSrv, caseTemplateSrv: CaseTemplateSrv, observableSrv: ObservableSrv @@ -202,6 +204,21 @@ class Properties @Inject() ( .property("endDate", UniMapping.date.optional)(_.field.updatable) .property("order", UniMapping.int)(_.field.updatable) .property("dueDate", UniMapping.date.optional)(_.field.updatable) + .property("assignee", UniMapping.string.optional)(_.select(_.assignee.login).custom { + case (_, value, vertex, _, graph, authContext) => + taskSrv + .get(vertex)(graph) + .getOrFail("Task") + .flatMap { task => + value.fold(taskSrv.unassign(task)(graph, authContext)) { user => + userSrv + .get(user)(graph) + .getOrFail("User") + .flatMap(taskSrv.assign(task, _)(graph, authContext)) + } + } + .map(_ => Json.obj("assignee" -> value)) + }) .build lazy val user: List[PublicProperty[_, _]] = diff --git a/thehive/app/org/thp/thehive/models/Task.scala b/thehive/app/org/thp/thehive/models/Task.scala index b16dda48a6..11c4cd3e7f 100644 --- a/thehive/app/org/thp/thehive/models/Task.scala +++ b/thehive/app/org/thp/thehive/models/Task.scala @@ -33,7 +33,7 @@ case class Task( case class RichTask( task: Task with Entity, - owner: Option[User with Entity] + assignee: Option[User with Entity] ) { def _id: String = task._id def _createdBy: String = task._createdBy diff --git a/thehive/app/org/thp/thehive/services/CaseSrv.scala b/thehive/app/org/thp/thehive/services/CaseSrv.scala index ebd64b3e45..2605baf1f0 100644 --- a/thehive/app/org/thp/thehive/services/CaseSrv.scala +++ b/thehive/app/org/thp/thehive/services/CaseSrv.scala @@ -67,7 +67,7 @@ class CaseSrv @Inject() ( _ <- caseUserSrv.create(CaseUser(), createdCase, assignee) _ <- shareSrv.shareCase(owner = true, createdCase, organisation, profileSrv.orgAdmin) _ <- caseTemplate.map(ct => caseCaseTemplateSrv.create(CaseCaseTemplate(), createdCase, ct.caseTemplate)).flip - createdTasks <- caseTemplate.fold(additionalTasks)(_.tasks.map(t => t.task -> t.owner)).toTry { + createdTasks <- caseTemplate.fold(additionalTasks)(_.tasks.map(t => t.task -> t.assignee)).toTry { case (task, owner) => taskSrv.create(task, owner) } _ <- createdTasks.toTry(t => shareSrv.shareTask(t, createdCase, organisation)) diff --git a/thehive/app/org/thp/thehive/services/TaskSrv.scala b/thehive/app/org/thp/thehive/services/TaskSrv.scala index d92eaeb884..e59f9311ad 100644 --- a/thehive/app/org/thp/thehive/services/TaskSrv.scala +++ b/thehive/app/org/thp/thehive/services/TaskSrv.scala @@ -83,7 +83,7 @@ class TaskSrv @Inject() (caseSrvProvider: Provider[CaseSrv], auditSrv: AuditSrv, case TaskStatus.InProgress => for { - _ <- get(t).user.headOption().fold(assign(t, o))(_ => Success(())) + _ <- get(t).assignee.headOption().fold(assign(t, o))(_ => Success(())) updated <- t.startDate.fold(get(t).updateOne("status" -> s, "startDate" -> Some(new Date())))(_ => setStatus()) } yield updated @@ -133,7 +133,7 @@ class TaskSteps(raw: GremlinScala[Vertex])(implicit @Named("with-thehive-schema" def logs = new LogSteps(raw.outTo[TaskLog]) - def user = new UserSteps(raw.outTo[TaskUser]) + def assignee = new UserSteps(raw.outTo[TaskUser]) def organisations = new OrganisationSteps(raw.inTo[ShareTask].inTo[OrganisationShare]) def organisations(permission: Permission) = diff --git a/thehive/app/org/thp/thehive/services/notification/triggers/LogInMyTask.scala b/thehive/app/org/thp/thehive/services/notification/triggers/LogInMyTask.scala index c5ec085d32..7771f6dc95 100644 --- a/thehive/app/org/thp/thehive/services/notification/triggers/LogInMyTask.scala +++ b/thehive/app/org/thp/thehive/services/notification/triggers/LogInMyTask.scala @@ -32,5 +32,5 @@ class LogInMyTask(logSrv: LogSrv) extends Trigger { audit.objectId.fold(false)(taskAssignee(_).fold(false)(_ == u.login)) } - def taskAssignee(logId: String)(implicit graph: Graph): Option[String] = logSrv.getByIds(logId).task.user.login.headOption() + def taskAssignee(logId: String)(implicit graph: Graph): Option[String] = logSrv.getByIds(logId).task.assignee.login.headOption() } diff --git a/thehive/app/org/thp/thehive/services/notification/triggers/TaskAssigned.scala b/thehive/app/org/thp/thehive/services/notification/triggers/TaskAssigned.scala index c39378dd7d..8e4c49f042 100644 --- a/thehive/app/org/thp/thehive/services/notification/triggers/TaskAssigned.scala +++ b/thehive/app/org/thp/thehive/services/notification/triggers/TaskAssigned.scala @@ -32,5 +32,5 @@ class TaskAssigned(taskSrv: TaskSrv) extends Trigger { } def taskAssignee(taskId: String, login: String)(implicit graph: Graph): Option[User with Entity] = - taskSrv.getByIds(taskId).user.has("login", login).headOption() + taskSrv.getByIds(taskId).assignee.has("login", login).headOption() }