Skip to content

Commit

Permalink
backend conversion route for tracings to hybrid (#3324)
Browse files Browse the repository at this point in the history
* create a make-hybrid route which lets you turn any non-hybrid tracing into a hybrid tracing #3288

* implement pr feedback #3324
  • Loading branch information
youri-k authored and fm3 committed Oct 9, 2018
1 parent 851a435 commit b673829
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 20 deletions.
12 changes: 12 additions & 0 deletions app/controllers/AnnotationController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ class AnnotationController @Inject()(annotationDAO: AnnotationDAO,
}
}

def makeHybrid(typ: String, id: String) = sil.SecuredAction.async { implicit request =>
for {
_ <- bool2Fox(AnnotationType.Explorational.toString == typ) ?~> "annotation.makeHybrid.explorationalsOnly"
annotation <- provider.provideAnnotation(typ, id, request.identity)
_ <- annotationService.makeAnnotationHybrid(request.identity, annotation) ?~> "annotation.makeHybrid.failed"
updated <- provider.provideAnnotation(typ, id, request.identity)
json <- annotationService.publicWrites(updated, Some(request.identity)) ?~> "annotation.write.failed"
} yield {
JsonOk(json)
}
}

private def finishAnnotation(typ: String, id: String, issuingUser: User)(implicit ctx: DBAccessContext): Fox[(Annotation, String)] = {
for {
annotation <- provider.provideAnnotation(typ, id, issuingUser) ?~> "annotation.notFound"
Expand Down
6 changes: 6 additions & 0 deletions app/models/annotation/Annotation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,12 @@ class AnnotationDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContex
_ <- run(sqlu"update webknossos.annotations set skeletonTracingId = ${newSkeletonTracingId} where _id = ${id.id}")
} yield ()

def updateVolumeTracingId(id: ObjectId, newVolumeTracingId: String)(implicit ctx: DBAccessContext): Fox[Unit] =
for {
_ <- assertUpdateAccess(id)
_ <- run(sqlu"update webknossos.annotations set volumeTracingId = ${newVolumeTracingId} where _id = ${id.id}")
} yield ()

def updateStatistics(id: ObjectId, statistics: JsObject)(implicit ctx: DBAccessContext): Fox[Unit] =
for {
_ <- assertUpdateAccess(id)
Expand Down
61 changes: 41 additions & 20 deletions app/models/annotation/AnnotationService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,35 +97,35 @@ class AnnotationService @Inject()(annotationInformationProvider: AnnotationInfor
)
}

def createTracings(dataSet: DataSet, dataSource: DataSource, tracingType: TracingType.Value, withFallback: Boolean)(implicit ctx: DBAccessContext): Fox[(Option[String], Option[String])] = tracingType match {
case TracingType.skeleton =>
for {
handler <- dataSetService.handlerFor(dataSet)
skeletonTracingId <- handler.saveSkeletonTracing(SkeletonTracingDefaults.createInstance.copy(dataSetName = dataSet.name, editPosition = dataSource.center))
} yield (Some(skeletonTracingId), None)
case TracingType.volume =>
for {
handler <- dataSetService.handlerFor(dataSet)
volumeTracingId <- handler.saveVolumeTracing(createVolumeTracing(dataSource, withFallback))
} yield (None, Some(volumeTracingId))
case TracingType.hybrid =>
for {
handler <- dataSetService.handlerFor(dataSet)
skeletonTracingId <- handler.saveSkeletonTracing(SkeletonTracingDefaults.createInstance.copy(dataSetName = dataSet.name, editPosition = dataSource.center))
volumeTracingId <- handler.saveVolumeTracing(createVolumeTracing(dataSource, withFallback))
} yield (Some(skeletonTracingId), Some(volumeTracingId))
}

def createExplorationalFor(
user: User,
_dataSet: ObjectId,
tracingType: TracingType.Value,
withFallback: Boolean)(implicit ctx: DBAccessContext): Fox[Annotation] = {

def createTracings(dataSet: DataSet, dataSource: DataSource): Fox[(Option[String], Option[String])] = tracingType match {
case TracingType.skeleton =>
for {
handler <- dataSetService.handlerFor(dataSet)
skeletonTracingId <- handler.saveSkeletonTracing(SkeletonTracingDefaults.createInstance.copy(dataSetName = dataSet.name, editPosition = dataSource.center))
} yield (Some(skeletonTracingId), None)
case TracingType.volume =>
for {
handler <- dataSetService.handlerFor(dataSet)
volumeTracingId <- handler.saveVolumeTracing(createVolumeTracing(dataSource, withFallback))
} yield (None, Some(volumeTracingId))
case TracingType.hybrid =>
for {
handler <- dataSetService.handlerFor(dataSet)
skeletonTracingId <- handler.saveSkeletonTracing(SkeletonTracingDefaults.createInstance.copy(dataSetName = dataSet.name, editPosition = dataSource.center))
volumeTracingId <- handler.saveVolumeTracing(createVolumeTracing(dataSource, withFallback))
} yield (Some(skeletonTracingId), Some(volumeTracingId))
}
for {
dataSet <- dataSetDAO.findOne(_dataSet)
dataSource <- dataSetService.dataSourceFor(dataSet)
usableDataSource <- dataSource.toUsable ?~> "DataSet is not imported."
tracingIds <- createTracings(dataSet, usableDataSource)
tracingIds <- createTracings(dataSet, usableDataSource, tracingType, withFallback)
teamId <- selectSuitableTeam(user, dataSet)
annotation = Annotation(
ObjectId.generate,
Expand All @@ -142,6 +142,27 @@ class AnnotationService @Inject()(annotationInformationProvider: AnnotationInfor
}
}

def makeAnnotationHybrid(user: User, annotation: Annotation)(implicit ctx: DBAccessContext) = {
def createNewTracings(dataSet: DataSet, dataSource: DataSource) = annotation.tracingType match {
case TracingType.skeleton => createTracings(dataSet, dataSource, TracingType.volume, false).flatMap {
case (_, Some(volumeId)) => annotationDAO.updateVolumeTracingId(annotation._id, volumeId)
case _ => Fox.failure("unexpectedReturn")
}
case TracingType.volume => createTracings(dataSet, dataSource, TracingType.skeleton, false).flatMap {
case (Some(skeletonId), _) => annotationDAO.updateSkeletonTracingId(annotation._id, skeletonId)
case _ => Fox.failure("unexpectedReturn")
}
case _ => Fox.failure("annotation.makeHybrid.alreadyHybrid")
}

for {
dataSet <- dataSetDAO.findOne(annotation._dataSet)
dataSource <- dataSetService.dataSourceFor(dataSet).flatMap(_.toUsable)
_ <- createNewTracings(dataSet, dataSource)
} yield ()

}

// WARNING: needs to be repeatable, might be called multiple times for an annotation
def finish(annotation: Annotation, user: User, restrictions: AnnotationRestrictions)(implicit ctx: DBAccessContext): Fox[String] = {
def executeFinish: Fox[String] = {
Expand Down
5 changes: 5 additions & 0 deletions conf/messages
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ annotation.transferee.noDataSetAccess=Cannot transfer annotation to a user who h
annotation.timelogging.read.failed=Time
annotation.write.failed=Could not convert annotation to json
annotation.noSkeleton=No skeleton tracing found for this annotation
annotation.makeHybrid.explorationalsOnly=Could not convert annotation to hybrid annotation because it is only allowed for explorational annotations.
annotation.makeHybrid.failed=Could not convert to hybrid.
annotation.makeHybrid.alreadyHybrid=Could not convert annotation to hybrid annotation because it is already a hybrid annotation.

task.create.success=Task successfully created
task.create.failed=Failed to create Task
Expand Down Expand Up @@ -215,3 +218,5 @@ serialization.failed=Failed to serialize data.

initialData.notEnabled=Initial Data Insertion is not enabled in the configuration of this wK instance
initialData.organizationsNotEmpty=There are already organizations present in the database. Please refresh the db schema and try again

unexpectedReturn=Unexpected return of parameters
1 change: 1 addition & 0 deletions conf/webknossos.routes
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ GET /api/annotations/:typ/:id/revert
POST /api/annotations/:typ/:id/transfer controllers.AnnotationController.transfer(typ: String, id: String)

GET /api/annotations/:typ/:id/info controllers.AnnotationController.info(typ: String, id: String)
PATCH /api/annotations/:typ/:id/makeHybrid controllers.AnnotationController.makeHybrid(typ: String, id: String)
DELETE /api/annotations/:typ/:id controllers.AnnotationController.cancel(typ: String, id: String)
GET /api/annotations/:typ/:id/merge/:mergedTyp/:mergedId controllers.AnnotationController.merge(typ: String, id: String, mergedTyp: String, mergedId: String)
GET /api/annotations/:typ/:id/download controllers.AnnotationIOController.download(typ: String, id: String)
Expand Down

0 comments on commit b673829

Please sign in to comment.