Skip to content

Commit

Permalink
Add new updateuser DirectoryDAO method
Browse files Browse the repository at this point in the history
  • Loading branch information
Ghost-in-a-Jar committed Jan 30, 2024
1 parent d6a5c79 commit 46a4dc8
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.broadinstitute.dsde.workbench.model._
import org.broadinstitute.dsde.workbench.model.google.ServiceAccountSubjectId
import org.broadinstitute.dsde.workbench.sam.azure.{ManagedIdentityObjectId, PetManagedIdentity, PetManagedIdentityId}
import org.broadinstitute.dsde.workbench.sam.model.api.{SamUser, SamUserAttributes}
import org.broadinstitute.dsde.workbench.sam.model.{BasicWorkbenchGroup, SamUserTos}
import org.broadinstitute.dsde.workbench.sam.model.{BasicWorkbenchGroup, SamUserTos, UserUpdate}
import org.broadinstitute.dsde.workbench.sam.util.SamRequestContext

import java.time.Instant
Expand Down Expand Up @@ -53,6 +53,7 @@ trait DirectoryDAO {
def setUserAzureB2CId(userId: WorkbenchUserId, b2cId: AzureB2CId, samRequestContext: SamRequestContext): IO[Unit]
def updateUserEmail(userId: WorkbenchUserId, email: WorkbenchEmail, samRequestContext: SamRequestContext): IO[Unit]
def deleteUser(userId: WorkbenchUserId, samRequestContext: SamRequestContext): IO[Unit]
def updateUser(userId: WorkbenchUserId, userUpdate: UserUpdate, samRequestContext: SamRequestContext): IO[Option[SamUser]]

def listUsersGroups(userId: WorkbenchUserId, samRequestContext: SamRequestContext): IO[Set[WorkbenchGroupIdentity]]
def listUserDirectMemberships(userId: WorkbenchUserId, samRequestContext: SamRequestContext): IO[LazyList[WorkbenchGroupIdentity]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,37 @@ class PostgresDirectoryDAO(protected val writeDbRef: DbReference, protected val

override def updateUserEmail(userId: WorkbenchUserId, email: WorkbenchEmail, samRequestContext: SamRequestContext): IO[Unit] = IO.unit

override def updateUser(userId: WorkbenchUserId, userUpdate: UserUpdate, samRequestContext: SamRequestContext): IO[Option[SamUser]] =
serializableWriteTransaction("updateUser", samRequestContext) { implicit session =>
val u = UserTable.column
val setColumnsClause = userUpdate match {
case UserUpdate(None, None) => throw new WorkbenchException("Cannot update user with no values.")
case UserUpdate(Some(newGoogleSubjectId), None) =>
s"set (${u.googleSubjectId}, ${u.updatedAt})"
case UserUpdate(None, Some(newAzureB2CId)) =>
s"set (${u.azureB2cId}, ${u.updatedAt})"
case UserUpdate(Some(newGoogleSubjectId), Some(newAzureB2CId)) =>
s"set (${u.googleSubjectId}, ${u.azureB2cId}, ${u.updatedAt})"
}

val updateGoogleSubjectIdClause = if (userUpdate.newGoogleSubjectId.isDefined) s"${userUpdate.newGoogleSubjectId}," else ""
val updateAzureB2CIDClause = if (userUpdate.newAzureB2CId.isDefined) s"${userUpdate.newAzureB2CId}," else ""

samsql"""update ${UserTable.table}
${setColumnsClause} =
(
${updateGoogleSubjectIdClause}
${updateAzureB2CIDClause}
${Instant.now()}
)
where ${u.id} = $userId
returning ${u.id}, ${u.googleSubjectId}, ${u.email}, ${u.azureB2cId}, ${u.enabled}, ${u.createdAt}, ${u.registeredAt}, ${u.updatedAt}"""
.map(r => UserTable.unmarshalUserRecord(UserTable(UserTable.syntax)(r)))
.single()
.apply()

}

override def deleteUser(userId: WorkbenchUserId, samRequestContext: SamRequestContext): IO[Unit] =
serializableWriteTransaction("deleteUser", samRequestContext) { implicit session =>
val userTable = UserTable.syntax
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ object UserStatusDetails {
tosAccepted: Boolean,
adminEnabled: Boolean
)

@Lenses final case class UserUpdate(
newAzureB2CId: Option[String],
newGoogleSubjectId: Option[String]
)
@Lenses final case class TermsOfServiceAcceptance(value: String) extends ValueObject

@Lenses final case class TermsOfServiceComplianceStatus(userId: WorkbenchUserId, userHasAcceptedLatestTos: Boolean, permitsSystemUsage: Boolean)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class UserService(
} else None

private def validateAzureB2CId(azureB2CId: AzureB2CId): Option[ErrorReport] =
if (!UUID_REGEX.matcher(azureB2CId.value).matches() && !(azureB2CId.value == "")) {
if (!UUID_REGEX.matcher(azureB2CId.value).matches() && !(azureB2CId.value == "null")) {
Option(ErrorReport(s"invalid azureB2CId [${azureB2CId.value}]"))
} else None

Expand Down Expand Up @@ -210,7 +210,7 @@ class UserService(
request.azureB2CId.foreach(azureB2CId => errorReports = errorReports ++ validateAzureB2CId(azureB2CId))
if (errorReports.nonEmpty) {
IO.raiseError(new WorkbenchExceptionWithErrorReport(ErrorReport(StatusCodes.BadRequest, "invalid user update", errorReports)))
} else if (request.googleSubjectId.contains(GoogleSubjectId("")) && request.azureB2CId.contains(AzureB2CId(""))) {
} else if (request.googleSubjectId.contains(GoogleSubjectId("null")) && request.azureB2CId.contains(AzureB2CId("null"))) {
IO.raiseError(
new WorkbenchExceptionWithErrorReport(
ErrorReport(StatusCodes.BadRequest, "unable to null both azureB2CId and googleSubjectId in the same request", errorReports)
Expand All @@ -222,21 +222,8 @@ class UserService(
directoryDAO.updateUserEmail(userId, email, samRequestContext)
updatedUser = user.copy(email = email)
}
request.googleSubjectId.foreach { googleSubjectId =>
directoryDAO.setGoogleSubjectId(userId, googleSubjectId, samRequestContext)
if (request.googleSubjectId.contains(GoogleSubjectId(""))) {
updatedUser = updatedUser.copy(googleSubjectId = None)
} else
updatedUser = updatedUser.copy(googleSubjectId = Option(googleSubjectId))
}
request.azureB2CId.foreach { azureB2CId =>
directoryDAO.setUserAzureB2CId(userId, azureB2CId, samRequestContext)
if (request.azureB2CId.contains(AzureB2CId(""))) {
updatedUser = updatedUser.copy(azureB2CId = None)
} else
updatedUser = updatedUser.copy(azureB2CId = Option(azureB2CId))
}
IO(Some(updatedUser))
val userUpdate = UserUpdate(request.azureB2CId.map(_.value), request.googleSubjectId.map(_.value))
directoryDAO.updateUser(userId, userUpdate, samRequestContext)
}
case None => IO(None)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import org.broadinstitute.dsde.workbench.sam._
import org.broadinstitute.dsde.workbench.sam.azure.{ManagedIdentityObjectId, PetManagedIdentity, PetManagedIdentityId}
import org.broadinstitute.dsde.workbench.sam.db.tables.TosTable
import org.broadinstitute.dsde.workbench.sam.model.api.{SamUser, SamUserAttributes}
import org.broadinstitute.dsde.workbench.sam.model.{AccessPolicy, BasicWorkbenchGroup, SamUserTos}
import org.broadinstitute.dsde.workbench.sam.model.{AccessPolicy, BasicWorkbenchGroup, SamUserTos, UserUpdate}
import org.broadinstitute.dsde.workbench.sam.util.SamRequestContext

import java.time.Instant
Expand Down Expand Up @@ -129,6 +129,22 @@ class MockDirectoryDAO(val groups: mutable.Map[WorkbenchGroupIdentity, Workbench
users -= userId
}

override def updateUser(userId: WorkbenchUserId, userUpdate: UserUpdate, samRequestContext: SamRequestContext): IO[Option[SamUser]] = {
val updatedUser = for {
user <- users.get(userId)
updatedUser = user.copy(
googleSubjectId = if (userUpdate.newGoogleSubjectId.isDefined) userUpdate.newGoogleSubjectId.map(GoogleSubjectId) else user.googleSubjectId,
azureB2CId = if (userUpdate.newAzureB2CId.isDefined) userUpdate.newAzureB2CId.map(AzureB2CId) else user.azureB2CId,
updatedAt = Instant.now()
)
} yield updatedUser

IO.pure(updatedUser.map { user =>
users.put(userId, user)
user
})
}

override def listUsersGroups(userId: WorkbenchUserId, samRequestContext: SamRequestContext): IO[Set[WorkbenchGroupIdentity]] = IO {
listSubjectsGroups(userId, Set.empty).map(_.id)
}
Expand Down

0 comments on commit 46a4dc8

Please sign in to comment.