Skip to content

Commit b681186

Browse files
authored
Add auth-triggered functions (#54)
1 parent b066ce1 commit b681186

File tree

4 files changed

+171
-0
lines changed

4 files changed

+171
-0
lines changed

src/builders/auth-builder.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { FunctionBuilder, TriggerDefinition, TriggerAnnotated } from '../builder';
2+
import { Event } from '../event';
3+
import { FirebaseEnv } from '../env';
4+
5+
export interface UserInfo {
6+
uid: string;
7+
email: string;
8+
displayName?: string;
9+
photoURL?: string;
10+
providerId: string;
11+
}
12+
13+
export interface AuthEventData {
14+
uid: string;
15+
email: string;
16+
emailVerified: boolean;
17+
displayName?: string;
18+
photoURL?: string;
19+
disabled: boolean;
20+
metadata: {
21+
createdAt: string;
22+
lastSignedInAt: string;
23+
};
24+
providerData?: Array<UserInfo>;
25+
}
26+
27+
export default class AuthBuilder extends FunctionBuilder {
28+
29+
constructor(env: FirebaseEnv) {
30+
super(env);
31+
}
32+
33+
onCreate(
34+
handler: (event: Event<AuthEventData>) => PromiseLike<any>
35+
): TriggerAnnotated & ((event: Event<AuthEventData>) => PromiseLike<any> | any) {
36+
return this._makeHandler(handler, 'user.create');
37+
}
38+
39+
onDelete(
40+
handler: (event: Event<AuthEventData>) => PromiseLike<any>
41+
): TriggerAnnotated & ((event: Event<AuthEventData>) => PromiseLike<any> | any) {
42+
return this._makeHandler(handler, 'user.delete');
43+
}
44+
45+
protected _toTrigger(event: string): TriggerDefinition {
46+
return {
47+
eventTrigger: {
48+
eventType: 'providers/firebase.auth/eventTypes/' + event,
49+
resource: 'projects/' + process.env.GCLOUD_PROJECT,
50+
},
51+
};
52+
}
53+
}

src/functions.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as firebase from 'firebase';
22

33
import Apps from './apps';
44
import { FirebaseEnv, FirebaseEnvData } from './env';
5+
import AuthBuilder from './builders/auth-builder';
56
import DatabaseBuilder from './builders/database-builder';
67
import HttpsBuilder from './builders/https-builder';
78
import PubsubBuilder from './builders/pubsub-builder';
@@ -16,6 +17,13 @@ export default class FirebaseFunctions {
1617
this._apps = apps;
1718
}
1819

20+
/**
21+
* Create a builder for a Firebase Authentication function.
22+
*/
23+
auth(): AuthBuilder {
24+
return new AuthBuilder(this._env);
25+
}
26+
1927
/**
2028
* Create a builder for a Firebase Realtime Database function.
2129
*/

test/builders/auth-builder.spec.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import AuthBuilder from '../../src/builders/auth-builder';
2+
import { expect as expect } from 'chai';
3+
import { FakeEnv } from '../support/helpers';
4+
import { AuthEventData } from '../../src/builders/auth-builder';
5+
import { Event } from '../../src/event';
6+
import * as Promise from 'bluebird';
7+
8+
describe('AuthBuilder', () => {
9+
let subject: AuthBuilder;
10+
let handler: (e: Event<AuthEventData>) => PromiseLike<any> | any;
11+
let env: FakeEnv;
12+
13+
beforeEach(() => {
14+
env = new FakeEnv();
15+
subject = new AuthBuilder(env);
16+
handler = () => {
17+
return true;
18+
};
19+
process.env.GCLOUD_PROJECT = 'project1';
20+
});
21+
22+
afterEach(() => {
23+
delete process.env.GCLOUD_PROJECT;
24+
});
25+
26+
describe('#onCreate', () => {
27+
it('should return a TriggerDefinition with appropriate values', () => {
28+
let result = subject.onCreate(handler);
29+
expect(result.__trigger).to.deep.equal({
30+
eventTrigger: {
31+
eventType: 'providers/firebase.auth/eventTypes/user.create',
32+
resource: 'projects/project1',
33+
},
34+
});
35+
});
36+
});
37+
38+
describe('#onDelete', () => {
39+
it('should return a TriggerDefinition with appropriate values', () => {
40+
let result = subject.onDelete(handler);
41+
expect(result.__trigger).to.deep.equal({
42+
eventTrigger: {
43+
eventType: 'providers/firebase.auth/eventTypes/user.delete',
44+
resource: 'projects/project1',
45+
},
46+
});
47+
});
48+
});
49+
50+
describe('#_dataConstructor', () => {
51+
it('should handle an event with the appropriate fields', () => {
52+
let func = subject.onCreate((ev: Event<AuthEventData>) => {
53+
return Promise.resolve(ev.data);
54+
});
55+
env.makeReady();
56+
57+
// The event data delivered over the wire will be the JSON for a UserRecord:
58+
// https://firebase.google.com/docs/auth/admin/manage-users#retrieve_user_data
59+
let event = {
60+
eventId: 'f2e2f0bf-2e47-4d92-b009-e7a375ecbd3e',
61+
eventType: 'providers/firebase.auth/eventTypes/user.create',
62+
resource: 'projects/myUnitTestProject',
63+
notSupported: {
64+
},
65+
data: {
66+
uid: 'abcde12345',
67+
email: 'foo@bar.baz',
68+
emailVerified: false,
69+
displayName: 'My Display Name',
70+
photoURL: 'bar.baz/foo.jpg',
71+
disabled: false,
72+
metadata: {
73+
createdAt: '2016-12-15T19:37:37.059Z',
74+
lastSignedInAt: '2017-01-01T00:00:00.000Z',
75+
},
76+
providerData: [{
77+
uid: 'g-abcde12345',
78+
email: 'foo@gmail.com',
79+
displayName: 'My Google Provider Display Name',
80+
photoURL: 'googleusercontent.com/foo.jpg',
81+
providerId: 'google.com',
82+
}],
83+
},
84+
};
85+
86+
return expect(func(event)).to.eventually.deep.equal(event.data);
87+
});
88+
89+
// This isn't expected to happen in production, but if it does we should
90+
// handle it gracefully.
91+
it('should tolerate missing fields in the payload', () => {
92+
let func = subject.onCreate((ev: Event<AuthEventData>) => {
93+
return Promise.resolve(ev.data);
94+
});
95+
env.makeReady();
96+
97+
let event = {
98+
data: {
99+
uid: 'abcde12345',
100+
metadata: {
101+
createdAt: '2016-12-15T19:37:37.059Z',
102+
},
103+
},
104+
};
105+
106+
return expect(func(<Event<AuthEventData>>event)).to.eventually.deep.equal(event.data);
107+
});
108+
});
109+
});

test/index.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import './builder.spec';
1212
import './env.spec';
1313
import './event.spec';
1414
import './credential.spec';
15+
import './builders/auth-builder.spec';
1516
import './builders/https-builder.spec';
1617
import './builders/pubsub-builder.spec';
1718
import './builders/storage-builder.spec';

0 commit comments

Comments
 (0)