-
Notifications
You must be signed in to change notification settings - Fork 32
Allow more dataset CRUD via API #9375
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
ef7f664
8f4d8ba
9741c46
951fc0e
53297d8
6763e1d
2e9a1ff
53c1bd4
725e902
eaee9b4
fa42045
9156b9e
d8cc97d
4612ae6
be708e2
9428872
b234495
d234201
0717a78
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -17,6 +17,14 @@ import play.api.libs.json._ | |||||||||||||||||||||||||||||||
| import play.api.mvc.{Action, AnyContent, PlayBodyParsers, Result} | ||||||||||||||||||||||||||||||||
| import security.WkEnv | ||||||||||||||||||||||||||||||||
| import com.scalableminds.util.objectid.ObjectId | ||||||||||||||||||||||||||||||||
| import com.scalableminds.webknossos.datastore.models.datasource.{ | ||||||||||||||||||||||||||||||||
| StaticColorLayer, | ||||||||||||||||||||||||||||||||
| StaticSegmentationLayer, | ||||||||||||||||||||||||||||||||
| UsableDataSource | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| import models.analytics.{AnalyticsService, ChangeDatasetSettingsEvent} | ||||||||||||||||||||||||||||||||
| import play.api.i18n.Messages | ||||||||||||||||||||||||||||||||
| import utils.MetadataAssertions | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| import scala.concurrent.ExecutionContext | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -44,8 +52,48 @@ class LegacyApiController @Inject()(datasetController: DatasetController, | |||||||||||||||||||||||||||||||
| organizationDAO: OrganizationDAO, | ||||||||||||||||||||||||||||||||
| datasetService: DatasetService, | ||||||||||||||||||||||||||||||||
| datasetDAO: DatasetDAO, | ||||||||||||||||||||||||||||||||
| analyticsService: AnalyticsService, | ||||||||||||||||||||||||||||||||
| sil: Silhouette[WkEnv])(implicit ec: ExecutionContext, bodyParsers: PlayBodyParsers) | ||||||||||||||||||||||||||||||||
| extends Controller { | ||||||||||||||||||||||||||||||||
| extends Controller | ||||||||||||||||||||||||||||||||
| with MetadataAssertions { | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| def updatePartialV12(datasetId: ObjectId): Action[DatasetUpdateParameters] = | ||||||||||||||||||||||||||||||||
| sil.SecuredAction.async(validateJson[DatasetUpdateParameters]) { implicit request => | ||||||||||||||||||||||||||||||||
| for { | ||||||||||||||||||||||||||||||||
| dataset <- datasetDAO.findOne(datasetId) ?~> Messages("dataset.notFound", datasetId) ~> NOT_FOUND | ||||||||||||||||||||||||||||||||
| _ <- Fox.assertTrue(datasetService.isEditableBy(dataset, Some(request.identity))) ?~> "notAllowed" ~> FORBIDDEN | ||||||||||||||||||||||||||||||||
| _ <- Fox.runOptional(request.body.metadata)(assertNoDuplicateMetadataKeys) | ||||||||||||||||||||||||||||||||
| _ <- datasetDAO.updatePartial(dataset._id, request.body) | ||||||||||||||||||||||||||||||||
| _ <- Fox.runOptional(request.body.dataSource) { dataSourceUpdates => | ||||||||||||||||||||||||||||||||
| def findOriginalAttachments(existingDataSource: UsableDataSource, layerName: String) = { | ||||||||||||||||||||||||||||||||
| val reverseLayerRenamingMap: Map[String, String] = request.body.layerRenamings | ||||||||||||||||||||||||||||||||
| .getOrElse(Seq.empty) | ||||||||||||||||||||||||||||||||
| .map(layerRenaming => (layerRenaming.newName, layerRenaming.oldName)) | ||||||||||||||||||||||||||||||||
| .toMap | ||||||||||||||||||||||||||||||||
| val existingLayerName = reverseLayerRenamingMap.getOrElse(layerName, layerName) | ||||||||||||||||||||||||||||||||
| val existingLayer = existingDataSource.dataLayers.find(_.name == existingLayerName) | ||||||||||||||||||||||||||||||||
| existingLayer.flatMap(_.attachments) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| for { | ||||||||||||||||||||||||||||||||
| existingDataSource <- datasetService.usableDataSourceFor(dataset) | ||||||||||||||||||||||||||||||||
| updatesWithUndoneAttachmentChanges = dataSourceUpdates.copy( | ||||||||||||||||||||||||||||||||
| dataLayers = dataSourceUpdates.dataLayers.map { | ||||||||||||||||||||||||||||||||
| case s: StaticColorLayer => s.copy(attachments = findOriginalAttachments(existingDataSource, s.name)) | ||||||||||||||||||||||||||||||||
| case s: StaticSegmentationLayer => | ||||||||||||||||||||||||||||||||
| s.copy(attachments = findOriginalAttachments(existingDataSource, s.name)) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
|
Comment on lines
+79
to
+85
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Non-exhaustive pattern match will throw The pattern match in 🐛 Proposed fix: Add a fallback case to pass through other layer types unchanged updatesWithUndoneAttachmentChanges = dataSourceUpdates.copy(
dataLayers = dataSourceUpdates.dataLayers.map {
case s: StaticColorLayer => s.copy(attachments = findOriginalAttachments(existingDataSource, s.name))
case s: StaticSegmentationLayer =>
s.copy(attachments = findOriginalAttachments(existingDataSource, s.name))
+ case other => other // Pass through layer types without attachments
}
)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| _ <- datasetService.updateDataSourceFromUserChanges(dataset, | ||||||||||||||||||||||||||||||||
| updatesWithUndoneAttachmentChanges, | ||||||||||||||||||||||||||||||||
| request.body.layerRenamings.getOrElse(Seq.empty), | ||||||||||||||||||||||||||||||||
| request.body.attachmentRenamings.getOrElse(Seq.empty)) | ||||||||||||||||||||||||||||||||
| } yield () | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| updated <- datasetDAO.findOne(datasetId) | ||||||||||||||||||||||||||||||||
| _ = analyticsService.track(ChangeDatasetSettingsEvent(request.identity, updated)) | ||||||||||||||||||||||||||||||||
| js <- datasetService.publicWrites(updated, Some(request.identity)) | ||||||||||||||||||||||||||||||||
| } yield Ok(js) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /* provide v8 */ | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normalize attachment renames against layer renames in the same request.
Line 478 forwards
attachmentRenamingsunchanged even though the request already contains the old→new layer mapping. A payload that renames a layer and still references the pre-renamelayerNamefor an attachment rename will only apply half of the change. Please rewrite or reject those mixed requests here before delegating.🔧 Suggested normalization in the controller
🤖 Prompt for AI Agents