diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 94c0f5211..d2941298f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -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 diff --git a/src/main/java/io/supertokens/bulkimport/BulkImport.java b/src/main/java/io/supertokens/bulkimport/BulkImport.java index 1f9e38d06..329fc7e63 100644 --- a/src/main/java/io/supertokens/bulkimport/BulkImport.java +++ b/src/main/java/io/supertokens/bulkimport/BulkImport.java @@ -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 users) throws StorageQueryException, TenantOrAppNotFoundException { @@ -75,4 +76,8 @@ public static BulkImportUserPaginationContainer getUsers(AppIdentifierWithStorag List resultUsers = users.subList(0, maxLoop); return new BulkImportUserPaginationContainer(resultUsers, nextPaginationToken); } + + public static List deleteUsers(AppIdentifierWithStorage appIdentifierWithStorage, String[] userIds) throws StorageQueryException { + return appIdentifierWithStorage.getBulkImportStorage().deleteBulkImportUsers(appIdentifierWithStorage, userIds); + } } diff --git a/src/main/java/io/supertokens/webserver/api/bulkimport/BulkImportAPI.java b/src/main/java/io/supertokens/webserver/api/bulkimport/BulkImportAPI.java index d6e903bb9..af2a29c9c 100644 --- a/src/main/java/io/supertokens/webserver/api/bulkimport/BulkImportAPI.java +++ b/src/main/java/io/supertokens/webserver/api/bulkimport/BulkImportAPI.java @@ -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; @@ -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 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); + } + } } diff --git a/src/test/java/io/supertokens/test/bulkimport/apis/DeleteFailedBulkImportUsersTest.java b/src/test/java/io/supertokens/test/bulkimport/apis/DeleteBulkImportUsersTest.java similarity index 90% rename from src/test/java/io/supertokens/test/bulkimport/apis/DeleteFailedBulkImportUsersTest.java rename to src/test/java/io/supertokens/test/bulkimport/apis/DeleteBulkImportUsersTest.java index 0e8ff9fdf..f4edc4ba3 100644 --- a/src/test/java/io/supertokens/test/bulkimport/apis/DeleteFailedBulkImportUsersTest.java +++ b/src/test/java/io/supertokens/test/bulkimport/apis/DeleteBulkImportUsersTest.java @@ -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; @@ -46,7 +47,7 @@ import static io.supertokens.test.bulkimport.BulkImportTestUtils.generateBulkImportUser; -public class DeleteFailedBulkImportUsersTest { +public class DeleteBulkImportUsersTest { @Rule public TestRule watchman = Utils.getOnFailure(); @@ -145,17 +146,25 @@ public void shouldReturn200Response() throws Exception { List 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));