Skip to content

Commit 4cd5d4e

Browse files
committed
clean flow, add WebhookMutator
1 parent 9170da7 commit 4cd5d4e

File tree

10 files changed

+106
-68
lines changed

10 files changed

+106
-68
lines changed

src/lib/OAuthModel.js

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
// @flow
22

3-
import type { Client, Repository, User } from '../types';
3+
import type {
4+
Client,
5+
TokenObject,
6+
User,
7+
UsersRepository,
8+
} from '../types';
49

510
import ouathClients from '../oauthClients.json';
611

712
class OauthModel {
8-
_usersRepository: Repository<User>;
13+
_usersRepository: UsersRepository;
914

10-
constructor(usersRepository: Repository<User>) {
15+
constructor(usersRepository: UsersRepository) {
1116
this._usersRepository = usersRepository;
1217
}
1318

14-
getAccessToken = (bearerToken: string) => {
19+
getAccessToken = (bearerToken: string): ?Object => {
1520
const user = this._usersRepository.getByAccessToken(bearerToken);
1621
if (!user) {
17-
return false;
22+
return null;
1823
}
1924

20-
const userTokenObject = user.accessTokens.find((tokenObject) =>
21-
tokenObject.accessToken === bearerToken,
25+
const userTokenObject = user.accessTokens.find(
26+
(tokenObject: TokenObject): boolean =>
27+
tokenObject.accessToken === bearerToken,
2228
);
2329

2430
return {
@@ -32,11 +38,11 @@ class OauthModel {
3238
client.clientId === clientId && client.clientSecret === clientSecret,
3339
);
3440

35-
getUser = async (username: string, password: string): User => {
36-
return await this._usersRepository.validateLogin(username, password);
37-
};
41+
getUser = async (username: string, password: string): Promise<User> =>
42+
await this._usersRepository.validateLogin(username, password);
43+
3844

39-
saveToken = (tokenObject, client, user) => {
45+
saveToken = (tokenObject: TokenObject, client: Client, user: User): Object => {
4046
this._usersRepository.saveAccessToken(user.id, tokenObject);
4147
return {
4248
accessToken: tokenObject.accessToken,

src/lib/controllers/Controller.js

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1+
// @flow
2+
3+
// todo annotate better
14
export default class Controller {
2-
bad(message) {
3-
return {
4-
data: {message},
5-
status: 400,
6-
};
7-
}
5+
bad = (message: string): Object => ({
6+
data: { message },
7+
status: 400,
8+
});
89

9-
ok(output) {
10-
return {
11-
data: output,
12-
status: 200,
13-
};
14-
}
10+
ok = (output?: Object): Object => ({
11+
data: output,
12+
status: 200,
13+
});
1514
}

src/lib/controllers/UsersController.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// @flow
22

3-
import type { Repository, User, UserCredentials } from '../../types';
3+
import type {
4+
UserCredentials,
5+
UsersRepository,
6+
} from '../../types';
47

58
import basicAuthParser from 'basic-auth-parser';
69
import Controller from './Controller';
@@ -9,17 +12,17 @@ import httpVerb from '../decorators/httpVerb';
912
import route from '../decorators/route';
1013

1114
class UsersController extends Controller {
12-
_usersRepository: Repository<User>;
15+
_usersRepository: UsersRepository;
1316

14-
constructor(usersRepository: Repository<User>) {
17+
constructor(usersRepository: UsersRepository) {
1518
super();
1619
this._usersRepository = usersRepository;
1720
}
1821

1922
@httpVerb('post')
2023
@route('/v1/users')
2124
@anonymous()
22-
async createUser(userCredentials: UserCredentials) {
25+
async createUser(userCredentials: UserCredentials): Promise<Object> {
2326
try {
2427
const isUserNameInUse =
2528
this._usersRepository.isUserNameInUse(userCredentials.username);
@@ -38,7 +41,7 @@ class UsersController extends Controller {
3841
@httpVerb('delete')
3942
@route('/v1/access_tokens/:token')
4043
@anonymous()
41-
async deleteAccessToken(token: string) {
44+
async deleteAccessToken(token: string): Promise<Object> {
4245
try {
4346
const { username, password } = basicAuthParser(this.request.get('authorization'));
4447
const user = await this._usersRepository.validateLogin(username, password);
@@ -54,7 +57,7 @@ class UsersController extends Controller {
5457
@httpVerb('get')
5558
@route('/v1/access_tokens')
5659
@anonymous()
57-
async getAccessTokens() {
60+
async getAccessTokens(): Promise<Object> {
5861
try {
5962
const { username, password } = basicAuthParser(this.request.get('authorization'));
6063
const user = await this._usersRepository.validateLogin(username, password);

src/lib/controllers/WebhookController.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
// @flow
22

3-
import type { Repository, Webhook, WebhookRequestType } from '../../types';
3+
import type {
4+
Repository,
5+
RequestType,
6+
Webhook,
7+
WebhookMutator,
8+
} from '../../types';
49

5-
import settings from '../../settings';
610
import Controller from './Controller';
711
import httpVerb from '../decorators/httpVerb';
812
import route from '../decorators/route';
913

10-
const REQUEST_TYPES: Array<WebhookRequestType> = [
14+
const REQUEST_TYPES: Array<RequestType> = [
1115
'DELETE', 'GET', 'POST', 'PUT',
1216
];
1317

@@ -39,19 +43,19 @@ class WebhookController extends Controller {
3943

4044
@httpVerb('get')
4145
@route('/v1/webhooks')
42-
get() {
46+
getAll(): Object {
4347
return this.ok(this._webhookRepository.getAll());
4448
}
4549

4650
@httpVerb('get')
4751
@route('/v1/webhooks/:webhookId')
48-
getByWebhookId(webhookId: string) {
52+
getById(webhookId: string): Object {
4953
return this.ok(this._webhookRepository.getById(webhookId));
5054
}
5155

5256
@httpVerb('post')
5357
@route('/v1/webhooks')
54-
post(model: Webhook) {
58+
create(model: WebhookMutator): Object {
5559
try {
5660
const validateError = validateWebhookModel(model);
5761
if (validateError) {
@@ -73,8 +77,8 @@ class WebhookController extends Controller {
7377

7478
@httpVerb('delete')
7579
@route('/v1/webhooks/:webhookId')
76-
delete(webhookId: string) {
77-
this._webhookRepository.delete(webhookId);
80+
deleteById(webhookId: string): Object {
81+
this._webhookRepository.deleteById(webhookId);
7882
return this.ok();
7983
}
8084
}

src/lib/decorators/types.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// @flow
2+
13
export type Decorator = (
24
target: Object,
35
name: string,
@@ -8,7 +10,7 @@ export type HttpVerb =
810
'checkout' |
911
'connect' |
1012
'copy' |
11-
'delete' |
13+
'deleteById' |
1214
'head' |
1315
'get' |
1416
'lock' |

src/lib/repository/UsersFileRepository.js

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@ import type { TokenObject, User, UserCredentials } from '../../types';
55
import { FileManager, uuid } from 'spark-protocol';
66
import PasswordHasher from '../PasswordHasher';
77

8-
// todo change class methods style to arrow functions.
98
class UsersFileRepository {
109
_fileManager: FileManager;
1110

1211
constructor(path: string) {
1312
this._fileManager = new FileManager(path);
1413
}
1514

16-
create = async (userCredentials: UserCredentials): User => {
15+
create = async (userCredentials: UserCredentials): Promise<User> => {
1716
const { username, password } = userCredentials;
1817

1918
const salt = await PasswordHasher.generateSalt();
@@ -33,19 +32,16 @@ class UsersFileRepository {
3332
return modelToSave;
3433
};
3534

36-
getAll(): Array<User> {
37-
return this._fileManager.getAllData();
38-
}
35+
getAll = (): Array<User> =>
36+
this._fileManager.getAllData();
3937

40-
getById(id: string): User {
41-
return this._fileManager.getFile(id + '.json');
42-
}
38+
getById = (id: string): User =>
39+
this._fileManager.getFile(`${id}.json`);
4340

44-
getByUsername(username: string) {
45-
return this.getAll().find((user: User) => user.username === username);
46-
}
41+
getByUsername = (username: string): ?User =>
42+
this.getAll().find((user: User): boolean => user.username === username);
4743

48-
async validateLogin(username: string, password: string) {
44+
async validateLogin(username: string, password: string): User {
4945
try {
5046
const user = this.getByUsername(username);
5147
if (!user) {
@@ -70,7 +66,7 @@ class UsersFileRepository {
7066
),
7167
);
7268

73-
deleteAccessToken(user: User, token: string) {
69+
deleteAccessToken = (user: User, token: string) => {
7470
const userToSave = {
7571
...user,
7672
accessTokens: user.accessTokens.filter(
@@ -80,18 +76,18 @@ class UsersFileRepository {
8076
};
8177

8278
this._fileManager.writeFile(`${user.id}.json`, userToSave);
83-
}
79+
};
8480

85-
deleteById(id: string) {
81+
deleteById = (id: string): void =>
8682
this._fileManager.deleteFile(`${id}.json`);
87-
}
83+
8884

8985
isUserNameInUse = (username: string): boolean =>
9086
this.getAll().some((user: User): boolean =>
9187
user.username === username,
9288
);
9389

94-
saveAccessToken(userId: string, tokenObject: TokenObject) {
90+
saveAccessToken = (userId: string, tokenObject: TokenObject) => {
9591
const user = this.getById(userId);
9692
const userToSave = {
9793
...user,

src/lib/repository/WebhookFileRepository.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class WebhookFileRepository {
2525
return modelToSave;
2626
};
2727

28-
delete = (id: string): void =>
28+
deleteById = (id: string): void =>
2929
this._fileManager.deleteFile(`${id}.json`);
3030

3131
getAll = (): Array<Webhook> =>

src/types.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// @flow
2+
13
export type Webhook = {
24
deviceID: string,
35
event: string,
@@ -7,14 +9,32 @@ export type Webhook = {
79
mydevices: boolean,
810
productIdOrSlug: ?string,
911
rejectUnauthorized: boolean,
10-
requestType: string,
12+
requestType: RequestType,
1113
responseTemplate: ?string,
1214
responseTopic: string,
1315
url: string,
1416
};
1517

16-
export type WebhookRequestType = 'DELETE' | 'GET' | 'POST' | 'PUT';
18+
export type WebhookMutator = {
19+
auth?: { Authorization: string },
20+
deviceID?: boolean,
21+
errorResponseTopic?: string,
22+
event: string,
23+
form?: { [key: string]: Object },
24+
headers?:{ [key: string]: string },
25+
json?: { [key: string]: Object },
26+
mydevices?: boolean,
27+
noDefaults?: boolean,
28+
productIdOrSlug?: string,
29+
query?: { [key: string]: Object },
30+
rejectUnauthorized?: boolean,
31+
requestType: RequestType,
32+
responseTemplate?: string,
33+
responseTopic?: string,
34+
url: string,
35+
};
1736

37+
export type RequestType = 'DELETE' | 'GET' | 'POST' | 'PUT';
1838

1939
export type Client = {
2040
clientId: string,
@@ -59,12 +79,21 @@ export type UserCredentials = {
5979

6080
export type Repository<TModel> = {
6181
create: (id: string, model: TModel) => TModel,
62-
delete: (id: string) => void,
82+
deleteById: (id: string) => void,
6383
getAll: () => Array<TModel>,
6484
getById: (id: string) => TModel,
6585
update: (id: string, model: TModel) => TModel,
6686
};
6787

88+
export type UsersRepository = Repository<User> & {
89+
deleteAccessToken: (accessToken: string) => void,
90+
getByAccessToken: (accessToken: string) => User,
91+
getByUsername: (username: string) => ?User,
92+
isUserNameInUse: (username: string) => boolean,
93+
saveAccessToken: (accessToken: string) => void,
94+
validateLogin: (username: string, password: string) => User,
95+
};
96+
6897
export type Settings = {
6998
accessTokenLifetime: number,
7099
baseUrl: string,

test/UsersController.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// @flow
22

3-
import type { TokenObject } from '../src/types';
3+
import type { TokenObject, UserCredentials } from '../src/types';
44

55
import test from 'ava';
66
import request from 'supertest-as-promised';
77
import ouathClients from '../src/oauthClients.json';
88
import app from './testApp';
99
import settings from './settings';
1010

11-
const USER_CREDENTIALS = {
11+
const USER_CREDENTIALS: UserCredentials = {
1212
password: 'password',
1313
username: '[email protected]',
1414
};
@@ -67,7 +67,7 @@ test.serial('should return all access tokens for the user', async t => {
6767
});
6868

6969

70-
test.serial('should delete access token for the user', async t => {
70+
test.serial('should deleteById access token for the user', async t => {
7171
const deleteResponse = await request(app)
7272
.delete(`/v1/access_tokens/${userToken}`)
7373
.auth(USER_CREDENTIALS.username, USER_CREDENTIALS.password);

0 commit comments

Comments
 (0)