Skip to content

Commit a4817e4

Browse files
Merge branch 'master' into accept-tos-at-sign-up
2 parents b1bb0b8 + e3d8e89 commit a4817e4

File tree

7 files changed

+41
-17
lines changed

7 files changed

+41
-17
lines changed

CHANGELOG.unreleased.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
1414

1515
### Changed
1616
- Reading image files on datastore filesystem is now done asynchronously. [#8126](https://github.com/scalableminds/webknossos/pull/8126)
17+
- Improved error messages for starting jobs on datasets from other organizations. [#8181](https://github.com/scalableminds/webknossos/pull/8181)
1718

1819
### Fixed
1920
- Fix performance bottleneck when deleting a lot of trees at once. [#8176](https://github.com/scalableminds/webknossos/pull/8176)

app/controllers/AiModelController.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package controllers
22

3+
import com.scalableminds.util.accesscontext.GlobalAccessContext
34
import com.scalableminds.util.geometry.{BoundingBox, Vec3Int}
45
import com.scalableminds.util.tools.{Fox, FoxImplicits}
56
import models.aimodels.{AiInference, AiInferenceDAO, AiInferenceService, AiModel, AiModelDAO, AiModelService}
@@ -18,6 +19,7 @@ import scala.concurrent.ExecutionContext
1819
import com.scalableminds.util.time.Instant
1920
import models.aimodels.AiModelCategory.AiModelCategory
2021
import models.organization.OrganizationDAO
22+
import play.api.i18n.Messages
2123

2224
case class TrainingAnnotationSpecification(annotationId: ObjectId,
2325
colorLayerName: String,
@@ -41,6 +43,7 @@ object RunTrainingParameters {
4143
case class RunInferenceParameters(annotationId: Option[ObjectId],
4244
aiModelId: ObjectId,
4345
datasetName: String,
46+
organizationId: String,
4447
colorLayerName: String,
4548
boundingBox: String,
4649
newDatasetName: String,
@@ -135,6 +138,7 @@ class AiModelController @Inject()(
135138
firstAnnotationId <- trainingAnnotations.headOption.map(_.annotationId).toFox
136139
annotation <- annotationDAO.findOne(firstAnnotationId)
137140
dataset <- datasetDAO.findOne(annotation._dataset)
141+
_ <- bool2Fox(request.identity._organization == dataset._organization) ?~> "job.trainModel.notAllowed.organization" ~> FORBIDDEN
138142
dataStore <- dataStoreDAO.findOneByName(dataset._dataStore) ?~> "dataStore.notFound"
139143
_ <- Fox
140144
.serialCombined(request.body.trainingAnnotations.map(_.annotationId))(annotationDAO.findOne) ?~> "annotation.notFound"
@@ -172,8 +176,13 @@ class AiModelController @Inject()(
172176
sil.SecuredAction.async(validateJson[RunInferenceParameters]) { implicit request =>
173177
for {
174178
_ <- userService.assertIsSuperUser(request.identity)
175-
organization <- organizationDAO.findOne(request.identity._organization)
176-
dataset <- datasetDAO.findOneByNameAndOrganization(request.body.datasetName, organization._id)
179+
organization <- organizationDAO.findOne(request.body.organizationId)(GlobalAccessContext) ?~> Messages(
180+
"organization.notFound",
181+
request.body.organizationId)
182+
_ <- bool2Fox(request.identity._organization == organization._id) ?~> "job.runInference.notAllowed.organization" ~> FORBIDDEN
183+
dataset <- datasetDAO.findOneByNameAndOrganization(request.body.datasetName, organization._id) ?~> Messages(
184+
"dataset.notFound",
185+
request.body.datasetName)
177186
dataStore <- dataStoreDAO.findOneByName(dataset._dataStore) ?~> "dataStore.notFound"
178187
_ <- aiModelDAO.findOne(request.body.aiModelId) ?~> "aiModel.notFound"
179188
_ <- datasetService.assertValidDatasetName(request.body.newDatasetName)

app/controllers/JobController.scala

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class JobController @Inject()(
124124
voxelSizeFactor <- Vec3Double.fromUriLiteral(scale).toFox
125125
voxelSizeUnit <- Fox.runOptional(unit)(u => LengthUnit.fromString(u).toFox)
126126
voxelSize = VoxelSize.fromFactorAndUnitWithDefault(voxelSizeFactor, voxelSizeUnit)
127-
_ <- bool2Fox(request.identity._organization == organization._id) ~> FORBIDDEN
127+
_ <- bool2Fox(request.identity._organization == organization._id) ?~> "job.convertToWkw.notAllowed.organization" ~> FORBIDDEN
128128
dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organization._id) ?~> Messages(
129129
"dataset.notFound",
130130
datasetName) ~> NOT_FOUND
@@ -230,7 +230,9 @@ class JobController @Inject()(
230230
sil.SecuredAction.async { implicit request =>
231231
log(Some(slackNotificationService.noticeFailedJobRequest)) {
232232
for {
233-
organization <- organizationDAO.findOne(organizationId) ?~> Messages("organization.notFound", organizationId)
233+
organization <- organizationDAO.findOne(organizationId)(GlobalAccessContext) ?~> Messages(
234+
"organization.notFound",
235+
organizationId)
234236
_ <- bool2Fox(request.identity._organization == organization._id) ?~> "job.inferNeurons.notAllowed.organization" ~> FORBIDDEN
235237
dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organization._id) ?~> Messages(
236238
"dataset.notFound",
@@ -261,7 +263,9 @@ class JobController @Inject()(
261263
sil.SecuredAction.async { implicit request =>
262264
log(Some(slackNotificationService.noticeFailedJobRequest)) {
263265
for {
264-
organization <- organizationDAO.findOne(organizationId) ?~> Messages("organization.notFound", organizationId)
266+
organization <- organizationDAO.findOne(organizationId)(GlobalAccessContext) ?~> Messages(
267+
"organization.notFound",
268+
organizationId)
265269
_ <- bool2Fox(request.identity._organization == organization._id) ?~> "job.inferMitochondria.notAllowed.organization" ~> FORBIDDEN
266270
dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organization._id) ?~> Messages(
267271
"dataset.notFound",
@@ -293,7 +297,9 @@ class JobController @Inject()(
293297
sil.SecuredAction.async { implicit request =>
294298
log(Some(slackNotificationService.noticeFailedJobRequest)) {
295299
for {
296-
organization <- organizationDAO.findOne(organizationId) ?~> Messages("organization.notFound", organizationId)
300+
organization <- organizationDAO.findOne(organizationId)(GlobalAccessContext) ?~> Messages(
301+
"organization.notFound",
302+
organizationId)
297303
_ <- bool2Fox(request.identity._organization == organization._id) ?~> "job.alignSections.notAllowed.organization" ~> FORBIDDEN
298304
dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organization._id) ?~> Messages(
299305
"dataset.notFound",
@@ -412,7 +418,9 @@ class JobController @Inject()(
412418
sil.SecuredAction.async { implicit request =>
413419
log(Some(slackNotificationService.noticeFailedJobRequest)) {
414420
for {
415-
organization <- organizationDAO.findOne(organizationId) ?~> Messages("organization.notFound", organizationId)
421+
organization <- organizationDAO.findOne(organizationId)(GlobalAccessContext) ?~> Messages(
422+
"organization.notFound",
423+
organizationId)
416424
_ <- bool2Fox(request.identity._organization == organization._id) ?~> "job.findLargestSegmentId.notAllowed.organization" ~> FORBIDDEN
417425
dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organization._id) ?~> Messages(
418426
"dataset.notFound",
@@ -434,9 +442,11 @@ class JobController @Inject()(
434442
sil.SecuredAction.async(validateJson[AnimationJobOptions]) { implicit request =>
435443
log(Some(slackNotificationService.noticeFailedJobRequest)) {
436444
for {
437-
organization <- organizationDAO.findOne(organizationId) ?~> Messages("organization.notFound", organizationId)
438-
userOrganization <- organizationDAO.findOne(request.identity._organization)
445+
organization <- organizationDAO.findOne(organizationId)(GlobalAccessContext) ?~> Messages(
446+
"organization.notFound",
447+
organizationId)
439448
_ <- bool2Fox(request.identity._organization == organization._id) ?~> "job.renderAnimation.notAllowed.organization" ~> FORBIDDEN
449+
userOrganization <- organizationDAO.findOne(request.identity._organization)
440450
dataset <- datasetDAO.findOneByNameAndOrganization(datasetName, organization._id) ?~> Messages(
441451
"dataset.notFound",
442452
datasetName) ~> NOT_FOUND

conf/messages

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ dataLayer.wrongMag=DataLayer “{0}” does not have mag “{1}”
138138
dataLayer.invalidMag=Supplied “{0}” is not a valid mag format. Please use “x-y-z”
139139

140140
zarr.invalidChunkCoordinates=Invalid chunk coordinates. Expected dot separated coordinates like c.<additional_axes.>x.y.z
141-
zarr.invalidFirstChunkCoord="First Channel must be 0"
141+
zarr.invalidFirstChunkCoord=First Channel must be 0
142142
zarr.chunkNotFound=Could not find the requested chunk
143143
zarr.notEnoughCoordinates=Invalid number of chunk coordinates. Expected to get at least 3 dimensions and channel 0.
144144
zarr.invalidAdditionalCoordinates=Invalid additional coordinates for this data layer.
@@ -150,8 +150,8 @@ nml.file.noFile=No file or file with empty content uploaded
150150
nml.file.differentDatasets=Cannot upload tracings that belong to different datasets at once
151151
nml.parameters.notFound=No parameters section found
152152
nml.element.invalid=Invalid {0}
153-
nml.comment.node.invalid=Invalid node id of comment {0}"
154-
nml.node.id.invalid=Invalid {0} node id {1}"
153+
nml.comment.node.invalid=Invalid node id of comment {0}
154+
nml.node.id.invalid=Invalid {0} node id {1}
155155
nml.node.attribute.invalid=Invalid node {0} for node id {1}
156156
nml.edge.invalid=Invalid edge {0} {1}
157157
nml.tree.id.invalid=Invalid tree id {0}
@@ -321,6 +321,7 @@ job.invalidBoundingBox = The selected bounding box could not be parsed, must be
321321
job.invalidMag = The selected mag could not be parsed, must be x-y-z
322322
job.volumeExceeded = The volume of the selected bounding box is too large.
323323
job.edgeLengthExceeded = An edge length of the selected bounding box is too large.
324+
job.convertToWkw.notAllowed.organization = Converting to WKW is only allowed for datasets of your own organization.
324325
job.inferNuclei.notAllowed.organization = Currently nuclei inferral is only allowed for datasets of your own organization.
325326
job.inferNeurons.notAllowed.organization = Currently neuron inferral is only allowed for datasets of your own organization.
326327
job.meshFile.notAllowed.organization = Calculating mesh files is only allowed for datasets of your own organization.
@@ -329,10 +330,11 @@ job.globalizeFloodfill.notAllowed.organization = Globalizing floodfills is only
329330
job.materializeVolumeAnnotation.notAllowed.organization = Materializing volume annotations is only allowed for datasets of your own organization.
330331
job.noWorkerForDatastoreAndJob = No webknossos-worker supporting the requested job is available for the selected datastore.
331332
job.emailNotifactionsDisabled = Email notifications are not enabled for this job type.
332-
job.renderAnimation.notAllowed.organization = "Rendering animations is only allowed for datasets of your own organization."
333-
job.alignSections.notAllowed.organization = "Aligning sections is only allowed for datasets of your own organization."
334-
job.alignSections.notAllowed.onlySuperUsers = "For now, aligning sections is only allowed for super users."
335-
job.additionalCoordinates.invalid = "The passed additional coordinates are invalid."
333+
job.renderAnimation.notAllowed.organization = Rendering animations is only allowed for datasets of your own organization.
334+
job.alignSections.notAllowed.organization = Aligning sections is only allowed for datasets of your own organization.
335+
job.additionalCoordinates.invalid = The passed additional coordinates are invalid.
336+
job.trainModel.notAllowed.organization = Training AI models is only allowed for datasets of your own organization.
337+
job.runInference.notAllowed.organization = Running inference is only allowed for datasets of your own organization.
336338

337339
voxelytics.disabled = Voxelytics workflow reporting and logging are not enabled for this WEBKNOSSOS instance.
338340
voxelytics.runNotFound = Workflow runs not found

frontend/javascripts/admin/api/jobs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ type RunInferenceParameters = {
348348
annotationId?: string;
349349
aiModelId: string;
350350
datasetName: string;
351+
organizationId: string;
351352
colorLayerName: string;
352353
boundingBox: Vector6;
353354
newDatasetName: string;

frontend/javascripts/dashboard/explorative_annotations_view.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ class ExplorativeAnnotationsView extends React.PureComponent<Props, State> {
699699
</div>
700700
<div className="flex-container">
701701
<div className="flex-item" style={{ flexGrow: 0 }}>
702-
{teamTags.length > 0 ? <TeamOutlined /> : null}
702+
{teamTags.length > 0 ? <TeamOutlined className="icon-margin-right"/> : null}
703703
</div>
704704
<div className="flex-item">{teamTags}</div>
705705
</div>

frontend/javascripts/oxalis/view/action-bar/starting_job_modals.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,7 @@ function CustomAiModelInferenceForm() {
829829
aiModelId: form.getFieldValue("aiModel"),
830830
workflowYaml: useCustomWorkflow ? form.getFieldValue("workflowYaml") : undefined,
831831
datasetName: dataset.name,
832+
organizationId: dataset.owningOrganization,
832833
colorLayerName: colorLayer.name,
833834
boundingBox,
834835
newDatasetName: newDatasetName,

0 commit comments

Comments
 (0)