Commit 27374e08 authored by Patricio Bruna's avatar Patricio Bruna

Merge branch 'master' of github.com:ZBoxApp/manager-react

parents f1bef87c c82ac91a
...@@ -101,7 +101,6 @@ http { ...@@ -101,7 +101,6 @@ http {
} }
} }
# HTTPS server # HTTPS server
# #
#server { #server {
......
module.exports = {"main":{"js":"/244695bundle.js"}}
\ No newline at end of file
...@@ -57,7 +57,6 @@ export default class DistributionLists extends React.Component { ...@@ -57,7 +57,6 @@ export default class DistributionLists extends React.Component {
if (domain) { if (domain) {
response.domain = domain; response.domain = domain;
const dl = DomainStore.getDistributionListById(id, domain); const dl = DomainStore.getDistributionListById(id, domain);
console.log(domain, dl);
response.distributionsList = dl; response.distributionsList = dl;
dl.getOwners((error, owners) => { dl.getOwners((error, owners) => {
...@@ -383,8 +382,6 @@ export default class DistributionLists extends React.Component { ...@@ -383,8 +382,6 @@ export default class DistributionLists extends React.Component {
let panelTabs; let panelTabs;
let isPrivate = null; let isPrivate = null;
console.log(this.state);
if (this.state.distributionsList && this.state.owners) { if (this.state.distributionsList && this.state.owners) {
const data = this.state.distributionsList; const data = this.state.distributionsList;
const domain = this.state.domain; const domain = this.state.domain;
......
...@@ -70,9 +70,8 @@ export default class AddAdminModal extends React.Component { ...@@ -70,9 +70,8 @@ export default class AddAdminModal extends React.Component {
e.preventDefault(); e.preventDefault();
this.props.domain.addAdmin( this.props.domain.addAdmin(
user.name, user.id,
(error, success) => { (error) => {
console.log(error, success);
if (error) { if (error) {
return this.setState({ return this.setState({
error: { error: {
......
...@@ -7,6 +7,10 @@ import * as Client from '../../utils/client.jsx'; ...@@ -7,6 +7,10 @@ import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx'; import * as Utils from '../../utils/utils.jsx';
import Promise from 'bluebird'; import Promise from 'bluebird';
import DomainStore from '../../stores/domain_store.jsx'; import DomainStore from '../../stores/domain_store.jsx';
import EventStore from '../../stores/event_store.jsx';
import Constants from '../../utils/constants.jsx';
const MessageType = Constants.MessageType;
export default class AntiSpam extends React.Component { export default class AntiSpam extends React.Component {
constructor(props) { constructor(props) {
...@@ -15,13 +19,18 @@ export default class AntiSpam extends React.Component { ...@@ -15,13 +19,18 @@ export default class AntiSpam extends React.Component {
this.handleDelete = this.handleDelete.bind(this); this.handleDelete = this.handleDelete.bind(this);
this.handleSave = this.handleSave.bind(this); this.handleSave = this.handleSave.bind(this);
this.alterDomain = this.alterDomain.bind(this); this.alterDomain = this.alterDomain.bind(this);
this.domain = DomainStore.getCurrent(); this.domain = DomainStore.getCurrent();
console.log(this.domain); this.blackList = null;
this.whiteList = null;
if (this.domain.attrs.amavisBlacklistSender) {
this.blackList = Array.isArray(this.domain.attrs.amavisBlacklistSender) ? this.domain.attrs.amavisBlacklistSender : this.domain.attrs.amavisBlacklistSender.trim().split(' '); this.blackList = Array.isArray(this.domain.attrs.amavisBlacklistSender) ? this.domain.attrs.amavisBlacklistSender : this.domain.attrs.amavisBlacklistSender.trim().split(' ');
}
if (this.domain.attrs.amavisWhitelistSender) {
this.whiteList = Array.isArray(this.domain.attrs.amavisWhitelistSender) ? this.domain.attrs.amavisWhitelistSender : this.domain.attrs.amavisWhitelistSender.trim().split(' '); this.whiteList = Array.isArray(this.domain.attrs.amavisWhitelistSender) ? this.domain.attrs.amavisWhitelistSender : this.domain.attrs.amavisWhitelistSender.trim().split(' ');
} }
}
handleDelete(e, item, action) { handleDelete(e, item, action) {
e.preventDefault(); e.preventDefault();
...@@ -56,20 +65,27 @@ export default class AntiSpam extends React.Component { ...@@ -56,20 +65,27 @@ export default class AntiSpam extends React.Component {
const attrs = {}; const attrs = {};
const isEmail = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const isEmail = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const isDomain = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/; const isDomain = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/;
const target = action === 'black' ? 'lista negra' : 'lista blanca';
e.preventDefault(); e.preventDefault();
const input = this.refs[`${action}-item`]; const input = this.refs[`${action}-item`];
const value = input.value.trim(); const value = input.value.trim();
if (!value || value === '') { if (!value || value === '') {
console.log('no hay valores'); EventStore.emitMessage({
message: `No puede agregar una ${target} vacia.`,
typeError: MessageType.ERROR
});
return false; return false;
} }
const isValid = isEmail.test(value) || isDomain.test(value); const isValid = isEmail.test(value) || isDomain.test(value);
if (!isValid) { if (!isValid) {
console.log('es invalido'); EventStore.emitMessage({
message: `Solo es posible agregar dominios o email en ${target}`,
typeError: MessageType.ERROR
});
return false; return false;
} }
...@@ -84,7 +100,7 @@ export default class AntiSpam extends React.Component { ...@@ -84,7 +100,7 @@ export default class AntiSpam extends React.Component {
break; break;
} }
this.alterDomain(attrs, e.target, input); return this.alterDomain(attrs, e.target, input);
} }
alterDomain(attrs, button, input) { alterDomain(attrs, button, input) {
...@@ -99,7 +115,6 @@ export default class AntiSpam extends React.Component { ...@@ -99,7 +115,6 @@ export default class AntiSpam extends React.Component {
id = `#${button.getAttribute('id')}`; id = `#${button.getAttribute('id')}`;
} }
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
if (hasButton) { if (hasButton) {
Utils.toggleStatusButtons(id, true); Utils.toggleStatusButtons(id, true);
...@@ -117,7 +132,10 @@ export default class AntiSpam extends React.Component { ...@@ -117,7 +132,10 @@ export default class AntiSpam extends React.Component {
update: true update: true
}); });
}).catch((err) => { }).catch((err) => {
console.log(err); EventStore.emitMessage({
message: err.message || err.reason,
typeError: MessageType.ERROR
});
}).finally(() => { }).finally(() => {
if (hasButton) { if (hasButton) {
Utils.toggleStatusButtons(id, false); Utils.toggleStatusButtons(id, false);
...@@ -134,7 +152,7 @@ export default class AntiSpam extends React.Component { ...@@ -134,7 +152,7 @@ export default class AntiSpam extends React.Component {
let whiteList = null; let whiteList = null;
let blackList = null; let blackList = null;
if (this.blackList.length > 0) { if (this.blackList && this.blackList.length > 0) {
blackList = this.blackList.map((black, i) => { blackList = this.blackList.map((black, i) => {
return ( return (
<tr <tr
...@@ -169,7 +187,7 @@ export default class AntiSpam extends React.Component { ...@@ -169,7 +187,7 @@ export default class AntiSpam extends React.Component {
); );
} }
if (this.whiteList.length > 0) { if (this.whiteList && this.whiteList.length > 0) {
whiteList = this.whiteList.map((white, i) => { whiteList = this.whiteList.map((white, i) => {
return ( return (
<tr <tr
......
//import * as Utils from '../../utils/utils.jsx';
import React from 'react'; import React from 'react';
import {browserHistory} from 'react-router';
import MessageBar from '../message_bar.jsx';
import Panel from '../panel.jsx'; import Panel from '../panel.jsx';
import CreateDomainForm from './multiform/create_domain_form.jsx';
import CompanyStore from '../../stores/company_store.jsx'; import MailCleanerForm from './multiform/mailcleaner_form.jsx';
import DNSZoneForm from './multiform/dns_form.jsx';
import DomainStore from '../../stores/domain_store.jsx'; import DomainStore from '../../stores/domain_store.jsx';
import ZimbraStore from '../../stores/zimbra_store.jsx'; import EventStore from '../../stores/event_store.jsx';
import MessageBar from '../message_bar.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';
export default class CreateDomain extends React.Component { export default class CreateDomain extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.planSize = this.planSize.bind(this); this.getNextStep = this.getNextStep.bind(this);
this.getCompanies = this.getCompanies.bind(this); this.showMessage = this.showMessage.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {}; this.multiform = window.manager_config.multiFormDomain;
} let total = 1;
planSize(e) {
e.preventDefault();
let total = 0;
const plans = Object.keys(this.state.plans);
plans.forEach((p) => { if (this.multiform) {
total += parseInt(this.refs[`plan-${p}`].value, 10) || 0; if (this.multiform.hasMailCleaner) {
}); total++;
this.refs.mailboxLimit.value = total;
} }
getCompanies() { if (this.multiform.hasDNSZone) {
const companyId = this.props.params.id; total++;
const companies = CompanyStore.getCompanies();
if (companies) {
this.setState({
plans: Utils.getEnabledPlansByCos(ZimbraStore.getAllCos()),
companies,
companyId
});
return GlobalActions.emitEndLoading();
} }
return Client.getAllCompanies().
then((data) => {
this.setState({
plans: Utils.getEnabledPlansByCos(ZimbraStore.getAllCos()),
companies: data,
companyId
});
}).
catch((error) => {
error.type = Constants.MessageType.ERROR;
this.setState({error});
}).
finally(() => {
GlobalActions.emitEndLoading();
});
} }
handleSubmit(e) { this.state = {
e.preventDefault(); step: 1,
GlobalActions.emitStartLoading(); total
};
}
const elementList = document.querySelectorAll('.has-error'); getNextStep(attrs) {
Array.from(elementList).forEach((el) => el.classList.remove('has-error')); const states = {};
Utils.validateInputRequired(this.refs). if (attrs.domain) {
then(() => { states.domain = attrs.domain;
const plans = Object.keys(this.state.plans); }
const zimbraDomainCOSMaxAccounts = [];
const name = this.refs.domainName.value.trim();
const businessCategory = this.refs.company.value.trim();
plans.forEach((p) => { states.step = attrs.step;
zimbraDomainCOSMaxAccounts.push(`${this.refs[`plan-${p}`].getAttribute('data-id')}:${this.refs[`plan-${p}`].value || 0}`);
});
const domain = { this.setState(states);
name,
attrs: {
zimbraDomainCOSMaxAccounts,
businessCategory
} }
};
Client.createDomain( showMessage(attrs) {
domain, this.setState({
(data) => { error: attrs.message,
CompanyStore.addDomain(businessCategory, data); type: attrs.typeError
DomainStore.setCurrent(data);
browserHistory.push(`/domains/${data.id}`);
},
(error) => {
GlobalActions.emitEndLoading();
return this.setState({error});
}
);
}).
catch((error) => {
GlobalActions.emitEndLoading();
error.refs = true;
error.type = error.typeError;
error.node.closest('.form-group').classList.add('has-error');
return this.setState({error});
}); });
} }
componentDidMount() { componentDidMount() {
this.getCompanies(); DomainStore.addNextStepListener(this.getNextStep);
EventStore.addMessageListener(this.showMessage);
} }
render() { componentWillUnmount() {
const companies = this.state.companies; DomainStore.removeNextStepListener(this.getNextStep);
const error = this.state.error; EventStore.removeMessageListener(this.showMessage);
if (companies || error) {
let backUrl = '/domains';
if (this.state.companyId) {
backUrl = `/companies/${this.state.companyId}`;
} }
let errorBar; render() {
if (error) { let form = null;
errorBar = ( let titleForm = null;
const progress = `${this.state.step}/${this.state.total}`;
let progressForm = null;
const width = ((100 / this.state.total) * this.state.step);
const progressSize = {
width: `${width}%`
};
let error = null;
if (this.state.error) {
error = (
<MessageBar <MessageBar
message={error.message} message={this.state.error}
type={error.type} type={this.state.type}
autoclose={true} autoclose={true}
/> />
); );
} }
const companiesOptions = companies.map((c) => { let step = this.state.step;
return (
<option
key={`company-${c.id}`}
value={c.id}
>
{c.name}
</option>
);
});
const statePlans = this.state.plans;
const enabledPlans = Object.keys(statePlans);
const plans = enabledPlans.map((p) => {
return (
<div
key={`plan-${statePlans[p]}`}
className='col-md-4 form-group required'
>
<label
htmlFor={`plan-${p}`}
clasName='label-top control-label'
>
<abbr title='Requerido'>{'*'}</abbr><br/>
{Utils.titleCase(p)}
</label>
<br/>
<div className='row'>
<div className='col-sm-8'>
<input
type='text'
className='form-control'
defaultValue='0'
data-required='true'
data-message={`Debe asignar la cantidad de casillas del tipo ${Utils.titleCase(p)}`}
data-id={statePlans[p]}
ref={`plan-${p}`}
onKeyUp={this.planSize}
/>
</div>
</div>
</div>
);
});
const form = (
<form
className='simple_form form-horizontal mailbox-form'
onSubmit={this.handleSubmit}
>
<div className='form-group string required'>
<label className='string required col-sm-3 control-label'>
<abbr title='requerido'>{'*'}</abbr>
{'Nombre'}
</label>
<div className='col-sm-8'>
<input
type='text'
data-required='true'
data-message='El nombre del dominio es obligatorio'
className='form-control'
ref='domainName'
placeholder='example.com'
/>
</div>
</div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
<abbr title='requerido'>{'*'}</abbr>
{'Empresa'}
</label>
<div className='col-sm-8'>
<select
className='form-control select required'
data-required='true'
data-message='Debe especificar a que empresa corresponde el dominio'
ref='company'
defaultValue={this.state.companyId}
>
{companiesOptions}
</select>
</div>
</div>
<div className='form-group row'>
<div className='col-md-8 col-md-offset-3'>
<div className='box-content'>
{plans}
</div>
</div>
</div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
{'Límite de casillas'}
</label>
<div className='col-sm-8'> if (!this.multiform.hasMailCleaner && step > 1) {
<input ++step;
type='text' }
className='form-control'
ref='mailboxLimit'
value='0'
disabled='disabled'
/>
</div>
</div>
<div className='form-group'> switch (step) {
<div className='col-sm-8 col-sm-offset-3'> case 1:
<input form = (
type='submit' <CreateDomainForm
name='commit' params={this.props.params}
value='Guardar' state={this.state}
className='btn btn-info'
/> />
<a
href='#'
className='btn btn-default'
onClick={(e) => Utils.handleLink(e, backUrl)}
>
{'Cancelar'}
</a>
</div>
</div>
</form>
); );
titleForm = 'Creación de Dominio';
break;
case 2:
form = <MailCleanerForm state={this.state}/>;
titleForm = 'Asignación del Dominio al MailCleaner';
break;
case 3:
form = <DNSZoneForm state={this.state}/>;
titleForm = 'Asignación de la Zona DNS';
break;
}
//onClick: (e) => Utils.handleLink(e, backUrl)
const actions = [ const actions = [
{ {
label: 'Cancelar', label: 'Cancelar',
props: { props: {
className: 'btn btn-default btn-xs', className: 'btn btn-default btn-xs'
onClick: (e) => Utils.handleLink(e, backUrl)
} }
} }
]; ];
if (this.state.total > 1) {
progressForm = (
<div className='progress'>
<div
className={'progress-bar progress-bar-info progress-bar-striped active text-center step'}
style={progressSize}
>
<span className='progress-text'>{`${titleForm} - ${progress}`}</span>
</div>
</div>
);
}
return ( return (
<Panel <Panel
title={'Agregar Dominio'} title={'Agregar Dominio'}
btnsHeader={actions}
error={errorBar}
classHeader={'forum-box'} classHeader={'forum-box'}
btnsHeader={actions}
> >
{error}
{progressForm}
{form} {form}
</Panel> </Panel>
); );
} }
return <div/>;
}
} }
CreateDomain.propTypes = { CreateDomain.propTypes = {
params: React.PropTypes.object.isRequired params: React.PropTypes.object.isRequired
}; };
import React from 'react';
import * as Utils from '../../utils/utils.jsx';
import Constants from '../../utils/constants.jsx';
import EventStore from '../../stores/event_store.jsx';
import DomainStore from '../../stores/domain_store.jsx';
const Labels = Constants.Labels;
const MessageType = Constants.MessageType;
export default class DNSZoneForm extends React.Component {
constructor(props) {
super(props);
this.addDNSRow = this.addDNSRow.bind(this);
this.removeRow = this.removeRow.bind(this);
this.handleChangeInput = this.handleChangeInput.bind(this);
this.addDNSRequest = this.addDNSRequest.bind(this);
this.zoneDNSChange = this.zoneDNSChange.bind(this);
this.zoneDNS = DomainStore.getZoneDNS();
this.instanceRow = {
name: '',
type: Constants.typesOfDNS[0],
content: '',
priority: 10,
ttl: 86400,
disabled: false
};
this.defaultRows = this.getRecords();
this.types = Constants.typesOfDNS;
this.state = {
fields: this.defaultRows
};
}
getRecords() {
const records = [];
const zoneRecords = this.zoneDNS;
if (zoneRecords) {
zoneRecords.records.forEach((zone) => {
const newObject = {};
Object.assign(newObject, this.instanceRow, zone);
records.push(newObject);
});
}
return records;
}
addDNSRequest() {
const records = this.defaultRows;
const zoneDNS = this.zoneDNS;
Utils.toggleStatusButtons('.savedns', true);
const button = this.refs.savedns;
const oldContent = button.innerHTML;
button.innerHTML = '<i class=\'fa fa-spinner fa-spin\'></i> Creando Zona DNS';
if (zoneDNS) {
zoneDNS.createOrModifyRecords(records, (err, data) => {
if (err) {
Utils.toggleStatusButtons('.savedns', false);
button.innerHTML = oldContent;
return EventStore.emitMessage({
message: err.reason,
typeError: MessageType.ERROR
});
}
DomainStore.setZoneDNS(data);
Utils.toggleStatusButtons('.savedns', false);
button.innerHTML = oldContent;
return EventStore.emitMessage({
message: 'Se ha registrado su nuevo DNS éxitoxamente.',
typeError: MessageType.SUCCESS
});
});
} else {
EventStore.emitMessage({
message: 'Ha ocurrido un error general al intentar agregar un registro DNS',
typeError: MessageType.ERROR
});
}
}
addDNSRow() {
const copy = Object.assign({}, this.instanceRow);
copy.enabled = true;
this.defaultRows.push(copy);
this.setState({
fields: this.defaultRows
});
}
removeRow(e, index) {
e.preventDefault();
const zoneDNS = this.zoneDNS;
const button = e.target;
const old = button.innerHTML;
button.innerHTML = '<i class=\'fa fa-spinner fa-spin\'></i>';
button.setAttribute('disabled', 'disabled');
if (this.defaultRows[index]) {
if (zoneDNS && zoneDNS.records[index]) {
return zoneDNS.deleteRecords(this.defaultRows[index], (error, success) => {
if (error) {
button.removeAttribute('disabled');
button.innerHTML = old;
return EventStore.emitMessage({
message: error.message,
typeError: MessageType.ERROR
});
}
const name = this.defaultRows[index].name;
DomainStore.setZoneDNS(success);
return EventStore.emitMessage({
message: `Se ha borrado su DNS ${name} éxitoxamente.`,
typeError: MessageType.ERROR
});
});
}
this.defaultRows.splice(index, 1);
this.setState({
fields: this.defaultRows
});
}
return false;
}
handleChangeInput(e, index, ref) {
const value = e.target.value;
if (this.defaultRows[index]) {
this.defaultRows[index][ref] = value;
return true;
}
return false;
}
zoneDNSChange() {
this.zoneDNS = DomainStore.getZoneDNS();
this.defaultRows = this.getRecords();
this.setState({
fields: this.defaultRows
});
}
componentDidMount() {
DomainStore.addZoneDNSChangeListener(this.zoneDNSChange);
}
componentWillUnmount() {
DomainStore.addZoneDNSChangeListener(this.zoneDNSChange);
}
render() {
let isVisible = false;
let fields = null;
let header = null;
const types = this.types.map((item) => {
return (
<option
key={item}
value={item}
>
{item}
</option>
);
});
fields = (
<div className='text-center'>
<h4>No existen Zonas DNS para su dominio : <strong>{this.props.domain.name}</strong></h4>
</div>
);
if (this.defaultRows.length > 0) {
isVisible = true;
header = (
<div className='row'>
<div className='col-xs-3'>
<strong>Nombre</strong>
</div>
<div className='col-xs-1'>
<strong>Tipo</strong>
</div>
<div className='col-xs-3'>
<strong>Contenido</strong>
</div>
<div className='col-xs-2'>
<strong>Prioridad</strong>
</div>
<div className='col-xs-2'>
<strong>TTL</strong>
</div>
<div className='col-xs-1'>
<strong>Acciones</strong>
</div>
</div>
);
fields = this.defaultRows.map((element, i) => {
const isDisabled = element.enabled ? null : true;
return (
<div
className='row set-margin-up'
key={`row-${new Date().getTime()}-${i}`}
id={`row-dns-${new Date().getTime()}-${i}`}
>
<div className='col-xs-3'>
<input
type='text'
defaultValue={element.name}
className='form-control'
onChange={(e) => {
this.handleChangeInput(e, i, Labels.name);
}}
disabled={isDisabled}
/>
</div>
<div className='col-xs-1'>
<select
className='form-control'
defaultValue={element.type}
onChange={(e) => {
this.handleChangeInput(e, i, Labels.type);
}}
disabled={isDisabled}
>
{types}
</select>
</div>
<div className='col-xs-3'>
<input
type='text'
className='form-control'
defaultValue={element.content}
onChange={(e) => {
this.handleChangeInput(e, i, Labels.content);
}}
/>
</div>
<div className='col-xs-2'>
<input
type='number'
className='form-control'
defaultValue={element.priority}
onChange={(e) => {
this.handleChangeInput(e, i, Labels.priority);
}}
/>
</div>
<div className='col-xs-2'>
<input
type='number'
className='form-control'
defaultValue={element.ttl}
onChange={(e) => {
this.handleChangeInput(e, i, Labels.ttl);
}}
/>
</div>
<div className='col-xs-1'>
<button
className='btn btn-danger'
onClick={(e) => {
this.removeRow(e, i);
}}
>
<i
className='fa fa-trash-o'
title='Delete'
>
</i>
</button>
</div>
</div>
);
});
}
return (
<div>
<blockquote className='clearfix'>
<p>
<button
className='btn btn-info pull-right'
onClick={this.addDNSRow}
>
<i className='fa fa-plus-circle fa-lg'></i> Agregar otro registro
</button>
</p>
</blockquote>
<form>
{header}
{fields}
<br/>
<br/>
<div className='col-xs-12 text-right'>
{(isVisible &&
<button
type='button'
className='btn btn-info savedns'
onClick={this.addDNSRequest}
ref='savedns'
>
{'Guardar'}
</button>
)}
</div>
</form>
</div>
);
}
}
DNSZoneForm.propTypes = {
domain: React.PropTypes.object
};
...@@ -8,7 +8,6 @@ import MessageBar from '../message_bar.jsx'; ...@@ -8,7 +8,6 @@ import MessageBar from '../message_bar.jsx';
import PageInfo from '../page_info.jsx'; import PageInfo from '../page_info.jsx';
import PanelTab from '../panel_tab.jsx'; import PanelTab from '../panel_tab.jsx';
import Button from '../button.jsx';
import DomainGeneralInfo from './domain_general_info.jsx'; import DomainGeneralInfo from './domain_general_info.jsx';
import DomainMailboxPlans from './domain_mailbox_plans.jsx'; import DomainMailboxPlans from './domain_mailbox_plans.jsx';
import DomainAdmins from './domain_admin_list.jsx'; import DomainAdmins from './domain_admin_list.jsx';
...@@ -16,6 +15,8 @@ import DomainDistributionList from './domain_distribution_list.jsx'; ...@@ -16,6 +15,8 @@ import DomainDistributionList from './domain_distribution_list.jsx';
import ToggleModalButton from '../toggle_modal_button.jsx'; import ToggleModalButton from '../toggle_modal_button.jsx';
import MultipleTaskModal from './multiple_task_modal.jsx'; import MultipleTaskModal from './multiple_task_modal.jsx';
import AntiSpamComponent from './antispam.jsx'; import AntiSpamComponent from './antispam.jsx';
import ZonaDNS from './domain_admin_dns.jsx';
import EventStore from '../../stores/event_store.jsx';
import DomainStore from '../../stores/domain_store.jsx'; import DomainStore from '../../stores/domain_store.jsx';
...@@ -27,27 +28,63 @@ export default class DomainDetails extends React.Component { ...@@ -27,27 +28,63 @@ export default class DomainDetails extends React.Component {
super(props); super(props);
this.getDomain = this.getDomain.bind(this); this.getDomain = this.getDomain.bind(this);
this.showMessage = this.showMessage.bind(this);
this.state = {}; this.state = {};
} }
showMessage(attrs) {
this.setState({
error: {
message: attrs.message,
type: attrs.typeError
}
});
}
getDomain() { getDomain() {
const domain = DomainStore.getCurrent(); const domain = DomainStore.getCurrent();
if (domain && domain.id === this.props.params.id) { if (domain && domain.id === this.props.params.id) {
GlobalActions.emitEndLoading(); GlobalActions.emitEndLoading();
Client.getZone(domain.name, (zone) => {
DomainStore.setZoneDNS(zone);
this.setState({
domain
});
GlobalActions.emitEndLoading();
}, () => {
DomainStore.setZoneDNS(null);
this.setState({ this.setState({
domain domain
}); });
GlobalActions.emitEndLoading();
});
} else { } else {
Client.getDomain( Client.getDomain(
this.props.params.id, this.props.params.id,
(data) => { (data) => {
DomainStore.setCurrent(data); DomainStore.setCurrent(data);
Client.getZone(data.name, (zone) => {
DomainStore.setZoneDNS(zone);
this.setState({
domain: data
});
GlobalActions.emitEndLoading();
}, () => {
this.setState({ this.setState({
domain: data domain: data
}); });
GlobalActions.emitEndLoading(); GlobalActions.emitEndLoading();
});
}, },
(error) => { (error) => {
this.setState({ this.setState({
...@@ -60,12 +97,14 @@ export default class DomainDetails extends React.Component { ...@@ -60,12 +97,14 @@ export default class DomainDetails extends React.Component {
} }
componentDidMount() { componentDidMount() {
EventStore.addMessageListener(this.showMessage);
$('#sidebar-domains').addClass('active'); $('#sidebar-domains').addClass('active');
this.getDomain(); this.getDomain();
} }
componentWillUnmount() { componentWillUnmount() {
$('#sidebar-domains').removeClass('active'); $('#sidebar-domains').removeClass('active');
EventStore.removeMessageListener(this.showMessage);
} }
render() { render() {
...@@ -125,14 +164,21 @@ export default class DomainDetails extends React.Component { ...@@ -125,14 +164,21 @@ export default class DomainDetails extends React.Component {
</div> </div>
); );
const zonaDNS = (
<ZonaDNS
domain={domain}
/>
);
const panelTabs = ( const panelTabs = (
<PanelTab <PanelTab
tabNames={['Administradores', 'AntiSpam', 'Listas De Distribución', 'Tareas Masivas']} tabNames={['Administradores', 'AntiSpam', 'Listas De Distribución', 'Tareas Masivas', 'Zona DNS']}
tabs={{ tabs={{
administradores: tabAdmin, administradores: tabAdmin,
antispam: tabAntiSpam, antispam: tabAntiSpam,
listas_de_distribución: tabDistribution, listas_de_distribución: tabDistribution,
tareas_masivas: tabTareasMasivas tareas_masivas: tabTareasMasivas,
zona_dns: zonaDNS
}} }}
location={this.props.location} location={this.props.location}
/> />
......
...@@ -56,13 +56,11 @@ export default class DomainGeneralInfo extends React.Component { ...@@ -56,13 +56,11 @@ export default class DomainGeneralInfo extends React.Component {
company: company.name company: company.name
}); });
} else { } else {
Client.getCompany(id). Client.getCompany(id, (data) => {
then((data) => {
this.setState({ this.setState({
company: data.name company: data.name
}); });
}). }, (error) => {
catch((error) => {
this.setState({ this.setState({
error: { error: {
message: error.message, message: error.message,
......
import React from 'react';
import {browserHistory} from 'react-router';
import CompanyStore from '../../../stores/company_store.jsx';
import DomainStore from '../../../stores/domain_store.jsx';
import ZimbraStore from '../../../stores/zimbra_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';
const MessageType = Constants.MessageType;
export default class CreateDomainForm extends React.Component {
constructor(props) {
super(props);
this.planSize = this.planSize.bind(this);
this.getCompanies = this.getCompanies.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {};
}
planSize(e) {
e.preventDefault();
let total = 0;
const plans = Object.keys(this.state.plans);
plans.forEach((p) => {
total += parseInt(this.refs[`plan-${p}`].value, 10) || 0;
});
this.refs.mailboxLimit.value = total;
}
getCompanies() {
const companyId = this.props.params.id;
const companies = CompanyStore.getCompanies();
if (companies) {
this.setState({
plans: Utils.getEnabledPlansByCos(ZimbraStore.getAllCos()),
companies,
companyId
});
return GlobalActions.emitEndLoading();
}
return Client.getAllCompanies().
then((data) => {
this.setState({
plans: Utils.getEnabledPlansByCos(ZimbraStore.getAllCos()),
companies: data,
companyId
});
}).
catch((error) => {
GlobalActions.emitMessage({
message: error.message,
typeError: MessageType.ERROR
});
}).
finally(() => {
GlobalActions.emitEndLoading();
});
}
handleSubmit(e) {
e.preventDefault();
const button = this.refs.createdomainbtn;
const oldContent = button.innerHTML;
if (this.props.state.total === this.props.state.step) {
GlobalActions.emitStartLoading();
}
const elementList = document.querySelectorAll('.has-error');
Array.from(elementList).forEach((el) => el.classList.remove('has-error'));
Utils.validateInputRequired(this.refs).
then(() => {
const plans = Object.keys(this.state.plans);
const zimbraDomainCOSMaxAccounts = [];
const name = this.refs.domainName.value.trim();
const businessCategory = this.refs.company.value.trim();
const zimbraDomainStatus = this.refs.zimbraDomainStatus.value.trim();
plans.forEach((p) => {
zimbraDomainCOSMaxAccounts.push(`${this.refs[`plan-${p}`].getAttribute('data-id')}:${this.refs[`plan-${p}`].value || 0}`);
});
const domain = {
name,
attrs: {
zimbraDomainCOSMaxAccounts,
businessCategory,
zimbraDomainStatus
}
};
button.innerHTML = '<i class=\'fa fa-spinner fa-spin\'></i> Creando Dominio';
Utils.toggleStatusButtons('.action-create-domain', true);
Client.createDomain(
domain,
(data) => {
CompanyStore.addDomain(businessCategory, data);
DomainStore.setCurrent(data);
if (this.props.state.total === this.props.state.step) {
browserHistory.push(`/domains/${data.id}`);
} else {
DomainStore.emitNextStep({
step: ++this.props.state.step,
domain: data
});
}
button.innerHTML = oldContent;
Utils.toggleStatusButtons('.action-create-domain', false);
},
(error) => {
if (this.props.state.total === this.props.state.step) {
GlobalActions.emitEndLoading();
}
button.innerHTML = oldContent;
Utils.toggleStatusButtons('.action-create-domain', false);
return GlobalActions.emitMessage({
message: error.message,
typeError: MessageType.ERROR
});
}
);
}).
catch((error) => {
if (this.props.state.total === this.props.state.step) {
GlobalActions.emitEndLoading();
}
error.refs = true;
error.type = error.typeError;
error.node.closest('.form-group').classList.add('has-error');
return GlobalActions.emitMessage({
message: error.message,
typeError: error.type
});
});
}
componentDidMount() {
Client.initPowerDNS();
this.getCompanies();
}
render() {
const companies = this.state.companies;
const error = this.state.error;
if (companies || error) {
let backUrl = '/domains';
if (this.state.companyId) {
backUrl = `/companies/${this.state.companyId}`;
}
const companiesOptions = companies.map((c) => {
return (
<option
key={`company-${c.id}`}
value={c.id}
>
{c.name}
</option>
);
});
const statePlans = this.state.plans;
const enabledPlans = Object.keys(statePlans);
const plans = enabledPlans.map((p) => {
return (
<div
key={`plan-${statePlans[p]}`}
className='col-md-4 form-group required'
>
<label
htmlFor={`plan-${p}`}
clasName='label-top control-label'
>
<abbr title='Requerido'>{'*'}</abbr><br/>
{Utils.titleCase(p)}
</label>
<br/>
<div className='row'>
<div className='col-sm-8'>
<input
type='text'
className='form-control'
defaultValue='0'
data-required='true'
data-message={`Debe asignar la cantidad de casillas del tipo ${Utils.titleCase(p)}`}
data-id={statePlans[p]}
ref={`plan-${p}`}
onKeyUp={this.planSize}
/>
</div>
</div>
</div>
);
});
const form = (
<form
className='simple_form form-horizontal mailbox-form'
onSubmit={this.handleSubmit}
>
<div className='form-group string required'>
<label className='string required col-sm-3 control-label'>
<abbr title='requerido'>{'*'}</abbr>
{'Nombre'}
</label>
<div className='col-sm-8'>
<input
type='text'
data-required='true'
data-message='El nombre del dominio es obligatorio'
className='form-control'
ref='domainName'
placeholder='example.com'
/>
</div>
</div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
<abbr title='requerido'>{'*'}</abbr>
{'Empresa'}
</label>
<div className='col-sm-8'>
<select
className='form-control select required'
data-required='true'
data-message='Debe especificar a que empresa corresponde el dominio'
ref='company'
defaultValue={this.state.companyId}
>
{companiesOptions}
</select>
</div>
</div>
<div className='form-group row'>
<div className='col-md-8 col-md-offset-3'>
<div className='box-content'>
{plans}
</div>
</div>
</div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
<abbr title='requerido'>{'*'}</abbr>
{'Status'}
</label>
<div className='col-sm-8'>
<select
className='form-control select'
data-required='true'
data-message='Debe especificar el status del dominio'
ref='zimbraDomainStatus'
>
<option value='active'>Activo</option>
<option value='closed'>Cerrado</option>
<option value='locked'>Bloqueado</option>
<option value='maintenance'>En Mantención</option>
<option value='suspended'>Suspendido</option>
</select>
</div>
</div>
<div className='form-group string'>
<label className='string required col-sm-3 control-label'>
{'Límite de casillas'}
</label>
<div className='col-sm-8'>
<input
type='text'
className='form-control'
ref='mailboxLimit'
value='0'
disabled='disabled'
/>
</div>
</div>
<div className='form-group'>
<div className='col-sm-8 col-sm-offset-3'>
<button
className='btn btn-info action-create-domain'
ref='createdomainbtn'
>
{'Guardar'}
</button>
<a
href='#'
className='btn btn-default'
onClick={(e) => Utils.handleLink(e, backUrl)}
>
{'Cancelar'}
</a>
</div>
</div>
</form>
);
return (
<div>
{form}
</div>
);
}
return <div/>;
}
}
CreateDomainForm.propTypes = {
params: React.PropTypes.object.isRequired,
state: React.PropTypes.object
};
import React from 'react';
import {browserHistory} from 'react-router';
import * as Utils from '../../../utils/utils.jsx';
import Constants from '../../../utils/constants.jsx';
import * as Client from '../../../utils/client.jsx';
import EventStore from '../../../stores/event_store.jsx';
import DomainStore from '../../../stores/domain_store.jsx';
const Labels = Constants.Labels;
const MessageType = Constants.MessageType;
export default class DNSZoneForm extends React.Component {
constructor(props) {
super(props);
this.nextStep = this.nextStep.bind(this);
this.addDNSRow = this.addDNSRow.bind(this);
this.removeRow = this.removeRow.bind(this);
this.handleChangeInput = this.handleChangeInput.bind(this);
this.addDNSRequest = this.addDNSRequest.bind(this);
this.instanceRow = {
name: '',
type: Constants.typesOfDNS[0],
content: '',
priority: 10,
ttl: 86400,
disabled: false
};
this.defaultRows = [
Object.assign({}, this.instanceRow),
Object.assign({}, this.instanceRow),
Object.assign({}, this.instanceRow)
];
this.types = Constants.typesOfDNS;
this.state = {
fields: this.defaultRows,
emptyValue: ''
};
}
nextStep() {
if (this.props.state.step === this.props.state.total) {
browserHistory.push(`/domains/${this.props.state.domain.id}`);
} else {
DomainStore.emitNextStep({
step: ++this.props.state.step
});
}
}
addDNSRequest() {
const request = {
name: this.props.state.domain.name,
kind: 'Master',
nameservers: []
};
const records = this.defaultRows;
Utils.toggleStatusButtons('.savedns', true);
const button = this.refs.savedns;
const oldContent = button.innerHTML;
button.innerHTML = '<i class=\'fa fa-spinner fa-spin\'></i> Creando Zona DNS';
Client.getZone(this.props.state.domain.name, (zona) => {
zona.createOrModifyRecords(records, (err) => {
if (err) {
EventStore.emitMessage({
message: err.reason,
typeError: MessageType.ERROR
});
button.innerHTML = oldContent;
return Utils.toggleStatusButtons('.savedns', false);
}
return this.nextStep();
});
}, () => {
Client.createZoneWithRecords(request, records, () => {
this.nextStep();
}, (error) => {
EventStore.emitMessage({
message: error.reason,
typeError: MessageType.ERROR
});
Utils.toggleStatusButtons('.savedns', false);
button.innerHTML = oldContent;
});
});
}
addDNSRow() {
const copy = Object.assign({}, this.instanceRow);
this.defaultRows.push(copy);
this.setState({
fields: this.defaultRows
});
}
removeRow(e, index) {
e.preventDefault();
if (this.defaultRows[index]) {
this.defaultRows.splice(index, 1);
this.setState({
fields: this.defaultRows
});
}
return false;
}
clearInputsFromParent(parentID) {
const parent = document.getElementById(parentID);
if (parent) {
const elements = parent.querySelectorAll('input, select');
let size = elements.length;
if (size > 0) {
for (;size-- > 0;) {
if (elements[size].nodeName.toLowerCase() === 'input') {
elements[size].value = '';
} else {
elements[size].selectedIndex = 0;
}
}
}
}
}
handleChangeInput(e, index, ref) {
const value = e.target.value;
if (this.defaultRows[index]) {
this.defaultRows[index][ref] = value;
return true;
}
return false;
}
render() {
const textButton = this.props.state.step === this.props.state.total ? 'Saltar y Finalizar' : 'Saltar este paso';
let fields = null;
let header = null;
const types = this.types.map((item) => {
return (
<option
key={item}
value={item}
>
{item}
</option>
);
});
fields = (
<div className='text-center'>
<h4>No existen Zonas DNS para su dominio : <strong>{this.props.state.domain.name}</strong></h4>
</div>
);
if (Array.isArray(this.defaultRows) && this.defaultRows.length > 0) {
header = (
<div className='row'>
<div className='col-xs-3'>
<strong>Nombre</strong>
</div>
<div className='col-xs-1'>
<strong>Tipo</strong>
</div>
<div className='col-xs-3'>
<strong>Contenido</strong>
</div>
<div className='col-xs-2'>
<strong>Prioridad</strong>
</div>
<div className='col-xs-2'>
<strong>TTL</strong>
</div>
<div className='col-xs-1'>
<strong>Acciones</strong>
</div>
</div>
);
fields = this.defaultRows.map((element, i) => {
return (
<div
className='row set-margin-up'
key={`row-${new Date().getTime()}-${i}`}
id={`row-dns-${new Date().getTime()}-${i}`}
>
<div className='col-xs-3'>
<input
type='text'
defaultValue={element.name}
className='form-control'
ref={`${Labels.name}-${i}`}
onChange={(e) => {
this.handleChangeInput(e, i, Labels.name);
}}
/>
</div>
<div className='col-xs-1'>
<select
className='form-control'
defaultValue={element.type}
ref={`${Labels.type}-${i}`}
onChange={(e) => {
this.handleChangeInput(e, i, Labels.type);
}}
>
{types}
</select>
</div>
<div className='col-xs-3'>
<input
type='text'
className='form-control'
defaultValue={element.content}
ref={`${Labels.content}-${i}`}
onChange={(e) => {
this.handleChangeInput(e, i, Labels.content);
}}
/>
</div>
<div className='col-xs-2'>
<input
type='number'
className='form-control'
defaultValue={element.priority}
ref={`${Labels.priority}-${i}`}
onChange={(e) => {
this.handleChangeInput(e, i, Labels.priority);
}}
/>
</div>
<div className='col-xs-2'>
<input
type='number'
className='form-control'
defaultValue={element.ttl}
ref={`${Labels.ttl}-${i}`}
onChange={(e) => {
this.handleChangeInput(e, i, Labels.ttl);
}}
/>
</div>
<div className='col-xs-1'>
<button
className='btn btn-danger'
onClick={(e) => {
this.removeRow(e, i);
}}
>
<i
className='fa fa-trash-o'
title='Delete'
>
</i>
</button>
</div>
</div>
);
});
}
return (
<div>
<blockquote className='clearfix'>
<p>
{'Editar Zona DNS para '}<strong>{this.props.state.domain.name}</strong>
<button
className='btn btn-info pull-right'
onClick={this.addDNSRow}
>
<i className='fa fa-plus-circle fa-lg'></i> Agregar otro registro
</button>
</p>
</blockquote>
<form>
{header}
{fields}
<br/>
<br/>
<div className='col-xs-12 text-right'>
<button
type='button'
className='btn btn-info savedns'
onClick={this.addDNSRequest}
ref='savedns'
>
{'Guardar'}
</button>
<button
type='button'
className='btn btn-info'
onClick={this.nextStep}
>
{textButton}
</button>
</div>
</form>
</div>
);
}
}
DNSZoneForm.propTypes = {
state: React.PropTypes.object
};
import React from 'react';
import * as Utils from '../../../utils/utils.jsx';
import {browserHistory} from 'react-router';
import DomainStore from '../../../stores/domain_store.jsx';
export default class MailCleanerForm extends React.Component {
constructor(props) {
super(props);
this.addMailCleaner = this.addMailCleaner.bind(this);
this.nextStep = this.nextStep.bind(this);
this.handleChangeOption = this.handleChangeOption.bind(this);
this.state = {};
}
nextStep() {
if (this.props.state.step === this.props.state.total) {
browserHistory.push(`/domains/${this.props.state.domain.id}`);
} else {
DomainStore.emitNextStep({
step: ++this.props.state.step
});
}
}
handleChangeOption() {
const isEnabledMailCleaner = this.refs.enableMailcleaner.checked;
Utils.toggleStatusButtons('.saveMC', !isEnabledMailCleaner);
}
addMailCleaner() {
const isEnabledMailCleaner = this.refs.enableMailcleaner.checked;
return isEnabledMailCleaner;
}
componentDidMount() {
Utils.toggleStatusButtons('.saveMC', true);
}
render() {
const textButton = this.props.state.step === this.props.state.total ? 'Saltar y Finalizar' : 'Saltar este paso';
return (
<div>
<blockquote>
<p>{'¿ Desea agregar su dominio '}<strong>{this.props.state.domain.name}</strong>{' a MailCleaner ?'}</p>
</blockquote>
<form>
<div className='col-xs-12'>
<label
className='radio radio-info radio-inline pretty-input'
>
<div className='pretty-checkbox'>
<input
type='checkbox'
className='pretty'
name='mailbox'
ref='enableMailcleaner'
onChange={this.handleChangeOption}
/>
<span></span>
</div>
{'Desea usar MailCleaner en su dominio: '} <strong>{this.props.state.domain.name}</strong>
</label>
</div>
<br/>
<br/>
<div className='col-xs-12 text-right'>
<button
type='button'
className='btn btn-info saveMC'
onClick={this.addMailCleaner}
>
{'Guardar'}
</button>
<button
type='button'
className='btn btn-info'
onClick={this.nextStep}
>
{textButton}
</button>
</div>
</form>
</div>
);
}
}
MailCleanerForm.propTypes = {
state: React.PropTypes.object
};
...@@ -69,8 +69,7 @@ export default class MultipleTaskModal extends React.Component { ...@@ -69,8 +69,7 @@ export default class MultipleTaskModal extends React.Component {
if (this.props.show) { if (this.props.show) {
this.props.onHide(); this.props.onHide();
} }
}, (err) => { }, () => {
console.log('err',err);
if (this.props.show) { if (this.props.show) {
this.props.onHide(); this.props.onHide();
} }
...@@ -93,8 +92,7 @@ export default class MultipleTaskModal extends React.Component { ...@@ -93,8 +92,7 @@ export default class MultipleTaskModal extends React.Component {
accounts: res accounts: res
}); });
}).catch((error) => { }).catch((error) => {
console.log('err', error); return error;
}).finally(() => {
}); });
} }
......
...@@ -11,7 +11,6 @@ import * as Utils from '../utils/utils.jsx'; ...@@ -11,7 +11,6 @@ import * as Utils from '../utils/utils.jsx';
import * as Client from '../utils/client.jsx'; import * as Client from '../utils/client.jsx';
import MailboxStore from '../stores/mailbox_store.jsx'; import MailboxStore from '../stores/mailbox_store.jsx';
export default class ImportMassiveModal extends React.Component { export default class ImportMassiveModal extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
...@@ -35,7 +34,6 @@ export default class ImportMassiveModal extends React.Component { ...@@ -35,7 +34,6 @@ export default class ImportMassiveModal extends React.Component {
this.uploaded = null; this.uploaded = null;
this.disabled = {}; this.disabled = {};
this.plans = Utils.getEnabledPlansByCos(ZimbraStore.getAllCos()); this.plans = Utils.getEnabledPlansByCos(ZimbraStore.getAllCos());
this.state = { this.state = {
...@@ -90,14 +88,17 @@ export default class ImportMassiveModal extends React.Component { ...@@ -90,14 +88,17 @@ export default class ImportMassiveModal extends React.Component {
} else { } else {
return this.setState({ return this.setState({
alert: true, alert: true,
alertMessage: 'Su archvio esta vacio, verifiquelo, por favor', alertMessage: 'Su archvio esta vacio, verifiquelo, por favor'
}); });
} }
return null;
}; };
fileReader.readAsText(file); fileReader.readAsText(file);
} }
return null;
} }
onChangeColumn(e, option, key) { onChangeColumn(e, option, key) {
...@@ -149,6 +150,8 @@ export default class ImportMassiveModal extends React.Component { ...@@ -149,6 +150,8 @@ export default class ImportMassiveModal extends React.Component {
if (pos === '') { if (pos === '') {
return true; return true;
} }
return null;
}); });
if (isEmpty) { if (isEmpty) {
...@@ -204,7 +207,7 @@ export default class ImportMassiveModal extends React.Component { ...@@ -204,7 +207,7 @@ export default class ImportMassiveModal extends React.Component {
if (!ul[c]) { if (!ul[c]) {
if (col.indexOf('@') > -1) { if (col.indexOf('@') > -1) {
if (isEmail.test(col)) { if (isEmail.test(col)) {
ul[c] = {} ul[c] = {};
ul[c][flagDefault] = []; ul[c][flagDefault] = [];
this.disabled[flagDefault] = { this.disabled[flagDefault] = {
col: c col: c
...@@ -246,8 +249,8 @@ export default class ImportMassiveModal extends React.Component { ...@@ -246,8 +249,8 @@ export default class ImportMassiveModal extends React.Component {
counter++; counter++;
} }
const length = (Array.isArray(this.uploaded[current])) ? this.uploaded[current].length : this.uploaded[current]['email'].length; const length = (Array.isArray(this.uploaded[current])) ? this.uploaded[current].length : this.uploaded[current].email.length;
const data = (Array.isArray(this.uploaded[current])) ? this.uploaded[current] : this.uploaded[current]['email']; const data = (Array.isArray(this.uploaded[current])) ? this.uploaded[current] : this.uploaded[current].email;
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
if (!padre[i]) { if (!padre[i]) {
...@@ -267,10 +270,11 @@ export default class ImportMassiveModal extends React.Component { ...@@ -267,10 +270,11 @@ export default class ImportMassiveModal extends React.Component {
return this.createMassiveAccounts(padre); return this.createMassiveAccounts(padre);
} }
return this.setState({ this.setState({
alert: true, alert: true,
alertMessage: 'Faltan columnas que son obligatorias, verifique por favor.' alertMessage: 'Faltan columnas que son obligatorias, verifique por favor.'
}); });
return null;
} }
createMassiveAccounts(accounts) { createMassiveAccounts(accounts) {
...@@ -324,9 +328,15 @@ export default class ImportMassiveModal extends React.Component { ...@@ -324,9 +328,15 @@ export default class ImportMassiveModal extends React.Component {
//Aqui va error batchrequest //Aqui va error batchrequest
GlobalActions.emitEndTask({ GlobalActions.emitEndTask({
id: 'casillamasiva' id: 'casillamasiva',
toast: {
message: 'Se han importado todas las casillas.',
title: 'Mailbox - Carga Masiva'
}
}); });
}); });
return null;
} }
render() { render() {
...@@ -339,7 +349,6 @@ export default class ImportMassiveModal extends React.Component { ...@@ -339,7 +349,6 @@ export default class ImportMassiveModal extends React.Component {
); );
} }
if (this.state.cols) { if (this.state.cols) {
const columns = this.state.cols; const columns = this.state.cols;
ul = []; ul = [];
......
...@@ -70,6 +70,8 @@ export default class ConfirmDeleteModal extends React.Component { ...@@ -70,6 +70,8 @@ export default class ConfirmDeleteModal extends React.Component {
}); });
}); });
} }
return null;
} }
render() { render() {
......
...@@ -182,6 +182,8 @@ export default class CreateMailBox extends React.Component { ...@@ -182,6 +182,8 @@ export default class CreateMailBox extends React.Component {
if (currentDomainId === domain.id) { if (currentDomainId === domain.id) {
return domain; return domain;
} }
return null;
}); });
} }
...@@ -481,5 +483,6 @@ export default class CreateMailBox extends React.Component { ...@@ -481,5 +483,6 @@ export default class CreateMailBox extends React.Component {
} }
CreateMailBox.propTypes = { CreateMailBox.propTypes = {
location: React.PropTypes.object location: React.PropTypes.object,
params: React.PropTypes.object
}; };
...@@ -92,7 +92,7 @@ export default class EditMailBox extends React.Component { ...@@ -92,7 +92,7 @@ export default class EditMailBox extends React.Component {
return false; return false;
} }
this.handleRenameAccount(mail); return this.handleRenameAccount(mail);
} }
handleRenameAccount(email) { handleRenameAccount(email) {
...@@ -139,7 +139,7 @@ export default class EditMailBox extends React.Component { ...@@ -139,7 +139,7 @@ export default class EditMailBox extends React.Component {
}); });
} }
GlobalActions.emitMessage({ return GlobalActions.emitMessage({
message: 'Error, no existe instancia de la casilla.', message: 'Error, no existe instancia de la casilla.',
typeError: messageType.ERROR typeError: messageType.ERROR
}); });
......
...@@ -132,6 +132,8 @@ export default class Mailboxes extends React.Component { ...@@ -132,6 +132,8 @@ export default class Mailboxes extends React.Component {
componentWillReceiveProps(newProps) { componentWillReceiveProps(newProps) {
const condition = this.props.location.query.page !== newProps.location.query.page; const condition = this.props.location.query.page !== newProps.location.query.page;
let domainId = null;
if (condition) { if (condition) {
const page = parseInt(newProps.location.query.page, 10) || 1; const page = parseInt(newProps.location.query.page, 10) || 1;
...@@ -142,13 +144,16 @@ export default class Mailboxes extends React.Component { ...@@ -142,13 +144,16 @@ export default class Mailboxes extends React.Component {
offset: ((page - 1) * QueryOptions.DEFAULT_LIMIT) offset: ((page - 1) * QueryOptions.DEFAULT_LIMIT)
}; };
this.getAllMailboxes(); domainId = this.props.params.domain_id;
this.getAllMailboxes(domainId);
} else { } else {
GlobalActions.emitStartLoading(); GlobalActions.emitStartLoading();
let domainId;
if (newProps.params.domain_id !== this.props.params.domain_id) { if (newProps.params.domain_id !== this.props.params.domain_id) {
domainId = newProps.params.domain_id; domainId = newProps.params.domain_id;
} }
this.getAllMailboxes(domainId); this.getAllMailboxes(domainId);
} }
} }
...@@ -221,8 +226,8 @@ export default class Mailboxes extends React.Component { ...@@ -221,8 +226,8 @@ export default class Mailboxes extends React.Component {
notMatches: true, notMatches: true,
domain: domainName domain: domainName
}); });
}).catch(() => { }).catch((error) => {
console.log('error',error); return error;
}).finally(() => { }).finally(() => {
GlobalActions.emitEndLoading(); GlobalActions.emitEndLoading();
}); });
...@@ -493,7 +498,7 @@ export default class Mailboxes extends React.Component { ...@@ -493,7 +498,7 @@ export default class Mailboxes extends React.Component {
className='form-control plans' className='form-control plans'
onChange={this.handleChangeFilter} onChange={this.handleChangeFilter}
> >
<option value=''>Todoas los planes</option> <option value=''>Todos los planes</option>
<option value='basic'>Básico</option> <option value='basic'>Básico</option>
<option value='professional'>Profesional</option> <option value='professional'>Profesional</option>
<option value='premium'>Premium</option> <option value='premium'>Premium</option>
...@@ -572,7 +577,6 @@ export default class Mailboxes extends React.Component { ...@@ -572,7 +577,6 @@ export default class Mailboxes extends React.Component {
onClick={this.handleTabChanged} onClick={this.handleTabChanged}
/> />
); );
} }
return ( return (
......
...@@ -97,7 +97,7 @@ export default class MailboxDetails extends React.Component { ...@@ -97,7 +97,7 @@ export default class MailboxDetails extends React.Component {
}); });
} }
this.setState({ return this.setState({
data: account, data: account,
alias: items, alias: items,
webmail: false webmail: false
...@@ -132,7 +132,7 @@ export default class MailboxDetails extends React.Component { ...@@ -132,7 +132,7 @@ export default class MailboxDetails extends React.Component {
}); });
} }
this.setState({ return this.setState({
data: result, data: result,
alias: items, alias: items,
webmail: false webmail: false
......
...@@ -39,12 +39,12 @@ export default class Pagination extends React.Component { ...@@ -39,12 +39,12 @@ export default class Pagination extends React.Component {
pageUrl = this.getPageQueryString(page); pageUrl = this.getPageQueryString(page);
} }
browserHistory.push(`/${this.props.url}${pageUrl}`); browserHistory.push(`${this.props.url}${pageUrl}`);
} }
handleNext(e) { handleNext(e) {
e.preventDefault(); e.preventDefault();
const page = this.getPageQueryString(this.props.currentPage + 1); const page = this.getPageQueryString(this.props.currentPage + 1);
browserHistory.push(`/${this.props.url}${page}`); browserHistory.push(`${this.props.url}${page}`);
} }
handleLast(e) { handleLast(e) {
e.preventDefault(); e.preventDefault();
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react'; import React from 'react';
import EventStore from '../stores/event_store.jsx'; import EventStore from '../stores/event_store.jsx';
import * as GlobalActions from '../action_creators/global_actions.jsx';
export default class ProgressTask extends React.Component { export default class ProgressTask extends React.Component {
constructor(props) { constructor(props) {
......
{ {
"debug": false, "debug": true,
"zimbraUrl": "http://zimbra.zboxapp.dev:8000/service/admin/soap", "zimbraUrl": "http://zimbra.zboxapp.dev:8000/service/admin/soap",
"zimbraProxy": "https://zimbra.zboxapp.dev:7071", "zimbraProxy": "https://zimbra.zboxapp.dev:7071",
"dnsApiUrl": "http://zimbra.zboxapp.dev:3000", "dnsApiUrl": "http://zimbra.zboxapp.dev:3000",
"webMailUrl": "https://zimbra.zboxapp.dev", "webMailUrl": "https://zimbra.zboxapp.dev",
"dns": {
"url": "http://192.168.1.8:8081",
"token": "otto"
},
"plans": { "plans": {
"basic": true, "basic": true,
"premium": true, "premium": true,
"professional": true, "professional": true,
"default": false "default": false
}, },
"multiFormDomain": {
"hasMailCleaner": false,
"hasDNSZone": true
},
"webmailLifetime": 3600, "webmailLifetime": 3600,
"companiesEndPoints": { "companiesEndPoints": {
"list": "http://zimbra.zboxapp.dev:8001/list", "list": "http://zimbra.zboxapp.dev:8001/list",
......
...@@ -31,17 +31,6 @@ ...@@ -31,17 +31,6 @@
<link rel='icon' type='image/png' sizes='192x192' href='images/favicon/android-chrome-192x192.png'> <link rel='icon' type='image/png' sizes='192x192' href='images/favicon/android-chrome-192x192.png'>
<link rel='manifest' href='config/manifest.json'> <link rel='manifest' href='config/manifest.json'>
<!-- Android add to homescreen --> <!-- Android add to homescreen -->
<style id='antiClickjack'>body{display:none !important;}</style>
<script src='/bundle.js'></script>
<script type='text/javascript'>
if (self === top) {
var blocker = document.getElementById('antiClickjack');
blocker.parentNode.removeChild(blocker);
}
</script>
</head> </head>
<body class='show-sidebar'> <body class='show-sidebar'>
<div id='root'/> <div id='root'/>
......
...@@ -25,9 +25,9 @@ ...@@ -25,9 +25,9 @@
} }
.taskboard { .taskboard {
height: 100%;
max-height: 0; max-height: 0;
overflow: hidden; overflow: hidden;
height: 100%;
transition: max-height 1s; transition: max-height 1s;
.alert { .alert {
...@@ -48,3 +48,9 @@ ...@@ -48,3 +48,9 @@
width: 100%; width: 100%;
} }
} }
.flash {
+ .progress {
margin-top: 10px;
}
}
...@@ -102,3 +102,32 @@ ...@@ -102,3 +102,32 @@
} }
} }
} }
.progress-text {
color: $white;
font-weight: bold;
text-align: center;
text-shadow: 0 1px 2px $black;
}
.progress-bar.step {
background-color: $bg-progresss-bar;
border-right: 0;
text-align: center;
&.first-step {
width: 33.33%;
}
&.second-step {
width: 66.66%;
}
&.third-step {
width: 100%;
}
}
.set-margin-up {
margin-top: 10px;
}
...@@ -93,3 +93,7 @@ $color-new-fields: #e4e5e7; ...@@ -93,3 +93,7 @@ $color-new-fields: #e4e5e7;
$bg-import-ok: rgba(78, 165, 224, .2); $bg-import-ok: rgba(78, 165, 224, .2);
$border-color-ok: #4ea5e0; $border-color-ok: #4ea5e0;
$bg-import-error: #ffe8e8; $bg-import-error: #ffe8e8;
// color ProgressBar
$bg-progresss-bar: #5bc0de;
...@@ -12,6 +12,7 @@ class DomainStoreClass extends EventEmitter { ...@@ -12,6 +12,7 @@ class DomainStoreClass extends EventEmitter {
this.current = null; this.current = null;
this.distributionListOwners = null; this.distributionListOwners = null;
this.distributionListMembers = null; this.distributionListMembers = null;
this.zoneDNS = null;
} }
getCurrent() { getCurrent() {
...@@ -241,6 +242,19 @@ class DomainStoreClass extends EventEmitter { ...@@ -241,6 +242,19 @@ class DomainStoreClass extends EventEmitter {
return false; return false;
} }
setZoneDNS(zone) {
this.zoneDNS = zone;
return this.emitZoneDNSChange(zone);
}
getZoneDNS() {
if (this.zoneDNS) {
return this.zoneDNS;
}
return null;
}
removeDistributionList(listId) { removeDistributionList(listId) {
if (this.current.lists) { if (this.current.lists) {
Reflect.deleteProperty(this.current.lists, listId); Reflect.deleteProperty(this.current.lists, listId);
...@@ -248,6 +262,18 @@ class DomainStoreClass extends EventEmitter { ...@@ -248,6 +262,18 @@ class DomainStoreClass extends EventEmitter {
this.emitDistributionListsChange(); this.emitDistributionListsChange();
} }
emitZoneDNSChange(zone) {
this.emit(eventTypes.ZONE_DNS_CHANGE_EVENT, zone);
}
addZoneDNSChangeListener(zone) {
this.on(eventTypes.ZONE_DNS_CHANGE_EVENT, zone);
}
removeZoneDNSChangeListener(zone) {
this.removeListener(eventTypes.ZONE_DNS_CHANGE_EVENT, zone);
}
emitDistributionListsChange() { emitDistributionListsChange() {
this.emit(eventTypes.DOMAIN_DLS_CHANGE_EVENT); this.emit(eventTypes.DOMAIN_DLS_CHANGE_EVENT);
} }
...@@ -259,6 +285,18 @@ class DomainStoreClass extends EventEmitter { ...@@ -259,6 +285,18 @@ class DomainStoreClass extends EventEmitter {
removeDistributionListsChangeListener(callback) { removeDistributionListsChangeListener(callback) {
this.removeListener(eventTypes.DOMAIN_DLS_CHANGE_EVENT, callback); this.removeListener(eventTypes.DOMAIN_DLS_CHANGE_EVENT, callback);
} }
emitNextStep(attrs) {
this.emit(eventTypes.NEXT_STEP_EVENT, attrs);
}
addNextStepListener(callback) {
this.on(eventTypes.NEXT_STEP_EVENT, callback);
}
removeNextStepListener(callback) {
this.removeListener(eventTypes.NEXT_STEP_EVENT, callback);
}
} }
const DomainStore = new DomainStoreClass(); const DomainStore = new DomainStoreClass();
......
...@@ -5,6 +5,7 @@ import $ from 'jquery'; ...@@ -5,6 +5,7 @@ import $ from 'jquery';
import Promise from 'bluebird'; import Promise from 'bluebird';
import ZimbraAdminApi from 'zimbra-admin-api-js'; import ZimbraAdminApi from 'zimbra-admin-api-js';
import Powerdns from 'js-powerdns';
import ZimbraStore from '../stores/zimbra_store.jsx'; import ZimbraStore from '../stores/zimbra_store.jsx';
import * as GlobalActions from '../action_creators/global_actions.jsx'; import * as GlobalActions from '../action_creators/global_actions.jsx';
...@@ -160,21 +161,19 @@ export function getAllCompanies() { ...@@ -160,21 +161,19 @@ export function getAllCompanies() {
}); });
} }
export function getCompany(id) { export function getCompany(id, success, error) {
const url = global.window.manager_config.companiesEndPoints.detail.replace('{id}', id); const url = global.window.manager_config.companiesEndPoints.detail.replace('{id}', id);
return new Promise((resolve, reject) => {
return $.ajax({ return $.ajax({
url, url,
dataType: 'json', dataType: 'json',
success: function onSuccess(data) { success: function onSuccess(data) {
resolve(data); success(data);
}, },
error: function onError(xhr, status, err) { error: function onError(xhr) {
reject(err); error(xhr.responseJSON);
} }
}); });
});
} }
export function getInvoices(id, success, error) { export function getInvoices(id, success, error) {
...@@ -665,3 +664,93 @@ export function renameAccount(account, success, error) { ...@@ -665,3 +664,93 @@ export function renameAccount(account, success, error) {
} }
); );
} }
export function initPowerDNS() {
return new Promise((resolve, reject) => {
const powerAttrs = window.manager_config.dns;
const api = new Powerdns({url: powerAttrs.url, token: powerAttrs.token});
if (api) {
return resolve(api);
}
return reject({
type: Constants.MessageType.ERROR,
message: 'PowerDNS no instanciado'
});
});
}
export function createZoneWithRecords(zoneData, records, success, error) {
initPowerDNS().then(
(api) => {
api.createZoneWithRecords(zoneData, records, (er, data) => {
if (er) {
return error(er);
}
return success(data);
});
},
(err) => {
const e = handleError('createZoneWithRecords', err);
return error(e);
}
);
}
export function getZone(domain, success, error) {
initPowerDNS().then(
(api) => {
api.getZone(domain, (er, data) => {
if (er) {
return error(er);
}
return success(data);
});
},
(err) => {
const e = handleError('getZone', err);
return error(e);
}
);
}
export function modifyOrCreateRecords(record, success, error) {
initPowerDNS().then(
(api) => {
api.modifyOrCreateRecords(record, (err, data) => {
if (err) {
const e = handleError('modifyOrCreateRecords', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('modifyOrCreateRecords', err);
return error(e);
}
);
}
export function deleteRecords(zoneUrl, record, success, error) {
initPowerDNS().then(
(api) => {
api.deleteRecords(zoneUrl, record, (err, data) => {
if (err) {
const e = handleError('deleteRecords', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('deleteRecords', err);
return error(e);
}
);
}
...@@ -31,7 +31,9 @@ export default { ...@@ -31,7 +31,9 @@ export default {
USER_CHANGE_EVENT: null, USER_CHANGE_EVENT: null,
NEW_MESSAGE_EVENT: null, NEW_MESSAGE_EVENT: null,
NEW_TOAST_EVENT: null, NEW_TOAST_EVENT: null,
MAILBOX_ADD_MASSIVE_EVENT: null MAILBOX_ADD_MASSIVE_EVENT: null,
NEXT_STEP_EVENT: null,
ZONE_DNS_CHANGE_EVENT: null
}), }),
MessageType: keyMirror({ MessageType: keyMirror({
...@@ -54,5 +56,50 @@ export default { ...@@ -54,5 +56,50 @@ export default {
MONTHS: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Juio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'], MONTHS: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Juio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
QueryOptions: { QueryOptions: {
DEFAULT_LIMIT: 10 DEFAULT_LIMIT: 10
} },
Labels: keyMirror({
name: null,
type: null,
content: null,
priority: null,
ttl: null
}),
typesOfDNS: [
'AAAA',
'AFSDB',
'CERT',
'CNAME',
'A',
'DLV',
'DNSKEY',
'DS',
'EUI48',
'EUI64',
'HINFO',
'IPSECKEY',
'KEY',
'KX',
'LOC',
'MINFO',
'MR',
'MX',
'NAPTR',
'NS',
'NSEC',
'NSEC3',
'NSEC3PARAM',
'OPT',
'PTR',
'RKEY',
'RP',
'RRSIG',
'SOA',
'SPF',
'SRV',
'SSHFP',
'TLSA',
'TSIG',
'TXT',
'WKS'
]
}; };
...@@ -2,11 +2,24 @@ const webpack = require('webpack'); ...@@ -2,11 +2,24 @@ const webpack = require('webpack');
const path = require('path'); const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin');
const AssetsPlugin = require('assets-webpack-plugin');
const assetsPluginInstance = new AssetsPlugin({
filename: 'path.json',
processOutput: function (assets) {
return 'module.exports = ' + JSON.stringify(assets);
}
});
const HtmlWebpackPlugin = require('html-webpack-plugin');
const htmlExtract = new ExtractTextPlugin('html', 'index.html'); const htmlExtract = new ExtractTextPlugin('html', 'index.html');
const Instancehtmlwebpackplugin = new HtmlWebpackPlugin({template: './src/index.html', inject: 'head'});
const NPM_TARGET = process.env.npm_lifecycle_event; //eslint-disable-line no-process-env const NPM_TARGET = process.env.npm_lifecycle_event; //eslint-disable-line no-process-env
// Create a simple hash based on timestamp promp
const timestamp = new Date().getTime().toString();
const hash = timestamp.slice(-6, timestamp.length);
var DEV = false; var DEV = false;
var FULLMAP = false; var FULLMAP = false;
if (NPM_TARGET === 'run' || NPM_TARGET === 'run-fullmap') { if (NPM_TARGET === 'run' || NPM_TARGET === 'run-fullmap') {
...@@ -17,11 +30,11 @@ if (NPM_TARGET === 'run' || NPM_TARGET === 'run-fullmap') { ...@@ -17,11 +30,11 @@ if (NPM_TARGET === 'run' || NPM_TARGET === 'run-fullmap') {
} }
var config = { var config = {
entry: ['babel-polyfill', './src/index.jsx', 'src/index.html'], entry: ['babel-polyfill', './src/index.jsx'],
output: { output: {
path: 'dist', path: 'dist',
publicPath: '/', publicPath: '/',
filename: 'bundle.js' filename: hash + 'bundle.js'
}, },
module: { module: {
loaders: [ loaders: [
...@@ -61,14 +74,12 @@ var config = { ...@@ -61,14 +74,12 @@ var config = {
query: { query: {
name: 'files/[hash].[ext]' name: 'files/[hash].[ext]'
} }
},
{
test: /\.html$/,
loader: htmlExtract.extract('html?attrs=link:href')
} }
] ]
}, },
plugins: [ plugins: [
Instancehtmlwebpackplugin,
assetsPluginInstance,
new CopyWebpackPlugin([ new CopyWebpackPlugin([
{from: 'src/config', to: 'config'} {from: 'src/config', to: 'config'}
]), ]),
......
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