Skip to content

Commit 0b307bc

Browse files
committed
Improves AdapterLoader, enforces configuraiton on Adapters
1 parent 8dc37b9 commit 0b307bc

17 files changed

+176
-109
lines changed

spec/AdapterLoader.spec.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
var loadAdapter = require("../src/Adapters/AdapterLoader").loadAdapter;
33
var FilesAdapter = require("../src/Adapters/Files/FilesAdapter").default;
44

5-
describe("AdaptableController", ()=>{
5+
describe("AdapterLoader", ()=>{
66

77
it("should instantiate an adapter from string in object", (done) => {
88
var adapterPath = require('path').resolve("./spec/MockAdapter");
99

1010
var adapter = loadAdapter({
1111
adapter: adapterPath,
12-
key: "value",
13-
foo: "bar"
12+
options: {
13+
key: "value",
14+
foo: "bar"
15+
}
1416
});
1517

1618
expect(adapter instanceof Object).toBe(true);
@@ -24,7 +26,6 @@ describe("AdaptableController", ()=>{
2426
var adapter = loadAdapter(adapterPath);
2527

2628
expect(adapter instanceof Object).toBe(true);
27-
expect(adapter.options).toBe(adapterPath);
2829
done();
2930
});
3031

@@ -65,4 +66,22 @@ describe("AdaptableController", ()=>{
6566
expect(adapter).toBe(originalAdapter);
6667
done();
6768
});
69+
70+
it("should fail loading an improperly configured adapter", (done) => {
71+
var Adapter = function(options) {
72+
if (!options.foo) {
73+
throw "foo is required for that adapter";
74+
}
75+
}
76+
var adapterOptions = {
77+
param: "key",
78+
doSomething: function() {}
79+
};
80+
81+
expect(() => {
82+
var adapter = loadAdapter(adapterOptions, Adapter);
83+
expect(adapter).toEqual(adapterOptions);
84+
}).not.toThrow("foo is required for that adapter");
85+
done();
86+
});
6887
});

spec/MockAdapter.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module.exports = function(options) {
2-
this.options = options;
3-
}
2+
return {
3+
options: options
4+
};
5+
};

spec/MockEmailAdapterWithOptions.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module.exports = options => {
33
throw "Options were not provided"
44
}
55
return {
6-
sendVerificationEmail: () => Promise.resolve()
6+
sendVerificationEmail: () => Promise.resolve(),
7+
sendMail: () => Promise.resolve()
78
}
89
}

spec/OneSignalPushAdapter.spec.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11

22
var OneSignalPushAdapter = require('../src/Adapters/Push/OneSignalPushAdapter');
33
var classifyInstallations = require('../src/Adapters/Push/PushAdapterUtils').classifyInstallations;
4+
5+
// Make mock config
6+
var pushConfig = {
7+
oneSignalAppId:"APP ID",
8+
oneSignalApiKey:"API KEY"
9+
};
10+
411
describe('OneSignalPushAdapter', () => {
512
it('can be initialized', (done) => {
6-
// Make mock config
7-
var pushConfig = {
8-
oneSignalAppId:"APP ID",
9-
oneSignalApiKey:"API KEY"
10-
};
1113

1214
var oneSignalPushAdapter = new OneSignalPushAdapter(pushConfig);
1315

@@ -17,9 +19,17 @@ describe('OneSignalPushAdapter', () => {
1719
expect(senderMap.android instanceof Function).toBe(true);
1820
done();
1921
});
22+
23+
it('cannt be initialized if options are missing', (done) => {
24+
25+
expect(() => {
26+
new OneSignalPushAdapter();
27+
}).toThrow("Trying to initialiazed OneSignalPushAdapter without oneSignalAppId or oneSignalApiKey");
28+
done();
29+
});
2030

2131
it('can get valid push types', (done) => {
22-
var oneSignalPushAdapter = new OneSignalPushAdapter();
32+
var oneSignalPushAdapter = new OneSignalPushAdapter(pushConfig);
2333

2434
expect(oneSignalPushAdapter.getValidPushTypes()).toEqual(['ios', 'android']);
2535
done();
@@ -56,7 +66,7 @@ describe('OneSignalPushAdapter', () => {
5666

5767

5868
it('can send push notifications', (done) => {
59-
var oneSignalPushAdapter = new OneSignalPushAdapter();
69+
var oneSignalPushAdapter = new OneSignalPushAdapter(pushConfig);
6070

6171
// Mock android ios senders
6272
var androidSender = jasmine.createSpy('send')
@@ -108,7 +118,7 @@ describe('OneSignalPushAdapter', () => {
108118
});
109119

110120
it("can send iOS notifications", (done) => {
111-
var oneSignalPushAdapter = new OneSignalPushAdapter();
121+
var oneSignalPushAdapter = new OneSignalPushAdapter(pushConfig);
112122
var sendToOneSignal = jasmine.createSpy('sendToOneSignal');
113123
oneSignalPushAdapter.sendToOneSignal = sendToOneSignal;
114124

@@ -135,7 +145,7 @@ describe('OneSignalPushAdapter', () => {
135145
});
136146

137147
it("can send Android notifications", (done) => {
138-
var oneSignalPushAdapter = new OneSignalPushAdapter();
148+
var oneSignalPushAdapter = new OneSignalPushAdapter(pushConfig);
139149
var sendToOneSignal = jasmine.createSpy('sendToOneSignal');
140150
oneSignalPushAdapter.sendToOneSignal = sendToOneSignal;
141151

@@ -157,10 +167,7 @@ describe('OneSignalPushAdapter', () => {
157167
});
158168

159169
it("can post the correct data", (done) => {
160-
var pushConfig = {
161-
oneSignalAppId:"APP ID",
162-
oneSignalApiKey:"API KEY"
163-
};
170+
164171
var oneSignalPushAdapter = new OneSignalPushAdapter(pushConfig);
165172

166173
var write = jasmine.createSpy('write');

spec/ParseUser.spec.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ describe('Parse.User testing', () => {
5151

5252
it('sends verification email if email verification is enabled', done => {
5353
var emailAdapter = {
54-
sendVerificationEmail: () => Promise.resolve()
54+
sendVerificationEmail: () => Promise.resolve(),
55+
sendMail: () => Promise.resolve()
5556
}
5657
setServerConfiguration({
5758
serverURL: 'http://localhost:8378/1',
@@ -89,7 +90,8 @@ describe('Parse.User testing', () => {
8990

9091
it('does not send verification email if email verification is disabled', done => {
9192
var emailAdapter = {
92-
sendVerificationEmail: () => Promise.resolve()
93+
sendVerificationEmail: () => Promise.resolve(),
94+
sendMail: () => Promise.resolve()
9395
}
9496
setServerConfiguration({
9597
serverURL: 'http://localhost:8378/1',
@@ -131,7 +133,8 @@ describe('Parse.User testing', () => {
131133
expect(options.appName).toEqual('emailing app');
132134
expect(options.user.get('email')).toEqual('[email protected]');
133135
done();
134-
}
136+
},
137+
sendMail: () => {}
135138
}
136139
setServerConfiguration({
137140
serverURL: 'http://localhost:8378/1',
@@ -175,7 +178,8 @@ describe('Parse.User testing', () => {
175178
done();
176179
});
177180
});
178-
}
181+
},
182+
sendMail: () => {}
179183
}
180184
setServerConfiguration({
181185
serverURL: 'http://localhost:8378/1',
@@ -232,7 +236,8 @@ describe('Parse.User testing', () => {
232236
done();
233237
});
234238
});
235-
}
239+
},
240+
sendMail: () => {}
236241
}
237242
setServerConfiguration({
238243
serverURL: 'http://localhost:8378/1',

src/Adapters/AdapterLoader.js

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,43 @@
1-
export function loadAdapter(options, defaultAdapter) {
2-
let adapter;
1+
export function loadAdapter(adapter, defaultAdapter, options) {
32

4-
// We have options and options have adapter key
5-
if (options) {
6-
// Pass an adapter as a module name, a function or an instance
7-
if (typeof options == "string" || typeof options == "function" || options.constructor != Object) {
8-
adapter = options;
3+
if (!adapter)
4+
{
5+
if (!defaultAdapter) {
6+
return options;
97
}
10-
if (options.adapter) {
11-
adapter = options.adapter;
8+
// Load from the default adapter when no adapter is set
9+
return loadAdapter(defaultAdapter, undefined, options);
10+
} else if (typeof adapter === "function") {
11+
try {
12+
return adapter(options);
13+
} catch(e) {
14+
var Adapter = adapter;
15+
return new Adapter(options);
1216
}
13-
}
14-
15-
if (!adapter) {
16-
adapter = defaultAdapter;
17-
}
18-
19-
// This is a string, require the module
20-
if (typeof adapter === "string") {
17+
} else if (typeof adapter === "string") {
2118
adapter = require(adapter);
2219
// If it's define as a module, get the default
2320
if (adapter.default) {
2421
adapter = adapter.default;
2522
}
23+
24+
return loadAdapter(adapter, undefined, options);
25+
} else if (adapter.module) {
26+
return loadAdapter(adapter.module, undefined, adapter.options);
27+
} else if (adapter.class) {
28+
return loadAdapter(adapter.class, undefined, adapter.options);
29+
} else if (adapter.adapter) {
30+
return loadAdapter(adapter.adapter, undefined, adapter.options);
31+
} else {
32+
// Try to load the defaultAdapter with the options
33+
// The default adapter should throw if the options are
34+
// incompatible
35+
try {
36+
return loadAdapter(defaultAdapter, undefined, adapter);
37+
} catch (e) {};
2638
}
27-
// From there it's either a function or an object
28-
// if it's an function, instanciate and pass the options
29-
if (typeof adapter === "function") {
30-
var Adapter = adapter;
31-
adapter = new Adapter(options);
32-
}
33-
return adapter;
39+
// return the adapter as is as it's unusable otherwise
40+
return adapter;
3441
}
3542

36-
module.exports = { loadAdapter }
43+
export default loadAdapter;

src/Adapters/Email/MailAdapter.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export class MailAdapter {
2+
sendVerificationEmail(options) {}
3+
sendMail(options) {}
4+
}
5+
6+
export default MailAdapter;

src/Adapters/Email/SimpleMailgunAdapter.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ let SimpleMailgunAdapter = mailgunOptions => {
66
}
77
let mailgun = Mailgun(mailgunOptions);
88

9-
let sendMail = (to, subject, text) => {
9+
let sendMail = ({to, subject, text}) => {
1010
let data = {
1111
from: mailgunOptions.fromAddress,
1212
to: to,
@@ -24,16 +24,21 @@ let SimpleMailgunAdapter = mailgunOptions => {
2424
});
2525
}
2626

27-
return {
27+
return Object.freeze({
2828
sendVerificationEmail: ({ link, user, appName, }) => {
2929
let verifyMessage =
3030
"Hi,\n\n" +
3131
"You are being asked to confirm the e-mail address " + user.email + " with " + appName + "\n\n" +
3232
"" +
3333
"Click here to confirm it:\n" + link;
34-
return sendMail(user.email, 'Please verify your e-mail for ' + appName, verifyMessage);
35-
}
36-
}
34+
return sendMail({
35+
to:user.email,
36+
subject: 'Please verify your e-mail for ' + appName,
37+
text: verifyMessage
38+
});
39+
},
40+
sendMail: sendMail
41+
});
3742
}
3843

3944
module.exports = SimpleMailgunAdapter

src/Adapters/Files/S3Adapter.js

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,38 @@
44

55
import * as AWS from 'aws-sdk';
66
import { FilesAdapter } from './FilesAdapter';
7+
import requiredParameter from '../../requiredParameter';
78

89
const DEFAULT_S3_REGION = "us-east-1";
910

11+
function parseS3AdapterOptions(...options) {
12+
if (options.length === 1 && typeof options[0] == "object") {
13+
return options;
14+
}
15+
16+
const additionalOptions = options[3] || {};
17+
18+
return {
19+
accessKey: options[0],
20+
secretKey: options[1],
21+
bucket: options[2],
22+
region: additionalOptions.region
23+
}
24+
}
25+
1026
export class S3Adapter extends FilesAdapter {
1127
// Creates an S3 session.
1228
// Providing AWS access and secret keys is mandatory
1329
// Region and bucket will use sane defaults if omitted
1430
constructor(
15-
accessKey,
16-
secretKey,
17-
bucket,
18-
{ region = DEFAULT_S3_REGION,
19-
bucketPrefix = '',
20-
directAccess = false } = {}
21-
) {
31+
accessKey = requiredParameter('S3Adapter requires an accessKey'),
32+
secretKey = requiredParameter('S3Adapter requires a secretKey'),
33+
bucket,
34+
{ region = DEFAULT_S3_REGION,
35+
bucketPrefix = '',
36+
directAccess = false } = {}) {
2237
super();
23-
38+
2439
this._region = region;
2540
this._bucket = bucket;
2641
this._bucketPrefix = bucketPrefix;

src/Adapters/Logger/FileLoggerAdapter.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,12 @@ let _verifyTransports = ({infoLogger, errorLogger, logsFolder}) => {
9999
}
100100

101101
export class FileLoggerAdapter extends LoggerAdapter {
102-
constructor(options = {}) {
102+
constructor(options) {
103103
super();
104-
104+
if (options && !options.logsFolder) {
105+
throw "FileLoggerAdapter requires logsFolder";
106+
}
107+
options = options || {};
105108
this._logsFolder = options.logsFolder || LOGS_FOLDER;
106109

107110
// check logs folder exists

0 commit comments

Comments
 (0)