Commit 8bfb3e74 authored by Elias Nahum's avatar Elias Nahum

Refactor domain components TODO: distribution lists and Zimbra connections

Domain Details (TODO: zimbra add and remove admins) other small tweaks
parent 11aa98e5
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import * as GlobalActions from '../action_creators/global_actions.jsx';
import * as Utils from '../utils/utils.jsx';
import DomainStore from '../../stores/domain_store.jsx';
import StatusLabel from '../components/status_label.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
import StatusLabel from '../status_label.jsx';
import {Modal} from 'react-bootstrap';
......@@ -27,9 +30,35 @@ export default class AddAdminModal extends React.Component {
const query = this.refs.searchUser.value.trim();
GlobalActions.emitStartLoading();
if (query) {
this.setState({users: []});
GlobalActions.emitStartLoading();
Client.getAllAccounts(
{
query: `mail=*${query}*`,
domain: this.props.domain.name
},
(data) => {
const admins = DomainStore.getAdmins(this.props.domain);
let users = [];
if (admins) {
data.account.forEach((u) => {
if (!admins.hasOwnProperty(u.id)) {
users.push(u);
}
});
} else {
users = data.account;
}
this.setState({users});
GlobalActions.emitEndLoading();
},
(error) => {
this.setState({
error: error.message
});
GlobalActions.emitEndLoading();
}
);
} else {
this.setState({users: null});
}
......@@ -37,6 +66,7 @@ export default class AddAdminModal extends React.Component {
handleAddAdmin(e, user) {
e.preventDefault();
console.log(user); //eslint-disable-line no-console
DomainStore.addAdmin(user);
}
shouldComponentUpdate(nextProps, nextState) {
......@@ -73,7 +103,19 @@ export default class AddAdminModal extends React.Component {
);
} else {
const rows = users.map((u) => {
const statusClass = 'mailbox-active'; //esto debe ser dependiendo del status que tenga el usuario
let status = u.attrs.zimbraAccountStatus;
let statusClass = '';
switch (status) {
case 'locked':
statusClass = 'label label-warning';
status = 'Bloqueada';
break;
default:
statusClass = 'label label-success';
status = 'Activa';
break;
}
return (
<tr
key={`user-${u.id}`}
......@@ -81,8 +123,8 @@ export default class AddAdminModal extends React.Component {
>
<td className='mailbox-status'>
<StatusLabel
classes={`label-mailbox ${statusClass}`}
children={u.status}
classes={statusClass}
children={status}
/>
</td>
<td className='mailbox-name'>
......@@ -92,11 +134,11 @@ export default class AddAdminModal extends React.Component {
Utils.handleLink(e, `/mailboxes/${u.id}`);
}}
>
{u.email}
{u.name}
</a>
</td>
<td className='mailbox-displayname'>
{u.givenName}
{u.attrs.givenName}
</td>
<td className='text-center'>
<a
......
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import DomainStore from '../../stores/domain_store.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
import {Modal} from 'react-bootstrap';
import React from 'react';
export default class AddDistributionListModal extends React.Component {
constructor(props) {
super(props);
this.handleAddList = this.handleAddList.bind(this);
this.state = {};
}
handleAddList(e) {
e.preventDefault();
GlobalActions.emitStartLoading();
Utils.validateInputRequired(this.refs).then(
() => {
const email = `${this.refs.dl_address.value.trim()}@${this.props.domain.name}`;
const displayName = this.refs.dl_name.value.trim();
Client.addDistributionList(
email,
{displayName},
(data) => {
DomainStore.addDistributionList(data);
GlobalActions.emitEndLoading();
this.props.onHide();
},
(error) => {
GlobalActions.emitEndLoading();
this.setState({
error
});
}
);
},
(error) => {
GlobalActions.emitEndLoading();
this.setState({error});
}
);
}
componentWillReceiveProps(nextProps) {
if (!this.props.show && nextProps.show) {
this.setState({error: null});
}
}
shouldComponentUpdate(nextProps, nextState) {
if (!this.props.show && !nextProps.show) {
return false;
}
if (!Utils.areObjectsEqual(this.props, nextProps)) {
return true;
}
return !Utils.areObjectsEqual(this.state, nextState);
}
render() {
let addressClass = 'form-group string required clearfix';
let errorLabel;
if (this.state.error) {
addressClass += ' has-error';
errorLabel = (
<div className='row'>
<div className='col-xs-12 text-center'>
<label className='text-danger'>{this.state.error.message}</label>
</div>
</div>
);
}
return (
<Modal
show={this.props.show}
onHide={this.props.onHide}
>
<div className='color-line'></div>
<Modal.Header closeButton={true}>
<Modal.Title>
{'Agregar lista de distribución'}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className={addressClass}>
<label
className='string required col-sm-3'
htmlFor='dl_address'
>
<abbr title='requerido'>{'*'}</abbr>
{' Dirección'}
</label>
<div className='col-sm-9'>
<div className='input-group col-sm-12'>
<input
className='string required form-control'
data-required='true'
placeholder='dirección email'
type='text'
name='dl_address'
id='dl_address'
ref='dl_address'
data-message='Debes asignar una dirección para la lista de distribución'
/>
<span className='input-group-addon'>
{`@${this.props.domain.name}`}
</span>
</div>
</div>
</div>
<div className='form-group string optional clearfix'>
<label
className='string optional col-sm-3'
htmlFor='dl_name'
>
{'Nombre'}
</label>
<div className='col-sm-9'>
<input
className='string optional string optional form-control'
placeholder='nombre mostrado en contactos'
type='text'
name='dl_name'
id='dl_name'
ref='dl_name'
/>
</div>
</div>
{errorLabel}
</Modal.Body>
<Modal.Footer>
<button
type='button'
className='btn btn-default'
onClick={this.props.onHide}
>
{'Cancelar'}
</button>
<button
type='button'
className='btn btn-primary'
onClick={this.handleAddList}
>
{'Guardar'}
</button>
</Modal.Footer>
</Modal>
);
}
}
AddDistributionListModal.propTypes = {
show: React.PropTypes.bool.isRequired,
onHide: React.PropTypes.func.isRequired,
domain: React.PropTypes.object.isRequired
};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import DomainStore from '../../stores/domain_store.jsx';
import Panel from '../panel.jsx';
import ToggleModalButton from '../toggle_modal_button.jsx';
import AddAdminModal from './add_admin_modal.jsx';
// import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
export default class DomainAdminList extends React.Component {
constructor(props) {
super(props);
this.getAdmins = this.getAdmins.bind(this);
this.handleRemoveAdmin = this.handleRemoveAdmin.bind(this);
this.onAdminsChange = this.onAdminsChange.bind(this);
this.state = this.getStateFromStores();
}
getStateFromStores() {
const admins = DomainStore.getAdmins(this.props.domain);
return {
admins
};
}
getAdmins() {
const domain = this.props.domain;
domain.getAdmins((err, admins) => {
DomainStore.setAdmins(domain, admins);
this.setState({admins});
});
}
handleRemoveAdmin(e, admin) {
e.preventDefault();
if (confirm(`¿Seguro quieres eliminar a ${admin.name} como administrador del dominio?`)) { //eslint-disable-line no-alert
// previo a esto hay que remover el usuario como admin del dominio
DomainStore.removeAdmin(admin.id);
}
}
onAdminsChange() {
const admins = DomainStore.getAdmins(this.props.domain);
if (!admins) {
return this.getAdmins();
}
return this.setState({admins});
}
componentDidMount() {
DomainStore.addAdminsChangeListener(this.onAdminsChange);
if (!this.state.admins) {
this.getAdmins();
}
}
componentWillUnmount() {
DomainStore.removeAdminsChangeListener(this.onAdminsChange);
}
render() {
if (!this.state.admins) {
return <div/>;
}
const domain = this.props.domain;
const adminRows = this.state.admins.map((a) => {
return (
<tr
key={`admin-${a.id}`}
className='user-row'
>
<td className='user-email'>
{a.name}
</td>
<td className='user-name text-center'>
{a.attrs.givenName}
</td>
<td className='user-type text-center'>
</td>
<td className='user-actions text-center'>
<ul className='list-inline list-unstyled'>
<li>
<a
className='btn btn-default btn-xs'
onClick={(e) => Utils.handleLink(e, `/mailboxes/${a.id}/edit`, this.props.location)}
>
{'Editar'}
</a>
</li>
<li>
<a
className='btn btn-danger btn-xs'
onClick={(e) => this.handleRemoveAdmin(e, a)}
>
{'Eliminar'}
</a>
</li>
</ul>
</td>
</tr>
);
});
let adminContent;
if (adminRows.length > 0) {
adminContent = (
<div className='table-responsive'>
<table
id='index-users'
cellPadding='1'
cellSpacing='1'
className='table table-condensed table-striped vertical-align'
>
<thead>
<tr>
<th>{'email'}</th>
<th className='text-center'>{'Nombre'}</th>
<th></th>
<th className='text-center'>{'Acciones'}</th>
</tr>
</thead>
<tbody>
{adminRows}
</tbody>
</table>
<ToggleModalButton
role='button'
className='btn btn-default'
dialogType={AddAdminModal}
dialogProps={{domain}}
>
{'Agregar administrador'}
</ToggleModalButton>
</div>
);
} else {
adminContent = (
<div className='empty-message'>
<h4>
{'No existen Administradores. '}
<ToggleModalButton
role='button'
dialogType={AddAdminModal}
dialogProps={{domain}}
>
{'Agregar administrador'}
</ToggleModalButton>
</h4>
</div>
);
}
return (
<Panel
hasHeader={false}
children={adminContent}
/>
);
}
}
DomainAdminList.propTypes = {
domain: React.PropTypes.object.isRequired,
location: React.PropTypes.object.isRequired
};
This diff is collapsed.
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import DomainStore from '../../stores/domain_store.jsx';
import Panel from '../panel.jsx';
import ToggleModalButton from '../toggle_modal_button.jsx';
import AddDistributionListModal from './add_distribution_list_modal.jsx';
import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
export default class DomainDistributionList extends React.Component {
constructor(props) {
super(props);
this.getLists = this.getLists.bind(this);
this.handleRemoveAdmin = this.handleRemoveAdmin.bind(this);
this.onListsChange = this.onListsChange.bind(this);
this.state = this.getStateFromStores();
}
getStateFromStores() {
const lists = DomainStore.getDistributionLists(this.props.domain);
return {
lists
};
}
getLists() {
const domain = this.props.domain;
domain.getAllDistributionLists(
(err, lists) => {
DomainStore.setDistibutionLists(domain, lists);
this.setState({lists});
}
);
}
onListsChange() {
const lists = DomainStore.getDistributionLists(this.props.domain);
if (!lists) {
return this.getAdmins();
}
return this.setState({lists});
}
handleRemoveAdmin(e, list) {
e.preventDefault();
if (confirm(`¿Seguro quieres eliminar la lista de distribución ${list.name} del dominio?`)) { //eslint-disable-line no-alert
Client.removeDistributionList(
list.id,
() => {
DomainStore.removeDistributionList(list.id);
},
(error) => {
this.setState({error});
}
);
}
}
componentDidMount() {
DomainStore.addDistributionListsChangeListener(this.onListsChange);
if (!this.state.lists) {
this.getLists();
}
}
componentWillUnmount() {
DomainStore.removeDistributionListsChangeListener(this.onListsChange);
}
render() {
if (!this.state.lists) {
return <div/>;
}
const domain = this.props.domain;
const headerButtons = [{
setComponent: (
<ToggleModalButton
key='lists-modal'
role='button'
className='btn btn-info add-button btn-xs'
dialogType={AddDistributionListModal}
dialogProps={{domain}}
>
{'Nueva lista'}
</ToggleModalButton>
)
}];
const listsRows = this.state.lists.map((dl) => {
return (
<tr
key={`dl-${dl.id}`}
className='distribution-list-row'
>
<td className='distribution-list-name'>
<h4>
{dl.name}
</h4>
</td>
<td className='distribution-list-size'>
{dl.members.length}
</td>
<td className='distribution-list-actions'>
<a
href='#'
onClick={(e) => Utils.handleLink(e, `/distribution_lists/${dl.id}`)}
>
{'Ver'}
</a>
{' | '}
<a
href='#'
onClick={(e) => this.handleRemoveAdmin(e, dl)}
>
{'Eliminar'}
</a>
</td>
</tr>
);
});
let panelBody;
if (listsRows.length > 0) {
panelBody = (
<div className='table-responsive'>
<table
cellPadding='1'
cellSpacing='1'
className='table table-condensed table-striped vertical-align'
>
<thead>
<tr>
<th>{'Nombre'}</th>
<th className='text-center'>{'Miembros'}</th>
<th className='text-center'>{'Acciones'}</th>
</tr>
</thead>
<tbody>
{listsRows}
</tbody>
</table>
</div>
);
} else {
panelBody = (
<div className='empty-message'>
<h4>
{'Actualmente no hay listas de distribución. '}
</h4>
</div>
);
}
return (
<Panel
hasHeader={true}
btnsHeader={headerButtons}
children={panelBody}
/>
);
}
}
DomainDistributionList.propTypes = {
domain: React.PropTypes.object.isRequired,
location: React.PropTypes.object.isRequired
};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import Panel from '../panel.jsx';
import StatusLabel from '../status_label.jsx';
import {getDnsInfo} from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
export default class DomainGeneralInfo extends React.Component {
constructor(props) {
super(props);
this.getMXRecord = this.getMXRecord.bind(this);
this.state = {
mx: null
};
}
componentWillMount() {
this.getMXRecord();
}
getMXRecord() {
getDnsInfo(
this.props.domain.name,
(data) => {
this.setState({
mx: data.mx
});
},
(err) => {
this.setState({
mx: err
});
}
);
}
render() {
const domain = this.props.domain;
const infoBody = (
<div className='row'>
<div className='col-md-12'>
<div
id={`domain-${domain.id}`}
className='domain-info'
>
<h4>
<span className='domain-name'>{`@${domain.name}`}</span>
<br/>
<small/>
</h4>
<p>
<a
className='account-name'
onClick={(e) => Utils.handleLink(e, `/accounts/${domain.id_empresa}`, this.props.location)}
>
{'Nombre de la Empresa'}
</a>
</p>
<ul className='list-unstyled'>
<li>
<strong>{'MX Record: '}</strong>
{this.state.mx}
</li>
<li>
<strong>{'Próxima renovación: '}</strong>
{'19/10/2016'}
</li>
<li>
</li>
</ul>
<ul className='list-inline list-unstyled'>
<li>
<StatusLabel
classes='btn btn-md btn-info'
children='Anual'
/>
</li>
</ul>
</div>
</div>
</div>
);
const editDomainButton = [{
label: 'Editar',
props: {
className: 'btn btn-default btn-xs',
onClick: (e) => Utils.handleLink(e, `/domains/${this.props.params.id}/edit`, this.props.location)
}
}];
return (
<Panel
title='Información General'
btnsHeader={editDomainButton}
children={infoBody}
/>
);
}
}
DomainGeneralInfo.propTypes = {
domain: React.PropTypes.object.isRequired,
location: React.PropTypes.object.isRequired,
params: React.PropTypes.object.isRequired
};
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import Panel from '../panel.jsx';
import * as Utils from '../../utils/utils.jsx';
export default class DomainMailboxPlans extends React.Component {
constructor(props) {
super(props);
this.getMailboxPlans = this.getMailboxPlans.bind(this);
this.state = {
plans: null
};
}
componentDidMount() {
this.getMailboxPlans();
}
getMailboxPlans() {
const plans = this.props.domain.plans;
if (plans) {
return this.setState({
plans
});
}
return this.props.domain.countAccounts(
(err, data) => {
if (err) {
return this.setState({plans: {}});
}
return this.setState({plans: data});
}
);
}
render() {
if (!this.state.plans) {
return <div/>;
}
const headerButtons = [
{
label: 'Ver casillas',
props: {
className: 'btn btn-default btn-xs',
onClick: (e) => Utils.handleLink(e, `/domains/${this.props.params.id}/mailboxes`, this.props.location)
}
},
{
label: 'Nueva Casilla',
props: {
className: 'btn btn-info add-button btn-xs',
onClick: (e) => Utils.handleLink(e, `/domains/${this.props.params.id}/mailboxes/new`, this.props.location)
}
}
];
const mailboxPlans = [];
const plans = this.state.plans;
const configPlans = global.window.manager_config.plans;
let totalUsed = 0;
let totalLimit = 0;
for (const key in plans) {
if (plans.hasOwnProperty(key) && configPlans[key]) {
const plan = plans[key];
totalUsed += plan.used;
totalLimit += plan.limit || 0;
mailboxPlans.push(
<tr key={`plan-${key}`}>
<td className='mbx-plan'
style={{borderTop: 0}}
>
{key}
</td>
<td
className='text-center'
style={{borderTop: 0}}
>
{plan.limit || '\u221e'}
</td>
<td
className='text-center'
style={{borderTop: 0}}
>
{plan.used}
</td>
</tr>
);
}
}
mailboxPlans.push(
<tr key='totalizacion-planes'>
<td className='mbx-plan'
style={{borderTop: 0}}
>
<strong>{'Total'}</strong>
</td>
<td
className='text-center'
style={{borderTop: 0}}
>
<strong>{totalLimit || '\u221e'}</strong>
</td>
<td
className='text-center'
style={{borderTop: 0}}
>
<strong>{totalUsed}</strong>
</td>
</tr>
);
const panelBody = (
<table
id='domain-mbxs'
cellPadding='1'
cellSpacing='1'
className='table'
style={{marginBottom: '0px'}}
>
<thead>
<tr>
<th style={{width: '50%'}}></th>
<th className='text-center'>Límite</th>
<th className='text-center'>Usadas</th>
</tr>
</thead>
<tbody>
{mailboxPlans}
</tbody>
</table>
);
return (
<Panel
title='Casillas'
btnsHeader={headerButtons}
children={panelBody}
/>
);
}
}
DomainMailboxPlans.propTypes = {
domain: React.PropTypes.object.isRequired,
location: React.PropTypes.object.isRequired,
params: React.PropTypes.object.isRequired
};
......@@ -3,7 +3,6 @@
import $ from 'jquery';
import React from 'react';
import {browserHistory} from 'react-router';
import MessageBar from '../message_bar.jsx';
import PageInfo from '../page_info.jsx';
......@@ -14,6 +13,7 @@ import StatusLabel from '../status_label.jsx';
import DomainStore from '../../stores/domain_store.jsx';
import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import Constants from '../../utils/constants.jsx';
......@@ -23,7 +23,6 @@ export default class Domains extends React.Component {
constructor(props) {
super(props);
this.handleLink = this.handleLink.bind(this);
this.getDomains = this.getDomains.bind(this);
const page = parseInt(this.props.location.query.page, 10) || 1;
......@@ -33,28 +32,34 @@ export default class Domains extends React.Component {
offset: ((page - 1) * QueryOptions.DEFAULT_LIMIT)
};
}
handleLink(e, domain) {
e.preventDefault();
DomainStore.setCurrent(domain);
const path = `/domains/${domain.id}`;
if (`/${this.props.location.pathname}` !== path) {
GlobalActions.emitStartLoading();
browserHistory.push(path);
}
}
getDomains() {
const self = this;
Client.getAllDomains(
{
limit: QueryOptions.DEFAULT_LIMIT,
offset: this.state.offset
},
(data) => {
this.setState({
const domains = data.domain;
const plans = domains.map((d) => {
return self.getPlans(d);
});
Promise.all(plans).then(
() => {
self.setState({
data
});
GlobalActions.emitEndLoading();
},
() => {
this.setState({
error: 'No se obtuvieron los planes de las cuentas'
});
GlobalActions.emitEndLoading();
}
);
},
(error) => {
this.setState({
error: error.message
......@@ -63,6 +68,19 @@ export default class Domains extends React.Component {
}
);
}
getPlans(domain) {
return new Promise((resolve, reject) => {
Client.countAccounts(domain.name,
(info) => {
domain.plans = info;
resolve();
},
() => {
reject();
}
);
});
}
componentWillReceiveProps(newProps) {
if (this.props.location.query.page !== newProps.location.query.page) {
const page = parseInt(newProps.location.query.page, 10) || 1;
......@@ -102,13 +120,14 @@ export default class Domains extends React.Component {
props: {
className: 'btn btn-success',
onClick: (e) => {
this.handleLink(e, '/domains/new');
Utils.handleLink(e, '/domains/new');
}
}
}];
let tableResults;
if (this.state.data) {
const configPlans = global.window.manager_config.plans;
tableResults = this.state.data.domain.map((d) => {
let status;
let statusClass = 'btn btn-sm ';
......@@ -128,14 +147,20 @@ export default class Domains extends React.Component {
}
let mailboxes;
if (d.mailboxes) {
const types = d.mailboxes.types.map((t, i) => {
return (<li key={`mailbox-${d.id}-${i}`}>{t.count} {t.type}</li>);
if (d.plans) {
let total = 0;
const types = [];
Object.keys(d.plans).forEach((key) => {
if (d.plans.hasOwnProperty(key) && configPlans[key]) {
const plan = d.plans[key];
total += plan.used;
types.push(<li key={`domain-plan-${key}`}>{plan.used} {key}</li>);
}
});
mailboxes = (
<td className='vertical-middle text-center'>
<span className='total-mbxs-per-domain'>d.mailboxes.total</span>
<span className='total-mbxs-per-domain'>{total}</span>
<ul className='list-inline'>
{types}
</ul>
......@@ -155,7 +180,10 @@ export default class Domains extends React.Component {
<h4>
<a
href='#'
onClick={(e) => this.handleLink(e, d)}
onClick={(e) => {
DomainStore.setCurrent(d);
Utils.handleLink(e, `/domains/${d.id}`);
}}
>
{d.name}
</a>
......@@ -193,7 +221,7 @@ export default class Domains extends React.Component {
<thead>
<tr>
<th>{'Nombre'}</th>
<th className='td-mbxs'>{'Casillas Usadas'}</th>
<th className='text-center'>{'Casillas Usadas'}</th>
<th className='text-center'>{'Descripción'}</th>
<th className='text-center'>{'Estado'}</th>
</tr>
......
......@@ -5,9 +5,7 @@ export default class Panel extends React.Component {
render() {
const btns = this.props.btnsHeader.map((btn, i) => {
if (btn.setComponent) {
return (
btn.setComponent
);
return btn.setComponent;
}
return (
<Button
......
{
"debug": true,
"zimbraUrl": "http://zimbra.zboxapp.dev:8000/service/admin/soap",
"zimbraProxy": "https://127.0.0.1:7071"
"zimbraProxy": "https://zimbra.zboxapp.dev:7071",
"dnsApiUrl": "http://zimbra.zboxapp.dev:3000",
"plans": {
"basic": true,
"premium": true,
"professional": true,
"default": false
}
}
......@@ -7,18 +7,6 @@ import Constants from '../utils/constants.jsx';
const PayloadSources = Constants.PayloadSources;
const AppDispatcher = Object.assign(new Flux.Dispatcher(), {
handleServerAction: function performServerAction(action) {
if (!action.type) {
console.warning('handleServerAction called with undefined action type'); // eslint-disable-line no-console
}
var payload = {
source: PayloadSources.SERVER_ACTION,
action
};
this.dispatch(payload);
},
handleViewAction: function performViewAction(action) {
if (!action.type) {
console.warning('handleViewAction called with undefined action type'); // eslint-disable-line no-console
......@@ -32,4 +20,4 @@ const AppDispatcher = Object.assign(new Flux.Dispatcher(), {
}
});
module.exports = AppDispatcher;
export default AppDispatcher;
<!DOCTYPE html>
<html>
<head>
<base href="/">
<meta charset="utf-8" />
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'>
<meta name='robots' content='noindex, nofollow'>
......@@ -33,12 +32,9 @@
<link rel='manifest' href='config/manifest.json'>
<!-- Android add to homescreen -->
<!-- CSS Should always go first -->
<link rel='stylesheet' class='code_theme'>
<!--<link rel='stylesheet' href='/static/css/styles.css'>-->
<style id='antiClickjack'>body{display:none !important;}</style>
<script src='bundle.js'></script>
<script src='/bundle.js'></script>
<script type='text/javascript'>
if (self === top) {
......
......@@ -23,3 +23,34 @@
.empty-search {
margin-top: 10px;
}
.mbx-plan {
text-transform: capitalize;
}
.total-mbxs-per-domain {
font-size: 16px;
font-weight: bold;
}
.distribution-list-row {
td {
&.distribution-list-name {
h4 {
font-size: 14px;
}
}
&.distribution-list-size {
font-size: 14px;
font-weight: bold;
padding-top: 10px;
text-align: center;
}
&.distribution-list-actions {
padding-top: 10px;
text-align: center;
}
}
}
// Copyright (c) 2016 ZBox, Spa. All Rights Reserved.
// See LICENSE.txt for license information.
class DomainStoreClass {
import EventEmitter from 'events';
import Constants from '../utils/constants.jsx';
const eventTypes = Constants.EventTypes;
class DomainStoreClass extends EventEmitter {
constructor() {
super();
this.current = null;
}
......@@ -23,6 +29,144 @@ class DomainStoreClass {
return null;
}
getAdminsAsObject(domain) {
if (this.current !== domain) {
this.setCurrent(domain);
}
const domainAdmins = this.current.admins;
if (!domainAdmins) {
return null;
}
return domainAdmins;
}
getAdmins(domain) {
if (this.current !== domain) {
this.setCurrent(domain);
}
const admins = [];
const domainAdmins = this.current.admins;
if (!domainAdmins) {
return null;
}
for (const id in domainAdmins) {
if (domainAdmins.hasOwnProperty(id)) {
admins.push(domainAdmins[id]);
}
}
return admins;
}
setAdmins(domain, adminsArray) {
if (this.current !== domain) {
this.setCurrent(domain);
}
const admins = {};
adminsArray.forEach((a) => {
admins[a.id] = a;
});
this.current.admins = admins;
}
addAdmin(user) {
const admins = this.current.admins || {};
admins[user.id] = user;
this.current.admins = admins;
this.emitAdminsChange();
}
removeAdmin(userId) {
if (this.current.admins) {
Reflect.deleteProperty(this.current.admins, userId);
}
this.emitAdminsChange();
}
emitAdminsChange() {
this.emit(eventTypes.DOMAIN_ADMINS_CHANGE_EVENT);
}
addAdminsChangeListener(callback) {
this.on(eventTypes.DOMAIN_ADMINS_CHANGE_EVENT, callback);
}
removeAdminsChangeListener(callback) {
this.removeListener(eventTypes.DOMAIN_ADMINS_CHANGE_EVENT, callback);
}
getDistributionLists(domain) {
if (this.current !== domain) {
this.setCurrent(domain);
}
const lists = [];
const distributionLists = this.current.lists;
if (!distributionLists) {
return null;
}
for (const id in distributionLists) {
if (distributionLists.hasOwnProperty(id)) {
lists.push(distributionLists[id]);
}
}
return lists;
}
setDistibutionLists(domain, listsArray) {
if (this.current !== domain) {
this.setCurrent(domain);
}
const lists = {};
listsArray.forEach((a) => {
lists[a.id] = a;
});
this.current.lists = lists;
}
addDistributionList(list) {
const lists = this.current.lists || {};
lists[list.id] = list;
this.current.lists = lists;
this.emitDistributionListsChange();
}
removeDistributionList(listId) {
if (this.current.lists) {
Reflect.deleteProperty(this.current.lists, listId);
}
this.emitDistributionListsChange();
}
emitDistributionListsChange() {
this.emit(eventTypes.DOMAIN_DLS_CHANGE_EVENT);
}
addDistributionListsChangeListener(callback) {
this.on(eventTypes.DOMAIN_DLS_CHANGE_EVENT, callback);
}
removeDistributionListsChangeListener(callback) {
this.removeListener(eventTypes.DOMAIN_DLS_CHANGE_EVENT, callback);
}
}
const DomainStore = new DomainStoreClass();
......
......@@ -4,34 +4,33 @@
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import Constants from '../utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
const START_LOADING_EVENT = 'start_loading';
const END_LOADING_EVENT = 'end_loading';
const eventTypes = Constants.EventTypes;
const ActionTypes = Constants.ActionTypes;
class EventStoreClass extends EventEmitter {
emitStartLoading() {
this.emit(START_LOADING_EVENT);
this.emit(eventTypes.START_LOADING_EVENT);
}
addStartLoadingListener(callback) {
this.on(START_LOADING_EVENT, callback);
this.on(eventTypes.START_LOADING_EVENT, callback);
}
removeStartLoadingListener(callback) {
this.removeListener(START_LOADING_EVENT, callback);
this.removeListener(eventTypes.START_LOADING_EVENT, callback);
}
emitEndLoading() {
this.emit(END_LOADING_EVENT);
this.emit(eventTypes.END_LOADING_EVENT);
}
addEndLoadingListener(callback) {
this.on(END_LOADING_EVENT, callback);
this.on(eventTypes.END_LOADING_EVENT, callback);
}
removeEndLoadingListener(callback) {
this.removeListener(END_LOADING_EVENT, callback);
this.removeListener(eventTypes.END_LOADING_EVENT, callback);
}
}
......
......@@ -4,9 +4,9 @@
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import Constants from '../utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
const CHANGE_EVENT = 'change';
const ActionTypes = Constants.ActionTypes;
const eventTypes = Constants.EventTypes;
class UserStoreClass extends EventEmitter {
constructor() {
......@@ -33,15 +33,15 @@ class UserStoreClass extends EventEmitter {
}
emitChange() {
this.emit(CHANGE_EVENT);
this.emit(eventTypes.USER_CHANGE_EVENT);
}
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
this.on(eventTypes.USER_CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
this.removeListener(eventTypes.USER_CHANGE_EVENT, callback);
}
}
......
......@@ -75,7 +75,7 @@ export function getMe(success, error) {
(zimbra) => {
zimbra.getInfo((err, data) => {
if (err) {
let e = handleError('getMe', err);
const e = handleError('getMe', err);
return error(e);
}
......@@ -85,7 +85,7 @@ export function getMe(success, error) {
});
},
(err) => {
let e = handleError('getMe', err);
const e = handleError('getMe', err);
return error(e);
}
);
......@@ -107,7 +107,7 @@ export function login(user, password, success, error) {
return error(e);
}
Utils.setCookie('token', zimbra.client.token, 3);
Utils.setCookie('token', zimbra.client.token);
ZimbraStore.setCurrent(zimbra);
return getMe(success, error);
});
......@@ -116,7 +116,7 @@ export function login(user, password, success, error) {
export function logout(callback) {
const cookie = Utils.getCookie('token');
if (cookie) {
Utils.setCookie('token', '', -1);
Utils.removeCookie('token');
}
ZimbraStore.setCurrent(null);
GlobalActions.saveUser(null);
......@@ -146,7 +146,7 @@ export function getAllDomains(opts, success, error) {
(zimbra) => {
zimbra.getAllDomains((err, data) => {
if (err) {
let e = handleError('getAllDomains', err);
const e = handleError('getAllDomains', err);
return error(e);
}
......@@ -154,7 +154,7 @@ export function getAllDomains(opts, success, error) {
}, opts);
},
(err) => {
let e = handleError('getAllDomains', err);
const e = handleError('getAllDomains', err);
return error(e);
}
);
......@@ -165,7 +165,7 @@ export function getDomain(id, success, error) {
(zimbra) => {
zimbra.getDomain(id, (err, data) => {
if (err) {
let e = handleError('getAllDomain', err);
const e = handleError('getAllDomain', err);
return error(e);
}
......@@ -173,7 +173,45 @@ export function getDomain(id, success, error) {
});
},
(err) => {
let e = handleError('getAllDomain', err);
const e = handleError('getAllDomain', err);
return error(e);
}
);
}
export function addDistributionList(name, attrs, success, error) {
initZimbra().then(
(zimbra) => {
zimbra.createDistributionList(name, attrs, (err, data) => {
if (err) {
const e = handleError('addDistributionList', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('addDistributionList', err);
return error(e);
}
);
}
export function removeDistributionList(id, success, error) {
initZimbra().then(
(zimbra) => {
zimbra.removeDistributionList(id, (err, data) => {
if (err) {
const e = handleError('removeDistributionList', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('removeDistributionList', err);
return error(e);
}
);
......@@ -184,7 +222,7 @@ export function getAllAccounts(opts, success, error) {
(zimbra) => {
zimbra.getAllAccounts((err, data) => {
if (err) {
let e = handleError('getAllAccounts', err);
const e = handleError('getAllAccounts', err);
return error(e);
}
......@@ -192,7 +230,7 @@ export function getAllAccounts(opts, success, error) {
}, opts);
},
(err) => {
let e = handleError('getAllAccounts', err);
const e = handleError('getAllAccounts', err);
return error(e);
}
);
......@@ -203,7 +241,7 @@ export function getAccount(id, success, error) {
(zimbra) => {
zimbra.getAccount(id, (err, data) => {
if (err) {
let e = handleError('getAccount', err);
const e = handleError('getAccount', err);
return error(e);
}
......@@ -211,7 +249,7 @@ export function getAccount(id, success, error) {
});
},
(err) => {
let e = handleError('getAccount', err);
const e = handleError('getAccount', err);
return error(e);
}
);
......@@ -222,7 +260,7 @@ export function createAccount(mail, passwd, attrs, success, error) {
(zimbra) => {
zimbra.createAccount(mail, passwd, attrs, (err, data) => {
if (err) {
let e = handleError('createAccount', err);
const e = handleError('createAccount', err);
return error(e);
}
......@@ -230,7 +268,7 @@ export function createAccount(mail, passwd, attrs, success, error) {
});
},
(err) => {
let e = handleError('createAccount', err);
const e = handleError('createAccount', err);
return error(e);
}
);
......@@ -241,7 +279,7 @@ export function modifyAccount(idZimbra, attrs, success, error) {
(zimbra) => {
zimbra.modifyAccount(idZimbra, attrs, (err, data) => {
if (err) {
let e = handleError('modifyAccount', err);
const e = handleError('modifyAccount', err);
return error(e);
}
......@@ -249,7 +287,7 @@ export function modifyAccount(idZimbra, attrs, success, error) {
});
},
(err) => {
let e = handleError('modifyAccount', err);
const e = handleError('modifyAccount', err);
return error(e);
}
);
......@@ -260,7 +298,26 @@ export function removeAccount(idZimbra, success, error) {
(zimbra) => {
zimbra.removeAccount(idZimbra, (err, data) => {
if (err) {
let e = handleError('removeAccount', err);
const e = handleError('removeAccount', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('removeAccount', err);
return error(e);
}
);
}
export function countAccounts(domain, success, error) {
return initZimbra().then(
(zimbra) => {
zimbra.countAccounts(domain, (err, data) => {
if (err) {
const e = handleError('removeAccount', err);
return error(e);
}
......@@ -268,8 +325,40 @@ export function removeAccount(idZimbra, success, error) {
});
},
(err) => {
let e = handleError('removeAccount', err);
const e = handleError('removeAccount', err);
return error(e);
}
);
}
export function getDnsInfo(domain, success, error) {
$.ajax({
url: `${global.window.manager_config.dnsApiUrl}/dns`,
type: 'POST',
contentType: ' application/json',
dataType: 'json',
data: JSON.stringify({domain}),
success: (data) => {
const result = {
exists: true,
mx: 'No asignado'
};
if (data.byTypes.length === 0) {
result.exists = false;
} else {
data.byTypes.some((b) => {
if (b.type === 'MX') {
result.mx = b.data[0].exchange;
return true;
}
return false;
});
}
success(result);
},
error: function onError() {
error('No pudimos obtener el registro MX del dominio.');
}
});
}
......@@ -16,6 +16,14 @@ export default {
VIEW_ACTION: null
}),
EventTypes: keyMirror({
DOMAIN_ADMINS_CHANGE_EVENT: null,
DOMAIN_DLS_CHANGE_EVENT: null,
START_LOADING_EVENT: null,
END_LOADING_EVENT: null,
USER_CHANGE_EVENT: null
}),
ZimbraCodes: {
AUTH_EXPIRED: 'service.AUTH_EXPIRED',
AUTH__REQUIRED: 'service.AUTH_REQUIRED'
......
......@@ -5,28 +5,16 @@ import {browserHistory} from 'react-router';
import * as GlobalActions from '../action_creators/global_actions.jsx';
import CONSTANTS from './constants.jsx';
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 setCookie(cname, cvalue) {
localStorage.setItem(cname, cvalue);
}
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 '';
return localStorage.getItem(cname);
}
export function removeCookie(cname) {
return localStorage.removeItem(cname);
}
export function slug(str) {
......
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