diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 9d54d690255..a91226bf10a 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -13,6 +13,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released ### Added - Hybrid tracings can now be imported directly in the tracing view via drag'n'drop. [#4837](https://github.com/scalableminds/webknossos/pull/4837) - The find data function now works for volume tracings, too. [#4847](https://github.com/scalableminds/webknossos/pull/4847) +- Added admins and dataset managers to dataset access list, as they can access all datasets of the organization. [#4862](https://github.com/scalableminds/webknossos/pull/4862) ### Changed - Brush circles are now connected with rectangles to provide a continuous stroke even if the brush is moved quickly. [#4785](https://github.com/scalableminds/webknossos/pull/4822) diff --git a/app/controllers/DataSetController.scala b/app/controllers/DataSetController.scala index 37391924028..d7a6bfec721 100755 --- a/app/controllers/DataSetController.scala +++ b/app/controllers/DataSetController.scala @@ -9,7 +9,7 @@ import com.scalableminds.util.tools.DefaultConverters._ import com.scalableminds.util.tools.{Fox, JsonHelper, Math} import models.binary._ import models.team.{OrganizationDAO, TeamDAO} -import models.user.{User, UserService} +import models.user.{User, UserDAO, UserService} import oxalis.security.{URLSharing, WkEnv} import play.api.cache.SyncCacheApi import play.api.i18n.{Messages, MessagesApi, MessagesProvider} @@ -21,6 +21,7 @@ import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.duration._ class DataSetController @Inject()(userService: UserService, + userDAO: UserDAO, dataSetService: DataSetService, dataSetAllowedTeamsDAO: DataSetAllowedTeamsDAO, dataSetDataLayerDAO: DataSetDataLayerDAO, @@ -176,11 +177,14 @@ class DataSetController @Inject()(userService: UserService, def accessList(organizationName: String, dataSetName: String) = sil.SecuredAction.async { implicit request => for { - dataSet <- dataSetDAO.findOneByNameAndOrganizationName(dataSetName, organizationName) ?~> notFoundMessage( - dataSetName) ~> NOT_FOUND + organization <- organizationDAO.findOneByName(organizationName) + dataSet <- dataSetDAO + .findOneByNameAndOrganization(dataSetName, organization._id) ?~> notFoundMessage(dataSetName) ~> NOT_FOUND allowedTeams <- dataSetService.allowedTeamIdsFor(dataSet._id) - users <- userService.findByTeams(allowedTeams) - usersJs <- Fox.serialCombined(users.distinct)(u => userService.compactWrites(u)) + usersByTeams <- userDAO.findAllByTeams(allowedTeams) + adminsAndDatasetManagers <- userDAO.findAdminsAndDatasetManagersByOrg(organization._id) + usersJs <- Fox.serialCombined((usersByTeams ++ adminsAndDatasetManagers).distinct)(u => + userService.compactWrites(u)) } yield { Ok(Json.toJson(usersJs)) } diff --git a/app/models/user/User.scala b/app/models/user/User.scala index b2912e89fed..840e4e78911 100755 --- a/app/models/user/User.scala +++ b/app/models/user/User.scala @@ -118,12 +118,13 @@ class UserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) parsed } - def findAllByTeams(teams: List[ObjectId], includeDeactivated: Boolean = true)(implicit ctx: DBAccessContext) = + def findAllByTeams(teams: List[ObjectId], includeDeactivated: Boolean = true)( + implicit ctx: DBAccessContext): Fox[List[User]] = if (teams.isEmpty) Fox.successful(List()) else for { accessQuery <- readAccessQuery - r <- run(sql"""select u.* + r <- run(sql"""select #${columnsWithPrefix("u.")} from (select #${columns} from #${existingCollectionName} where #${accessQuery}) u join webknossos.user_team_roles on u._id = webknossos.user_team_roles._user where webknossos.user_team_roles._team in #${writeStructTupleWithQuotes(teams.map(_.id))} and (u.isDeactivated = false or u.isDeactivated = ${includeDeactivated}) @@ -131,6 +132,20 @@ class UserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) parsed <- Fox.combined(r.toList.map(parse)) } yield parsed + def findAdminsAndDatasetManagersByOrg(organizationId: ObjectId)(implicit ctx: DBAccessContext): Fox[List[User]] = + for { + accessQuery <- readAccessQuery + r <- run(sql"""select #${columns} + from #${existingCollectionName} + where #${accessQuery} + and (isDatasetManager + or isAdmin) + and not isDeactivated + and _organization = $organizationId + order by _id""".as[UsersRow]) + parsed <- Fox.combined(r.toList.map(parse)) + } yield parsed + def findAllByIds(ids: List[ObjectId])(implicit ctx: DBAccessContext): Fox[List[User]] = for { accessQuery <- readAccessQuery diff --git a/app/models/user/UserService.scala b/app/models/user/UserService.scala index fd6f6324c6c..1b3a39ad86a 100755 --- a/app/models/user/UserService.scala +++ b/app/models/user/UserService.scala @@ -47,9 +47,6 @@ class UserService @Inject()(conf: WkConf, def defaultUser = userDAO.findOneByEmail(defaultUserEmail)(GlobalAccessContext) - def findByTeams(teams: List[ObjectId])(implicit ctx: DBAccessContext) = - userDAO.findAllByTeams(teams) - def findOneById(userId: ObjectId, useCache: Boolean)(implicit ctx: DBAccessContext): Fox[User] = if (useCache) userCache.findUser(userId) @@ -253,7 +250,7 @@ class UserService @Inject()(conf: WkConf, } def compactWrites(user: User): Fox[JsObject] = { - implicit val ctx = GlobalAccessContext + implicit val ctx: DBAccessContext = GlobalAccessContext for { teamMemberships <- teamMembershipsFor(user._id) teamMembershipsJs <- Fox.serialCombined(teamMemberships)(tm => teamMembershipService.publicWrites(tm)) @@ -263,6 +260,8 @@ class UserService @Inject()(conf: WkConf, "email" -> user.email, "firstName" -> user.firstName, "lastName" -> user.lastName, + "isAdmin" -> user.isAdmin, + "isDatasetManager" -> user.isDatasetManager, "isAnonymous" -> false, "teams" -> teamMembershipsJs ) diff --git a/frontend/javascripts/dashboard/advanced_dataset/dataset_access_list_view.js b/frontend/javascripts/dashboard/advanced_dataset/dataset_access_list_view.js index 9198c469864..6bff1f4a1f3 100644 --- a/frontend/javascripts/dashboard/advanced_dataset/dataset_access_list_view.js +++ b/frontend/javascripts/dashboard/advanced_dataset/dataset_access_list_view.js @@ -39,6 +39,30 @@ export default class DatasetAccessListView extends React.PureComponent { + if (user.isAdmin) { + return [ + + Admin + , + ]; + } else { + const managerTags = user.isDatasetManager + ? [ + + Dataset Manager + , + ] + : []; + const teamTags = user.teams.map(team => ( + + {team.name} + + )); + return managerTags.concat(teamTags); + } + } + renderTable() { return (
@@ -49,11 +73,7 @@ export default class DatasetAccessListView extends React.PureComponent {user.firstName} {user.lastName}
- {user.teams.map(team => ( - - {team.name} - - ))} + {this.renderUserTags(user)} ))} diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/annotations.e2e.js.md b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/annotations.e2e.js.md index 4fb38e7e940..7b2059ab25c 100644 --- a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/annotations.e2e.js.md +++ b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/annotations.e2e.js.md @@ -861,7 +861,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: 'id', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -945,7 +947,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: 'id', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -1078,7 +1082,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: 'id', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -1167,7 +1173,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: 'id', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -1295,7 +1303,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -1428,7 +1438,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: 'id', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -1517,7 +1529,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: 'id', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/annotations.e2e.js.snap b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/annotations.e2e.js.snap index cc84ad7e511..c07250438c1 100644 Binary files a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/annotations.e2e.js.snap and b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/annotations.e2e.js.snap differ diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.md b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.md index 2eb1aaf406a..53ef19b82c1 100644 --- a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.md +++ b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.md @@ -11,7 +11,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -35,7 +37,9 @@ Generated by [AVA](https://ava.li). email: 'user_B@scalableminds.com', firstName: 'user_B', id: '670b9f4d2a7c0e4d008da6ef', + isAdmin: false, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyB', teams: [ { @@ -49,7 +53,9 @@ Generated by [AVA](https://ava.li). email: 'user_C@scalableminds.com', firstName: 'user_C', id: '770b9f4d2a7c0e4d008da6ef', + isAdmin: false, isAnonymous: false, + isDatasetManager: false, lastName: 'BoyC', teams: [ { diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.snap b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.snap index ae9f0eccca5..c66bee43f18 100644 Binary files a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.snap and b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/datasets.e2e.js.snap differ diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/projects.e2e.js.md b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/projects.e2e.js.md index f11eb9701ca..89c2d4236c6 100644 --- a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/projects.e2e.js.md +++ b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/projects.e2e.js.md @@ -15,7 +15,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -62,7 +64,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -100,7 +104,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -134,7 +140,9 @@ Generated by [AVA](https://ava.li). email: 'user_D@scalableminds.com', firstName: 'user_D', id: '870b9f4d2a7c0e4d008da6ef', + isAdmin: false, isAnonymous: false, + isDatasetManager: false, lastName: 'BoyD', teams: [ { @@ -158,7 +166,9 @@ Generated by [AVA](https://ava.li). email: 'user_D@scalableminds.com', firstName: 'user_D', id: '870b9f4d2a7c0e4d008da6ef', + isAdmin: false, isAnonymous: false, + isDatasetManager: false, lastName: 'BoyD', teams: [ { @@ -182,7 +192,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -222,7 +234,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -257,7 +271,9 @@ Generated by [AVA](https://ava.li). email: 'user_D@scalableminds.com', firstName: 'user_D', id: '870b9f4d2a7c0e4d008da6ef', + isAdmin: false, isAnonymous: false, + isDatasetManager: false, lastName: 'BoyD', teams: [ { @@ -282,7 +298,9 @@ Generated by [AVA](https://ava.li). email: 'user_D@scalableminds.com', firstName: 'user_D', id: '870b9f4d2a7c0e4d008da6ef', + isAdmin: false, isAnonymous: false, + isDatasetManager: false, lastName: 'BoyD', teams: [ { @@ -307,7 +325,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -346,7 +366,9 @@ Generated by [AVA](https://ava.li). email: 'user_D@scalableminds.com', firstName: 'user_D', id: '870b9f4d2a7c0e4d008da6ef', + isAdmin: false, isAnonymous: false, + isDatasetManager: false, lastName: 'BoyD', teams: [ { @@ -373,7 +395,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -410,7 +434,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -447,7 +473,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -484,7 +512,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/projects.e2e.js.snap b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/projects.e2e.js.snap index ac4fe029817..e889bda5f80 100644 Binary files a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/projects.e2e.js.snap and b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/projects.e2e.js.snap differ diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/scripts.e2e.js.md b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/scripts.e2e.js.md index adb037d161d..c71693e26fe 100644 --- a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/scripts.e2e.js.md +++ b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/scripts.e2e.js.md @@ -14,7 +14,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -50,7 +52,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -83,7 +87,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -116,7 +122,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/scripts.e2e.js.snap b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/scripts.e2e.js.snap index 82b52873d0f..dc1a1cfdabd 100644 Binary files a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/scripts.e2e.js.snap and b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/scripts.e2e.js.snap differ diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/tasks.e2e.js.md b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/tasks.e2e.js.md index a1fdfdd9c21..72d3fcdc809 100644 --- a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/tasks.e2e.js.md +++ b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/tasks.e2e.js.md @@ -167,7 +167,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: 'id', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { @@ -296,7 +298,9 @@ Generated by [AVA](https://ava.li). email: 'user_A@scalableminds.com', firstName: 'user_A', id: '570b9f4d2a7c0e4d008da6ef', + isAdmin: true, isAnonymous: false, + isDatasetManager: true, lastName: 'BoyA', teams: [ { diff --git a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/tasks.e2e.js.snap b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/tasks.e2e.js.snap index a62467ca834..aa8f9a5dcfb 100644 Binary files a/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/tasks.e2e.js.snap and b/frontend/javascripts/test/snapshots/public/test-bundle/test/backend-snapshot-tests/tasks.e2e.js.snap differ