Merge pull request #296 from guillegiu/master
fix bug #288 and add validatios
This commit is contained in:
commit
3b5d23b78b
|
@ -290,7 +290,7 @@ class StaffEditor extends React.Component {
|
|||
API.call({
|
||||
path: '/staff/edit',
|
||||
data: {
|
||||
staffId: this.props.staffId,
|
||||
staffId: (!this.props.myAccount) ? this.props.staffId : null,
|
||||
sendEmailOnNewTicket: (eventType === 'SEND_EMAIL_ON_NEW_TICKET') ? form.sendEmailOnNewTicket * 1 : null,
|
||||
email: (eventType === 'EMAIL') ? form.email : null,
|
||||
password: (eventType === 'PASSWORD') ? form.password : null,
|
||||
|
@ -331,7 +331,7 @@ class StaffEditor extends React.Component {
|
|||
path: '/staff/edit',
|
||||
dataAsForm: true,
|
||||
data: {
|
||||
staffId: this.props.staffId,
|
||||
staffId: (!this.props.myAcount) ? this.props.staffId : null,
|
||||
file: event.target.files[0]
|
||||
}
|
||||
}).then(() => {
|
||||
|
|
|
@ -32,7 +32,7 @@ class AdminPanelMyTickets extends React.Component {
|
|||
{(this.props.error) ? <Message type="error">{i18n('ERROR_RETRIEVING_TICKETS')}</Message> : <TicketList {...this.getProps()}/>}
|
||||
<div style={{textAlign: 'right', marginTop: 10}}>
|
||||
<Button onClick={this.onCreateTicket.bind(this)} type="secondary" size="medium">
|
||||
<Icon size="sm" name="plus"/> Create ticket
|
||||
<Icon size="sm" name="plus"/> {i18n('CREATE_TICKET')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -55,7 +55,7 @@ class AdminPanelMyTickets extends React.Component {
|
|||
<div>
|
||||
<CreateTicketForm onSuccess={this.onCreateTicketSuccess.bind(this)} />
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<Button onClick={ModalContainer.closeModal} type="link">Close</Button>
|
||||
<Button onClick={ModalContainer.closeModal} type="link">{i18n('CLOSE')}</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -9,6 +9,9 @@ import Table from 'core-components/table';
|
|||
import SearchBox from 'core-components/search-box';
|
||||
import Button from 'core-components/button';
|
||||
import Message from 'core-components/message';
|
||||
import Icon from 'core-components/icon';
|
||||
import ModalContainer from 'app-components/modal-container';
|
||||
import MainSignUpWidget from 'app/main/main-signup/main-signup-widget';
|
||||
|
||||
class AdminPanelListUsers extends React.Component {
|
||||
|
||||
|
@ -37,6 +40,11 @@ class AdminPanelListUsers extends React.Component {
|
|||
<Header title={i18n('LIST_USERS')} description={i18n('LIST_USERS_DESCRIPTION')} />
|
||||
<SearchBox className="admin-panel-list-users__search-box" placeholder={i18n('SEARCH_USERS')} onSearch={this.onSearch.bind(this)} />
|
||||
{(this.state.error) ? <Message type="error">{i18n('ERROR_RETRIEVING_USERS')}</Message> : <Table {...this.getTableProps()}/>}
|
||||
<div style={{textAlign: 'right', marginTop: 10}}>
|
||||
<Button onClick={this.onCreateUser.bind(this)} type="secondary" size="medium">
|
||||
<Icon size="sm" name="plus"/> {i18n('ADD_USER')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -149,6 +157,20 @@ class AdminPanelListUsers extends React.Component {
|
|||
}).then(this.onUsersRetrieved.bind(this)).catch(this.onUsersRejected.bind(this));
|
||||
}
|
||||
|
||||
onCreateUser(user) {
|
||||
ModalContainer.openModal(
|
||||
<div className="admin-panel-list-users__add-user-form">
|
||||
<MainSignUpWidget onSuccess={this.onCreateUserSuccess.bind(this)} />
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<Button onClick={ModalContainer.closeModal} type="link">{i18n('CLOSE')}</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
onCreateUserSuccess() {
|
||||
ModalContainer.closeModal();
|
||||
}
|
||||
|
||||
onUsersRetrieved(result) {
|
||||
this.setState({
|
||||
page: result.data.page * 1,
|
||||
|
|
|
@ -21,4 +21,8 @@
|
|||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
&__add-user-form {
|
||||
max-width: 500px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,112 +1,18 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import _ from 'lodash';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
||||
import Captcha from 'app/main/captcha';
|
||||
import SubmitButton from 'core-components/submit-button';
|
||||
import Message from 'core-components/message';
|
||||
import Form from 'core-components/form';
|
||||
import FormField from 'core-components/form-field';
|
||||
import Widget from 'core-components/widget';
|
||||
import Header from 'core-components/header';
|
||||
import MainSignUpWidget from 'app/main/main-signup/main-signup-widget';
|
||||
|
||||
class MainSignUpPageWidget extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: false,
|
||||
email: null
|
||||
};
|
||||
}
|
||||
class MainSignUpPage extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="main-signup-page">
|
||||
<Widget className="signup-widget col-md-6 col-md-offset-3">
|
||||
<Header title={i18n('SIGN_UP')} description={i18n('SIGN_UP_VIEW_DESCRIPTION')} />
|
||||
<Form {...this.getFormProps()}>
|
||||
<div className="signup-widget__inputs">
|
||||
<FormField {...this.getInputProps()} label={i18n('FULL_NAME')} name="name" validation="NAME" required/>
|
||||
<FormField {...this.getInputProps()} label={i18n('EMAIL')} name="email" validation="EMAIL" required/>
|
||||
<FormField {...this.getInputProps(true)} label={i18n('PASSWORD')} name="password" validation="PASSWORD" required/>
|
||||
<FormField {...this.getInputProps(true)} label={i18n('REPEAT_PASSWORD')} name="repeated-password" validation="REPEAT_PASSWORD" required/>
|
||||
</div>
|
||||
<div className="signup-widget__captcha">
|
||||
<Captcha ref="captcha"/>
|
||||
</div>
|
||||
<SubmitButton type="primary">{i18n('SIGN_UP')}</SubmitButton>
|
||||
</Form>
|
||||
|
||||
{this.renderMessage()}
|
||||
</Widget>
|
||||
<MainSignUpWidget {...this.props} className="col-md-6 col-md-offset-3" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderMessage() {
|
||||
switch (this.state.message) {
|
||||
case 'success':
|
||||
return <Message type="success">{i18n('SIGNUP_SUCCESS')}</Message>;
|
||||
case 'fail':
|
||||
return <Message type="error">{i18n('EMAIL_EXISTS')}</Message>;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
getFormProps() {
|
||||
return {
|
||||
loading: this.state.loading,
|
||||
className: 'signup-widget__form',
|
||||
onSubmit: this.onSignupFormSubmit.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getInputProps(password) {
|
||||
return {
|
||||
className: 'signup-widget__input',
|
||||
fieldProps: {
|
||||
size: 'medium',
|
||||
password: password
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onSignupFormSubmit(formState) {
|
||||
const captcha = this.refs.captcha.getWrappedInstance();
|
||||
|
||||
if (!captcha.getValue()) {
|
||||
captcha.focus();
|
||||
} else {
|
||||
this.setState({
|
||||
loading: true
|
||||
});
|
||||
|
||||
API.call({
|
||||
path: '/user/signup',
|
||||
data: _.extend({captcha: captcha.getValue()}, formState)
|
||||
}).then(this.onSignupSuccess.bind(this)).catch(this.onSignupFail.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
onSignupSuccess() {
|
||||
this.setState({
|
||||
loading: false,
|
||||
message: 'success'
|
||||
});
|
||||
}
|
||||
|
||||
onSignupFail() {
|
||||
this.setState({
|
||||
loading: false,
|
||||
message: 'fail'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default MainSignUpPageWidget;
|
||||
export default MainSignUpPage;
|
||||
|
|
|
@ -1,23 +1,3 @@
|
|||
.main-signup-page {
|
||||
min-height: 669px;
|
||||
|
||||
.signup-widget {
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
|
||||
&__form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&__inputs {
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&__captcha {
|
||||
margin: 10px auto 20px;
|
||||
height: 78px;
|
||||
width: 304px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import _ from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
||||
import Captcha from 'app/main/captcha';
|
||||
import SubmitButton from 'core-components/submit-button';
|
||||
import Message from 'core-components/message';
|
||||
import Form from 'core-components/form';
|
||||
import FormField from 'core-components/form-field';
|
||||
import Widget from 'core-components/widget';
|
||||
import Header from 'core-components/header';
|
||||
|
||||
class MainSignUpWidget extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: false,
|
||||
email: null
|
||||
};
|
||||
}
|
||||
static propTypes = {
|
||||
onSuccess: React.PropTypes.func,
|
||||
className: React.PropTypes.string
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Widget className={this.getClass()}>
|
||||
<Header title={i18n('SIGN_UP')} description={i18n('SIGN_UP_VIEW_DESCRIPTION')} />
|
||||
<Form {...this.getFormProps()}>
|
||||
<div className="signup-widget__inputs">
|
||||
<FormField {...this.getInputProps()} label={i18n('FULL_NAME')} name="name" validation="NAME" required/>
|
||||
<FormField {...this.getInputProps()} label={i18n('EMAIL')} name="email" validation="EMAIL" required/>
|
||||
<FormField {...this.getInputProps(true)} label={i18n('PASSWORD')} name="password" validation="PASSWORD" required/>
|
||||
<FormField {...this.getInputProps(true)} label={i18n('REPEAT_PASSWORD')} name="repeated-password" validation="REPEAT_PASSWORD" required/>
|
||||
</div>
|
||||
<div className="signup-widget__captcha">
|
||||
<Captcha ref="captcha"/>
|
||||
</div>
|
||||
<SubmitButton type="primary">{i18n('SIGN_UP')}</SubmitButton>
|
||||
</Form>
|
||||
|
||||
{this.renderMessage()}
|
||||
</Widget>
|
||||
);
|
||||
}
|
||||
|
||||
renderMessage() {
|
||||
switch (this.state.message) {
|
||||
case 'success':
|
||||
return <Message type="success">{i18n('SIGNUP_SUCCESS')}</Message>;
|
||||
case 'fail':
|
||||
return <Message type="error">{i18n('EMAIL_EXISTS')}</Message>;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
getClass() {
|
||||
let classes = {
|
||||
'signup-widget': true,
|
||||
[this.props.className]: this.props.className
|
||||
};
|
||||
return classNames(classes);
|
||||
}
|
||||
|
||||
getFormProps() {
|
||||
return {
|
||||
loading: this.state.loading,
|
||||
className: 'signup-widget__form',
|
||||
onSubmit: this.onSignupFormSubmit.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getInputProps(password) {
|
||||
return {
|
||||
className: 'signup-widget__input',
|
||||
fieldProps: {
|
||||
size: 'medium',
|
||||
password: password
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onSignupFormSubmit(formState) {
|
||||
const captcha = this.refs.captcha.getWrappedInstance();
|
||||
|
||||
if (!captcha.getValue()) {
|
||||
captcha.focus();
|
||||
} else {
|
||||
this.setState({
|
||||
loading: true
|
||||
});
|
||||
|
||||
API.call({
|
||||
path: '/user/signup',
|
||||
data: _.extend({captcha: captcha.getValue()}, formState)
|
||||
}).then(this.onSignupSuccess.bind(this)).catch(this.onSignupFail.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
onSignupSuccess() {
|
||||
this.setState({
|
||||
loading: false,
|
||||
message: 'success'
|
||||
});
|
||||
}
|
||||
|
||||
onSignupFail() {
|
||||
this.setState({
|
||||
loading: false,
|
||||
message: 'fail'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default MainSignUpWidget;
|
|
@ -0,0 +1,19 @@
|
|||
.signup-widget {
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
|
||||
&__form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&__inputs {
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&__captcha {
|
||||
margin: 10px auto 20px;
|
||||
height: 78px;
|
||||
width: 304px;
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ import React from 'react';
|
|||
import Button from 'core-components/button';
|
||||
import Icon from 'core-components/icon';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
|
||||
class FileUploader extends React.Component {
|
||||
static propTypes = {
|
||||
text: React.PropTypes.string,
|
||||
|
@ -11,7 +13,7 @@ class FileUploader extends React.Component {
|
|||
};
|
||||
|
||||
static defaultProps = {
|
||||
text: 'Upload file'
|
||||
text: i18n('UPLOAD_FILE')
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -37,4 +39,4 @@ class FileUploader extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default FileUploader;
|
||||
export default FileUploader;
|
||||
|
|
|
@ -181,6 +181,8 @@ export default {
|
|||
'UPDATE': 'Atualizar',
|
||||
'NEVER': 'Nunca',
|
||||
'HIMSELF': 'ele mesmo',
|
||||
'ADD_USER': 'Adicionar usuário',
|
||||
'UPLOAD_FILE': 'Subir arquivo',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Chamados criados',
|
||||
'CHART_CLOSE': 'Chamados fechados',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': '更新',
|
||||
'NEVER': '从来没有',
|
||||
'HIMSELF': '他自己',
|
||||
'ADD_USER': '添加用户',
|
||||
'UPLOAD_FILE': '上传文件',
|
||||
|
||||
'CHART_CREATE_TICKET': '已創建門票',
|
||||
'CHART_CLOSE': '門票已關閉',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'Aktualisierung',
|
||||
'NEVER': 'Niemals',
|
||||
'HIMSELF': 'selbst',
|
||||
'ADD_USER': 'Benutzer hinzufügen',
|
||||
'UPLOAD_FILE': 'Datei hochladen',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Tickets erstellt',
|
||||
'CHART_CLOSE': 'Tickets geschlossen',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'Update',
|
||||
'NEVER': 'Never',
|
||||
'HIMSELF': 'himself',
|
||||
'ADD_USER': 'Add user',
|
||||
'UPLOAD_FILE': 'Upload file',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Tickets created',
|
||||
'CHART_CLOSE': 'Tickets closed',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'Actualizar',
|
||||
'NEVER': 'Nunca',
|
||||
'HIMSELF': 'si mismo',
|
||||
'ADD_USER': 'Añadir un usuario',
|
||||
'UPLOAD_FILE': 'Subir archivo',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Tickets creados',
|
||||
'CHART_CLOSE': 'Tickets cerrados',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'Mettre à jour',
|
||||
'NEVER': 'Jamais',
|
||||
'HIMSELF': 'lui-même',
|
||||
'ADD_USER': 'Ajouter un utilisateur',
|
||||
'UPLOAD_FILE': 'Téléverser un fichier',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Tickets créés',
|
||||
'CHART_CLOSE': 'Tickets fermés',
|
||||
|
|
|
@ -182,6 +182,8 @@
|
|||
'UPDATE': 'Ενημέρωση',
|
||||
'NEVER': 'Ποτέ',
|
||||
'HIMSELF': 'ο ίδιος',
|
||||
'ADD_USER': 'Πρόσθεσε χρήστη',
|
||||
'UPLOAD_FILE': 'Ανέβασμα αρχείου',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Τα εισιτήρια δημιουργήθηκαν',
|
||||
'CHART_CLOSE': 'Τα εισιτήρια κλείσανε',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'अद्यतन',
|
||||
'NEVER': 'कभी नहीँ',
|
||||
'HIMSELF': 'स्वयं',
|
||||
'ADD_USER': 'उपयोगकर्ता जोड़ें',
|
||||
'UPLOAD_FILE': 'दस्तावेज अपलोड करें',
|
||||
|
||||
'CHART_CREATE_TICKET': 'टिकट बनाया',
|
||||
'CHART_CLOSE': 'टिकट बंद कर दिया',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'Aggiornare',
|
||||
'NEVER': 'Mai',
|
||||
'HIMSELF': 'lui stesso',
|
||||
'ADD_USER': 'Aggiungi utente',
|
||||
'UPLOAD_FILE': 'Caricare un file',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Tickets creato',
|
||||
'CHART_CLOSE': 'Tickets chiuso',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': '更新',
|
||||
'NEVER': '決して',
|
||||
'HIMSELF': '彼自身',
|
||||
'ADD_USER': 'ユーザーを追加する',
|
||||
'UPLOAD_FILE': 'ファイルをアップロードする',
|
||||
|
||||
'CHART_CREATE_TICKET': '作成されたチケット',
|
||||
'CHART_CLOSE': 'チケットが閉じられました',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'Update',
|
||||
'NEVER': 'Nooit',
|
||||
'HIMSELF': 'zichzelf',
|
||||
'ADD_USER': 'Voeg gebruiker toe',
|
||||
'UPLOAD_FILE': 'Upload bestand',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Aangemaakte incidenten',
|
||||
'CHART_CLOSE': 'Gesloten incidenten',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'Actualizar',
|
||||
'NEVER': 'Nunca',
|
||||
'HIMSELF': 'ele mesmo',
|
||||
'ADD_USER': 'Adicionar usuário',
|
||||
'UPLOAD_FILE': 'Subir arquivo',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Ingressos criados',
|
||||
'CHART_CLOSE': 'Ingressos fechados',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'Обновить',
|
||||
'NEVER': 'Никогда',
|
||||
'HIMSELF': 'сам',
|
||||
'ADD_USER': 'Добавить пользователя',
|
||||
'UPLOAD_FILE': 'Загрузить файл',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Билеты создано',
|
||||
'CHART_CLOSE': ' Билеты закрыты',
|
||||
|
|
|
@ -182,6 +182,8 @@ export default {
|
|||
'UPDATE': 'Güncelleştirme',
|
||||
'NEVER': 'Asla',
|
||||
'HIMSELF': 'kendisi',
|
||||
'ADD_USER': 'Kullanıcı Ekle',
|
||||
'UPLOAD_FILE': 'Dosya yükleme',
|
||||
|
||||
'CHART_CREATE_TICKET': 'Biletler oluşturuldu',
|
||||
'CHART_CLOSE': 'Biletler kapandı',
|
||||
|
|
|
@ -36,7 +36,21 @@ class EditStaffController extends Controller {
|
|||
public function validations() {
|
||||
return [
|
||||
'permission' => 'staff_1',
|
||||
'requestData' => []
|
||||
'requestData' => [
|
||||
'email' => [
|
||||
'validation' => DataValidator::oneOf(DataValidator::email(), DataValidator::falseVal()),
|
||||
'error' => ERRORS::INVALID_EMAIL
|
||||
],
|
||||
'password' => [
|
||||
'validation' => DataValidator::oneOf(DataValidator::length(5, 200), DataValidator::falseVal()),
|
||||
'error' => ERRORS::INVALID_PASSWORD
|
||||
],
|
||||
'level' => [
|
||||
'validation' => DataValidator::oneOf(DataValidator::between(1, 3, true), DataValidator::falseVal()),
|
||||
'error' => ERRORS::INVALID_LEVEL
|
||||
]
|
||||
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ class SignUpController extends Controller {
|
|||
throw new Exception(ERRORS::ALREADY_BANNED);
|
||||
}
|
||||
|
||||
if (!Setting::getSetting('registration')->value && $apiKey->isNull() && !$this->csvImported) {
|
||||
if (!Setting::getSetting('registration')->value && $apiKey->isNull() && !Controller::isStaffLogged(2) && !$this->csvImported) {
|
||||
throw new Exception(ERRORS::NO_PERMISSION);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue