Skip to content

Add createTenant and updateTenant operations. #377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions src/main/java/com/google/firebase/auth/FirebaseUserManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.firebase.FirebaseApp;
import com.google.firebase.ImplFirebaseTrampolines;
import com.google.firebase.auth.UserRecord.CreateRequest;
import com.google.firebase.auth.UserRecord.UpdateRequest;
import com.google.firebase.auth.UserRecord;
import com.google.firebase.auth.internal.DownloadAccountResponse;
import com.google.firebase.auth.internal.GetAccountInfoResponse;
import com.google.firebase.auth.internal.HttpErrorResponse;
Expand Down Expand Up @@ -171,7 +171,7 @@ UserRecord getUserByPhoneNumber(String phoneNumber) throws FirebaseAuthException
return new UserRecord(response.getUsers().get(0), jsonFactory);
}

String createUser(CreateRequest request) throws FirebaseAuthException {
String createUser(UserRecord.CreateRequest request) throws FirebaseAuthException {
GenericJson response = post(
"/accounts", request.getProperties(), GenericJson.class);
if (response != null) {
Expand All @@ -183,7 +183,8 @@ String createUser(CreateRequest request) throws FirebaseAuthException {
throw new FirebaseAuthException(INTERNAL_ERROR, "Failed to create new user");
}

void updateUser(UpdateRequest request, JsonFactory jsonFactory) throws FirebaseAuthException {
void updateUser(UserRecord.UpdateRequest request, JsonFactory jsonFactory)
throws FirebaseAuthException {
GenericJson response = post(
"/accounts:update", request.getProperties(jsonFactory), GenericJson.class);
if (response == null || !request.getUid().equals(response.get("localId"))) {
Expand Down Expand Up @@ -230,20 +231,33 @@ UserImportResult importUsers(UserImportRequest request) throws FirebaseAuthExcep

Tenant getTenant(String tenantId) throws FirebaseAuthException {
GenericUrl url = new GenericUrl(tenantMgtBaseUrl + "/tenants/" + tenantId);
Tenant response = sendRequest("GET", url, null, Tenant.class);
if (Strings.isNullOrEmpty(response.getTenantId())) {
throw new FirebaseAuthException(TENANT_NOT_FOUND_ERROR, "Failed to get tenant.");
}
return response;
return sendRequest("GET", url, null, Tenant.class);
}

Tenant createTenant(Tenant.CreateRequest request) throws FirebaseAuthException {
GenericUrl url = new GenericUrl(tenantMgtBaseUrl + "/tenants");
return sendRequest("POST", url, request.getProperties(), Tenant.class);
}

Tenant updateTenant(Tenant.UpdateRequest request) throws FirebaseAuthException {
Map<String, Object> properties = request.getProperties();
checkArgument(!properties.isEmpty(), "tenant update must have at least one property set");
GenericUrl url = new GenericUrl(tenantMgtBaseUrl + "/tenants/" + request.getTenantId());
url.put("updateMask", generateMask(properties));
return sendRequest("PATCH", url, properties, Tenant.class);
}

private static String generateMask(Map<String, Object> properties) {
// This implementation does not currently handle the case of nested properties. This is fine
// since we do not currently generate masks for any properties with nested values. When it
// comes time to implement this, we can check if a property has nested properties by checking
// if it is an instance of the Map class.
return String.join(",", ImmutableSortedSet.copyOf(properties.keySet()));
}

void deleteTenant(String tenantId) throws FirebaseAuthException {
GenericUrl url = new GenericUrl(tenantMgtBaseUrl + "/tenants/" + tenantId);
GenericJson response = sendRequest("DELETE", url, null, GenericJson.class);
if (response == null) {
throw new FirebaseAuthException(TENANT_NOT_FOUND_ERROR,
"Failed to delete tenant: " + tenantId);
}
sendRequest("DELETE", url, null, GenericJson.class);
}

ListTenantsResponse listTenants(int maxResults, String pageToken)
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/google/firebase/auth/Tenant.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ Map<String, Object> getProperties() {
*/
public static final class UpdateRequest {

private final String tenantId;
private final Map<String,Object> properties = new HashMap<>();

/**
Expand All @@ -148,11 +149,11 @@ public static final class UpdateRequest {
*/
public UpdateRequest(String tenantId) {
checkArgument(!Strings.isNullOrEmpty(tenantId), "tenant ID must not be null or empty");
properties.put("name", tenantId);
this.tenantId = tenantId;
}

String getTenantId() {
return (String) properties.get("name");
return tenantId;
}

/**
Expand Down
77 changes: 75 additions & 2 deletions src/main/java/com/google/firebase/auth/TenantManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
* This class can be used to perform a variety of tenant-related operations, including creating,
* updating, and listing tenants.
*
* <p>TODO(micahstairs): Implement the following methods: getAuthForTenant(), createTenant(), and
* updateTenant().
* <p>TODO(micahstairs): Implement getAuthForTenant().
*/
public final class TenantManager {

Expand Down Expand Up @@ -154,6 +153,80 @@ protected ListTenantsPage execute() throws FirebaseAuthException {
};
}

/**
* Creates a new tenant with the attributes contained in the specified {@link CreateRequest}.
*
* @param request A non-null {@link CreateRequest} instance.
* @return A {@link Tenant} instance corresponding to the newly created tenant.
* @throws NullPointerException if the provided request is null.
* @throws FirebaseAuthException if an error occurs while creating the tenant.
*/
public Tenant createTenant(@NonNull CreateRequest request) throws FirebaseAuthException {
return createTenantOp(request).call();
}

/**
* Similar to {@link #createTenant(CreateRequest)} but performs the operation asynchronously.
*
* @param request A non-null {@link CreateRequest} instance.
* @return An {@code ApiFuture} which will complete successfully with a {@link Tenant}
* instance corresponding to the newly created tenant. If an error occurs while creating the
* tenant, the future throws a {@link FirebaseAuthException}.
* @throws NullPointerException if the provided request is null.
*/
public ApiFuture<Tenant> createTenantAsync(@NonNull CreateRequest request) {
return createTenantOp(request).callAsync(firebaseApp);
}

/**
* Updates an existing user account with the attributes contained in the specified {@link
* UpdateRequest}.
*
* @param request A non-null {@link UpdateRequest} instance.
* @return A {@link Tenant} instance corresponding to the updated user account.
* @throws NullPointerException if the provided update request is null.
* @throws FirebaseAuthException if an error occurs while updating the user account.
*/
public Tenant updateTenant(@NonNull UpdateRequest request) throws FirebaseAuthException {
return updateTenantOp(request).call();
}

/**
* Similar to {@link #updateTenant(UpdateRequest)} but performs the operation asynchronously.
*
* @param request A non-null {@link UpdateRequest} instance.
* @return An {@code ApiFuture} which will complete successfully with a {@link Tenant}
* instance corresponding to the updated user account. If an error occurs while updating the
* user account, the future throws a {@link FirebaseAuthException}.
*/
public ApiFuture<Tenant> updateTenantAsync(@NonNull UpdateRequest request) {
return updateTenantOp(request).callAsync(firebaseApp);
}

private CallableOperation<Tenant, FirebaseAuthException> updateTenantOp(
final UpdateRequest request) {
// TODO(micahstairs): Add a check to make sure the app has not been destroyed yet.
checkNotNull(request, "update request must not be null");
return new CallableOperation<Tenant, FirebaseAuthException>() {
@Override
protected Tenant execute() throws FirebaseAuthException {
return userManager.updateTenant(request);
}
};
}

private CallableOperation<Tenant, FirebaseAuthException> createTenantOp(
final CreateRequest request) {
// TODO(micahstairs): Add a check to make sure the app has not been destroyed yet.
checkNotNull(request, "create request must not be null");
return new CallableOperation<Tenant, FirebaseAuthException>() {
@Override
protected Tenant execute() throws FirebaseAuthException {
return userManager.createTenant(request);
}
};
}

/**
* Deletes the tenant identified by the specified tenant ID.
*
Expand Down
Loading