Commit 2384b73a authored by Juorder Gonzalez's avatar Juorder Gonzalez Committed by Juorder Antonio

add resend account of mailbox from admin domain and make visible delete...

add resend account of mailbox from admin domain and make visible delete massive for global admin only

add notification for domain migrating mailboxes
parents 0d526cdb 8b6f65ae
module.exports = {"main":{"js":"/142926bundle.js"}} module.exports = {"main":{"js":"/222915bundle.js"}}
\ No newline at end of file \ No newline at end of file
...@@ -42,6 +42,7 @@ export default class DomainMailboxPlans extends React.Component { ...@@ -42,6 +42,7 @@ export default class DomainMailboxPlans extends React.Component {
); );
} }
render() { render() {
const countAccounts = this.state.plans;
if (!this.state.plans) { if (!this.state.plans) {
return <div/>; return <div/>;
} }
...@@ -72,127 +73,142 @@ export default class DomainMailboxPlans extends React.Component { ...@@ -72,127 +73,142 @@ export default class DomainMailboxPlans extends React.Component {
const mailboxPlans = []; const mailboxPlans = [];
let panelBody = null; let panelBody = null;
const cos = Utils.getEnabledPlansByCosId(ZimbraStore.getAllCos());
const planKeys = Object.keys(cos).map((c) => {
return cos[c];
});
const domain = this.props.domain;
const domainCos = domain.maxAccountsByCos();
const domainPlans = Utils.getPlansFromDomain(domain);
const plans = {};
let noLimitError; let noLimitError;
let totalUsed = 0; const isNotMigrating = !countAccounts.migracion;
let totalLimit = 0;
if (isNotMigrating) {
planKeys.forEach((key) => { const cos = Utils.getEnabledPlansByCosId(ZimbraStore.getAllCos());
plans[key] = { const planKeys = Object.keys(cos).map((c) => {
limit: 0, return cos[c];
used: 0
};
});
let used = 0;
if (domainCos) {
Object.keys(domainCos).forEach((id) => {
const limit = domainCos[id];
used = domainPlans[cos[id]].used;
plans[cos[id]].limit += limit;
plans[cos[id]].used += used;
}); });
}
for (const key in plans) { const domain = this.props.domain;
if (plans.hasOwnProperty(key) && plans[key].limit !== 0) { const domainCos = domain.maxAccountsByCos();
const plan = plans[key]; const domainPlans = Utils.getPlansFromDomain(domain);
totalUsed += (parseInt(plan.used, 10)) ? parseInt(plan.used, 10) : 0; const plans = {};
if (plan.limit === 0) { let totalUsed = 0;
//totalLimit = '\u221e'; let totalLimit = 0;
if (!noLimitError) { planKeys.forEach((key) => {
noLimitError = ( plans[key] = {
<MessageBar limit: 0,
message='Existen dominios sin límites asignados' used: 0
type='WARNING' };
autoclose={true} });
/>
); let used = 0;
if (domainCos) {
Object.keys(domainCos).forEach((id) => {
const limit = domainCos[id];
used = domainPlans[cos[id]].used;
plans[cos[id]].limit += limit;
plans[cos[id]].used += used;
});
}
for (const key in plans) {
if (plans.hasOwnProperty(key) && plans[key].limit !== 0) {
const plan = plans[key];
totalUsed += (parseInt(plan.used, 10)) ? parseInt(plan.used, 10) : 0;
if (plan.limit === 0) {
//totalLimit = '\u221e';
if (!noLimitError) {
noLimitError = (
<MessageBar
message='Existen dominios sin límites asignados'
type='WARNING'
autoclose={true}
/>
);
}
} else {
totalLimit += plan.limit;
} }
} else {
totalLimit += plan.limit; 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>
);
} }
}
if (mailboxPlans.length > 0) {
mailboxPlans.push( mailboxPlans.push(
<tr key={`plan-${key}`}> <tr key='totalizacion-planes'>
<td className='mbx-plan' <td className='mbx-plan'
style={{borderTop: 0}} style={{borderTop: 0}}
> >
{key} <strong>{'Total'}</strong>
</td> </td>
<td <td
className='text-center' className='text-center'
style={{borderTop: 0}} style={{borderTop: 0}}
> >
{plan.limit || '\u221e'} <strong>{totalLimit}</strong>
</td> </td>
<td <td
className='text-center' className='text-center'
style={{borderTop: 0}} style={{borderTop: 0}}
> >
{plan.used} <strong>{totalUsed}</strong>
</td> </td>
</tr> </tr>
); );
}
}
if (mailboxPlans.length > 0) { panelBody = (
mailboxPlans.push( <table
<tr key='totalizacion-planes'> id='domain-mbxs'
<td className='mbx-plan' cellPadding='1'
style={{borderTop: 0}} cellSpacing='1'
className='table'
style={{marginBottom: '0px'}}
> >
<strong>{'Total'}</strong> <thead>
</td> <tr>
<td <th style={{width: '50%'}}></th>
className='text-center' <th className='text-center'>{'Límite'}</th>
style={{borderTop: 0}} <th className='text-center'>{'Usadas'}</th>
> </tr>
<strong>{totalLimit}</strong> </thead>
</td> <tbody>
<td {mailboxPlans}
className='text-center' </tbody>
style={{borderTop: 0}} </table>
> );
<strong>{totalUsed}</strong> } else {
</td> panelBody = (
</tr> <div className='text-center'>
); <h4 className='text-danger'>{'No se han asignado límites de casillas.'}</h4>
</div>
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>
);
} else { } else {
panelBody = ( panelBody = (
<div className='text-center'> <div className='text-center'>
<h4 className='text-danger'>{'No se han asignado límites de casillas.'}</h4> <h4 className='text-danger'>{'Se esta realizando una migracion.'}</h4>
<blockquote>
{`Limite : ${countAccounts.migracion.limit || 'No definido'}`}
<br/>
{`Usadas : ${countAccounts.migracion.used || 'No definido'}`}
</blockquote>
</div> </div>
); );
} }
......
...@@ -19,6 +19,7 @@ import ToggleModalButton from '../toggle_modal_button.jsx'; ...@@ -19,6 +19,7 @@ import ToggleModalButton from '../toggle_modal_button.jsx';
import MessageBar from '../message_bar.jsx'; import MessageBar from '../message_bar.jsx';
import Promise from 'bluebird'; import Promise from 'bluebird';
import MailboxStore from '../../stores/mailbox_store.jsx'; import MailboxStore from '../../stores/mailbox_store.jsx';
import ResendForm from './reenvios_form.jsx';
import * as Client from '../../utils/client.jsx'; import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx'; import * as Utils from '../../utils/utils.jsx';
...@@ -343,7 +344,7 @@ export default class MailboxDetails extends React.Component { ...@@ -343,7 +344,7 @@ export default class MailboxDetails extends React.Component {
/> />
); );
const tab2 = ( const tabAlias = (
<Panel <Panel
title='Casillas' title='Casillas'
hasHeader={false} hasHeader={false}
...@@ -352,12 +353,17 @@ export default class MailboxDetails extends React.Component { ...@@ -352,12 +353,17 @@ export default class MailboxDetails extends React.Component {
/> />
); );
const reenvios = (
<ResendForm mailbox={this.state.data}/>
);
panelTabs = ( panelTabs = (
<PanelTab <PanelTab
tabNames={['Resp Vacaciones', 'Alias']} tabNames={['Resp Vacaciones', 'Alias', 'Reenvios']}
tabs={{ tabs={{
resp_vacaciones: tabAdmin, resp_vacaciones: tabAdmin,
alias: tab2 alias: tabAlias,
reenvios
}} }}
location={this.props.location} location={this.props.location}
/> />
......
import React from 'react';
import * as Client from '../../utils/client.jsx';
import EventStore from '../../stores/event_store.jsx';
import Constants from '../../utils/constants.jsx';
const messageType = Constants.MessageType;
export default class ResendForm extends React.Component {
constructor(props) {
super(props);
this.onUpdateAttrs = this.onUpdateAttrs.bind(this);
const {attrs} = this.props.mailbox;
this.state = {
zimbraPrefMailForwardingAddress: attrs.zimbraPrefMailForwardingAddress || '',
zimbraMailForwardingAddress: attrs.zimbraMailForwardingAddress || ''
};
}
onUpdateAttrs(e) {
e.preventDefault();
const {mailbox} = this.props;
const attrs = {};
let zimbraMailForwardingAddressTextarea = this.refs.zimbraMailForwardingAddress.value.trim();
let zimbraPrefMailForwardingAddressInput = this.refs.zimbraPrefMailForwardingAddress.value.trim();
let hasError = false;
const pattern = /^(([^<>()\[\]\\.,;:\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,}))$/;
if (zimbraMailForwardingAddressTextarea !== '') {
const arrayMailboxes = zimbraMailForwardingAddressTextarea.split(/\r?\n/gi);
zimbraMailForwardingAddressTextarea = [];
if (arrayMailboxes && arrayMailboxes.length > 0) {
arrayMailboxes.forEach((mailbox) => {
if (mailbox !== '') {
const cleanEmail = mailbox.trim();
const isNotRightEmail = !pattern.test(cleanEmail);
if (isNotRightEmail) {
hasError = true;
} else {
zimbraMailForwardingAddressTextarea.push(mailbox);
}
}
});
}
}
if (zimbraPrefMailForwardingAddressInput !== '') {
if (!pattern.test(zimbraPrefMailForwardingAddressInput)) {
hasError = true;
}
}
if (hasError) {
return EventStore.emitToast({
body: 'Algunas de las cuentas de correo, no tiene el formato de un correo electrónico, verifique por favor.',
title: 'Reenvios',
type: messageType.ERROR.toLowerCase()
});
}
attrs.zimbraMailForwardingAddress = zimbraMailForwardingAddressTextarea;
attrs.zimbraPrefMailForwardingAddress = zimbraPrefMailForwardingAddressInput;
Client.modifyAccount(mailbox.id, attrs, () => {
//MailboxStore.updateMailbox(data.id, mailbox, this.domain_id);
EventStore.emitToast({
title: 'Reenvios',
body: 'Se han modificado los correos de reenvio éxitosamente.',
type: messageType.SUCCESS.toLowerCase()
});
this.setState(attrs);
}, (error) => {
EventStore.emitToast({
title: 'Reenvios',
body: error.message,
type: messageType.ERROR.toLowerCase()
});
});
}
renderMailbox(mailboxes) {
const accounts = mailboxes.constructor.name === 'Array' ? mailboxes.join('\r\n') : mailboxes;
return accounts;
}
render() {
const {zimbraPrefMailForwardingAddress, zimbraMailForwardingAddress} = this.state;
return (
<div>
<div className='row margin-bottom'>
<div className='col-xs-12'>
<blockquote className='custom-blockquote'>
<p>
<i>
{'Direcciones de reenvío especificadas por el usuario'}
</i>
</p>
</blockquote>
</div>
<div className='col-xs-8'>
<input
type='text'
ref='zimbraPrefMailForwardingAddress'
className='form-control'
id='forwardingAddress'
defaultValue={this.renderMailbox(zimbraPrefMailForwardingAddress)}
/>
</div>
</div>
<div className='row margin-bottom'>
<div className='col-xs-12'>
<blockquote className='custom-blockquote'>
<p>
<i>
{'Direcciones de reenvío ocultas para el usuario'}
</i>
</p>
<p>
<i>
<small>
{'Separe las cuentas de correo con una nueva linea (Tecla Enter)'}
</small>
</i>
</p>
</blockquote>
</div>
<div className='col-xs-12'>
<textarea
ref='zimbraMailForwardingAddress'
id='forwardingAddressHidden'
rows='10'
className='form-control noresize'
defaultValue={this.renderMailbox(zimbraMailForwardingAddress)}
>
</textarea>
</div>
</div>
<div className='row'>
<div className='col-xs-12 text-right'>
<button
className='btn btn-info'
onClick={this.onUpdateAttrs}
>
{'Guardar'}
</button>
</div>
</div>
</div>
);
}
}
ResendForm.propTypes = {
mailbox: React.PropTypes.object
};
...@@ -5,6 +5,7 @@ import * as GlobalActions from '../../action_creators/global_actions.jsx'; ...@@ -5,6 +5,7 @@ import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Utils from '../../utils/utils.jsx'; import * as Utils from '../../utils/utils.jsx';
import ErrorStore from '../../stores/error_store.jsx'; import ErrorStore from '../../stores/error_store.jsx';
import UserStore from '../../stores/user_store.jsx';
import PageInfo from '../page_info.jsx'; import PageInfo from '../page_info.jsx';
import Panel from '../panel.jsx'; import Panel from '../panel.jsx';
...@@ -39,8 +40,13 @@ export default class MassiveDelete extends React.Component { ...@@ -39,8 +40,13 @@ export default class MassiveDelete extends React.Component {
} }
} }
componentWillReceiveProps() {
GlobalActions.emitEndLoading();
}
componentDidMount() { componentDidMount() {
this.handleCommands(); this.handleCommands();
GlobalActions.emitEndLoading();
} }
handleDelete(e) { handleDelete(e) {
...@@ -55,13 +61,13 @@ export default class MassiveDelete extends React.Component { ...@@ -55,13 +61,13 @@ export default class MassiveDelete extends React.Component {
} }
const preMailboxes = consoleText.split(/\r?\n/gi); const preMailboxes = consoleText.split(/\r?\n/gi);
const pattern = /^(([^<>()\[\]\\.,;:\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 getAccountByBatch = []; const getAccountByBatch = [];
const deleteAccountByBatch = []; const deleteAccountByBatch = [];
const wrongEmails = []; const wrongEmails = [];
const emailsNotFound = []; const emailsNotFound = [];
preMailboxes.forEach((email) => { preMailboxes.forEach((email) => {
const pattern = /^(([^<>()\[\]\\.,;:\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 cleanEmail = email.trim(); const cleanEmail = email.trim();
const condition = pattern.test(cleanEmail) && cleanEmail !== ''; const condition = pattern.test(cleanEmail) && cleanEmail !== '';
...@@ -246,21 +252,38 @@ export default class MassiveDelete extends React.Component { ...@@ -246,21 +252,38 @@ export default class MassiveDelete extends React.Component {
} }
render() { render() {
const consoleText = ( let buttons = null;
<div let consoleText = null;
className='row'
key='deleteConsole' if (!UserStore.isGlobalAdmin()) {
> consoleText = (
<div className='col-xs-12'> <div
<blockquote className='custom-blockquote'> className='text-center'
<p> key='notAllowed'
<i> >
{'Escribir el nombre de las casillas a la cual se quiere eliminar, cada casilla debe ser separada por un salto de linea (Tecla Enter).'} <h3 className='page-header'>
</i> {'Usted no tiene permisos para ingresar a esta area'}
</p> </h3>
</blockquote>
</div> </div>
<div className='col-xs-12 wrapper-console'> );
}
if (UserStore.isGlobalAdmin()) {
consoleText = (
<div
className='row'
key='deleteConsole'
>
<div className='col-xs-12'>
<blockquote className='custom-blockquote'>
<p>
<i>
{'Escribir el nombre de las casillas a la cual se quiere eliminar, cada casilla debe ser separada por un salto de linea (Tecla Enter).'}
</i>
</p>
</blockquote>
</div>
<div className='col-xs-12 wrapper-console'>
<textarea <textarea
className='form-control consoleText' className='form-control consoleText'
ref='console' ref='console'
...@@ -274,25 +297,26 @@ export default class MassiveDelete extends React.Component { ...@@ -274,25 +297,26 @@ export default class MassiveDelete extends React.Component {
</code> </code>
{'PARA EJECUTAR'} {'PARA EJECUTAR'}
</span> </span>
</div>
</div> </div>
</div> );
);
buttons = (
const buttons = ( <div
<div key={'btn-actions'}
key={'btn-actions'} className='row'
className='row' >
> <div className='col-xs-12 text-right'>
<div className='col-xs-12 text-right'> <button
<button className='btn btn-danger'
className='btn btn-danger' onClick={this.handleDelete}
onClick={this.handleDelete} >
> {'Borrar Casillas'}
{'Borrar Casillas'} </button>
</button> </div>
</div> </div>
</div> );
); }
return ( return (
<div> <div>
......
...@@ -13,6 +13,7 @@ export default class SidebarMenu extends React.Component { ...@@ -13,6 +13,7 @@ export default class SidebarMenu extends React.Component {
this.handleLink = this.handleLink.bind(this); this.handleLink = this.handleLink.bind(this);
this.openSupportModal = this.openSupportModal.bind(this); this.openSupportModal = this.openSupportModal.bind(this);
} }
handleLink(e, path) { handleLink(e, path) {
e.preventDefault(); e.preventDefault();
if (`/${this.props.location.pathname}` !== path) { if (`/${this.props.location.pathname}` !== path) {
...@@ -93,6 +94,17 @@ export default class SidebarMenu extends React.Component { ...@@ -93,6 +94,17 @@ export default class SidebarMenu extends React.Component {
{'Soporte'} {'Soporte'}
</a> </a>
</li> </li>
{UserStore.isGlobalAdmin() && (
<li>
<a
className='nav-label'
href='#'
onClick={(e) => this.handleLink(e, '/deleteMassive')}
>
{'Borrado Masivo'}
</a>
</li>
)}
<li> <li>
<Link <Link
to='/logout' to='/logout'
......
...@@ -25,6 +25,7 @@ import EditDistributionList from './components/distribution/edit_distribution_li ...@@ -25,6 +25,7 @@ import EditDistributionList from './components/distribution/edit_distribution_li
import SearchView from './components/search/search.jsx'; import SearchView from './components/search/search.jsx';
import SalesForm from './components/sales/sales.jsx'; import SalesForm from './components/sales/sales.jsx';
import TemplateError from './components/404/404.jsx'; import TemplateError from './components/404/404.jsx';
import DeleteMassive from './components/massive/masive_delete.jsx';
import * as Client from './utils/client.jsx'; import * as Client from './utils/client.jsx';
import * as Utils from './utils/utils.jsx'; import * as Utils from './utils/utils.jsx';
...@@ -216,6 +217,11 @@ function renderRootComponent() { ...@@ -216,6 +217,11 @@ function renderRootComponent() {
path='sales/:domainId/mailboxes' path='sales/:domainId/mailboxes'
component={SalesForm} component={SalesForm}
/> />
<Route
path='/deleteMassive'
component={DeleteMassive}
/>
</Route> </Route>
<Route component={NotLoggedIn}> <Route component={NotLoggedIn}>
<IndexRedirect to='login'/> <IndexRedirect to='login'/>
......
...@@ -1855,6 +1855,14 @@ label { ...@@ -1855,6 +1855,14 @@ label {
} }
} }
.noresize {
resize: none;
}
.margin-bottom {
margin-bottom: 20px;
}
// Error Page // Error Page
// scss-lint:enable all // scss-lint:enable all
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