Skip to content

Commit

Permalink
feature: Add tenant update endpoint (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
anarsultanov authored Feb 22, 2024
1 parent a2ef026 commit e994039
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public interface TenantModel {

String getName();

void setName(String name);

RealmModel getRealm();

/* Membership */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public String getName() {
return tenant.getName();
}

@Override
public void setName(String name) {
tenant.setName(name);
}

@Override
public RealmModel getRealm() {
return session.realms().getRealm(tenant.getRealmId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

import dev.sultanov.keycloak.multitenancy.model.TenantModel;
import dev.sultanov.keycloak.multitenancy.resource.representation.TenantRepresentation;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.KeycloakSession;

public class TenantResource extends AbstractAdminResource<TenantAdminAuth> {

Expand All @@ -27,6 +29,22 @@ public TenantRepresentation getTenant() {
return ModelMapper.toRepresentation(tenant);
}

@PUT
@Produces(MediaType.APPLICATION_JSON)
@Consumes(value = MediaType.APPLICATION_JSON)
@Operation(operationId = "updateTenant", summary = "Update tenant")
public Response updateTenant(TenantRepresentation request) {

tenant.setName(request.getName());

adminEvent.operation(OperationType.UPDATE)
.resourcePath(session.getContext().getUri())
.representation(ModelMapper.toRepresentation(tenant))
.success();

return Response.noContent().build();
}

@DELETE
@Operation(operationId = "deleteTenant", summary = "Delete tenant")
public void deleteTenant() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import dev.sultanov.keycloak.multitenancy.resource.representation.TenantInvitationRepresentation;
import dev.sultanov.keycloak.multitenancy.resource.representation.TenantMembershipRepresentation;
import dev.sultanov.keycloak.multitenancy.resource.representation.TenantRepresentation;
import dev.sultanov.keycloak.multitenancy.support.BaseIntegrationTest;
import dev.sultanov.keycloak.multitenancy.support.actor.KeycloakAdminCli;
import dev.sultanov.keycloak.multitenancy.support.browser.AccountPage;
Expand All @@ -24,7 +25,7 @@ void setUp() {
}

@Test
void admin_shouldBeAbleToRevokeMembership_whenUserAcceptsInvitation() {
void adminRevokesMembership_shouldSucceed_whenUserHasAcceptedInvitation() {
// given
var adminUser = keycloakAdminClient.createVerifiedUser();
var tenantResource = adminUser.createTenant();
Expand Down Expand Up @@ -61,4 +62,39 @@ void admin_shouldBeAbleToRevokeMembership_whenUserAcceptsInvitation() {
.containsExactly(adminUser.getUserData().getEmail().toLowerCase());
}
}

@Test
void adminUpdatesTenant_shouldReturnNoContent_whenTenantIsSuccessfullyUpdated() {
// given
var adminUser = keycloakAdminClient.createVerifiedUser();
var tenantResource = adminUser.createTenant();
var newName = "new-name";

// when
var request = new TenantRepresentation();
request.setName(newName);
try (var response = tenantResource.updateTenant(request)) {

// then
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_NO_CONTENT);
assertThat(tenantResource.toRepresentation().getName()).isEqualTo(newName);
}
}

@Test
void adminUpdatesTenant_shouldReturnConflict_whenUpdatedTenantNameAlreadyExists() {
// given
var adminUser = keycloakAdminClient.createVerifiedUser();
var tenantResource = adminUser.createTenant();
var existingTenantName = keycloakAdminClient.createVerifiedUser().createTenant().toRepresentation().getName();

// when
var request = new TenantRepresentation();
request.setName(existingTenantName);
try (var response = tenantResource.updateTenant(request)) {

// then
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_CONFLICT);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
package dev.sultanov.keycloak.multitenancy.support.api;

import dev.sultanov.keycloak.multitenancy.resource.representation.TenantRepresentation;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.openapi.annotations.Operation;

public interface TenantResource {

@GET
@Produces(MediaType.APPLICATION_JSON)
TenantRepresentation toRepresentation();

@PUT
@Produces(MediaType.APPLICATION_JSON)
@Consumes(value = MediaType.APPLICATION_JSON)
Response updateTenant(TenantRepresentation request);

@DELETE
@Produces(MediaType.APPLICATION_JSON)
Response deleteTenant();
Expand Down

0 comments on commit e994039

Please sign in to comment.