From b3fdae4e7d7e757b7451c551f9c42276e4a0ca84 Mon Sep 17 00:00:00 2001 From: Florian M Date: Wed, 14 Dec 2022 12:17:15 +0100 Subject: [PATCH 1/2] add protected and private modifiers to DAO hierarchy --- app/WebKnossosModule.scala | 1 - app/controllers/InitialDataController.scala | 3 +- app/controllers/TeamController.scala | 10 +-- app/models/annotation/Annotation.scala | 36 ++++---- .../annotation/AnnotationPrivateLink.scala | 10 +-- app/models/annotation/AnnotationService.scala | 7 +- app/models/annotation/TracingStore.scala | 8 +- app/models/binary/DataSet.scala | 12 +-- app/models/binary/DataStore.scala | 10 +-- app/models/binary/Publication.scala | 8 +- app/models/folder/Folder.scala | 16 ++-- app/models/job/Job.scala | 10 +-- app/models/job/Worker.scala | 8 +- app/models/mesh/Mesh.scala | 10 +-- app/models/organization/Organization.scala | 12 +-- app/models/project/Project.scala | 12 +-- app/models/shortlinks/ShortLink.scala | 8 +- app/models/task/Script.scala | 10 +-- app/models/task/Task.scala | 12 +-- app/models/task/TaskCreationService.scala | 6 +- app/models/task/TaskType.scala | 12 +-- app/models/team/Team.scala | 12 +-- app/models/user/Invite.scala | 8 +- app/models/user/MultiUser.scala | 8 +- app/models/user/User.scala | 38 ++++---- app/models/user/UserService.scala | 9 +- app/models/user/time/TimeSpan.scala | 8 +- app/oxalis/security/Token.scala | 8 +- app/utils/SQLHelpers.scala | 88 +++++++++---------- 29 files changed, 194 insertions(+), 206 deletions(-) diff --git a/app/WebKnossosModule.scala b/app/WebKnossosModule.scala index 951a8858bea..105bee3fa1e 100644 --- a/app/WebKnossosModule.scala +++ b/app/WebKnossosModule.scala @@ -21,7 +21,6 @@ class WebKnossosModule extends AbstractModule { bind(classOf[UserService]).asEagerSingleton() bind(classOf[TaskService]).asEagerSingleton() bind(classOf[UserDAO]).asEagerSingleton() - bind(classOf[UserTeamRolesDAO]).asEagerSingleton() bind(classOf[UserExperiencesDAO]).asEagerSingleton() bind(classOf[UserDataSetConfigurationDAO]).asEagerSingleton() bind(classOf[UserCache]).asEagerSingleton() diff --git a/app/controllers/InitialDataController.scala b/app/controllers/InitialDataController.scala index c4a9357248b..3c8581ad941 100644 --- a/app/controllers/InitialDataController.scala +++ b/app/controllers/InitialDataController.scala @@ -38,7 +38,6 @@ class InitialDataController @Inject()(initialDataService: InitialDataService, si class InitialDataService @Inject()(userService: UserService, userDAO: UserDAO, multiUserDAO: MultiUserDAO, - userTeamRolesDAO: UserTeamRolesDAO, userExperiencesDAO: UserExperiencesDAO, taskTypeDAO: TaskTypeDAO, dataStoreDAO: DataStoreDAO, @@ -182,7 +181,7 @@ Samplecountry _ <- multiUserDAO.insertOne(multiUser) _ <- userDAO.insertOne(user) _ <- userExperiencesDAO.updateExperiencesForUser(user, Map("sampleExp" -> 10)) - _ <- userTeamRolesDAO.insertTeamMembership( + _ <- userDAO.insertTeamMembership( user._id, TeamMembership(organizationTeam._id, isTeamManager = isTeamManager)) _ = logger.info("Inserted default user") diff --git a/app/controllers/TeamController.scala b/app/controllers/TeamController.scala index e757a275f35..d5aba6b3c92 100755 --- a/app/controllers/TeamController.scala +++ b/app/controllers/TeamController.scala @@ -4,19 +4,19 @@ import com.mohiva.play.silhouette.api.Silhouette import com.scalableminds.util.tools.Fox import io.swagger.annotations._ import models.team._ -import models.user.UserTeamRolesDAO +import models.user.UserDAO import oxalis.security.WkEnv import play.api.i18n.Messages import play.api.libs.json._ -import utils.ObjectId -import javax.inject.Inject import play.api.mvc.{Action, AnyContent} +import utils.ObjectId +import javax.inject.Inject import scala.concurrent.ExecutionContext @Api class TeamController @Inject()(teamDAO: TeamDAO, - userTeamRolesDAO: UserTeamRolesDAO, + userDAO: UserDAO, teamService: TeamService, sil: Silhouette[WkEnv])(implicit ec: ExecutionContext) extends Controller { @@ -46,7 +46,7 @@ class TeamController @Inject()(teamDAO: TeamDAO, _ <- bool2Fox(!team.isOrganizationTeam) ?~> "team.delete.organizationTeam" ~> FORBIDDEN _ <- teamService.assertNoReferences(teamIdValidated) ?~> "team.delete.inUse" ~> FORBIDDEN _ <- teamDAO.deleteOne(teamIdValidated) - _ <- userTeamRolesDAO.removeTeamFromAllUsers(teamIdValidated) + _ <- userDAO.removeTeamFromAllUsers(teamIdValidated) _ <- teamDAO.removeTeamFromAllDatasetsAndFolders(teamIdValidated) } yield JsonOk(Messages("team.deleted")) } diff --git a/app/models/annotation/Annotation.scala b/app/models/annotation/Annotation.scala index ad0115cb91d..fa650dce7d9 100755 --- a/app/models/annotation/Annotation.scala +++ b/app/models/annotation/Annotation.scala @@ -144,12 +144,12 @@ class AnnotationLayerDAO @Inject()(SQLClient: SQLClient)(implicit ec: ExecutionC class AnnotationDAO @Inject()(sqlClient: SQLClient, annotationLayerDAO: AnnotationLayerDAO)( implicit ec: ExecutionContext) extends SQLDAO[Annotation, AnnotationsRow, Annotations](sqlClient) { - val collection = Annotations + protected val collection = Annotations - def idColumn(x: Annotations): Rep[String] = x._Id - def isDeletedColumn(x: Annotations): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Annotations): Rep[String] = x._Id + protected def isDeletedColumn(x: Annotations): Rep[Boolean] = x.isdeleted - def parse(r: AnnotationsRow): Fox[Annotation] = + protected def parse(r: AnnotationsRow): Fox[Annotation] = for { state <- AnnotationState.fromString(r.state).toFox typ <- AnnotationType.fromString(r.typ).toFox @@ -180,7 +180,7 @@ class AnnotationDAO @Inject()(sqlClient: SQLClient, annotationLayerDAO: Annotati ) } - override def anonymousReadAccessQ(sharingToken: Option[String]) = s"visibility = '${AnnotationVisibility.Public}'" + protected override def anonymousReadAccessQ(sharingToken: Option[String]) = s"visibility = '${AnnotationVisibility.Public}'" private def listAccessQ(requestingUserId: ObjectId): String = s""" @@ -206,7 +206,7 @@ class AnnotationDAO @Inject()(sqlClient: SQLClient, annotationLayerDAO: Annotati ) """ - override def readAccessQ(requestingUserId: ObjectId): String = + override protected def readAccessQ(requestingUserId: ObjectId): String = s"""( visibility = '${AnnotationVisibility.Public}' or (visibility = '${AnnotationVisibility.Internal}' @@ -218,12 +218,12 @@ class AnnotationDAO @Inject()(sqlClient: SQLClient, annotationLayerDAO: Annotati in (select _organization from webknossos.users_ where _id = '$requestingUserId' and isAdmin) )""" - override def deleteAccessQ(requestingUserId: ObjectId) = + override protected def deleteAccessQ(requestingUserId: ObjectId) = s"""(_team in (select _team from webknossos.user_team_roles where isTeamManager and _user = '$requestingUserId') or _user = '$requestingUserId' or (select _organization from webknossos.teams where webknossos.teams._id = _team) in (select _organization from webknossos.users_ where _id = '$requestingUserId' and isAdmin))""" - override def updateAccessQ(requestingUserId: ObjectId): String = + override protected def updateAccessQ(requestingUserId: ObjectId): String = deleteAccessQ(requestingUserId) // read operations @@ -543,36 +543,32 @@ class AnnotationDAO @Inject()(sqlClient: SQLClient, annotationLayerDAO: Annotati _ <- run( sqlu"insert into webknossos.annotation_contributors (_annotation, _user) values($id, $userId) on conflict do nothing") } yield () -} - -class SharedAnnotationsDAO @Inject()(annotationDAO: AnnotationDAO, sqlClient: SQLClient)(implicit ec: ExecutionContext) - extends SimpleSQLDAO(sqlClient) { // Does not use access query (because they dont support prefixes). Use only after separate access check! def findAllSharedForTeams(teams: List[ObjectId]): Fox[List[Annotation]] = for { result <- run( - sql"""select distinct #${annotationDAO.columnsWithPrefix("a.")} from webknossos.annotations_ a + sql"""select distinct #${columnsWithPrefix("a.")} from webknossos.annotations_ a join webknossos.annotation_sharedTeams l on a._id = l._annotation where l._team in #${writeStructTupleWithQuotes(teams.map(t => sanitize(t.toString)))}""" .as[AnnotationsRow]) - parsed <- Fox.combined(result.toList.map(annotationDAO.parse)) + parsed <- Fox.combined(result.toList.map(parse)) } yield parsed def updateTeamsForSharedAnnotation(annotationId: ObjectId, teams: List[ObjectId])( - implicit ctx: DBAccessContext): Fox[Unit] = { + implicit ctx: DBAccessContext): Fox[Unit] = { val clearQuery = sqlu"delete from webknossos.annotation_sharedTeams where _annotation = $annotationId" - val insertQueries = teams.map(teamId => sqlu"""insert into webknossos.annotation_sharedTeams(_annotation, _team) + val insertQueries = teams.map(teamId => + sqlu"""insert into webknossos.annotation_sharedTeams(_annotation, _team) values($annotationId, $teamId)""") val composedQuery = DBIO.sequence(List(clearQuery) ++ insertQueries) for { - _ <- annotationDAO.assertUpdateAccess(annotationId) + _ <- assertUpdateAccess(annotationId) _ <- run(composedQuery.transactionally.withTransactionIsolation(Serializable), - retryCount = 50, - retryIfErrorContains = List(transactionSerializationError)) + retryCount = 50, + retryIfErrorContains = List(transactionSerializationError)) } yield () } - } diff --git a/app/models/annotation/AnnotationPrivateLink.scala b/app/models/annotation/AnnotationPrivateLink.scala index 2ccc68e4f10..ec533296380 100644 --- a/app/models/annotation/AnnotationPrivateLink.scala +++ b/app/models/annotation/AnnotationPrivateLink.scala @@ -45,13 +45,13 @@ class AnnotationPrivateLinkService @Inject()()(implicit ec: ExecutionContext) { class AnnotationPrivateLinkDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[AnnotationPrivateLink, AnnotationPrivatelinksRow, AnnotationPrivatelinks](sqlClient) { - val collection = AnnotationPrivatelinks + protected val collection = AnnotationPrivatelinks - def idColumn(x: AnnotationPrivatelinks): Rep[String] = x._Id + protected def idColumn(x: AnnotationPrivatelinks): Rep[String] = x._Id - def isDeletedColumn(x: AnnotationPrivatelinks): Rep[Boolean] = x.isdeleted + protected def isDeletedColumn(x: AnnotationPrivatelinks): Rep[Boolean] = x.isdeleted - def parse(r: AnnotationPrivatelinksRow): Fox[AnnotationPrivateLink] = + protected def parse(r: AnnotationPrivatelinksRow): Fox[AnnotationPrivateLink] = Fox.successful( AnnotationPrivateLink( ObjectId(r._Id), @@ -62,7 +62,7 @@ class AnnotationPrivateLinkDAO @Inject()(sqlClient: SQLClient)(implicit ec: Exec ) ) - override def readAccessQ(requestingUserId: ObjectId): String = + override protected def readAccessQ(requestingUserId: ObjectId): String = s"""(_annotation in (select _id from webknossos.annotations_ where _user = '${requestingUserId.id}'))""" def insertOne(aPL: AnnotationPrivateLink): Fox[Unit] = diff --git a/app/models/annotation/AnnotationService.scala b/app/models/annotation/AnnotationService.scala index 84a73e94adb..bd9fcea1e1c 100755 --- a/app/models/annotation/AnnotationService.scala +++ b/app/models/annotation/AnnotationService.scala @@ -105,8 +105,7 @@ class AnnotationService @Inject()( nmlWriter: NmlWriter, temporaryFileCreator: TemporaryFileCreator, meshDAO: MeshDAO, - meshService: MeshService, - sharedAnnotationsDAO: SharedAnnotationsDAO + meshService: MeshService )(implicit ec: ExecutionContext, val materializer: Materializer) extends BoxImplicits with FoxImplicits @@ -589,11 +588,11 @@ class AnnotationService @Inject()( // Does not use access query (because they dont support prefixes). Use only after separate access check! def sharedAnnotationsFor(userTeams: List[ObjectId]): Fox[List[Annotation]] = - sharedAnnotationsDAO.findAllSharedForTeams(userTeams) + annotationDAO.findAllSharedForTeams(userTeams) def updateTeamsForSharedAnnotation(annotationId: ObjectId, teams: List[ObjectId])( implicit ctx: DBAccessContext): Fox[Unit] = - sharedAnnotationsDAO.updateTeamsForSharedAnnotation(annotationId, teams) + annotationDAO.updateTeamsForSharedAnnotation(annotationId, teams) def zipAnnotations(annotations: List[Annotation], zipFileName: String, skipVolumeData: Boolean)( implicit diff --git a/app/models/annotation/TracingStore.scala b/app/models/annotation/TracingStore.scala index c501094d3c4..44776df99ae 100644 --- a/app/models/annotation/TracingStore.scala +++ b/app/models/annotation/TracingStore.scala @@ -59,12 +59,12 @@ class TracingStoreService @Inject()(tracingStoreDAO: TracingStoreDAO, rpc: RPC)( class TracingStoreDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[TracingStore, TracingstoresRow, Tracingstores](sqlClient) { - val collection = Tracingstores + protected val collection = Tracingstores - def idColumn(x: Tracingstores): Rep[String] = x.name - def isDeletedColumn(x: Tracingstores): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Tracingstores): Rep[String] = x.name + protected def isDeletedColumn(x: Tracingstores): Rep[Boolean] = x.isdeleted - def parse(r: TracingstoresRow): Fox[TracingStore] = + protected def parse(r: TracingstoresRow): Fox[TracingStore] = Fox.successful( TracingStore( r.name, diff --git a/app/models/binary/DataSet.scala b/app/models/binary/DataSet.scala index 3f72377403a..03868cd5882 100755 --- a/app/models/binary/DataSet.scala +++ b/app/models/binary/DataSet.scala @@ -62,11 +62,11 @@ class DataSetDAO @Inject()(sqlClient: SQLClient, dataSetDataLayerDAO: DataSetDataLayerDAO, organizationDAO: OrganizationDAO)(implicit ec: ExecutionContext) extends SQLDAO[DataSet, DatasetsRow, Datasets](sqlClient) { - val collection = Datasets + protected val collection = Datasets - def idColumn(x: Datasets): Rep[String] = x._Id + protected def idColumn(x: Datasets): Rep[String] = x._Id - def isDeletedColumn(x: Datasets): Rep[Boolean] = x.isdeleted + protected def isDeletedColumn(x: Datasets): Rep[Boolean] = x.isdeleted private def parseScaleOpt(literalOpt: Option[String]): Fox[Option[Vec3Double]] = literalOpt match { case Some(literal) => @@ -79,7 +79,7 @@ class DataSetDAO @Inject()(sqlClient: SQLClient, private def writeScaleLiteral(scale: Vec3Double): String = writeStructTuple(List(scale.x, scale.y, scale.z).map(_.toString)) - def parse(r: DatasetsRow): Fox[DataSet] = + protected def parse(r: DatasetsRow): Fox[DataSet] = for { scale <- parseScaleOpt(r.scale) defaultViewConfigurationOpt <- Fox.runOptional(r.defaultviewconfiguration)( @@ -405,7 +405,7 @@ class DataSetDAO @Inject()(sqlClient: SQLClient, class DataSetResolutionsDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SimpleSQLDAO(sqlClient) { - def parseRow(row: DatasetResolutionsRow): Fox[Vec3Int] = + private def parseRow(row: DatasetResolutionsRow): Fox[Vec3Int] = for { resolution <- Vec3Int.fromList(parseArrayTuple(row.resolution).map(_.toInt)) ?~> "could not parse resolution" } yield resolution @@ -447,7 +447,7 @@ class DataSetDataLayerDAO @Inject()(sqlClient: SQLClient, dataSetResolutionsDAO: implicit ec: ExecutionContext) extends SimpleSQLDAO(sqlClient) { - def parseRow(row: DatasetLayersRow, dataSetId: ObjectId, skipResolutions: Boolean = false): Fox[DataLayer] = { + private def parseRow(row: DatasetLayersRow, dataSetId: ObjectId, skipResolutions: Boolean): Fox[DataLayer] = { val result: Fox[Fox[DataLayer]] = for { category <- Category.fromString(row.category).toFox ?~> "Could not parse Layer Category" boundingBox <- BoundingBox diff --git a/app/models/binary/DataStore.scala b/app/models/binary/DataStore.scala index cba1ca7602d..21dbc00a33d 100644 --- a/app/models/binary/DataStore.scala +++ b/app/models/binary/DataStore.scala @@ -82,15 +82,15 @@ class DataStoreService @Inject()(dataStoreDAO: DataStoreDAO)(implicit ec: Execut class DataStoreDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[DataStore, DatastoresRow, Datastores](sqlClient) { - val collection = Datastores + protected val collection = Datastores - def idColumn(x: Datastores): Rep[String] = x.name - def isDeletedColumn(x: Datastores): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Datastores): Rep[String] = x.name + protected def isDeletedColumn(x: Datastores): Rep[Boolean] = x.isdeleted - override def readAccessQ(requestingUserId: ObjectId): String = + override protected def readAccessQ(requestingUserId: ObjectId): String = s"(onlyAllowedOrganization is null) OR (onlyAllowedOrganization in (select _organization from webknossos.users_ where _id = '$requestingUserId'))" - def parse(r: DatastoresRow): Fox[DataStore] = + protected def parse(r: DatastoresRow): Fox[DataStore] = Fox.successful( DataStore( r.name, diff --git a/app/models/binary/Publication.scala b/app/models/binary/Publication.scala index c153a34fdc8..10d124a3018 100644 --- a/app/models/binary/Publication.scala +++ b/app/models/binary/Publication.scala @@ -54,13 +54,13 @@ class PublicationService @Inject()(dataSetService: DataSetService, class PublicationDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Publication, PublicationsRow, Publications](sqlClient) { - val collection = Publications + protected val collection = Publications - def idColumn(x: Publications): Rep[String] = x._Id + protected def idColumn(x: Publications): Rep[String] = x._Id - def isDeletedColumn(x: Publications): Rep[Boolean] = x.isdeleted + protected def isDeletedColumn(x: Publications): Rep[Boolean] = x.isdeleted - def parse(r: PublicationsRow): Fox[Publication] = + protected def parse(r: PublicationsRow): Fox[Publication] = Fox.successful( Publication( ObjectId(r._Id), diff --git a/app/models/folder/Folder.scala b/app/models/folder/Folder.scala index 30bac9822df..656e75552cd 100644 --- a/app/models/folder/Folder.scala +++ b/app/models/folder/Folder.scala @@ -75,22 +75,22 @@ class FolderService @Inject()(teamDAO: TeamDAO, class FolderDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Folder, FoldersRow, Folders](sqlClient) { - val collection = Folders - def idColumn(x: Folders): Rep[String] = x._Id - def isDeletedColumn(x: Folders): Rep[Boolean] = x.isdeleted + protected val collection = Folders + protected def idColumn(x: Folders): Rep[String] = x._Id + protected def isDeletedColumn(x: Folders): Rep[Boolean] = x.isdeleted - def parse(r: FoldersRow): Fox[Folder] = + protected def parse(r: FoldersRow): Fox[Folder] = Fox.successful(Folder(ObjectId(r._Id), r.name)) - def parseWithParent(t: (String, String, Option[String])): Fox[FolderWithParent] = + private def parseWithParent(t: (String, String, Option[String])): Fox[FolderWithParent] = Fox.successful(FolderWithParent(ObjectId(t._1), t._2, t._3.map(ObjectId(_)))) - override def readAccessQ(requestingUserId: ObjectId): String = readAccessQWithPrefix(requestingUserId, "") + override protected def readAccessQ(requestingUserId: ObjectId): String = readAccessQWithPrefix(requestingUserId, "") - def readAccessQWithPrefix(requestingUserId: ObjectId, prefix: String): String = + private def readAccessQWithPrefix(requestingUserId: ObjectId, prefix: String): String = rawAccessQ(write = false, requestingUserId, prefix) - override def updateAccessQ(requestingUserId: ObjectId): String = + override protected def updateAccessQ(requestingUserId: ObjectId): String = rawAccessQ(write = true, requestingUserId, prefix = "") private def rawAccessQ(write: Boolean, requestingUserId: ObjectId, prefix: String): String = { diff --git a/app/models/job/Job.scala b/app/models/job/Job.scala index a50d44aab6f..8bd16732573 100644 --- a/app/models/job/Job.scala +++ b/app/models/job/Job.scala @@ -92,12 +92,12 @@ case class Job( class JobDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Job, JobsRow, Jobs](sqlClient) { - val collection = Jobs + protected val collection = Jobs - def idColumn(x: Jobs): Rep[String] = x._Id - def isDeletedColumn(x: Jobs): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Jobs): Rep[String] = x._Id + protected def isDeletedColumn(x: Jobs): Rep[Boolean] = x.isdeleted - def parse(r: JobsRow): Fox[Job] = + protected def parse(r: JobsRow): Fox[Job] = for { manualStateOpt <- Fox.runOptional(r.manualstate)(JobState.fromString) state <- JobState.fromString(r.state) @@ -120,7 +120,7 @@ class JobDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) ) } - override def readAccessQ(requestingUserId: ObjectId) = + override protected def readAccessQ(requestingUserId: ObjectId) = s"""_owner = '$requestingUserId'""" override def findAll(implicit ctx: DBAccessContext): Fox[List[Job]] = diff --git a/app/models/job/Worker.scala b/app/models/job/Worker.scala index 4ab64b52e6d..0fbe7ee49da 100644 --- a/app/models/job/Worker.scala +++ b/app/models/job/Worker.scala @@ -30,13 +30,13 @@ case class Worker(_id: ObjectId, class WorkerDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Worker, WorkersRow, Workers](sqlClient) { - val collection = Workers + protected val collection = Workers - def idColumn(x: Workers): Rep[String] = x._Id + protected def idColumn(x: Workers): Rep[String] = x._Id - def isDeletedColumn(x: Workers): Rep[Boolean] = x.isdeleted + protected def isDeletedColumn(x: Workers): Rep[Boolean] = x.isdeleted - def parse(r: WorkersRow): Fox[Worker] = + protected def parse(r: WorkersRow): Fox[Worker] = Fox.successful( Worker( ObjectId(r._Id), diff --git a/app/models/mesh/Mesh.scala b/app/models/mesh/Mesh.scala index ed4cb022bd9..3f20ab9be3e 100644 --- a/app/models/mesh/Mesh.scala +++ b/app/models/mesh/Mesh.scala @@ -55,19 +55,19 @@ class MeshService @Inject()()(implicit ec: ExecutionContext) { class MeshDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[MeshInfo, MeshesRow, Meshes](sqlClient) { - val collection = Meshes + protected val collection = Meshes - def idColumn(x: Meshes): Rep[String] = x._Id + protected def idColumn(x: Meshes): Rep[String] = x._Id - def isDeletedColumn(x: Meshes): Rep[Boolean] = x.isdeleted + protected def isDeletedColumn(x: Meshes): Rep[Boolean] = x.isdeleted private val infoColumns = (columnsList diff Seq("data")).mkString(", ") type InfoTuple = (ObjectId, ObjectId, String, String, Instant, Boolean) - override def parse(r: MeshesRow): Fox[MeshInfo] = + override protected def parse(r: MeshesRow): Fox[MeshInfo] = Fox.failure("not implemented, use parseInfo or get the data directly") - def parseInfo(r: InfoTuple): Fox[MeshInfo] = + private def parseInfo(r: InfoTuple): Fox[MeshInfo] = for { position <- Vec3Int.fromList(parseArrayTuple(r._4).map(_.toInt)) ?~> "could not parse mesh position" } yield { diff --git a/app/models/organization/Organization.scala b/app/models/organization/Organization.scala index f46b424284e..3b912c774a3 100755 --- a/app/models/organization/Organization.scala +++ b/app/models/organization/Organization.scala @@ -31,13 +31,13 @@ case class Organization( class OrganizationDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Organization, OrganizationsRow, Organizations](sqlClient) { - val collection = Organizations + protected val collection = Organizations - def idColumn(x: Organizations): Rep[String] = x._Id + protected def idColumn(x: Organizations): Rep[String] = x._Id - def isDeletedColumn(x: Organizations): Rep[Boolean] = x.isdeleted + protected def isDeletedColumn(x: Organizations): Rep[Boolean] = x.isdeleted - def parse(r: OrganizationsRow): Fox[Organization] = + protected def parse(r: OrganizationsRow): Fox[Organization] = for { pricingPlan <- PricingPlan.fromString(r.pricingplan).toFox } yield { @@ -57,11 +57,11 @@ class OrganizationDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionCont ) } - override def readAccessQ(requestingUserId: ObjectId): String = + override protected def readAccessQ(requestingUserId: ObjectId): String = s"((_id in (select _organization from webknossos.users_ where _multiUser = (select _multiUser from webknossos.users_ where _id = '$requestingUserId')))" + s"or 'true' in (select isSuperUser from webknossos.multiUsers_ where _id in (select _multiUser from webknossos.users_ where _id = '$requestingUserId')))" - override def anonymousReadAccessQ(sharingToken: Option[String]): String = sharingToken match { + override protected def anonymousReadAccessQ(sharingToken: Option[String]): String = sharingToken match { case Some(_) => "true" case _ => "false" } diff --git a/app/models/project/Project.scala b/app/models/project/Project.scala index 6e5d3407f82..b0a825cd57e 100755 --- a/app/models/project/Project.scala +++ b/app/models/project/Project.scala @@ -57,12 +57,12 @@ object Project { class ProjectDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Project, ProjectsRow, Projects](sqlClient) { - val collection = Projects + protected val collection = Projects - def idColumn(x: Projects): Rep[String] = x._Id - def isDeletedColumn(x: Projects): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Projects): Rep[String] = x._Id + protected def isDeletedColumn(x: Projects): Rep[Boolean] = x.isdeleted - def parse(r: ProjectsRow): Fox[Project] = + protected def parse(r: ProjectsRow): Fox[Project] = Fox.successful( Project( ObjectId(r._Id), @@ -77,13 +77,13 @@ class ProjectDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) r.isdeleted )) - override def readAccessQ(requestingUserId: ObjectId) = + override protected def readAccessQ(requestingUserId: ObjectId) = s"""( (_team in (select _team from webknossos.user_team_roles where _user = '${requestingUserId.id}')) or _owner = '${requestingUserId.id}' or _organization = (select _organization from webknossos.users_ where _id = '${requestingUserId.id}' and isAdmin) )""" - override def deleteAccessQ(requestingUserId: ObjectId) = s"_owner = '${requestingUserId.id}'" + override protected def deleteAccessQ(requestingUserId: ObjectId) = s"_owner = '${requestingUserId.id}'" // read operations diff --git a/app/models/shortlinks/ShortLink.scala b/app/models/shortlinks/ShortLink.scala index 079ebfe82ef..03b7d5dbd76 100644 --- a/app/models/shortlinks/ShortLink.scala +++ b/app/models/shortlinks/ShortLink.scala @@ -19,13 +19,13 @@ object ShortLink { class ShortLinkDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[ShortLink, ShortlinksRow, Shortlinks](sqlClient) { - val collection = Shortlinks + protected val collection = Shortlinks - def idColumn(x: Shortlinks): Rep[String] = x._Id + protected def idColumn(x: Shortlinks): Rep[String] = x._Id - override def isDeletedColumn(x: Tables.Shortlinks): Rep[Boolean] = false + override protected def isDeletedColumn(x: Tables.Shortlinks): Rep[Boolean] = false - def parse(r: ShortlinksRow): Fox[ShortLink] = + protected def parse(r: ShortlinksRow): Fox[ShortLink] = Fox.successful( ShortLink( ObjectId(r._Id), diff --git a/app/models/task/Script.scala b/app/models/task/Script.scala index 29c23d6110b..0e540f7ed41 100644 --- a/app/models/task/Script.scala +++ b/app/models/task/Script.scala @@ -47,15 +47,15 @@ object Script { class ScriptDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Script, ScriptsRow, Scripts](sqlClient) { - val collection = Scripts + protected val collection = Scripts - def idColumn(x: Scripts): Rep[String] = x._Id - def isDeletedColumn(x: Scripts): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Scripts): Rep[String] = x._Id + protected def isDeletedColumn(x: Scripts): Rep[Boolean] = x.isdeleted - override def readAccessQ(requestingUserId: ObjectId): String = + override protected def readAccessQ(requestingUserId: ObjectId): String = s"(select _organization from webknossos.users_ u where u._id = _owner) = (select _organization from webknossos.users_ u where u._id = '$requestingUserId')" - def parse(r: ScriptsRow): Fox[Script] = + protected def parse(r: ScriptsRow): Fox[Script] = Fox.successful( Script( ObjectId(r._Id), diff --git a/app/models/task/Task.scala b/app/models/task/Task.scala index cf956dfe480..99aad97d2c1 100755 --- a/app/models/task/Task.scala +++ b/app/models/task/Task.scala @@ -36,12 +36,12 @@ case class Task( class TaskDAO @Inject()(sqlClient: SQLClient, projectDAO: ProjectDAO)(implicit ec: ExecutionContext) extends SQLDAO[Task, TasksRow, Tasks](sqlClient) { - val collection = Tasks + protected val collection = Tasks - def idColumn(x: Tasks): profile.api.Rep[String] = x._Id - def isDeletedColumn(x: Tasks): profile.api.Rep[Boolean] = x.isdeleted + protected def idColumn(x: Tasks): profile.api.Rep[String] = x._Id + protected def isDeletedColumn(x: Tasks): profile.api.Rep[Boolean] = x.isdeleted - def parse(r: TasksRow): Fox[Task] = + protected def parse(r: TasksRow): Fox[Task] = for { editPosition <- Vec3Int.fromList(parseArrayTuple(r.editposition).map(_.toInt)) ?~> "could not parse edit position" editRotation <- Vec3Double.fromList(parseArrayTuple(r.editrotation).map(_.toDouble)) ?~> "could not parse edit rotation" @@ -64,11 +64,11 @@ class TaskDAO @Inject()(sqlClient: SQLClient, projectDAO: ProjectDAO)(implicit e ) } - override def readAccessQ(requestingUserId: ObjectId) = + override protected def readAccessQ(requestingUserId: ObjectId) = s"""((select _team from webknossos.projects p where _project = p._id) in (select _team from webknossos.user_team_roles where _user = '${requestingUserId.id}') or ((select _organization from webknossos.teams where webknossos.teams._id = (select _team from webknossos.projects p where _project = p._id)) in (select _organization from webknossos.users_ where _id = '${requestingUserId.id}' and isAdmin)))""" - override def deleteAccessQ(requestingUserId: ObjectId) = + override protected def deleteAccessQ(requestingUserId: ObjectId) = s"""((select _team from webknossos.projects p where _project = p._id) in (select _team from webknossos.user_team_roles where isTeamManager and _user = '${requestingUserId.id}') or ((select _organization from webknossos.teams where webknossos.teams._id = (select _team from webknossos.projects p where _project = p._id)) in (select _organization from webknossos.users_ where _id = '${requestingUserId.id}' and isAdmin)))""" diff --git a/app/models/task/TaskCreationService.scala b/app/models/task/TaskCreationService.scala index 379b977a2bc..39072b2cde2 100644 --- a/app/models/task/TaskCreationService.scala +++ b/app/models/task/TaskCreationService.scala @@ -16,7 +16,7 @@ import models.annotation._ import models.binary.{DataSet, DataSetDAO, DataSetService} import models.project.{Project, ProjectDAO} import models.team.{Team, TeamDAO, TeamService} -import models.user.{User, UserExperiencesDAO, UserService, UserTeamRolesDAO} +import models.user.{User, UserDAO, UserExperiencesDAO, UserService} import net.liftweb.common.{Box, Empty, Failure, Full} import oxalis.telemetry.SlackNotificationService import play.api.i18n.{Messages, MessagesProvider} @@ -33,7 +33,7 @@ class TaskCreationService @Inject()(taskTypeService: TaskTypeService, userService: UserService, teamDAO: TeamDAO, teamService: TeamService, - userTeamRolesDAO: UserTeamRolesDAO, + userDAO: UserDAO, slackNotificationService: SlackNotificationService, projectDAO: ProjectDAO, annotationDAO: AnnotationDAO, @@ -506,7 +506,7 @@ class TaskCreationService @Inject()(taskTypeService: TaskTypeService, if (dataSetTeams.isEmpty) Fox.successful(Some(subteamId)) else { for { - memberDifference <- userTeamRolesDAO.findMemberDifference(subteamId, dataSetTeams) + memberDifference <- userDAO.findTeamMemberDifference(subteamId, dataSetTeams) } yield if (memberDifference.isEmpty) None else Some(subteamId) } diff --git a/app/models/task/TaskType.scala b/app/models/task/TaskType.scala index e8428f8f503..bda72f3a50a 100755 --- a/app/models/task/TaskType.scala +++ b/app/models/task/TaskType.scala @@ -78,12 +78,12 @@ class TaskTypeService @Inject()(teamDAO: TeamDAO, taskTypeDAO: TaskTypeDAO)(impl class TaskTypeDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[TaskType, TasktypesRow, Tasktypes](sqlClient) { - val collection = Tasktypes + protected val collection = Tasktypes - def idColumn(x: Tasktypes): Rep[String] = x._Id - def isDeletedColumn(x: Tasktypes): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Tasktypes): Rep[String] = x._Id + protected def isDeletedColumn(x: Tasktypes): Rep[Boolean] = x.isdeleted - def parse(r: TasktypesRow): Fox[TaskType] = + protected def parse(r: TasktypesRow): Fox[TaskType] = for { tracingType <- TracingType.fromString(r.tracingtype) ?~> "failed to parse tracing type" settingsAllowedModes <- Fox.combined(parseArrayTuple(r.settingsAllowedmodes).map(TracingMode.fromString(_).toFox)) ?~> "failed to parse tracing mode" @@ -108,11 +108,11 @@ class TaskTypeDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) r.isdeleted ) - override def readAccessQ(requestingUserId: ObjectId) = + override protected def readAccessQ(requestingUserId: ObjectId) = s"""(_team in (select _team from webknossos.user_team_roles where _user = '${requestingUserId.id}') or _organization = (select _organization from webknossos.users_ where _id = '${requestingUserId.id}' and isAdmin))""" - override def updateAccessQ(requestingUserId: ObjectId) = + override protected def updateAccessQ(requestingUserId: ObjectId) = s"""(_team in (select _team from webknossos.user_team_roles where isTeamManager and _user = '${requestingUserId.id}') or _organization = (select _organization from webknossos.users_ where _id = '${requestingUserId.id}' and isAdmin))""" diff --git a/app/models/team/Team.scala b/app/models/team/Team.scala index e7ac3cb1652..0ddd1825d51 100755 --- a/app/models/team/Team.scala +++ b/app/models/team/Team.scala @@ -98,12 +98,12 @@ class TeamService @Inject()(organizationDAO: OrganizationDAO, class TeamDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Team, TeamsRow, Teams](sqlClient) { - val collection = Teams + protected val collection = Teams - def idColumn(x: Teams): Rep[String] = x._Id - def isDeletedColumn(x: Teams): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Teams): Rep[String] = x._Id + protected def isDeletedColumn(x: Teams): Rep[Boolean] = x.isdeleted - def parse(r: TeamsRow): Fox[Team] = + protected def parse(r: TeamsRow): Fox[Team] = Fox.successful( Team( ObjectId(r._Id), @@ -114,11 +114,11 @@ class TeamDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) r.isdeleted )) - override def readAccessQ(requestingUserId: ObjectId) = + override protected def readAccessQ(requestingUserId: ObjectId) = s"""(_id in (select _team from webknossos.user_team_roles where _user = '$requestingUserId') or _organization in (select _organization from webknossos.users_ where _id = '$requestingUserId' and isAdmin))""" - override def deleteAccessQ(requestingUserId: ObjectId) = + override protected def deleteAccessQ(requestingUserId: ObjectId) = s"""(not isorganizationteam and _organization in (select _organization from webknossos.users_ where _id = '$requestingUserId' and isAdmin))""" diff --git a/app/models/user/Invite.scala b/app/models/user/Invite.scala index e4ba58f0d04..0a61c35aabf 100644 --- a/app/models/user/Invite.scala +++ b/app/models/user/Invite.scala @@ -84,13 +84,13 @@ class InviteService @Inject()(conf: WkConf, class InviteDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Invite, InvitesRow, Invites](sqlClient) { - val collection = Invites + protected val collection = Invites - def idColumn(x: Invites): Rep[String] = x._Id + protected def idColumn(x: Invites): Rep[String] = x._Id - def isDeletedColumn(x: Invites): Rep[Boolean] = x.isdeleted + protected def isDeletedColumn(x: Invites): Rep[Boolean] = x.isdeleted - def parse(r: InvitesRow): Fox[Invite] = + protected def parse(r: InvitesRow): Fox[Invite] = Fox.successful( Invite( ObjectId(r._Id), diff --git a/app/models/user/MultiUser.scala b/app/models/user/MultiUser.scala index fef6fad8c66..f04c2c726ff 100644 --- a/app/models/user/MultiUser.scala +++ b/app/models/user/MultiUser.scala @@ -30,12 +30,12 @@ case class MultiUser( class MultiUserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[MultiUser, MultiusersRow, Multiusers](sqlClient) { - val collection = Multiusers + protected val collection = Multiusers - def idColumn(x: Multiusers): Rep[String] = x._Id - def isDeletedColumn(x: Multiusers): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Multiusers): Rep[String] = x._Id + protected def isDeletedColumn(x: Multiusers): Rep[Boolean] = x.isdeleted - def parse(r: MultiusersRow): Fox[MultiUser] = + protected def parse(r: MultiusersRow): Fox[MultiUser] = for { novelUserExperienceInfos <- JsonHelper.parseAndValidateJson[JsObject](r.noveluserexperienceinfos).toFox theme <- Theme.fromString(r.selectedtheme).toFox diff --git a/app/models/user/User.scala b/app/models/user/User.scala index 50f2e5ae9d9..4358035c404 100755 --- a/app/models/user/User.scala +++ b/app/models/user/User.scala @@ -60,12 +60,12 @@ case class User( class UserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[User, UsersRow, Users](sqlClient) { - val collection = Users + protected val collection = Users - def idColumn(x: Users): Rep[String] = x._Id - def isDeletedColumn(x: Users): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Users): Rep[String] = x._Id + protected def isDeletedColumn(x: Users): Rep[Boolean] = x.isdeleted - def parse(r: UsersRow): Fox[User] = + protected def parse(r: UsersRow): Fox[User] = for { userConfiguration <- parseAndValidateJson[JsObject](r.userconfiguration) } yield { @@ -88,14 +88,14 @@ class UserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) ) } - override def readAccessQ(requestingUserId: ObjectId) = + override protected def readAccessQ(requestingUserId: ObjectId) = s"""(_id in (select _user from webknossos.user_team_roles where _team in (select _team from webknossos.user_team_roles where _user = '$requestingUserId' and isTeamManager))) or (_organization in (select _organization from webknossos.users_ where _id = '$requestingUserId' and isAdmin)) or _id = '$requestingUserId'""" - override def deleteAccessQ(requestingUserId: ObjectId) = + override protected def deleteAccessQ(requestingUserId: ObjectId) = s"_organization in (select _organization from webknossos.users_ where _id = '$requestingUserId' and isAdmin)" - def listAccessQ(requestingUserId: ObjectId) = + private def listAccessQ(requestingUserId: ObjectId) = s"""(${readAccessQ(requestingUserId)}) and ( @@ -262,11 +262,6 @@ class UserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) _ <- run(sqlu"""update webknossos.users set isDeleted = true where _organization = $organizationId""") } yield () -} - -class UserTeamRolesDAO @Inject()(userDAO: UserDAO, sqlClient: SQLClient)(implicit ec: ExecutionContext) - extends SimpleSQLDAO(sqlClient) { - def findTeamMembershipsForUser(userId: ObjectId): Fox[List[TeamMembership]] = { val query = for { (teamRoleRow, team) <- UserTeamRoles.filter(_._User === userId.id) join Teams on (_._Team === _._Id) @@ -281,23 +276,23 @@ class UserTeamRolesDAO @Inject()(userDAO: UserDAO, sqlClient: SQLClient)(implici } yield teamMemberships } - private def insertQuery(userId: ObjectId, teamMembership: TeamMembership) = + private def insertTeamMembershipQuery(userId: ObjectId, teamMembership: TeamMembership) = sqlu"insert into webknossos.user_team_roles(_user, _team, isTeamManager) values($userId, ${teamMembership.teamId}, ${teamMembership.isTeamManager})" def updateTeamMembershipsForUser(userId: ObjectId, teamMemberships: List[TeamMembership])( - implicit ctx: DBAccessContext): Fox[Unit] = { + implicit ctx: DBAccessContext): Fox[Unit] = { val clearQuery = sqlu"delete from webknossos.user_team_roles where _user = $userId" - val insertQueries = teamMemberships.map(insertQuery(userId, _)) + val insertQueries = teamMemberships.map(insertTeamMembershipQuery(userId, _)) for { - _ <- userDAO.assertUpdateAccess(userId) + _ <- assertUpdateAccess(userId) _ <- run(DBIO.sequence(List(clearQuery) ++ insertQueries).transactionally) } yield () } def insertTeamMembership(userId: ObjectId, teamMembership: TeamMembership)(implicit ctx: DBAccessContext): Fox[Unit] = for { - _ <- userDAO.assertUpdateAccess(userId) - _ <- run(insertQuery(userId, teamMembership)) + _ <- assertUpdateAccess(userId) + _ <- run(insertTeamMembershipQuery(userId, teamMembership)) } yield () def removeTeamFromAllUsers(teamId: ObjectId): Fox[Unit] = @@ -305,9 +300,9 @@ class UserTeamRolesDAO @Inject()(userDAO: UserDAO, sqlClient: SQLClient)(implici _ <- run(sqlu"delete from webknossos.user_team_roles where _team = $teamId") } yield () - def findMemberDifference(potentialSubteam: ObjectId, superteams: List[ObjectId]): Fox[List[User]] = + def findTeamMemberDifference(potentialSubteam: ObjectId, superteams: List[ObjectId]): Fox[List[User]] = for { - r <- run(sql"""select #${userDAO.columnsWithPrefix("u.")} from webknossos.users_ u + r <- run(sql"""select #${columnsWithPrefix("u.")} from webknossos.users_ u join webknossos.user_team_roles tr on u._id = tr._user where not u.isAdmin and not u.isDeactivated @@ -316,8 +311,9 @@ class UserTeamRolesDAO @Inject()(userDAO: UserDAO, sqlClient: SQLClient)(implici (select _user from webknossos.user_team_roles where _team in #${writeStructTupleWithQuotes(superteams.map(_.id))}) """.as[UsersRow]) - parsed <- Fox.combined(r.toList.map(userDAO.parse)) + parsed <- Fox.combined(r.toList.map(parse)) } yield parsed + } class UserExperiencesDAO @Inject()(sqlClient: SQLClient, userDAO: UserDAO)(implicit ec: ExecutionContext) diff --git a/app/models/user/UserService.scala b/app/models/user/UserService.scala index f6f50d23247..6f25c2e1ee7 100755 --- a/app/models/user/UserService.scala +++ b/app/models/user/UserService.scala @@ -29,7 +29,6 @@ import scala.concurrent.{ExecutionContext, Future} class UserService @Inject()(conf: WkConf, userDAO: UserDAO, multiUserDAO: MultiUserDAO, - userTeamRolesDAO: UserTeamRolesDAO, userExperiencesDAO: UserExperiencesDAO, userDataSetConfigurationDAO: UserDataSetConfigurationDAO, userDataSetLayerConfigurationDAO: UserDataSetLayerConfigurationDAO, @@ -115,7 +114,7 @@ class UserService @Inject()(conf: WkConf, lastTaskTypeId = None ) _ <- userDAO.insertOne(user) - _ <- Fox.combined(teamMemberships.map(userTeamRolesDAO.insertTeamMembership(user._id, _))) + _ <- Fox.combined(teamMemberships.map(userDAO.insertTeamMembership(user._id, _))) } yield user } @@ -153,7 +152,7 @@ class UserService @Inject()(conf: WkConf, created = Instant.now ) _ <- userDAO.insertOne(user) - _ <- Fox.combined(teamMemberships.map(userTeamRolesDAO.insertTeamMembership(user._id, _))) + _ <- Fox.combined(teamMemberships.map(userDAO.insertTeamMembership(user._id, _))) _ = logger.info( s"Multiuser ${originalUser._multiUser} joined organization $organizationId with new user id $newUserId.") } yield user @@ -187,7 +186,7 @@ class UserService @Inject()(conf: WkConf, isDatasetManager, isDeactivated = !activated, lastTaskTypeId) - _ <- userTeamRolesDAO.updateTeamMembershipsForUser(user._id, teamMemberships) + _ <- userDAO.updateTeamMembershipsForUser(user._id, teamMemberships) _ <- userExperiencesDAO.updateExperiencesForUser(user, experiences) _ = userCache.invalidateUser(user._id) _ <- if (oldEmail == email) Fox.successful(()) else tokenDAO.updateEmail(oldEmail, email) @@ -257,7 +256,7 @@ class UserService @Inject()(conf: WkConf, userExperiencesDAO.findAllExperiencesForUser(_user) def teamMembershipsFor(_user: ObjectId): Fox[List[TeamMembership]] = - userTeamRolesDAO.findTeamMembershipsForUser(_user) + userDAO.findTeamMembershipsForUser(_user) def teamManagerMembershipsFor(_user: ObjectId): Fox[List[TeamMembership]] = for { diff --git a/app/models/user/time/TimeSpan.scala b/app/models/user/time/TimeSpan.scala index f93c23502d1..563ad876aaa 100755 --- a/app/models/user/time/TimeSpan.scala +++ b/app/models/user/time/TimeSpan.scala @@ -47,12 +47,12 @@ object TimeSpan { class TimeSpanDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[TimeSpan, TimespansRow, Timespans](sqlClient) { - val collection = Timespans + protected val collection = Timespans - def idColumn(x: Timespans): Rep[String] = x._Id - def isDeletedColumn(x: Timespans): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Timespans): Rep[String] = x._Id + protected def isDeletedColumn(x: Timespans): Rep[Boolean] = x.isdeleted - def parse(r: TimespansRow): Fox[TimeSpan] = + protected def parse(r: TimespansRow): Fox[TimeSpan] = Fox.successful( TimeSpan( ObjectId(r._Id), diff --git a/app/oxalis/security/Token.scala b/app/oxalis/security/Token.scala index 53dc80284c0..de9c44a53a1 100644 --- a/app/oxalis/security/Token.scala +++ b/app/oxalis/security/Token.scala @@ -54,12 +54,12 @@ object Token { class TokenDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SQLDAO[Token, TokensRow, Tokens](sqlClient) { - val collection = Tokens + protected val collection = Tokens - def idColumn(x: Tokens): Rep[String] = x._Id - def isDeletedColumn(x: Tokens): Rep[Boolean] = x.isdeleted + protected def idColumn(x: Tokens): Rep[String] = x._Id + protected def isDeletedColumn(x: Tokens): Rep[Boolean] = x.isdeleted - def parse(r: TokensRow): Fox[Token] = + protected def parse(r: TokensRow): Fox[Token] = for { tokenType <- TokenType.fromString(r.tokentype).toFox } yield { diff --git a/app/utils/SQLHelpers.scala b/app/utils/SQLHelpers.scala index 48604d74f38..c8a1092699c 100644 --- a/app/utils/SQLHelpers.scala +++ b/app/utils/SQLHelpers.scala @@ -25,31 +25,31 @@ class SQLClient @Inject()(configuration: Configuration, slackNotificationService } trait SQLTypeImplicits { - implicit object SetObjectId extends SetParameter[ObjectId] { + protected implicit object SetObjectId extends SetParameter[ObjectId] { def apply(v: ObjectId, pp: PositionedParameters): Unit = pp.setString(v.id) } - implicit object SetObjectIdOpt extends SetParameter[Option[ObjectId]] { + protected implicit object SetObjectIdOpt extends SetParameter[Option[ObjectId]] { def apply(v: Option[ObjectId], pp: PositionedParameters): Unit = pp.setStringOption(v.map(_.id)) } - implicit object GetObjectId extends GetResult[ObjectId] { + protected implicit object GetObjectId extends GetResult[ObjectId] { override def apply(v1: PositionedResult): ObjectId = ObjectId(v1.<<) } - implicit object SetInstant extends SetParameter[Instant] { + protected implicit object SetInstant extends SetParameter[Instant] { def apply(v: Instant, pp: PositionedParameters): Unit = pp.setTimestamp(v.toSql) } - implicit object SetInstantOpt extends SetParameter[Option[Instant]] { + protected implicit object SetInstantOpt extends SetParameter[Option[Instant]] { def apply(v: Option[Instant], pp: PositionedParameters): Unit = pp.setTimestampOption(v.map(_.toSql)) } - implicit object GetInstant extends GetResult[Instant] { + protected implicit object GetInstant extends GetResult[Instant] { override def apply(v1: PositionedResult): Instant = Instant.fromSql(v1.<<) } - implicit object GetInstantOpt extends GetResult[Option[Instant]] { + protected implicit object GetInstantOpt extends GetResult[Option[Instant]] { override def apply(v1: PositionedResult): Option[Instant] = v1.nextTimestampOption().map(Instant.fromSql) } } @@ -59,9 +59,9 @@ class SimpleSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext with LazyLogging with SQLTypeImplicits { - lazy val transactionSerializationError = "could not serialize access" + protected lazy val transactionSerializationError = "could not serialize access" - def run[R](query: DBIOAction[R, NoStream, Nothing], + protected def run[R](query: DBIOAction[R, NoStream, Nothing], retryCount: Int = 0, retryIfErrorContains: List[String] = List()): Fox[R] = { val foxFuture = sqlClient.db.run(query.asTry).map { result: Try[R] => @@ -96,22 +96,22 @@ class SimpleSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext s"Causing query: ${query.getDumpInfo.mainInfo}" ) - def writeArrayTuple(elements: List[String]): String = { + protected def writeArrayTuple(elements: List[String]): String = { val commaSeparated = elements.map(sanitizeInArrayTuple).map(e => s""""$e"""").mkString(",") s"{$commaSeparated}" } - def writeStructTuple(elements: List[String]): String = { + protected def writeStructTuple(elements: List[String]): String = { val commaSeparated = elements.mkString(",") s"($commaSeparated)" } - def writeStructTupleWithQuotes(elements: List[String]): String = { + protected def writeStructTupleWithQuotes(elements: List[String]): String = { val commaSeparated = elements.map(e => s"'$e'").mkString(",") s"($commaSeparated)" } - def parseArrayTuple(literal: String): List[String] = { + protected def parseArrayTuple(literal: String): List[String] = { val trimmed = literal.drop(1).dropRight(1) if (trimmed.isEmpty) List.empty @@ -125,7 +125,7 @@ class SimpleSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext } } - def escapeLiteral(aString: String): String = { + protected def escapeLiteral(aString: String): String = { // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c var hasBackslash = false val escaped = new StringBuffer("'") @@ -149,38 +149,38 @@ class SimpleSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext } } - def writeEscapedTuple(seq: List[String]): String = + protected def writeEscapedTuple(seq: List[String]): String = "(" + seq.map(escapeLiteral).mkString(", ") + ")" - def sanitize(aString: String): String = aString.replaceAll("'", "") + protected def sanitize(aString: String): String = aString.replaceAll("'", "") // escape ' by doubling it, escape " with backslash, drop commas - def sanitizeInArrayTuple(aString: String): String = + protected def sanitizeInArrayTuple(aString: String): String = aString.replaceAll("'", """''""").replaceAll(""""""", """\\"""").replaceAll(""",""", "") - def desanitizeFromArrayTuple(aString: String): String = + protected def desanitizeFromArrayTuple(aString: String): String = aString.replaceAll("""\\"""", """"""").replaceAll("""\\,""", ",") - def optionLiteral(aStringOpt: Option[String]): String = aStringOpt match { + protected def optionLiteral(aStringOpt: Option[String]): String = aStringOpt match { case Some(aString) => "'" + aString + "'" case None => "null" } - def optionLiteralSanitized(aStringOpt: Option[String]): String = optionLiteral(aStringOpt.map(sanitize)) + protected def optionLiteralSanitized(aStringOpt: Option[String]): String = optionLiteral(aStringOpt.map(sanitize)) } abstract class SecuredSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SimpleSQLDAO(sqlClient) { - def collectionName: String - def existingCollectionName: String = collectionName + "_" + protected def collectionName: String + protected def existingCollectionName: String = collectionName + "_" - def anonymousReadAccessQ(sharingToken: Option[String]): String = "false" - def readAccessQ(requestingUserId: ObjectId): String = "true" - def updateAccessQ(requestingUserId: ObjectId): String = readAccessQ(requestingUserId) - def deleteAccessQ(requestingUserId: ObjectId): String = readAccessQ(requestingUserId) + protected def anonymousReadAccessQ(sharingToken: Option[String]): String = "false" + protected def readAccessQ(requestingUserId: ObjectId): String = "true" + protected def updateAccessQ(requestingUserId: ObjectId): String = readAccessQ(requestingUserId) + protected def deleteAccessQ(requestingUserId: ObjectId): String = readAccessQ(requestingUserId) - def readAccessQuery(implicit ctx: DBAccessContext): Fox[String] = + protected def readAccessQuery(implicit ctx: DBAccessContext): Fox[String] = if (ctx.globalAccess) Fox.successful("true") else { for { @@ -217,7 +217,7 @@ abstract class SecuredSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: Execut } yield () } - def userIdFromCtx(implicit ctx: DBAccessContext): Fox[ObjectId] = + protected def userIdFromCtx(implicit ctx: DBAccessContext): Fox[ObjectId] = ctx.data match { case Some(user: User) => Fox.successful(user._id) case Some(userSharingTokenContainer: UserSharingTokenContainer) => @@ -225,7 +225,7 @@ abstract class SecuredSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: Execut case _ => Fox.failure("Access denied.") } - def accessQueryFromAccessQWithPrefix(accessQ: (ObjectId, String) => String, prefix: String)( + protected def accessQueryFromAccessQWithPrefix(accessQ: (ObjectId, String) => String, prefix: String)( implicit ctx: DBAccessContext): Fox[String] = if (ctx.globalAccess) Fox.successful("true") else { @@ -239,7 +239,7 @@ abstract class SecuredSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: Execut } } - def accessQueryFromAccessQ(accessQ: ObjectId => String)(implicit ctx: DBAccessContext): Fox[String] = + protected def accessQueryFromAccessQ(accessQ: ObjectId => String)(implicit ctx: DBAccessContext): Fox[String] = if (ctx.globalAccess) Fox.successful("true") else { for { @@ -271,31 +271,31 @@ abstract class SecuredSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: Execut abstract class SQLDAO[C, R, X <: AbstractTable[R]] @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) extends SecuredSQLDAO(sqlClient) { - def collection: TableQuery[X] - def collectionName: String = + protected def collection: TableQuery[X] + protected def collectionName: String = collection.shaped.value.schemaName.map(_ + ".").getOrElse("") + collection.shaped.value.tableName - def columnsList: List[String] = collection.baseTableRow.create_*.map(_.name).toList + protected def columnsList: List[String] = collection.baseTableRow.create_*.map(_.name).toList def columns: String = columnsList.mkString(", ") def columnsWithPrefix(prefix: String): String = columnsList.map(prefix + _).mkString(", ") - def idColumn(x: X): Rep[String] - def isDeletedColumn(x: X): Rep[Boolean] + protected def idColumn(x: X): Rep[String] + protected def isDeletedColumn(x: X): Rep[Boolean] - def notdel(r: X): Rep[Boolean] = isDeletedColumn(r) === false + protected def notdel(r: X): Rep[Boolean] = isDeletedColumn(r) === false - def parse(row: X#TableElementType): Fox[C] + protected def parse(row: X#TableElementType): Fox[C] - def parseFirst(rowSeq: Seq[X#TableElementType], queryLabel: ObjectId): Fox[C] = + protected def parseFirst(rowSeq: Seq[X#TableElementType], queryLabel: ObjectId): Fox[C] = parseFirst(rowSeq, queryLabel.toString) - def parseFirst(rowSeq: Seq[X#TableElementType], queryLabel: String): Fox[C] = + protected def parseFirst(rowSeq: Seq[X#TableElementType], queryLabel: String): Fox[C] = for { firstRow <- rowSeq.headOption.toFox // No error chain here, as this should stay Fox.Empty parsed <- parse(firstRow) ?~> s"Parsing failed for row in $collectionName queried by $queryLabel" } yield parsed - def parseAll(rowSeq: Seq[X#TableElementType]): Fox[List[C]] = + protected def parseAll(rowSeq: Seq[X#TableElementType]): Fox[List[C]] = Fox.combined(rowSeq.toList.map(parse)) ?~> s"Parsing failed for a row in $collectionName during list query" @nowarn // suppress warning about unused implicit ctx, as it is used in subclasses @@ -322,7 +322,7 @@ abstract class SQLDAO[C, R, X <: AbstractTable[R]] @Inject()(sqlClient: SQLClien } yield () } - def updateStringCol(id: ObjectId, column: X => Rep[String], newValue: String)( + protected def updateStringCol(id: ObjectId, column: X => Rep[String], newValue: String)( implicit ctx: DBAccessContext): Fox[Unit] = { val q = for { row <- collection if notdel(row) && idColumn(row) === id.id } yield column(row) for { @@ -331,11 +331,11 @@ abstract class SQLDAO[C, R, X <: AbstractTable[R]] @Inject()(sqlClient: SQLClien } yield () } - def updateObjectIdCol(id: ObjectId, column: X => Rep[String], newValue: ObjectId)( + protected def updateObjectIdCol(id: ObjectId, column: X => Rep[String], newValue: ObjectId)( implicit ctx: DBAccessContext): Fox[Unit] = updateStringCol(id, column, newValue.id) - def updateBooleanCol(id: ObjectId, column: X => Rep[Boolean], newValue: Boolean)( + protected def updateBooleanCol(id: ObjectId, column: X => Rep[Boolean], newValue: Boolean)( implicit ctx: DBAccessContext): Fox[Unit] = { val q = for { row <- collection if notdel(row) && idColumn(row) === id.id } yield column(row) for { @@ -344,7 +344,7 @@ abstract class SQLDAO[C, R, X <: AbstractTable[R]] @Inject()(sqlClient: SQLClien } yield () } - def updateTimestampCol(id: ObjectId, column: X => Rep[java.sql.Timestamp], newValue: Instant)( + protected def updateTimestampCol(id: ObjectId, column: X => Rep[java.sql.Timestamp], newValue: Instant)( implicit ctx: DBAccessContext): Fox[Unit] = { val q = for { row <- collection if notdel(row) && idColumn(row) === id.id } yield column(row) for { From 24fdc1cd23c66fd592c37e54d763c46b222fd1e0 Mon Sep 17 00:00:00 2001 From: Florian M Date: Wed, 14 Dec 2022 12:32:36 +0100 Subject: [PATCH 2/2] format --- app/controllers/InitialDataController.scala | 5 ++--- app/controllers/TeamController.scala | 6 ++---- app/models/annotation/Annotation.scala | 12 ++++++------ app/models/user/User.scala | 2 +- app/utils/SQLHelpers.scala | 18 +++++++++--------- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/app/controllers/InitialDataController.scala b/app/controllers/InitialDataController.scala index 3c8581ad941..804ab45ce4c 100644 --- a/app/controllers/InitialDataController.scala +++ b/app/controllers/InitialDataController.scala @@ -181,9 +181,8 @@ Samplecountry _ <- multiUserDAO.insertOne(multiUser) _ <- userDAO.insertOne(user) _ <- userExperiencesDAO.updateExperiencesForUser(user, Map("sampleExp" -> 10)) - _ <- userDAO.insertTeamMembership( - user._id, - TeamMembership(organizationTeam._id, isTeamManager = isTeamManager)) + _ <- userDAO.insertTeamMembership(user._id, + TeamMembership(organizationTeam._id, isTeamManager = isTeamManager)) _ = logger.info("Inserted default user") } yield () } diff --git a/app/controllers/TeamController.scala b/app/controllers/TeamController.scala index d5aba6b3c92..b58fe9a525a 100755 --- a/app/controllers/TeamController.scala +++ b/app/controllers/TeamController.scala @@ -15,10 +15,8 @@ import javax.inject.Inject import scala.concurrent.ExecutionContext @Api -class TeamController @Inject()(teamDAO: TeamDAO, - userDAO: UserDAO, - teamService: TeamService, - sil: Silhouette[WkEnv])(implicit ec: ExecutionContext) +class TeamController @Inject()(teamDAO: TeamDAO, userDAO: UserDAO, teamService: TeamService, sil: Silhouette[WkEnv])( + implicit ec: ExecutionContext) extends Controller { private def teamNameReads: Reads[String] = diff --git a/app/models/annotation/Annotation.scala b/app/models/annotation/Annotation.scala index fa650dce7d9..2b6d1182159 100755 --- a/app/models/annotation/Annotation.scala +++ b/app/models/annotation/Annotation.scala @@ -180,7 +180,8 @@ class AnnotationDAO @Inject()(sqlClient: SQLClient, annotationLayerDAO: Annotati ) } - protected override def anonymousReadAccessQ(sharingToken: Option[String]) = s"visibility = '${AnnotationVisibility.Public}'" + override protected def anonymousReadAccessQ(sharingToken: Option[String]) = + s"visibility = '${AnnotationVisibility.Public}'" private def listAccessQ(requestingUserId: ObjectId): String = s""" @@ -556,19 +557,18 @@ class AnnotationDAO @Inject()(sqlClient: SQLClient, annotationLayerDAO: Annotati } yield parsed def updateTeamsForSharedAnnotation(annotationId: ObjectId, teams: List[ObjectId])( - implicit ctx: DBAccessContext): Fox[Unit] = { + implicit ctx: DBAccessContext): Fox[Unit] = { val clearQuery = sqlu"delete from webknossos.annotation_sharedTeams where _annotation = $annotationId" - val insertQueries = teams.map(teamId => - sqlu"""insert into webknossos.annotation_sharedTeams(_annotation, _team) + val insertQueries = teams.map(teamId => sqlu"""insert into webknossos.annotation_sharedTeams(_annotation, _team) values($annotationId, $teamId)""") val composedQuery = DBIO.sequence(List(clearQuery) ++ insertQueries) for { _ <- assertUpdateAccess(annotationId) _ <- run(composedQuery.transactionally.withTransactionIsolation(Serializable), - retryCount = 50, - retryIfErrorContains = List(transactionSerializationError)) + retryCount = 50, + retryIfErrorContains = List(transactionSerializationError)) } yield () } } diff --git a/app/models/user/User.scala b/app/models/user/User.scala index 4358035c404..76d2878a06f 100755 --- a/app/models/user/User.scala +++ b/app/models/user/User.scala @@ -280,7 +280,7 @@ class UserDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext) sqlu"insert into webknossos.user_team_roles(_user, _team, isTeamManager) values($userId, ${teamMembership.teamId}, ${teamMembership.isTeamManager})" def updateTeamMembershipsForUser(userId: ObjectId, teamMemberships: List[TeamMembership])( - implicit ctx: DBAccessContext): Fox[Unit] = { + implicit ctx: DBAccessContext): Fox[Unit] = { val clearQuery = sqlu"delete from webknossos.user_team_roles where _user = $userId" val insertQueries = teamMemberships.map(insertTeamMembershipQuery(userId, _)) for { diff --git a/app/utils/SQLHelpers.scala b/app/utils/SQLHelpers.scala index c8a1092699c..5c1f9cb8e70 100644 --- a/app/utils/SQLHelpers.scala +++ b/app/utils/SQLHelpers.scala @@ -25,31 +25,31 @@ class SQLClient @Inject()(configuration: Configuration, slackNotificationService } trait SQLTypeImplicits { - protected implicit object SetObjectId extends SetParameter[ObjectId] { + implicit protected object SetObjectId extends SetParameter[ObjectId] { def apply(v: ObjectId, pp: PositionedParameters): Unit = pp.setString(v.id) } - protected implicit object SetObjectIdOpt extends SetParameter[Option[ObjectId]] { + implicit protected object SetObjectIdOpt extends SetParameter[Option[ObjectId]] { def apply(v: Option[ObjectId], pp: PositionedParameters): Unit = pp.setStringOption(v.map(_.id)) } - protected implicit object GetObjectId extends GetResult[ObjectId] { + implicit protected object GetObjectId extends GetResult[ObjectId] { override def apply(v1: PositionedResult): ObjectId = ObjectId(v1.<<) } - protected implicit object SetInstant extends SetParameter[Instant] { + implicit protected object SetInstant extends SetParameter[Instant] { def apply(v: Instant, pp: PositionedParameters): Unit = pp.setTimestamp(v.toSql) } - protected implicit object SetInstantOpt extends SetParameter[Option[Instant]] { + implicit protected object SetInstantOpt extends SetParameter[Option[Instant]] { def apply(v: Option[Instant], pp: PositionedParameters): Unit = pp.setTimestampOption(v.map(_.toSql)) } - protected implicit object GetInstant extends GetResult[Instant] { + implicit protected object GetInstant extends GetResult[Instant] { override def apply(v1: PositionedResult): Instant = Instant.fromSql(v1.<<) } - protected implicit object GetInstantOpt extends GetResult[Option[Instant]] { + implicit protected object GetInstantOpt extends GetResult[Option[Instant]] { override def apply(v1: PositionedResult): Option[Instant] = v1.nextTimestampOption().map(Instant.fromSql) } } @@ -62,8 +62,8 @@ class SimpleSQLDAO @Inject()(sqlClient: SQLClient)(implicit ec: ExecutionContext protected lazy val transactionSerializationError = "could not serialize access" protected def run[R](query: DBIOAction[R, NoStream, Nothing], - retryCount: Int = 0, - retryIfErrorContains: List[String] = List()): Fox[R] = { + retryCount: Int = 0, + retryIfErrorContains: List[String] = List()): Fox[R] = { val foxFuture = sqlClient.db.run(query.asTry).map { result: Try[R] => result match { case Success(res) =>