diff --git a/app/controllers/AiModelController.scala b/app/controllers/AiModelController.scala index b25a39f3b2..8f3911374e 100644 --- a/app/controllers/AiModelController.scala +++ b/app/controllers/AiModelController.scala @@ -86,23 +86,21 @@ class AiModelController @Inject()( extends Controller with FoxImplicits { - def readAiModelInfo(aiModelId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def readAiModelInfo(aiModelId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => { for { _ <- userService.assertIsSuperUser(request.identity) - aiModelIdValidated <- ObjectId.fromString(aiModelId) - aiModel <- aiModelDAO.findOne(aiModelIdValidated) ?~> "aiModel.notFound" ~> NOT_FOUND + aiModel <- aiModelDAO.findOne(aiModelId) ?~> "aiModel.notFound" ~> NOT_FOUND jsResult <- aiModelService.publicWrites(aiModel) } yield Ok(jsResult) } } - def readAiInferenceInfo(aiInferenceId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def readAiInferenceInfo(aiInferenceId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => { for { _ <- userService.assertIsSuperUser(request.identity) - aiInferenceIdValidated <- ObjectId.fromString(aiInferenceId) - aiInference <- aiInferenceDAO.findOne(aiInferenceIdValidated) ?~> "aiInference.notFound" ~> NOT_FOUND + aiInference <- aiInferenceDAO.findOne(aiInferenceId) ?~> "aiInference.notFound" ~> NOT_FOUND jsResult <- aiInferenceService.publicWrites(aiInference, request.identity) } yield Ok(jsResult) } @@ -213,15 +211,14 @@ class AiModelController @Inject()( } yield Ok(newAiModelJs) } - def updateAiModelInfo(aiModelId: String): Action[UpdateAiModelParameters] = + def updateAiModelInfo(aiModelId: ObjectId): Action[UpdateAiModelParameters] = sil.SecuredAction.async(validateJson[UpdateAiModelParameters]) { implicit request => for { _ <- userService.assertIsSuperUser(request.identity) - aiModelIdValidated <- ObjectId.fromString(aiModelId) - aiModel <- aiModelDAO.findOne(aiModelIdValidated) ?~> "aiModel.notFound" ~> NOT_FOUND + aiModel <- aiModelDAO.findOne(aiModelId) ?~> "aiModel.notFound" ~> NOT_FOUND _ <- aiModelDAO.updateOne( aiModel.copy(name = request.body.name, comment = request.body.comment, modified = Instant.now)) - updatedAiModel <- aiModelDAO.findOne(aiModelIdValidated) ?~> "aiModel.notFound" ~> NOT_FOUND + updatedAiModel <- aiModelDAO.findOne(aiModelId) ?~> "aiModel.notFound" ~> NOT_FOUND jsResult <- aiModelService.publicWrites(updatedAiModel) } yield Ok(jsResult) } @@ -248,15 +245,14 @@ class AiModelController @Inject()( } yield Ok } - def deleteAiModel(aiModelId: String): Action[AnyContent] = + def deleteAiModel(aiModelId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- userService.assertIsSuperUser(request.identity) - aiModelIdValidated <- ObjectId.fromString(aiModelId) - referencesCount <- aiInferenceDAO.countForModel(aiModelIdValidated) + referencesCount <- aiInferenceDAO.countForModel(aiModelId) _ <- bool2Fox(referencesCount == 0) ?~> "aiModel.delete.referencedByInferences" - _ <- aiModelDAO.findOne(aiModelIdValidated) ?~> "aiModel.notFound" ~> NOT_FOUND - _ <- aiModelDAO.deleteOne(aiModelIdValidated) + _ <- aiModelDAO.findOne(aiModelId) ?~> "aiModel.notFound" ~> NOT_FOUND + _ <- aiModelDAO.deleteOne(aiModelId) } yield Ok } diff --git a/app/controllers/AnnotationController.scala b/app/controllers/AnnotationController.scala index a6162e682d..f771191e53 100755 --- a/app/controllers/AnnotationController.scala +++ b/app/controllers/AnnotationController.scala @@ -90,7 +90,7 @@ class AnnotationController @Inject()( def info( // Type of the annotation, one of Task, Explorational, CompoundTask, CompoundProject, CompoundTaskType typ: String, // For Task and Explorational annotations, id is an annotation id. For CompoundTask, id is a task id. For CompoundProject, id is a project id. For CompoundTaskType, id is a task type id - id: String, + id: ObjectId, // Timestamp in milliseconds (time at which the request is sent) timestamp: Long): Action[AnyContent] = sil.UserAwareAction.async { implicit request => log() { @@ -118,7 +118,7 @@ class AnnotationController @Inject()( } } - def infoWithoutType(id: String, + def infoWithoutType(id: ObjectId, // Timestamp in milliseconds (time at which the request is sent timestamp: Long): Action[AnyContent] = sil.UserAwareAction.async { implicit request => log() { @@ -130,7 +130,7 @@ class AnnotationController @Inject()( } } - def merge(typ: String, id: String, mergedTyp: String, mergedId: String): Action[AnyContent] = + def merge(typ: String, id: ObjectId, mergedTyp: String, mergedId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotationA <- provider.provideAnnotation(typ, id, request.identity) ~> NOT_FOUND @@ -143,7 +143,7 @@ class AnnotationController @Inject()( } yield JsonOk(js, Messages("annotation.merge.success")) } - def mergeWithoutType(id: String, mergedTyp: String, mergedId: String): Action[AnyContent] = + def mergeWithoutType(id: ObjectId, mergedTyp: String, mergedId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(id, request.identity) ~> NOT_FOUND @@ -151,7 +151,7 @@ class AnnotationController @Inject()( } yield result } - def reset(typ: String, id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def reset(typ: String, id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(typ, id, request.identity) ~> NOT_FOUND _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(request.identity, annotation._team)) @@ -161,7 +161,7 @@ class AnnotationController @Inject()( } yield JsonOk(json, Messages("annotation.reset.success")) } - def reopen(typ: String, id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def reopen(typ: String, id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => def isReopenAllowed(user: User, annotation: Annotation) = for { isAdminOrTeamManager <- userService.isTeamManagerOrAdminOf(user, annotation._team) @@ -181,8 +181,8 @@ class AnnotationController @Inject()( } yield JsonOk(json, Messages("annotation.reopened")) } - def editLockedState(typ: String, id: String, isLockedByOwner: Boolean): Action[AnyContent] = sil.SecuredAction.async { - implicit request => + def editLockedState(typ: String, id: ObjectId, isLockedByOwner: Boolean): Action[AnyContent] = + sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(typ, id, request.identity) _ <- bool2Fox(annotation._user == request.identity._id) ?~> "annotation.isLockedByOwner.notAllowed" @@ -193,9 +193,9 @@ class AnnotationController @Inject()( updatedAnnotation <- provider.provideAnnotation(typ, id, request.identity) ~> NOT_FOUND json <- annotationService.publicWrites(updatedAnnotation, Some(request.identity)) ?~> "annotation.write.failed" } yield JsonOk(json, Messages("annotation.isLockedByOwner.success")) - } + } - def addAnnotationLayer(typ: String, id: String): Action[AnnotationLayerParameters] = + def addAnnotationLayer(typ: String, id: ObjectId): Action[AnnotationLayerParameters] = sil.SecuredAction.async(validateJson[AnnotationLayerParameters]) { implicit request => for { _ <- bool2Fox(AnnotationType.Explorational.toString == typ) ?~> "annotation.addLayer.explorationalsOnly" @@ -211,7 +211,7 @@ class AnnotationController @Inject()( } yield JsonOk(json) } - def addAnnotationLayerWithoutType(id: String): Action[AnnotationLayerParameters] = + def addAnnotationLayerWithoutType(id: ObjectId): Action[AnnotationLayerParameters] = sil.SecuredAction.async(validateJson[AnnotationLayerParameters]) { implicit request => for { annotation <- provider.provideAnnotation(id, request.identity) ~> NOT_FOUND @@ -219,7 +219,7 @@ class AnnotationController @Inject()( } yield result } - def deleteAnnotationLayer(typ: String, id: String, layerName: String): Action[AnyContent] = + def deleteAnnotationLayer(typ: String, id: ObjectId, layerName: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- bool2Fox(AnnotationType.Explorational.toString == typ) ?~> "annotation.deleteLayer.explorationalsOnly" @@ -235,7 +235,7 @@ class AnnotationController @Inject()( } yield Ok } - def deleteAnnotationLayerWithoutType(id: String, layerName: String): Action[AnyContent] = + def deleteAnnotationLayerWithoutType(id: ObjectId, layerName: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(id, request.identity) ~> NOT_FOUND @@ -243,11 +243,10 @@ class AnnotationController @Inject()( } yield result } - def createExplorational(datasetId: String): Action[List[AnnotationLayerParameters]] = + def createExplorational(datasetId: ObjectId): Action[List[AnnotationLayerParameters]] = sil.SecuredAction.async(validateJson[List[AnnotationLayerParameters]]) { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetIdValidated) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND annotation <- annotationService.createExplorationalFor( request.identity, dataset._id, @@ -259,12 +258,11 @@ class AnnotationController @Inject()( } yield JsonOk(json) } - def getSandbox(datasetId: String, typ: String, sharingToken: Option[String]): Action[AnyContent] = + def getSandbox(datasetId: ObjectId, typ: String, sharingToken: Option[String]): Action[AnyContent] = sil.UserAwareAction.async { implicit request => val ctx = URLSharing.fallbackTokenAccessContext(sharingToken) // users with dataset sharing token may also get a sandbox annotation for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated)(ctx) ?~> Messages("dataset.notFound", datasetIdValidated) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId)(ctx) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND tracingType <- TracingType.fromString(typ).toFox _ <- bool2Fox(tracingType == TracingType.skeleton) ?~> "annotation.sandbox.skeletonOnly" annotation = Annotation( @@ -283,7 +281,7 @@ class AnnotationController @Inject()( } yield JsonOk(json) } - def makeHybrid(typ: String, id: String, fallbackLayerName: Option[String]): Action[AnyContent] = + def makeHybrid(typ: String, id: ObjectId, fallbackLayerName: Option[String]): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- bool2Fox(AnnotationType.Explorational.toString == typ) ?~> "annotation.addLayer.explorationalsOnly" @@ -297,7 +295,7 @@ class AnnotationController @Inject()( } yield JsonOk(json) } - def makeHybridWithoutType(id: String, fallbackLayerName: Option[String]): Action[AnyContent] = + def makeHybridWithoutType(id: ObjectId, fallbackLayerName: Option[String]): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(id, request.identity) ~> NOT_FOUND @@ -305,7 +303,7 @@ class AnnotationController @Inject()( } yield result } - def downsample(typ: String, id: String, tracingId: String): Action[AnyContent] = sil.SecuredAction.async { + def downsample(typ: String, id: ObjectId, tracingId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- bool2Fox(AnnotationType.Explorational.toString == typ) ?~> "annotation.downsample.explorationalsOnly" @@ -321,7 +319,7 @@ class AnnotationController @Inject()( } yield JsonOk(json) } - def downsampleWithoutType(id: String, tracingId: String): Action[AnyContent] = sil.SecuredAction.async { + def downsampleWithoutType(id: ObjectId, tracingId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(id, request.identity) ~> NOT_FOUND @@ -393,7 +391,7 @@ class AnnotationController @Inject()( f"$value%1.1f %%" } - private def finishAnnotation(typ: String, id: String, issuingUser: User, timestamp: Instant)( + private def finishAnnotation(typ: String, id: ObjectId, issuingUser: User, timestamp: Instant)( implicit ctx: DBAccessContext): Fox[(Annotation, String)] = for { annotation <- provider.provideAnnotation(typ, id, issuingUser) ~> NOT_FOUND @@ -403,7 +401,7 @@ class AnnotationController @Inject()( _ <- timeSpanService.logUserInteractionIfTheyArePotentialContributor(timestamp, issuingUser, annotation) // log time on tracing end } yield (updated, message) - def finish(typ: String, id: String, timestamp: Long): Action[AnyContent] = sil.SecuredAction.async { + def finish(typ: String, id: ObjectId, timestamp: Long): Action[AnyContent] = sil.SecuredAction.async { implicit request => log() { for { @@ -419,7 +417,10 @@ class AnnotationController @Inject()( log() { withJsonAs[JsArray](request.body \ "annotations") { annotationIds => val results = Fox.serialSequence(annotationIds.value.toList) { jsValue => - jsValue.asOpt[String].toFox.flatMap(id => finishAnnotation(typ, id, request.identity, Instant(timestamp))) + jsValue + .asOpt[String] + .toFox + .flatMap(id => finishAnnotation(typ, ObjectId(id), request.identity, Instant(timestamp))) } results.map { _ => @@ -429,7 +430,7 @@ class AnnotationController @Inject()( } } - def editAnnotation(typ: String, id: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { + def editAnnotation(typ: String, id: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => for { annotation <- provider.provideAnnotation(typ, id, request.identity) ~> NOT_FOUND @@ -453,7 +454,7 @@ class AnnotationController @Inject()( } yield JsonOk(Messages("annotation.edit.success")) } - def editAnnotationLayer(typ: String, id: String, tracingId: String): Action[JsValue] = + def editAnnotationLayer(typ: String, id: ObjectId, tracingId: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => for { annotation <- provider.provideAnnotation(typ, id, request.identity) ~> NOT_FOUND @@ -464,11 +465,10 @@ class AnnotationController @Inject()( } yield JsonOk(Messages("annotation.edit.success")) } - def annotationsForTask(taskId: String): Action[AnyContent] = + def annotationsForTask(taskId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - taskIdValidated <- ObjectId.fromString(taskId) - task <- taskDAO.findOne(taskIdValidated) ?~> "task.notFound" ~> NOT_FOUND + task <- taskDAO.findOne(taskId) ?~> "task.notFound" ~> NOT_FOUND project <- projectDAO.findOne(task._project) _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(request.identity, project._team)) annotations <- annotationService.annotationsFor(task._id) ?~> "task.annotation.failed" @@ -476,7 +476,7 @@ class AnnotationController @Inject()( } yield Ok(JsArray(jsons.flatten)) } - def cancel(typ: String, id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def cancel(typ: String, id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => def tryToCancel(annotation: Annotation) = annotation match { case t if t.typ == AnnotationType.Task => @@ -496,14 +496,14 @@ class AnnotationController @Inject()( } yield result } - def cancelWithoutType(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def cancelWithoutType(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(id, request.identity) ~> NOT_FOUND result <- cancel(annotation.typ.toString, id)(request) } yield result } - def transfer(typ: String, id: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => + def transfer(typ: String, id: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => for { restrictions <- provider.restrictionsFor(typ, id) ?~> "restrictions.notFound" ~> NOT_FOUND _ <- restrictions.allowFinish(request.identity) ?~> "notAllowed" ~> FORBIDDEN @@ -514,7 +514,7 @@ class AnnotationController @Inject()( } yield JsonOk(json) } - def duplicate(typ: String, id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def duplicate(typ: String, id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(typ, id, request.identity) ~> NOT_FOUND newAnnotation <- duplicateAnnotation(annotation, request.identity) @@ -553,7 +553,7 @@ class AnnotationController @Inject()( } - def getSharedTeams(typ: String, id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def getSharedTeams(typ: String, id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(typ, id, request.identity) _ <- bool2Fox(annotation._user == request.identity._id) ?~> "notAllowed" ~> FORBIDDEN @@ -562,7 +562,7 @@ class AnnotationController @Inject()( } yield Ok(Json.toJson(json)) } - def updateSharedTeams(typ: String, id: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { + def updateSharedTeams(typ: String, id: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => withJsonBodyAs[List[String]] { teams => for { @@ -576,7 +576,7 @@ class AnnotationController @Inject()( } } - def updateOthersMayEdit(typ: String, id: String, othersMayEdit: Boolean): Action[AnyContent] = + def updateOthersMayEdit(typ: String, id: ObjectId, othersMayEdit: Boolean): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { annotation <- provider.provideAnnotation(typ, id, request.identity) @@ -623,14 +623,13 @@ class AnnotationController @Inject()( } } yield annotationLayer.copy(tracingId = newTracingId) - def tryAcquiringAnnotationMutex(id: String): Action[AnyContent] = + def tryAcquiringAnnotationMutex(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => logTime(slackNotificationService.noticeSlowRequest, durationThreshold = 1 second) { for { - idValidated <- ObjectId.fromString(id) annotation <- provider.provideAnnotation(id, request.identity) ~> NOT_FOUND _ <- bool2Fox(annotation.othersMayEdit) ?~> "notAllowed" ~> FORBIDDEN - restrictions <- provider.restrictionsFor(AnnotationIdentifier(annotation.typ, idValidated)) ?~> "restrictions.notFound" ~> NOT_FOUND + restrictions <- provider.restrictionsFor(AnnotationIdentifier(annotation.typ, id)) ?~> "restrictions.notFound" ~> NOT_FOUND _ <- restrictions.allowUpdate(request.identity) ?~> "notAllowed" ~> FORBIDDEN mutexResult <- annotationMutexService.tryAcquiringAnnotationMutex(annotation._id, request.identity._id) ?~> "annotation.mutex.failed" resultJson <- annotationMutexService.publicWrites(mutexResult) diff --git a/app/controllers/AnnotationIOController.scala b/app/controllers/AnnotationIOController.scala index a587c9d954..77ecc7480c 100755 --- a/app/controllers/AnnotationIOController.scala +++ b/app/controllers/AnnotationIOController.scala @@ -349,7 +349,7 @@ class AnnotationIOController @Inject()( // NML or Zip file containing skeleton and/or volume data of this annotation. In case of Compound annotations, multiple such annotations wrapped in another zip def download(typ: String, - id: String, + id: ObjectId, skeletonVersion: Option[Long], volumeVersion: Option[Long], skipVolumeData: Option[Boolean], @@ -359,7 +359,7 @@ class AnnotationIOController @Inject()( for { identifier <- AnnotationIdentifier.parse(typ, id) volumeDataZipFormatParsed = volumeDataZipFormat.flatMap(VolumeDataZipFormat.fromString) - _ = request.identity.foreach(user => analyticsService.track(DownloadAnnotationEvent(user, id, typ))) + _ = request.identity.foreach(user => analyticsService.track(DownloadAnnotationEvent(user, id.toString, typ))) result <- identifier.annotationType match { case AnnotationType.View => Fox.failure("Cannot download View annotation") case AnnotationType.CompoundProject => downloadProject(id, request.identity, skipVolumeData.getOrElse(false)) @@ -379,7 +379,7 @@ class AnnotationIOController @Inject()( } yield result } - def downloadWithoutType(id: String, + def downloadWithoutType(id: ObjectId, skeletonVersion: Option[Long], volumeVersion: Option[Long], skipVolumeData: Option[Boolean], @@ -396,7 +396,7 @@ class AnnotationIOController @Inject()( } yield result } - private def downloadExplorational(annotationId: String, + private def downloadExplorational(annotationId: ObjectId, typ: String, issuingUser: Option[User], skeletonVersion: Option[Long], @@ -523,15 +523,14 @@ class AnnotationIOController @Inject()( } } - private def downloadProject(projectId: String, userOpt: Option[User], skipVolumeData: Boolean)( + private def downloadProject(projectId: ObjectId, userOpt: Option[User], skipVolumeData: Boolean)( implicit ctx: DBAccessContext, m: MessagesProvider) = for { user <- userOpt.toFox ?~> Messages("notAllowed") ~> FORBIDDEN - projectIdValidated <- ObjectId.fromString(projectId) - project <- projectDAO.findOne(projectIdValidated) ?~> Messages("project.notFound", projectId) ~> NOT_FOUND + project <- projectDAO.findOne(projectId) ?~> Messages("project.notFound", projectId) ~> NOT_FOUND _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(user, project._team)) ?~> "notAllowed" ~> FORBIDDEN - annotations <- annotationDAO.findAllFinishedForProject(projectIdValidated) + annotations <- annotationDAO.findAllFinishedForProject(projectId) zip <- annotationService.zipAnnotations(annotations, project.name, skipVolumeData, @@ -541,7 +540,7 @@ class AnnotationIOController @Inject()( Ok.sendFile(file, inline = false, fileName = _ => Some(TextUtils.normalize(project.name + "_nmls.zip"))) } - private def downloadTask(taskId: String, userOpt: Option[User], skipVolumeData: Boolean)( + private def downloadTask(taskId: ObjectId, userOpt: Option[User], skipVolumeData: Boolean)( implicit ctx: DBAccessContext, m: MessagesProvider) = { def createTaskZip(task: Task): Fox[TemporaryFile] = annotationService.annotationsFor(task._id).flatMap { @@ -553,7 +552,7 @@ class AnnotationIOController @Inject()( for { user <- userOpt.toFox ?~> Messages("notAllowed") ~> FORBIDDEN - task <- taskDAO.findOne(ObjectId(taskId)).toFox ?~> Messages("task.notFound") ~> NOT_FOUND + task <- taskDAO.findOne(taskId).toFox ?~> Messages("task.notFound") ~> NOT_FOUND project <- projectDAO.findOne(task._project) ?~> Messages("project.notFound") ~> NOT_FOUND _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(user, project._team)) ?~> Messages("notAllowed") ~> FORBIDDEN zip <- createTaskZip(task) @@ -563,7 +562,7 @@ class AnnotationIOController @Inject()( } } - private def downloadTaskType(taskTypeId: String, userOpt: Option[User], skipVolumeData: Boolean)( + private def downloadTaskType(taskTypeId: ObjectId, userOpt: Option[User], skipVolumeData: Boolean)( implicit ctx: DBAccessContext, m: MessagesProvider) = { def createTaskTypeZip(taskType: TaskType) = @@ -582,8 +581,7 @@ class AnnotationIOController @Inject()( for { user <- userOpt.toFox ?~> Messages("notAllowed") ~> FORBIDDEN - taskTypeIdValidated <- ObjectId.fromString(taskTypeId) ?~> "taskType.id.invalid" - taskType <- taskTypeDAO.findOne(taskTypeIdValidated) ?~> "taskType.notFound" ~> NOT_FOUND + taskType <- taskTypeDAO.findOne(taskTypeId) ?~> "taskType.notFound" ~> NOT_FOUND _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(user, taskType._team)) ?~> "notAllowed" ~> FORBIDDEN zip <- createTaskTypeZip(taskType) } yield { diff --git a/app/controllers/AnnotationPrivateLinkController.scala b/app/controllers/AnnotationPrivateLinkController.scala index 631a95b4a7..b79efbb224 100644 --- a/app/controllers/AnnotationPrivateLinkController.scala +++ b/app/controllers/AnnotationPrivateLinkController.scala @@ -64,20 +64,17 @@ class AnnotationPrivateLinkController @Inject()( } yield Ok(Json.toJson(linksJsonList)) } - def listByAnnotation(annotationId: String): Action[AnyContent] = + def listByAnnotation(annotationId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - annotationIdValidated <- ObjectId.fromString(annotationId) - links <- annotationPrivateLinkDAO.findAllByAnnotation(annotationIdValidated) + links <- annotationPrivateLinkDAO.findAllByAnnotation(annotationId) linksJsonList <- Fox.serialCombined(links)(annotationPrivateLinkService.publicWrites) } yield Ok(Json.toJson(linksJsonList)) } - def get(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def get(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - idValidated <- ObjectId.fromString(id) - - annotationPrivateLink <- annotationPrivateLinkDAO.findOne(idValidated) + annotationPrivateLink <- annotationPrivateLinkDAO.findOne(id) _ <- bool2Fox(annotationPrivateLink.expirationDateTime.forall(_ > Instant.now)) ?~> "Token expired" ~> NOT_FOUND _ <- annotationDAO.findOne(annotationPrivateLink._annotation) ?~> "annotation.notFound" ~> NOT_FOUND @@ -100,27 +97,25 @@ class AnnotationPrivateLinkController @Inject()( } yield Ok(js) } - def update(id: String): Action[AnnotationPrivateLinkParams] = + def update(id: ObjectId): Action[AnnotationPrivateLinkParams] = sil.SecuredAction.async(validateJson[AnnotationPrivateLinkParams]) { implicit request => val params = request.body for { annotationId <- ObjectId.fromString(params.annotation) - idValidated <- ObjectId.fromString(id) - aPLInfo <- annotationPrivateLinkDAO.findOne(idValidated) ?~> "annotation private link not found" ~> NOT_FOUND + aPLInfo <- annotationPrivateLinkDAO.findOne(id) ?~> "annotation private link not found" ~> NOT_FOUND _ <- annotationDAO.assertUpdateAccess(aPLInfo._annotation) ?~> "notAllowed" ~> FORBIDDEN _ <- annotationDAO.assertUpdateAccess(annotationId) ?~> "notAllowed" ~> FORBIDDEN - _ <- annotationPrivateLinkDAO.updateOne(idValidated, annotationId, params.expirationDateTime) ?~> "update.failed" - updated <- annotationPrivateLinkDAO.findOne(idValidated) ?~> "not Found" + _ <- annotationPrivateLinkDAO.updateOne(id, annotationId, params.expirationDateTime) ?~> "update.failed" + updated <- annotationPrivateLinkDAO.findOne(id) ?~> "not Found" js <- annotationPrivateLinkService.publicWrites(updated) ?~> "write failed" } yield Ok(js) } - def delete(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def delete(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - idValidated <- ObjectId.fromString(id) - aPLInfo <- annotationPrivateLinkDAO.findOne(idValidated) ?~> "notFound" ~> NOT_FOUND + aPLInfo <- annotationPrivateLinkDAO.findOne(id) ?~> "notFound" ~> NOT_FOUND _ <- annotationDAO.assertUpdateAccess(aPLInfo._annotation) ?~> "notAllowed" ~> FORBIDDEN - _ <- annotationPrivateLinkDAO.deleteOne(idValidated) ?~> "delete failed" + _ <- annotationPrivateLinkDAO.deleteOne(id) ?~> "delete failed" } yield JsonOk("privateLink deleted") } } diff --git a/app/controllers/AuthenticationController.scala b/app/controllers/AuthenticationController.scala index c186e6203a..a28b1d166b 100755 --- a/app/controllers/AuthenticationController.scala +++ b/app/controllers/AuthenticationController.scala @@ -213,14 +213,13 @@ class AuthenticationController @Inject()( result <- combinedAuthenticatorService.embed(cookie, Redirect("/dashboard")) //to login the new user } yield result - def accessibleBySwitching(datasetId: Option[String], + def accessibleBySwitching(datasetId: Option[ObjectId], annotationId: Option[String], workflowHash: Option[String]): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - datasetIdValidated <- Fox.runOptional(datasetId)(ObjectId.fromString(_)) selectedOrganization <- authenticationService.getOrganizationToSwitchTo(request.identity, - datasetIdValidated, + datasetId, annotationId, workflowHash) selectedOrganizationJs <- organizationService.publicWrites(selectedOrganization) diff --git a/app/controllers/ConfigurationController.scala b/app/controllers/ConfigurationController.scala index cbb40e3bf5..69652d7cbc 100755 --- a/app/controllers/ConfigurationController.scala +++ b/app/controllers/ConfigurationController.scala @@ -35,50 +35,43 @@ class ConfigurationController @Inject()( } yield JsonOk(Messages("user.configuration.updated")) } - def readDatasetViewConfiguration(datasetId: String, sharingToken: Option[String]): Action[List[String]] = + def readDatasetViewConfiguration(datasetId: ObjectId, sharingToken: Option[String]): Action[List[String]] = sil.UserAwareAction.async(validateJson[List[String]]) { implicit request => val ctx = URLSharing.fallbackTokenAccessContext(sharingToken) for { - datasetIdValidated <- ObjectId.fromString(datasetId) configuration <- request.identity.toFox - .flatMap( - user => - datasetConfigurationService.getDatasetViewConfigurationForUserAndDataset( - request.body, - user, - datasetIdValidated)(GlobalAccessContext)) + .flatMap(user => + datasetConfigurationService.getDatasetViewConfigurationForUserAndDataset(request.body, user, datasetId)( + GlobalAccessContext)) .orElse( - datasetConfigurationService.getDatasetViewConfigurationForDataset(request.body, datasetIdValidated)(ctx) + datasetConfigurationService.getDatasetViewConfigurationForDataset(request.body, datasetId)(ctx) ) .getOrElse(Map.empty) } yield Ok(Json.toJson(configuration)) } - def updateDatasetViewConfiguration(datasetId: String): Action[JsValue] = + def updateDatasetViewConfiguration(datasetId: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json(maxLength = 20480)) { implicit request => for { jsConfiguration <- request.body.asOpt[JsObject] ?~> "user.configuration.dataset.invalid" - datasetIdValidated <- ObjectId.fromString(datasetId) conf = jsConfiguration.fields.toMap datasetConf = conf - "layers" layerConf = conf.get("layers") - _ <- userService.updateDatasetViewConfiguration(request.identity, datasetIdValidated, datasetConf, layerConf) + _ <- userService.updateDatasetViewConfiguration(request.identity, datasetId, datasetConf, layerConf) } yield JsonOk(Messages("user.configuration.dataset.updated")) } - def readDatasetAdminViewConfiguration(datasetId: String): Action[AnyContent] = + def readDatasetAdminViewConfiguration(datasetId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - configuration <- datasetConfigurationService.getCompleteAdminViewConfiguration(datasetIdValidated) + configuration <- datasetConfigurationService.getCompleteAdminViewConfiguration(datasetId) } yield Ok(Json.toJson(configuration)) } - def updateDatasetAdminViewConfiguration(datasetNameAndId: String): Action[JsValue] = + def updateDatasetAdminViewConfiguration(datasetId: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json(maxLength = 20480)) { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetNameAndId) - dataset <- datasetDAO.findOne(datasetIdValidated)(GlobalAccessContext) + dataset <- datasetDAO.findOne(datasetId)(GlobalAccessContext) _ <- datasetService.isEditableBy(dataset, Some(request.identity)) ?~> "notAllowed" ~> FORBIDDEN jsObject <- request.body.asOpt[JsObject].toFox ?~> "user.configuration.dataset.invalid" _ <- datasetConfigurationService.updateAdminViewConfigurationFor(dataset, jsObject.fields.toMap) diff --git a/app/controllers/DatasetController.scala b/app/controllers/DatasetController.scala index 846b95b0d1..6115afa3e8 100755 --- a/app/controllers/DatasetController.scala +++ b/app/controllers/DatasetController.scala @@ -103,15 +103,14 @@ class DatasetController @Inject()(userService: UserService, (__ \ "metadata").readNullable[JsArray] and (__ \ "folderId").readNullable[ObjectId]).tupled - def removeFromThumbnailCache(datasetId: String): Action[AnyContent] = + def removeFromThumbnailCache(datasetId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - _ <- thumbnailCachingService.removeFromCache(datasetIdValidated) + _ <- thumbnailCachingService.removeFromCache(datasetId) } yield Ok } - def thumbnail(datasetId: String, + def thumbnail(datasetId: ObjectId, dataLayerName: String, w: Option[Int], h: Option[Int], @@ -120,9 +119,8 @@ class DatasetController @Inject()(userService: UserService, sil.UserAwareAction.async { implicit request => val ctx = URLSharing.fallbackTokenAccessContext(sharingToken) for { - datasetIdValidated <- ObjectId.fromString(datasetId) - _ <- datasetDAO.findOne(datasetIdValidated)(ctx) ?~> notFoundMessage(datasetId) ~> NOT_FOUND // To check Access Rights - image <- thumbnailService.getThumbnailWithCache(datasetIdValidated, dataLayerName, w, h, mappingName) + _ <- datasetDAO.findOne(datasetId)(ctx) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND // To check Access Rights + image <- thumbnailService.getThumbnailWithCache(datasetId, dataLayerName, w, h, mappingName) } yield { addRemoteOriginHeaders(Ok(image)).as(jpegMimeType).withHeaders(CACHE_CONTROL -> "public, max-age=86400") } @@ -165,9 +163,9 @@ class DatasetController @Inject()(userService: UserService, // Optional filtering: List only datasets of the requesting user’s organization onlyMyOrganization: Option[Boolean], // Optional filtering: List only datasets uploaded by the user with this id - uploaderId: Option[String], + uploaderId: Option[ObjectId], // Optional filtering: List only datasets in the folder with this id - folderId: Option[String], + folderId: Option[ObjectId], // Optional filtering: If a folderId was specified, this parameter controls whether subfolders should be considered, too (default: false) recursive: Option[Boolean], // Optional filtering: List only datasets with names matching this search query @@ -178,8 +176,7 @@ class DatasetController @Inject()(userService: UserService, compact: Option[Boolean] ): Action[AnyContent] = sil.UserAwareAction.async { implicit request => for { - folderIdValidated <- Fox.runOptional(folderId)(ObjectId.fromString) - uploaderIdValidated <- Fox.runOptional(uploaderId)(ObjectId.fromString) + _ <- Fox.successful(()) organizationIdOpt = if (onlyMyOrganization.getOrElse(false)) request.identity.map(_._organization) else @@ -190,8 +187,8 @@ class DatasetController @Inject()(userService: UserService, isActive, isUnreported, organizationIdOpt, - folderIdValidated, - uploaderIdValidated, + folderId, + uploaderId, searchQuery, request.identity.map(_._id), recursive.getOrElse(false), @@ -203,8 +200,8 @@ class DatasetController @Inject()(userService: UserService, datasets <- datasetDAO.findAllWithSearch(isActive, isUnreported, organizationIdOpt, - folderIdValidated, - uploaderIdValidated, + folderId, + uploaderId, searchQuery, recursive.getOrElse(false), limit) ?~> "dataset.list.failed" @@ -243,10 +240,9 @@ class DatasetController @Inject()(userService: UserService, } } yield js.flatten - def accessList(datasetId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def accessList(datasetId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> notFoundMessage(datasetIdValidated.toString) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization) allowedTeams <- teamService.allowedTeamIdsForDataset(dataset, cumulative = true) ?~> "allowedTeams.notFound" usersByTeams <- userDAO.findAllByTeams(allowedTeams) @@ -256,15 +252,14 @@ class DatasetController @Inject()(userService: UserService, } yield Ok(Json.toJson(usersJs)) } - def read(datasetId: String, + def read(datasetId: ObjectId, // Optional sharing token allowing access to datasets your team does not normally have access to.") sharingToken: Option[String]): Action[AnyContent] = sil.UserAwareAction.async { implicit request => log() { val ctx = URLSharing.fallbackTokenAccessContext(sharingToken) for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated)(ctx) ?~> notFoundMessage(datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId)(ctx) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ~> NOT_FOUND _ <- Fox.runOptional(request.identity)(user => datasetLastUsedTimesDAO.updateForDatasetAndUser(dataset._id, user._id)) @@ -284,12 +279,11 @@ class DatasetController @Inject()(userService: UserService, } } - def health(datasetId: String, sharingToken: Option[String]): Action[AnyContent] = + def health(datasetId: ObjectId, sharingToken: Option[String]): Action[AnyContent] = sil.UserAwareAction.async { implicit request => val ctx = URLSharing.fallbackTokenAccessContext(sharingToken) for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated)(ctx) ?~> notFoundMessage(datasetIdValidated.toString) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId)(ctx) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND dataSource <- datasetService.dataSourceFor(dataset) ?~> "dataSource.notFound" ~> NOT_FOUND usableDataSource <- dataSource.toUsable.toFox ?~> "dataset.notImported" datalayer <- usableDataSource.dataLayers.headOption.toFox ?~> "dataset.noLayers" @@ -300,29 +294,27 @@ class DatasetController @Inject()(userService: UserService, } yield Ok("Ok") } - def updatePartial(datasetId: String): Action[DatasetUpdateParameters] = + def updatePartial(datasetId: ObjectId): Action[DatasetUpdateParameters] = sil.SecuredAction.async(validateJson[DatasetUpdateParameters]) { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> notFoundMessage(datasetIdValidated.toString) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND _ <- Fox.assertTrue(datasetService.isEditableBy(dataset, Some(request.identity))) ?~> "notAllowed" ~> FORBIDDEN _ <- Fox.runOptional(request.body.metadata)(assertNoDuplicateMetadataKeys) _ <- datasetDAO.updatePartial(dataset._id, request.body) - updated <- datasetDAO.findOne(datasetIdValidated) + updated <- datasetDAO.findOne(datasetId) _ = analyticsService.track(ChangeDatasetSettingsEvent(request.identity, updated)) js <- datasetService.publicWrites(updated, Some(request.identity)) } yield Ok(js) } // Note that there exists also updatePartial (which will only expect the changed fields) - def update(datasetId: String): Action[JsValue] = + def update(datasetId: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => withJsonBodyUsing(datasetPublicReads) { case (description, datasetName, legacyDatasetDisplayName, sortingKey, isPublic, tags, metadata, folderId) => val name = if (legacyDatasetDisplayName.isDefined) legacyDatasetDisplayName else datasetName for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> notFoundMessage(datasetIdValidated.toString) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND maybeUpdatedMetadata = metadata.getOrElse(dataset.metadata) _ <- assertNoDuplicateMetadataKeys(maybeUpdatedMetadata) _ <- Fox.assertTrue(datasetService.isEditableBy(dataset, Some(request.identity))) ?~> "notAllowed" ~> FORBIDDEN @@ -336,18 +328,17 @@ class DatasetController @Inject()(userService: UserService, maybeUpdatedMetadata, folderId.getOrElse(dataset._folder) ) - updated <- datasetDAO.findOne(datasetIdValidated) + updated <- datasetDAO.findOne(datasetId) _ = analyticsService.track(ChangeDatasetSettingsEvent(request.identity, updated)) js <- datasetService.publicWrites(updated, Some(request.identity)) } yield Ok(Json.toJson(js)) } } - def updateTeams(datasetId: String): Action[List[ObjectId]] = + def updateTeams(datasetId: ObjectId): Action[List[ObjectId]] = sil.SecuredAction.async(validateJson[List[ObjectId]]) { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> notFoundMessage(datasetIdValidated.toString) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND _ <- Fox.assertTrue(datasetService.isEditableBy(dataset, Some(request.identity))) ?~> "notAllowed" ~> FORBIDDEN includeMemberOnlyTeams = request.identity.isDatasetManager userTeams <- if (includeMemberOnlyTeams) teamDAO.findAll else teamDAO.findAllEditable @@ -359,24 +350,22 @@ class DatasetController @Inject()(userService: UserService, } yield Ok(Json.toJson(newTeams)) } - def getSharingToken(datasetId: String): Action[AnyContent] = + def getSharingToken(datasetId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> notFoundMessage(datasetIdValidated.toString) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND _ <- bool2Fox(dataset._organization == request.identity._organization) ~> FORBIDDEN token <- datasetService.getSharingToken(dataset._id) } yield Ok(Json.obj("sharingToken" -> token.trim)) } - def deleteSharingToken(datasetId: String): Action[AnyContent] = + def deleteSharingToken(datasetId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> notFoundMessage(datasetIdValidated.toString) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND _ <- bool2Fox(dataset._organization == request.identity._organization) ~> FORBIDDEN _ <- Fox.assertTrue(datasetService.isEditableBy(dataset, Some(request.identity))) ?~> "notAllowed" ~> FORBIDDEN - _ <- datasetDAO.updateSharingTokenById(datasetIdValidated, None) + _ <- datasetDAO.updateSharingTokenById(datasetId, None) } yield Ok } @@ -438,17 +427,16 @@ class DatasetController @Inject()(userService: UserService, case _ => Messages("dataset.notFoundConsiderLogin", datasetName) } - def segmentAnythingMask(datasetId: String, + def segmentAnythingMask(datasetId: ObjectId, dataLayerName: String, intensityMin: Option[Float], intensityMax: Option[Float]): Action[SegmentAnythingMaskParameters] = sil.SecuredAction.async(validateJson[SegmentAnythingMaskParameters]) { implicit request => log() { for { - datasetIdValidated <- ObjectId.fromString(datasetId) _ <- bool2Fox(conf.Features.segmentAnythingEnabled) ?~> "segmentAnything.notEnabled" _ <- bool2Fox(conf.SegmentAnything.uri.nonEmpty) ?~> "segmentAnything.noUri" - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> notFoundMessage(datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> notFoundMessage(datasetId.toString) ~> NOT_FOUND dataSource <- datasetService.dataSourceFor(dataset) ?~> "dataSource.notFound" ~> NOT_FOUND usableDataSource <- dataSource.toUsable ?~> "dataset.notImported" dataLayer <- usableDataSource.dataLayers.find(_.name == dataLayerName) ?~> "dataset.noLayers" diff --git a/app/controllers/FolderController.scala b/app/controllers/FolderController.scala index b4bc528d3c..c730b5a91d 100644 --- a/app/controllers/FolderController.scala +++ b/app/controllers/FolderController.scala @@ -37,59 +37,55 @@ class FolderController @Inject()( } yield Ok(rootFolderJson) } - def get(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def get(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - idValidated <- ObjectId.fromString(id) - folder <- folderDAO.findOne(idValidated) ?~> "folder.notFound" + folder <- folderDAO.findOne(id) ?~> "folder.notFound" organization <- organizationDAO.findOne(request.identity._organization) folderJson <- folderService.publicWrites(folder, Some(request.identity), Some(organization)) } yield Ok(folderJson) } - def update(id: String): Action[FolderParameters] = sil.SecuredAction.async(validateJson[FolderParameters]) { + def update(id: ObjectId): Action[FolderParameters] = sil.SecuredAction.async(validateJson[FolderParameters]) { implicit request => for { - idValidated <- ObjectId.fromString(id) + _ <- Fox.successful(()) params = request.body organization <- organizationDAO.findOne(request.identity._organization) - _ <- folderDAO.findOne(idValidated) ?~> "folder.notFound" - - <- Fox.assertTrue(folderDAO.isEditable(idValidated)) ?~> "folder.update.notAllowed" ~> FORBIDDEN + _ <- folderDAO.findOne(id) ?~> "folder.notFound" + - <- Fox.assertTrue(folderDAO.isEditable(id)) ?~> "folder.update.notAllowed" ~> FORBIDDEN _ <- folderService.assertValidFolderName(params.name) _ <- assertNoDuplicateMetadataKeys(params.metadata) - _ <- folderDAO.updateMetadata(idValidated, params.metadata) - _ <- folderDAO.updateName(idValidated, params.name) ?~> "folder.update.name.failed" + _ <- folderDAO.updateMetadata(id, params.metadata) + _ <- folderDAO.updateName(id, params.name) ?~> "folder.update.name.failed" _ <- folderService - .updateAllowedTeams(idValidated, params.allowedTeams, request.identity) ?~> "folder.update.teams.failed" - updated <- folderDAO.findOne(idValidated) + .updateAllowedTeams(id, params.allowedTeams, request.identity) ?~> "folder.update.teams.failed" + updated <- folderDAO.findOne(id) folderJson <- folderService.publicWrites(updated, Some(request.identity), Some(organization)) } yield Ok(folderJson) } - def move(id: String, newParentId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def move(id: ObjectId, newParentId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - idValidated <- ObjectId.fromString(id) - newParentIdValidated <- ObjectId.fromString(newParentId) organization <- organizationDAO.findOne(request.identity._organization) - _ <- bool2Fox(organization._rootFolder != idValidated) ?~> "folder.move.root" - _ <- folderDAO.findOne(idValidated) ?~> "folder.notFound" - _ <- folderDAO.findOne(newParentIdValidated) ?~> "folder.notFound" - _ <- folderDAO.moveSubtree(idValidated, newParentIdValidated) - updated <- folderDAO.findOne(idValidated) + _ <- bool2Fox(organization._rootFolder != id) ?~> "folder.move.root" + _ <- folderDAO.findOne(id) ?~> "folder.notFound" + _ <- folderDAO.findOne(newParentId) ?~> "folder.notFound" + _ <- folderDAO.moveSubtree(id, newParentId) + updated <- folderDAO.findOne(id) folderJson <- folderService.publicWrites(updated, Some(request.identity), Some(organization)) } yield Ok(folderJson) } - def delete(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def delete(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - idValidated <- ObjectId.fromString(id) organization <- organizationDAO.findOne(request.identity._organization) - _ <- bool2Fox(organization._rootFolder != idValidated) ?~> "folder.delete.root" - _ <- folderDAO.findOne(idValidated) ?~> "folder.notFound" - childrenCount <- folderDAO.countChildren(idValidated) - datasetsCount <- datasetDAO.countByFolder(idValidated) + _ <- bool2Fox(organization._rootFolder != id) ?~> "folder.delete.root" + _ <- folderDAO.findOne(id) ?~> "folder.notFound" + childrenCount <- folderDAO.countChildren(id) + datasetsCount <- datasetDAO.countByFolder(id) _ <- bool2Fox(childrenCount == 0) ?~> "folder.delete.notEmpty.children" _ <- bool2Fox(datasetsCount == 0) ?~> "folder.delete.notEmpty.datasets" - _ <- folderDAO.deleteOne(idValidated) + _ <- folderDAO.deleteOne(id) } yield Ok } @@ -103,13 +99,12 @@ class FolderController @Inject()( } yield Ok(Json.toJson(foldersWithParentsJson)) } - def create(parentId: String, name: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def create(parentId: ObjectId, name: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - parentIdValidated <- ObjectId.fromString(parentId) _ <- folderService.assertValidFolderName(name) newFolder = Folder(ObjectId.generate, name, JsArray.empty) - _ <- folderDAO.findOne(parentIdValidated) ?~> "folder.notFound" - _ <- folderDAO.insertAsChild(parentIdValidated, newFolder) ?~> "folder.create.failed" + _ <- folderDAO.findOne(parentId) ?~> "folder.notFound" + _ <- folderDAO.insertAsChild(parentId, newFolder) ?~> "folder.create.failed" organization <- organizationDAO.findOne(request.identity._organization) ?~> "folder.notFound" folderJson <- folderService.publicWrites(newFolder, Some(request.identity), Some(organization)) } yield Ok(folderJson) diff --git a/app/controllers/JobController.scala b/app/controllers/JobController.scala index 4ccfdea0bd..c93ab0c302 100644 --- a/app/controllers/JobController.scala +++ b/app/controllers/JobController.scala @@ -89,11 +89,10 @@ class JobController @Inject()( } yield Ok(Json.toJson(jobsJsonList)) } - def get(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def get(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- bool2Fox(wkconf.Features.jobsEnabled) ?~> "job.disabled" - idValidated <- ObjectId.fromString(id) - job <- jobDAO.findOne(idValidated) ?~> "job.notFound" + job <- jobDAO.findOne(id) ?~> "job.notFound" js <- jobService.publicWrites(job) } yield Ok(js) } @@ -104,23 +103,21 @@ class JobController @Inject()( * The worker-written “state” field is later updated by the worker when it has successfully cancelled the job run. * When both fields are set, the cancelling is complete and wk no longer includes the job in the to_cancel list sent to worker */ - def cancel(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def cancel(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- bool2Fox(wkconf.Features.jobsEnabled) ?~> "job.disabled" - jobIdValidated <- ObjectId.fromString(id) - job <- jobDAO.findOne(jobIdValidated) - _ <- jobDAO.updateManualState(jobIdValidated, JobState.CANCELLED) + job <- jobDAO.findOne(id) + _ <- jobDAO.updateManualState(id, JobState.CANCELLED) js <- jobService.publicWrites(job) } yield Ok(js) } // Note that the dataset has to be registered by reserveUpload via the datastore first. - def runConvertToWkwJob(datasetId: String, scale: String, unit: Option[String]): Action[AnyContent] = + def runConvertToWkwJob(datasetId: ObjectId, scale: String, unit: Option[String]): Action[AnyContent] = sil.SecuredAction.async { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND voxelSizeFactor <- Vec3Double.fromUriLiteral(scale).toFox voxelSizeUnit <- Fox.runOptional(unit)(u => LengthUnit.fromString(u).toFox) voxelSize = VoxelSize.fromFactorAndUnitWithDefault(voxelSizeFactor, voxelSizeUnit) @@ -144,14 +141,13 @@ class JobController @Inject()( } } - def runComputeMeshFileJob(datasetId: String, + def runComputeMeshFileJob(datasetId: ObjectId, layerName: String, mag: String, agglomerateView: Option[String]): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) @@ -172,11 +168,10 @@ class JobController @Inject()( } yield Ok(js) } - def runComputeSegmentIndexFileJob(datasetId: String, layerName: String): Action[AnyContent] = + def runComputeSegmentIndexFileJob(datasetId: ObjectId, layerName: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) @@ -194,12 +189,11 @@ class JobController @Inject()( } yield Ok(js) } - def runInferNucleiJob(datasetId: String, layerName: String, newDatasetName: String): Action[AnyContent] = + def runInferNucleiJob(datasetId: ObjectId, layerName: String, newDatasetName: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) @@ -220,15 +214,14 @@ class JobController @Inject()( } } - def runInferNeuronsJob(datasetId: String, + def runInferNeuronsJob(datasetId: ObjectId, layerName: String, bbox: String, newDatasetName: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) @@ -252,15 +245,14 @@ class JobController @Inject()( } } - def runInferMitochondriaJob(datasetId: String, + def runInferMitochondriaJob(datasetId: ObjectId, layerName: String, bbox: String, newDatasetName: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) @@ -285,22 +277,20 @@ class JobController @Inject()( } } - def runAlignSectionsJob(datasetId: String, + def runAlignSectionsJob(datasetId: ObjectId, layerName: String, newDatasetName: String, - annotationId: Option[String] = None): Action[AnyContent] = + annotationId: Option[ObjectId] = None): Action[AnyContent] = sil.SecuredAction.async { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) _ <- bool2Fox(request.identity._organization == organization._id) ?~> "job.alignSections.notAllowed.organization" ~> FORBIDDEN _ <- datasetService.assertValidDatasetName(newDatasetName) _ <- datasetService.assertValidLayerNameLax(layerName) - _ <- Fox.runOptional(annotationId)(ObjectId.fromString) command = JobCommand.align_sections commandArgs = Json.obj( "organization_id" -> organization._id, @@ -316,19 +306,18 @@ class JobController @Inject()( } } - def runExportTiffJob(datasetId: String, + def runExportTiffJob(datasetId: ObjectId, bbox: String, additionalCoordinates: Option[String], layerName: Option[String], mag: Option[String], annotationLayerName: Option[String], - annotationId: Option[String], + annotationId: Option[ObjectId], asOmeTiff: Boolean): Action[AnyContent] = sil.SecuredAction.async { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) @@ -372,9 +361,9 @@ class JobController @Inject()( } } - def runMaterializeVolumeAnnotationJob(datasetId: String, + def runMaterializeVolumeAnnotationJob(datasetId: ObjectId, fallbackLayerName: String, - annotationId: String, + annotationId: ObjectId, annotationType: String, newDatasetName: String, outputSegmentationLayerName: String, @@ -383,8 +372,7 @@ class JobController @Inject()( sil.SecuredAction.async { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) @@ -411,12 +399,11 @@ class JobController @Inject()( } } - def runFindLargestSegmentIdJob(datasetId: String, layerName: String): Action[AnyContent] = + def runFindLargestSegmentIdJob(datasetId: ObjectId, layerName: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) @@ -435,12 +422,11 @@ class JobController @Inject()( } } - def runRenderAnimationJob(datasetId: String): Action[AnimationJobOptions] = + def runRenderAnimationJob(datasetId: ObjectId): Action[AnimationJobOptions] = sil.SecuredAction.async(validateJson[AnimationJobOptions]) { implicit request => log(Some(slackNotificationService.noticeFailedJobRequest)) { for { - datasetIdValidated <- ObjectId.fromString(datasetId) - dataset <- datasetDAO.findOne(datasetIdValidated) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND + dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND organization <- organizationDAO.findOne(dataset._organization)(GlobalAccessContext) ?~> Messages( "organization.notFound", dataset._organization) @@ -478,11 +464,10 @@ class JobController @Inject()( } } - def redirectToExport(jobId: String): Action[AnyContent] = + def redirectToExport(jobId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - jobIdValidated <- ObjectId.fromString(jobId) - job <- jobDAO.findOne(jobIdValidated) + job <- jobDAO.findOne(jobId) dataStore <- dataStoreDAO.findOneByName(job._dataStore) ?~> "dataStore.notFound" userAuthToken <- wkSilhouetteEnvironment.combinedAuthenticatorService.findOrCreateToken( request.identity.loginInfo) diff --git a/app/controllers/LegacyApiController.scala b/app/controllers/LegacyApiController.scala index cb8d983285..dcb4d0235c 100644 --- a/app/controllers/LegacyApiController.scala +++ b/app/controllers/LegacyApiController.scala @@ -71,7 +71,7 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, sil.UserAwareAction.async { implicit request => for { dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organizationId) - result <- datasetController.read(dataset._id.toString, sharingToken)(request) + result <- datasetController.read(dataset._id, sharingToken)(request) adaptedResult <- replaceInResult(migrateDatasetJsonToOldFormat)(result) } yield adaptedResult } @@ -81,7 +81,7 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, for { _ <- Fox.successful(logVersioned(request)) dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organizationId) - result <- datasetController.update(dataset._id.toString)(request) + result <- datasetController.update(dataset._id)(request) adaptedResult <- replaceInResult(migrateDatasetJsonToOldFormat)(result) } yield adaptedResult } @@ -91,7 +91,7 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, for { _ <- Fox.successful(logVersioned(request)) dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organizationId) - result <- datasetController.updateTeams(dataset._id.toString)(request) + result <- datasetController.updateTeams(dataset._id)(request) } yield result } @@ -100,11 +100,11 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, for { _ <- Fox.successful(logVersioned(request)) dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organizationId) - sharingToken <- datasetController.getSharingToken(dataset._id.toString)(request) + sharingToken <- datasetController.getSharingToken(dataset._id)(request) } yield sharingToken } - def readTaskV8(taskId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def readTaskV8(taskId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- Fox.successful(logVersioned(request)) result <- taskController.read(taskId)(request) @@ -127,7 +127,7 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, } yield adaptedResult } - def updateTaskV8(taskId: String): Action[LegacyTaskParameters] = + def updateTaskV8(taskId: ObjectId): Action[LegacyTaskParameters] = sil.SecuredAction.async(validateJson[LegacyTaskParameters]) { implicit request => val params = request.body for { @@ -141,7 +141,7 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, } yield adaptedResult } - def tasksForProjectV8(id: String, + def tasksForProjectV8(id: ObjectId, limit: Option[Int] = None, pageNumber: Option[Int] = None, includeTotalCount: Option[Boolean]): Action[AnyContent] = @@ -153,15 +153,16 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, } yield replacedResults } - def annotationInfoV8(id: String, timestamp: Long): Action[AnyContent] = sil.SecuredAction.async { implicit request => - for { - _ <- Fox.successful(logVersioned(request)) - result <- annotationController.infoWithoutType(id, timestamp)(request) - adaptedResult <- replaceInResult(addDataSetToTaskInAnnotation)(result) - } yield adaptedResult + def annotationInfoV8(id: ObjectId, timestamp: Long): Action[AnyContent] = sil.SecuredAction.async { + implicit request => + for { + _ <- Fox.successful(logVersioned(request)) + result <- annotationController.infoWithoutType(id, timestamp)(request) + adaptedResult <- replaceInResult(addDataSetToTaskInAnnotation)(result) + } yield adaptedResult } - def annotationsForTaskV8(taskId: String): Action[AnyContent] = + def annotationsForTaskV8(taskId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- Fox.successful(logVersioned(request)) @@ -176,8 +177,8 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, isUnreported: Option[Boolean], organizationName: Option[String], onlyMyOrganization: Option[Boolean], - uploaderId: Option[String], - folderId: Option[String], + uploaderId: Option[ObjectId], + folderId: Option[ObjectId], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], @@ -200,8 +201,8 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, isUnreported: Option[Boolean], organizationName: Option[String], onlyMyOrganization: Option[Boolean], - uploaderId: Option[String], - folderId: Option[String], + uploaderId: Option[ObjectId], + folderId: Option[ObjectId], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], @@ -225,7 +226,7 @@ class LegacyApiController @Inject()(annotationController: AnnotationController, sil.UserAwareAction.async { implicit request => for { dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organizationName) - result <- datasetController.read(dataset._id.toString, sharingToken)(request) + result <- datasetController.read(dataset._id, sharingToken)(request) adaptedResult <- replaceInResult(replaceVoxelSize)(result) } yield adaptedResult } diff --git a/app/controllers/MaintenanceController.scala b/app/controllers/MaintenanceController.scala index cbe7ee820c..401d24c11f 100644 --- a/app/controllers/MaintenanceController.scala +++ b/app/controllers/MaintenanceController.scala @@ -33,30 +33,27 @@ class MaintenanceController @Inject()( } yield Ok(Json.toJson(js)) } - def readOne(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def readOne(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- userService.assertIsSuperUser(request.identity) ?~> "notAllowed" ~> FORBIDDEN - idValidated <- ObjectId.fromString(id) - maintenance <- maintenanceDAO.findOne(idValidated) + maintenance <- maintenanceDAO.findOne(id) } yield Ok(maintenanceService.publicWrites(maintenance)) } - def update(id: String): Action[MaintenanceParameters] = sil.SecuredAction.async(validateJson[MaintenanceParameters]) { - implicit request => + def update(id: ObjectId): Action[MaintenanceParameters] = + sil.SecuredAction.async(validateJson[MaintenanceParameters]) { implicit request => for { _ <- userService.assertIsSuperUser(request.identity) ?~> "notAllowed" ~> FORBIDDEN - idValidated <- ObjectId.fromString(id) - _ <- maintenanceDAO.findOne(idValidated) ?~> "maintenance.notFound" - _ <- maintenanceDAO.updateOne(idValidated, request.body) - updated <- maintenanceDAO.findOne(idValidated) + _ <- maintenanceDAO.findOne(id) ?~> "maintenance.notFound" + _ <- maintenanceDAO.updateOne(id, request.body) + updated <- maintenanceDAO.findOne(id) } yield Ok(maintenanceService.publicWrites(updated)) - } + } - def delete(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def delete(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- userService.assertIsSuperUser(request.identity) ?~> "notAllowed" ~> FORBIDDEN - idValidated <- ObjectId.fromString(id) - _ <- maintenanceDAO.deleteOne(idValidated) + _ <- maintenanceDAO.deleteOne(id) } yield Ok } diff --git a/app/controllers/MeshController.scala b/app/controllers/MeshController.scala index 3eddfb41ba..d0b4481a4d 100644 --- a/app/controllers/MeshController.scala +++ b/app/controllers/MeshController.scala @@ -21,10 +21,9 @@ class MeshController @Inject()(meshDAO: MeshDAO, extends Controller with FoxImplicits { - def get(id: String): Action[AnyContent] = sil.UserAwareAction.async { implicit request => + def get(id: ObjectId): Action[AnyContent] = sil.UserAwareAction.async { implicit request => for { - idValidated <- ObjectId.fromString(id) - meshInfo <- meshDAO.findOne(idValidated) ?~> "mesh.notFound" ~> NOT_FOUND + meshInfo <- meshDAO.findOne(id) ?~> "mesh.notFound" ~> NOT_FOUND _ <- annotationDAO.findOne(meshInfo._annotation) ?~> "annotation.notFound" ~> NOT_FOUND meshInfoJs <- meshService.publicWrites(meshInfo) ?~> "mesh.write.failed" } yield JsonOk(meshInfoJs) @@ -43,46 +42,41 @@ class MeshController @Inject()(meshDAO: MeshDAO, } yield Ok(js) } - def update(id: String): Action[MeshInfoParameters] = sil.SecuredAction.async(validateJson[MeshInfoParameters]) { + def update(id: ObjectId): Action[MeshInfoParameters] = sil.SecuredAction.async(validateJson[MeshInfoParameters]) { implicit request => val params = request.body for { - idValidated <- ObjectId.fromString(id) - meshInfo <- meshDAO.findOne(idValidated) ?~> "mesh.notFound" ~> NOT_FOUND + meshInfo <- meshDAO.findOne(id) ?~> "mesh.notFound" ~> NOT_FOUND _ <- annotationDAO.assertUpdateAccess(meshInfo._annotation) ?~> "notAllowed" ~> FORBIDDEN _ <- annotationDAO.assertUpdateAccess(params.annotationId) ?~> "notAllowed" ~> FORBIDDEN - _ <- meshDAO - .updateOne(idValidated, params.annotationId, params.description, params.position) ?~> "mesh.update.failed" - updated <- meshDAO.findOne(idValidated) ?~> "mesh.notFound" + _ <- meshDAO.updateOne(id, params.annotationId, params.description, params.position) ?~> "mesh.update.failed" + updated <- meshDAO.findOne(id) ?~> "mesh.notFound" js <- meshService.publicWrites(updated) ?~> "mesh.write.failed" } yield Ok(js) } - def getData(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def getData(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - idValidated <- ObjectId.fromString(id) - meshInfo <- meshDAO.findOne(idValidated) ?~> "mesh.notFound" ~> NOT_FOUND + meshInfo <- meshDAO.findOne(id) ?~> "mesh.notFound" ~> NOT_FOUND _ <- annotationDAO.findOne(meshInfo._annotation) ?~> "annotation.notFound" ~> NOT_FOUND - data <- meshDAO.getData(idValidated) ?~> "mesh.data.get.failed" + data <- meshDAO.getData(id) ?~> "mesh.data.get.failed" } yield Ok(data) } - def updateData(id: String): Action[RawBuffer] = sil.SecuredAction.async(parse.raw) { implicit request => + def updateData(id: ObjectId): Action[RawBuffer] = sil.SecuredAction.async(parse.raw) { implicit request => for { - idValidated <- ObjectId.fromString(id) - meshInfo <- meshDAO.findOne(idValidated) ?~> "mesh.notFound" ~> NOT_FOUND + meshInfo <- meshDAO.findOne(id) ?~> "mesh.notFound" ~> NOT_FOUND _ <- annotationDAO.assertUpdateAccess(meshInfo._annotation) ?~> "notAllowed" ~> FORBIDDEN byteString <- request.body.asBytes(maxLength = 1024 * 1024 * 1024) ?~> "mesh.data.read.failed" - _ <- meshDAO.updateData(idValidated, byteString.toArray) ?~> "mesh.data.save.failed" + _ <- meshDAO.updateData(id, byteString.toArray) ?~> "mesh.data.save.failed" } yield Ok } - def delete(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def delete(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - idValidated <- ObjectId.fromString(id) - meshInfo <- meshDAO.findOne(idValidated) ?~> "mesh.notFound" ~> NOT_FOUND + meshInfo <- meshDAO.findOne(id) ?~> "mesh.notFound" ~> NOT_FOUND _ <- annotationDAO.assertUpdateAccess(meshInfo._annotation) ?~> "notAllowed" ~> FORBIDDEN - _ <- meshDAO.deleteOne(idValidated) ?~> "mesh.delete.failed" + _ <- meshDAO.deleteOne(id) ?~> "mesh.delete.failed" } yield Ok } diff --git a/app/controllers/ProjectController.scala b/app/controllers/ProjectController.scala index c96f27d642..b5c667427f 100644 --- a/app/controllers/ProjectController.scala +++ b/app/controllers/ProjectController.scala @@ -49,10 +49,9 @@ class ProjectController @Inject()(projectService: ProjectService, } yield Ok(Json.toJson(js)) } - def read(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def read(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - projectIdValidated <- ObjectId.fromString(id) - project <- projectDAO.findOne(projectIdValidated) ?~> "project.notFound" ~> NOT_FOUND + project <- projectDAO.findOne(id) ?~> "project.notFound" ~> NOT_FOUND js <- projectService.publicWrites(project) } yield Ok(js) } @@ -65,10 +64,9 @@ class ProjectController @Inject()(projectService: ProjectService, } yield Ok(js) } - def delete(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def delete(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - projectIdValidated <- ObjectId.fromString(id) - project <- projectDAO.findOne(projectIdValidated) ?~> "project.notFound" ~> NOT_FOUND + project <- projectDAO.findOne(id) ?~> "project.notFound" ~> NOT_FOUND _ <- bool2Fox(project.isDeletableBy(request.identity)) ?~> "project.remove.notAllowed" ~> FORBIDDEN _ <- projectService.deleteOne(project._id) ?~> "project.remove.failure" } yield JsonOk(Messages("project.remove.success")) @@ -88,44 +86,41 @@ class ProjectController @Inject()(projectService: ProjectService, } } - def update(id: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => + def update(id: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => withJsonBodyUsing(Project.projectPublicReads) { updateRequest => for { - projectIdValidated <- ObjectId.fromString(id) - project <- projectDAO.findOne(projectIdValidated)(GlobalAccessContext) ?~> "project.notFound" ~> NOT_FOUND + project <- projectDAO.findOne(id)(GlobalAccessContext) ?~> "project.notFound" ~> NOT_FOUND _ <- Fox .assertTrue(userService.isTeamManagerOrAdminOf(request.identity, project._team)) ?~> "notAllowed" ~> FORBIDDEN _ <- projectDAO .updateOne(updateRequest.copy(name = project.name, _id = project._id, paused = project.paused)) ?~> "project.update.failed" - updated <- projectDAO.findOne(projectIdValidated) + updated <- projectDAO.findOne(id) js <- projectService.publicWrites(updated) } yield Ok(js) } } - def pause(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def pause(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => updatePauseStatus(id, isPaused = true) } - def resume(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def resume(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => updatePauseStatus(id, isPaused = false) } - private def updatePauseStatus(id: String, isPaused: Boolean)(implicit request: SecuredRequest[WkEnv, _]) = + private def updatePauseStatus(id: ObjectId, isPaused: Boolean)(implicit request: SecuredRequest[WkEnv, _]) = for { - projectIdValidated <- ObjectId.fromString(id) - project <- projectDAO.findOne(projectIdValidated) ?~> "project.notFound" ~> NOT_FOUND + project <- projectDAO.findOne(id) ?~> "project.notFound" ~> NOT_FOUND _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(request.identity, project._team)) ?~> "notAllowed" ~> FORBIDDEN _ <- projectDAO.updatePaused(project._id, isPaused) ?~> "project.update.failed" - updatedProject <- projectDAO.findOne(projectIdValidated) + updatedProject <- projectDAO.findOne(id) js <- projectService.publicWrites(updatedProject) } yield Ok(js) - def projectsForTaskType(taskTypeId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def projectsForTaskType(taskTypeId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - taskTypeIdValidated <- ObjectId.fromString(taskTypeId) - _ <- taskTypeDAO.findOne(taskTypeIdValidated) ?~> "taskType.notFound" ~> NOT_FOUND - projects <- projectDAO.findAllWithTaskType(taskTypeId) ?~> "project.list.failed" + _ <- taskTypeDAO.findOne(taskTypeId) ?~> "taskType.notFound" ~> NOT_FOUND + projects <- projectDAO.findAllWithTaskType(taskTypeId.toString) ?~> "project.list.failed" allCounts <- taskDAO.countPendingInstancesAndTimeByProject js <- Fox.serialCombined(projects) { project => for { @@ -138,14 +133,13 @@ class ProjectController @Inject()(projectService: ProjectService, } } - def tasksForProject(id: String, + def tasksForProject(id: ObjectId, limit: Option[Int] = None, pageNumber: Option[Int] = None, includeTotalCount: Option[Boolean]): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - projectIdValidated <- ObjectId.fromString(id) - project <- projectDAO.findOne(projectIdValidated) ?~> "project.notFound" ~> NOT_FOUND + project <- projectDAO.findOne(id) ?~> "project.notFound" ~> NOT_FOUND _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(request.identity, project._team)) ?~> "notAllowed" ~> FORBIDDEN tasks <- taskDAO.findAllByProject(project._id, limit.getOrElse(Int.MaxValue), pageNumber.getOrElse(0)) taskCount <- Fox.runIf(includeTotalCount.getOrElse(false))( @@ -160,22 +154,20 @@ class ProjectController @Inject()(projectService: ProjectService, } } - def incrementEachTasksInstances(id: String, delta: Option[Long]): Action[AnyContent] = + def incrementEachTasksInstances(id: ObjectId, delta: Option[Long]): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- bool2Fox(delta.getOrElse(1L) >= 0) ?~> "project.increaseTaskInstances.negative" - projectIdValidated <- ObjectId.fromString(id) - project <- projectDAO.findOne(projectIdValidated) ?~> "project.notFound" ~> NOT_FOUND + project <- projectDAO.findOne(id) ?~> "project.notFound" ~> NOT_FOUND _ <- taskDAO.incrementTotalInstancesOfAllWithProject(project._id, delta.getOrElse(1L)) pendingInstancesAndTime <- taskDAO.countPendingInstancesAndTimeForProject(project._id) js <- projectService.publicWritesWithStatus(project, pendingInstancesAndTime._1, pendingInstancesAndTime._2) } yield Ok(js) } - def usersWithActiveTasks(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def usersWithActiveTasks(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - projectIdValidated <- ObjectId.fromString(id) - project <- projectDAO.findOne(projectIdValidated) ?~> "project.notFound" ~> NOT_FOUND + project <- projectDAO.findOne(id) ?~> "project.notFound" ~> NOT_FOUND usersWithActiveTasks <- projectDAO.findUsersWithActiveTasks(project._id) } yield { Ok(Json.toJson(usersWithActiveTasks.map(tuple => @@ -183,10 +175,9 @@ class ProjectController @Inject()(projectService: ProjectService, } } - def transferActiveTasks(id: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => + def transferActiveTasks(id: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => for { - projectIdValidated <- ObjectId.fromString(id) - project <- projectDAO.findOne(projectIdValidated) ?~> "project.notFound" ~> NOT_FOUND + project <- projectDAO.findOne(id) ?~> "project.notFound" ~> NOT_FOUND _ <- Fox .assertTrue(userService.isTeamManagerOrAdminOf(request.identity, project._team)) ?~> "notAllowed" ~> FORBIDDEN newUserId <- (request.body \ "userId").asOpt[String].toFox ?~> "user.id.notFound" ~> NOT_FOUND @@ -194,7 +185,7 @@ class ProjectController @Inject()(projectService: ProjectService, activeAnnotations <- annotationDAO.findAllActiveForProject(project._id) _ <- Fox.serialCombined(activeAnnotations) { id => annotationService.transferAnnotationToUser(AnnotationType.Task.toString, - id.toString, + id, newUserIdValidated, request.identity) } diff --git a/app/controllers/PublicationController.scala b/app/controllers/PublicationController.scala index 049d2cc4f6..025fd5de20 100755 --- a/app/controllers/PublicationController.scala +++ b/app/controllers/PublicationController.scala @@ -22,10 +22,10 @@ class PublicationController @Inject()(publicationService: PublicationService, override def allowRemoteOrigin: Boolean = true - def read(publicationId: String): Action[AnyContent] = + def read(publicationId: ObjectId): Action[AnyContent] = sil.UserAwareAction.async { implicit request => for { - publication <- publicationDAO.findOne(ObjectId(publicationId)) ?~> "publication.notFound" ~> NOT_FOUND + publication <- publicationDAO.findOne(publicationId) ?~> "publication.notFound" ~> NOT_FOUND js <- publicationService.publicWrites(publication) } yield Ok(js) } diff --git a/app/controllers/ReportController.scala b/app/controllers/ReportController.scala index 43a89df57c..bb65e7d9a9 100644 --- a/app/controllers/ReportController.scala +++ b/app/controllers/ReportController.scala @@ -164,21 +164,19 @@ class ReportController @Inject()(reportDAO: ReportDAO, extends Controller with FoxImplicits { - def projectProgressReport(teamId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def projectProgressReport(teamId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - teamIdValidated <- ObjectId.fromString(teamId) - _ <- teamDAO.findOne(teamIdValidated) ?~> "team.notFound" ~> NOT_FOUND - entries <- reportDAO.projectProgress(teamIdValidated) + _ <- teamDAO.findOne(teamId) ?~> "team.notFound" ~> NOT_FOUND + entries <- reportDAO.projectProgress(teamId) } yield Ok(Json.toJson(entries)) } - def availableTasksReport(teamId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def availableTasksReport(teamId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - teamIdValidated <- ObjectId.fromString(teamId) - team <- teamDAO.findOne(teamIdValidated) ?~> "team.notFound" ~> NOT_FOUND + team <- teamDAO.findOne(teamId) ?~> "team.notFound" ~> NOT_FOUND users <- userDAO.findAllByTeams(List(team._id)) nonUnlistedUsers = users.filter(!_.isUnlisted) - nonAdminUsers <- Fox.filterNot(nonUnlistedUsers)(u => userService.isTeamManagerOrAdminOf(u, teamIdValidated)) + nonAdminUsers <- Fox.filterNot(nonUnlistedUsers)(u => userService.isTeamManagerOrAdminOf(u, teamId)) entries: List[AvailableTaskCountsEntry] <- getAvailableTaskCountsAndProjects(nonAdminUsers) } yield Ok(Json.toJson(entries)) } diff --git a/app/controllers/ScriptController.scala b/app/controllers/ScriptController.scala index 91f7821900..225a97734b 100644 --- a/app/controllers/ScriptController.scala +++ b/app/controllers/ScriptController.scala @@ -40,10 +40,9 @@ class ScriptController @Inject()(scriptDAO: ScriptDAO, } } - def get(scriptId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def get(scriptId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - scriptIdValidated <- ObjectId.fromString(scriptId) - script <- scriptDAO.findOne(scriptIdValidated) ?~> "script.notFound" ~> NOT_FOUND + script <- scriptDAO.findOne(scriptId) ?~> "script.notFound" ~> NOT_FOUND js <- scriptService.publicWrites(script) ?~> "script.write.failed" } yield { Ok(js) @@ -59,11 +58,10 @@ class ScriptController @Inject()(scriptDAO: ScriptDAO, } } - def update(scriptId: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => + def update(scriptId: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => withJsonBodyUsing(scriptPublicReads) { scriptFromForm => for { - scriptIdValidated <- ObjectId.fromString(scriptId) - oldScript <- scriptDAO.findOne(scriptIdValidated) ?~> "script.notFound" ~> NOT_FOUND + oldScript <- scriptDAO.findOne(scriptId) ?~> "script.notFound" ~> NOT_FOUND _ <- bool2Fox(oldScript._owner == request.identity._id) ?~> "script.notOwner" ~> FORBIDDEN _ <- scriptService.assertValidScriptName(scriptFromForm.name) updatedScript = scriptFromForm.copy(_id = oldScript._id) @@ -75,13 +73,12 @@ class ScriptController @Inject()(scriptDAO: ScriptDAO, } } - def delete(scriptId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def delete(scriptId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - scriptIdValidated <- ObjectId.fromString(scriptId) - oldScript <- scriptDAO.findOne(scriptIdValidated) ?~> "script.notFound" ~> NOT_FOUND + oldScript <- scriptDAO.findOne(scriptId) ?~> "script.notFound" ~> NOT_FOUND _ <- bool2Fox(oldScript._owner == request.identity._id) ?~> "script.notOwner" ~> FORBIDDEN - _ <- scriptDAO.deleteOne(scriptIdValidated) ?~> "script.removalFailed" - _ <- taskDAO.removeScriptFromAllTasks(scriptIdValidated) ?~> "script.removalFailed" + _ <- scriptDAO.deleteOne(scriptId) ?~> "script.removalFailed" + _ <- taskDAO.removeScriptFromAllTasks(scriptId) ?~> "script.removalFailed" } yield { Ok } diff --git a/app/controllers/TaskController.scala b/app/controllers/TaskController.scala index 76daf25323..3965c4849a 100755 --- a/app/controllers/TaskController.scala +++ b/app/controllers/TaskController.scala @@ -36,9 +36,9 @@ class TaskController @Inject()(taskCreationService: TaskCreationService, with ProtoGeometryImplicits with FoxImplicits { - def read(taskId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def read(taskId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - task <- taskDAO.findOne(ObjectId(taskId)) ?~> "task.notFound" ~> NOT_FOUND + task <- taskDAO.findOne(taskId) ?~> "task.notFound" ~> NOT_FOUND js <- taskService.publicWrites(task) } yield Ok(js) } @@ -110,35 +110,32 @@ class TaskController @Inject()(taskCreationService: TaskCreationService, } yield Ok(Json.toJson(result)) } - def update(taskId: String): Action[TaskParameters] = + def update(taskId: ObjectId): Action[TaskParameters] = sil.SecuredAction.async(validateJson[TaskParameters]) { implicit request => val params = request.body for { - taskIdValidated <- ObjectId.fromString(taskId) ?~> "task.id.invalid" - task <- taskDAO.findOne(taskIdValidated) ?~> "task.notFound" ~> NOT_FOUND + task <- taskDAO.findOne(taskId) ?~> "task.notFound" ~> NOT_FOUND project <- projectDAO.findOne(task._project) _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(request.identity, project._team)) ?~> "notAllowed" ~> FORBIDDEN _ <- taskDAO.updateTotalInstances(task._id, task.totalInstances + params.pendingInstances - task.pendingInstances) - updatedTask <- taskDAO.findOne(taskIdValidated) + updatedTask <- taskDAO.findOne(taskId) json <- taskService.publicWrites(updatedTask) } yield JsonOk(json, Messages("task.editSuccess")) } - def delete(taskId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def delete(taskId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - taskIdValidated <- ObjectId.fromString(taskId) ?~> "task.id.invalid" - task <- taskDAO.findOne(taskIdValidated) ?~> "task.notFound" ~> NOT_FOUND + task <- taskDAO.findOne(taskId) ?~> "task.notFound" ~> NOT_FOUND project <- projectDAO.findOne(task._project) _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(request.identity, project._team)) ?~> "notAllowed" _ <- taskDAO.removeOneAndItsAnnotations(task._id) ?~> "task.remove.failed" } yield JsonOk(Messages("task.removed")) } - def listTasksForType(taskTypeId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def listTasksForType(taskTypeId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - taskTypeIdValidated <- ObjectId.fromString(taskTypeId) ?~> "taskType.id.invalid" - tasks <- taskDAO.findAllByTaskType(taskTypeIdValidated) ?~> "taskType.notFound" ~> NOT_FOUND + tasks <- taskDAO.findAllByTaskType(taskTypeId) ?~> "taskType.notFound" ~> NOT_FOUND js <- Fox.serialCombined(tasks)(taskService.publicWrites(_)) } yield Ok(Json.toJson(js)) } @@ -176,25 +173,20 @@ class TaskController @Inject()(taskCreationService: TaskCreationService, } } - def assignOne(id: String, userId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def assignOne(id: ObjectId, userId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => log() { for { - taskIdValidated <- ObjectId.fromString(id) - userIdValidated <- ObjectId.fromString(userId) - assignee <- userService.findOneCached(userIdValidated) - teams <- userService.teamIdsFor(userIdValidated) - task <- taskDAO.findOne(taskIdValidated) + assignee <- userService.findOneCached(userId) + teams <- userService.teamIdsFor(userId) + task <- taskDAO.findOne(id) project <- projectDAO.findOne(task._project) _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(request.identity, project._team)) ?~> "notAllowed" _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(request.identity, assignee)) ?~> "notAllowed" - (_, initializingAnnotationId) <- taskDAO - .assignOneTo(taskIdValidated, userIdValidated, teams) ?~> "task.unavailable" - insertedAnnotationBox <- annotationService - .createAnnotationFor(assignee, taskIdValidated, initializingAnnotationId) - .futureBox + (_, initializingAnnotationId) <- taskDAO.assignOneTo(id, userId, teams) ?~> "task.unavailable" + insertedAnnotationBox <- annotationService.createAnnotationFor(assignee, id, initializingAnnotationId).futureBox _ <- annotationService.abortInitializedAnnotationOnFailure(initializingAnnotationId, insertedAnnotationBox) _ <- insertedAnnotationBox.toFox - taskUpdated <- taskDAO.findOne(taskIdValidated) + taskUpdated <- taskDAO.findOne(id) taskJson <- taskService.publicWrites(taskUpdated)(GlobalAccessContext) } yield Ok(taskJson) } diff --git a/app/controllers/TaskTypeController.scala b/app/controllers/TaskTypeController.scala index 02cb856d80..b40e3f96c9 100755 --- a/app/controllers/TaskTypeController.scala +++ b/app/controllers/TaskTypeController.scala @@ -47,10 +47,9 @@ class TaskTypeController @Inject()(taskTypeDAO: TaskTypeDAO, } } - def get(taskTypeId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def get(taskTypeId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - taskTypeIdValidated <- ObjectId.fromString(taskTypeId) ?~> "taskType.id.invalid" - taskType <- taskTypeDAO.findOne(taskTypeIdValidated) ?~> "taskType.notFound" ~> NOT_FOUND + taskType <- taskTypeDAO.findOne(taskTypeId) ?~> "taskType.notFound" ~> NOT_FOUND _ <- Fox.assertTrue(userService.isTeamManagerOrAdminOf(request.identity, taskType._team)) js <- taskTypeService.publicWrites(taskType) } yield Ok(js) @@ -63,11 +62,10 @@ class TaskTypeController @Inject()(taskTypeDAO: TaskTypeDAO, } yield Ok(Json.toJson(js)) } - def update(taskTypeId: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => + def update(taskTypeId: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => withJsonBodyUsing(taskTypePublicReads) { taskTypeFromForm => for { - taskTypeIdValidated <- ObjectId.fromString(taskTypeId) ?~> "taskType.id.invalid" - taskType <- taskTypeDAO.findOne(taskTypeIdValidated) ?~> "taskType.notFound" ~> NOT_FOUND + taskType <- taskTypeDAO.findOne(taskTypeId) ?~> "taskType.notFound" ~> NOT_FOUND _ <- bool2Fox(taskTypeFromForm.tracingType == taskType.tracingType) ?~> "taskType.tracingTypeImmutable" _ <- bool2Fox(taskTypeFromForm.settings.magRestrictions == taskType.settings.magRestrictions) ?~> "taskType.magRestrictionsImmutable" updatedTaskType = taskTypeFromForm.copy(_id = taskType._id) @@ -86,14 +84,13 @@ class TaskTypeController @Inject()(taskTypeDAO: TaskTypeDAO, } } - def delete(taskTypeId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def delete(taskTypeId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - taskTypeIdValidated <- ObjectId.fromString(taskTypeId) ?~> "taskType.id.invalid" - taskType <- taskTypeDAO.findOne(taskTypeIdValidated) ?~> "taskType.notFound" ~> NOT_FOUND + taskType <- taskTypeDAO.findOne(taskTypeId) ?~> "taskType.notFound" ~> NOT_FOUND _ <- Fox .assertTrue(userService.isTeamManagerOrAdminOf(request.identity, taskType._team)) ?~> "notAllowed" ~> FORBIDDEN - _ <- taskTypeDAO.deleteOne(taskTypeIdValidated) ?~> "taskType.deleteFailure" - _ <- taskDAO.removeAllWithTaskTypeAndItsAnnotations(taskTypeIdValidated) ?~> "taskType.deleteFailure" + _ <- taskTypeDAO.deleteOne(taskTypeId) ?~> "taskType.deleteFailure" + _ <- taskDAO.removeAllWithTaskTypeAndItsAnnotations(taskTypeId) ?~> "taskType.deleteFailure" _ = logger.info(s"TaskType $taskTypeId was deleted.") } yield JsonOk(Messages("taskType.deleteSuccess", taskType.summary)) } diff --git a/app/controllers/TeamController.scala b/app/controllers/TeamController.scala index 47e22bec89..f280908503 100755 --- a/app/controllers/TeamController.scala +++ b/app/controllers/TeamController.scala @@ -29,16 +29,15 @@ class TeamController @Inject()(teamDAO: TeamDAO, userDAO: UserDAO, teamService: } yield Ok(Json.toJson(js)) } - def delete(id: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def delete(id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - teamIdValidated <- ObjectId.fromString(id) _ <- bool2Fox(request.identity.isAdmin) ?~> "user.noAdmin" ~> FORBIDDEN - team <- teamDAO.findOne(teamIdValidated) ?~> "team.notFound" ~> NOT_FOUND + team <- teamDAO.findOne(id) ?~> "team.notFound" ~> NOT_FOUND _ <- bool2Fox(!team.isOrganizationTeam) ?~> "team.delete.organizationTeam" ~> FORBIDDEN - _ <- teamService.assertNoReferences(teamIdValidated) ?~> "team.delete.inUse" ~> FORBIDDEN - _ <- teamDAO.deleteOne(teamIdValidated) - _ <- userDAO.removeTeamFromAllUsers(teamIdValidated) - _ <- teamDAO.removeTeamFromAllDatasetsAndFolders(teamIdValidated) + _ <- teamService.assertNoReferences(id) ?~> "team.delete.inUse" ~> FORBIDDEN + _ <- teamDAO.deleteOne(id) + _ <- userDAO.removeTeamFromAllUsers(id) + _ <- teamDAO.removeTeamFromAllDatasetsAndFolders(id) } yield JsonOk(Messages("team.deleted")) } diff --git a/app/controllers/TimeController.scala b/app/controllers/TimeController.scala index 95216464d5..7d1416a554 100644 --- a/app/controllers/TimeController.scala +++ b/app/controllers/TimeController.scala @@ -27,11 +27,10 @@ class TimeController @Inject()(userService: UserService, with FoxImplicits { // Called by webknossos-libs client. Sums monthly. Includes exploratives - def userLoggedTime(userId: String): Action[AnyContent] = + def userLoggedTime(userId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - userIdValidated <- ObjectId.fromString(userId) ?~> "user.id.invalid" - user <- userDAO.findOne(userIdValidated) ?~> "user.notFound" ~> NOT_FOUND + user <- userDAO.findOne(userId) ?~> "user.notFound" ~> NOT_FOUND _ <- Fox.assertTrue(userService.isEditableBy(user, request.identity)) ?~> "notAllowed" ~> FORBIDDEN timeSpansBox: Box[List[TimeSpan]] <- timeSpanDAO.findAllByUser(user._id).futureBox timesGrouped: Map[Month, Duration] = timeSpanService.sumTimespansPerInterval(TimeSpan.groupByMonth, @@ -47,7 +46,7 @@ class TimeController @Inject()(userService: UserService, } } - def timeSummedByAnnotationForUser(userId: String, + def timeSummedByAnnotationForUser(userId: ObjectId, start: Long, end: Long, annotationTypes: String, @@ -55,11 +54,10 @@ class TimeController @Inject()(userService: UserService, projectIds: Option[String]): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - userIdValidated <- ObjectId.fromString(userId) projectIdsValidated <- ObjectId.fromCommaSeparated(projectIds) annotationTypesValidated <- AnnotationType.fromCommaSeparated(annotationTypes) ?~> "invalidAnnotationType" annotationStatesValidated <- AnnotationState.fromCommaSeparated(annotationStates) ?~> "invalidAnnotationState" - user <- userService.findOneCached(userIdValidated) ?~> "user.notFound" ~> NOT_FOUND + user <- userService.findOneCached(userId) ?~> "user.notFound" ~> NOT_FOUND isTeamManagerOrAdmin <- userService.isTeamManagerOrAdminOf(request.identity, user) _ <- bool2Fox(isTeamManagerOrAdmin || user._id == request.identity._id) ?~> "user.notAuthorised" ~> FORBIDDEN timesByAnnotation <- timeSpanDAO.summedByAnnotationForUser(user._id, @@ -71,7 +69,7 @@ class TimeController @Inject()(userService: UserService, } yield Ok(timesByAnnotation) } - def timeSpansOfUser(userId: String, + def timeSpansOfUser(userId: ObjectId, start: Long, end: Long, annotationTypes: String, @@ -79,11 +77,10 @@ class TimeController @Inject()(userService: UserService, projectIds: Option[String]): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - userIdValidated <- ObjectId.fromString(userId) projectIdsValidated <- ObjectId.fromCommaSeparated(projectIds) annotationTypesValidated <- AnnotationType.fromCommaSeparated(annotationTypes) ?~> "invalidAnnotationType" annotationStatesValidated <- AnnotationState.fromCommaSeparated(annotationStates) ?~> "invalidAnnotationState" - user <- userService.findOneCached(userIdValidated) ?~> "user.notFound" ~> NOT_FOUND + user <- userService.findOneCached(userId) ?~> "user.notFound" ~> NOT_FOUND isTeamManagerOrAdmin <- userService.isTeamManagerOrAdminOf(request.identity, user) _ <- bool2Fox(isTeamManagerOrAdmin || user._id == request.identity._id) ?~> "user.notAuthorised" ~> FORBIDDEN timeSpansJs <- timeSpanDAO.findAllByUserWithTask(user._id, diff --git a/app/controllers/UserController.scala b/app/controllers/UserController.scala index 059b870212..466ccbed5c 100755 --- a/app/controllers/UserController.scala +++ b/app/controllers/UserController.scala @@ -43,11 +43,10 @@ class UserController @Inject()(userService: UserService, } } - def user(userId: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => + def user(userId: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request => log() { for { - userIdValidated <- ObjectId.fromString(userId) ?~> "user.id.invalid" - user <- userDAO.findOne(userIdValidated) ?~> "user.notFound" ~> NOT_FOUND + user <- userDAO.findOne(userId) ?~> "user.notFound" ~> NOT_FOUND _ <- Fox.assertTrue(userService.isEditableBy(user, request.identity)) ?~> "notAllowed" ~> FORBIDDEN js <- userService.publicWrites(user, request.identity) } yield Ok(js) @@ -104,25 +103,24 @@ class UserController @Inject()(userService: UserService, } } - def userAnnotations(userId: String, + def userAnnotations(userId: ObjectId, isFinished: Option[Boolean], limit: Option[Int], pageNumber: Option[Int] = None, includeTotalCount: Option[Boolean] = None): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - userIdValidated <- ObjectId.fromString(userId) ?~> "user.id.invalid" - user <- userDAO.findOne(userIdValidated) ?~> "user.notFound" ~> NOT_FOUND + user <- userDAO.findOne(userId) ?~> "user.notFound" ~> NOT_FOUND _ <- Fox.assertTrue(userService.isEditableBy(user, request.identity)) ?~> "notAllowed" ~> FORBIDDEN annotations <- annotationDAO.findAllListableExplorationals( isFinished, - Some(userIdValidated), + Some(userId), filterOwnedOrShared = false, limit.getOrElse(annotationService.DefaultAnnotationListLimit), pageNumber.getOrElse(0) ) annotationCount <- Fox.runIf(includeTotalCount.getOrElse(false))( - annotationDAO.countAllFor(userIdValidated, isFinished, AnnotationType.Explorational)) + annotationDAO.countAllFor(userId, isFinished, AnnotationType.Explorational)) jsonList = annotations.map(annotationService.writeCompactInfo) } yield { val result = Ok(Json.toJson(jsonList)) @@ -133,23 +131,22 @@ class UserController @Inject()(userService: UserService, } } - def userTasks(userId: String, + def userTasks(userId: ObjectId, isFinished: Option[Boolean], limit: Option[Int], pageNumber: Option[Int] = None, includeTotalCount: Option[Boolean] = None): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { - userIdValidated <- ObjectId.fromString(userId) ?~> "user.id.invalid" - user <- userDAO.findOne(userIdValidated) ?~> "user.notFound" ~> NOT_FOUND + user <- userDAO.findOne(userId) ?~> "user.notFound" ~> NOT_FOUND _ <- Fox.assertTrue(userService.isEditableBy(user, request.identity)) ?~> "notAllowed" ~> FORBIDDEN - annotations <- annotationDAO.findAllFor(userIdValidated, + annotations <- annotationDAO.findAllFor(userId, isFinished, AnnotationType.Task, limit.getOrElse(annotationService.DefaultAnnotationListLimit), pageNumber.getOrElse(0)) annotationCount <- Fox.runIf(includeTotalCount.getOrElse(false))( - annotationDAO.countAllFor(userIdValidated, isFinished, AnnotationType.Task)) + annotationDAO.countAllFor(userId, isFinished, AnnotationType.Task)) jsonList <- Fox.serialCombined(annotations)(a => annotationService.publicWrites(a, Some(request.identity))) } yield { val result = Ok(Json.toJson(jsonList)) @@ -254,7 +251,7 @@ class UserController @Inject()(userService: UserService, } yield () } else Fox.successful(()) - def update(userId: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => + def update(userId: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => val issuingUser = request.identity withJsonBodyUsing(userUpdateReader) { case (firstNameOpt, @@ -267,8 +264,7 @@ class UserController @Inject()(userService: UserService, experiencesOpt, lastTaskTypeIdOpt) => for { - userIdValidated <- ObjectId.fromString(userId) ?~> "user.id.invalid" - user <- userDAO.findOne(userIdValidated) ?~> "user.notFound" ~> NOT_FOUND + user <- userDAO.findOne(userId) ?~> "user.notFound" ~> NOT_FOUND oldExperience <- userService.experiencesFor(user._id) oldAssignedMemberships <- userService.teamMembershipsFor(user._id) firstName = firstNameOpt.getOrElse(user.firstName) @@ -310,45 +306,43 @@ class UserController @Inject()(userService: UserService, updatedTeams, trimmedExperiences, lastTaskTypeId) - updatedUser <- userDAO.findOne(userIdValidated) + updatedUser <- userDAO.findOne(userId) updatedJs <- userService.publicWrites(updatedUser, request.identity) } yield Ok(updatedJs) } } - def updateLastTaskTypeId(userId: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => - val issuingUser = request.identity - withJsonBodyUsing((__ \ "lastTaskTypeId").readNullable[String]) { lastTaskTypeId => - for { - userIdValidated <- ObjectId.fromString(userId) ?~> "user.id.invalid" - user <- userDAO.findOne(userIdValidated) ?~> "user.notFound" ~> NOT_FOUND - isEditable <- userService.isEditableBy(user, request.identity) ?~> "notAllowed" ~> FORBIDDEN - _ <- bool2Fox(isEditable | user._id == issuingUser._id) - _ <- userService.updateLastTaskTypeId(user, lastTaskTypeId) - updatedUser <- userDAO.findOne(userIdValidated) - updatedJs <- userService.publicWrites(updatedUser, request.identity) - } yield Ok(updatedJs) - } + def updateLastTaskTypeId(userId: ObjectId): Action[JsValue] = sil.SecuredAction.async(parse.json) { + implicit request => + val issuingUser = request.identity + withJsonBodyUsing((__ \ "lastTaskTypeId").readNullable[String]) { lastTaskTypeId => + for { + user <- userDAO.findOne(userId) ?~> "user.notFound" ~> NOT_FOUND + isEditable <- userService.isEditableBy(user, request.identity) ?~> "notAllowed" ~> FORBIDDEN + _ <- bool2Fox(isEditable | user._id == issuingUser._id) + _ <- userService.updateLastTaskTypeId(user, lastTaskTypeId) + updatedUser <- userDAO.findOne(userId) + updatedJs <- userService.publicWrites(updatedUser, request.identity) + } yield Ok(updatedJs) + } } - def updateNovelUserExperienceInfos(userId: String): Action[JsObject] = + def updateNovelUserExperienceInfos(userId: ObjectId): Action[JsObject] = sil.SecuredAction.async(validateJson[JsObject]) { implicit request => for { - userIdValidated <- ObjectId.fromString(userId) ?~> "user.id.invalid" - _ <- bool2Fox(request.identity._id == userIdValidated) ?~> "notAllowed" ~> FORBIDDEN + _ <- bool2Fox(request.identity._id == userId) ?~> "notAllowed" ~> FORBIDDEN _ <- multiUserDAO.updateNovelUserExperienceInfos(request.identity._multiUser, request.body) - updatedUser <- userDAO.findOne(userIdValidated) + updatedUser <- userDAO.findOne(userId) updatedJs <- userService.publicWrites(updatedUser, request.identity) } yield Ok(updatedJs) } - def updateSelectedTheme(userId: String): Action[Theme] = + def updateSelectedTheme(userId: ObjectId): Action[Theme] = sil.SecuredAction.async(validateJson[Theme]) { implicit request => for { - userIdValidated <- ObjectId.fromString(userId) ?~> "user.id.invalid" - _ <- bool2Fox(request.identity._id == userIdValidated) ?~> "notAllowed" ~> FORBIDDEN + _ <- bool2Fox(request.identity._id == userId) ?~> "notAllowed" ~> FORBIDDEN _ <- multiUserDAO.updateSelectedTheme(request.identity._multiUser, request.body) - updatedUser <- userDAO.findOne(userIdValidated) + updatedUser <- userDAO.findOne(userId) updatedJs <- userService.publicWrites(updatedUser, request.identity) } yield Ok(updatedJs) } diff --git a/app/controllers/VoxelyticsController.scala b/app/controllers/VoxelyticsController.scala index 6ee4b6d622..65cdf27fc7 100644 --- a/app/controllers/VoxelyticsController.scala +++ b/app/controllers/VoxelyticsController.scala @@ -110,22 +110,21 @@ class VoxelyticsController @Inject()( })) } yield workflowsAsJson - def getWorkflow(workflowHash: String, runId: Option[String]): Action[AnyContent] = + def getWorkflow(workflowHash: String, runIdOpt: Option[ObjectId]): Action[AnyContent] = sil.SecuredAction.async { implicit request => for { _ <- bool2Fox(wkConf.Features.voxelyticsEnabled) ?~> "voxelytics.disabled" - runIdValidatedOpt <- Fox.runOptional(runId)(ObjectId.fromString(_)) // Auth is implemented in `voxelyticsDAO.findRuns` workflow <- voxelyticsDAO.findWorkflowByHashAndOrganization(request.identity._organization, workflowHash) ?~> "voxelytics.workflowNotFound" ~> NOT_FOUND // Fetching all runs for this workflow or specified run // If all runs are fetched, a combined version of the workflow report // will be returned that contains the information of the most recent task runs - runs <- runIdValidatedOpt + runs <- runIdOpt .map( - runIdValidated => + runId => voxelyticsDAO.findRuns(request.identity, - Some(List(runIdValidated)), + Some(List(runId)), Some(workflowHash), conf.staleTimeout, allowUnlisted = true)) @@ -221,14 +220,13 @@ class VoxelyticsController @Inject()( } yield Ok } - def getChunkStatistics(workflowHash: String, runIdOpt: Option[String], taskName: String): Action[AnyContent] = + def getChunkStatistics(workflowHash: String, runIdOpt: Option[ObjectId], taskName: String): Action[AnyContent] = sil.SecuredAction.async { implicit request => { for { _ <- bool2Fox(wkConf.Features.voxelyticsEnabled) ?~> "voxelytics.disabled" - runIdOptValidated <- Fox.runOptional(runIdOpt)(ObjectId.fromString) runs <- voxelyticsDAO.findRuns(request.identity, - runIdOptValidated.map(List(_)), + runIdOpt.map(List(_)), Some(workflowHash), conf.staleTimeout, allowUnlisted = true) @@ -239,16 +237,15 @@ class VoxelyticsController @Inject()( } def getArtifactChecksums(workflowHash: String, - runIdOpt: Option[String], + runIdOpt: Option[ObjectId], taskName: String, artifactName: Option[String]): Action[AnyContent] = sil.SecuredAction.async { implicit request => { for { _ <- bool2Fox(wkConf.Features.voxelyticsEnabled) ?~> "voxelytics.disabled" - runIdOptValidated <- Fox.runOptional(runIdOpt)(ObjectId.fromString) runs <- voxelyticsDAO.findRuns(request.identity, - runIdOptValidated.map(List(_)), + runIdOpt.map(List(_)), Some(workflowHash), conf.staleTimeout, allowUnlisted = true) @@ -268,7 +265,7 @@ class VoxelyticsController @Inject()( } yield Ok } - def getLogs(runId: String, + def getLogs(runId: ObjectId, taskName: Option[String], minLevel: Option[String], startTimestamp: Long, @@ -278,9 +275,8 @@ class VoxelyticsController @Inject()( { for { _ <- bool2Fox(wkConf.Features.voxelyticsEnabled) ?~> "voxelytics.disabled" - runIdValidated <- ObjectId.fromString(runId) - runName <- voxelyticsDAO.getRunNameById(runIdValidated, request.identity._organization) - _ <- voxelyticsService.checkAuth(runIdValidated, request.identity) ~> UNAUTHORIZED + runName <- voxelyticsDAO.getRunNameById(runId, request.identity._organization) + _ <- voxelyticsService.checkAuth(runId, request.identity) ~> UNAUTHORIZED organization <- organizationDAO.findOne(request.identity._organization) logEntries <- lokiClient.queryLogsBatched( runName, diff --git a/app/controllers/WKRemoteDataStoreController.scala b/app/controllers/WKRemoteDataStoreController.scala index 750e946556..9da2737172 100644 --- a/app/controllers/WKRemoteDataStoreController.scala +++ b/app/controllers/WKRemoteDataStoreController.scala @@ -242,27 +242,25 @@ class WKRemoteDataStoreController @Inject()( } } - def jobExportProperties(name: String, key: String, jobId: String): Action[AnyContent] = Action.async { + def jobExportProperties(name: String, key: String, jobId: ObjectId): Action[AnyContent] = Action.async { implicit request => dataStoreService.validateAccess(name, key) { _ => for { - jobIdValidated <- ObjectId.fromString(jobId) - job <- jobDAO.findOne(jobIdValidated)(GlobalAccessContext) + job <- jobDAO.findOne(jobId)(GlobalAccessContext) jobOwner <- userDAO.findOne(job._owner)(GlobalAccessContext) organization <- organizationDAO.findOne(jobOwner._organization)(GlobalAccessContext) latestRunId <- job.latestRunId.toFox ?~> "job.notRun" exportFileName <- job.exportFileName.toFox ?~> "job.noExportFileName" - jobExportProperties = JobExportProperties(jobId, latestRunId, organization._id, exportFileName) + jobExportProperties = JobExportProperties(jobId.toString, latestRunId, organization._id, exportFileName) } yield Ok(Json.toJson(jobExportProperties)) } } - def findCredential(name: String, key: String, credentialId: String): Action[AnyContent] = Action.async { + def findCredential(name: String, key: String, credentialId: ObjectId): Action[AnyContent] = Action.async { implicit request => dataStoreService.validateAccess(name, key) { _ => for { - credentialIdValidated <- ObjectId.fromString(credentialId) - credential <- credentialDAO.findOne(credentialIdValidated) + credential <- credentialDAO.findOne(credentialId) } yield Ok(Json.toJson(credential)) } } diff --git a/app/controllers/WKRemoteWorkerController.scala b/app/controllers/WKRemoteWorkerController.scala index b9edd6bce6..a23e81560c 100644 --- a/app/controllers/WKRemoteWorkerController.scala +++ b/app/controllers/WKRemoteWorkerController.scala @@ -72,26 +72,24 @@ class WKRemoteWorkerController @Inject()(jobDAO: JobDAO, lowPriorityOrEmpty ++ highPriorityOrEmpty } - def updateJobStatus(key: String, id: String): Action[JobStatus] = Action.async(validateJson[JobStatus]) { + def updateJobStatus(key: String, id: ObjectId): Action[JobStatus] = Action.async(validateJson[JobStatus]) { implicit request => for { _ <- workerDAO.findOneByKey(key) ?~> "jobs.worker.notFound" - jobIdParsed <- ObjectId.fromString(id) - jobBeforeChange <- jobDAO.findOne(jobIdParsed)(GlobalAccessContext) - _ <- jobDAO.updateStatus(jobIdParsed, request.body) - jobAfterChange <- jobDAO.findOne(jobIdParsed)(GlobalAccessContext) + jobBeforeChange <- jobDAO.findOne(id)(GlobalAccessContext) + _ <- jobDAO.updateStatus(id, request.body) + jobAfterChange <- jobDAO.findOne(id)(GlobalAccessContext) _ = jobService.trackStatusChange(jobBeforeChange, jobAfterChange) _ <- jobService.cleanUpIfFailed(jobAfterChange) } yield Ok } - def attachVoxelyticsWorkflow(key: String, id: String): Action[String] = Action.async(validateJson[String]) { + def attachVoxelyticsWorkflow(key: String, id: ObjectId): Action[String] = Action.async(validateJson[String]) { implicit request => for { _ <- workerDAO.findOneByKey(key) ?~> "jobs.worker.notFound" _ <- bool2Fox(wkConf.Features.voxelyticsEnabled) ?~> "voxelytics.disabled" - jobIdParsed <- ObjectId.fromString(id) - organizationId <- jobDAO.organizationIdForJobId(jobIdParsed) ?~> "job.notFound" + organizationId <- jobDAO.organizationIdForJobId(id) ?~> "job.notFound" workflowHash = request.body existingWorkflowBox <- voxelyticsDAO.findWorkflowByHashAndOrganization(organizationId, workflowHash).futureBox _ <- existingWorkflowBox match { @@ -99,19 +97,18 @@ class WKRemoteWorkerController @Inject()(jobDAO: JobDAO, case Empty => voxelyticsDAO.upsertWorkflow(workflowHash, "initializing worker workflow", organizationId) case f: Failure => f.toFox } - _ <- jobDAO.updateVoxelyticsWorkflow(jobIdParsed, request.body) + _ <- jobDAO.updateVoxelyticsWorkflow(id, request.body) } yield Ok } - def attachDatasetToInference(key: String, id: String): Action[String] = + def attachDatasetToInference(key: String, id: ObjectId): Action[String] = Action.async(validateJson[String]) { implicit request => implicit val ctx: DBAccessContext = GlobalAccessContext for { _ <- workerDAO.findOneByKey(key) ?~> "jobs.worker.notFound" - jobIdParsed <- ObjectId.fromString(id) - organizationId <- jobDAO.organizationIdForJobId(jobIdParsed) ?~> "job.notFound" + organizationId <- jobDAO.organizationIdForJobId(id) ?~> "job.notFound" dataset <- datasetDAO.findOneByDirectoryNameAndOrganization(request.body, organizationId) - aiInference <- aiInferenceDAO.findOneByJobId(jobIdParsed) ?~> "aiInference.notFound" + aiInference <- aiInferenceDAO.findOneByJobId(id) ?~> "aiInference.notFound" _ <- aiInferenceDAO.updateDataset(aiInference._id, dataset._id) } yield Ok } diff --git a/app/models/annotation/AnnotationIdentifier.scala b/app/models/annotation/AnnotationIdentifier.scala index 91cb054d2c..b246f884b1 100644 --- a/app/models/annotation/AnnotationIdentifier.scala +++ b/app/models/annotation/AnnotationIdentifier.scala @@ -15,9 +15,8 @@ case class AnnotationIdentifier(annotationType: AnnotationType, identifier: Obje object AnnotationIdentifier extends FoxImplicits { - def parse(typ: String, id: String)(implicit ec: ExecutionContext): Fox[AnnotationIdentifier] = + def parse(typ: String, id: ObjectId)(implicit ec: ExecutionContext): Fox[AnnotationIdentifier] = for { - identifier <- ObjectId.fromString(id) typ <- AnnotationType.fromString(typ) ?~> ("Invalid AnnotationType: " + typ) - } yield AnnotationIdentifier(typ, identifier) + } yield AnnotationIdentifier(typ, id) } diff --git a/app/models/annotation/AnnotationInformationProvider.scala b/app/models/annotation/AnnotationInformationProvider.scala index 9d7e4dd35f..09c64bede9 100755 --- a/app/models/annotation/AnnotationInformationProvider.scala +++ b/app/models/annotation/AnnotationInformationProvider.scala @@ -19,27 +19,26 @@ class AnnotationInformationProvider @Inject()( extends play.api.http.Status with FoxImplicits { - def provideAnnotation(typ: String, id: String, user: User)(implicit ctx: DBAccessContext): Fox[Annotation] = + def provideAnnotation(typ: String, id: ObjectId, user: User)(implicit ctx: DBAccessContext): Fox[Annotation] = provideAnnotation(typ, id, Some(user)) - def provideAnnotation(typ: String, id: String, userOpt: Option[User])( + def provideAnnotation(typ: String, id: ObjectId, userOpt: Option[User])( implicit ctx: DBAccessContext): Fox[Annotation] = for { annotationIdentifier <- AnnotationIdentifier.parse(typ, id) annotation <- provideAnnotation(annotationIdentifier, userOpt) ?~> "annotation.notFound" } yield annotation - def provideAnnotation(id: String, userOpt: Option[User])(implicit ctx: DBAccessContext): Fox[Annotation] = + def provideAnnotation(id: ObjectId, userOpt: Option[User])(implicit ctx: DBAccessContext): Fox[Annotation] = // this function only supports task/explorational look ups, not compound annotations for { - annotationIdValidated <- ObjectId.fromString(id) - _annotation <- annotationDAO.findOne(annotationIdValidated) ?~> "annotation.notFound" + _annotation <- annotationDAO.findOne(id) ?~> "annotation.notFound" typ = if (_annotation._task.isEmpty) AnnotationType.Explorational else AnnotationType.Task - annotationIdentifier = AnnotationIdentifier(typ, annotationIdValidated) + annotationIdentifier = AnnotationIdentifier(typ, id) annotation <- provideAnnotation(annotationIdentifier, userOpt) ?~> "annotation.notFound" } yield annotation - def provideAnnotation(id: String, user: User)(implicit ctx: DBAccessContext): Fox[Annotation] = + def provideAnnotation(id: ObjectId, user: User)(implicit ctx: DBAccessContext): Fox[Annotation] = provideAnnotation(id, Some(user)) def provideAnnotation(annotationIdentifier: AnnotationIdentifier, userOpt: Option[User])( @@ -52,7 +51,7 @@ class AnnotationInformationProvider @Inject()( } else Fox.successful(annotation.name) - def restrictionsFor(typ: String, id: String)(implicit ctx: DBAccessContext): Fox[AnnotationRestrictions] = + def restrictionsFor(typ: String, id: ObjectId)(implicit ctx: DBAccessContext): Fox[AnnotationRestrictions] = for { annotationIdentifier <- AnnotationIdentifier.parse(typ, id) restrictions <- restrictionsFor(annotationIdentifier) diff --git a/app/models/annotation/AnnotationService.scala b/app/models/annotation/AnnotationService.scala index 3b333d7bf7..72f2fb53bc 100755 --- a/app/models/annotation/AnnotationService.scala +++ b/app/models/annotation/AnnotationService.scala @@ -828,7 +828,7 @@ class AnnotationService @Inject()( } } - def transferAnnotationToUser(typ: String, id: String, userId: ObjectId, issuingUser: User)( + def transferAnnotationToUser(typ: String, id: ObjectId, userId: ObjectId, issuingUser: User)( implicit ctx: DBAccessContext): Fox[Annotation] = for { annotation <- annotationInformationProvider.provideAnnotation(typ, id, issuingUser) ?~> "annotation.notFound" diff --git a/build.sbt b/build.sbt index 4c8a23c213..fe85824220 100644 --- a/build.sbt +++ b/build.sbt @@ -33,6 +33,9 @@ Compile / console / scalacOptions -= "-Xlint:unused" scapegoatIgnoredFiles := Seq(".*/Tables.scala", ".*/Routes.scala", ".*/.*mail.*template\\.scala") scapegoatDisabledInspections := Seq("FinalModifierOnCaseClass", "UnusedMethodParameter", "UnsafeTraversableMethods") +// Allow path binding for ObjectId +routesImport += "com.scalableminds.util.objectid.ObjectId" + lazy val commonSettings = Seq( resolvers ++= DependencyResolvers.dependencyResolvers, Compile / doc / sources := Seq.empty, diff --git a/conf/webknossos.latest.routes b/conf/webknossos.latest.routes index 76e22722a2..be9cf811e9 100644 --- a/conf/webknossos.latest.routes +++ b/conf/webknossos.latest.routes @@ -13,9 +13,9 @@ POST /triggers/initialData GET /maintenances/listCurrentAndUpcoming controllers.MaintenanceController.listCurrentAndUpcoming() GET /maintenances/listAll controllers.MaintenanceController.listAll() POST /maintenances controllers.MaintenanceController.create() -GET /maintenances/:id controllers.MaintenanceController.readOne(id) -PUT /maintenances/:id controllers.MaintenanceController.update(id) -DELETE /maintenances/:id controllers.MaintenanceController.delete(id) +GET /maintenances/:id controllers.MaintenanceController.readOne(id: ObjectId) +PUT /maintenances/:id controllers.MaintenanceController.update(id: ObjectId) +DELETE /maintenances/:id controllers.MaintenanceController.delete(id: ObjectId) POST /maintenances controllers.MaintenanceController.create() POST /maintenances/adHoc controllers.MaintenanceController.createAdHocMaintenance() @@ -27,7 +27,7 @@ GET /auth/token DELETE /auth/token controllers.AuthenticationController.deleteToken() GET /auth/switch controllers.AuthenticationController.switchMultiUser(to: String) POST /auth/switchOrganization/:organizationId controllers.AuthenticationController.switchOrganization(organizationId: String) -GET /auth/accessibleBySwitching controllers.AuthenticationController.accessibleBySwitching(datasetId: Option[String], annotationId: Option[String], workflowHash: Option[String]) +GET /auth/accessibleBySwitching controllers.AuthenticationController.accessibleBySwitching(datasetId: Option[ObjectId], annotationId: Option[String], workflowHash: Option[String]) POST /auth/sendInvites controllers.AuthenticationController.sendInvites() POST /auth/startResetPassword controllers.AuthenticationController.handleStartResetPassword() POST /auth/changePassword controllers.AuthenticationController.changePassword() @@ -43,10 +43,10 @@ POST /auth/createUserInOrganization/:organizationId # Configurations GET /user/userConfiguration controllers.ConfigurationController.read() PUT /user/userConfiguration controllers.ConfigurationController.update() -POST /datasetConfigurations/:datasetId controllers.ConfigurationController.readDatasetViewConfiguration(datasetId: String, sharingToken: Option[String]) -PUT /datasetConfigurations/:datasetId controllers.ConfigurationController.updateDatasetViewConfiguration(datasetId: String) -GET /datasetConfigurations/default/:datasetId controllers.ConfigurationController.readDatasetAdminViewConfiguration(datasetId: String) -PUT /datasetConfigurations/default/:datasetId controllers.ConfigurationController.updateDatasetAdminViewConfiguration(datasetId: String) +POST /datasetConfigurations/:datasetId controllers.ConfigurationController.readDatasetViewConfiguration(datasetId: ObjectId, sharingToken: Option[String]) +PUT /datasetConfigurations/:datasetId controllers.ConfigurationController.updateDatasetViewConfiguration(datasetId: ObjectId) +GET /datasetConfigurations/default/:datasetId controllers.ConfigurationController.readDatasetAdminViewConfiguration(datasetId: ObjectId) +PUT /datasetConfigurations/default/:datasetId controllers.ConfigurationController.updateDatasetAdminViewConfiguration(datasetId: ObjectId) # Users POST /user/tasks/request controllers.TaskController.request() @@ -56,52 +56,52 @@ GET /users GET /user controllers.UserController.current() GET /user/tasks controllers.UserController.tasks(isFinished: Option[Boolean], limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) GET /user/annotations controllers.UserController.annotations(isFinished: Option[Boolean], limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) -GET /users/:id controllers.UserController.user(id: String) -PATCH /users/:id controllers.UserController.update(id: String) -PUT /users/:id/taskTypeId controllers.UserController.updateLastTaskTypeId(id: String) -PUT /users/:id/novelUserExperienceInfos controllers.UserController.updateNovelUserExperienceInfos(id: String) -PUT /users/:id/selectedTheme controllers.UserController.updateSelectedTheme(id: String) -GET /users/:id/tasks controllers.UserController.userTasks(id: String, isFinished: Option[Boolean], limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) -GET /users/:id/annotations controllers.UserController.userAnnotations(id: String, isFinished: Option[Boolean], limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) -GET /users/:id/loggedTime controllers.TimeController.userLoggedTime(id: String) +GET /users/:id controllers.UserController.user(id: ObjectId) +PATCH /users/:id controllers.UserController.update(id: ObjectId) +PUT /users/:id/taskTypeId controllers.UserController.updateLastTaskTypeId(id: ObjectId) +PUT /users/:id/novelUserExperienceInfos controllers.UserController.updateNovelUserExperienceInfos(id: ObjectId) +PUT /users/:id/selectedTheme controllers.UserController.updateSelectedTheme(id: ObjectId) +GET /users/:id/tasks controllers.UserController.userTasks(id: ObjectId, isFinished: Option[Boolean], limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) +GET /users/:id/annotations controllers.UserController.userAnnotations(id: ObjectId, isFinished: Option[Boolean], limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) +GET /users/:id/loggedTime controllers.TimeController.userLoggedTime(id: ObjectId) # Team GET /teams controllers.TeamController.list(isEditable: Option[Boolean]) POST /teams controllers.TeamController.create() -DELETE /teams/:id controllers.TeamController.delete(id: String) -GET /teams/:id/availableTasksReport controllers.ReportController.availableTasksReport(id: String) -GET /teams/:id/projectProgressReport controllers.ReportController.projectProgressReport(id: String) +DELETE /teams/:id controllers.TeamController.delete(id: ObjectId) +GET /teams/:id/availableTasksReport controllers.ReportController.availableTasksReport(id: ObjectId) +GET /teams/:id/projectProgressReport controllers.ReportController.projectProgressReport(id: ObjectId) # Datasets -POST /datasets/:datasetId/createExplorational controllers.AnnotationController.createExplorational(datasetId: String) -GET /datasets/:datasetId/sandbox/:typ controllers.AnnotationController.getSandbox(datasetId: String, typ: String, sharingToken: Option[String]) -GET /datasets controllers.DatasetController.list(isActive: Option[Boolean], isUnreported: Option[Boolean], organizationId: Option[String], onlyMyOrganization: Option[Boolean], uploaderId: Option[String], folderId: Option[String], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], compact: Option[Boolean]) +POST /datasets/:datasetId/createExplorational controllers.AnnotationController.createExplorational(datasetId: ObjectId) +GET /datasets/:datasetId/sandbox/:typ controllers.AnnotationController.getSandbox(datasetId: ObjectId, typ: String, sharingToken: Option[String]) +GET /datasets controllers.DatasetController.list(isActive: Option[Boolean], isUnreported: Option[Boolean], organizationId: Option[String], onlyMyOrganization: Option[Boolean], uploaderId: Option[ObjectId], folderId: Option[ObjectId], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], compact: Option[Boolean]) POST /datasets controllers.DatasetController.create(typ: String) POST /datasets/exploreRemote controllers.DatasetController.exploreRemoteDataset() POST /datasets/exploreAndAddRemote controllers.DatasetController.exploreAndAddRemoteDataset() GET /datasets/disambiguate/:datasetName/toNew controllers.DatasetController.getOrganizationForDataset(datasetName: String) GET /datasets/disambiguate/:organizationId/:datasetName/toId controllers.DatasetController.getDatasetIdFromNameAndOrganization(datasetName: String, organizationId: String) -GET /datasets/:datasetId/health controllers.DatasetController.health(datasetId: String, sharingToken: Option[String]) -PATCH /datasets/:datasetId controllers.DatasetController.update(datasetId: String) -PATCH /datasets/:datasetId/updatePartial controllers.DatasetController.updatePartial(datasetId: String) -GET /datasets/:datasetId/accessList controllers.DatasetController.accessList(datasetId: String) -GET /datasets/:datasetId/sharingToken controllers.DatasetController.getSharingToken(datasetId: String) -DELETE /datasets/:datasetId/sharingToken controllers.DatasetController.deleteSharingToken(datasetId: String) -PATCH /datasets/:datasetId/teams controllers.DatasetController.updateTeams(datasetId: String) -GET /datasets/:datasetId/layers/:layer/thumbnail controllers.DatasetController.thumbnail(datasetId: String, layer: String, w: Option[Int], h: Option[Int], mappingName: Option[String], sharingToken: Option[String]) -POST /datasets/:datasetId/layers/:layer/segmentAnythingMask controllers.DatasetController.segmentAnythingMask(datasetId: String, layer: String, intensityMin: Option[Float], intensityMax: Option[Float]) -PUT /datasets/:datasetId/clearThumbnailCache controllers.DatasetController.removeFromThumbnailCache(datasetId: String) +GET /datasets/:datasetId/health controllers.DatasetController.health(datasetId: ObjectId, sharingToken: Option[String]) +PATCH /datasets/:datasetId controllers.DatasetController.update(datasetId: ObjectId) +PATCH /datasets/:datasetId/updatePartial controllers.DatasetController.updatePartial(datasetId: ObjectId) +GET /datasets/:datasetId/accessList controllers.DatasetController.accessList(datasetId: ObjectId) +GET /datasets/:datasetId/sharingToken controllers.DatasetController.getSharingToken(datasetId: ObjectId) +DELETE /datasets/:datasetId/sharingToken controllers.DatasetController.deleteSharingToken(datasetId: ObjectId) +PATCH /datasets/:datasetId/teams controllers.DatasetController.updateTeams(datasetId: ObjectId) +GET /datasets/:datasetId/layers/:layer/thumbnail controllers.DatasetController.thumbnail(datasetId: ObjectId, layer: String, w: Option[Int], h: Option[Int], mappingName: Option[String], sharingToken: Option[String]) +POST /datasets/:datasetId/layers/:layer/segmentAnythingMask controllers.DatasetController.segmentAnythingMask(datasetId: ObjectId, layer: String, intensityMin: Option[Float], intensityMax: Option[Float]) +PUT /datasets/:datasetId/clearThumbnailCache controllers.DatasetController.removeFromThumbnailCache(datasetId: ObjectId) GET /datasets/:datasetName/isValidNewName controllers.DatasetController.isValidNewName(datasetName: String) -GET /datasets/:datasetId controllers.DatasetController.read(datasetId: String, sharingToken: Option[String]) +GET /datasets/:datasetId controllers.DatasetController.read(datasetId: ObjectId, sharingToken: Option[String]) # Folders GET /folders/root controllers.FolderController.getRoot() GET /folders/tree controllers.FolderController.getTree() -POST /folders/create controllers.FolderController.create(parentId: String, name: String) -GET /folders/:id controllers.FolderController.get(id: String) -PUT /folders/:id controllers.FolderController.update(id: String) -PUT /folders/:id/move controllers.FolderController.move(id: String, newParentId: String) -DELETE /folders/:id controllers.FolderController.delete(id: String) +POST /folders/create controllers.FolderController.create(parentId: ObjectId, name: String) +GET /folders/:id controllers.FolderController.get(id: ObjectId) +PUT /folders/:id controllers.FolderController.update(id: ObjectId) +PUT /folders/:id/move controllers.FolderController.move(id: ObjectId, newParentId: ObjectId) +DELETE /folders/:id controllers.FolderController.delete(id: ObjectId) # Datastores GET /datastores controllers.DataStoreController.list() @@ -112,8 +112,8 @@ POST /datastores/:name/reserveUpload GET /datastores/:name/getUnfinishedUploadsForUser controllers.WKRemoteDataStoreController.getUnfinishedUploadsForUser(name: String, key: String, token: String, organizationName: String) POST /datastores/:name/reportDatasetUpload controllers.WKRemoteDataStoreController.reportDatasetUpload(name: String, key: String, token: String, datasetDirectoryName: String, datasetSizeBytes: Long, needsConversion: Boolean, viaAddRoute: Boolean) POST /datastores/:name/deleteDataset controllers.WKRemoteDataStoreController.deleteDataset(name: String, key: String) -GET /datastores/:name/jobExportProperties controllers.WKRemoteDataStoreController.jobExportProperties(name: String, key: String, jobId: String) -GET /datastores/:name/findCredential controllers.WKRemoteDataStoreController.findCredential(name: String, key: String, credentialId: String) +GET /datastores/:name/jobExportProperties controllers.WKRemoteDataStoreController.jobExportProperties(name: String, key: String, jobId: ObjectId) +GET /datastores/:name/findCredential controllers.WKRemoteDataStoreController.findCredential(name: String, key: String, credentialId: ObjectId) POST /datastores/:name/validateUserAccess controllers.UserTokenController.validateAccessViaDatastore(name: String, key: String, token: Option[String]) POST /datastores controllers.DataStoreController.create() DELETE /datastores/:name controllers.DataStoreController.delete(name: String) @@ -133,102 +133,102 @@ POST /userToken/generate # Annotations POST /annotations/upload controllers.AnnotationIOController.upload() -POST /annotations/:typ/:id/duplicate controllers.AnnotationController.duplicate(typ: String, id: String) -PATCH /annotations/:typ/:id/edit controllers.AnnotationController.editAnnotation(typ: String, id: String) -PATCH /annotations/:typ/:id/editLayer/:tracingId controllers.AnnotationController.editAnnotationLayer(typ: String, id: String, tracingId: String) +POST /annotations/:typ/:id/duplicate controllers.AnnotationController.duplicate(typ: String, id: ObjectId) +PATCH /annotations/:typ/:id/edit controllers.AnnotationController.editAnnotation(typ: String, id: ObjectId) +PATCH /annotations/:typ/:id/editLayer/:tracingId controllers.AnnotationController.editAnnotationLayer(typ: String, id: ObjectId, tracingId: String) -PATCH /annotations/:typ/:id/finish controllers.AnnotationController.finish(typ: String, id: String, timestamp: Long) +PATCH /annotations/:typ/:id/finish controllers.AnnotationController.finish(typ: String, id: ObjectId, timestamp: Long) PATCH /annotations/:typ/finish controllers.AnnotationController.finishAll(typ: String, timestamp: Long) -PATCH /annotations/:typ/:id/reopen controllers.AnnotationController.reopen(typ: String, id: String) -PUT /annotations/:typ/:id/reset controllers.AnnotationController.reset(typ: String, id: String) -PATCH /annotations/:typ/:id/transfer controllers.AnnotationController.transfer(typ: String, id: String) -PATCH /annotations/:typ/:id/editLockedState controllers.AnnotationController.editLockedState(typ: String, id: String, isLockedByOwner: Boolean) - -GET /annotations/:id/info controllers.AnnotationController.infoWithoutType(id: String, timestamp: Long) -PATCH /annotations/:id/makeHybrid controllers.AnnotationController.makeHybridWithoutType(id: String, fallbackLayerName: Option[String]) -PATCH /annotations/:id/downsample controllers.AnnotationController.downsampleWithoutType(id: String, tracingId: String) -PATCH /annotations/:id/addAnnotationLayer controllers.AnnotationController.addAnnotationLayerWithoutType(id: String) -PATCH /annotations/:id/deleteAnnotationLayer controllers.AnnotationController.deleteAnnotationLayerWithoutType(id: String, layerName: String) -DELETE /annotations/:id controllers.AnnotationController.cancelWithoutType(id: String) -POST /annotations/:id/merge/:mergedTyp/:mergedId controllers.AnnotationController.mergeWithoutType(id: String, mergedTyp: String, mergedId: String) -GET /annotations/:id/download controllers.AnnotationIOController.downloadWithoutType(id: String, skeletonVersion: Option[Long], volumeVersion: Option[Long], skipVolumeData: Option[Boolean], volumeDataZipFormat: Option[String]) -POST /annotations/:id/acquireMutex controllers.AnnotationController.tryAcquiringAnnotationMutex(id: String) +PATCH /annotations/:typ/:id/reopen controllers.AnnotationController.reopen(typ: String, id: ObjectId) +PUT /annotations/:typ/:id/reset controllers.AnnotationController.reset(typ: String, id: ObjectId) +PATCH /annotations/:typ/:id/transfer controllers.AnnotationController.transfer(typ: String, id: ObjectId) +PATCH /annotations/:typ/:id/editLockedState controllers.AnnotationController.editLockedState(typ: String, id: ObjectId, isLockedByOwner: Boolean) + +GET /annotations/:id/info controllers.AnnotationController.infoWithoutType(id: ObjectId, timestamp: Long) +PATCH /annotations/:id/makeHybrid controllers.AnnotationController.makeHybridWithoutType(id: ObjectId, fallbackLayerName: Option[String]) +PATCH /annotations/:id/downsample controllers.AnnotationController.downsampleWithoutType(id: ObjectId, tracingId: String) +PATCH /annotations/:id/addAnnotationLayer controllers.AnnotationController.addAnnotationLayerWithoutType(id: ObjectId) +PATCH /annotations/:id/deleteAnnotationLayer controllers.AnnotationController.deleteAnnotationLayerWithoutType(id: ObjectId, layerName: String) +DELETE /annotations/:id controllers.AnnotationController.cancelWithoutType(id: ObjectId) +POST /annotations/:id/merge/:mergedTyp/:mergedId controllers.AnnotationController.mergeWithoutType(id: ObjectId, mergedTyp: String, mergedId: ObjectId) +GET /annotations/:id/download controllers.AnnotationIOController.downloadWithoutType(id: ObjectId, skeletonVersion: Option[Long], volumeVersion: Option[Long], skipVolumeData: Option[Boolean], volumeDataZipFormat: Option[String]) +POST /annotations/:id/acquireMutex controllers.AnnotationController.tryAcquiringAnnotationMutex(id: ObjectId) PATCH /annotations/addSegmentIndicesToAll controllers.AnnotationController.addSegmentIndicesToAll(parallelBatchCount: Int, dryRun: Boolean, skipTracings: Option[String]) -GET /annotations/:typ/:id/info controllers.AnnotationController.info(typ: String, id: String, timestamp: Long) -PATCH /annotations/:typ/:id/makeHybrid controllers.AnnotationController.makeHybrid(typ: String, id: String, fallbackLayerName: Option[String]) -PATCH /annotations/:typ/:id/downsample controllers.AnnotationController.downsample(typ: String, id: String, tracingId: String) -PATCH /annotations/:typ/:id/addAnnotationLayer controllers.AnnotationController.addAnnotationLayer(typ: String, id: String) -PATCH /annotations/:typ/:id/deleteAnnotationLayer controllers.AnnotationController.deleteAnnotationLayer(typ: String, id: String, layerName: String) -DELETE /annotations/:typ/:id controllers.AnnotationController.cancel(typ: String, id: String) -POST /annotations/:typ/:id/merge/:mergedTyp/:mergedId controllers.AnnotationController.merge(typ: String, id: String, mergedTyp: String, mergedId: String) -GET /annotations/:typ/:id/download controllers.AnnotationIOController.download(typ: String, id: String, skeletonVersion: Option[Long], volumeVersion: Option[Long], skipVolumeData: Option[Boolean], volumeDataZipFormat: Option[String]) +GET /annotations/:typ/:id/info controllers.AnnotationController.info(typ: String, id: ObjectId, timestamp: Long) +PATCH /annotations/:typ/:id/makeHybrid controllers.AnnotationController.makeHybrid(typ: String, id: ObjectId, fallbackLayerName: Option[String]) +PATCH /annotations/:typ/:id/downsample controllers.AnnotationController.downsample(typ: String, id: ObjectId, tracingId: String) +PATCH /annotations/:typ/:id/addAnnotationLayer controllers.AnnotationController.addAnnotationLayer(typ: String, id: ObjectId) +PATCH /annotations/:typ/:id/deleteAnnotationLayer controllers.AnnotationController.deleteAnnotationLayer(typ: String, id: ObjectId, layerName: String) +DELETE /annotations/:typ/:id controllers.AnnotationController.cancel(typ: String, id: ObjectId) +POST /annotations/:typ/:id/merge/:mergedTyp/:mergedId controllers.AnnotationController.merge(typ: String, id: ObjectId, mergedTyp: String, mergedId: ObjectId) +GET /annotations/:typ/:id/download controllers.AnnotationIOController.download(typ: String, id: ObjectId, skeletonVersion: Option[Long], volumeVersion: Option[Long], skipVolumeData: Option[Boolean], volumeDataZipFormat: Option[String]) GET /annotations/source/:accessTokenOrId controllers.AnnotationPrivateLinkController.annotationSource(accessTokenOrId: String, userToken: Option[String]) GET /annotations/readable controllers.AnnotationController.listExplorationals(isFinished: Option[Boolean], limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) -GET /annotations/:typ/:id/sharedTeams controllers.AnnotationController.getSharedTeams(typ: String, id: String) -PATCH /annotations/:typ/:id/sharedTeams controllers.AnnotationController.updateSharedTeams(typ: String, id: String) -PATCH /annotations/:typ/:id/othersMayEdit controllers.AnnotationController.updateOthersMayEdit(typ: String, id: String, othersMayEdit: Boolean) +GET /annotations/:typ/:id/sharedTeams controllers.AnnotationController.getSharedTeams(typ: String, id: ObjectId) +PATCH /annotations/:typ/:id/sharedTeams controllers.AnnotationController.updateSharedTeams(typ: String, id: ObjectId) +PATCH /annotations/:typ/:id/othersMayEdit controllers.AnnotationController.updateOthersMayEdit(typ: String, id: ObjectId, othersMayEdit: Boolean) # Annotation Private Links GET /zarrPrivateLinks controllers.AnnotationPrivateLinkController.list() -GET /zarrPrivateLinks/byAnnotation/:annotationId controllers.AnnotationPrivateLinkController.listByAnnotation(annotationId: String) +GET /zarrPrivateLinks/byAnnotation/:annotationId controllers.AnnotationPrivateLinkController.listByAnnotation(annotationId: ObjectId) POST /zarrPrivateLinks controllers.AnnotationPrivateLinkController.create() -PUT /zarrPrivateLinks/:id controllers.AnnotationPrivateLinkController.update(id: String) -DELETE /zarrPrivateLinks/:id controllers.AnnotationPrivateLinkController.delete(id: String) -GET /zarrPrivateLinks/:id controllers.AnnotationPrivateLinkController.get(id: String) +PUT /zarrPrivateLinks/:id controllers.AnnotationPrivateLinkController.update(id: ObjectId) +DELETE /zarrPrivateLinks/:id controllers.AnnotationPrivateLinkController.delete(id: ObjectId) +GET /zarrPrivateLinks/:id controllers.AnnotationPrivateLinkController.get(id: ObjectId) # Meshes POST /meshes controllers.MeshController.create() -PUT /meshes/:id controllers.MeshController.update(id: String) -DELETE /meshes/:id controllers.MeshController.delete(id: String) -GET /meshes/:id controllers.MeshController.get(id: String) -PUT /meshes/:id/data controllers.MeshController.updateData(id: String) -GET /meshes/:id/data controllers.MeshController.getData(id: String) +PUT /meshes/:id controllers.MeshController.update(id: ObjectId) +DELETE /meshes/:id controllers.MeshController.delete(id: ObjectId) +GET /meshes/:id controllers.MeshController.get(id: ObjectId) +PUT /meshes/:id/data controllers.MeshController.updateData(id: ObjectId) +GET /meshes/:id/data controllers.MeshController.getData(id: ObjectId) # Tasks POST /tasks controllers.TaskController.create() POST /tasks/createFromFiles controllers.TaskController.createFromFiles() POST /tasks/list controllers.TaskController.listTasks() GET /tasks/experienceDomains controllers.TaskController.listExperienceDomains() -GET /tasks/:id controllers.TaskController.read(id: String) -DELETE /tasks/:id controllers.TaskController.delete(id: String) -PUT /tasks/:id controllers.TaskController.update(id: String) -POST /tasks/:id/assign controllers.TaskController.assignOne(id: String, userId: String) -GET /tasks/:id/annotations controllers.AnnotationController.annotationsForTask(id: String) +GET /tasks/:id controllers.TaskController.read(id: ObjectId) +DELETE /tasks/:id controllers.TaskController.delete(id: ObjectId) +PUT /tasks/:id controllers.TaskController.update(id: ObjectId) +POST /tasks/:id/assign controllers.TaskController.assignOne(id: ObjectId, userId: ObjectId) +GET /tasks/:id/annotations controllers.AnnotationController.annotationsForTask(id: ObjectId) # TaskTypes GET /taskTypes controllers.TaskTypeController.list() POST /taskTypes controllers.TaskTypeController.create() -DELETE /taskTypes/:id controllers.TaskTypeController.delete(id: String) -GET /taskTypes/:id/tasks controllers.TaskController.listTasksForType(id: String) -GET /taskTypes/:id/projects controllers.ProjectController.projectsForTaskType(id: String) -GET /taskTypes/:id controllers.TaskTypeController.get(id: String) -PUT /taskTypes/:id controllers.TaskTypeController.update(id: String) +DELETE /taskTypes/:id controllers.TaskTypeController.delete(id: ObjectId) +GET /taskTypes/:id/tasks controllers.TaskController.listTasksForType(id: ObjectId) +GET /taskTypes/:id/projects controllers.ProjectController.projectsForTaskType(id: ObjectId) +GET /taskTypes/:id controllers.TaskTypeController.get(id: ObjectId) +PUT /taskTypes/:id controllers.TaskTypeController.update(id: ObjectId) # Scripts GET /scripts controllers.ScriptController.list() POST /scripts controllers.ScriptController.create() -GET /scripts/:id controllers.ScriptController.get(id: String) -PUT /scripts/:id controllers.ScriptController.update(id: String) -DELETE /scripts/:id controllers.ScriptController.delete(id: String) +GET /scripts/:id controllers.ScriptController.get(id: ObjectId) +PUT /scripts/:id controllers.ScriptController.update(id: ObjectId) +DELETE /scripts/:id controllers.ScriptController.delete(id: ObjectId) # Projects GET /projects controllers.ProjectController.list() GET /projects/withStatus controllers.ProjectController.listWithStatus() POST /projects controllers.ProjectController.create() GET /projects/byName/:name controllers.ProjectController.readByName(name: String) -GET /projects/:id controllers.ProjectController.read(id: String) -DELETE /projects/:id controllers.ProjectController.delete(id: String) -PUT /projects/:id controllers.ProjectController.update(id: String) -GET /projects/:id/tasks controllers.ProjectController.tasksForProject(id: String, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) -PATCH /projects/:id/incrementEachTasksInstances controllers.ProjectController.incrementEachTasksInstances(id: String, delta: Option[Long]) -PATCH /projects/:id/pause controllers.ProjectController.pause(id: String) -PATCH /projects/:id/resume controllers.ProjectController.resume(id: String) -GET /projects/:id/usersWithActiveTasks controllers.ProjectController.usersWithActiveTasks(id:String) -POST /projects/:id/transferActiveTasks controllers.ProjectController.transferActiveTasks(id:String) +GET /projects/:id controllers.ProjectController.read(id: ObjectId) +DELETE /projects/:id controllers.ProjectController.delete(id: ObjectId) +PUT /projects/:id controllers.ProjectController.update(id: ObjectId) +GET /projects/:id/tasks controllers.ProjectController.tasksForProject(id: ObjectId, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) +PATCH /projects/:id/incrementEachTasksInstances controllers.ProjectController.incrementEachTasksInstances(id: ObjectId, delta: Option[Long]) +PATCH /projects/:id/pause controllers.ProjectController.pause(id: ObjectId) +PATCH /projects/:id/resume controllers.ProjectController.resume(id: ObjectId) +GET /projects/:id/usersWithActiveTasks controllers.ProjectController.usersWithActiveTasks(id:ObjectId) +POST /projects/:id/transferActiveTasks controllers.ProjectController.transferActiveTasks(id:ObjectId) # Organizations GET /organizations controllers.OrganizationController.list(compact: Option[Boolean]) @@ -252,46 +252,46 @@ GET /termsOfService/acceptanceNeeded # Time Tracking # Note, there is also /users/:id/loggedTime -GET /time/user/:userId/spans controllers.TimeController.timeSpansOfUser(userId: String, start: Long, end: Long, annotationTypes: String, annotationStates: String, projectIds: Option[String]) -GET /time/user/:userId/summedByAnnotation controllers.TimeController.timeSummedByAnnotationForUser(userId: String, start: Long, end: Long, annotationTypes: String, annotationStates: String, projectIds: Option[String]) +GET /time/user/:userId/spans controllers.TimeController.timeSpansOfUser(userId: ObjectId, start: Long, end: Long, annotationTypes: String, annotationStates: String, projectIds: Option[String]) +GET /time/user/:userId/summedByAnnotation controllers.TimeController.timeSummedByAnnotationForUser(userId: ObjectId, start: Long, end: Long, annotationTypes: String, annotationStates: String, projectIds: Option[String]) GET /time/overview controllers.TimeController.timeOverview(start: Long, end: Long, annotationTypes: String, annotationStates: String, teamIds: Option[String], projectIds: Option[String]) # Long-Running Jobs GET /jobs/request controllers.WKRemoteWorkerController.requestJobs(key: String) GET /jobs controllers.JobController.list() GET /jobs/status controllers.JobController.status() -POST /jobs/run/convertToWkw/:datasetId controllers.JobController.runConvertToWkwJob(datasetId: String, scale: String, unit: Option[String]) -POST /jobs/run/computeMeshFile/:datasetId controllers.JobController.runComputeMeshFileJob(datasetId: String, layerName: String, mag: String, agglomerateView: Option[String]) -POST /jobs/run/computeSegmentIndexFile/:datasetId controllers.JobController.runComputeSegmentIndexFileJob(datasetId: String, layerName: String) -POST /jobs/run/exportTiff/:datasetId controllers.JobController.runExportTiffJob(datasetId: String, bbox: String, additionalCoordinates: Option[String], layerName: Option[String], mag: Option[String], annotationLayerName: Option[String], annotationId: Option[String], asOmeTiff: Boolean) -POST /jobs/run/inferNuclei/:datasetId controllers.JobController.runInferNucleiJob(datasetId: String, layerName: String, newDatasetName: String) -POST /jobs/run/inferNeurons/:datasetId controllers.JobController.runInferNeuronsJob(datasetId: String, layerName: String, bbox: String, newDatasetName: String) -POST /jobs/run/inferMitochondria/:datasetId controllers.JobController.runInferMitochondriaJob(datasetId: String, layerName: String, bbox: String, newDatasetName: String) -POST /jobs/run/alignSections/:datasetId controllers.JobController.runAlignSectionsJob(datasetId: String, layerName: String, newDatasetName: String, annotationId: Option[String]) -POST /jobs/run/materializeVolumeAnnotation/:datasetId controllers.JobController.runMaterializeVolumeAnnotationJob(datasetId: String, fallbackLayerName: String, annotationId: String, annotationType: String, newDatasetName: String, outputSegmentationLayerName: String, mergeSegments: Boolean, volumeLayerName: Option[String]) -POST /jobs/run/findLargestSegmentId/:datasetId controllers.JobController.runFindLargestSegmentIdJob(datasetId: String, layerName: String) -POST /jobs/run/renderAnimation/:datasetId controllers.JobController.runRenderAnimationJob(datasetId: String) -GET /jobs/:id controllers.JobController.get(id: String) -PATCH /jobs/:id/cancel controllers.JobController.cancel(id: String) -POST /jobs/:id/status controllers.WKRemoteWorkerController.updateJobStatus(key: String, id: String) -POST /jobs/:id/attachVoxelyticsWorkflow controllers.WKRemoteWorkerController.attachVoxelyticsWorkflow(key: String, id: String) -POST /jobs/:id/attachDatasetToInference controllers.WKRemoteWorkerController.attachDatasetToInference(key: String, id: String) -GET /jobs/:id/export controllers.JobController.redirectToExport(id: String) +POST /jobs/run/convertToWkw/:datasetId controllers.JobController.runConvertToWkwJob(datasetId: ObjectId, scale: String, unit: Option[String]) +POST /jobs/run/computeMeshFile/:datasetId controllers.JobController.runComputeMeshFileJob(datasetId: ObjectId, layerName: String, mag: String, agglomerateView: Option[String]) +POST /jobs/run/computeSegmentIndexFile/:datasetId controllers.JobController.runComputeSegmentIndexFileJob(datasetId: ObjectId, layerName: String) +POST /jobs/run/exportTiff/:datasetId controllers.JobController.runExportTiffJob(datasetId: ObjectId, bbox: String, additionalCoordinates: Option[String], layerName: Option[String], mag: Option[String], annotationLayerName: Option[String], annotationId: Option[ObjectId], asOmeTiff: Boolean) +POST /jobs/run/inferNuclei/:datasetId controllers.JobController.runInferNucleiJob(datasetId: ObjectId, layerName: String, newDatasetName: String) +POST /jobs/run/inferNeurons/:datasetId controllers.JobController.runInferNeuronsJob(datasetId: ObjectId, layerName: String, bbox: String, newDatasetName: String) +POST /jobs/run/inferMitochondria/:datasetId controllers.JobController.runInferMitochondriaJob(datasetId: ObjectId, layerName: String, bbox: String, newDatasetName: String) +POST /jobs/run/alignSections/:datasetId controllers.JobController.runAlignSectionsJob(datasetId: ObjectId, layerName: String, newDatasetName: String, annotationId: Option[ObjectId]) +POST /jobs/run/materializeVolumeAnnotation/:datasetId controllers.JobController.runMaterializeVolumeAnnotationJob(datasetId: ObjectId, fallbackLayerName: String, annotationId: ObjectId, annotationType: String, newDatasetName: String, outputSegmentationLayerName: String, mergeSegments: Boolean, volumeLayerName: Option[String]) +POST /jobs/run/findLargestSegmentId/:datasetId controllers.JobController.runFindLargestSegmentIdJob(datasetId: ObjectId, layerName: String) +POST /jobs/run/renderAnimation/:datasetId controllers.JobController.runRenderAnimationJob(datasetId: ObjectId) +GET /jobs/:id controllers.JobController.get(id: ObjectId) +PATCH /jobs/:id/cancel controllers.JobController.cancel(id: ObjectId) +POST /jobs/:id/status controllers.WKRemoteWorkerController.updateJobStatus(key: String, id: ObjectId) +POST /jobs/:id/attachVoxelyticsWorkflow controllers.WKRemoteWorkerController.attachVoxelyticsWorkflow(key: String, id: ObjectId) +POST /jobs/:id/attachDatasetToInference controllers.WKRemoteWorkerController.attachDatasetToInference(key: String, id: ObjectId) +GET /jobs/:id/export controllers.JobController.redirectToExport(id: ObjectId) # AI Models POST /aiModels/runTraining controllers.AiModelController.runTraining POST /aiModels/inferences/runInference controllers.AiModelController.runInference -GET /aiModels/inferences/:id controllers.AiModelController.readAiInferenceInfo(id: String) +GET /aiModels/inferences/:id controllers.AiModelController.readAiInferenceInfo(id: ObjectId) GET /aiModels/inferences controllers.AiModelController.listAiInferences GET /aiModels controllers.AiModelController.listAiModels POST /aiModels/register controllers.AiModelController.registerAiModel -GET /aiModels/:id controllers.AiModelController.readAiModelInfo(id: String) -PUT /aiModels/:id controllers.AiModelController.updateAiModelInfo(id: String) -DELETE /aiModels/:id controllers.AiModelController.deleteAiModel(id: String) +GET /aiModels/:id controllers.AiModelController.readAiModelInfo(id: ObjectId) +PUT /aiModels/:id controllers.AiModelController.updateAiModelInfo(id: ObjectId) +DELETE /aiModels/:id controllers.AiModelController.deleteAiModel(id: ObjectId) # Publications GET /publications controllers.PublicationController.listPublications() -GET /publications/:id controllers.PublicationController.read(id: String) +GET /publications/:id controllers.PublicationController.read(id: ObjectId) # Shortlinks POST /shortLinks controllers.ShortLinkController.create() @@ -309,10 +309,10 @@ POST /verifyEmail # Voxelytics POST /voxelytics/workflows controllers.VoxelyticsController.storeWorkflow() GET /voxelytics/workflows controllers.VoxelyticsController.listWorkflows() -GET /voxelytics/workflows/:workflowHash controllers.VoxelyticsController.getWorkflow(workflowHash: String, runId: Option[String]) +GET /voxelytics/workflows/:workflowHash controllers.VoxelyticsController.getWorkflow(workflowHash: String, runId: Option[ObjectId]) DELETE /voxelytics/workflows/:workflowHash controllers.VoxelyticsController.deleteWorkflow(workflowHash: String) POST /voxelytics/workflows/:workflowHash/events controllers.VoxelyticsController.storeWorkflowEvents(workflowHash: String, runName: String) -GET /voxelytics/workflows/:workflowHash/chunkStatistics controllers.VoxelyticsController.getChunkStatistics(workflowHash: String, runId: Option[String], taskName: String) -GET /voxelytics/workflows/:workflowHash/artifactChecksums controllers.VoxelyticsController.getArtifactChecksums(workflowHash: String, runId: Option[String], taskName: String, artifactName: Option[String]) +GET /voxelytics/workflows/:workflowHash/chunkStatistics controllers.VoxelyticsController.getChunkStatistics(workflowHash: String, runId: Option[ObjectId], taskName: String) +GET /voxelytics/workflows/:workflowHash/artifactChecksums controllers.VoxelyticsController.getArtifactChecksums(workflowHash: String, runId: Option[ObjectId], taskName: String, artifactName: Option[String]) POST /voxelytics/logs controllers.VoxelyticsController.appendLogs() -GET /voxelytics/logs controllers.VoxelyticsController.getLogs(runId: String, taskName: Option[String], minLevel: Option[String], startTimestamp:Long, endTimestamp: Long, limit: Option[Int]) +GET /voxelytics/logs controllers.VoxelyticsController.getLogs(runId: ObjectId, taskName: Option[String], minLevel: Option[String], startTimestamp:Long, endTimestamp: Long, limit: Option[Int]) diff --git a/conf/webknossos.versioned.routes b/conf/webknossos.versioned.routes index 3ee48062b8..300e16ebe5 100644 --- a/conf/webknossos.versioned.routes +++ b/conf/webknossos.versioned.routes @@ -22,12 +22,12 @@ GET /v8/datasets/:organizationId/:datasetName/sharingToken co PATCH /v8/datasets/:organizationId/:datasetName/teams controllers.LegacyApiController.updateDatasetTeamsV8(organizationId: String, datasetName: String) GET /v8/datasets/:organizationId/:datasetName/isValidNewName controllers.LegacyApiController.isValidNewNameV8(datasetName: String, organizationId: String) GET /v8/datasets/:organizationId/:datasetName controllers.LegacyApiController.readDatasetV8(organizationId: String, datasetName: String, sharingToken: Option[String]) -GET /v8/tasks/:id controllers.LegacyApiController.readTaskV8(id: String) +GET /v8/tasks/:id controllers.LegacyApiController.readTaskV8(id: ObjectId) POST /v8/tasks controllers.LegacyApiController.createTaskV8() -PUT /v8/tasks/:id controllers.LegacyApiController.updateTaskV8(id: String) -GET /v8/projects/:id/tasks controllers.LegacyApiController.tasksForProjectV8(id: String, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) -GET /v8/annotations/:id/info controllers.LegacyApiController.annotationInfoV8(id: String, timestamp: Long) -GET /v8/tasks/:id/annotations controllers.LegacyApiController.annotationsForTaskV8(id: String) +PUT /v8/tasks/:id controllers.LegacyApiController.updateTaskV8(id: ObjectId) +GET /v8/projects/:id/tasks controllers.LegacyApiController.tasksForProjectV8(id: ObjectId, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) +GET /v8/annotations/:id/info controllers.LegacyApiController.annotationInfoV8(id: ObjectId, timestamp: Long) +GET /v8/tasks/:id/annotations controllers.LegacyApiController.annotationsForTaskV8(id: ObjectId) -> /v8/ webknossos.latest.Routes #v7: support changes to v9 @@ -36,15 +36,15 @@ GET /v7/datasets/:organizationId/:datasetName/sharingToken co PATCH /v7/datasets/:organizationId/:datasetName/teams controllers.LegacyApiController.updateDatasetTeamsV8(organizationId: String, datasetName: String) GET /v7/datasets/:organizationId/:datasetName/isValidNewName controllers.LegacyApiController.isValidNewNameV8(datasetName: String, organizationId: String) GET /v7/datasets/:organizationId/:datasetName controllers.LegacyApiController.readDatasetV8(organizationId: String, datasetName: String, sharingToken: Option[String]) -GET /v7/tasks/:id controllers.LegacyApiController.readTaskV8(id: String) +GET /v7/tasks/:id controllers.LegacyApiController.readTaskV8(id: ObjectId) POST /v7/tasks controllers.LegacyApiController.createTaskV8() -PUT /v7/tasks/:id controllers.LegacyApiController.updateTaskV8(id: String) -GET /v7/projects/:id/tasks controllers.LegacyApiController.tasksForProjectV8(id: String, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) -GET /v7/annotations/:id/info controllers.LegacyApiController.annotationInfoV8(id: String, timestamp: Long) -GET /v7/tasks/:id/annotations controllers.LegacyApiController.annotationsForTaskV8(id: String) +PUT /v7/tasks/:id controllers.LegacyApiController.updateTaskV8(id: ObjectId) +GET /v7/projects/:id/tasks controllers.LegacyApiController.tasksForProjectV8(id: ObjectId, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) +GET /v7/annotations/:id/info controllers.LegacyApiController.annotationInfoV8(id: ObjectId, timestamp: Long) +GET /v7/tasks/:id/annotations controllers.LegacyApiController.annotationsForTaskV8(id: ObjectId) # v7: support changes to v8 -GET /v7/datasets controllers.LegacyApiController.listDatasetsV7(isActive: Option[Boolean], isUnreported: Option[Boolean], organizationName: Option[String], onlyMyOrganization: Option[Boolean], uploaderId: Option[String], folderId: Option[String], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], compact: Option[Boolean]) +GET /v7/datasets controllers.LegacyApiController.listDatasetsV7(isActive: Option[Boolean], isUnreported: Option[Boolean], organizationName: Option[String], onlyMyOrganization: Option[Boolean], uploaderId: Option[ObjectId], folderId: Option[ObjectId], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], compact: Option[Boolean]) -> /v7/ webknossos.latest.Routes @@ -53,16 +53,16 @@ PATCH /v6/datasets/:organizationId/:datasetName co GET /v6/datasets/:organizationId/:datasetName/sharingToken controllers.LegacyApiController.getDatasetSharingTokenV8(organizationId: String, datasetName: String) PATCH /v6/datasets/:organizationId/:datasetName/teams controllers.LegacyApiController.updateDatasetTeamsV8(organizationId: String, datasetName: String) GET /v6/datasets/:organizationId/:datasetName/isValidNewName controllers.LegacyApiController.isValidNewNameV8(datasetName: String, organizationId: String) -GET /v6/tasks/:id controllers.LegacyApiController.readTaskV8(id: String) +GET /v6/tasks/:id controllers.LegacyApiController.readTaskV8(id: ObjectId) POST /v6/tasks controllers.LegacyApiController.createTaskV8() -PUT /v6/tasks/:id controllers.LegacyApiController.updateTaskV8(id: String) -GET /v6/projects/:id/tasks controllers.LegacyApiController.tasksForProjectV8(id: String, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) -GET /v6/annotations/:id/info controllers.LegacyApiController.annotationInfoV8(id: String, timestamp: Long) -GET /v6/tasks/:id/annotations controllers.LegacyApiController.annotationsForTaskV8(id: String) +PUT /v6/tasks/:id controllers.LegacyApiController.updateTaskV8(id: ObjectId) +GET /v6/projects/:id/tasks controllers.LegacyApiController.tasksForProjectV8(id: ObjectId, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) +GET /v6/annotations/:id/info controllers.LegacyApiController.annotationInfoV8(id: ObjectId, timestamp: Long) +GET /v6/tasks/:id/annotations controllers.LegacyApiController.annotationsForTaskV8(id: ObjectId) # v6: support changes to v7 -GET /v6/datasets controllers.LegacyApiController.listDatasetsV6(isActive: Option[Boolean], isUnreported: Option[Boolean], organizationName: Option[String], onlyMyOrganization: Option[Boolean], uploaderId: Option[String], folderId: Option[String], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], compact: Option[Boolean]) +GET /v6/datasets controllers.LegacyApiController.listDatasetsV6(isActive: Option[Boolean], isUnreported: Option[Boolean], organizationName: Option[String], onlyMyOrganization: Option[Boolean], uploaderId: Option[ObjectId], folderId: Option[ObjectId], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], compact: Option[Boolean]) GET /v6/datasets/:organizationName/:datasetName controllers.LegacyApiController.readDatasetV6(organizationName: String, datasetName: String, sharingToken: Option[String]) -> /v6/ webknossos.latest.Routes @@ -73,15 +73,15 @@ PATCH /v5/datasets/:organizationId/:datasetName co GET /v5/datasets/:organizationId/:datasetName/sharingToken controllers.LegacyApiController.getDatasetSharingTokenV8(organizationId: String, datasetName: String) PATCH /v5/datasets/:organizationId/:datasetName/teams controllers.LegacyApiController.updateDatasetTeamsV8(organizationId: String, datasetName: String) GET /v5/datasets/:organizationId/:datasetName/isValidNewName controllers.LegacyApiController.isValidNewNameV8(datasetName: String, organizationId: String) -GET /v5/tasks/:id controllers.LegacyApiController.readTaskV8(id: String) +GET /v5/tasks/:id controllers.LegacyApiController.readTaskV8(id: ObjectId) POST /v5/tasks controllers.LegacyApiController.createTaskV8() -PUT /v5/tasks/:id controllers.LegacyApiController.updateTaskV8(id: String) -GET /v5/projects/:id/tasks controllers.LegacyApiController.tasksForProjectV8(id: String, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) -GET /v5/annotations/:id/info controllers.LegacyApiController.annotationInfoV8(id: String, timestamp: Long) -GET /v5/tasks/:id/annotations controllers.LegacyApiController.annotationsForTaskV8(id: String) +PUT /v5/tasks/:id controllers.LegacyApiController.updateTaskV8(id: ObjectId) +GET /v5/projects/:id/tasks controllers.LegacyApiController.tasksForProjectV8(id: ObjectId, limit: Option[Int], pageNumber: Option[Int], includeTotalCount: Option[Boolean]) +GET /v5/annotations/:id/info controllers.LegacyApiController.annotationInfoV8(id: ObjectId, timestamp: Long) +GET /v5/tasks/:id/annotations controllers.LegacyApiController.annotationsForTaskV8(id: ObjectId) # v5: support changes to v7 -GET /v5/datasets controllers.LegacyApiController.listDatasetsV6(isActive: Option[Boolean], isUnreported: Option[Boolean], organizationName: Option[String], onlyMyOrganization: Option[Boolean], uploaderId: Option[String], folderId: Option[String], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], compact: Option[Boolean]) +GET /v5/datasets controllers.LegacyApiController.listDatasetsV6(isActive: Option[Boolean], isUnreported: Option[Boolean], organizationName: Option[String], onlyMyOrganization: Option[Boolean], uploaderId: Option[ObjectId], folderId: Option[ObjectId], includeSubfolders: Option[Boolean], searchQuery: Option[String], limit: Option[Int], compact: Option[Boolean]) GET /v5/datasets/:organizationName/:datasetName controllers.LegacyApiController.readDatasetV6(organizationName: String, datasetName: String, sharingToken: Option[String]) # v5: support changes to v6 diff --git a/util/src/main/scala/com/scalableminds/util/objectid/ObjectId.scala b/util/src/main/scala/com/scalableminds/util/objectid/ObjectId.scala index 61d917850d..dfb37cbb84 100644 --- a/util/src/main/scala/com/scalableminds/util/objectid/ObjectId.scala +++ b/util/src/main/scala/com/scalableminds/util/objectid/ObjectId.scala @@ -3,6 +3,7 @@ package com.scalableminds.util.objectid import com.scalableminds.util.tools.TextUtils.parseCommaSeparated import com.scalableminds.util.tools.{Fox, FoxImplicits} import play.api.libs.json._ +import play.api.mvc.{PathBindable, QueryStringBindable} import reactivemongo.api.bson.BSONObjectID import scala.concurrent.ExecutionContext @@ -33,4 +34,22 @@ object ObjectId extends FoxImplicits { override def writes(o: ObjectId): JsValue = JsString(o.id) } + + implicit def pathBinder: PathBindable[ObjectId] = + new PathBindable[ObjectId] { + override def bind(key: String, value: String): Either[String, ObjectId] = + fromStringSync(value).toRight(s"Cannot parse parameter $key as ObjectId: $value") + + override def unbind(key: String, value: ObjectId): String = value.id + } + + implicit def queryBinder: QueryStringBindable[ObjectId] = + new QueryStringBindable[ObjectId] { + override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, ObjectId]] = + params.get(key).flatMap(_.headOption).map { value => + fromStringSync(value).toRight(s"Cannot parse parameter $key as ObjectId: $value") + } + + override def unbind(key: String, value: ObjectId): String = value.id + } }