@budibase/worker 3.14.0 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/worker",
3
3
  "email": "hi@budibase.com",
4
- "version": "3.14.0",
4
+ "version": "3.15.0",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -115,5 +115,5 @@
115
115
  }
116
116
  }
117
117
  },
118
- "gitHead": "7ff8f5fc9480931c373b86dd573882841dd290d4"
118
+ "gitHead": "d220e217e0f03ff770421191b5b49cf8268f007f"
119
119
  }
@@ -30,6 +30,7 @@ import {
30
30
  LockType,
31
31
  LookupAccountHolderResponse,
32
32
  LookupTenantUserResponse,
33
+ OIDCUser,
33
34
  SaveUserResponse,
34
35
  SearchUsersRequest,
35
36
  SearchUsersResponse,
@@ -114,11 +115,20 @@ export const changeTenantOwnerEmail = async (
114
115
  try {
115
116
  for (const tenantId of tenantIds) {
116
117
  await tenancy.doInTenant(tenantId, async () => {
117
- const tenantUser = await userSdk.db.getUserByEmail(originalEmail)
118
+ const tenantUser = (await userSdk.db.getUserByEmail(
119
+ originalEmail
120
+ )) as OIDCUser
118
121
  if (!tenantUser) {
119
122
  return
120
123
  }
121
124
  tenantUser.email = newAccountEmail
125
+
126
+ tenantUser.provider = undefined
127
+ tenantUser.providerType = undefined
128
+ tenantUser.thirdPartyProfile = undefined
129
+ tenantUser.profile = undefined
130
+ tenantUser.oauth2 = undefined
131
+
122
132
  await userSdk.db.save(tenantUser, {
123
133
  currentUserId: tenantUser._id,
124
134
  isAccountHolder: true,
@@ -1,4 +1,4 @@
1
- import { InviteUsersResponse, User } from "@budibase/types"
1
+ import { InviteUsersResponse, User, OIDCUser } from "@budibase/types"
2
2
 
3
3
  import { TestConfiguration, mocks, structures } from "../../../../tests"
4
4
  import { events, tenancy, accounts as _accounts } from "@budibase/backend-core"
@@ -800,4 +800,162 @@ describe("/api/global/users", () => {
800
800
  expect(response.unsuccessful.length).toBe(1)
801
801
  })
802
802
  })
803
+
804
+ describe("PUT /api/global/users/tenant/owner", () => {
805
+ it("should successfully change tenant owner email for existing user", async () => {
806
+ const originalEmail = `original-${structures.uuid()}@example.com`
807
+ const newEmail = `new-${structures.uuid()}@example.com`
808
+ const tenantId = config.getTenantId()
809
+
810
+ const user = await config.doInTenant(async () => {
811
+ return await userSdk.db.save(
812
+ {
813
+ email: originalEmail,
814
+ tenantId,
815
+ } as any,
816
+ { requirePassword: false, isAccountHolder: true }
817
+ )
818
+ })
819
+
820
+ await config.api.users.changeTenantOwnerEmail(newEmail, originalEmail, [
821
+ tenantId,
822
+ ])
823
+
824
+ const updatedUser = await config.doInTenant(async () => {
825
+ return await userSdk.db.getUser(user._id!)
826
+ })
827
+
828
+ expect(updatedUser).toBeDefined()
829
+ expect(updatedUser!.email).toBe(newEmail)
830
+ })
831
+
832
+ it("should handle multiple tenants", async () => {
833
+ const originalEmail = `original-${structures.uuid()}@example.com`
834
+ const newEmail = `new-${structures.uuid()}@example.com`
835
+ const tenant1 = config.getTenantId()
836
+ const tenant2 = structures.tenant.id()
837
+
838
+ const user1 = await config.doInTenant(async () => {
839
+ return await userSdk.db.save(
840
+ {
841
+ email: originalEmail,
842
+ tenantId: tenant1,
843
+ } as any,
844
+ { requirePassword: false, isAccountHolder: true }
845
+ )
846
+ })
847
+
848
+ const user2 = await config.doInSpecificTenant(tenant2, async () => {
849
+ return await userSdk.db.save(
850
+ {
851
+ email: originalEmail,
852
+ tenantId: tenant2,
853
+ } as any,
854
+ { requirePassword: false, isAccountHolder: true }
855
+ )
856
+ })
857
+
858
+ await config.api.users.changeTenantOwnerEmail(newEmail, originalEmail, [
859
+ tenant1,
860
+ tenant2,
861
+ ])
862
+
863
+ const updatedUser1 = await config.doInTenant(async () => {
864
+ return await userSdk.db.getUser(user1._id!)
865
+ })
866
+
867
+ const updatedUser2 = await config.doInSpecificTenant(
868
+ tenant2,
869
+ async () => {
870
+ return await userSdk.db.getUser(user2._id!)
871
+ }
872
+ )
873
+
874
+ expect(updatedUser1).toBeDefined()
875
+ expect(updatedUser1!.email).toBe(newEmail)
876
+ expect(updatedUser2).toBeDefined()
877
+ expect(updatedUser2!.email).toBe(newEmail)
878
+ })
879
+
880
+ it("should not fail if user doesn't exist in tenant", async () => {
881
+ const originalEmail = `nonexistent-${structures.uuid()}@example.com`
882
+ const newEmail = `new-${structures.uuid()}@example.com`
883
+ const tenantId = config.getTenantId()
884
+
885
+ await config.api.users.changeTenantOwnerEmail(newEmail, originalEmail, [
886
+ tenantId,
887
+ ])
888
+
889
+ const user = await config.doInTenant(async () => {
890
+ return await userSdk.db.getUserByEmail(newEmail)
891
+ })
892
+
893
+ expect(user).toBeUndefined()
894
+ })
895
+
896
+ it("should handle empty tenant list", async () => {
897
+ const originalEmail = `original-${structures.uuid()}@example.com`
898
+ const newEmail = `new-${structures.uuid()}@example.com`
899
+
900
+ await config.api.users.changeTenantOwnerEmail(newEmail, originalEmail, [])
901
+ })
902
+
903
+ it("should clear all OIDC-related fields", async () => {
904
+ const originalEmail = `original-${structures.uuid()}@example.com`
905
+ const newEmail = `new-${structures.uuid()}@example.com`
906
+ const tenantId = config.getTenantId()
907
+ const profile = {}
908
+ const provider = "oidc"
909
+ const providerType = "oidc"
910
+ const thirdPartyProfile = {}
911
+ const oauth2 = {}
912
+
913
+ await config.doInTenant(async () => {
914
+ await userSdk.db.save(
915
+ {
916
+ email: originalEmail,
917
+ tenantId,
918
+ profile,
919
+ provider,
920
+ providerType,
921
+ thirdPartyProfile,
922
+ oauth2,
923
+ } as any,
924
+ { requirePassword: false, isAccountHolder: true }
925
+ )
926
+ })
927
+
928
+ await config.api.users.changeTenantOwnerEmail(newEmail, originalEmail, [
929
+ tenantId,
930
+ ])
931
+
932
+ const updatedUser = (await config.doInTenant(async () => {
933
+ return await userSdk.db.getUserByEmail(newEmail)
934
+ })) as OIDCUser
935
+
936
+ expect(updatedUser).toBeDefined()
937
+ expect(updatedUser!.email).toBe(newEmail)
938
+ expect(updatedUser.profile).toBe(undefined)
939
+ expect(updatedUser.provider).toBe(undefined)
940
+ expect(updatedUser.providerType).toBe(undefined)
941
+ expect(updatedUser.thirdPartyProfile).toBe(undefined)
942
+ expect(updatedUser.oauth2).toBe(undefined)
943
+ })
944
+
945
+ it("should require internal API headers", async () => {
946
+ const originalEmail = `original-${structures.uuid()}@example.com`
947
+ const newEmail = `new-${structures.uuid()}@example.com`
948
+ const tenantId = config.getTenantId()
949
+
950
+ await config.request
951
+ .put(`/api/global/users/tenant/owner`)
952
+ .send({
953
+ newAccountEmail: newEmail,
954
+ originalEmail,
955
+ tenantIds: [tenantId],
956
+ })
957
+ .set(config.defaultHeaders())
958
+ .expect(403)
959
+ })
960
+ })
803
961
  })
@@ -138,9 +138,9 @@ class TestConfiguration {
138
138
 
139
139
  // TENANCY
140
140
 
141
- doInTenant(task: any) {
142
- return context.doInTenant(this.tenantId, () => {
143
- return task()
141
+ async doInTenant<T>(task: () => Promise<T>): Promise<T> {
142
+ return await context.doInTenant(this.tenantId, async () => {
143
+ return await task()
144
144
  })
145
145
  }
146
146
 
@@ -171,6 +171,15 @@ class TestConfiguration {
171
171
  }
172
172
  }
173
173
 
174
+ async doInSpecificTenant<T>(
175
+ tenantId: string,
176
+ task: () => Promise<T>
177
+ ): Promise<T> {
178
+ return await context.doInTenant(tenantId, async () => {
179
+ return await task()
180
+ })
181
+ }
182
+
174
183
  // AUTH
175
184
 
176
185
  async _createSession({
@@ -214,4 +214,17 @@ export class UserAPI extends TestAPI {
214
214
 
215
215
  return resp.body as InviteUsersResponse
216
216
  }
217
+
218
+ changeTenantOwnerEmail = (
219
+ newAccountEmail: string,
220
+ originalEmail: string,
221
+ tenantIds: string[],
222
+ status = 200
223
+ ) => {
224
+ return this.request
225
+ .put(`/api/global/users/tenant/owner`)
226
+ .send({ newAccountEmail, originalEmail, tenantIds })
227
+ .set(this.config.internalAPIHeaders())
228
+ .expect(status)
229
+ }
217
230
  }