Skip to content

Commit 310f0bd

Browse files
authored
STITCH-4077 Javascript SDK: Decode and expose customData on UserProfile (#349)
1 parent b4bfa9c commit 310f0bd

File tree

18 files changed

+214
-17
lines changed

18 files changed

+214
-17
lines changed

packages/browser/core/src/core/auth/StitchAuth.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,9 @@ export default interface StitchAuth {
207207
* @param listener
208208
*/
209209
removeAuthListener(listener: StitchAuthListener);
210+
211+
/**
212+
* Refresh a user's custom data field.
213+
*/
214+
refreshCustomData(): Promise<void>;
210215
}

packages/browser/core/src/core/auth/StitchUser.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,17 @@ export default interface StitchUser extends CoreStitchUser {
8383
*/
8484
readonly identities: StitchUserIdentity[];
8585

86+
/**
87+
* You can store arbitrary data about your application users
88+
* in a MongoDB collection and configure Stitch to automatically
89+
* expose each user’s data in a field of their user object.
90+
* For example, you might store a user’s preferred language,
91+
* date of birth, or their local timezone.
92+
*
93+
* If this functionality has not been configured, it will be empty.
94+
*/
95+
readonly customData: { [key: string]: any };
96+
8697
/**
8798
* Links this {@link StitchUser} with a new identity, where the identity is
8899
* resolved via an external OAuth2 login process (e.g. Facebook or Google).

packages/browser/core/src/core/auth/internal/StitchAuthImpl.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,10 @@ export default class StitchAuthImpl extends CoreStitchAuth<StitchUser>
407407
}
408408
}
409409

410+
public refreshCustomData(): Promise<void> {
411+
return this.refreshAccessToken();
412+
}
413+
410414
/**
411415
* Utility function used to force the compiler to enforce an exhaustive
412416
* switch statment in dispatchAuthEvent at compile-time.

packages/browser/core/src/core/auth/internal/StitchUserFactoryImpl.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ export default class StitchUserFactoryImpl
3737
loggedInProviderName: string,
3838
isLoggedIn: boolean,
3939
lastAuthActivity: Date,
40-
userProfile: StitchUserProfileImpl
40+
userProfile: StitchUserProfileImpl,
41+
customData?: { [key: string]: any }
4142
): StitchUser {
4243
return new StitchUserImpl(
4344
id,
@@ -46,7 +47,8 @@ export default class StitchUserFactoryImpl
4647
isLoggedIn,
4748
lastAuthActivity,
4849
userProfile,
49-
this.auth
50+
this.auth,
51+
customData
5052
);
5153
}
5254
}

packages/browser/core/src/core/auth/internal/StitchUserImpl.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,17 @@ export default class StitchUserImpl extends CoreStitchUserImpl
3333
isLoggedIn: boolean,
3434
lastAuthActivity: Date,
3535
profile: StitchUserProfileImpl,
36-
private readonly auth: StitchAuthImpl
36+
private readonly auth: StitchAuthImpl,
37+
customData?: { [key: string] : any }
3738
) {
3839
super(
3940
id,
4041
loggedInProviderType,
4142
loggedInProviderName,
4243
isLoggedIn,
4344
lastAuthActivity,
44-
profile
45+
profile,
46+
customData
4547
);
4648
}
4749

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { BaseStitchBrowserIntTestHarness } from "mongodb-stitch-browser-testutils";
2+
import {
3+
AnonProviderConfig,
4+
CustomUserConfigData,
5+
MongoConfig,
6+
MongoDbRule,
7+
MongoDbService,
8+
Role,
9+
Rule,
10+
Schema,
11+
ServiceResource,
12+
StitchFunction,
13+
UserpassProvider,
14+
UserpassProviderConfig
15+
} from "mongodb-stitch-core-admin-client";
16+
import { UserPasswordCredential } from "mongodb-stitch-core-sdk";
17+
import { StitchAppClient } from "mongodb-stitch-browser-core";
18+
19+
const harness = new BaseStitchBrowserIntTestHarness();
20+
21+
beforeAll(() => harness.setup());
22+
afterAll(() => harness.teardown());
23+
24+
describe("StitchAppClient", () => {
25+
const db = "db1"
26+
const coll = "coll1"
27+
const functionName = "addUserProfile";
28+
const user = "stitch@10gen.com";
29+
const password = "stitchuser";
30+
const colorField = "favoriteColor";
31+
const favoriteColor = "blue";
32+
33+
let client: StitchAppClient;
34+
35+
it("should define custom data", async () => {
36+
const { app: appResponse, appResource: app } = await harness.createApp();
37+
await harness.addProvider(app, new AnonProviderConfig());
38+
const mongoConfg = new MongoConfig("mongodb://localhost:26000");
39+
const mongoService = new MongoDbService(mongoConfg);
40+
const svc = await harness.addService(app, mongoService);
41+
42+
await harness.addRule(svc[1] as ServiceResource<Rule, MongoDbService>, new MongoDbRule(
43+
db,
44+
coll,
45+
[new Role()],
46+
new Schema()));
47+
48+
await harness.addProvider(app,
49+
new UserpassProvider(new UserpassProviderConfig(
50+
"http://emailConfirmUrl.com",
51+
"http://resetPasswordUrl.com",
52+
"email subject",
53+
"password subject")));
54+
55+
await app.customUserData.create(new CustomUserConfigData(
56+
(svc[0] as MongoDbService).id,
57+
db,
58+
coll,
59+
"recoome",
60+
true));
61+
62+
await app.functions.create(new StitchFunction(
63+
"addUserProfile",
64+
false,
65+
`
66+
exports = async function(color) {
67+
const coll = context.services.get("mongodb1")
68+
.db("${db}").collection("${coll}");
69+
await coll.insertOne({
70+
"recoome": context.user.id,
71+
"${colorField}": "${favoriteColor}"
72+
});
73+
return true;
74+
}
75+
`,
76+
undefined));
77+
78+
client = harness.getAppClient(appResponse);
79+
await harness.registerAndLoginWithUserPass(app, client, user, password);
80+
expect(client.auth.user).toBeDefined();
81+
expect(client.auth.user!!.customData).toEqual({});
82+
83+
await client.callFunction(functionName, [favoriteColor]);
84+
85+
await client.auth.refreshCustomData();
86+
87+
expect(client.auth.user!!.customData[colorField]).toEqual(favoriteColor);
88+
});
89+
90+
it("should have custom data defined on login", async () => {
91+
await client.auth.logout();
92+
93+
await client.auth.loginWithCredential(new UserPasswordCredential(user, password));
94+
95+
expect(client.auth.user!!.customData[colorField]).toEqual(favoriteColor);
96+
})
97+
});

packages/core/admin-client/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
"build-main": "tsc -p tsconfig.cjs.json",
6464
"build-module": "tsc -p tsconfig.esm.json",
6565
"prepare": "npm run build",
66-
"test": "jest",
6766
"watch": "tsc -w -p tsconfig.esm.json",
6867
"lint": "tslint 'src/**/*.ts' '__tests__/**/*.ts'",
6968
"lint-fix": "tslint --fix 'src/**/*.ts' '__tests__/**/*.ts'",

packages/core/admin-client/src/StitchAdminUser.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class StitchAdminUser implements CoreStitchUser {
6464
*/
6565
public readonly profile: StitchUserProfileImpl;
6666

67+
public readonly customData: { [key: string] : any };
68+
6769
/**
6870
* An array of `StitchCore.StitchUserIdentity` objects representing the identities linked
6971
* to this user which can be used to log in as this user.
@@ -81,14 +83,16 @@ class StitchAdminUser implements CoreStitchUser {
8183
providerName: string,
8284
isLoggedIn: boolean,
8385
lastAuthActivity: Date,
84-
userProfile: StitchUserProfileImpl
86+
userProfile: StitchUserProfileImpl,
87+
customData?: { [key: string] : any }
8588
) {
8689
this.id = id;
8790
this.loggedInProviderType = providerType;
8891
this.loggedInProviderName = providerName;
8992
this.isLoggedIn = isLoggedIn;
9093
this.lastAuthActivity = lastAuthActivity;
9194
this.profile = userProfile;
95+
this.customData = customData === undefined ? {} : customData;
9296
}
9397
}
9498

@@ -103,15 +107,17 @@ class StitchAdminUserFactory implements StitchUserFactory<StitchAdminUser> {
103107
loggedInProviderName: string,
104108
isLoggedIn: boolean,
105109
lastAuthActivity: Date,
106-
userProfile?: StitchUserProfileImpl
110+
userProfile?: StitchUserProfileImpl,
111+
customData?: { [key: string] : any }
107112
): StitchAdminUser {
108113
return new StitchAdminUser(
109114
id,
110115
loggedInProviderType,
111116
loggedInProviderName,
112117
isLoggedIn,
113118
lastAuthActivity,
114-
userProfile!
119+
userProfile!,
120+
customData
115121
);
116122
}
117123
}

packages/core/admin-client/src/apps/AppsResources.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import { EJSON } from "bson";
1818
import { Method, StitchAuthRequest } from "mongodb-stitch-core-sdk";
1919
import { AuthProvidersResource } from "../authProviders/AuthProvidersResources";
20+
import { CustomUserDataResource } from "../customUserData/CustomUserDataConfig";
2021
import { DebugResource } from "../debug/DebugResources";
2122
import { FunctionsResource } from "../functions/FunctionsResources";
2223
import { deserialize, jsonProperty } from "../JsonMapper";
@@ -55,6 +56,10 @@ export class AppResource extends BasicResource<App> {
5556
this.adminAuth,
5657
`${this.url}/auth_providers`
5758
);
59+
public readonly customUserData = new CustomUserDataResource(
60+
this.adminAuth,
61+
`${this.url}/custom_user_data`
62+
);
5863
public readonly debug = new DebugResource(
5964
this.adminAuth,
6065
`${this.url}/debug`
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { EJSON } from "bson";
2+
import { Method, StitchAuthRequest } from "mongodb-stitch-core-sdk";
3+
import { jsonProperty, serialize } from "../JsonMapper"
4+
import { BasicResource } from "../Resources"
5+
6+
7+
export class CustomUserConfigData {
8+
constructor(
9+
@jsonProperty("mongo_service_id") public mongoServiceId: string,
10+
@jsonProperty("database_name") public databaseName: string,
11+
@jsonProperty("collection_name") public collectionName: string,
12+
@jsonProperty("user_id_field") public userIdField: string,
13+
@jsonProperty("enabled") public enabled: boolean) {
14+
}
15+
}
16+
17+
export class CustomUserDataResource extends BasicResource<void> {
18+
// POST a new application
19+
// - parameter name: name of the new application
20+
// - parameter defaults: whether or not to enable default values
21+
public create(data: CustomUserConfigData): Promise<void> {
22+
const req = new StitchAuthRequest.Builder()
23+
.withMethod(Method.PATCH)
24+
.withPath(this.url)
25+
.withBody(EJSON.stringify(serialize(data)))
26+
.build();
27+
28+
return this.adminAuth.doAuthenticatedRequest(req).then((_) => { return } );
29+
}
30+
}

0 commit comments

Comments
 (0)