Skip to content

Commit 3a0e104

Browse files
authored
fix: app id in user id queries (#134)
1 parent a237aaa commit 3a0e104

File tree

6 files changed

+80
-71
lines changed

6 files changed

+80
-71
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
99

10+
## [4.0.1] - 2023-07-11
11+
12+
- Fixes duplicate users in users search queries when user is associated to multiple tenants
13+
14+
1015
## [4.0.0] - 2023-06-02
1116

1217
### Changes

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ plugins {
22
id 'java-library'
33
}
44

5-
version = "4.0.0"
5+
version = "4.0.1"
66

77
repositories {
88
mavenCentral()

src/main/java/io/supertokens/storage/postgresql/queries/EmailPasswordQueries.java

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ public static UserInfo getUserInfoUsingId_Transaction(Start start, Connection co
223223
}
224224
return null;
225225
});
226-
return userInfoWithTenantIds_transaction(start, con, userInfo);
226+
return userInfoWithTenantIds_transaction(start, con, appIdentifier, userInfo);
227227
}
228228

229229
public static PasswordResetTokenInfo getPasswordResetTokenInfo(Start start, AppIdentifier appIdentifier, String token)
@@ -306,7 +306,7 @@ public static UserInfo signUp(Start start, TenantIdentifier tenantIdentifier, St
306306
});
307307
}
308308

309-
UserInfo userInfo = userInfoWithTenantIds_transaction(start, sqlCon, new UserInfoPartial(userId, email, passwordHash, timeJoined));
309+
UserInfo userInfo = userInfoWithTenantIds_transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), new UserInfoPartial(userId, email, passwordHash, timeJoined));
310310

311311
sqlCon.commit();
312312
return userInfo;
@@ -352,7 +352,7 @@ public static UserInfo getUserInfoUsingId(Start start, AppIdentifier appIdentifi
352352
}
353353
return null;
354354
});
355-
return userInfoWithTenantIds(start, userInfo);
355+
return userInfoWithTenantIds(start, appIdentifier, userInfo);
356356
}
357357

358358
public static UserInfoPartial getUserInfoUsingId(Start start, Connection sqlCon, AppIdentifier appIdentifier, String id) throws SQLException, StorageQueryException {
@@ -371,13 +371,13 @@ public static UserInfoPartial getUserInfoUsingId(Start start, Connection sqlCon,
371371
});
372372
}
373373

374-
public static List<UserInfo> getUsersInfoUsingIdList(Start start, List<String> ids)
374+
public static List<UserInfo> getUsersInfoUsingIdList(Start start, AppIdentifier appIdentifier, List<String> ids)
375375
throws SQLException, StorageQueryException {
376376
if (ids.size() > 0) {
377377
// No need to filter based on tenantId because the id list is already filtered for a tenant
378378
StringBuilder QUERY = new StringBuilder("SELECT user_id, email, password_hash, time_joined "
379379
+ "FROM " + getConfig(start).getEmailPasswordUsersTable());
380-
QUERY.append(" WHERE user_id IN (");
380+
QUERY.append(" WHERE app_id = ? AND user_id IN (");
381381
for (int i = 0; i < ids.size(); i++) {
382382

383383
QUERY.append("?");
@@ -389,9 +389,10 @@ public static List<UserInfo> getUsersInfoUsingIdList(Start start, List<String> i
389389
QUERY.append(")");
390390

391391
List<UserInfoPartial> userInfos = execute(start, QUERY.toString(), pst -> {
392+
pst.setString(1, appIdentifier.getAppId());
392393
for (int i = 0; i < ids.size(); i++) {
393-
// i+1 cause this starts with 1 and not 0
394-
pst.setString(i + 1, ids.get(i));
394+
// i+2 cause this starts with 1 and not 0, and 1 is appId
395+
pst.setString(i + 2, ids.get(i));
395396
}
396397
}, result -> {
397398
List<UserInfoPartial> finalResult = new ArrayList<>();
@@ -400,7 +401,7 @@ public static List<UserInfo> getUsersInfoUsingIdList(Start start, List<String> i
400401
}
401402
return finalResult;
402403
});
403-
return userInfoWithTenantIds(start, userInfos);
404+
return userInfoWithTenantIds(start, appIdentifier, userInfos);
404405
}
405406
return Collections.emptyList();
406407
}
@@ -423,7 +424,7 @@ public static UserInfo getUserInfoUsingEmail(Start start, TenantIdentifier tenan
423424
}
424425
return null;
425426
});
426-
return userInfoWithTenantIds(start, userInfo);
427+
return userInfoWithTenantIds(start, tenantIdentifier.toAppIdentifier(), userInfo);
427428
}
428429

429430
public static boolean addUserIdToTenant_Transaction(Start start, Connection sqlCon,
@@ -477,35 +478,35 @@ public static boolean removeUserIdFromTenant_Transaction(Start start, Connection
477478
// automatically deleted from emailpassword_user_to_tenant because of foreign key constraint
478479
}
479480

480-
private static UserInfo userInfoWithTenantIds(Start start, UserInfoPartial userInfo)
481+
private static UserInfo userInfoWithTenantIds(Start start, AppIdentifier appIdentifier, UserInfoPartial userInfo)
481482
throws SQLException, StorageQueryException {
482483
if (userInfo == null) return null;
483484
try (Connection con = ConnectionPool.getConnection(start)) {
484-
return userInfoWithTenantIds_transaction(start, con, Arrays.asList(userInfo)).get(0);
485+
return userInfoWithTenantIds_transaction(start, con, appIdentifier, Arrays.asList(userInfo)).get(0);
485486
}
486487
}
487488

488-
private static List<UserInfo> userInfoWithTenantIds(Start start, List<UserInfoPartial> userInfos)
489+
private static List<UserInfo> userInfoWithTenantIds(Start start, AppIdentifier appIdentifier, List<UserInfoPartial> userInfos)
489490
throws SQLException, StorageQueryException {
490491
try (Connection con = ConnectionPool.getConnection(start)) {
491-
return userInfoWithTenantIds_transaction(start, con, userInfos);
492+
return userInfoWithTenantIds_transaction(start, con, appIdentifier, userInfos);
492493
}
493494
}
494495

495-
private static UserInfo userInfoWithTenantIds_transaction(Start start, Connection sqlCon, UserInfoPartial userInfo)
496+
private static UserInfo userInfoWithTenantIds_transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, UserInfoPartial userInfo)
496497
throws SQLException, StorageQueryException {
497498
if (userInfo == null) return null;
498-
return userInfoWithTenantIds_transaction(start, sqlCon, Arrays.asList(userInfo)).get(0);
499+
return userInfoWithTenantIds_transaction(start, sqlCon, appIdentifier, Arrays.asList(userInfo)).get(0);
499500
}
500501

501-
private static List<UserInfo> userInfoWithTenantIds_transaction(Start start, Connection sqlCon, List<UserInfoPartial> userInfos)
502+
private static List<UserInfo> userInfoWithTenantIds_transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, List<UserInfoPartial> userInfos)
502503
throws SQLException, StorageQueryException {
503504
String[] userIds = new String[userInfos.size()];
504505
for (int i = 0; i < userInfos.size(); i++) {
505506
userIds[i] = userInfos.get(i).id;
506507
}
507508

508-
Map<String, List<String>> tenantIdsForUserIds = GeneralQueries.getTenantIdsForUserIds_transaction(start, sqlCon, userIds);
509+
Map<String, List<String>> tenantIdsForUserIds = GeneralQueries.getTenantIdsForUserIds_transaction(start, sqlCon, appIdentifier, userIds);
509510
List<UserInfo> result = new ArrayList<>();
510511
for (UserInfoPartial userInfo : userInfos) {
511512
result.add(new UserInfo(userInfo.id, userInfo.email, userInfo.passwordHash, userInfo.timeJoined,

src/main/java/io/supertokens/storage/postgresql/queries/GeneralQueries.java

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,7 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant
712712
+ " AS allAuthUsersTable" +
713713
" JOIN " + getConfig(start).getEmailPasswordUserToTenantTable()
714714
+ " AS emailpasswordTable ON allAuthUsersTable.app_id = emailpasswordTable.app_id AND "
715+
+ "allAuthUsersTable.tenant_id = emailpasswordTable.tenant_id AND "
715716
+ "allAuthUsersTable.user_id = emailpasswordTable.user_id";
716717

717718
// attach email tags to queries
@@ -737,15 +738,14 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant
737738
// check if we should search through the thirdparty table
738739
if (dashboardSearchTags.shouldThirdPartyTableBeSearched()) {
739740
String QUERY = "SELECT allAuthUsersTable.*" + " FROM " + getConfig(start).getUsersTable()
740-
+ " AS allAuthUsersTable" +
741-
" JOIN " + getConfig(start).getThirdPartyUsersTable()
742-
+ " AS thirdPartyTable ON allAuthUsersTable.app_id = thirdPartyTable.app_id AND"
743-
+ " allAuthUsersTable.user_id = thirdPartyTable.user_id"
741+
+ " AS allAuthUsersTable"
744742
+ " JOIN " + getConfig(start).getThirdPartyUserToTenantTable()
745-
+
746-
" AS thirdPartyToTenantTable ON thirdPartyTable.app_id = thirdPartyToTenantTable" +
747-
".app_id AND"
748-
+ " thirdPartyTable.user_id = thirdPartyToTenantTable.user_id";
743+
+ " AS thirdPartyToTenantTable ON allAuthUsersTable.app_id = thirdPartyToTenantTable.app_id AND"
744+
+ " allAuthUsersTable.tenant_id = thirdPartyToTenantTable.tenant_id AND"
745+
+ " allAuthUsersTable.user_id = thirdPartyToTenantTable.user_id"
746+
+ " JOIN " + getConfig(start).getThirdPartyUsersTable()
747+
+ " AS thirdPartyTable ON thirdPartyToTenantTable.app_id = thirdPartyTable.app_id AND"
748+
+ " thirdPartyToTenantTable.user_id = thirdPartyTable.user_id";
749749

750750
// check if email tag is present
751751
if (dashboardSearchTags.emails != null) {
@@ -810,6 +810,7 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant
810810
+ " AS allAuthUsersTable" +
811811
" JOIN " + getConfig(start).getPasswordlessUserToTenantTable()
812812
+ " AS passwordlessTable ON allAuthUsersTable.app_id = passwordlessTable.app_id AND"
813+
+ " allAuthUsersTable.tenant_id = passwordlessTable.tenant_id AND"
813814
+ " allAuthUsersTable.user_id = passwordlessTable.user_id";
814815

815816
// check if email tag is present
@@ -985,7 +986,7 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant
985986
// we give the userId[] for each recipe to fetch all those user's details
986987
for (RECIPE_ID recipeId : recipeIdToUserIdListMap.keySet()) {
987988
List<? extends AuthRecipeUserInfo> users = getUserInfoForRecipeIdFromUserIds(start,
988-
tenantIdentifier, recipeId, recipeIdToUserIdListMap.get(recipeId));
989+
tenantIdentifier.toAppIdentifier(), recipeId, recipeIdToUserIdListMap.get(recipeId));
989990

990991
// we fill in all the slots in finalResult based on their position in
991992
// usersFromQuery
@@ -1004,16 +1005,16 @@ public static AuthRecipeUserInfo[] getUsers(Start start, TenantIdentifier tenant
10041005
}
10051006

10061007
private static List<? extends AuthRecipeUserInfo> getUserInfoForRecipeIdFromUserIds(Start start,
1007-
TenantIdentifier tenantIdentifier,
1008+
AppIdentifier appIdentifier,
10081009
RECIPE_ID recipeId,
10091010
List<String> userIds)
10101011
throws StorageQueryException, SQLException {
10111012
if (recipeId == RECIPE_ID.EMAIL_PASSWORD) {
1012-
return EmailPasswordQueries.getUsersInfoUsingIdList(start, userIds);
1013+
return EmailPasswordQueries.getUsersInfoUsingIdList(start, appIdentifier, userIds);
10131014
} else if (recipeId == RECIPE_ID.THIRD_PARTY) {
1014-
return ThirdPartyQueries.getUsersInfoUsingIdList(start, userIds);
1015+
return ThirdPartyQueries.getUsersInfoUsingIdList(start, appIdentifier, userIds);
10151016
} else if (recipeId == RECIPE_ID.PASSWORDLESS) {
1016-
return PasswordlessQueries.getUsersByIdList(start, userIds);
1017+
return PasswordlessQueries.getUsersByIdList(start, appIdentifier, userIds);
10171018
} else {
10181019
throw new IllegalArgumentException("No implementation of get users for recipe: " + recipeId.toString());
10191020
}
@@ -1035,12 +1036,12 @@ public static String getRecipeIdForUser_Transaction(Start start, Connection sqlC
10351036
});
10361037
}
10371038

1038-
public static Map<String, List<String>> getTenantIdsForUserIds_transaction(Start start, Connection sqlCon, String[] userIds)
1039+
public static Map<String, List<String>> getTenantIdsForUserIds_transaction(Start start, Connection sqlCon, AppIdentifier appIdentifier, String[] userIds)
10391040
throws SQLException, StorageQueryException {
10401041
if (userIds != null && userIds.length > 0) {
10411042
StringBuilder QUERY = new StringBuilder("SELECT user_id, tenant_id "
10421043
+ "FROM " + getConfig(start).getUsersTable());
1043-
QUERY.append(" WHERE user_id IN (");
1044+
QUERY.append(" WHERE app_id = ? AND user_id IN (");
10441045
for (int i = 0; i < userIds.length; i++) {
10451046

10461047
QUERY.append("?");
@@ -1052,9 +1053,10 @@ public static Map<String, List<String>> getTenantIdsForUserIds_transaction(Start
10521053
QUERY.append(")");
10531054

10541055
return execute(sqlCon, QUERY.toString(), pst -> {
1056+
pst.setString(1, appIdentifier.getAppId());
10551057
for (int i = 0; i < userIds.length; i++) {
1056-
// i+1 cause this starts with 1 and not 0
1057-
pst.setString(i + 1, userIds[i]);
1058+
// i+2 cause this starts with 1 and not 0, and 1 is appId
1059+
pst.setString(i + 2, userIds[i]);
10581060
}
10591061
}, result -> {
10601062
Map<String, List<String>> finalResult = new HashMap<>();

0 commit comments

Comments
 (0)