Commit b986fd93 authored by Elias Nahum's avatar Elias Nahum

Basic router functionallity

parent a4ed0e7b
.PHONY: build install test run run-fullmap clean stop nuke .PHONY: build install test run run-fullmap clean stop nuke stop-server start-server
test: test:
@echo Checking for style guide compliance @echo Checking for style guide compliance
...@@ -10,24 +10,22 @@ install: package.json ...@@ -10,24 +10,22 @@ install: package.json
@npm install @npm install
@touch $@
build: | install test build: | install test
@echo Building ZBox Manager Webapp @echo Building ZBox Manager Webapp
@npm run build @npm run build
run: install run: | install start-server
@echo Running ZBox Manager Webapp for development @echo Running ZBox Manager Webapp for development
@npm run run & @npm run run &
run-fullmap: install run-fullmap: | install start-server
@echo FULL SOURCE MAP Running ZBox Manager Webapp for development FULL SOURCE MAP @echo FULL SOURCE MAP Running ZBox Manager Webapp for development FULL SOURCE MAP
@npm run run-fullmap & @npm run run-fullmap &
stop: stop: | stop-server
@echo Stopping changes watching @echo Stopping changes watching
@for PROCID in $$(ps -ef | grep "[n]ode.*[w]ebpack" | awk '{ print $$2 }'); do \ @for PROCID in $$(ps -ef | grep "[n]ode.*[w]ebpack" | awk '{ print $$2 }'); do \
...@@ -43,3 +41,15 @@ clean: ...@@ -43,3 +41,15 @@ clean:
nuke: clean nuke: clean
@rm -rf node_modules @rm -rf node_modules
stop-server:
@echo Stopping ZBox Manager 2.0 Test Server
@for PROCID in $$(ps -ef | grep "[b]abel-node.*server" | awk '{ print $$2 }'); do \
echo stopping webpack watch $$PROCID; \
kill $$PROCID; \
done
start-server:
@echo Starting ZBox Manager 2.0 Test Server
@npm run server &
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
"check": "eslint --ext \".jsx\" --ignore-pattern node_modules --quiet .", "check": "eslint --ext \".jsx\" --ignore-pattern node_modules --quiet .",
"build": "webpack", "build": "webpack",
"run": "webpack --progress --watch", "run": "webpack --progress --watch",
"run-fullmap": "webpack --progress --watch" "run-fullmap": "webpack --progress --watch",
"server": "babel-node server.js"
} }
} }
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
const http = require('http');
const fs = require('fs');
const mimes = {
js: 'text/javascript',
json: 'application/json',
css: 'text/css',
png: 'image/png',
jpg: 'image/jpg',
svg: 'image/svg+xml',
eot: 'application/vnd.ms-fontobject',
woff2: 'application/font-woff2',
woff: 'application/font-woff',
ttf: 'application/x-font-truetype'
};
const server = http.createServer((req, res) => {
const mime = /^\/[a-zA-Z0-9\/]*\.(js|json|css|jpg|png|gif|svg|ttf|eot|woff|woff2)$/.exec(req.url.toString());
if (mime) {
const ext = mime[1];
return sendFileContent(res, 'dist/' + req.url.toString().substring(1), mimes[ext]);
}
return sendFileContent(res, 'dist/index.html', 'text/html');
});
server.listen(8000);
server.on('listening', () => {
const addr = server.address();
const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
console.info('ZBox Manager 2.0 Test Server listening on ' + bind); //eslint-disable-line no-console
});
function sendFileContent(response, fileName, contentType) {
fs.readFile(fileName, (err, data) => {
if (err) {
response.writeHead(404);
response.write('Not Found!');
} else {
response.writeHead(200, {'Content-Type': contentType});
response.write(data);
}
response.end();
});
}
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import $ from 'jquery';
import React from 'react';
import {Link} from 'react-router';
export default class ErrorPage extends React.Component {
componentDidMount() {
$('body').attr('class', 'error');
}
componentWillUnmount() {
$('body').attr('class', '');
}
render() {
const title = this.props.location.query.title;
const message = this.props.location.query.message;
const linkMessage = this.props.location.query.linkmessage;
let link = this.props.location.query.link;
if (!link || link === '') {
link = '/';
}
return (
<div className='container-fluid'>
<div className='error__container'>
<div className='error__icon'>
<i className='fa fa-exclamation-triangle'/>
</div>
<h2>{title}</h2>
<p>{message}</p>
<Link to={link}>{linkMessage}</Link>
</div>
</div>
);
}
}
ErrorPage.defaultProps = {
};
ErrorPage.propTypes = {
location: React.PropTypes.object
};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
export default class LoadingScreen extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div
className='loading-screen'
style={{position: this.props.position}}
>
<div className='loading__content'>
<h3>{'Cargando'}</h3>
<div className='round round-1'></div>
<div className='round round-2'></div>
<div className='round round-3'></div>
</div>
</div>
);
}
}
LoadingScreen.defaultProps = {
position: 'relative'
};
LoadingScreen.propTypes = {
position: React.PropTypes.oneOf(['absolute', 'fixed', 'relative', 'static', 'inherit'])
};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import $ from 'jquery';
import React from 'react';
export default class LoggedIn extends React.Component {
componentWillMount() {
// Asignar aqui los css que correspondan
$('#root').attr('class', 'manager-view');
// Device tracking setup
var iOS = (/(iPad|iPhone|iPod)/g).test(navigator.userAgent);
if (iOS) {
$('body').addClass('ios');
}
}
componentWillUnmount() {
$('#root').attr('class', '');
}
render() {
let content = [];
if (this.props.children) {
content = this.props.children;
} else {
content.push(
this.props.sidebar
);
}
return (
<div className=''>
<div className='container-fluid'>
{content}
</div>
</div>
);
}
}
LoggedIn.defaultProps = {
};
LoggedIn.propTypes = {
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
]),
sidebar: React.PropTypes.element,
center: React.PropTypes.element
};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import * as Client from '../../utils/client.jsx';
import LoginEmail from './login_email.jsx';
import {browserHistory, Link} from 'react-router';
import React from 'react';
export default class Login extends React.Component {
constructor(props) {
super(props);
this.submit = this.submit.bind(this);
this.state = {
doneCheckLogin: false
};
}
componentDidMount() {
Client.isLoggedIn((data) => {
if (data && data.logged_in) {
browserHistory.push('/accounts');
} else {
this.setState({doneCheckLogin: true}); //eslint-disable-line react/no-did-mount-set-state
}
});
}
submit(username, password) {
this.setState({loginError: null});
Client.login(username, password,
() => {
browserHistory.push('/accounts');
},
(err) => {
this.setState({loginError: err.message});
}
);
}
render() {
if (!this.state.doneCheckLogin) {
return <div/>;
}
return (
<div>
<div className='signup-header'>
<Link to='/'>
<span className='fa fa-chevron-left'/>
{'Volver'}
</Link>
</div>
<div className='col-sm-12'>
<div className=''>
<h5 className='margin--less'>{'Iniciar Sesión'}</h5>
<h2 className=''>
{'ZBox Manager'}
</h2>
<LoginEmail
submit={this.submit}
loginError={this.state.loginError}
/>
</div>
</div>
</div>
);
}
}
Login.defaultProps = {
};
Login.propTypes = {
params: React.PropTypes.object.isRequired
};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
export default class LoginEmail extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
loginError: props.loginError
};
}
componentWillReceiveProps(nextProps) {
this.setState({loginError: nextProps.loginError});
}
handleSubmit(e) {
e.preventDefault();
var state = {};
const email = this.refs.email.value.trim();
if (!email) {
state.loginError = 'El correo electrónico es obligatorio';
this.setState(state);
return;
}
const password = this.refs.password.value.trim();
if (!password) {
state.loginError = 'La contraseña es obligatoria';
this.setState(state);
return;
}
state.loginError = '';
this.setState(state);
this.props.submit(email, password);
}
render() {
let loginError;
let errorClass = '';
if (this.state.loginError) {
loginError = <label className='control-label'>{this.state.loginError}</label>;
errorClass = ' has-error';
}
return (
<form onSubmit={this.handleSubmit}>
<div className='signup__email-container'>
<div className={'form-group' + errorClass}>
{loginError}
</div>
<div className={'form-group' + errorClass}>
<input
autoFocus={true}
type='email'
className='form-control'
name='email'
ref='email'
placeholder='Correo electrónico'
spellCheck='false'
/>
</div>
<div className={'form-group' + errorClass}>
<input
autoFocus={false}
type='password'
className='form-control'
name='password'
ref='password'
placeholder='Contraseña'
spellCheck='false'
/>
</div>
<div className='form-group'>
<button
type='submit'
className='btn btn-primary'
>
{'Iniciar Sesión'}
</button>
</div>
</div>
</form>
);
}
}
LoginEmail.defaultProps = {
};
LoginEmail.propTypes = {
submit: React.PropTypes.func.isRequired,
loginError: React.PropTypes.string
};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import $ from 'jquery';
import React from 'react';
export default class NotLoggedIn extends React.Component {
componentDidMount() {
$('body').attr('class', 'sticky');
$('#root').attr('class', 'container-fluid');
}
componentWillUnmount() {
$('body').attr('class', '');
$('#root').attr('class', '');
}
render() {
return (
<div className='inner-wrap'>
<div className='row content'>
{this.props.children}
</div>
</div>
);
}
}
NotLoggedIn.defaultProps = {
};
NotLoggedIn.propTypes = {
children: React.PropTypes.object,
location: React.PropTypes.object
};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import * as Client from '../utils/client.jsx';
import React from 'react';
import {browserHistory} from 'react-router';
export default class Root extends React.Component {
constructor(props) {
super(props);
this.state = {
root: true
};
this.redirectIfNecessary = this.redirectIfNecessary.bind(this);
}
redirectIfNecessary(props) {
if (props.location.pathname === '/') {
Client.isLoggedIn((data) => {
if (!data || !data.logged_in) {
browserHistory.push('/login');
} else {
browserHistory.push('/accounts');
}
});
}
}
componentWillReceiveProps(newProps) {
this.redirectIfNecessary(newProps);
}
componentWillMount() {
this.redirectIfNecessary(this.props);
}
render() {
if (this.props.children == null) {
return <div/>;
}
return this.props.children;
}
}
Root.defaultProps = {
};
Root.propTypes = {
children: React.PropTypes.object
};
{ {
"debug": true,
"zimbraUrl": "https://zimbra.zboxapp.dev:7071/service/admin/soap" "zimbraUrl": "https://zimbra.zboxapp.dev:7071/service/admin/soap"
} }
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8" />
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'> <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'>
<meta name='robots' content='noindex, nofollow'> <meta name='robots' content='noindex, nofollow'>
<meta name='referrer' content='no-referrer'> <meta name='referrer' content='no-referrer'>
......
...@@ -4,7 +4,23 @@ ...@@ -4,7 +4,23 @@
import './sass/styles.scss'; import './sass/styles.scss';
import $ from 'jquery'; import $ from 'jquery';
import React from 'react';
import ReactDOM from 'react-dom';
import {Router, Route, IndexRedirect, Redirect, browserHistory} from 'react-router';
import Root from './components/root.jsx';
import ErrorPage from './components/error_page.jsx';
import LoggedIn from './components/logged_in.jsx';
import NotLoggedIn from './components/not_logged_in.jsx';
import Login from './components/login/login.jsx';
import * as Client from './utils/client.jsx'; import * as Client from './utils/client.jsx';
import * as Utils from './utils/utils.jsx';
const notFoundParams = {
title: 'Page not found',
message: 'The page you where trying to reach does not exist',
link: '/',
linkmessage: 'Back to Manager'
};
function preRenderSetup(callwhendone) { function preRenderSetup(callwhendone) {
const d1 = Client.getClientConfig( const d1 = Client.getClientConfig(
...@@ -14,6 +30,11 @@ function preRenderSetup(callwhendone) { ...@@ -14,6 +30,11 @@ function preRenderSetup(callwhendone) {
} }
global.window.manager_config = data; global.window.manager_config = data;
if (data.debug) {
global.window.Zimbra = Client;
global.window.Utils = Utils;
}
}, },
(err) => { (err) => {
console.error(err); //eslint-disable-line no-console console.error(err); //eslint-disable-line no-console
...@@ -23,13 +44,55 @@ function preRenderSetup(callwhendone) { ...@@ -23,13 +44,55 @@ function preRenderSetup(callwhendone) {
$.when(d1).done(callwhendone); $.when(d1).done(callwhendone);
} }
function onLoggedOut() {
Client.logout(
() => {
browserHistory.push('/login');
}
);
}
function renderRootComponent() { function renderRootComponent() {
console.log('eliminar'); //eslint-disable-line no-console ReactDOM.render((
<Router
history={browserHistory}
>
<Route
path='/'
component={Root}
>
<Route
path='error'
component={ErrorPage}
/>
<Route
component={LoggedIn}
>
<Route
path='/logout'
onEnter={onLoggedOut}
/>
</Route>
<Route component={NotLoggedIn}>
<IndexRedirect to='login'/>
<Route
path='login'
component={Login}
/>
<Redirect
from='*'
to='/error'
query={notFoundParams}
/>
</Route>
</Route>
</Router>
),
document.getElementById('root'));
} }
global.window.setup_root = () => { global.window.setup_root = () => {
// Do the pre-render setup and call renderRootComponent when done // Do the pre-render setup and call renderRootComponent when done
preRenderSetup(renderRootComponent); preRenderSetup(renderRootComponent);
}; };
global.window.Zimbra = Client;
...@@ -3,24 +3,32 @@ ...@@ -3,24 +3,32 @@
import $ from 'jquery'; import $ from 'jquery';
import jszimbra from 'js-zimbra'; import jszimbra from 'js-zimbra';
import * as Utils from './utils.jsx';
import Domain from '../zimbra/domain.jsx'; import Domain from '../zimbra/domain.jsx';
let domain; let domain;
// función que maneja el error como corresponde // función que maneja el error como corresponde
function handleError(methodName, err) { function handleError(methodName, err) {
var e = null; let e = null;
try { try {
e = JSON.parse(err); e = JSON.parse(err.responseText);
} catch (parseError) { } catch (parseError) {
e = null; e = null;
} }
console.error(methodName, e); //eslint-disable-line no-console console.error(methodName, e); //eslint-disable-line no-console
const error = {};
if (e) {
error.message = e.Body.Fault.Reason.Text;
} else {
error.message = 'Ocurrio un error general';
}
// Aqui deberiamos revisar si falta hacer login nuevamente // Aqui deberiamos revisar si falta hacer login nuevamente
return e; return error;
} }
export function getClientConfig(success, error) { export function getClientConfig(success, error) {
...@@ -36,8 +44,10 @@ export function getClientConfig(success, error) { ...@@ -36,8 +44,10 @@ export function getClientConfig(success, error) {
} }
export function login(username, secret, success, error) { export function login(username, secret, success, error) {
const config = global.window.manager_config;
const zimbra = new jszimbra.Communication({ const zimbra = new jszimbra.Communication({
url: global.window.manager_config.zimbraUrl url: config.zimbraUrl,
debug: config.debug
}); });
zimbra.auth({ zimbra.auth({
...@@ -54,10 +64,37 @@ export function login(username, secret, success, error) { ...@@ -54,10 +64,37 @@ export function login(username, secret, success, error) {
// aqui deberiamos inicializar todas las apis // aqui deberiamos inicializar todas las apis
domain = new Domain(zimbra); domain = new Domain(zimbra);
return success(); Utils.setCookie('token', zimbra.token, 3);
return success(zimbra);
}); });
} }
export function logout(callback) {
// Aqui debemos asignar como null todas aquellas clases instanciadas
domain = null;
const cookie = Utils.getCookie('token');
if (cookie) {
Utils.setCookie('token', '', -1);
}
return callback();
}
export function isLoggedIn(callback) {
const cookie = Utils.getCookie('token');
const data = {
logged_in: false,
token: null
};
if (cookie) {
data.logged_in = true;
data.token = cookie;
}
return callback(data);
}
export function getDomain(name, by, attrs, success, error) { export function getDomain(name, by, attrs, success, error) {
if (domain) { if (domain) {
return domain.get(name, by, attrs, return domain.get(name, by, attrs,
......
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
const COOKIE_TIMEOUT = 24 * 60 * 60 * 1000;
export function setCookie(cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + (exdays * COOKIE_TIMEOUT));
const expires = 'expires=' + d.toUTCString();
document.cookie = cname + '=' + cvalue + '; ' + expires;
}
export function getCookie(cname) {
var name = cname + '=';
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment