Skip to content

Refactor and deduplicate logic in Users/Sessions Routers. #375

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/Routers/InstallationsRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ export class InstallationsRouter extends ClassesRouter {
}

getExpressRouter() {
var router = new PromiseRouter();
router.route('GET','/installations', (req) => { return this.handleFind(req); });
router.route('GET','/installations/:objectId', (req) => { return this.handleGet(req); });
router.route('POST','/installations', (req) => { return this.handleCreate(req); });
router.route('PUT','/installations/:objectId', (req) => { return this.handleUpdate(req); });
router.route('DELETE','/installations/:objectId', (req) => { return this.handleDelete(req); });
let router = new PromiseRouter();
router.route('GET','/installations', req => { return this.handleFind(req); });
router.route('GET','/installations/:objectId', req => { return this.handleGet(req); });
router.route('POST','/installations', req => { return this.handleCreate(req); });
router.route('PUT','/installations/:objectId', req => { return this.handleUpdate(req); });
router.route('DELETE','/installations/:objectId', req => { return this.handleDelete(req); });
return router;
}
}
Expand Down
63 changes: 63 additions & 0 deletions src/Routers/SessionsRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

import ClassesRouter from './ClassesRouter';
import PromiseRouter from '../PromiseRouter';
import rest from '../rest';
import Auth from '../Auth';

export class SessionsRouter extends ClassesRouter {
handleFind(req) {
req.params.className = '_Session';
return super.handleFind(req);
}

handleGet(req) {
req.params.className = '_Session';
return super.handleGet(req);
}

handleCreate(req) {
req.params.className = '_Session';
return super.handleCreate(req);
}

handleUpdate(req) {
req.params.className = '_Session';
return super.handleUpdate(req);
}

handleDelete(req) {
req.params.className = '_Session';
return super.handleDelete(req);
}

handleMe(req) {
// TODO: Verify correct behavior
if (!req.info || !req.info.sessionToken) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN,
'Session token required.');
}
return rest.find(req.config, Auth.master(req.config), '_Session', { _session_token: req.info.sessionToken })
.then((response) => {
if (!response.results || response.results.length == 0) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN,
'Session token not found.');
}
return {
response: response.results[0]
};
});
}

getExpressRouter() {
let router = new PromiseRouter();
router.route('GET','/sessions/me', req => { return this.handleMe(req); });
router.route('GET', '/sessions', req => { return this.handleFind(req); });
router.route('GET', '/sessions/:objectId', req => { return this.handleGet(req); });
router.route('POST', '/sessions', req => { return this.handleCreate(req); });
router.route('PUT', '/sessions/:objectId', req => { return this.handleUpdate(req); });
router.route('DELETE', '/sessions/:objectId', req => { return this.handleDelete(req); });
return router;
}
}

export default SessionsRouter;
163 changes: 163 additions & 0 deletions src/Routers/UsersRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// These methods handle the User-related routes.

import hat from 'hat';
import deepcopy from 'deepcopy';

import ClassesRouter from './ClassesRouter';
import PromiseRouter from '../PromiseRouter';
import rest from '../rest';
import Auth from '../Auth';
import passwordCrypto from '../password';
import RestWrite from '../RestWrite';

const rack = hat.rack();

export class UsersRouter extends ClassesRouter {
handleFind(req) {
req.params.className = '_User';
return super.handleFind(req);
}

handleGet(req) {
req.params.className = '_User';
return super.handleGet(req);
}

handleCreate(req) {
let data = deepcopy(req.body);
data.installationId = req.info.installationId;
req.body = data;
req.params.className = '_User';
return super.handleCreate(req);
}

handleUpdate(req) {
req.params.className = '_User';
return super.handleUpdate(req);
}

handleDelete(req) {
req.params.className = '_User';
return super.handleDelete(req);
}

handleMe(req) {
if (!req.info || !req.info.sessionToken) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
'Object not found.');
}
return rest.find(req.config, Auth.master(req.config), '_Session',
{ _session_token: req.info.sessionToken },
{ include: 'user' })
.then((response) => {
if (!response.results ||
response.results.length == 0 ||
!response.results[0].user) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
'Object not found.');
} else {
let user = response.results[0].user;
return { response: user };
}
});
}

handleLogIn(req) {
// Use query parameters instead if provided in url
if (!req.body.username && req.query.username) {
req.body = req.query;
}

// TODO: use the right error codes / descriptions.
if (!req.body.username) {
throw new Parse.Error(Parse.Error.USERNAME_MISSING, 'username is required.');
}
if (!req.body.password) {
throw new Parse.Error(Parse.Error.PASSWORD_MISSING, 'password is required.');
}

let user;
return req.database.find('_User', { username: req.body.username })
.then((results) => {
if (!results.length) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
}
user = results[0];
return passwordCrypto.compare(req.body.password, user.password);
}).then((correct) => {
if (!correct) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Invalid username/password.');
}

let token = 'r:' + rack();
user.sessionToken = token;
delete user.password;

req.config.filesController.expandFilesInObject(req.config, user);

let expiresAt = new Date();
expiresAt.setFullYear(expiresAt.getFullYear() + 1);

let sessionData = {
sessionToken: token,
user: {
__type: 'Pointer',
className: '_User',
objectId: user.objectId
},
createdWith: {
'action': 'login',
'authProvider': 'password'
},
restricted: false,
expiresAt: Parse._encode(expiresAt)
};

if (req.info.installationId) {
sessionData.installationId = req.info.installationId
}

let create = new RestWrite(req.config, Auth.master(req.config), '_Session', null, sessionData);
return create.execute();
}).then(() => {
return { response: user };
});
}

handleLogOut(req) {
let success = {response: {}};
if (req.info && req.info.sessionToken) {
return rest.find(req.config, Auth.master(req.config), '_Session',
{ _session_token: req.info.sessionToken }
).then((records) => {
if (records.results && records.results.length) {
return rest.del(req.config, Auth.master(req.config), '_Session',
records.results[0].objectId
).then(() => {
return Promise.resolve(success);
});
}
return Promise.resolve(success);
});
}
return Promise.resolve(success);
}

getExpressRouter() {
let router = new PromiseRouter();
router.route('GET', '/users', req => { return this.handleFind(req); });
router.route('POST', '/users', req => { return this.handleCreate(req); });
router.route('GET', '/users/:objectId', req => { return this.handleGet(req); });
router.route('PUT', '/users/:objectId', req => { return this.handleUpdate(req); });
router.route('DELETE', '/users/:objectId', req => { return this.handleDelete(req); });
router.route('GET', '/users/me', req => { return this.handleMe(req); });
router.route('GET', '/login', req => { return this.handleLogIn(req); });
router.route('POST', '/logout', req => { return this.handleLogOut(req); });
router.route('POST', '/requestPasswordReset', () => {
throw new Parse.Error(Parse.Error.COMMAND_UNAVAILABLE, 'This path is not implemented yet.');
});
return router;
}
}

export default UsersRouter;
6 changes: 4 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { PushController } from './Controllers/PushController';

import { ClassesRouter } from './Routers/ClassesRouter';
import { InstallationsRouter } from './Routers/InstallationsRouter';
import { UsersRouter } from './Routers/UsersRouter';
import { SessionsRouter } from './Routers/SessionsRouter';

// Mutate the Parse object to add the Cloud Code handlers
addParseCloud();
Expand Down Expand Up @@ -129,8 +131,8 @@ function ParseServer(args) {

let routers = [
new ClassesRouter().getExpressRouter(),
require('./users'),
require('./sessions'),
new UsersRouter().getExpressRouter(),
new SessionsRouter().getExpressRouter(),
require('./roles'),
require('./analytics'),
new InstallationsRouter().getExpressRouter(),
Expand Down
98 changes: 0 additions & 98 deletions src/sessions.js

This file was deleted.

Loading