From b673829ec1ba8514e66941439a3196a83a0087d4 Mon Sep 17 00:00:00 2001 From: Youri K Date: Tue, 9 Oct 2018 13:06:45 +0200 Subject: [PATCH] backend conversion route for tracings to hybrid (#3324) * create a make-hybrid route which lets you turn any non-hybrid tracing into a hybrid tracing #3288 * implement pr feedback #3324 --- app/controllers/AnnotationController.scala | 12 ++++ app/models/annotation/Annotation.scala | 6 ++ app/models/annotation/AnnotationService.scala | 61 +++++++++++++------ conf/messages | 5 ++ conf/webknossos.routes | 1 + 5 files changed, 65 insertions(+), 20 deletions(-) diff --git a/app/controllers/AnnotationController.scala b/app/controllers/AnnotationController.scala index 3e1c358d9b6..b997489902b 100755 --- a/app/controllers/AnnotationController.scala +++ b/app/controllers/AnnotationController.scala @@ -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" diff --git a/app/models/annotation/Annotation.scala b/app/models/annotation/Annotation.scala index 0d5da1e2176..51c1b44c246 100755 --- a/app/models/annotation/Annotation.scala +++ b/app/models/annotation/Annotation.scala @@ -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) diff --git a/app/models/annotation/AnnotationService.scala b/app/models/annotation/AnnotationService.scala index 7fbf9018282..ada1275981d 100755 --- a/app/models/annotation/AnnotationService.scala +++ b/app/models/annotation/AnnotationService.scala @@ -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, @@ -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] = { diff --git a/conf/messages b/conf/messages index 99a94f39310..f93a8b26327 100644 --- a/conf/messages +++ b/conf/messages @@ -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 @@ -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 diff --git a/conf/webknossos.routes b/conf/webknossos.routes index daa99784b11..65cecde40cc 100644 --- a/conf/webknossos.routes +++ b/conf/webknossos.routes @@ -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)