Merged in fixes-deploy-bloque-3 (pull request #134)
Fixes deploy bloque 3
This commit is contained in:
commit
751876bd11
|
@ -55,24 +55,24 @@
|
|||
"dependencies": {
|
||||
"app-module-path": "^1.0.3",
|
||||
"chart.js": "^2.4.0",
|
||||
"classnames": "^2.1.3",
|
||||
"draft-js": "^0.8.1",
|
||||
"draft-js-export-html": "^0.4.0",
|
||||
"classnames": "^2.2.5",
|
||||
"draft-js": "^0.10.0",
|
||||
"draft-js-export-html": "^0.5.2",
|
||||
"jquery": "^2.1.4",
|
||||
"keycode": "^2.1.4",
|
||||
"localStorage": "^1.0.3",
|
||||
"lodash": "^3.10.0",
|
||||
"messageformat": "^0.2.2",
|
||||
"react": "^15.0.1",
|
||||
"react": "^15.4.2",
|
||||
"react-chartjs-2": "^2.0.0",
|
||||
"react-document-title": "^1.0.2",
|
||||
"react-dom": "^15.0.1",
|
||||
"react-dom": "^15.4.2",
|
||||
"react-draft-wysiwyg": "^1.7.6",
|
||||
"react-google-recaptcha": "^0.5.2",
|
||||
"react-motion": "^0.4.7",
|
||||
"react-redux": "^4.4.5",
|
||||
"react-router": "^2.4.0",
|
||||
"react-router-redux": "^4.0.5",
|
||||
"react-rte-browserify": "^0.5.0",
|
||||
"redux": "^3.5.2",
|
||||
"redux-promise-middleware": "^3.3.2"
|
||||
}
|
||||
|
|
|
@ -102,6 +102,7 @@ describe('Session Actions,', function () {
|
|||
});
|
||||
APICallMock.call.reset();
|
||||
storeMock.dispatch.reset();
|
||||
sessionStoreMock.isLoggedIn.returns(true)
|
||||
});
|
||||
|
||||
after(function () {
|
||||
|
@ -114,7 +115,7 @@ describe('Session Actions,', function () {
|
|||
}));
|
||||
});
|
||||
|
||||
it('should return CHECK_SESSION and dispatch SESSION_ACTIVE if session is active', function () {
|
||||
it('should return CHECK_SESSION and dispatch SESSION_CHECKED if session is active', function () {
|
||||
APICallMock.call.returns({
|
||||
then: function (resolve) {
|
||||
resolve({
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
|
||||
export default {
|
||||
openModal(content) {
|
||||
openModal(config) {
|
||||
return {
|
||||
type: 'OPEN_MODAL',
|
||||
payload: content
|
||||
payload: config
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -4,20 +4,36 @@ import sessionStore from 'lib-app/session-store';
|
|||
import store from 'app/store';
|
||||
|
||||
export default {
|
||||
|
||||
login(loginData) {
|
||||
return {
|
||||
type: 'LOGIN',
|
||||
payload: API.call({
|
||||
path: '/user/login',
|
||||
data: loginData
|
||||
}).then((result) => {
|
||||
store.dispatch(this.getUserData(result.data.userId, result.data.token, result.data.staff));
|
||||
|
||||
if(result.data.staff) {
|
||||
store.dispatch(AdminDataActions.retrieveCustomResponses());
|
||||
}
|
||||
payload: new Promise((resolve, reject) => {
|
||||
let loginCall = () => {
|
||||
API.call({
|
||||
path: '/user/login',
|
||||
data: loginData
|
||||
}).then((result) => {
|
||||
store.dispatch(this.getUserData(result.data.userId, result.data.token, result.data.staff));
|
||||
|
||||
return result;
|
||||
if(result.data.staff) {
|
||||
store.dispatch(AdminDataActions.retrieveCustomResponses());
|
||||
}
|
||||
|
||||
resolve(result);
|
||||
}).catch((result) => {
|
||||
if(result.message === 'SESSION_EXISTS') {
|
||||
API.call({
|
||||
path: '/user/logout',
|
||||
data: {}
|
||||
}).then(loginCall);
|
||||
} else {
|
||||
reject(result);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
loginCall();
|
||||
})
|
||||
};
|
||||
},
|
||||
|
@ -81,23 +97,31 @@ export default {
|
|||
initSession() {
|
||||
return {
|
||||
type: 'CHECK_SESSION',
|
||||
payload: API.call({
|
||||
path: '/user/check-session',
|
||||
data: {}
|
||||
}).then((result) => {
|
||||
if (!result.data.sessionActive) {
|
||||
if (sessionStore.isRememberDataExpired()) {
|
||||
payload: new Promise((resolve, reject) => {
|
||||
API.call({
|
||||
path: '/user/check-session',
|
||||
data: {}
|
||||
}).then((result) => {
|
||||
if (!result.data.sessionActive) {
|
||||
if (sessionStore.isRememberDataExpired()) {
|
||||
store.dispatch({
|
||||
type: 'LOGOUT_FULFILLED'
|
||||
});
|
||||
} else {
|
||||
store.dispatch(this.autoLogin());
|
||||
}
|
||||
|
||||
resolve(result);
|
||||
} else if(sessionStore.isLoggedIn()) {
|
||||
store.dispatch({
|
||||
type: 'LOGOUT_FULFILLED'
|
||||
type: 'SESSION_CHECKED'
|
||||
});
|
||||
|
||||
resolve(result);
|
||||
} else {
|
||||
store.dispatch(this.autoLogin());
|
||||
reject(result);
|
||||
}
|
||||
} else {
|
||||
store.dispatch({
|
||||
type: 'SESSION_CHECKED'
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ class ActivityRow extends React.Component {
|
|||
</Link>
|
||||
</span>
|
||||
<span className="activity-row__message"> {i18n('ACTIVITY_' + this.props.type)} </span>
|
||||
{_.includes(ticketRelatedTypes, this.props.type) ? this.renderTicketNumber() : null}
|
||||
{_.includes(ticketRelatedTypes, this.props.type) ? this.renderTicketNumber() : this.props.to}
|
||||
<span className="separator" />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
&__ticket-link {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
margin: 15px;
|
||||
}
|
||||
.separator {
|
||||
margin: 15px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import React from 'react';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import ModalContainer from 'app-components/modal-container';
|
||||
|
||||
import Button from 'core-components/button';
|
||||
import Input from 'core-components/input';
|
||||
import ModalContainer from 'app-components/modal-container';
|
||||
import Icon from 'core-components/icon';
|
||||
|
||||
|
||||
class AreYouSure extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -26,7 +29,8 @@ class AreYouSure extends React.Component {
|
|||
|
||||
static openModal(description, onYes, type) {
|
||||
ModalContainer.openModal(
|
||||
<AreYouSure description={description} onYes={onYes} type={type}/>
|
||||
<AreYouSure description={description} onYes={onYes} type={type}/>,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -40,21 +44,25 @@ class AreYouSure extends React.Component {
|
|||
<div className="are-you-sure__header" id="are-you-sure__header">
|
||||
{i18n('ARE_YOU_SURE')}
|
||||
</div>
|
||||
<span className="are-you-sure__close-icon" onClick={this.onNo.bind(this)}>
|
||||
<Icon name="times" size="2x"/>
|
||||
</span>
|
||||
<div className="are-you-sure__description" id="are-you-sure__description">
|
||||
{this.props.description || (this.props.type === 'secure' && i18n('PLEASE_CONFIRM_PASSWORD'))}
|
||||
</div>
|
||||
{(this.props.type === 'secure') ? this.renderPassword() : null}
|
||||
<span className="separator" />
|
||||
<div className="are-you-sure__buttons">
|
||||
<div className="are-you-sure__yes-button">
|
||||
<Button type="secondary" size="small" onClick={this.onYes.bind(this)} ref="yesButton" tabIndex="2">
|
||||
{i18n('YES')}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="are-you-sure__no-button">
|
||||
<Button type="link" size="auto" onClick={this.onNo.bind(this)} tabIndex="2">
|
||||
{i18n('CANCEL')}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="are-you-sure__yes-button">
|
||||
<Button type="secondary" size="small" onClick={this.onYes.bind(this)} ref="yesButton" tabIndex="2">
|
||||
{i18n('YES')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -62,7 +70,7 @@ class AreYouSure extends React.Component {
|
|||
|
||||
renderPassword() {
|
||||
return (
|
||||
<Input className="are-you-sure__password" password placeholder="password" name="password" value={this.state.password} onChange={this.onPasswordChange.bind(this)} onKeyDown={this.onInputKeyDown.bind(this)}/>
|
||||
<Input className="are-you-sure__password" password placeholder="password" name="password" ref="password" size="medium" value={this.state.password} onChange={this.onPasswordChange.bind(this)} onKeyDown={this.onInputKeyDown.bind(this)}/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -79,7 +87,11 @@ class AreYouSure extends React.Component {
|
|||
}
|
||||
|
||||
onYes() {
|
||||
if (this.props.type === 'default' || this.state.password){
|
||||
if (this.props.type === 'secure' && !this.state.password) {
|
||||
this.refs.password.focus()
|
||||
}
|
||||
|
||||
if (this.props.type === 'default' || this.state.password) {
|
||||
this.closeModal();
|
||||
|
||||
if (this.props.onYes) {
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
@import "../scss/vars";
|
||||
|
||||
.are-you-sure {
|
||||
width: 400px;
|
||||
text-align: center;
|
||||
width: 800px;
|
||||
text-align: left;
|
||||
|
||||
&__header {
|
||||
color: $primary-red;
|
||||
font-size: $font-size--xl;
|
||||
background-color: $secondary-blue;
|
||||
border-top-right-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
color: white;
|
||||
font-size: $font-size--lg;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
&__description {
|
||||
color: $dark-grey;
|
||||
font-size: $font-size--md;
|
||||
margin-bottom: 50px;
|
||||
padding: 14px 5% 0;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
margin: 0 auto;
|
||||
margin-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&__yes-button,
|
||||
|
@ -30,7 +35,25 @@
|
|||
|
||||
&__password {
|
||||
margin: 0 auto;
|
||||
margin-top: -30px;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
&__close-icon {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.separator {
|
||||
width: 90%;
|
||||
margin: 30px auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.are-you-sure {
|
||||
width: auto;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import keyCode from 'keycode';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import store from 'app/store';
|
||||
import ModalActions from 'actions/modal-actions';
|
||||
|
@ -8,11 +9,12 @@ import Modal from 'core-components/modal';
|
|||
|
||||
class ModalContainer extends React.Component {
|
||||
|
||||
static openModal(content) {
|
||||
static openModal(content, noPadding) {
|
||||
store.dispatch(
|
||||
ModalActions.openModal(
|
||||
content
|
||||
)
|
||||
ModalActions.openModal({
|
||||
content,
|
||||
noPadding
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -48,7 +50,7 @@ class ModalContainer extends React.Component {
|
|||
|
||||
renderModal() {
|
||||
return (
|
||||
<Modal content={this.props.modal.content} />
|
||||
<Modal content={this.props.modal.content} noPadding={this.props.modal.noPadding}/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class PeopleList extends React.Component {
|
|||
name: React.PropTypes.node,
|
||||
assignedTickets: React.PropTypes.number,
|
||||
closedTickets: React.PropTypes.number,
|
||||
lastLogin: React.PropTypes.number
|
||||
lastLogin: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.string])
|
||||
})),
|
||||
pageSize: React.PropTypes.number,
|
||||
page: React.PropTypes.number,
|
||||
|
|
|
@ -134,10 +134,10 @@ class Stats extends React.Component {
|
|||
API.call({
|
||||
path: '/system/get-stats',
|
||||
data: this.getApiCallData(periodName)
|
||||
}).then(this.onRetrieveSuccess.bind(this, period));
|
||||
}).then(this.onRetrieveSuccess.bind(this));
|
||||
}
|
||||
|
||||
onRetrieveSuccess(period, result) {
|
||||
onRetrieveSuccess(result) {
|
||||
let newStats = this.getDefaultStats();
|
||||
|
||||
let newStrokes = this.getStrokes().map((name) => {
|
||||
|
@ -149,7 +149,7 @@ class Stats extends React.Component {
|
|||
|
||||
let realPeriod = result.data.length / this.getStrokes().length;
|
||||
|
||||
result.data.map((item) => {
|
||||
result.data.reverse().map((item) => {
|
||||
newStats[item.type] += item.value * 1;
|
||||
|
||||
newStrokes[ ID[item.type] ].values.push({
|
||||
|
|
|
@ -46,9 +46,11 @@ class TicketEvent extends React.Component {
|
|||
}
|
||||
|
||||
renderStaffPic() {
|
||||
let profilePicName = this.props.author.profilePic;
|
||||
|
||||
return (
|
||||
<div className="ticket-event__staff-pic">
|
||||
<img src={this.props.author.profilePic} className="ticket-event__staff-pic-img" />
|
||||
<img src={(profilePicName) ? API.getFileLink(profilePicName) : (API.getURL() + '/images/profile.png')} className="ticket-event__staff-pic-img" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import RichTextEditor from 'react-rte-browserify';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
@ -16,6 +16,7 @@ import DropDown from 'core-components/drop-down';
|
|||
import Button from 'core-components/button';
|
||||
import Message from 'core-components/message';
|
||||
import Icon from 'core-components/icon';
|
||||
import TextEditor from 'core-components/text-editor';
|
||||
|
||||
class TicketViewer extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -37,7 +38,7 @@ class TicketViewer extends React.Component {
|
|||
|
||||
state = {
|
||||
loading: false,
|
||||
commentValue: RichTextEditor.createEmptyValue(),
|
||||
commentValue: TextEditor.createEmpty(),
|
||||
commentEdited: false
|
||||
};
|
||||
|
||||
|
@ -178,7 +179,7 @@ class TicketViewer extends React.Component {
|
|||
|
||||
renderTicketEvent(options, index) {
|
||||
return (
|
||||
<TicketEvent {...options} key={index} />
|
||||
<TicketEvent {...options} author={(!_.isEmpty(options.author)) ? options.author : this.props.ticket.author} key={index} />
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -190,7 +191,7 @@ class TicketViewer extends React.Component {
|
|||
<div className="ticket-viewer__response-field row">
|
||||
<Form {...this.getCommentFormProps()}>
|
||||
<FormField name="content" validation="TEXT_AREA" required field="textarea" />
|
||||
<FormField name="file" field="file"/>
|
||||
{(this.props.allowAttachments) ? <FormField name="file" field="file"/> : null}
|
||||
<SubmitButton>{i18n('RESPOND_TICKET')}</SubmitButton>
|
||||
</Form>
|
||||
</div>
|
||||
|
@ -304,7 +305,7 @@ class TicketViewer extends React.Component {
|
|||
onCustomResponsesChanged({index}) {
|
||||
let replaceContentWithCustomResponse = () => {
|
||||
this.setState({
|
||||
commentValue: RichTextEditor.createValueFromString(this.props.customResponses[index-1].content || '', 'html'),
|
||||
commentValue: TextEditor.getEditorStateFromHTML(this.props.customResponses[index-1].content || ''),
|
||||
commentEdited: false
|
||||
});
|
||||
};
|
||||
|
@ -333,7 +334,9 @@ class TicketViewer extends React.Component {
|
|||
onCommentSuccess() {
|
||||
this.setState({
|
||||
loading: false,
|
||||
commentError: false
|
||||
commentValue: TextEditor.createEmpty(),
|
||||
commentError: false,
|
||||
commentEdited: false
|
||||
});
|
||||
|
||||
this.onTicketModification();
|
||||
|
@ -353,4 +356,9 @@ class TicketViewer extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default TicketViewer;
|
||||
export default connect((store) => {
|
||||
return {
|
||||
allowAttachments: store.config['allow-attachments'],
|
||||
userSystemEnabled: store.config['user-system-enabled']
|
||||
};
|
||||
})(TicketViewer);
|
||||
|
|
|
@ -25,7 +25,7 @@ class AdminPanelStaffWidget extends React.Component {
|
|||
</div>
|
||||
</div>
|
||||
<div className="admin-panel-staff-widget__profile-pic-wrapper">
|
||||
<img className="admin-panel-staff-widget__profile-pic" src={(this.props.session.userProfilePic) ? API.getFileLink(this.props.session.userProfilePic) : (API.getURL() + '/images/logo.png')} />
|
||||
<img className="admin-panel-staff-widget__profile-pic" src={(this.props.session.userProfilePic) ? API.getFileLink(this.props.session.userProfilePic) : (API.getURL() + '/images/profile.png')} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||
import _ from 'lodash';
|
||||
import {connect} from 'react-redux';
|
||||
import {browserHistory} from 'react-router';
|
||||
import RichTextEditor from 'react-rte-browserify';
|
||||
|
||||
import ArticlesActions from 'actions/articles-actions';
|
||||
import SessionStore from 'lib-app/session-store';
|
||||
|
@ -17,6 +16,7 @@ import Button from 'core-components/button';
|
|||
import Form from 'core-components/form';
|
||||
import FormField from 'core-components/form-field';
|
||||
import SubmitButton from 'core-components/submit-button';
|
||||
import TextEditor from 'core-components/text-editor';
|
||||
|
||||
class AdminPanelViewArticle extends React.Component {
|
||||
|
||||
|
@ -117,7 +117,7 @@ class AdminPanelViewArticle extends React.Component {
|
|||
editable: true,
|
||||
form: {
|
||||
title: article.title,
|
||||
content: RichTextEditor.createValueFromString(article.content, 'html')
|
||||
content: TextEditor.getEditorStateFromHTML(article.content)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ class AdminPanelMyAccount extends React.Component {
|
|||
getEditorProps() {
|
||||
return {
|
||||
myAccount: true,
|
||||
staffId: this.props.userId,
|
||||
staffId: this.props.userId * 1,
|
||||
name: this.props.userName,
|
||||
email: this.props.userEmail,
|
||||
profilePic: this.props.userProfilePic,
|
||||
level: this.props.userLevel,
|
||||
level: this.props.userLevel * 1,
|
||||
departments: this.props.userDepartments,
|
||||
onChange: () => this.props.dispatch(SessionActions.getUserData(null, null, true))
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ class AdminPanelStats extends React.Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<div class="admin-panel-stats">
|
||||
<div className="admin-panel-stats">
|
||||
<Header title={i18n('STATISTICS')} description={i18n('STATISTICS_DESCRIPTION')}/>
|
||||
<Stats type="general"/>
|
||||
</div>
|
||||
|
|
|
@ -9,6 +9,7 @@ import AreYouSure from 'app-components/are-you-sure';
|
|||
import ModalContainer from 'app-components/modal-container';
|
||||
|
||||
import Message from 'core-components/message';
|
||||
import InfoTooltip from 'core-components/info-tooltip';
|
||||
import Button from 'core-components/button';
|
||||
import FileUploader from 'core-components/file-uploader';
|
||||
import Header from 'core-components/header';
|
||||
|
@ -21,6 +22,7 @@ class AdminPanelAdvancedSettings extends React.Component {
|
|||
|
||||
state = {
|
||||
loading: true,
|
||||
messageTitle: null,
|
||||
messageType: '',
|
||||
messageContent: '',
|
||||
keyName: '',
|
||||
|
@ -42,7 +44,9 @@ class AdminPanelAdvancedSettings extends React.Component {
|
|||
<div className="col-md-12">
|
||||
<div className="col-md-6">
|
||||
<div className="admin-panel-advanced-settings__user-system-enabled">
|
||||
<span className="admin-panel-advanced-settings__text">{i18n('ENABLE_USER_SYSTEM')}</span>
|
||||
<span className="admin-panel-advanced-settings__text">
|
||||
{i18n('ENABLE_USER_SYSTEM')} <InfoTooltip text={i18n('ENABLE_USER_SYSTEM_DESCRIPTION')} />
|
||||
</span>
|
||||
<ToggleButton className="admin-panel-advanced-settings__toggle-button" value={this.props.config['user-system-enabled']} onChange={this.onToggleButtonUserSystemChange.bind(this)}/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -57,19 +61,17 @@ class AdminPanelAdvancedSettings extends React.Component {
|
|||
<span className="separator" />
|
||||
</div>
|
||||
<div className="col-md-12">
|
||||
<div className="col-md-3">
|
||||
<div className="admin-panel-advanced-settings__text">{i18n('INCLUDE_USERS_VIA_CSV')}</div>
|
||||
<div className="col-md-4">
|
||||
<div className="admin-panel-advanced-settings__text">
|
||||
{i18n('INCLUDE_USERS_VIA_CSV')} <InfoTooltip text={i18n('CSV_DESCRIPTION')} />
|
||||
</div>
|
||||
<FileUploader className="admin-panel-advanced-settings__button" text="Upload" onChange={this.onImportCSV.bind(this)}/>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="admin-panel-advanced-settings__text">{i18n('INCLUDE_DATABASE_VIA_SQL')}</div>
|
||||
<FileUploader className="admin-panel-advanced-settings__button" text="Upload" onChange={this.onImportSQL.bind(this)}/>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="col-md-4">
|
||||
<div className="admin-panel-advanced-settings__text">{i18n('BACKUP_DATABASE')}</div>
|
||||
<Button className="admin-panel-advanced-settings__button" type="secondary" size="medium" onClick={this.onBackupDatabase.bind(this)}>Download</Button>
|
||||
</div>
|
||||
<div className="col-md-3">
|
||||
<div className="col-md-4">
|
||||
<div className="admin-panel-advanced-settings__text">{i18n('DELETE_ALL_USERS')}</div>
|
||||
<Button className="admin-panel-advanced-settings__button" size="medium" onClick={this.onDeleteAllUsers.bind(this)}>Delete</Button>
|
||||
</div>
|
||||
|
@ -93,7 +95,7 @@ class AdminPanelAdvancedSettings extends React.Component {
|
|||
|
||||
renderMessage() {
|
||||
return (
|
||||
<Message type={this.state.messageType}>{this.state.messageContent}</Message>
|
||||
<Message type={this.state.messageType} title={this.state.messageTitle}>{this.state.messageContent}</Message>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -197,10 +199,11 @@ class AdminPanelAdvancedSettings extends React.Component {
|
|||
}).then(() => {
|
||||
this.setState({
|
||||
messageType: 'success',
|
||||
messageTitle: null,
|
||||
messageContent: this.props.config['user-system-enabled'] ? i18n('USER_SYSTEM_DISABLED') : i18n('USER_SYSTEM_ENABLED')
|
||||
});
|
||||
this.props.dispatch(ConfigActions.updateData());
|
||||
}).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_UPDATING_SETTINGS')}));
|
||||
}).catch(() => this.setState({messageType: 'error', messageTitle: null, messageContent: i18n('ERROR_UPDATING_SETTINGS')}));
|
||||
}
|
||||
|
||||
onAreYouSureRegistrationOk(password) {
|
||||
|
@ -212,42 +215,39 @@ class AdminPanelAdvancedSettings extends React.Component {
|
|||
}).then(() => {
|
||||
this.setState({
|
||||
messageType: 'success',
|
||||
messageTitle: null,
|
||||
messageContent: this.props.config['registration'] ? i18n('REGISTRATION_DISABLED') : i18n('REGISTRATION_ENABLED')
|
||||
});
|
||||
this.props.dispatch(ConfigActions.updateData());
|
||||
}).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_UPDATING_SETTINGS')}));
|
||||
}).catch(() => this.setState({messageType: 'error', messageTitle: null, messageContent: i18n('ERROR_UPDATING_SETTINGS')}));
|
||||
}
|
||||
|
||||
onImportCSV(event) {
|
||||
AreYouSure.openModal(null, this.onAreYouSureCSVOk.bind(this, event.target.value), 'secure');
|
||||
}
|
||||
|
||||
onImportSQL(event) {
|
||||
AreYouSure.openModal(null, this.onAreYouSureSQLOk.bind(this, event.target.value), 'secure');
|
||||
}
|
||||
|
||||
onAreYouSureCSVOk(file, password) {
|
||||
API.call({
|
||||
path: '/system/import-csv',
|
||||
data: {
|
||||
file: file,
|
||||
password: password
|
||||
}
|
||||
})
|
||||
.then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_CSV_DESCRIPTION')}))
|
||||
.catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_CSV_DESCRIPTION')}));
|
||||
}
|
||||
|
||||
onAreYouSureSQLOk(file, password) {
|
||||
API.call({
|
||||
path: '/system/import-sql',
|
||||
path: '/system/csv-import',
|
||||
dataAsForm: true,
|
||||
data: {
|
||||
file: file,
|
||||
password: password
|
||||
}
|
||||
})
|
||||
.then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_IMPORTING_SQL_DESCRIPTION')}))
|
||||
.catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_IMPORTING_SQL_DESCRIPTION')}));
|
||||
.then((result) => this.setState({
|
||||
messageType: 'success',
|
||||
messageTitle: i18n('SUCCESS_IMPORTING_CSV_DESCRIPTION'),
|
||||
messageContent: (result.data.length) ? (
|
||||
<div>
|
||||
{i18n('ERRORS_FOUND')}
|
||||
<ul>
|
||||
{result.data.map((error) => <li>{error}</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
) : null
|
||||
}))
|
||||
.catch(() => this.setState({messageType: 'error', messageTitle: null, messageContent: i18n('INVALID_FILE')}));
|
||||
}
|
||||
|
||||
onBackupDatabase() {
|
||||
|
@ -275,8 +275,8 @@ class AdminPanelAdvancedSettings extends React.Component {
|
|||
data: {
|
||||
password: password
|
||||
}
|
||||
}).then(() => this.setState({messageType: 'success', messageContent: i18n('SUCCESS_DELETING_ALL_USERS')}
|
||||
)).catch(() => this.setState({messageType: 'error', messageContent: i18n('ERROR_DELETING_ALL_USERS')}));
|
||||
}).then(() => this.setState({messageType: 'success', messageTitle: null, messageContent: i18n('SUCCESS_DELETING_ALL_USERS')}
|
||||
)).catch(() => this.setState({messageType: 'error', messageTitle: null, messageContent: i18n('ERROR_DELETING_ALL_USERS')}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import RichTextEditor from 'react-rte-browserify';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
@ -15,6 +14,7 @@ import Loading from 'core-components/loading';
|
|||
import Form from 'core-components/form';
|
||||
import FormField from 'core-components/form-field';
|
||||
import SubmitButton from 'core-components/submit-button';
|
||||
import TextEditor from 'core-components/text-editor';
|
||||
|
||||
class AdminPanelEmailTemplates extends React.Component {
|
||||
|
||||
|
@ -28,7 +28,7 @@ class AdminPanelEmailTemplates extends React.Component {
|
|||
language: 'en',
|
||||
form: {
|
||||
title: '',
|
||||
content: RichTextEditor.createEmptyValue()
|
||||
content: TextEditor.createEmpty()
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -182,7 +182,7 @@ class AdminPanelEmailTemplates extends React.Component {
|
|||
language = language || this.state.language;
|
||||
|
||||
form.title = (items[index] && items[index][language].subject) || '';
|
||||
form.content = RichTextEditor.createValueFromString((items[index] && items[index][language].body) || '', 'html');
|
||||
form.content = TextEditor.getEditorStateFromHTML((items[index] && items[index][language].body) || '');
|
||||
|
||||
this.setState({
|
||||
selectedIndex: index,
|
||||
|
|
|
@ -167,7 +167,7 @@ class AdminPanelSystemPreferences extends React.Component {
|
|||
'recaptcha-private': form.reCaptchaPrivate,
|
||||
'url': form['url'],
|
||||
'title': form['title'],
|
||||
'layout': form['layout'] == 1 ? 'Full width' : 'Boxed',
|
||||
'layout': form['layout'] ? 'full-width' : 'boxed',
|
||||
'time-zone': form['time-zone'],
|
||||
'no-reply-email': form['no-reply-email'],
|
||||
'smtp-host': form['smtp-host'],
|
||||
|
@ -213,15 +213,15 @@ class AdminPanelSystemPreferences extends React.Component {
|
|||
'reCaptchaPrivate': result.data.reCaptchaPrivate,
|
||||
'url': result.data['url'],
|
||||
'title': result.data['title'],
|
||||
'layout': result.data['layout'] == 'full-width' ? 1 : 0,
|
||||
'layout': (result.data['layout'] == 'full-width') ? 1 : 0,
|
||||
'time-zone': result.data['time-zone'],
|
||||
'no-reply-email': result.data['no-reply-email'],
|
||||
'smtp-host': result.data['smtp-host'],
|
||||
'smtp-port': result.data['smtp-port'],
|
||||
'smtp-user': result.data['smtp-user'],
|
||||
'smtp-pass': '',
|
||||
'maintenance-mode': result.data['maintenance-mode'],
|
||||
'allow-attachments': result.data['allow-attachments'],
|
||||
'maintenance-mode': !!(result.data['maintenance-mode'] * 1),
|
||||
'allow-attachments': !!(result.data['allow-attachments'] * 1),
|
||||
'max-size': result.data['max-size'],
|
||||
'allowedLanguages': result.data.allowedLanguages.map(lang => (_.indexOf(languageKeys, lang))),
|
||||
'supportedLanguages': result.data.supportedLanguages.map(lang => (_.indexOf(languageKeys, lang)))
|
||||
|
|
|
@ -17,6 +17,10 @@ class AddStaffModal extends React.Component {
|
|||
closeModal: React.PropTypes.func
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
onSuccess: React.PropTypes.func
|
||||
};
|
||||
|
||||
state = {
|
||||
loading: false,
|
||||
errors: {},
|
||||
|
@ -78,7 +82,13 @@ class AddStaffModal extends React.Component {
|
|||
level: form.level + 1,
|
||||
departments: JSON.stringify(departments)
|
||||
}
|
||||
}).then(this.context.closeModal).catch((result) => {
|
||||
}).then(() => {
|
||||
this.context.closeModal();
|
||||
|
||||
if(this.props.onSuccess) {
|
||||
this.props.onSuccess();
|
||||
}
|
||||
}).catch((result) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
error: result.message
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import {connect} from 'react-redux';
|
||||
import RichTextEditor from 'react-rte-browserify';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
@ -31,7 +30,6 @@ class AdminPanelDepartments extends React.Component {
|
|||
errors: {},
|
||||
form: {
|
||||
title: '',
|
||||
content: RichTextEditor.createEmptyValue(),
|
||||
language: 'en'
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
&__update-name-button {
|
||||
float: left;
|
||||
min-width: 156px;
|
||||
}
|
||||
|
||||
&__optional-buttons {
|
||||
|
|
|
@ -26,10 +26,7 @@ class AdminPanelStaffMembers extends React.Component {
|
|||
};
|
||||
|
||||
componentDidMount() {
|
||||
API.call({
|
||||
path: '/staff/get-all',
|
||||
data: {}
|
||||
}).then(this.onStaffRetrieved.bind(this));
|
||||
this.retrieveStaffMembers();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -48,7 +45,7 @@ class AdminPanelStaffMembers extends React.Component {
|
|||
}
|
||||
|
||||
onAddNewStaff() {
|
||||
ModalContainer.openModal(<AddStaffModal />);
|
||||
ModalContainer.openModal(<AddStaffModal onSuccess={this.retrieveStaffMembers.bind(this)} />);
|
||||
}
|
||||
|
||||
getDepartmentDropdownProps() {
|
||||
|
@ -71,13 +68,14 @@ class AdminPanelStaffMembers extends React.Component {
|
|||
if(!this.state.selectedDepartment) {
|
||||
staffList = this.state.staffList;
|
||||
} else {
|
||||
staffList = _.filter(this.state.staffList, (o) => {
|
||||
return _.findIndex(o.departments, {id: this.state.selectedDepartment}) !== -1;
|
||||
})
|
||||
staffList = _.filter(this.state.staffList, (staff) => {
|
||||
return _.findIndex(staff.departments, {id: this.state.selectedDepartment}) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
return staffList.map(staff => {
|
||||
return _.extend({}, staff, {
|
||||
profilePic: (staff.profilePic) ? API.getFileLink(staff.profilePic) : (API.getURL() + '/images/profile.png'),
|
||||
name: (
|
||||
<Link className="admin-panel-staff-members__link" to={'/admin/panel/staff/view-staff/' + staff.id}>
|
||||
{staff.name}
|
||||
|
@ -99,6 +97,13 @@ class AdminPanelStaffMembers extends React.Component {
|
|||
return departments;
|
||||
}
|
||||
|
||||
retrieveStaffMembers() {
|
||||
API.call({
|
||||
path: '/staff/get-all',
|
||||
data: {}
|
||||
}).then(this.onStaffRetrieved.bind(this));
|
||||
}
|
||||
|
||||
onStaffRetrieved(result) {
|
||||
if(result.status == 'success'){
|
||||
this.setState({
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import React from 'react';
|
||||
import {browserHistory} from 'react-router';
|
||||
import {connect} from 'react-redux';
|
||||
import _ from 'lodash';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
import SessionActions from 'actions/session-actions';
|
||||
|
||||
import StaffEditor from 'app/admin/panel/staff/staff-editor';
|
||||
import Header from 'core-components/header';
|
||||
|
@ -17,12 +19,7 @@ class AdminPanelViewStaff extends React.Component {
|
|||
};
|
||||
|
||||
componentDidMount() {
|
||||
API.call({
|
||||
path: '/staff/get',
|
||||
data: {
|
||||
staffId: this.props.params.staffId
|
||||
}
|
||||
}).then(this.onStaffRetrieved.bind(this));
|
||||
this.retrieveStaff();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -37,15 +34,29 @@ class AdminPanelViewStaff extends React.Component {
|
|||
getProps() {
|
||||
return _.extend({}, this.state.userData, {
|
||||
staffId: this.props.params.staffId * 1,
|
||||
onDelete: this.onDelete.bind(this)
|
||||
onDelete: this.onDelete.bind(this),
|
||||
onChange: this.retrieveStaff.bind(this)
|
||||
});
|
||||
}
|
||||
|
||||
retrieveStaff() {
|
||||
API.call({
|
||||
path: '/staff/get',
|
||||
data: {
|
||||
staffId: this.props.params.staffId
|
||||
}
|
||||
}).then(this.onStaffRetrieved.bind(this));
|
||||
}
|
||||
|
||||
onStaffRetrieved(result) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
userData: result.data
|
||||
});
|
||||
|
||||
if(this.props.userId == this.props.params.staffId) {
|
||||
this.props.dispatch(SessionActions.getUserData(null, null, true))
|
||||
}
|
||||
}
|
||||
|
||||
onDelete() {
|
||||
|
@ -53,4 +64,4 @@ class AdminPanelViewStaff extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default AdminPanelViewStaff;
|
||||
export default connect((store) => store.session)(AdminPanelViewStaff);
|
||||
|
|
|
@ -31,6 +31,10 @@ class StaffEditor extends React.Component {
|
|||
onDelete: React.PropTypes.func
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
tickets: []
|
||||
};
|
||||
|
||||
state = {
|
||||
email: this.props.email,
|
||||
level: this.props.level - 1,
|
||||
|
@ -73,7 +77,7 @@ class StaffEditor extends React.Component {
|
|||
</div>
|
||||
<label className={this.getPictureWrapperClass()}>
|
||||
<div className="staff-editor__card-pic-background"></div>
|
||||
<img className="staff-editor__card-pic" src={(this.props.profilePic) ? API.getFileLink(this.props.profilePic) : (API.getURL() + '/images/logo.png')} />
|
||||
<img className="staff-editor__card-pic" src={(this.props.profilePic) ? API.getFileLink(this.props.profilePic) : (API.getURL() + '/images/profile.png')} />
|
||||
{(this.state.loadingPicture) ? <Loading className="staff-editor__card-pic-loading" size="large"/> : <Icon className="staff-editor__card-pic-icon" name="upload" size="4x"/>}
|
||||
<input className="staff-editor__image-uploader" type="file" multiple={false} accept="image/x-png,image/gif,image/jpeg" onChange={this.onProfilePicChange.bind(this)}/>
|
||||
</label>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import {connect} from 'react-redux';
|
||||
import RichTextEditor from 'react-rte-browserify';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
@ -18,6 +17,7 @@ import Loading from 'core-components/loading';
|
|||
import Form from 'core-components/form';
|
||||
import FormField from 'core-components/form-field';
|
||||
import SubmitButton from 'core-components/submit-button';
|
||||
import TextEditor from 'core-components/text-editor';
|
||||
|
||||
class AdminPanelCustomResponses extends React.Component {
|
||||
static defaultProps = {
|
||||
|
@ -31,7 +31,7 @@ class AdminPanelCustomResponses extends React.Component {
|
|||
errors: {},
|
||||
form: {
|
||||
title: '',
|
||||
content: RichTextEditor.createEmptyValue(),
|
||||
content: TextEditor.createEmpty(),
|
||||
language: 'en'
|
||||
}
|
||||
};
|
||||
|
@ -203,7 +203,7 @@ class AdminPanelCustomResponses extends React.Component {
|
|||
let form = _.clone(this.state.form);
|
||||
|
||||
form.title = (this.props.items[index] && this.props.items[index].name) || '';
|
||||
form.content = RichTextEditor.createValueFromString((this.props.items[index] && this.props.items[index].content) || '', 'html');
|
||||
form.content = TextEditor.getEditorStateFromHTML((this.props.items[index] && this.props.items[index].content) || '');
|
||||
form.language = (this.props.items[index] && this.props.items[index].language) || 'en';
|
||||
|
||||
this.setState({
|
||||
|
|
|
@ -14,6 +14,7 @@ class AdminPanelViewTicket extends React.Component {
|
|||
|
||||
static propTypes = {
|
||||
avoidSeen: React.PropTypes.bool,
|
||||
onRetrieveFail: React.PropTypes.func,
|
||||
assignmentAllowed: React.PropTypes.bool
|
||||
};
|
||||
|
||||
|
@ -108,6 +109,10 @@ class AdminPanelViewTicket extends React.Component {
|
|||
loading: false,
|
||||
ticket: {}
|
||||
});
|
||||
|
||||
if(this.props.onRetrieveFail) {
|
||||
this.props.onRetrieveFail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -151,8 +151,8 @@ class AdminPanelListUsers extends React.Component {
|
|||
|
||||
onUsersRetrieved(result) {
|
||||
this.setState({
|
||||
page: result.data.page,
|
||||
pages: result.data.pages,
|
||||
page: result.data.page * 1,
|
||||
pages: result.data.pages * 1,
|
||||
users: result.data.users,
|
||||
orderBy: result.data.orderBy,
|
||||
desc: (result.data.desc === '1'),
|
||||
|
|
|
@ -46,6 +46,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.ticket-list__number {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.signup-widget {
|
||||
background-color: $very-light-grey;
|
||||
}
|
||||
|
|
|
@ -153,9 +153,7 @@ let DemoPage = React.createClass({
|
|||
title: 'ModalTrigger',
|
||||
render: (
|
||||
<Button onClick={function () {
|
||||
ModalContainer.openModal(
|
||||
<AreYouSure description="I confirm I want to perform this action." onYes={()=> {alert('yes');}} />
|
||||
);
|
||||
AreYouSure.openModal('I confirm I want to perform this action.', ()=> {alert('yes');}, 'secure')
|
||||
}}>
|
||||
Open Modal
|
||||
</Button>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
import { browserHistory } from 'react-router';
|
||||
import RichTextEditor from 'react-rte-browserify';
|
||||
import {connect} from 'react-redux';
|
||||
import {EditorState, convertToRaw} from 'draft-js';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
@ -33,7 +33,7 @@ class CreateTicketForm extends React.Component {
|
|||
message: null,
|
||||
form: {
|
||||
title: '',
|
||||
content: RichTextEditor.createEmptyValue(),
|
||||
content: EditorState.createEmpty(),
|
||||
departmentIndex: 0,
|
||||
email: '',
|
||||
name: '',
|
||||
|
@ -59,11 +59,9 @@ class CreateTicketForm extends React.Component {
|
|||
}}/>
|
||||
</div>
|
||||
<FormField label={i18n('CONTENT')} name="content" validation="TEXT_AREA" required field="textarea" />
|
||||
<div className="create-ticket-form__file">
|
||||
<FormField name="file" field="file" />
|
||||
</div>
|
||||
{(this.props.allowAttachments) ? this.renderFileUpload() : null}
|
||||
{(!this.props.userLogged) ? this.renderCaptcha() : null}
|
||||
<SubmitButton>Create Ticket</SubmitButton>
|
||||
<SubmitButton>{i18n('CREATE_TICKET')}</SubmitButton>
|
||||
</Form>
|
||||
{this.renderMessage()}
|
||||
</div>
|
||||
|
@ -79,6 +77,14 @@ class CreateTicketForm extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
renderFileUpload() {
|
||||
return (
|
||||
<div className="create-ticket-form__file">
|
||||
<FormField name="file" field="file" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderCaptcha() {
|
||||
return (
|
||||
<div className="create-ticket-form__captcha">
|
||||
|
@ -138,7 +144,7 @@ class CreateTicketForm extends React.Component {
|
|||
store.dispatch(SessionActions.getUserData());
|
||||
setTimeout(() => {browserHistory.push('/dashboard')}, 2000);
|
||||
} else {
|
||||
setTimeout(() => {browserHistory.push('/check-ticket/' + email + '/' + result.data.ticketNumber)}, 2000);
|
||||
setTimeout(() => {browserHistory.push('/check-ticket/' + result.data.ticketNumber + '/' + email)}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,4 +156,9 @@ class CreateTicketForm extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateTicketForm;
|
||||
export default connect((store) => {
|
||||
return {
|
||||
allowAttachments: store.config['allow-attachments']
|
||||
};
|
||||
})(CreateTicketForm);
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ import React from 'react';
|
|||
import API from 'lib-app/api-call';
|
||||
import i18n from 'lib-app/i18n';
|
||||
|
||||
import ModalContainer from 'app-components/modal-container';
|
||||
import AreYouSure from 'app-components/are-you-sure';
|
||||
|
||||
import Header from 'core-components/header';
|
||||
|
@ -64,11 +63,11 @@ class DashboardEditProfilePage extends React.Component {
|
|||
}
|
||||
}
|
||||
onSubmitEditEmail(formState) {
|
||||
ModalContainer.openModal(<AreYouSure onYes={this.callEditEmailAPI.bind(this, formState)}/>);
|
||||
AreYouSure.openModal(i18n('EMAIL_WILL_CHANGE'), this.callEditEmailAPI.bind(this, formState));
|
||||
}
|
||||
|
||||
onSubmitEditPassword(formState) {
|
||||
ModalContainer.openModal(<AreYouSure onYes={this.callEditPassAPI.bind(this, formState)}/>);
|
||||
AreYouSure.openModal(i18n('PASSWORD_WILL_CHANGE'), this.callEditPassAPI.bind(this, formState));
|
||||
}
|
||||
|
||||
callEditEmailAPI(formState){
|
||||
|
|
|
@ -81,7 +81,7 @@ class MainCheckTicketPage extends React.Component {
|
|||
});
|
||||
|
||||
API.call({
|
||||
path: '/ticket/get',
|
||||
path: '/ticket/check',
|
||||
data: {
|
||||
captcha: captcha && captcha.getValue(),
|
||||
ticketNumber: form.ticketNumber,
|
||||
|
|
|
@ -32,7 +32,7 @@ class MainLayoutHeader extends React.Component {
|
|||
result = (
|
||||
<div className="main-layout-header__login-links">
|
||||
<Button type="clean" route={{to:'/'}}>{i18n('LOG_IN')}</Button>
|
||||
{(this.props.config['registration']) ? <Button type="clean" route={{to:'/signup'}}>{i18n('SIGN_UP')}</Button> : null}
|
||||
{(!!(this.props.config['registration'] * 1)) ? <Button type="clean" route={{to:'/signup'}}>{i18n('SIGN_UP')}</Button> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import React from 'react';
|
||||
import {browserHistory} from 'react-router';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import AdminPanelViewTicket from 'app/admin/panel/tickets/admin-panel-view-ticket'
|
||||
|
||||
|
@ -10,11 +12,22 @@ class MainViewTicketPage extends React.Component {
|
|||
return (
|
||||
<div className="main-view-ticket-page">
|
||||
<Widget>
|
||||
<AdminPanelViewTicket {...this.props} avoidSeen assignmentAllowed={false} />
|
||||
<AdminPanelViewTicket {...this.props} avoidSeen assignmentAllowed={false} onRetrieveFail={this.onRetrieveFail.bind(this)} />
|
||||
</Widget>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onRetrieveFail() {
|
||||
if (!this.props.config['user-system-enabled']) {
|
||||
setTimeout(() => {browserHistory.push('/check-ticket')}, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default MainViewTicketPage;
|
||||
|
||||
export default connect((store) => {
|
||||
return {
|
||||
config: store.config
|
||||
};
|
||||
})(MainViewTicketPage);
|
Binary file not shown.
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
|
@ -0,0 +1,17 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
let Mock = ReactMock();
|
||||
|
||||
_.extend(Mock, {
|
||||
createEmpty: stub().returns({editorState: true}),
|
||||
|
||||
getEditorStateFromHTML: stub().returns({editorState: true}),
|
||||
|
||||
getHTMLFromEditorState: stub().returns('HTML_CODE'),
|
||||
|
||||
isEditorState: (item) => {
|
||||
return item.editorState;
|
||||
}
|
||||
});
|
||||
|
||||
export default Mock;
|
|
@ -1,15 +1,13 @@
|
|||
const Input = ReactMock();
|
||||
const Checkbox = ReactMock();
|
||||
const DropDown = ReactMock();
|
||||
const TextEditor = ReactMock();
|
||||
|
||||
const RichTextEditor = require('react-rte-browserify');
|
||||
const TextEditorMock = require('core-components/__mocks__/text-editor-mock');
|
||||
|
||||
const FormField = requireUnit('core-components/form-field', {
|
||||
'core-components/input': Input,
|
||||
'core-components/checkbox': Checkbox,
|
||||
'core-components/drop-down': DropDown,
|
||||
'core-components/text-editor': TextEditor
|
||||
'core-components/text-editor': TextEditorMock
|
||||
});
|
||||
|
||||
|
||||
|
@ -21,7 +19,7 @@ describe('FormField component', function () {
|
|||
'input': Input,
|
||||
'checkbox': Checkbox,
|
||||
'select': DropDown,
|
||||
'textarea': TextEditor
|
||||
'textarea': TextEditorMock
|
||||
};
|
||||
|
||||
component = reRenderIntoDocument(
|
||||
|
@ -32,10 +30,9 @@ describe('FormField component', function () {
|
|||
|
||||
describe('when calling static getDefaultValue', function () {
|
||||
it('should return correct values', function () {
|
||||
expect(FormField.getDefaultValue('input')).to.equal('');
|
||||
expect(FormField.getDefaultValue('checkbox')).to.equal(false);
|
||||
expect(FormField.getDefaultValue('select')).to.equal(0);
|
||||
expect(FormField.getDefaultValue('textarea') instanceof RichTextEditor.EditorValue).to.equal(true);
|
||||
expect(FormField.getDefaultValue('textarea')).to.equal(TextEditorMock.createEmpty());
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -415,7 +412,7 @@ describe('FormField component', function () {
|
|||
errored: true,
|
||||
name: 'MOCK_NAME',
|
||||
onBlur: component.props.onBlur,
|
||||
required: true,
|
||||
required: true
|
||||
});
|
||||
expect(innerField.props.value).to.deep.equal({value: 'VALUE_MOCk'});
|
||||
});
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
// MOCKS
|
||||
const ValidationFactoryMock = require('lib-app/__mocks__/validations/validation-factory-mock');
|
||||
const TextEditorMock = require('core-components/__mocks__/text-editor-mock');
|
||||
const FormField = ReactMock();
|
||||
const RichTextEditor = require('react-rte-browserify');
|
||||
|
||||
// COMPONENT
|
||||
const Form = requireUnit('core-components/form', {
|
||||
'lib-app/validations/validations-factory': ValidationFactoryMock,
|
||||
'core-components/form-field': FormField
|
||||
'core-components/form-field': FormField,
|
||||
'core-components/text-editor': TextEditorMock
|
||||
});
|
||||
|
||||
describe('Form component', function () {
|
||||
|
@ -186,12 +187,11 @@ describe('Form component', function () {
|
|||
expect(form.props.onSubmit).to.not.have.been.called;
|
||||
});
|
||||
|
||||
it('should tranform RichTextEditor value to HTML', function () {
|
||||
form.state.form.first = RichTextEditor.createEmptyValue();
|
||||
form.state.form.first.toString = stub().returns('HTML_CODE');
|
||||
it('should transform TextEdit value to HTML', function () {
|
||||
form.state.form.first = TextEditorMock.createEmpty();
|
||||
|
||||
TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
|
||||
expect(form.state.form.first.toString).to.have.been.called;
|
||||
expect(TextEditorMock.getHTMLFromEditorState).to.have.been.calledWith(form.state.form.first);
|
||||
expect(form.props.onSubmit).to.have.been.calledWith({
|
||||
first: 'HTML_CODE',
|
||||
second: 'value2',
|
||||
|
|
|
@ -63,6 +63,7 @@ class Button extends React.Component {
|
|||
delete props.route;
|
||||
delete props.iconName;
|
||||
delete props.type;
|
||||
delete props.inverted;
|
||||
|
||||
return props;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import RichTextEditor from 'react-rte-browserify';
|
||||
import classNames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
@ -44,7 +43,7 @@ class FormField extends React.Component {
|
|||
return [];
|
||||
}
|
||||
else if (field === 'textarea') {
|
||||
return RichTextEditor.createEmptyValue();
|
||||
return TextEditor.createEmpty();
|
||||
}
|
||||
else if (field === 'select') {
|
||||
return 0;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import RichTextEditor from 'react-rte-browserify';
|
||||
|
||||
import {reactDFS, renderChildrenWithProps} from 'lib-core/react-dfs';
|
||||
import ValidationFactory from 'lib-app/validations/validations-factory';
|
||||
|
||||
import FormField from 'core-components/form-field';
|
||||
import TextEditor from 'core-components/text-editor';
|
||||
|
||||
class Form extends React.Component {
|
||||
|
||||
|
@ -161,8 +161,8 @@ class Form extends React.Component {
|
|||
event.preventDefault();
|
||||
|
||||
const form = _.mapValues(this.getFormValue(), (field) => {
|
||||
if (field instanceof RichTextEditor.EditorValue) {
|
||||
return field.toString('html');
|
||||
if (TextEditor.isEditorState(field)) {
|
||||
return TextEditor.getHTMLFromEditorState(field);
|
||||
} else {
|
||||
return field;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import {Motion, spring} from 'react-motion';
|
||||
|
||||
class Modal extends React.Component {
|
||||
static propTypes = {
|
||||
content: React.PropTypes.node
|
||||
content: React.PropTypes.node,
|
||||
noPadding: React.PropTypes.bool
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -30,13 +32,22 @@ class Modal extends React.Component {
|
|||
|
||||
renderModal(animation) {
|
||||
return (
|
||||
<div className="modal" style={{opacity: animation.fade}}>
|
||||
<div className={this.getClass()} style={{opacity: animation.fade}}>
|
||||
<div className="modal__content" style={{transform: 'scale(' + animation.scale + ')'}}>
|
||||
{this.props.content}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
getClass() {
|
||||
let classes = {
|
||||
'modal': true,
|
||||
'modal_no-padding': this.props.noPadding
|
||||
};
|
||||
|
||||
return classNames(classes);
|
||||
}
|
||||
}
|
||||
|
||||
export default Modal;
|
|
@ -18,4 +18,11 @@
|
|||
padding: 50px;
|
||||
box-shadow: 0 0 10px white;
|
||||
}
|
||||
|
||||
&_no-padding {
|
||||
|
||||
.modal__content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import RichTextEditor from 'react-rte-browserify';
|
||||
import {Editor} from 'react-draft-wysiwyg';
|
||||
import {EditorState, ContentState, convertFromHTML} from 'draft-js';
|
||||
import {stateToHTML} from 'draft-js-export-html';
|
||||
|
||||
class TextEditor extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -8,16 +10,38 @@ class TextEditor extends React.Component {
|
|||
onChange: React.PropTypes.func,
|
||||
value: React.PropTypes.object
|
||||
};
|
||||
|
||||
static createEmpty() {
|
||||
return EditorState.createEmpty()
|
||||
}
|
||||
|
||||
static getEditorStateFromHTML(htmlString) {
|
||||
const blocksFromHTML = convertFromHTML(htmlString);
|
||||
const state = ContentState.createFromBlockArray(
|
||||
blocksFromHTML.contentBlocks,
|
||||
blocksFromHTML.entityMap
|
||||
);
|
||||
|
||||
return EditorState.createWithContent(state);
|
||||
}
|
||||
|
||||
static getHTMLFromEditorState(editorState) {
|
||||
return stateToHTML(editorState.getCurrentContent());
|
||||
}
|
||||
|
||||
static isEditorState(editorState) {
|
||||
return editorState && editorState.getCurrentContent;
|
||||
}
|
||||
|
||||
state = {
|
||||
value: RichTextEditor.createEmptyValue(),
|
||||
value: EditorState.createEmpty(),
|
||||
focused: false
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={this.getClass()}>
|
||||
<RichTextEditor {...this.getEditorProps()} />
|
||||
<Editor {...this.getEditorProps()} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -36,15 +60,39 @@ class TextEditor extends React.Component {
|
|||
|
||||
getEditorProps() {
|
||||
return {
|
||||
className: 'text-editor__editor',
|
||||
value: this.props.value || this.state.value,
|
||||
wrapperClassName: 'text-editor__editor',
|
||||
editorState: this.props.value || this.state.value,
|
||||
ref: 'editor',
|
||||
onChange: this.onEditorChange.bind(this),
|
||||
toolbar: this.getToolbarOptions(),
|
||||
onEditorStateChange: this.onEditorChange.bind(this),
|
||||
onFocus: this.onEditorFocus.bind(this),
|
||||
onBlur: this.onBlur.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getToolbarOptions() {
|
||||
return {
|
||||
options: ['inline', 'blockType', 'list', 'link', 'image'],
|
||||
inline: {
|
||||
inDropdown: false,
|
||||
options: ['bold', 'italic', 'underline', 'strikethrough', 'monospace']
|
||||
},
|
||||
blockType: {
|
||||
inDropdown: true,
|
||||
options: [ 'Normal', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Blockquote']
|
||||
},
|
||||
list: {
|
||||
inDropdown: false,
|
||||
options: ['unordered', 'ordered']
|
||||
},
|
||||
image: {
|
||||
urlEnabled: true,
|
||||
uploadEnabled: false,
|
||||
alignmentEnabled: false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onEditorChange(value) {
|
||||
this.setState({value});
|
||||
|
||||
|
@ -71,7 +119,7 @@ class TextEditor extends React.Component {
|
|||
|
||||
focus() {
|
||||
if (this.refs.editor) {
|
||||
this.refs.editor._focus();
|
||||
this.refs.editor.focusEditor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,17 @@
|
|||
.text-editor {
|
||||
|
||||
.text-editor__editor {
|
||||
background-color: white;
|
||||
border: 1px solid $grey;
|
||||
border-radius: 3px;
|
||||
|
||||
.DraftEditor-root {
|
||||
height: 200px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.public-DraftEditor-content {
|
||||
height: 185px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module.exports = [
|
|||
data: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'staff@opensupports.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
level: 3,
|
||||
staff: true,
|
||||
departments: [
|
||||
|
@ -50,7 +50,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -61,7 +61,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -71,7 +71,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -82,7 +82,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -103,7 +103,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -123,7 +123,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -167,7 +167,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -178,7 +178,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -188,7 +188,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -199,7 +199,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -220,7 +220,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -240,7 +240,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -284,7 +284,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -295,7 +295,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -305,7 +305,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -316,7 +316,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -337,7 +337,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -357,7 +357,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -443,7 +443,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -454,7 +454,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -464,7 +464,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -475,7 +475,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -496,7 +496,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -516,7 +516,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -560,7 +560,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -571,7 +571,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -581,7 +581,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -592,7 +592,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -613,7 +613,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -633,7 +633,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -677,7 +677,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -688,7 +688,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -698,7 +698,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -709,7 +709,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -730,7 +730,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -750,7 +750,7 @@ module.exports = [
|
|||
author: {
|
||||
name: 'Emilia Clarke',
|
||||
email: 'jobs@steve.com',
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
staff: true
|
||||
}
|
||||
},
|
||||
|
@ -979,7 +979,7 @@ module.exports = [
|
|||
data: [
|
||||
{
|
||||
id: 22,
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
name: 'Emilia Clarke',
|
||||
departments: [{id: 2, name: 'Technical issues'}],
|
||||
assignedTickets: 4,
|
||||
|
@ -988,7 +988,7 @@ module.exports = [
|
|||
},
|
||||
{
|
||||
id: 22,
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
name: 'Yulian A GUI Yermo',
|
||||
departments: [{id: 2, name: 'Technical issues'}, {id: 1, name: 'Sales Support'}],
|
||||
assignedTickets: 9,
|
||||
|
@ -997,7 +997,7 @@ module.exports = [
|
|||
},
|
||||
{
|
||||
id: 22,
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
name: 'Miltona Costa',
|
||||
departments: [{id: 1, name: 'Sales Support'}],
|
||||
assignedTickets: -1,
|
||||
|
@ -1006,7 +1006,7 @@ module.exports = [
|
|||
},
|
||||
{
|
||||
id: 22,
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
name: 'Emiliasnikova Rusachestkvuy',
|
||||
departments: [{id: 1, name: 'Sales Support'}, {id: 3, name: 'System and Administration'}],
|
||||
assignedTickets: 100,
|
||||
|
@ -1015,7 +1015,7 @@ module.exports = [
|
|||
},
|
||||
{
|
||||
id: 22,
|
||||
profilePic: 'http://www.opensupports.com/profilepic.jpg',
|
||||
profilePic: '',
|
||||
name: 'Laurita Morrechaga Rusachestkvuy',
|
||||
departments: [{id: 3, name: 'System and Administration'}],
|
||||
assignedTickets: 1,
|
||||
|
|
|
@ -40,7 +40,7 @@ module.exports = [
|
|||
status: 'success',
|
||||
data: [
|
||||
{id: 1, name: 'Common issue #1', language: 'en', content: 'some content 1'},
|
||||
{id: 2, name: 'Common issue #2', language: 'en', content: 'some content 2'},
|
||||
{id: 2, name: 'Common issue #2', language: 'en', content: 'some <strong>content</strong> 2'},
|
||||
{id: 3, name: 'Common issue #3', language: 'en', content: 'some content 3'},
|
||||
{id: 4, name: 'H<>ufiges Problem #1', language: 'de', content: 'einige Inhalte 1'},
|
||||
{id: 5, name: 'H<>ufiges Problem #2', language: 'de', content: 'einige Inhalte 2'}
|
||||
|
|
|
@ -161,7 +161,6 @@ export default {
|
|||
'ENABLE_USER_SYSTEM': 'Use user system for customers',
|
||||
'ENABLE_USER_REGISTRATION': 'Enable user registration',
|
||||
'INCLUDE_USERS_VIA_CSV': 'Include users via CSV file',
|
||||
'INCLUDE_DATABASE_VIA_SQL': 'Include database via SQL file',
|
||||
'BACKUP_DATABASE': 'Backup database',
|
||||
'DELETE_ALL_USERS': 'Delete all users',
|
||||
'PLEASE_CONFIRM_PASSWORD': 'Please confirm your password to make these changes',
|
||||
|
@ -250,6 +249,8 @@ export default {
|
|||
'ADD_API_KEY_DESCRIPTION': 'Insert the name and a registration api key be generated.',
|
||||
'SIGN_UP_VIEW_DESCRIPTION': 'Here you can create an account for our support center. It is required for send tickets and see documentation.',
|
||||
'EDIT_PROFILE_VIEW_DESCRIPTION': 'Here you can edit your user by changing your email or your password.',
|
||||
'ENABLE_USER_SYSTEM_DESCRIPTION': 'Enable/disable the use of an user system. If you disable it, all users will be deleted but the tickets will be kept. If you enable it, the users of existent tickets will be created.',
|
||||
'CSV_DESCRIPTION': 'The CSV file must have 3 columns: email, password, name. There is no limit in row count. It will be created one user per row in the file.',
|
||||
|
||||
//ERRORS
|
||||
'EMAIL_OR_PASSWORD': 'Email or password invalid',
|
||||
|
@ -275,13 +276,18 @@ export default {
|
|||
'ERROR_URL': 'Invalid URL',
|
||||
'UNVERIFIED_EMAIL': 'Email is not verified yet',
|
||||
'ERROR_UPDATING_SETTINGS': 'An error occurred while trying to update settings',
|
||||
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Invalid email or ticket number',
|
||||
'INVALID_FILE': 'Invalid file',
|
||||
'ERRORS_FOUND': 'Errors found',
|
||||
|
||||
//MESSAGES
|
||||
'SIGNUP_SUCCESS': 'You have registered successfully in our support system.',
|
||||
'TICKET_SENT': 'Ticket has been created successfully.',
|
||||
'VALID_RECOVER': 'Password recovered successfully',
|
||||
'EMAIL_EXISTS': 'Email already exists',
|
||||
'ARE_YOU_SURE': 'Are you sure?',
|
||||
'ARE_YOU_SURE': 'Confirm action',
|
||||
'EMAIL_WILL_CHANGE': 'The current email will be changed',
|
||||
'PASSWORD_WILL_CHANGE': 'The current password will be changed',
|
||||
'EMAIL_CHANGED': 'Email has been changed successfully',
|
||||
'PASSWORD_CHANGED': 'Password has been changed successfully',
|
||||
'OLD_PASSWORD_INCORRECT': 'Old password is incorrect',
|
||||
|
@ -294,5 +300,7 @@ export default {
|
|||
'FAILED_EDIT_STAFF': 'An error occurred while trying to edit staff member.',
|
||||
'EMAIL_BANNED_SUCCESSFULLY': 'Email has been banned successfully',
|
||||
'WILL_DELETE_STAFF': 'This staff member will be deleted and all its tickets will be unassigned.',
|
||||
'WILL_RECOVER_EMAIL_TEMPLATE': 'This email template will be recover to it\'s default value on this language.'
|
||||
'WILL_RECOVER_EMAIL_TEMPLATE': 'This email template will be recover to it\'s default value on this language.',
|
||||
'SUCCESS_IMPORTING_CSV_DESCRIPTION': 'CSV File has been imported successfully',
|
||||
'SUCCESS_DELETING_ALL_USERS': 'Users have beend deleted successfully'
|
||||
};
|
||||
|
|
|
@ -27,8 +27,6 @@ let renderApplication = function () {
|
|||
render(<Provider store={store}>{routes}</Provider>, document.getElementById('app'));
|
||||
};
|
||||
window.store = store;
|
||||
store.dispatch(ConfigActions.init());
|
||||
store.dispatch(SessionActions.initSession());
|
||||
|
||||
let unsubscribe = store.subscribe(() => {
|
||||
console.log(store.getState());
|
||||
|
@ -38,3 +36,6 @@ let unsubscribe = store.subscribe(() => {
|
|||
renderApplication();
|
||||
}
|
||||
});
|
||||
|
||||
store.dispatch(ConfigActions.init());
|
||||
store.dispatch(SessionActions.initSession());
|
||||
|
|
|
@ -29,6 +29,7 @@ function processData (data, dataAsForm = false) {
|
|||
|
||||
module.exports = {
|
||||
call: function ({path, data, plain, dataAsForm}) {
|
||||
console.log('request ' + path, data);
|
||||
return new Promise(function (resolve, reject) {
|
||||
APIUtils.post(apiUrl + path, processData(data, dataAsForm), dataAsForm)
|
||||
.then(function (result) {
|
||||
|
|
|
@ -23,7 +23,7 @@ class SessionStore {
|
|||
}
|
||||
|
||||
isLoggedIn() {
|
||||
return !!this.getItem('token');
|
||||
return !!this.getItem('userId');
|
||||
}
|
||||
|
||||
closeSession() {
|
||||
|
@ -62,6 +62,7 @@ class SessionStore {
|
|||
this.setItem('title', configs.title);
|
||||
this.setItem('registration', configs.registration);
|
||||
this.setItem('user-system-enabled', configs['user-system-enabled']);
|
||||
this.setItem('allow-attachments', configs['allow-attachments']);
|
||||
}
|
||||
|
||||
getConfigs() {
|
||||
|
@ -72,9 +73,11 @@ class SessionStore {
|
|||
allowedLanguages: JSON.parse(this.getItem('allowedLanguages')),
|
||||
supportedLanguages: JSON.parse(this.getItem('supportedLanguages')),
|
||||
layout: this.getItem('layout'),
|
||||
registration: this.getItem('registration'),
|
||||
title: this.getItem('title'),
|
||||
['user-system-enabled']: this.getItem('user-system-enabled')
|
||||
registration: (this.getItem('registration') * 1),
|
||||
'user-system-enabled': (this.getItem('user-system-enabled') * 1),
|
||||
'allow-attachments': (this.getItem('allow-attachments') * 1),
|
||||
'maintenance-mode': (this.getItem('maintenance-mode') * 1)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import RichTextEditor from 'react-rte-browserify';
|
||||
import TextEditor from 'core-components/text-editor';
|
||||
|
||||
import Validator from 'lib-app/validations/validator';
|
||||
|
||||
|
@ -11,8 +11,8 @@ class LengthValidator extends Validator {
|
|||
}
|
||||
|
||||
validate(value = '', form = {}) {
|
||||
if (value instanceof RichTextEditor.EditorValue) {
|
||||
value = value.getEditorState().getCurrentContent().getPlainText();
|
||||
if (TextEditor.isEditorState(value)) {
|
||||
value = value.getCurrentContent().getPlainText();
|
||||
}
|
||||
|
||||
if (value.length < this.minlength) return this.getError(this.errorKey);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Validator from 'lib-app/validations/validator';
|
||||
import AlphaNumericValidator from 'lib-app/validations/alphanumeric-validator';
|
||||
import EmailValidator from 'lib-app/validations/email-validator';
|
||||
import RepeatPasswordValidator from 'lib-app/validations/repeat-password-validator';
|
||||
import LengthValidator from 'lib-app/validations/length-validator';
|
||||
|
@ -7,8 +6,8 @@ import ListValidator from 'lib-app/validations/list-validator';
|
|||
|
||||
let validators = {
|
||||
'DEFAULT': new Validator(),
|
||||
'NAME': new AlphaNumericValidator('ERROR_NAME', new LengthValidator(2, 'ERROR_NAME')),
|
||||
'TITLE': new AlphaNumericValidator('ERROR_TITLE', new LengthValidator(2, 'ERROR_TITLE')),
|
||||
'NAME': new LengthValidator(2, 'ERROR_NAME'),
|
||||
'TITLE': new LengthValidator(2, 'ERROR_TITLE'),
|
||||
'EMAIL': new EmailValidator(),
|
||||
'TEXT_AREA': new LengthValidator(10, 'ERROR_CONTENT_SHORT'),
|
||||
'PASSWORD': new LengthValidator(6, 'ERROR_PASSWORD'),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import RichTextEditor from 'react-rte-browserify';
|
||||
import TextEditor from 'core-components/text-editor';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
|
||||
|
@ -20,8 +20,8 @@ class Validator {
|
|||
}
|
||||
|
||||
validate(value, form) {
|
||||
if (value instanceof RichTextEditor.EditorValue) {
|
||||
value = value.getEditorState().getPlainText()
|
||||
if (TextEditor.isEditorState(value)) {
|
||||
value = value.getPlainText();
|
||||
}
|
||||
|
||||
if (value.length === 0) return this.getError('ERROR_EMPTY');
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
@import 'scss/typography';
|
||||
@import 'scss/base';
|
||||
@import 'scss/font_awesome/font-awesome';
|
||||
@import 'scss/react-draft-wysiwyg';
|
||||
|
||||
@import 'core-components/*';
|
||||
@import 'app-components/*';
|
||||
|
|
|
@ -26,7 +26,6 @@ class AdminDataReducer extends Reducer {
|
|||
getTypeHandlers() {
|
||||
return {
|
||||
'CUSTOM_RESPONSES_FULFILLED': this.onCustomResponses,
|
||||
'SESSION_CHECKED': this.onSessionChecked,
|
||||
|
||||
'MY_TICKETS_FULFILLED': this.onMyTicketsRetrieved,
|
||||
'MY_TICKETS_REJECTED': this.onMyTicketsRejected,
|
||||
|
@ -51,15 +50,6 @@ class AdminDataReducer extends Reducer {
|
|||
});
|
||||
}
|
||||
|
||||
onSessionChecked(state) {
|
||||
const customResponses = sessionStore.getItem('customResponses');
|
||||
|
||||
return _.extend({}, state, {
|
||||
customResponses: JSON.parse(customResponses),
|
||||
customResponsesLoaded: true
|
||||
});
|
||||
}
|
||||
|
||||
onMyTicketsRetrieved(state, payload) {
|
||||
return _.extend({}, state, {
|
||||
myTickets: payload.data,
|
||||
|
|
|
@ -37,6 +37,10 @@ class ConfigReducer extends Reducer {
|
|||
|
||||
return _.extend({}, state, payload.data, {
|
||||
language: currentLanguage || payload.language,
|
||||
registration: !!(payload.data.registration * 1),
|
||||
'user-system-enabled': !!(payload.data['user-system-enabled']* 1),
|
||||
'allow-attachments': !!(payload.data['allow-attachments']* 1),
|
||||
'maintenance-mode': !!(payload.data['maintenance-mode']* 1),
|
||||
initDone: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ class ModalReducer extends Reducer {
|
|||
getInitialState() {
|
||||
return {
|
||||
opened: false,
|
||||
noPadding: false,
|
||||
content: null
|
||||
};
|
||||
}
|
||||
|
@ -23,7 +24,8 @@ class ModalReducer extends Reducer {
|
|||
|
||||
return _.extend({}, state, {
|
||||
opened: true,
|
||||
content: payload
|
||||
content: payload.content,
|
||||
noPadding: payload.noPadding || false
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -32,7 +34,8 @@ class ModalReducer extends Reducer {
|
|||
|
||||
return _.extend({}, state, {
|
||||
opened: false,
|
||||
content: null
|
||||
content: null,
|
||||
noPadding: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,985 @@
|
|||
.rdw-option-wrapper {
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 5px;
|
||||
min-width: 25px;
|
||||
height: 20px;
|
||||
border-radius: 2px;
|
||||
margin: 0 4px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
background: white;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.rdw-option-wrapper:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
}
|
||||
.rdw-option-wrapper:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-option-active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-option-disabled {
|
||||
opacity: 0.3;
|
||||
cursor: default;
|
||||
}
|
||||
.rdw-dropdown-wrapper {
|
||||
height: 30px;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
margin: 0 3px;
|
||||
text-transform: capitalize;
|
||||
background: white;
|
||||
}
|
||||
.rdw-dropdown-wrapper:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-dropdown-wrapper:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
.rdw-dropdown-wrapper:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-dropdown-carettoopen {
|
||||
height: 0px;
|
||||
width: 0px;
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
right: 10%;
|
||||
border-top: 6px solid black;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
.rdw-dropdown-carettoclose {
|
||||
height: 0px;
|
||||
width: 0px;
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
right: 10%;
|
||||
border-bottom: 6px solid black;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
.rdw-dropdown-selectedtext {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-dropdown-optionwrapper {
|
||||
z-index: 100;
|
||||
position: relative;
|
||||
border: 1px solid #F1F1F1;
|
||||
width: 98%;
|
||||
background: white;
|
||||
border-radius: 2px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.rdw-dropdown-optionwrapper:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
.rdw-dropdownoption-default {
|
||||
min-height: 25px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-dropdownoption-highlighted {
|
||||
background: #F1F1F1;
|
||||
}
|
||||
.rdw-dropdownoption-active {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.rdw-dropdownoption-disabled {
|
||||
opacity: 0.3;
|
||||
cursor: default;
|
||||
}
|
||||
.rdw-inline-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.rdw-inline-dropdown {
|
||||
width: 50px;
|
||||
}
|
||||
.rdw-inline-dropdownoption {
|
||||
height: 40px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-block-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.rdw-block-dropdown {
|
||||
width: 110px;
|
||||
}
|
||||
.rdw-fontsize-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.rdw-fontsize-dropdown {
|
||||
min-width: 40px;
|
||||
}
|
||||
.rdw-fontsize-option {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-fontfamily-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.rdw-fontfamily-dropdown {
|
||||
width: 115px;
|
||||
}
|
||||
.rdw-fontfamily-placeholder {
|
||||
white-space: nowrap;
|
||||
max-width: 90px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.rdw-fontfamily-optionwrapper {
|
||||
width: 140px;
|
||||
}
|
||||
.rdw-list-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.rdw-list-dropdown {
|
||||
width: 50px;
|
||||
z-index: 90;
|
||||
}
|
||||
.rdw-list-dropdownOption {
|
||||
height: 40px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-text-align-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.rdw-text-align-dropdown {
|
||||
width: 50px;
|
||||
z-index: 90;
|
||||
}
|
||||
.rdw-text-align-dropdownOption {
|
||||
height: 40px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-right-aligned-block {
|
||||
text-align: right;
|
||||
}
|
||||
.rdw-left-aligned-block {
|
||||
text-align: left;
|
||||
}
|
||||
.rdw-center-aligned-block {
|
||||
text-align: center;
|
||||
}
|
||||
.rdw-justify-aligned-block {
|
||||
text-align: justify;
|
||||
}
|
||||
.rdw-right-aligned-block > div {
|
||||
display: inline;
|
||||
}
|
||||
.rdw-left-aligned-block > div {
|
||||
display: inline;
|
||||
}
|
||||
.rdw-center-aligned-block > div {
|
||||
display: inline;
|
||||
}
|
||||
.rdw-justify-aligned-block > div {
|
||||
display: inline;
|
||||
}
|
||||
.rdw-colorpicker-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
}
|
||||
.rdw-colorpicker-modal {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
width: 175px;
|
||||
height: 175px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-colorpicker-modal-header {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.rdw-colorpicker-modal-style-label {
|
||||
font-size: 15px;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
padding: 0 10px 5px;
|
||||
}
|
||||
.rdw-colorpicker-modal-style-label-active {
|
||||
border-bottom: 2px solid #0a66b7;
|
||||
}
|
||||
.rdw-colorpicker-modal-options {
|
||||
margin: 5px auto;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
width: 170px;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.rdw-colorpicker-cube {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 1px solid #F1F1F1;
|
||||
}
|
||||
.rdw-colorpicker-option {
|
||||
margin: 3px;
|
||||
padding: 0;
|
||||
min-height: 20px;
|
||||
border: none;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
min-width: 22px;
|
||||
box-shadow: 1px 2px 1px #BFBDBD inset;
|
||||
}
|
||||
.rdw-colorpicker-option:hover {
|
||||
box-shadow: 1px 2px 1px #BFBDBD;
|
||||
}
|
||||
.rdw-colorpicker-option:active {
|
||||
box-shadow: -1px -2px 1px #BFBDBD;
|
||||
}
|
||||
.rdw-colorpicker-option-active {
|
||||
box-shadow: 0px 0px 2px 2px #BFBDBD;
|
||||
}
|
||||
.rdw-link-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
}
|
||||
.rdw-link-dropdown {
|
||||
width: 50px;
|
||||
}
|
||||
.rdw-link-dropdownOption {
|
||||
height: 40px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-link-dropdownPlaceholder {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.rdw-link-modal {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
width: 235px;
|
||||
height: 180px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-link-modal-label {
|
||||
font-size: 15px;
|
||||
}
|
||||
.rdw-link-modal-input {
|
||||
margin-top: 5px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #F1F1F1;
|
||||
height: 25px;
|
||||
margin-bottom: 15px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-link-modal-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-link-modal-buttonsection {
|
||||
margin: 0 auto;
|
||||
}
|
||||
.rdw-link-modal-btn {
|
||||
margin-left: 10px;
|
||||
width: 75px;
|
||||
height: 30px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background: white;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.rdw-link-modal-btn:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
}
|
||||
.rdw-link-modal-btn:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-link-modal-btn:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.rdw-link-modal-btn:disabled {
|
||||
background: #ece9e9;
|
||||
}
|
||||
.rdw-link-dropdownoption {
|
||||
height: 40px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-history-dropdown {
|
||||
width: 50px;
|
||||
}
|
||||
.rdw-embedded-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
}
|
||||
.rdw-embedded-modal {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
width: 235px;
|
||||
height: 180px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-embedded-modal-header {
|
||||
font-size: 15px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.rdw-embedded-modal-header-option {
|
||||
width: 50%;
|
||||
cursor: pointer;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rdw-embedded-modal-header-label {
|
||||
width: 95px;
|
||||
border: 1px solid #f1f1f1;
|
||||
margin-top: 5px;
|
||||
background: #6EB8D4;
|
||||
border-bottom: 2px solid #0a66b7;
|
||||
}
|
||||
.rdw-embedded-modal-link-section {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rdw-embedded-modal-link-input {
|
||||
width: 95%;
|
||||
height: 35px;
|
||||
margin: 10px 0;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
font-size: 15px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-embedded-modal-link-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-embedded-modal-btn-section {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-embedded-modal-btn {
|
||||
margin: 0 3px;
|
||||
width: 75px;
|
||||
height: 30px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background: white;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.rdw-embedded-modal-btn:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
}
|
||||
.rdw-embedded-modal-btn:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-embedded-modal-btn:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.rdw-embedded-modal-btn:disabled {
|
||||
background: #ece9e9;
|
||||
}
|
||||
.rdw-embedded-modal-size {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
margin: 5px 0 10px;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.rdw-embedded-modal-size-input {
|
||||
width: 45%;
|
||||
height: 20px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rdw-embedded-modal-size-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-emoji-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
}
|
||||
.rdw-emoji-modal {
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
width: 235px;
|
||||
height: 180px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-emoji-icon {
|
||||
margin: 2.5px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
cursor: pointer;
|
||||
font-size: 22px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
.rdw-spinner {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.rdw-spinner > div {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: #333;
|
||||
|
||||
border-radius: 100%;
|
||||
display: inline-block;
|
||||
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
}
|
||||
.rdw-spinner .rdw-bounce1 {
|
||||
-webkit-animation-delay: -0.32s;
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
.rdw-spinner .rdw-bounce2 {
|
||||
-webkit-animation-delay: -0.16s;
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
@-webkit-keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% { -webkit-transform: scale(0) }
|
||||
40% { -webkit-transform: scale(1.0) }
|
||||
}
|
||||
@keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
} 40% {
|
||||
-webkit-transform: scale(1.0);
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
.rdw-image-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
}
|
||||
.rdw-image-modal {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
left: 5px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
width: 235px;
|
||||
height: 200px;
|
||||
border: 1px solid #F1F1F1;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
box-shadow: 3px 3px 5px #BFBDBD;
|
||||
}
|
||||
.rdw-image-modal-header {
|
||||
font-size: 15px;
|
||||
margin: 10px 0;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.rdw-image-modal-header-option {
|
||||
width: 50%;
|
||||
cursor: pointer;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rdw-image-modal-header-label {
|
||||
width: 80px;
|
||||
background: #f1f1f1;
|
||||
border: 1px solid #f1f1f1;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.rdw-image-modal-header-label-highlighted {
|
||||
background: #6EB8D4;
|
||||
border-bottom: 2px solid #0a66b7;
|
||||
}
|
||||
.rdw-image-modal-upload-option {
|
||||
height: 65px;
|
||||
width: 100%;
|
||||
color: gray;
|
||||
cursor: pointer;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
border: none;
|
||||
font-size: 15px;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
background-color: #f1f1f1;
|
||||
outline: 2px dashed gray;
|
||||
outline-offset: -10px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.rdw-image-modal-upload-option-highlighted {
|
||||
outline: 2px dashed #0a66b7;
|
||||
}
|
||||
.rdw-image-modal-upload-option-label {
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
.rdw-image-modal-upload-option-input {
|
||||
width: 0.1px;
|
||||
height: 0.1px;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
.rdw-image-modal-url-section {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.rdw-image-modal-url-input {
|
||||
width: 95%;
|
||||
height: 35px;
|
||||
margin: 25px 0 5px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
font-size: 15px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rdw-image-modal-btn-section {
|
||||
margin: 10px auto 0;
|
||||
}
|
||||
.rdw-image-modal-url-input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.rdw-image-modal-btn {
|
||||
margin: 0 5px;
|
||||
width: 75px;
|
||||
height: 30px;
|
||||
border: 1px solid #F1F1F1;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background: white;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.rdw-image-modal-btn:hover {
|
||||
box-shadow: 1px 1px 0px #BFBDBD;
|
||||
}
|
||||
.rdw-image-modal-btn:active {
|
||||
box-shadow: 1px 1px 0px #BFBDBD inset;
|
||||
}
|
||||
.rdw-image-modal-btn:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.rdw-image-modal-btn:disabled {
|
||||
background: #ece9e9;
|
||||
}
|
||||
.rdw-image-modal-spinner {
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.rdw-remove-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
}
|
||||
.rdw-history-wrapper {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.rdw-history-dropdownoption {
|
||||
height: 40px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-history-dropdown {
|
||||
width: 50px;
|
||||
}
|
||||
.rdw-link-decorator-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
.rdw-link-decorator-icon {
|
||||
position: absolute;
|
||||
left: 40%;
|
||||
top: 0;
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
}
|
||||
.rdw-mention-link {
|
||||
text-decoration: none;
|
||||
color: #1236ff;
|
||||
background-color: #f0fbff;
|
||||
padding: 1px 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.rdw-suggestion-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
.rdw-suggestion-dropdown {
|
||||
position: absolute;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
border: 1px solid #F1F1F1;
|
||||
min-width: 100px;
|
||||
max-height: 150px;
|
||||
overflow: auto;
|
||||
background: white;
|
||||
z-index: 100;
|
||||
}
|
||||
.rdw-suggestion-option {
|
||||
padding: 7px 5px;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
}
|
||||
.rdw-suggestion-option-active {
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
.rdw-hashtag-link {
|
||||
text-decoration: none;
|
||||
color: #1236ff;
|
||||
background-color: #f0fbff;
|
||||
padding: 1px 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.rdw-image-alignment-options-popup {
|
||||
position: absolute;;
|
||||
background: white;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
padding: 5px 2px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #F1F1F1;
|
||||
width: 105px;
|
||||
cursor: pointer;
|
||||
z-index: 100;
|
||||
}
|
||||
.rdw-alignment-option-left {
|
||||
-webkit-box-pack: start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.rdw-image-alignment-option {
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
min-width: 15px;
|
||||
}
|
||||
.rdw-image-alignment {
|
||||
position: relative;
|
||||
}
|
||||
.rdw-image-imagewrapper {
|
||||
position: relative;
|
||||
}
|
||||
.rdw-image-center {
|
||||
float: none;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rdw-image-left {
|
||||
float: left;
|
||||
}
|
||||
.rdw-image-right {
|
||||
float: right;
|
||||
}
|
||||
.rdw-editor-main {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.rdw-editor-toolbar {
|
||||
padding: 6px 5px 0;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #F1F1F1;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
background: white;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
font-size: 15px;
|
||||
margin-bottom: 5px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.public-DraftStyleDefault-block {
|
||||
margin: 1em 0;
|
||||
}
|
||||
.rdw-editor-wrapper:focus {
|
||||
outline: none;
|
||||
}
|
||||
/**
|
||||
* Draft v0.9.1
|
||||
*
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
.DraftEditor-editorContainer, .DraftEditor-root, .public-DraftEditor-content{height:inherit;text-align:initial}.public-DraftEditor-content[contenteditable=true]{-webkit-user-modify:read-write-plaintext-only}.DraftEditor-root{position:relative}.DraftEditor-editorContainer{background-color:rgba(255,255,255,0);border-left:.1px solid transparent;position:relative;z-index:1}.public-DraftEditor-block{position:relative}.DraftEditor-alignLeft .public-DraftStyleDefault-block{text-align:left}.DraftEditor-alignLeft .public-DraftEditorPlaceholder-root{left:0;text-align:left}.DraftEditor-alignCenter .public-DraftStyleDefault-block{text-align:center}.DraftEditor-alignCenter .public-DraftEditorPlaceholder-root{margin:0 auto;text-align:center;width:100%}.DraftEditor-alignRight .public-DraftStyleDefault-block{text-align:right}.DraftEditor-alignRight .public-DraftEditorPlaceholder-root{right:0;text-align:right}.public-DraftEditorPlaceholder-root{color:#9197a3;position:absolute;z-index:0}.public-DraftEditorPlaceholder-hasFocus{color:#bdc1c9}.DraftEditorPlaceholder-hidden{display:none}.public-DraftStyleDefault-block{position:relative;white-space:pre-wrap}.public-DraftStyleDefault-ltr{direction:ltr;text-align:left}.public-DraftStyleDefault-rtl{direction:rtl;text-align:right}.public-DraftStyleDefault-listLTR{direction:ltr}.public-DraftStyleDefault-listRTL{direction:rtl}.public-DraftStyleDefault-ol, .public-DraftStyleDefault-ul{margin:16px 0;padding:0}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-listLTR{margin-left:1.5em}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-listRTL{margin-right:1.5em}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-listLTR{margin-left:3em}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-listRTL{margin-right:3em}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-listLTR{margin-left:4.5em}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-listRTL{margin-right:4.5em}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-listLTR{margin-left:6em}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-listRTL{margin-right:6em}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-listLTR{margin-left:7.5em}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-listRTL{margin-right:7.5em}.public-DraftStyleDefault-unorderedListItem{list-style-type:square;position:relative}.public-DraftStyleDefault-unorderedListItem.public-DraftStyleDefault-depth0{list-style-type:disc}.public-DraftStyleDefault-unorderedListItem.public-DraftStyleDefault-depth1{list-style-type:circle}.public-DraftStyleDefault-orderedListItem{list-style-type:none;position:relative}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-listLTR:before{left:-36px;position:absolute;text-align:right;width:30px}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-listRTL:before{position:absolute;right:-36px;text-align:left;width:30px}.public-DraftStyleDefault-orderedListItem:before{content:counter(ol0) ". ";counter-increment:ol0}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth1:before{content:counter(ol1) ". ";counter-increment:ol1}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth2:before{content:counter(ol2) ". ";counter-increment:ol2}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth3:before{content:counter(ol3) ". ";counter-increment:ol3}.public-DraftStyleDefault-orderedListItem.public-DraftStyleDefault-depth4:before{content:counter(ol4) ". ";counter-increment:ol4}.public-DraftStyleDefault-depth0.public-DraftStyleDefault-reset{counter-reset:ol0}.public-DraftStyleDefault-depth1.public-DraftStyleDefault-reset{counter-reset:ol1}.public-DraftStyleDefault-depth2.public-DraftStyleDefault-reset{counter-reset:ol2}.public-DraftStyleDefault-depth3.public-DraftStyleDefault-reset{counter-reset:ol3}.public-DraftStyleDefault-depth4.public-DraftStyleDefault-reset{counter-reset:ol4}
|
||||
|
||||
/*# sourceMappingURL=react-draft-wysiwyg.css.map*/
|
|
@ -5,7 +5,8 @@
|
|||
"phpmailer/phpmailer": "^5.2",
|
||||
"google/recaptcha": "~1.1",
|
||||
"gabordemooij/redbean": "^4.3",
|
||||
"ifsnop/mysqldump-php": "2.*"
|
||||
"ifsnop/mysqldump-php": "2.*",
|
||||
"ezyang/htmlpurifier": "^4.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "5.0.*"
|
||||
|
|
|
@ -26,8 +26,6 @@ class AddTopicController extends Controller {
|
|||
'iconColor' => Controller::request('iconColor')
|
||||
]);
|
||||
|
||||
$staff = Controller::getLoggedUser();
|
||||
|
||||
Log::createLog('ADD_TOPIC', $topic->name);
|
||||
|
||||
Response::respondSuccess([
|
||||
|
|
|
@ -30,7 +30,7 @@ class AddArticleController extends Controller {
|
|||
$article = new Article();
|
||||
$article->setProperties([
|
||||
'title' => Controller::request('title'),
|
||||
'content' => Controller::request('content'),
|
||||
'content' => Controller::request('content', true),
|
||||
'lastEdited' => Date::getCurrentDate(),
|
||||
'position' => Controller::request('position') || 1
|
||||
]);
|
||||
|
@ -39,8 +39,6 @@ class AddArticleController extends Controller {
|
|||
$topic->ownArticleList->add($article);
|
||||
$topic->store();
|
||||
|
||||
$staff = Controller::getLoggedUser();
|
||||
|
||||
Log::createLog('ADD_ARTICLE', $article->title);
|
||||
|
||||
Response::respondSuccess([
|
||||
|
|
|
@ -33,7 +33,7 @@ class EditArticleController extends Controller {
|
|||
}
|
||||
|
||||
if(Controller::request('content')) {
|
||||
$article->content = Controller::request('content');
|
||||
$article->content = Controller::request('content', true);
|
||||
}
|
||||
|
||||
if(Controller::request('title')) {
|
||||
|
|
|
@ -19,7 +19,7 @@ class AddStaffController extends Controller {
|
|||
'permission' => 'staff_3',
|
||||
'requestData' => [
|
||||
'name' => [
|
||||
'validation' => DataValidator::length(2, 55)->alpha(),
|
||||
'validation' => DataValidator::length(2, 55),
|
||||
'error' => ERRORS::INVALID_NAME
|
||||
],
|
||||
'email' => [
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
use RedBeanPHP\Facade as RedBean;
|
||||
use Respect\Validation\Validator as DataValidator;
|
||||
|
||||
class GetNewTicketsStaffController extends Controller {
|
||||
|
@ -18,10 +19,16 @@ class GetNewTicketsStaffController extends Controller {
|
|||
$query .= 'department_id=' . $department->id . ' OR ';
|
||||
}
|
||||
$query = substr($query,0,-3);
|
||||
$query .= ') AND owner_id IS NULL';
|
||||
|
||||
$ownerExists = RedBean::exec('SHOW COLUMNS FROM ticket LIKE \'owner_id\'');
|
||||
|
||||
if($ownerExists != 0) {
|
||||
$query .= ') AND owner_id IS NULL';
|
||||
} else {
|
||||
$query .= ')';
|
||||
}
|
||||
|
||||
$ticketList = Ticket::find($query);
|
||||
|
||||
|
||||
Response::respondSuccess($ticketList->toArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,11 @@ class LastEventsStaffController extends Controller {
|
|||
$query = substr($query,0,-3);
|
||||
$query .= ') ORDER BY id desc LIMIT ? OFFSET ?' ;
|
||||
|
||||
$eventList = Ticketevent::find($query, [10, 10*($page-1)]);
|
||||
|
||||
Response::respondSuccess($eventList->toArray());
|
||||
if(Ticketevent::count() && !$user->sharedTicketList->isEmpty()) {
|
||||
$eventList = Ticketevent::find($query, [10, 10*($page-1)]);
|
||||
Response::respondSuccess($eventList->toArray());
|
||||
} else {
|
||||
Response::respondSuccess([]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ class SearchTicketStaffController extends Controller {
|
|||
'permission' => 'staff_1',
|
||||
'requestData' => [
|
||||
'query' => [
|
||||
'validation' => DataValidator::alpha(),
|
||||
'validation' => DataValidator::length(1),
|
||||
'error' => ERRORS::INVALID_QUERY
|
||||
],
|
||||
'page' => [
|
||||
|
|
|
@ -12,10 +12,10 @@ require_once 'system/recover-mail-template.php';
|
|||
require_once 'system/disable-registration.php';
|
||||
require_once 'system/enable-registration.php';
|
||||
require_once 'system/disable-user-system.php';
|
||||
require_once 'system/enabled-user-system.php';
|
||||
require_once 'system/enable-user-system.php';
|
||||
require_once 'system/add-api-key.php';
|
||||
require_once 'system/delete-api-key.php';
|
||||
require_once 'system/get-all-keys.php';
|
||||
require_once 'system/get-api-keys.php';
|
||||
require_once 'system/get-stats.php';
|
||||
require_once 'system/delete-all-users.php';
|
||||
require_once 'system/csv-import.php';
|
||||
|
@ -40,12 +40,12 @@ $systemControllerGroup->addController(new EnableRegistrationController);
|
|||
$systemControllerGroup->addController(new GetStatsController);
|
||||
$systemControllerGroup->addController(new AddAPIKeyController);
|
||||
$systemControllerGroup->addController(new DeleteAPIKeyController);
|
||||
$systemControllerGroup->addController(new GetAllKeyController);
|
||||
$systemControllerGroup->addController(new GetAPIKeysController);
|
||||
$systemControllerGroup->addController(new DeleteAllUsersController);
|
||||
$systemControllerGroup->addController(new BackupDatabaseController);
|
||||
$systemControllerGroup->addController(new DownloadController);
|
||||
$systemControllerGroup->addController(new CSVImportController);
|
||||
$systemControllerGroup->addController(new DisableUserSystemController);
|
||||
$systemControllerGroup->addController(new EnabledUserSystemController);
|
||||
$systemControllerGroup->addController(new EnableUserSystemController);
|
||||
|
||||
$systemControllerGroup->finalize();
|
||||
$systemControllerGroup->finalize();
|
||||
|
|
|
@ -12,7 +12,7 @@ class CSVImportController extends Controller {
|
|||
}
|
||||
|
||||
public function handler() {
|
||||
$fileUploader = $this->uploadFile();
|
||||
$fileUploader = $this->uploadFile(true);
|
||||
|
||||
if(!$fileUploader instanceof FileUploader) {
|
||||
throw new Exception(ERRORS::INVALID_FILE);
|
||||
|
|
|
@ -10,7 +10,7 @@ class DeleteAPIKeyController extends Controller {
|
|||
'permission' => 'staff_3',
|
||||
'requestData' => [
|
||||
'name' => [
|
||||
'validation' => DataValidator::length(2, 55)->alpha(),
|
||||
'validation' => DataValidator::length(2, 55),
|
||||
'error' => ERRORS::INVALID_NAME
|
||||
]
|
||||
]
|
||||
|
|
|
@ -32,8 +32,8 @@ class EditMailTemplateController extends Controller {
|
|||
public function handler() {
|
||||
$language = Controller::request('language');
|
||||
$templateType = Controller::request('templateType');
|
||||
$subject = Controller::request('subject');
|
||||
$body = Controller::request('body');
|
||||
$subject = Controller::request('subject', true);
|
||||
$body = Controller::request('body', true);
|
||||
|
||||
$mailTemplate = MailTemplate::findOne(' language = ? AND type = ?', [$language, $templateType]);
|
||||
if($mailTemplate->isNull()) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
class EnabledUserSystemController extends Controller {
|
||||
const PATH = '/enabled-user-system';
|
||||
class EnableUserSystemController extends Controller {
|
||||
const PATH = '/enable-user-system';
|
||||
const METHOD = 'POST';
|
||||
|
||||
public function validations() {
|
||||
|
@ -31,19 +31,17 @@ class EnabledUserSystemController extends Controller {
|
|||
|
||||
foreach($ticketList as $ticket) {
|
||||
|
||||
$userRow = User::getDataStore($ticket->authorEmail, 'email');
|
||||
$userInstance = User::getDataStore($ticket->authorEmail, 'email');
|
||||
|
||||
if($userRow->isNull()) {
|
||||
$this->createUser($ticket->authorEmail,$ticket->authorName);
|
||||
|
||||
} else {
|
||||
$userRow->tickets = $userRow->tickets + 1;
|
||||
$userRow->sharedTicketList->add($ticket);
|
||||
$userRow->store();
|
||||
if($userInstance->isNull()) {
|
||||
$userInstance = $this->createUser($ticket->authorEmail, $ticket->authorName);
|
||||
}
|
||||
|
||||
$actualUserRow = User::getDataStore($ticket->authorEmail,'email');
|
||||
$ticket->author = $actualUserRow;
|
||||
$userInstance->tickets = $userInstance->tickets + 1;
|
||||
$userInstance->sharedTicketList->add($ticket);
|
||||
$userInstance->store();
|
||||
|
||||
$ticket->author = $userInstance;
|
||||
$ticket->authorName = null;
|
||||
$ticket->authorEmail = null;
|
||||
$ticket->store();
|
||||
|
@ -59,7 +57,7 @@ class EnabledUserSystemController extends Controller {
|
|||
$userInstance->setProperties([
|
||||
'name' => $name,
|
||||
'signupDate' => Date::getCurrentDate(),
|
||||
'tickets' => 1,
|
||||
'tickets' => 0,
|
||||
'email' => $email,
|
||||
'password' => Hashing::hashPassword($password),
|
||||
'verificationToken' => null
|
||||
|
@ -75,5 +73,6 @@ class EnabledUserSystemController extends Controller {
|
|||
]);
|
||||
$mailSender->send();
|
||||
|
||||
return $userInstance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
use Respect\Validation\Validator as DataValidator;
|
||||
|
||||
class GetAllKeyController extends Controller {
|
||||
const PATH = '/get-all-keys';
|
||||
class GetAPIKeysController extends Controller {
|
||||
const PATH = '/get-api-keys';
|
||||
const METHOD = 'POST';
|
||||
|
||||
public function validations() {
|
|
@ -10,7 +10,7 @@ class GetStatsController extends Controller {
|
|||
'permission' => 'staff_1',
|
||||
'requestData' => [
|
||||
'period' => [
|
||||
'validation' => DataValidator::in(['week', 'month', 'quarter', 'year']),
|
||||
'validation' => DataValidator::in(['WEEK', 'MONTH', 'QUARTER', 'YEAR']),
|
||||
'error' => ERRORS::INVALID_PERIOD
|
||||
]
|
||||
]
|
||||
|
@ -123,16 +123,16 @@ class GetStatsController extends Controller {
|
|||
$daysToRetrieve = 0;
|
||||
|
||||
switch ($period) {
|
||||
case 'week':
|
||||
case 'WEEK':
|
||||
$daysToRetrieve = 7;
|
||||
break;
|
||||
case 'month':
|
||||
case 'MONTH':
|
||||
$daysToRetrieve = 30;
|
||||
break;
|
||||
case 'quarter':
|
||||
case 'QUARTER':
|
||||
$daysToRetrieve = 90;
|
||||
break;
|
||||
case 'year':
|
||||
case 'YEAR':
|
||||
$daysToRetrieve = 365;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ class InitSettingsController extends Controller {
|
|||
'url' => 'http://www.opensupports.com/support',
|
||||
'registration' => true,
|
||||
'user-system-enabled' => true,
|
||||
'last-stat-day' => '20170101', //TODO: get current date
|
||||
'last-stat-day' => date('YmdHi', strtotime(' -12 day ')), //TODO: get current date
|
||||
'ticket-gap' => Hashing::generateRandomPrime(100000, 999999),
|
||||
'file-gap' => Hashing::generateRandomPrime(100000, 999999),
|
||||
'file-first-number' => Hashing::generateRandomNumber(100000, 999999),
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
include 'ticket/create.php';
|
||||
include 'ticket/comment.php';
|
||||
include 'ticket/get.php';
|
||||
include 'ticket/check.php';
|
||||
include 'ticket/add-custom-response.php';
|
||||
include 'ticket/delete-custom-response.php';
|
||||
include 'ticket/edit-custom-response.php';
|
||||
|
@ -18,6 +19,7 @@ $ticketControllers->setGroupPath('/ticket');
|
|||
$ticketControllers->addController(new CreateController);
|
||||
$ticketControllers->addController(new CommentController);
|
||||
$ticketControllers->addController(new TicketGetController);
|
||||
$ticketControllers->addController(new CheckTicketController);
|
||||
$ticketControllers->addController(new AddCustomResponseController);
|
||||
$ticketControllers->addController(new DeleteCustomResponseController);
|
||||
$ticketControllers->addController(new EditCustomResponseController);
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
use Respect\Validation\Validator as DataValidator;
|
||||
DataValidator::with('CustomValidations', true);
|
||||
|
||||
class CheckTicketController extends Controller {
|
||||
const PATH = '/check';
|
||||
const METHOD = 'POST';
|
||||
|
||||
public function validations() {
|
||||
return [
|
||||
'permission' => 'any',
|
||||
'requestData' => [
|
||||
'ticketNumber' => [
|
||||
'validation' => DataValidator::validTicketNumber(),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
],
|
||||
'email' => [
|
||||
'validation' => DataValidator::email(),
|
||||
'error' => ERRORS::INVALID_EMAIL
|
||||
],
|
||||
'captcha' => [
|
||||
'validation' => DataValidator::captcha(),
|
||||
'error' => ERRORS::INVALID_CAPTCHA
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function handler() {
|
||||
if (Controller::isUserSystemEnabled() || Controller::isStaffLogged()) {
|
||||
throw new Exception(ERRORS::NO_PERMISSION);
|
||||
}
|
||||
|
||||
$email = Controller::request('email');
|
||||
$ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber'));
|
||||
|
||||
if($ticket->authorEmail === $email) {
|
||||
$session = Session::getInstance();
|
||||
$session->createTicketSession($ticket->ticketNumber);
|
||||
|
||||
Response::respondSuccess([
|
||||
'token' => $session->getToken(),
|
||||
'ticketNumber' => $ticket->ticketNumber
|
||||
]);
|
||||
} else {
|
||||
throw new Exception(ERRORS::NO_PERMISSION);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,42 +10,49 @@ class CommentController extends Controller {
|
|||
private $content;
|
||||
|
||||
public function validations() {
|
||||
$validations = [
|
||||
'permission' => 'user',
|
||||
'requestData' => [
|
||||
'content' => [
|
||||
'validation' => DataValidator::length(20, 5000),
|
||||
'error' => ERRORS::INVALID_CONTENT
|
||||
],
|
||||
'ticketNumber' => [
|
||||
'validation' => DataValidator::validTicketNumber(),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
if(!Controller::isUserSystemEnabled()) {
|
||||
$validations['permission'] = 'any';
|
||||
$session = Session::getInstance();
|
||||
$session = Session::getInstance();
|
||||
|
||||
$validations['requestData']['csrf_token'] = [
|
||||
'validation' => DataValidator::equals($session->getToken()),
|
||||
'error' => ERRORS::NO_PERMISSION
|
||||
if (Controller::isUserSystemEnabled() || Controller::isStaffLogged()) {
|
||||
return [
|
||||
'permission' => 'user',
|
||||
'requestData' => [
|
||||
'content' => [
|
||||
'validation' => DataValidator::length(20, 5000),
|
||||
'error' => ERRORS::INVALID_CONTENT
|
||||
],
|
||||
'ticketNumber' => [
|
||||
'validation' => DataValidator::validTicketNumber(),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
]
|
||||
]
|
||||
];
|
||||
$validations['requestData']['ticketNumber'] = [
|
||||
'validation' => DataValidator::equals($session->getTicketNumber()),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
} else {
|
||||
return [
|
||||
'permission' => 'any',
|
||||
'requestData' => [
|
||||
'content' => [
|
||||
'validation' => DataValidator::length(20, 5000),
|
||||
'error' => ERRORS::INVALID_CONTENT
|
||||
],
|
||||
'ticketNumber' => [
|
||||
'validation' => DataValidator::equals($session->getTicketNumber()),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
],
|
||||
'csrf_token' => [
|
||||
'validation' => DataValidator::equals($session->getToken()),
|
||||
'error' => Controller::request('csrf_token') . ' ' . $session->getToken()
|
||||
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
return $validations;
|
||||
}
|
||||
|
||||
public function handler() {
|
||||
$session = Session::getInstance();
|
||||
$this->requestData();
|
||||
|
||||
if (!Controller::isUserSystemEnabled() || $session->isLoggedWithId($this->ticket->author->id) || Controller::isStaffLogged()) {
|
||||
if ((!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) || $session->isLoggedWithId(($this->ticket->author) ? $this->ticket->author->id : 0) || (Controller::isStaffLogged() && $session->isLoggedWithId(($this->ticket->owner) ? $this->ticket->owner->id : 0))) {
|
||||
$this->storeComment();
|
||||
|
||||
Log::createLog('COMMENT', $this->ticket->ticketNumber);
|
||||
|
@ -58,13 +65,8 @@ class CommentController extends Controller {
|
|||
|
||||
private function requestData() {
|
||||
$ticketNumber = Controller::request('ticketNumber');
|
||||
$email = Controller::request('email');
|
||||
$this->ticket = Ticket::getByTicketNumber($ticketNumber);
|
||||
$this->content = Controller::request('content');
|
||||
|
||||
if(!Controller::isUserSystemEnabled() && $this->ticket->authorEmail !== $email && !Controller::isStaffLogged()) {
|
||||
throw new Exception(ERRORS::NO_PERMISSION);
|
||||
}
|
||||
$this->content = Controller::request('content', true);
|
||||
}
|
||||
|
||||
private function storeComment() {
|
||||
|
@ -84,7 +86,7 @@ class CommentController extends Controller {
|
|||
$this->ticket->unreadStaff = true;
|
||||
$comment->authorUser = Controller::getLoggedUser();
|
||||
}
|
||||
|
||||
|
||||
$this->ticket->addEvent($comment);
|
||||
$this->ticket->store();
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ class CreateController extends Controller {
|
|||
|
||||
public function handler() {
|
||||
$this->title = Controller::request('title');
|
||||
$this->content = Controller::request('content');
|
||||
$this->content = Controller::request('content', true);
|
||||
$this->departmentId = Controller::request('departmentId');
|
||||
$this->language = Controller::request('language');
|
||||
$this->email = Controller::request('email');
|
||||
|
|
|
@ -22,7 +22,7 @@ class EditCustomResponseController extends Controller {
|
|||
$customResponse = CustomResponse::getDataStore(Controller::request('id'));
|
||||
|
||||
if (Controller::request('content')) {
|
||||
$customResponse->content = Controller::request('content');
|
||||
$customResponse->content = Controller::request('content', true);
|
||||
}
|
||||
|
||||
if (Controller::request('language')) {
|
||||
|
|
|
@ -9,83 +9,53 @@ class TicketGetController extends Controller {
|
|||
private $ticket;
|
||||
|
||||
public function validations() {
|
||||
$validations = [
|
||||
'permission' => 'user',
|
||||
'requestData' => [
|
||||
'ticketNumber' => [
|
||||
'validation' => DataValidator::validTicketNumber(),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
$session = Session::getInstance();
|
||||
|
||||
if (Controller::isUserSystemEnabled() || Controller::isStaffLogged()) {
|
||||
return [
|
||||
'permission' => 'user',
|
||||
'requestData' => [
|
||||
'ticketNumber' => [
|
||||
'validation' => DataValidator::validTicketNumber(),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) {
|
||||
$validations['permission'] = 'any';
|
||||
|
||||
if(Controller::request('token')) {
|
||||
$session = Session::getInstance();
|
||||
|
||||
$validations['requestData']['csrf_token'] = [
|
||||
'validation' => DataValidator::equals($session->getToken()),
|
||||
'error' => ERRORS::NO_PERMISSION
|
||||
];
|
||||
$validations['requestData']['ticketNumber'] = [
|
||||
'validation' => DataValidator::equals($session->getTicketNumber()),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
];
|
||||
} else {
|
||||
$validations['requestData']['email'] = [
|
||||
'validation' => DataValidator::email(),
|
||||
'error' => ERRORS::INVALID_EMAIL
|
||||
];
|
||||
$validations['requestData']['captcha'] = [
|
||||
'validation' => DataValidator::captcha(),
|
||||
'error' => ERRORS::INVALID_CAPTCHA
|
||||
];
|
||||
}
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'permission' => 'any',
|
||||
'requestData' => [
|
||||
'ticketNumber' => [
|
||||
'validation' => DataValidator::equals($session->getTicketNumber()),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
],
|
||||
'csrf_token' => [
|
||||
'validation' => DataValidator::equals($session->getToken()),
|
||||
'error' => $session->getToken() . ' != ' . Controller::request('csrf_token')
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
return $validations;
|
||||
}
|
||||
|
||||
public function handler() {
|
||||
$email = Controller::request('email');
|
||||
|
||||
$this->ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber'));
|
||||
|
||||
if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) {
|
||||
if($this->ticket->authorEmail === $email) {
|
||||
if(!Controller::request('token')) {
|
||||
$this->generateSessionToken();
|
||||
} else {
|
||||
Response::respondSuccess($this->ticket->toArray());
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if(Controller::isUserSystemEnabled() || Controller::isStaffLogged()) {
|
||||
if ($this->shouldDenyPermission()) {
|
||||
throw new Exception(ERRORS::NO_PERMISSION);
|
||||
} else {
|
||||
Response::respondSuccess($this->ticket->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->shouldDenyPermission()) {
|
||||
throw new Exception(ERRORS::NO_PERMISSION);
|
||||
} else {
|
||||
Response::respondSuccess($this->ticket->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
private function generateSessionToken() {
|
||||
$session = Session::getInstance();
|
||||
$token = Hashing::generateRandomToken();
|
||||
|
||||
$session->createTicketSession($this->ticket->ticketNUmber);
|
||||
|
||||
Response::respondSuccess(['token' => $token, 'ticketNumber' => $this->ticket->ticketNUmber]);
|
||||
}
|
||||
|
||||
private function shouldDenyPermission() {
|
||||
$user = Controller::getLoggedUser();
|
||||
|
||||
return (!Controller::isStaffLogged() && (Controller::isUserSystemEnabled() && $this->ticket->author->id !== $user->id)) ||
|
||||
(Controller::isStaffLogged() && $this->ticket->owner && $this->ticket->owner->id !== $user->id);
|
||||
(Controller::isStaffLogged() && (($this->ticket->owner && $this->ticket->owner->id !== $user->id) || !$user->sharedDepartmentList->includesId($this->ticket->department->id)));
|
||||
}
|
||||
}
|
|
@ -30,6 +30,11 @@ class DeleteUserController extends Controller {
|
|||
|
||||
Log::createLog('DELETE_USER', $user->name);
|
||||
RedBean::exec('DELETE FROM log WHERE author_user_id = ?', [$userId]);
|
||||
|
||||
foreach($user->sharedTicketList as $ticket) {
|
||||
$ticket->delete();
|
||||
}
|
||||
|
||||
$user->delete();
|
||||
|
||||
Response::respondSuccess();
|
||||
|
|
|
@ -24,6 +24,11 @@ class LoginController extends Controller {
|
|||
}
|
||||
|
||||
if ($this->checkInputCredentials() || $this->checkRememberToken()) {
|
||||
if($this->userInstance->verificationToken !== null) {
|
||||
Response::respondError(ERRORS::UNVERIFIED_USER);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->createUserSession();
|
||||
$this->createSessionCookie();
|
||||
if(Controller::request('staff')) {
|
||||
|
@ -31,14 +36,6 @@ class LoginController extends Controller {
|
|||
$this->userInstance->store();
|
||||
}
|
||||
|
||||
$email = Controller::request('email');
|
||||
$userRow = User::getDataStore($email, 'email');
|
||||
|
||||
if($userRow->verificationToken !== null) {
|
||||
Response::respondError(ERRORS::UNVERIFIED_USER);
|
||||
return;
|
||||
}
|
||||
|
||||
Response::respondSuccess($this->getUserData());
|
||||
} else {
|
||||
Response::respondError(ERRORS::INVALID_CREDENTIALS);
|
||||
|
|
|
@ -22,7 +22,7 @@ class SignUpController extends Controller {
|
|||
'permission' => 'any',
|
||||
'requestData' => [
|
||||
'name' => [
|
||||
'validation' => DataValidator::length(2, 55)->alpha(),
|
||||
'validation' => DataValidator::length(2, 55),
|
||||
'error' => ERRORS::INVALID_NAME
|
||||
],
|
||||
'email' => [
|
||||
|
|
|
@ -55,4 +55,6 @@ foreach (glob('controllers/*.php') as $controller) {
|
|||
include_once $controller;
|
||||
}
|
||||
|
||||
Date::setTimeZone();
|
||||
|
||||
$app->run();
|
||||
|
|
|
@ -47,8 +47,16 @@ abstract class Controller {
|
|||
self::$dataRequester = $dataRequester;
|
||||
}
|
||||
|
||||
public static function request($key) {
|
||||
return call_user_func(self::$dataRequester, $key);
|
||||
public static function request($key, $secure = false) {
|
||||
$result = call_user_func(self::$dataRequester, $key);
|
||||
|
||||
if($secure) {
|
||||
$config = HTMLPurifier_Config::createDefault();
|
||||
$purifier = new HTMLPurifier($config);
|
||||
return $purifier->purify($result);
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getLoggedUser() {
|
||||
|
@ -78,8 +86,10 @@ abstract class Controller {
|
|||
return \Slim\Slim::getInstance();
|
||||
}
|
||||
|
||||
public function uploadFile() {
|
||||
if(!isset($_FILES['file'])) return '';
|
||||
public function uploadFile($forceUpload = false) {
|
||||
$allowAttachments = Setting::getSetting('allow-attachments')->getValue();
|
||||
|
||||
if(!isset($_FILES['file']) || (!$allowAttachments && !$forceUpload)) return '';
|
||||
|
||||
$maxSize = Setting::getSetting('max-size')->getValue();
|
||||
$fileGap = Setting::getSetting('file-gap')->getValue();
|
||||
|
|
|
@ -45,6 +45,10 @@ class DataStoreList implements IteratorAggregate {
|
|||
return $includes;
|
||||
}
|
||||
|
||||
public function isEmpty() {
|
||||
return empty($this->list);
|
||||
}
|
||||
|
||||
public function toBeanList() {
|
||||
$beanList = [];
|
||||
|
||||
|
|
|
@ -1,5 +1,21 @@
|
|||
<?php
|
||||
class Date {
|
||||
public static function setTimeZone() {
|
||||
$timezone = Setting::getSetting('time-zone');
|
||||
|
||||
if(!$timezone->isNull()) {
|
||||
$timezone = $timezone->getValue();
|
||||
|
||||
if($timezone > 0) {
|
||||
date_default_timezone_set('GMT+' . $timezone);
|
||||
} else if($timezone == 0) {
|
||||
date_default_timezone_set('GMT');
|
||||
} else {
|
||||
date_default_timezone_set('GMT-' . abs($timezone * 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getCurrentDate() {
|
||||
return date('YmdHi');
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class Ticket extends DataStore {
|
|||
public static function getTicket($value, $property = 'id') {
|
||||
return parent::getDataStore($value, $property);
|
||||
}
|
||||
|
||||
|
||||
public static function getByTicketNumber($value) {
|
||||
return Ticket::getTicket($value, 'ticketNumber');
|
||||
}
|
||||
|
@ -50,19 +50,19 @@ class Ticket extends DataStore {
|
|||
public function generateUniqueTicketNumber() {
|
||||
$linearCongruentialGenerator = new LinearCongruentialGenerator();
|
||||
$ticketQuantity = Ticket::count();
|
||||
|
||||
|
||||
if ($ticketQuantity === 0) {
|
||||
$ticketNumber = $linearCongruentialGenerator->generateFirst();
|
||||
} else {
|
||||
$linearCongruentialGenerator->setGap(Setting::getSetting('ticket-gap')->value);
|
||||
$linearCongruentialGenerator->setFirst(Ticket::getTicket(1)->ticketNumber);
|
||||
|
||||
|
||||
$ticketNumber = $linearCongruentialGenerator->generate($ticketQuantity);
|
||||
}
|
||||
|
||||
return $ticketNumber;
|
||||
}
|
||||
|
||||
|
||||
public function toArray() {
|
||||
return [
|
||||
'ticketNumber' => $this->ticketNumber,
|
||||
|
@ -81,9 +81,7 @@ class Ticket extends DataStore {
|
|||
'priority' => $this->priority,
|
||||
'author' => $this->authorToArray(),
|
||||
'owner' => $this->ownerToArray(),
|
||||
'events' => $this->eventsToArray(),
|
||||
'authorEmail' => $this->authorEmail,
|
||||
'authorName' => $this->authorName
|
||||
'events' => $this->eventsToArray()
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -97,7 +95,10 @@ class Ticket extends DataStore {
|
|||
'email' => $author->email
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
return [
|
||||
'name' => $this->authorName,
|
||||
'email' => $this->authorEmail
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,7 +144,7 @@ class Ticket extends DataStore {
|
|||
|
||||
return $events;
|
||||
}
|
||||
|
||||
|
||||
public function addEvent(Ticketevent $event) {
|
||||
$this->ownTicketeventList->add($event);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ require './system/disable-registration.rb'
|
|||
require './system/enable-registration.rb'
|
||||
require './system/add-api-key.rb'
|
||||
require './system/delete-api-key.rb'
|
||||
require './system/get-all-keys.rb'
|
||||
require './system/get-api-keys.rb'
|
||||
require './system/file-upload-download.rb'
|
||||
require './system/csv-import.rb'
|
||||
require './system/disable-user-system.rb'
|
||||
|
|
|
@ -10,7 +10,7 @@ class Scripts
|
|||
raise response['message']
|
||||
end
|
||||
userRow = $database.getRow('user', email, 'email')
|
||||
response = request('/user/verify', {
|
||||
request('/user/verify', {
|
||||
:email => email,
|
||||
:token => userRow['verification_token']
|
||||
})
|
||||
|
@ -32,9 +32,9 @@ class Scripts
|
|||
response['data']
|
||||
end
|
||||
|
||||
def self.createTicket()
|
||||
def self.createTicket(title = 'Winter is coming')
|
||||
result = request('/ticket/create', {
|
||||
title: 'Winter is coming',
|
||||
title: title,
|
||||
content: 'The north remembers',
|
||||
departmentId: 1,
|
||||
language: 'en',
|
||||
|
@ -46,7 +46,7 @@ class Scripts
|
|||
end
|
||||
|
||||
def self.createAPIKey(name)
|
||||
result = request('/system/add-api-key', {
|
||||
request('/system/add-api-key', {
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token,
|
||||
name: name
|
||||
|
|
|
@ -9,7 +9,6 @@ describe'system/disable-user-system' do
|
|||
password:$staff[:password]
|
||||
})
|
||||
|
||||
puts result['message']
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
row = $database.getRow('setting', 'user-system-enabled', 'name')
|
||||
|
@ -20,7 +19,7 @@ describe'system/disable-user-system' do
|
|||
|
||||
numberOftickets= $database.query("SELECT * FROM ticket WHERE author_id IS NULL AND author_email IS NOT NULL AND author_name IS NOT NULL")
|
||||
|
||||
(numberOftickets.num_rows).should.equal(35)
|
||||
(numberOftickets.num_rows).should.equal(36)
|
||||
|
||||
request('/user/logout')
|
||||
|
||||
|
@ -56,14 +55,13 @@ describe'system/disable-user-system' do
|
|||
(result['message']).should.equal('SYSTEM_USER_IS_ALREADY_DISABLED')
|
||||
end
|
||||
|
||||
it 'should enabled the user system' do
|
||||
result = request('/system/enabled-user-system', {
|
||||
it 'should enable the user system' do
|
||||
result = request('/system/enable-user-system', {
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token,
|
||||
password:$staff[:password]
|
||||
})
|
||||
|
||||
puts result['message']
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
row = $database.getRow('setting', 'user-system-enabled', 'name')
|
||||
|
@ -71,12 +69,12 @@ describe'system/disable-user-system' do
|
|||
|
||||
numberOftickets= $database.query("SELECT * FROM ticket WHERE author_email IS NULL AND author_name IS NULL AND author_id IS NOT NULL" )
|
||||
|
||||
(numberOftickets.num_rows).should.equal(35)
|
||||
(numberOftickets.num_rows).should.equal(36)
|
||||
|
||||
end
|
||||
|
||||
it 'should not enabled the user system' do
|
||||
result = request('/system/enabled-user-system', {
|
||||
it 'should not enable the user system' do
|
||||
result = request('/system/enable-user-system', {
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token,
|
||||
password:$staff[:password]
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
describe'system/get-all-keys' do
|
||||
describe'system/get-api-keys' do
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
|
||||
it 'should get all API keys' do
|
||||
it 'should get all API keys' do
|
||||
Scripts.createAPIKey('namekey1')
|
||||
Scripts.createAPIKey('namekey2')
|
||||
Scripts.createAPIKey('namekey3')
|
||||
Scripts.createAPIKey('namekey4')
|
||||
Scripts.createAPIKey('namekey5')
|
||||
|
||||
result= request('/system/get-all-keys', {
|
||||
result = request('/system/get-api-keys', {
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token,
|
||||
})
|
|
@ -74,7 +74,7 @@ describe'/system/get-stats' do
|
|||
@result = request('/system/get-stats', {
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token,
|
||||
period: 'week'
|
||||
period: 'WEEK'
|
||||
})
|
||||
|
||||
def assertData(position, date, type, value)
|
||||
|
@ -126,7 +126,7 @@ describe'/system/get-stats' do
|
|||
@result = request('/system/get-stats', {
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token,
|
||||
period: 'week',
|
||||
period: 'WEEK',
|
||||
staffId: '1'
|
||||
})
|
||||
assertData(0, yesterday, 'CLOSE', '4')
|
||||
|
|
|
@ -1,28 +1,30 @@
|
|||
describe '/user/delete' do
|
||||
|
||||
request('/user/logout')
|
||||
result = request('/user/login', {
|
||||
email: 'staff@opensupports.com',
|
||||
password: 'staff',
|
||||
staff: true
|
||||
})
|
||||
|
||||
$csrf_userid = result['data']['userId']
|
||||
$csrf_token = result['data']['token']
|
||||
|
||||
it 'should delete user' do
|
||||
Scripts.createUser('deletable@opensupports.com', 'deletable')
|
||||
Scripts.login('deletable@opensupports.com', 'deletable')
|
||||
Scripts.createTicket('Ticket that will be deleted')
|
||||
|
||||
request('/user/logout')
|
||||
Scripts.login('staff@opensupports.com', 'staff', true)
|
||||
ticket = $database.getLastRow('ticket')
|
||||
deletable_user = $database.getLastRow('user')
|
||||
|
||||
result = request('/user/delete', {
|
||||
userId: 4,
|
||||
userId: deletable_user['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
user = $database.getRow('user', 4 , 'id')
|
||||
(user).should.equal(nil)
|
||||
last_ticket = $database.getLastRow('ticket')
|
||||
last_log = $database.getLastRow('log')
|
||||
user = $database.getRow('user', deletable_user['id'] , 'id')
|
||||
|
||||
lastLog = $database.getLastRow('log')
|
||||
(lastLog['type']).should.equal('DELETE_USER')
|
||||
(user).should.equal(nil)
|
||||
(ticket['id']).should.not.equal(last_ticket['id'])
|
||||
(last_log['type']).should.equal('DELETE_USER')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -52,5 +52,13 @@ describe '/user/edit-password' do
|
|||
csrf_token: $csrf_token
|
||||
})
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
request('/user/logout')
|
||||
|
||||
result = request('/user/login',{
|
||||
email: 'steve@jobs.com',
|
||||
password: 'newpassword'
|
||||
})
|
||||
(result['status']).should.equal('success')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -41,15 +41,6 @@ describe '/user/signup' do
|
|||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_NAME')
|
||||
|
||||
result = request('/user/signup', {
|
||||
name: 'tyri0n',
|
||||
email: 'tyrion@outlook.com',
|
||||
password: 'Lannister'
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_NAME')
|
||||
end
|
||||
|
||||
it 'should fail if email is invalid' do
|
||||
|
|
Loading…
Reference in New Issue