Skip to content

Commit

Permalink
[update] Add user panel
Browse files Browse the repository at this point in the history
  • Loading branch information
imouto1994 committed Apr 22, 2016
1 parent 8d4ab25 commit 627b545
Show file tree
Hide file tree
Showing 19 changed files with 226 additions and 27 deletions.
1 change: 1 addition & 0 deletions .istanbul.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
instrumentation:
root: src
excludes: ['**/api/helpers/**/*.js', '**/api/controllers/**/*.js', '**/api/models/Model.js']
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
"redux-router": "1.0.0-beta7",
"redux-thunk": "1.0.3",
"sendgrid": "2.0.0",
"serialize-javascript": "^1.2.0",
"serve-favicon": "2.3.0",
"sharp": "0.12.2",
"slick-carousel": "1.5.9",
Expand Down
3 changes: 3 additions & 0 deletions src/api/config/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const snapshotUpload = multer({ storage: StorageHelper.getSnapshotStorage() });
export default (app) => {
// Authentication
app.get('/user', UserController.request.getUser);
app.get('/users', Authorisation.requireAdmin, UserController.request.getUsers);
app.get('/user/me', Authorisation.checkUser, UserController.request.me);
app.get('/user/userInfo', Authorisation.requireUser, UserController.request.info);
app.get('/user/adminInfo', Authorisation.requireAdmin, UserController.request.info);
Expand All @@ -20,6 +21,8 @@ export default (app) => {
app.post('/user/resetPassword', UserController.request.resetPassword);
app.post('/user/logout', Authorisation.requireUser, UserController.request.logout);

app.delete('/user/:userId', Authorisation.requireAdmin, UserController.request.deleteUser);

// Model
app.get('/model', ModelController.request.getModels);
app.get('/model/:modelId', ModelController.request.getModel);
Expand Down
12 changes: 9 additions & 3 deletions src/api/controllers/ModelController.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import JSZip from 'jszip';
import fs from 'fs';
import path from 'path';

import { ClientError, Constants, StringHelper } from 'common';
import { MongooseHelper, ResponseHelper, TextureHelper, ModelHelper } from 'api/helpers';
import { Model, User } from 'api/models';
import ClientError from 'common/errors/ClientError';
import Constants from 'common/constants';
import StringHelper from 'common/string';
import MongooseHelper from 'api/helpers/mongoose';
import ResponseHelper from 'api/helpers/response';
import TextureHelper from 'api/helpers/texture';
import ModelHelper from 'api/helpers/model';
import Model from 'api/models/Model';
import User from 'api/models/User';

const DEBUG_ENV = 'UserController';

Expand Down
17 changes: 17 additions & 0 deletions src/api/controllers/UserController.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ UserController.request.getUser = function (req, res) {
ResponseHelper.handle(UserController.promise.getUser, req, res, DEBUG_ENV);
};

UserController.request.getUsers = function (req, res) {
ResponseHelper.handle(UserController.promise.getUsers, req, res, DEBUG_ENV);
};

UserController.request.me = function (req, res) {
ResponseHelper.handle(UserController.promise.me, req, res, DEBUG_ENV);
};
Expand Down Expand Up @@ -66,13 +70,21 @@ UserController.request.changePassword = function (req, res) {
ResponseHelper.handle(UserController.promise.changePassword, req, res, DEBUG_ENV);
};

UserController.request.deleteUser = function (req, res) {
ResponseHelper.handle(UserController.promise.deleteUser, req, res, DEBUG_ENV);
};

// ---------------------------------------------------------------------------- //

UserController.promise.getUser = function (req) {
const { query, options } = req.query;
return User.findUser(query, options);
};

UserController.promise.getUsers = function () {
return Promise.resolve(User.find({}).exec());
};

UserController.promise.me = function (req, needAuthorized = false) {
if (needAuthorized && !req.user) {
return Promise.reject(new ClientError(Constants.ERROR_TOKEN_UNVERIFIED));
Expand Down Expand Up @@ -209,4 +221,9 @@ UserController.promise.changePassword = function (req) {
});
};

UserController.promise.deleteUser = function (req) {
const { userId } = req.params;
return Promise.resolve(User.remove({ _id: userId }).exec());
};

export default UserController;
4 changes: 2 additions & 2 deletions src/api/models/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import mongoose, { Schema } from 'mongoose';
import _ from 'lodash';
import Promise from 'bluebird';

import { MongooseHelper } from 'api/helpers';
import { Constants } from 'common';
import MongooseHelper from 'api/helpers/mongoose';
import Constants from 'common/constants';

const ObjectId = Schema.Types.ObjectId;

Expand Down
19 changes: 18 additions & 1 deletion src/webapp/actions/UserActions.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {
REQ_GET_USERS,
REQ_GET_USER,
REQ_GET_USER_ME,
REQ_GET_USER_USER_INFO,
REQ_GET_USER_ADMIN_INFO,
REQ_POST_USER_REGISTER,
REQ_POST_USER_LOGIN,
REQ_POST_USER_LOGOUT,
REQ_POST_USER_RESET_PASSWORD
REQ_POST_USER_RESET_PASSWORD,
REQ_DEL_USER
} from './types';

export default {
Expand All @@ -21,6 +23,13 @@ export default {
};
},

getUsers() {
return {
type: REQ_GET_USERS,
promise: apiClient => apiClient.get('/userS')
};
},

me() {
return {
type: REQ_GET_USER_ME,
Expand Down Expand Up @@ -86,5 +95,13 @@ export default {
}
})
};
},

deleteUser(userId) {
return {
type: REQ_DEL_USER,
promise: apiClient => apiClient.delete(`/user/${userId}`),
payload: userId
};
}
};
5 changes: 4 additions & 1 deletion src/webapp/actions/types/UserActionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const normalTypes = {
};

const promiseTypes = {
REQ_GET_USERS: null,
REQ_GET_USER: null,
REQ_GET_USER_ME: null,
REQ_GET_USER_USER_INFO: null,
Expand All @@ -13,7 +14,9 @@ const promiseTypes = {
REQ_POST_USER_REGISTER: null,
REQ_POST_USER_LOGIN: null,
REQ_POST_USER_LOGOUT: null,
REQ_POST_USER_RESET_PASSWORD: null
REQ_POST_USER_RESET_PASSWORD: null,

REQ_DEL_USER: null
};

export default TypeHelper.combineTypes(normalTypes, promiseTypes);
12 changes: 9 additions & 3 deletions src/webapp/components/_containers/AdminContainer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { Link } from 'react-router';

const CLASS_NAME = 'cb-ctn-admin';

Expand All @@ -11,12 +12,17 @@ class AdminContainer extends React.Component {
const { children } = this.props;

return (
<div className={ CLASS_NAME }>
<div className={ CLASS_NAME } style={ { padding: '5px 10px' } }>
<div className="row">
<div className="col-sm-6">
<button className="btn btn-success btn-block cb-margin-top-10px cb-margin-bottom-10px">
<Link to="/admin" className="btn btn-success btn-block cb-margin-top-10px cb-margin-bottom-10px">
MONITOR MODELS
</button>
</Link>
</div>
<div className="col-sm-6">
<Link to="/admin/user" className="btn btn-success btn-block cb-margin-top-10px cb-margin-bottom-10px">
MONITOR USERS
</Link>
</div>
</div>
{ children }
Expand Down
77 changes: 77 additions & 0 deletions src/webapp/components/_containers/AdminUsersContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react';
import Immutable from 'immutable';
import { connect } from 'react-redux';

import { UserActions } from 'webapp/actions';

const CLASS_NAME = 'cb-ctn-admin-users';

class AdminUsersContainer extends React.Component {
static fetchData({ dispatch }) {
return dispatch(UserActions.getUsers());
}

static propTypes = {
users: React.PropTypes.instanceOf(Immutable.List),
dispatch: React.PropTypes.func.isRequired
};

_onDeleteButtonClick = (user) => {
const { dispatch } = this.props;
dispatch(UserActions.deleteUser(user.get('_id')));
};

render() {
return (
<div className={ CLASS_NAME }>
{ this.renderUsersTable() }
</div>
);
}

renderUsersTable() {
const { users } = this.props;

return (
<table className="table table-striped table-bordered">
<thead>
<tr>
<th>User ID</th>
<th>User Name</th>
<th>User Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{
users.map(this.renderUserRow.bind(this))
}
</tbody>
</table>
);
}

renderUserRow(user, index) {
return (
<tr key={ index }>
<td>{ user.get('_id') }</td>
<td>{ user.get('name') }</td>
<td>{ user.get('email') }</td>
<td>
<button className="btn btn-danger btn-sm" onClick={ () => this._onDeleteButtonClick(user) }>
DELETE?
</button>
</td>
</tr>
);
}
}

export default connect(state => {
const userIds = state.UserStore.get('userIds');
const users = state.UserStore.get('users');

return {
users: userIds.map(id => users.get(id))
};
})(AdminUsersContainer);
2 changes: 1 addition & 1 deletion src/webapp/components/_containers/AppContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class AppContainer extends PureComponent {
}
return (
<div className="col-sm-9 pull-left">
<form className="cb-navbar-form" onSubmit={ this._onSearchFormSubmit }>
<form className="navbar-form" onSubmit={ this._onSearchFormSubmit }>
<div className="input-group" style={ { width: '100%' } }>
<input id={ SEARCH_FIELD }
type="text"
Expand Down
40 changes: 37 additions & 3 deletions src/webapp/components/_containers/ModelEditContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import Immutable from 'immutable';
import { connect } from 'react-redux';
import PureComponent from 'react-pure-render/component';
import { DropdownButton, MenuItem, SplitButton, ButtonGroup, Grid, Row, Col } from 'react-bootstrap';
import { DropdownButton, MenuItem, SplitButton, ButtonGroup, Grid, Row, Col, Modal } from 'react-bootstrap';

import { OBJLoader, OBJMTLLoader } from '../../render';
import { ModelViewer } from '../model';
Expand Down Expand Up @@ -67,7 +67,8 @@
statisticsIndex: 0,

// Walkthrough
selectedWalkthroughIndex: undefined
selectedWalkthroughIndex: undefined,
deleteConfirm: false
};
}

Expand Down Expand Up @@ -193,10 +194,18 @@
dispatch(SnapshotActions.triggerSnapshot(walkthrough.get('key')));
};

_onWalkthroughDeletePrompt = (e) => {
e.preventDefault();
const { deleteConfirm } = this.state;
this.setState({ deleteConfirm: !deleteConfirm });
};

_onWalkthroughDelete = (e) => {
e.preventDefault();
const { dispatch, params } = this.props;
const { selectedWalkthroughIndex } = this.state;
this.setState({ deleteConfirm: false });
this.setState({ selectedWalkthroughIndex: undefined });
dispatch(WalkthroughActions.deleteWalkthrough(params.modelId, selectedWalkthroughIndex));
};

Expand Down Expand Up @@ -485,7 +494,7 @@
// ----------------- WALKTHROUGH RENDER-----------------
// -----------------------------------------------------
_renderWalkthroughSection() {
const { selectedWalkthroughIndex } = this.state;
const { selectedWalkthroughIndex, deleteConfirm } = this.state;
if (typeof selectedWalkthroughIndex === 'undefined') {
return undefined;
}
Expand Down Expand Up @@ -520,7 +529,32 @@
Update Position
</button>
{ selectedWalkthroughIndex < walkthroughPoints.size - 1 && this._renderWalkthroughAnimationDropdown() }
<button className="btn btn-danger cb-margin-left-10px" onClick={ e => this._onWalkthroughDeletePrompt(e) }>
Delete Point
</button>
<p></p>{ this._renderAnimationDurationField() }
{ deleteConfirm && this._renderDeleteWarning() }
</div>
);
}

_renderDeleteWarning() {
return (
<div className="static-modal">
<Modal.Dialog>
<Modal.Header>
<Modal.Title><h4>Delete Point Warning</h4></Modal.Title>
</Modal.Header>

<Modal.Body>
Are you sure that you want to delete this point?
</Modal.Body>

<Modal.Footer>
<button className="btn btn-primary" onClick={ e => this._onWalkthroughDeletePrompt(e) }>Cancel</button>
<button className="btn btn-danger" onClick={ e => this._onWalkthroughDelete(e) }>Confirm Delete</button>
</Modal.Footer>
</Modal.Dialog>
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/webapp/components/_containers/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export default {
AdminContainer: require('./AdminContainer'),
AdminModelsContainer: require('./AdminModelsContainer'),
AdminUsersContainer: require('./AdminUsersContainer'),
AdminLoginContainer: require('./AdminLoginContainer'),
AppContainer: require('./AppContainer'),
AuthorisationContainer: require('./AuthorisationContainer'),
Expand Down
2 changes: 2 additions & 0 deletions src/webapp/config/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
AppContainer,
AdminContainer,
AdminModelsContainer,
AdminUsersContainer,
AdminLoginContainer,
AuthorisationContainer,
HomeContainer,
Expand Down Expand Up @@ -33,6 +34,7 @@ export default (
<Route path="u/:username" component={ ProfileContainer } />
<Route path="admin" component={ AdminContainer }>
<IndexRoute component={ AdminModelsContainer } />
<Route path="user" component={ AdminUsersContainer } />
</Route>
</Route>
<Route path="/adminLogin" component={ AdminLoginContainer } />
Expand Down
Loading

0 comments on commit 627b545

Please sign in to comment.