Skip to content

Commit

Permalink
APIS-7329 Add new method to remove all collaborators for given userId (
Browse files Browse the repository at this point in the history
…#55)

* APIS-7329 Add new method to remove all collaborators for given userId

* APIS-7329 Add new method to remove all collaborators for given userId

* APIS-7329 Add new method to remove all collaborators for given userId
  • Loading branch information
petekirby-ee authored Oct 21, 2024
1 parent c426714 commit 6a6c69d
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ class TeamMemberController @Inject() (teamMemberService: TeamMemberService, cc:
}
}

def removeAllCollaboratorsForUserId(): Action[JsValue] = Action.async(parse.tolerantJson) { implicit request =>
withJsonBody[RemoveAllCollaboratorsForUserIdRequest] { removeCollaboratorRequest =>
teamMemberService.removeAllCollaboratorsForUserId(removeCollaboratorRequest)
.map {
case List(UpdateOrganisationSuccessResult(organisation: Organisation)) => NoContent
case Nil => NoContent
case _ => InternalServerError(s"Unable to RemoveAllCollaboratorsForUserId for ${removeCollaboratorRequest.userId}")
}
}
}

def getOrganisationUserByOrganisationId(organisationId: OrganisationId): Action[AnyContent] = Action.async { implicit request =>
teamMemberService.getOrganisationUserByOrganisationId(organisationId)
.map(x => Ok(Json.toJson(x)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package uk.gov.hmrc.apiplatformxmlservices.models

import play.api.libs.json.{Json, OFormat}
import uk.gov.hmrc.apiplatform.modules.common.domain.models.LaxEmailAddress
import uk.gov.hmrc.apiplatform.modules.common.domain.models.{LaxEmailAddress, UserId}

/* Organisation request responses */

Expand All @@ -40,12 +40,19 @@ case class AddCollaboratorRequest(email: LaxEmailAddress, firstName: String, las
object AddCollaboratorRequest {
implicit val formatAddCollaboratorRequest: OFormat[AddCollaboratorRequest] = Json.format[AddCollaboratorRequest]
}

case class RemoveCollaboratorRequest(email: LaxEmailAddress, gatekeeperUserId: String)

object RemoveCollaboratorRequest {
implicit val formatRemoveCollaboratorRequest: OFormat[RemoveCollaboratorRequest] = Json.format[RemoveCollaboratorRequest]
}

case class RemoveAllCollaboratorsForUserIdRequest(userId: UserId, gatekeeperUserId: String)

object RemoveAllCollaboratorsForUserIdRequest {
implicit val formatRemoveAllCollaboratorsForUserIdRequest: OFormat[RemoveAllCollaboratorsForUserIdRequest] = Json.format[RemoveAllCollaboratorsForUserIdRequest]
}

case class ErrorResponseMessage(message: String)

object ErrorResponseMessage {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ import scala.concurrent.{ExecutionContext, Future}
import com.mongodb.client.model.ReturnDocument
import org.mongodb.scala.model.Filters._
import org.mongodb.scala.model.Indexes._
import org.mongodb.scala.model.Updates.{addToSet, set, setOnInsert}
import org.mongodb.scala.model.Updates.{addToSet, pull, set, setOnInsert}
import org.mongodb.scala.model.{FindOneAndUpdateOptions, _}

import play.api.libs.json.Json
import uk.gov.hmrc.apiplatform.modules.common.domain.models.UserId
import uk.gov.hmrc.mongo.MongoComponent
import uk.gov.hmrc.mongo.play.json.{Codecs, PlayMongoRepository}
Expand Down Expand Up @@ -125,6 +126,19 @@ class OrganisationRepository @Inject() (mongo: MongoComponent)(implicit ec: Exec
}
}

def removeCollaboratorFromOrganisation(organisationId: OrganisationId, userId: UserId): Future[UpdateOrganisationResult] = {
collection.findOneAndUpdate(
equal("organisationId", Codecs.toBson(organisationId)),
pull("collaborators", Codecs.toBson(Json.obj("userId" -> userId))),
FindOneAndUpdateOptions().upsert(false).returnDocument(ReturnDocument.AFTER)
)
.toFutureOption()
.map {
case Some(organisation: Organisation) => UpdateOrganisationSuccessResult(organisation)
case _ => UpdateOrganisationFailedResult()
}
}

def createOrUpdate(organisation: Organisation): Future[Either[Exception, Organisation]] = {
val query = and(equal("organisationId", Codecs.toBson(organisation.organisationId)), equal("vendorId", Codecs.toBson(organisation.vendorId)))

Expand Down Expand Up @@ -172,5 +186,4 @@ class OrganisationRepository @Inject() (mongo: MongoComponent)(implicit ec: Exec
collection.deleteOne(equal("organisationId", Codecs.toBson(organisationId))).toFuture()
.map(x => x.getDeletedCount == 1)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ import uk.gov.hmrc.apiplatformxmlservices.connectors.ThirdPartyDeveloperConnecto
import uk.gov.hmrc.apiplatformxmlservices.models._
import uk.gov.hmrc.apiplatformxmlservices.models.thirdpartydeveloper.UserResponse
import uk.gov.hmrc.apiplatformxmlservices.repository.OrganisationRepository
import uk.gov.hmrc.apiplatformxmlservices.util.ApplicationLogger

@Singleton
class TeamMemberService @Inject() (
organisationRepository: OrganisationRepository,
override val thirdPartyDeveloperConnector: ThirdPartyDeveloperConnector,
override val xmlApiService: XmlApiService
)(implicit val ec: ExecutionContext
) extends UserFunctions {
) extends UserFunctions with ApplicationLogger {

def removeCollaborator(organisationId: OrganisationId, request: RemoveCollaboratorRequest): Future[Either[ManageCollaboratorResult, Organisation]] = {
(for {
Expand All @@ -47,6 +48,18 @@ class TeamMemberService @Inject() (
} yield updatedOrganisation).value
}

def removeAllCollaboratorsForUserId(request: RemoveAllCollaboratorsForUserIdRequest): Future[List[UpdateOrganisationResult]] = {
for {
organisations <- organisationRepository.findByUserId(request.userId)
updatedOrganisations <- Future.traverse(organisations)(handleRemoveCollaboratorFromOrg(request.userId))
_ = logger.info(s"Removed all XML vender collaborators for userId $request.userId")
} yield updatedOrganisations
}

private def handleRemoveCollaboratorFromOrg(userId: UserId)(organisation: Organisation) = {
organisationRepository.removeCollaboratorFromOrganisation(organisation.organisationId, userId)
}

def addCollaborator(
organisationId: OrganisationId,
email: LaxEmailAddress,
Expand Down Expand Up @@ -75,7 +88,7 @@ class TeamMemberService @Inject() (

private def getDeveloperByEmail(organisationId: OrganisationId, email: LaxEmailAddress)(implicit hc: HeaderCarrier) = {
def mapResult(results: Future[Either[Throwable, List[UserResponse]]]): Future[List[OrganisationUser]] = results map {
case Right(Nil) => List(OrganisationUser(organisationId, None, email, "", "", List.empty[XmlApi])) // User not found in TPD - just return minimum data
case Right(Nil) => List(OrganisationUser(organisationId, None, email, "", "", List.empty[XmlApi])) // User not found in TPD - just return minimum data
case Right(users: List[UserResponse]) => List(toOrganisationUser(organisationId, users.head))
case _ => List.empty[OrganisationUser]
}
Expand Down
21 changes: 12 additions & 9 deletions conf/organisation.routes
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# organistion routes
# organisation routes

GET /:organisationId uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.findByOrgId(organisationId: OrganisationId)
GET / uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.findByParams(vendorId: Option[VendorId], organisationName: Option[OrganisationName], userId: Option[UserId], sortBy: Option[OrganisationSortBy])
POST / uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.create()
PUT / uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.update()
DELETE /:organisationId uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.deleteByOrgId(organisationId: OrganisationId)
GET /:organisationId uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.findByOrgId(organisationId: OrganisationId)
GET / uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.findByParams(vendorId: Option[VendorId], organisationName: Option[OrganisationName], userId: Option[UserId], sortBy: Option[OrganisationSortBy])

POST /:organisationId uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.updateOrganisationDetails(organisationId: OrganisationId)
POST / uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.create()
PUT / uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.update()
DELETE /:organisationId uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.deleteByOrgId(organisationId: OrganisationId)

POST /:organisationId uk.gov.hmrc.apiplatformxmlservices.controllers.OrganisationController.updateOrganisationDetails(organisationId: OrganisationId)

# collaborator endpoints
POST /:organisationId/add-collaborator uk.gov.hmrc.apiplatformxmlservices.controllers.TeamMemberController.addCollaborator(organisationId: OrganisationId)
POST /:organisationId/remove-collaborator uk.gov.hmrc.apiplatformxmlservices.controllers.TeamMemberController.removeCollaborator(organisationId: OrganisationId)
POST /:organisationId/remove-collaborator uk.gov.hmrc.apiplatformxmlservices.controllers.TeamMemberController.removeCollaborator(organisationId: OrganisationId)

GET /:organisationId/get-users uk.gov.hmrc.apiplatformxmlservices.controllers.TeamMemberController.getOrganisationUserByOrganisationId(organisationId: OrganisationId)

GET /:organisationId/get-users uk.gov.hmrc.apiplatformxmlservices.controllers.TeamMemberController.getOrganisationUserByOrganisationId(organisationId: OrganisationId)
POST /all/remove-collaborators uk.gov.hmrc.apiplatformxmlservices.controllers.TeamMemberController.removeAllCollaboratorsForUserId()
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,6 @@ class OrganisationRepositoryISpec
case _ => fail()
}
}

}

"addCollaboratorToOrganisation" should {
Expand Down Expand Up @@ -315,7 +314,46 @@ class OrganisationRepositoryISpec
case _ => fail()
}
}
}

"removeCollaboratorFromOrganisation" should {
"return UpdateOrganisationSuccessResult when collaborator successfully removed from Organisation" in new Setup {
await(repo.createOrUpdate(org3))

val result = await(repo.removeCollaboratorFromOrganisation(org3.organisationId, aCollaborator.userId))

result match {
case UpdateOrganisationSuccessResult(organisation: Organisation) => {
organisation.organisationId shouldBe org3.organisationId
organisation.collaborators shouldBe List(collaboratorTwo)
}
case _ => fail()
}
}

"return UpdateOrganisationSuccessResult when collaborator not found in Organisation" in new Setup {
await(repo.createOrUpdate(org3))

val result = await(repo.removeCollaboratorFromOrganisation(org3.organisationId, collaboratorThree.userId))

result match {
case UpdateOrganisationSuccessResult(organisation: Organisation) => {
organisation.organisationId shouldBe org3.organisationId
organisation.collaborators shouldBe List(aCollaborator, collaboratorTwo)
}
case _ => fail()
}
}

"return UpdateOrganisationFailedResult when organisation not found" in new Setup {
val result = await(repo.removeCollaboratorFromOrganisation(OrganisationId.random, aCollaborator.userId))

println(result)
result match {
case _: UpdateOrganisationFailedResult => succeed
case _ => fail()
}
}
}

"createOrUpdate" should {
Expand All @@ -339,8 +377,6 @@ class OrganisationRepositoryISpec
await(repo.createOrUpdate(anOrganisation))

val updatedOrganisation = anOrganisation.copy(organisationId = OrganisationId.random, name = OrganisationName("New organisation name"), vendorId = aVendorId)
println(anOrganisation)
println(updatedOrganisation)
await(repo.createOrUpdate(updatedOrganisation)) match {
case Right(a) =>
println(a)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ class TeamMemberControllerSpec extends AsyncHmrcSpec with CommonTestData with Or
val updateOrganisationDetailsRequest =
FakeRequest("POST", s"/organisations/${anOrganisationId.value}").withBody(Json.toJson(updateOrganisationDetailsRequestObj))

val orgOne = OrganisationWithNameAndVendorId(name = OrganisationName("OrgOne"), vendorId = VendorId(1))
val orgTwo = OrganisationWithNameAndVendorId(name = OrganisationName("OrgTwo"), vendorId = VendorId(2))

val orgOne = OrganisationWithNameAndVendorId(name = OrganisationName("OrgOne"), vendorId = VendorId(1))
val orgTwo = OrganisationWithNameAndVendorId(name = OrganisationName("OrgTwo"), vendorId = VendorId(2))
val gatekeeperUserId = "gatekeeperuser@hmrc.gov.uk"
}

"TeamMemberController" when {
Expand Down Expand Up @@ -129,6 +129,38 @@ class TeamMemberControllerSpec extends AsyncHmrcSpec with CommonTestData with Or

}
}
}

"removeAllCollaboratorsForUserId" should {
"return 204 when service returns success" in new Setup {
val request = RemoveAllCollaboratorsForUserIdRequest(aUserId, gatekeeperUserId)
val updateOrganisationResult = UpdateOrganisationSuccessResult(organisation)
when(mockTeamMemberService.removeAllCollaboratorsForUserId(eqTo(request))).thenReturn(Future.successful(List(updateOrganisationResult)))

val removeAllCollaboratorsForUserIdRequest =
FakeRequest("POST", "/organisations/all/remove-collaborators").withBody(Json.toJson(request))
val result: Future[Result] = controller.removeAllCollaboratorsForUserId()(removeAllCollaboratorsForUserIdRequest)
status(result) shouldBe Status.NO_CONTENT
}

"return 204 when service returns empty list" in new Setup {
val request = RemoveAllCollaboratorsForUserIdRequest(aUserId, gatekeeperUserId)
when(mockTeamMemberService.removeAllCollaboratorsForUserId(eqTo(request))).thenReturn(Future.successful(List.empty))

val removeAllCollaboratorsForUserIdRequest =
FakeRequest("POST", "/organisations/all/remove-collaborators").withBody(Json.toJson(request))
val result: Future[Result] = controller.removeAllCollaboratorsForUserId()(removeAllCollaboratorsForUserIdRequest)
status(result) shouldBe Status.NO_CONTENT
}

"return 500 when service returns failure" in new Setup {
val request = RemoveAllCollaboratorsForUserIdRequest(aUserId, gatekeeperUserId)
when(mockTeamMemberService.removeAllCollaboratorsForUserId(eqTo(request))).thenReturn(Future.successful(List(UpdateOrganisationFailedResult())))

val removeAllCollaboratorsForUserIdRequest =
FakeRequest("POST", "/organisations/all/remove-collaborators").withBody(Json.toJson(request))
val result: Future[Result] = controller.removeAllCollaboratorsForUserId()(removeAllCollaboratorsForUserIdRequest)
status(result) shouldBe Status.INTERNAL_SERVER_ERROR
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,71 @@ class TeamMemberServiceSpec extends AsyncHmrcSpec {
await(inTest.getOrganisationUserByOrganisationId(anOrganisationId)) shouldBe Nil

}

}

"removeAllCollaboratorsForUserId" should {

"return a list of UpdateOrganisationSuccessResult when successful for one organisation" in new Setup {
when(mockOrganisationRepo.findByUserId(eqTo(aUserId))).thenReturn(Future.successful(List(organisationWithCollaborators)))
when(mockOrganisationRepo.removeCollaboratorFromOrganisation(eqTo(organisationWithCollaborators.organisationId), eqTo(aUserId))).thenReturn(
Future.successful(UpdateOrganisationSuccessResult(organisationWithCollaborators))
)

val result = await(inTest.removeAllCollaboratorsForUserId(RemoveAllCollaboratorsForUserIdRequest(aUserId, gatekeeperUserId)))
result shouldBe List(UpdateOrganisationSuccessResult(organisationWithCollaborators))

verify(mockOrganisationRepo).removeCollaboratorFromOrganisation(eqTo(organisationWithCollaborators.organisationId), eqTo(aUserId))
}

"return a list of UpdateOrganisationSuccessResult when successful for three organisations" in new Setup {
val collaboratorThree = Collaborator(UserId.random, LaxEmailAddress("emailThree@example.com"))
val organisationWithCollaborators2 = anOrganisation.copy(organisationId = OrganisationId.random, collaborators = List(aCollaborator, collaboratorThree))
val organisationWithCollaborators3 = anOrganisation.copy(organisationId = OrganisationId.random, collaborators = List(collaboratorTwo, collaboratorThree))

when(mockOrganisationRepo.findByUserId(eqTo(aUserId))).thenReturn(Future.successful(List(
organisationWithCollaborators,
organisationWithCollaborators2,
organisationWithCollaborators3
)))
when(mockOrganisationRepo.removeCollaboratorFromOrganisation(eqTo(organisationWithCollaborators.organisationId), eqTo(aUserId))).thenReturn(
Future.successful(UpdateOrganisationSuccessResult(organisationWithCollaborators))
)
when(mockOrganisationRepo.removeCollaboratorFromOrganisation(eqTo(organisationWithCollaborators2.organisationId), eqTo(aUserId))).thenReturn(
Future.successful(UpdateOrganisationSuccessResult(organisationWithCollaborators2))
)
when(mockOrganisationRepo.removeCollaboratorFromOrganisation(eqTo(organisationWithCollaborators3.organisationId), eqTo(aUserId))).thenReturn(
Future.successful(UpdateOrganisationSuccessResult(organisationWithCollaborators3))
)

val result = await(inTest.removeAllCollaboratorsForUserId(RemoveAllCollaboratorsForUserIdRequest(aUserId, gatekeeperUserId)))
result shouldBe List(
UpdateOrganisationSuccessResult(organisationWithCollaborators),
UpdateOrganisationSuccessResult(organisationWithCollaborators2),
UpdateOrganisationSuccessResult(organisationWithCollaborators3)
)

verify(mockOrganisationRepo).removeCollaboratorFromOrganisation(eqTo(organisationWithCollaborators.organisationId), eqTo(aUserId))
verify(mockOrganisationRepo).removeCollaboratorFromOrganisation(eqTo(organisationWithCollaborators2.organisationId), eqTo(aUserId))
verify(mockOrganisationRepo).removeCollaboratorFromOrganisation(eqTo(organisationWithCollaborators3.organisationId), eqTo(aUserId))
}

"return a list of UpdateOrganisationSuccessResult when successful no organisations" in new Setup {
when(mockOrganisationRepo.findByUserId(eqTo(aUserId))).thenReturn(Future.successful(List.empty))

val result = await(inTest.removeAllCollaboratorsForUserId(RemoveAllCollaboratorsForUserIdRequest(aUserId, gatekeeperUserId)))
result shouldBe List.empty

verify(mockOrganisationRepo, never).removeCollaboratorFromOrganisation(*[OrganisationId], *[UserId])
}

"return a failure" in new Setup {
when(mockOrganisationRepo.findByUserId(eqTo(aUserId))).thenReturn(Future.successful(List(organisationWithCollaborators)))
when(mockOrganisationRepo.removeCollaboratorFromOrganisation(eqTo(organisationWithCollaborators.organisationId), eqTo(aUserId))).thenReturn(
Future.successful(UpdateOrganisationFailedResult())
)

val result = await(inTest.removeAllCollaboratorsForUserId(RemoveAllCollaboratorsForUserIdRequest(aUserId, gatekeeperUserId)))
result shouldBe List(UpdateOrganisationFailedResult())
}
}
}

0 comments on commit 6a6c69d

Please sign in to comment.