Skip to content
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

feat: Add delete bulk import users api #935

Closed
wants to merge 8 commits into from
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ highlighting the necessary changes)
latest branch (`git branch --all`) whose `X.Y` is greater than the latest released tag.
- If no such branch exists, then create one from the latest released branch.
- [ ] If added a foreign key constraint on `app_id_to_user_id` table, make sure to delete from this table when deleting the user as well if `deleteUserIdMappingToo` is false.
- [ ] If added a new recipe, then make sure to update the bulk import API to include the new recipe.
## Remaining TODOs for this PR

- [ ] Item1
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/io/supertokens/bulkimport/BulkImport.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class BulkImport {
public static final int MAX_USERS_TO_ADD = 10000;
public static final int GET_USERS_PAGINATION_LIMIT = 500;
public static final int GET_USERS_DEFAULT_LIMIT = 100;
public static final int DELETE_USERS_LIMIT = 500;

public static void addUsers(AppIdentifierWithStorage appIdentifierWithStorage, List<BulkImportUser> users)
throws StorageQueryException, TenantOrAppNotFoundException {
Expand Down Expand Up @@ -75,4 +76,8 @@ public static BulkImportUserPaginationContainer getUsers(AppIdentifierWithStorag
List<BulkImportUser> resultUsers = users.subList(0, maxLoop);
return new BulkImportUserPaginationContainer(resultUsers, nextPaginationToken);
}

public static List<String> deleteUsers(AppIdentifierWithStorage appIdentifierWithStorage, String[] userIds) throws StorageQueryException {
return appIdentifierWithStorage.getBulkImportStorage().deleteBulkImportUsers(appIdentifierWithStorage, userIds);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
Expand Down Expand Up @@ -177,4 +178,60 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S
result.addProperty("status", "OK");
super.sendJsonResponse(200, result, resp);
}

@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
JsonObject input = InputParser.parseJsonObjectOrThrowError(req);
JsonArray arr = InputParser.parseArrayOrThrowError(input, "ids", false);

if (arr.size() == 0) {
throw new ServletException(new WebserverAPI.BadRequestException("Field name 'ids' cannot be an empty array"));
}

if (arr.size() > BulkImport.DELETE_USERS_LIMIT) {
throw new ServletException(new WebserverAPI.BadRequestException("Field name 'ids' cannot contain more than "
+ BulkImport.DELETE_USERS_LIMIT + " elements"));
}

String[] userIds = new String[arr.size()];

for (int i = 0; i < userIds.length; i++) {
String userId = InputParser.parseStringFromElementOrThrowError(arr.get(i), "ids", false);
if (userId.isEmpty()) {
throw new ServletException(new WebserverAPI.BadRequestException("Field name 'ids' cannot contain an empty string"));
}
userIds[i] = userId;
}

AppIdentifierWithStorage appIdentifierWithStorage;
try {
appIdentifierWithStorage = getAppIdentifierWithStorageFromRequestAndEnforcePublicTenant(req);
} catch (TenantOrAppNotFoundException | BadPermissionException e) {
throw new ServletException(e);
}

try {
List<String> deletedIds = BulkImport.deleteUsers(appIdentifierWithStorage, userIds);

JsonArray deletedIdsJson = new JsonArray();
JsonArray invalidIds = new JsonArray();

for (String userId : userIds) {
if (deletedIds.contains(userId)) {
deletedIdsJson.add(new JsonPrimitive(userId));
} else {
invalidIds.add(new JsonPrimitive(userId));
}
}

JsonObject result = new JsonObject();
result.add("deletedIds", deletedIdsJson);
result.add("invalidIds", invalidIds);

super.sendJsonResponse(200, result, resp);

} catch (StorageQueryException e) {
throw new ServletException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.List;

Expand Down Expand Up @@ -46,7 +47,7 @@

import static io.supertokens.test.bulkimport.BulkImportTestUtils.generateBulkImportUser;

public class DeleteFailedBulkImportUsersTest {
public class DeleteBulkImportUsersTest {
@Rule
public TestRule watchman = Utils.getOnFailure();

Expand Down Expand Up @@ -145,17 +146,25 @@ public void shouldReturn200Response() throws Exception {
List<BulkImportUser> users = generateBulkImportUser(5);
BulkImport.addUsers(appIdentifierWithStorage, users);

String invalidId = io.supertokens.utils.Utils.getUUID();
JsonObject request = new JsonObject();
JsonArray ids = new JsonArray();
JsonArray validIds = new JsonArray();
for (BulkImportUser user : users) {
ids.add(new JsonPrimitive(user.id));
validIds.add(new JsonPrimitive(user.id));
}
request.add("ids", ids);
validIds.add(new JsonPrimitive(invalidId));

request.add("ids", validIds);

JsonObject response = HttpRequestForTesting.sendJsonDELETERequest(process.getProcess(), "",
"http://localhost:3567/bulk-import/users",
request, 1000, 10000, null, Utils.getCdiVersionStringLatestForTests(), null);
assertEquals("OK", response.get("status").getAsString());
request, 1000000, 1000000, null, Utils.getCdiVersionStringLatestForTests(), null);

response.get("deletedIds").getAsJsonArray().forEach(id -> {
assertTrue(validIds.contains(id));
});

assertEquals(invalidId, response.get("invalidIds").getAsJsonArray().get(0).getAsString());

process.kill();
Assert.assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
Expand Down
Loading