Default department feature (#805)

* pt 2

* do not allow to delete default depto

* ticket craete changes and ruby tests

* set langauge to ticket  and ruby tests

* show departments/lenaguages dropdown logic frontend

* default department frontend

* fix github comments

* add logic edit-setting

* add settings to reducer

* resolve git hub comments logic frontend

* delete variables without use

* select default department dropdown

* fix ruby tabulation

* delete creaticketform console.log
This commit is contained in:
Guillermo Giuliana 2020-06-15 16:27:45 -03:00 committed by GitHub
parent 21290c600f
commit 1e7a3e2f4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 633 additions and 57 deletions

View File

@ -5,9 +5,10 @@ import {connect} from 'react-redux';
import i18n from 'lib-app/i18n'; import i18n from 'lib-app/i18n';
import API from 'lib-app/api-call'; import API from 'lib-app/api-call';
import ConfigActions from 'actions/config-actions'; import ConfigActions from 'actions/config-actions';
import SessionStore from 'lib-app/session-store';
import AreYouSure from 'app-components/are-you-sure'; import AreYouSure from 'app-components/are-you-sure';
import DepartmentDropDown from 'app-components/department-dropdown'; import DepartmentDropdown from 'app-components/department-dropdown';
import InfoTooltip from 'core-components/info-tooltip'; import InfoTooltip from 'core-components/info-tooltip';
import Button from 'core-components/button'; import Button from 'core-components/button';
@ -16,10 +17,20 @@ import Listing from 'core-components/listing';
import Form from 'core-components/form'; import Form from 'core-components/form';
import FormField from 'core-components/form-field'; import FormField from 'core-components/form-field';
import SubmitButton from 'core-components/submit-button'; import SubmitButton from 'core-components/submit-button';
import DropDown from 'core-components/drop-down';
import Icon from 'core-components/icon'; import Icon from 'core-components/icon';
import Message from 'core-components/message'; import Message from 'core-components/message';
import Loading from 'core-components/loading'
function getPublicDepartmentList(){
return _.filter(SessionStore.getDepartments(),item => item.private != 1)
}
export const getPublicDepartmentIndexFromDepartmentId = (departmentId) => {
const departments = getPublicDepartmentList();
const departmentIndex = _.findIndex(departments, department => department.id == departmentId );
return (departmentIndex !== -1) ? departmentIndex : 0;
}
class AdminPanelDepartments extends React.Component { class AdminPanelDepartments extends React.Component {
static defaultProps = { static defaultProps = {
items: [] items: []
@ -32,14 +43,23 @@ class AdminPanelDepartments extends React.Component {
edited: false, edited: false,
errorMessage: null, errorMessage: null,
errors: {}, errors: {},
defaultDepartmentError: null,
form: { form: {
title: '', title: '',
language: 'en', language: 'en',
private: 0, private: 0,
} },
defaultDepartment: this.props.defaultDepartmentId,
defaultDepartmentLocked: this.props.defaultDepartmentLocked * 1,
}; };
render() { render() {
const {
errorMessage,
formLoading,
selectedIndex
} = this.state;
return ( return (
<div className="admin-panel-departments"> <div className="admin-panel-departments">
<Header title={i18n('DEPARTMENTS')} description={i18n('DEPARTMENTS_DESCRIPTION')} /> <Header title={i18n('DEPARTMENTS')} description={i18n('DEPARTMENTS_DESCRIPTION')} />
@ -48,7 +68,7 @@ class AdminPanelDepartments extends React.Component {
<Listing {...this.getListingProps()}/> <Listing {...this.getListingProps()}/>
</div> </div>
<div className="col-md-8"> <div className="col-md-8">
{(this.state.errorMessage) ? <Message type="error">{i18n(this.state.errorMessage)}</Message> : null} {(errorMessage) ? <Message type="error">{i18n(errorMessage)}</Message> : null}
<Form {...this.getFormProps()}> <Form {...this.getFormProps()}>
<div> <div>
<FormField className="admin-panel-departments__name" label={i18n('NAME')} name="name" validation="NAME" required fieldProps={{size: 'large'}}/> <FormField className="admin-panel-departments__name" label={i18n('NAME')} name="name" validation="NAME" required fieldProps={{size: 'large'}}/>
@ -57,16 +77,63 @@ class AdminPanelDepartments extends React.Component {
<InfoTooltip className="admin-panel-departments__info-tooltip" text={i18n('PRIVATE_DEPARTMENT_DESCRIPTION')} /> <InfoTooltip className="admin-panel-departments__info-tooltip" text={i18n('PRIVATE_DEPARTMENT_DESCRIPTION')} />
</div> </div>
</div> </div>
<SubmitButton size="medium" className="admin-panel-departments__update-name-button" type="secondary"> <SubmitButton
{i18n((this.state.selectedIndex !== -1) ? 'UPDATE_DEPARTMENT' : 'ADD_DEPARTMENT')} size="medium"
className="admin-panel-departments__update-name-button"
type="secondary">
{formLoading ?
<Loading /> :
i18n((selectedIndex !== -1) ?
'UPDATE_DEPARTMENT' :
'ADD_DEPARTMENT')}
</SubmitButton> </SubmitButton>
</Form> </Form>
{(this.state.selectedIndex !== -1 && this.props.departments.length) ? this.renderOptionalButtons() : null} {(selectedIndex !== -1 && this.props.departments.length) ? this.renderOptionalButtons() : null}
</div> </div>
</div> </div>
{this.renderDefaultDepartmentForm()}
</div> </div>
); );
} }
renderDefaultDepartmentForm() {
const {
defaultDepartmentError,
formLoading
} = this.state
return (
<div className="admin-panel-departments__default-departments-container">
<span className="separator" />
{(defaultDepartmentError !== null) ?
((!defaultDepartmentError) ?
<Message type="success">{i18n('SETTINGS_UPDATED')}</Message> :
<Message type="error">{i18n(defaultDepartmentError)}</Message>) :
null}
<Form {...this.getDefaultDepartmentFormProps()} className="admin-panel-departments__default-departments-container__form">
<div className="admin-panel-departments__default-departments-container__form__fields" >
<FormField
className="admin-panel-departments__default-departments-container__form__fields__select"
label={i18n('DEFAULT_DEPARTMENT')}
name="defaultDepartment"
field="select"
decorator={DepartmentDropdown}
fieldProps={{ departments: getPublicDepartmentList() , size: 'medium' }}
/>
<div className="admin-panel-departments__default-departments-container__form__fields__lock-option">
<FormField label={i18n('LOCK_DEPARTMENT_DESCRIPTION')} name="locked" field="checkbox"/>
</div>
</div>
<SubmitButton
className="admin-panel-departments__default-departments-container__form__button"
size="medium"
type="secondary" >
{formLoading ? <Loading /> : i18n('UPDATE_DEFAULT_DEPARTMENT')}
</SubmitButton>
</Form>
</div>
)
}
renderOptionalButtons() { renderOptionalButtons() {
return ( return (
@ -93,22 +160,32 @@ class AdminPanelDepartments extends React.Component {
{i18n('WILL_DELETE_DEPARTMENT')} {i18n('WILL_DELETE_DEPARTMENT')}
<div className="admin-panel-departments__transfer-tickets"> <div className="admin-panel-departments__transfer-tickets">
<span className="admin-panel-departments__transfer-tickets-title">{i18n('TRANSFER_TICKETS_TO')}</span> <span className="admin-panel-departments__transfer-tickets-title">{i18n('TRANSFER_TICKETS_TO')}</span>
<DepartmentDropDown className="admin-panel-departments__transfer-tickets-drop-down" departments={this.getDropDownDepartments()} onChange={(event) => this.setState({selectedDropDownIndex: event.index})} size="medium"/> <DepartmentDropdown
className="admin-panel-departments__transfer-tickets-drop-down"
departments={this.getDropDownDepartments()}
onChange={(event) => this.setState({selectedDropDownIndex: event.index})}
size="medium" />
</div> </div>
</div> </div>
); );
} }
getListingProps() { getListingProps() {
const {
departments,
defaultDepartmentId
} = this.props;
return { return {
className: 'admin-panel-departments__list', className: 'admin-panel-departments__list',
title: i18n('DEPARTMENTS'), title: i18n('DEPARTMENTS'),
items: this.props.departments.map(department => { items: departments.map(department => {
return { return {
content: ( content: (
<span> <span>
{department.name} {department.name}
{department.private*1 ? <Icon className="admin-panel-departments__private-icon" name='user-secret'/> : null } {department.private*1 ? <Icon className="admin-panel-departments__private-icon" name='user-secret'/> : null }
{department.id == defaultDepartmentId ? <spam className="admin-panel-departments__default-icon"> {i18n('DEFAULT')} </spam> : null }
{(!department.owners) ? ( {(!department.owners) ? (
<span className="admin-panel-departments__warning"> <span className="admin-panel-departments__warning">
<InfoTooltip type="warning" text={i18n('NO_STAFF_ASSIGNED')}/> <InfoTooltip type="warning" text={i18n('NO_STAFF_ASSIGNED')}/>
@ -126,13 +203,42 @@ class AdminPanelDepartments extends React.Component {
} }
getFormProps() { getFormProps() {
const {
form,
errors,
formLoading
} = this.state
return { return {
values: this.state.form, values: form,
errors: this.state.errors, errors: errors,
loading: this.state.formLoading,
onChange: (form) => {this.setState({form, edited: true})}, onChange: (form) => {this.setState({form, edited: true})},
onValidateErrors: (errors) => {this.setState({errors})}, onValidateErrors: (errors) => {this.setState({errors})},
onSubmit: this.onFormSubmit.bind(this) onSubmit: this.onFormSubmit.bind(this),
loading: formLoading
};
}
getDefaultDepartmentFormProps() {
const {
formLoading
} = this.state;
return {
values: {
defaultDepartment: getPublicDepartmentIndexFromDepartmentId(this.state.defaultDepartment),
locked: this.state.defaultDepartmentLocked,
},
onChange: (formValue) => {
this.setState({
edited: true,
defaultDepartmentError: null,
defaultDepartment: getPublicDepartmentList()[formValue.defaultDepartment].id,
defaultDepartmentLocked: formValue.locked,
});
},
onSubmit: this.onDefaultDepartmentFormSubmit.bind(this),
loading: formLoading
}; };
} }
@ -144,6 +250,23 @@ class AdminPanelDepartments extends React.Component {
} }
} }
onDefaultDepartmentFormSubmit(formValue) {
let publicDepartments = getPublicDepartmentList();
this.setState({formLoading: true, edited: false});
API.call({
path: '/system/edit-settings',
data: {
'default-department-id': this.getCurrentDepartment(publicDepartments, formValue.defaultDepartment).id,
'default-is-locked': formValue.locked ? 1 : 0
}
}).then(() => {
this.retrieveDepartments();
this.setState({formLoading: false, errorMessage: false, defaultDepartmentError: false});
}).catch(result => this.setState({formLoading: false, defaultDepartmentError: result.message}));
}
onFormSubmit(form) { onFormSubmit(form) {
this.setState({formLoading: true, edited: false}); this.setState({formLoading: true, edited: false});
@ -151,14 +274,14 @@ class AdminPanelDepartments extends React.Component {
API.call({ API.call({
path: '/system/edit-department', path: '/system/edit-department',
data: { data: {
departmentId: this.getCurrentDepartment().id, departmentId: this.getCurrentDepartment(this.props.departments).id,
name: form.name, name: form.name,
private: form.private ? 1 : 0 private: form.private ? 1 : 0
} }
}).then(() => { }).then(() => {
this.setState({formLoading: false}); this.setState({formLoading: false,errorMessage: false, defaultDepartmentError: null});
this.retrieveDepartments(); this.retrieveDepartments();
}).catch(result => this.setState({formLoading: false, errorMessage: result.message})); }).catch(result => this.setState({formLoading: false, errorMessage: result.message, defaultDepartmentError: null}));
} else { } else {
API.call({ API.call({
path: '/system/add-department', path: '/system/add-department',
@ -167,9 +290,13 @@ class AdminPanelDepartments extends React.Component {
private: form.private ? 1 : 0 private: form.private ? 1 : 0
} }
}).then(() => { }).then(() => {
this.setState({formLoading: false,errorMessage: false, defaultDepartmentError: null});
this.retrieveDepartments(); this.retrieveDepartments();
this.onItemChange(-1); this.onItemChange(-1);
}).catch(this.onItemChange.bind(this, -1)); }).catch(() => {
this.onItemChange.bind(this, -1)
this.setState({defaultDepartmentError: null});
});
} }
} }
@ -189,19 +316,20 @@ class AdminPanelDepartments extends React.Component {
API.call({ API.call({
path: '/system/delete-department', path: '/system/delete-department',
data: { data: {
departmentId: this.getCurrentDepartment().id, departmentId: this.getCurrentDepartment(this.props.departments).id,
transferDepartmentId: this.getDropDownItemId() transferDepartmentId: this.getDropDownItemId()
} }
}).then(() => { }).then(() => {
this.retrieveDepartments(); this.retrieveDepartments();
this.onItemChange(-1); this.onItemChange(-1);
this.setState({defaultDepartmentError: null});
}) })
.catch(result => this.setState({errorMessage: result.message})); .catch(result => this.setState({errorMessage: result.message, defaultDepartmentError: null}));
} }
updateForm(index) { updateForm(index) {
let form = _.clone(this.state.form); let form = _.clone(this.state.form);
let department = this.getCurrentDepartment(index); let department = this.getCurrentDepartment(this.props.departments,index);
form.name = (department && department.name) || ''; form.name = (department && department.name) || '';
form.private = (department && department.private) || 0; form.private = (department && department.private) || 0;
@ -212,7 +340,8 @@ class AdminPanelDepartments extends React.Component {
formLoading: false, formLoading: false,
form, form,
errorMessage: null, errorMessage: null,
errors: {} errors: {},
defaultDepartmentError: null
}); });
} }
@ -223,12 +352,17 @@ class AdminPanelDepartments extends React.Component {
}); });
} }
getCurrentDepartment(index) { getCurrentDepartment(list, index) {
return this.props.departments[(index == undefined) ? this.state.selectedIndex : index]; return list[(index == undefined) ? this.state.selectedIndex : index];
} }
getDropDownItemId() { getDropDownItemId() {
return this.props.departments.filter((department, index) => index !== this.state.selectedIndex)[this.state.selectedDropDownIndex].id; const {
selectedIndex,
selectedDropDownIndex
} = this.state;
return this.props.departments.filter((department, index) => index !== selectedIndex)[selectedDropDownIndex].id;
} }
getDropDownDepartments() { getDropDownDepartments() {
@ -238,6 +372,8 @@ class AdminPanelDepartments extends React.Component {
export default connect((store) => { export default connect((store) => {
return { return {
defaultDepartmentId: store.config['default-department-id']*1,
defaultDepartmentLocked: store.config['default-is-locked']*1,
departments: store.config.departments departments: store.config.departments
}; };
})(AdminPanelDepartments); })(AdminPanelDepartments);

View File

@ -18,6 +18,32 @@
display:inline-block; display:inline-block;
margin-left: 10px; margin-left: 10px;
} }
&__default-departments-container {
&__form {
text-align: left;
&__fields {
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: flex-start;
padding-bottom: 10px;
&__lock-option {
display: flex;
flex-direction: row;
align-items: center;
&__info-tooltip {
padding-left: 5px;
}
}
}
&__button {
min-width: 156px;
}
}
}
&__optional-buttons { &__optional-buttons {
float: right; float: right;
@ -49,7 +75,13 @@
&__private-icon { &__private-icon {
margin-left: 5px; margin-left: 5px;
} }
&__info-tooltip { &__default-icon {
color: lightgrey;
font-style: italic;
text-transform: lowercase;
margin-left: 3px;
}
&__info-tooltip {
margin-left: 2px; margin-left: 2px;
} }
} }

View File

@ -77,7 +77,7 @@ class AdminPanelMyTickets extends React.Component {
onCreateTicket() { onCreateTicket() {
ModalContainer.openModal( ModalContainer.openModal(
<div> <div>
<CreateTicketForm onSuccess={this.onCreateTicketSuccess.bind(this)} /> <CreateTicketForm isStaff={true} onSuccess={this.onCreateTicketSuccess.bind(this)} />
<div style={{textAlign: 'center'}}> <div style={{textAlign: 'center'}}>
<Button onClick={ModalContainer.closeModal} type="link">{i18n('CLOSE')}</Button> <Button onClick={ModalContainer.closeModal} type="link">{i18n('CLOSE')}</Button>
</div> </div>

View File

@ -7,8 +7,9 @@ import i18n from 'lib-app/i18n';
import API from 'lib-app/api-call'; import API from 'lib-app/api-call';
import SessionStore from 'lib-app/session-store'; import SessionStore from 'lib-app/session-store';
import LanguageSelector from 'app-components/language-selector'; import LanguageSelector from 'app-components/language-selector';
import Captcha from 'app/main/captcha';
import DepartmentDropdown from 'app-components/department-dropdown'; import DepartmentDropdown from 'app-components/department-dropdown';
import Captcha from 'app/main/captcha';
import {getPublicDepartmentIndexFromDepartmentId} from 'app/admin/panel/staff/admin-panel-departments';
import Header from 'core-components/header'; import Header from 'core-components/header';
import TextEditor from 'core-components/text-editor'; import TextEditor from 'core-components/text-editor';
@ -18,14 +19,16 @@ import SubmitButton from 'core-components/submit-button';
import Message from 'core-components/message'; import Message from 'core-components/message';
class CreateTicketForm extends React.Component { class CreateTicketForm extends React.Component {
static propTypes = { static propTypes = {
userLogged: React.PropTypes.bool, userLogged: React.PropTypes.bool,
isStaff: React.PropTypes.bool,
onSuccess: React.PropTypes.func, onSuccess: React.PropTypes.func,
}; };
static defaultProps = { static defaultProps = {
userLogged: true userLogged: true,
isStaff: false
}; };
state = { state = {
@ -34,7 +37,7 @@ class CreateTicketForm extends React.Component {
form: { form: {
title: '', title: '',
content: TextEditor.createEmpty(), content: TextEditor.createEmpty(),
departmentIndex: 0, departmentIndex: getPublicDepartmentIndexFromDepartmentId(this.props.defaultDepartmentId),
email: '', email: '',
name: '', name: '',
language: this.props.language language: this.props.language
@ -49,14 +52,18 @@ class CreateTicketForm extends React.Component {
{(!this.props.userLogged) ? this.renderEmailAndName() : null} {(!this.props.userLogged) ? this.renderEmailAndName() : null}
<FormField label={i18n('TITLE')} name="title" validation="TITLE" required field="input" fieldProps={{size: 'large'}}/> <FormField label={i18n('TITLE')} name="title" validation="TITLE" required field="input" fieldProps={{size: 'large'}}/>
<div className="row"> <div className="row">
<FormField className="col-md-5" label={i18n('DEPARTMENT')} name="departmentIndex" field="select" decorator={DepartmentDropdown} fieldProps={{ {!(this.props.isDefaultDepartmentLocked*1) || this.props.isStaff ?
departments: SessionStore.getDepartments(), <FormField className="col-md-5" label={i18n('DEPARTMENT')} name="departmentIndex" field="select" decorator={DepartmentDropdown} fieldProps={{
size: 'medium' departments: SessionStore.getDepartments(),
}} /> size: 'medium'
<FormField className="col-md-5" label={i18n('LANGUAGE')} name="language" field="select" decorator={LanguageSelector} fieldProps={{ }} /> : null
type: 'supported', }
size: 'medium' {!this.props.onlyOneSupportedLanguage ?
}}/> <FormField className="col-md-5" label={i18n('LANGUAGE')} name="language" field="select" decorator={LanguageSelector} fieldProps={{
type: 'supported',
size: 'medium'
}}/> : null
}
</div> </div>
<FormField <FormField
label={i18n('CONTENT')} label={i18n('CONTENT')}
@ -162,9 +169,11 @@ class CreateTicketForm extends React.Component {
export default connect((store) => { export default connect((store) => {
const { language, supportedLanguages } = store.config; const { language, supportedLanguages } = store.config;
return { return {
language: _.includes(supportedLanguages, language) ? language : supportedLanguages[0], language: _.includes(supportedLanguages, language) ? language : supportedLanguages[0],
allowAttachments: store.config['allow-attachments'] onlyOneSupportedLanguage: supportedLanguages.length == 1 ? true : false,
isDefaultDepartmentLocked: store.config['default-is-locked'],
allowAttachments: store.config['allow-attachments'],
defaultDepartmentId: store.config['default-department-id']
}; };
})(CreateTicketForm); })(CreateTicketForm);

View File

@ -5,6 +5,7 @@ export default {
'ACCOUNT': 'Account', 'ACCOUNT': 'Account',
'SUBMIT': 'Submit', 'SUBMIT': 'Submit',
'EMAIL': 'Email', 'EMAIL': 'Email',
'DEFAULT': 'Default',
'PASSWORD': 'Password', 'PASSWORD': 'Password',
'REPEAT_PASSWORD': 'Repeat password', 'REPEAT_PASSWORD': 'Repeat password',
'LOG_IN': 'Log in', 'LOG_IN': 'Log in',
@ -26,6 +27,7 @@ export default {
'TICKET_LIST': 'Ticket List', 'TICKET_LIST': 'Ticket List',
'SUPPORT_CENTER': 'Support Center', 'SUPPORT_CENTER': 'Support Center',
'DEPARTMENT': 'Department', 'DEPARTMENT': 'Department',
'DEFAULT_DEPARTMENT': 'Default Department',
'AUTHOR': 'Author', 'AUTHOR': 'Author',
'DATE': 'Date', 'DATE': 'Date',
'RESPOND': 'Respond', 'RESPOND': 'Respond',
@ -134,6 +136,7 @@ export default {
'EDIT_STAFF': 'Edit staff member', 'EDIT_STAFF': 'Edit staff member',
'ADD_DEPARTMENT': 'Add department', 'ADD_DEPARTMENT': 'Add department',
'UPDATE_DEPARTMENT': 'Update department', 'UPDATE_DEPARTMENT': 'Update department',
'UPDATE_DEFAULT_DEPARTMENT': 'Update default department',
'TRANSFER_TICKETS_TO': 'Transfer tickets to', 'TRANSFER_TICKETS_TO': 'Transfer tickets to',
'COMMENTS': 'Comments', 'COMMENTS': 'Comments',
'DELETE_STAFF_MEMBER': 'Delete staff member', 'DELETE_STAFF_MEMBER': 'Delete staff member',
@ -201,6 +204,7 @@ export default {
'INVITE_STAFF': 'Invite staff', 'INVITE_STAFF': 'Invite staff',
'UPLOAD_FILE': 'Upload file', 'UPLOAD_FILE': 'Upload file',
'PRIVATE': 'Private', 'PRIVATE': 'Private',
'LOCKED': 'Locked',
'ENABLE_USER': 'Enable User', 'ENABLE_USER': 'Enable User',
'DISABLE_USER': 'Disable User', 'DISABLE_USER': 'Disable User',
'SHOW_CLOSED_TICKETS': 'Show Closed Tickets', 'SHOW_CLOSED_TICKETS': 'Show Closed Tickets',
@ -340,6 +344,7 @@ export default {
'PRIVATE_RESPONSE_DESCRIPTION': 'This response will only be seen by staff members', 'PRIVATE_RESPONSE_DESCRIPTION': 'This response will only be seen by staff members',
'PRIVATE_TOPIC_DESCRIPTION': 'This topic will only be seen by staff members', 'PRIVATE_TOPIC_DESCRIPTION': 'This topic will only be seen by staff members',
'PRIVATE_DEPARTMENT_DESCRIPTION': 'This department will only be seen by staff members', 'PRIVATE_DEPARTMENT_DESCRIPTION': 'This department will only be seen by staff members',
'LOCK_DEPARTMENT_DESCRIPTION': 'Allow users to create tickets only in the default department',
'EMAIL_SETTINGS_DESCRIPTION': 'Here you can edit the settings for receiving and sending email to your customers.', 'EMAIL_SETTINGS_DESCRIPTION': 'Here you can edit the settings for receiving and sending email to your customers.',
'IMAP_POLLING_DESCRIPTION': 'Inbox checking will not be done automatically by OpenSupports. You have to make POST requests periodically to this url to process the emails: {url}', 'IMAP_POLLING_DESCRIPTION': 'Inbox checking will not be done automatically by OpenSupports. You have to make POST requests periodically to this url to process the emails: {url}',
'NEW_CUSTOM_FIELD_DESCRIPTION': 'Here you can create a custom field for an user, it can be a blank text box or a fixed set of options.', 'NEW_CUSTOM_FIELD_DESCRIPTION': 'Here you can create a custom field for an user, it can be a blank text box or a fixed set of options.',
@ -380,7 +385,10 @@ export default {
'USER_DISABLED': 'This account is disabled.', 'USER_DISABLED': 'This account is disabled.',
'INVALID_SYNTAX': 'Invalid syntax.', 'INVALID_SYNTAX': 'Invalid syntax.',
'DEPARTMENT_PRIVATE_TICKETS': 'This department has tickets created by non-staff and it can not be private', 'DEPARTMENT_PRIVATE_TICKETS': 'This department has tickets created by non-staff and it can not be private',
'DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE': 'Default department can not be private',
'CURRENTLY_UNAVAILABLE': 'Currently unavailable', 'CURRENTLY_UNAVAILABLE': 'Currently unavailable',
'CAN_NOT_DELETE_DEFAULT_DEPARTMENT': 'Default department can not be deleted',
'INVALID_DEFAULT_DEPARTMENT': 'Default department choosen is invalid',
//MESSAGES //MESSAGES
'SIGNUP_SUCCESS': 'You have registered successfully in our support system.', 'SIGNUP_SUCCESS': 'You have registered successfully in our support system.',

View File

@ -69,7 +69,10 @@ class SessionStore {
this.setItem('maintenance-mode', configs['maintenance-mode']); this.setItem('maintenance-mode', configs['maintenance-mode']);
this.setItem('max-size', configs['max-size']); this.setItem('max-size', configs['max-size']);
this.setItem('tags', JSON.stringify(configs['tags'])); this.setItem('tags', JSON.stringify(configs['tags']));
this.setItem('max-size', configs['max-size']);
this.setItem('tags', JSON.stringify(configs['tags']));
this.setItem('default-is-locked', configs['default-is-locked']);
this.setItem('default-department-id', configs['default-department-id']);
} }
getConfigs() { getConfigs() {
@ -86,7 +89,10 @@ class SessionStore {
'allow-attachments': (this.getItem('allow-attachments') * 1), 'allow-attachments': (this.getItem('allow-attachments') * 1),
'maintenance-mode': (this.getItem('maintenance-mode') * 1), 'maintenance-mode': (this.getItem('maintenance-mode') * 1),
'max-size': this.getItem('max-size'), 'max-size': this.getItem('max-size'),
'tags': JSON.parse(this.getItem('tags')) 'tags': JSON.parse(this.getItem('tags')),
'default-is-locked': this.getItem('default-is-locked'),
'default-department-id': this.getItem('default-department-id')
}; };
} }

View File

@ -38,11 +38,10 @@ class ConfigReducer extends Reducer {
if(payload.data.allowedLanguages && !_.includes(payload.data.allowedLanguages, currentLanguage)) { if(payload.data.allowedLanguages && !_.includes(payload.data.allowedLanguages, currentLanguage)) {
currentLanguage = payload.data.language; currentLanguage = payload.data.language;
} }
sessionStore.storeConfigs(_.extend({}, payload.data, { sessionStore.storeConfigs(_.extend({}, payload.data, {
language: currentLanguage || payload.data.language language: currentLanguage || payload.data.language
})); }));
return _.extend({}, state, payload.data, { return _.extend({}, state, payload.data, {
language: currentLanguage || payload.data.language || 'en', language: currentLanguage || payload.data.language || 'en',
registration: !!(payload.data.registration * 1), registration: !!(payload.data.registration * 1),
@ -50,7 +49,9 @@ class ConfigReducer extends Reducer {
'allow-attachments': !!(payload.data['allow-attachments']* 1), 'allow-attachments': !!(payload.data['allow-attachments']* 1),
'maintenance-mode': !!(payload.data['maintenance-mode']* 1), 'maintenance-mode': !!(payload.data['maintenance-mode']* 1),
departments: payload.data.departments && payload.data.departments.map(department => _.extend({}, department, {private: department.private * 1})), departments: payload.data.departments && payload.data.departments.map(department => _.extend({}, department, {private: department.private * 1})),
initDone: true initDone: true,
'default-department-id': payload.data['default-department-id'],
'default-is-locked': payload.data['default-is-locked'],
}); });
} }

View File

@ -49,8 +49,11 @@ class DeleteDepartmentController extends Controller {
} }
public function handler() { public function handler() {
$this->departmentId = Controller::request('departmentId'); $this->departmentId = Controller::request('departmentId');
$this->transferDepartmentId = Controller::request('transferDepartmentId'); $this->transferDepartmentId = Controller::request('transferDepartmentId');
$this->checkDepartmentIdDefault();
if ($this->departmentId === $this->transferDepartmentId) { if ($this->departmentId === $this->transferDepartmentId) {
throw new RequestException(ERRORS::SAME_DEPARTMENT); throw new RequestException(ERRORS::SAME_DEPARTMENT);
@ -108,4 +111,9 @@ class DeleteDepartmentController extends Controller {
$ticket->store(); $ticket->store();
} }
} }
public function checkDepartmentIdDefault() {
$defaultDepartment = Setting::getSetting('default-department-id');
if ($defaultDepartment && $this->departmentId == $defaultDepartment->value) throw new Exception(ERRORS::CAN_NOT_DELETE_DEFAULT_DEPARTMENT);
}
} }

View File

@ -53,6 +53,10 @@ class EditDepartmentController extends Controller {
$departmentInstance = Department::getDataStore($departmentId); $departmentInstance = Department::getDataStore($departmentId);
if($private && $departmentId == Setting::getSetting('default-department-id')->getValue()){
throw new RequestException(ERRORS::DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE);
}
if($private && Ticket::count(' author_id IS NOT NULL AND department_id = ? ', [$departmentId])) { if($private && Ticket::count(' author_id IS NOT NULL AND department_id = ? ', [$departmentId])) {
throw new RequestException(ERRORS::DEPARTMENT_PRIVATE_TICKETS); throw new RequestException(ERRORS::DEPARTMENT_PRIVATE_TICKETS);
} }

View File

@ -1,4 +1,6 @@
<?php <?php
use Respect\Validation\Validator as DataValidator;
DataValidator::with('CustomValidations', true);
/** /**
* @api {post} /system/edit-settings Edit settings * @api {post} /system/edit-settings Edit settings
@ -29,7 +31,12 @@ class EditSettingsController extends Controller {
public function validations() { public function validations() {
return [ return [
'permission' => 'staff_3', 'permission' => 'staff_3',
'requestData' => [] 'requestData' => [
'default-department-id' => [
'validation' => DataValidator::oneOf(DataValidator::dataStoreId('department'),DataValidator::nullType()),
'error' => ERRORS::INVALID_DEFAULT_DEPARTMENT
],
]
]; ];
} }
@ -53,8 +60,11 @@ class EditSettingsController extends Controller {
'max-size', 'max-size',
'title', 'title',
'url', 'url',
'mail-template-header-image' 'mail-template-header-image',
'default-is-locked',
'default-department-id'
]; ];
$this->checkDefaultDepartmentValid();
foreach($settings as $setting) { foreach($settings as $setting) {
if(Controller::request($setting)!==null) { if(Controller::request($setting)!==null) {
@ -64,6 +74,7 @@ class EditSettingsController extends Controller {
} }
} }
if(Controller::request('allowedLanguages') || Controller::request('supportedLanguages')) { if(Controller::request('allowedLanguages') || Controller::request('supportedLanguages')) {
$this->handleLanguages(); $this->handleLanguages();
} }
@ -89,6 +100,25 @@ class EditSettingsController extends Controller {
$language->store(); $language->store();
} }
} }
public function checkDefaultDepartmentValid() {
$departmentId = Controller::request('default-department-id');
if($departmentId){
$Publicdepartments = Department::getPublicDepartmentNames();
$isValid = false;
foreach($Publicdepartments as $department) {
if($department['id'] == $departmentId){
$isValid = true;
}
}
if(!$isValid) throw new Exception(ERRORS::INVALID_DEFAULT_DEPARTMENT);
}
}
} }

View File

@ -59,6 +59,8 @@ class GetSettingsController extends Controller {
'mail-template-header-image' => Setting::getSetting('mail-template-header-image')->getValue(), 'mail-template-header-image' => Setting::getSetting('mail-template-header-image')->getValue(),
'tags' => Tag::getAll()->toArray(), 'tags' => Tag::getAll()->toArray(),
'mandatory-login' => Setting::getSetting('mandatory-login')->getValue(), 'mandatory-login' => Setting::getSetting('mandatory-login')->getValue(),
'default-department-id' => Setting::getSetting('default-department-id')->getValue(),
'default-is-locked' => Setting::getSetting('default-is-locked')->getValue()
]; ];
} else { } else {
$settingsList = [ $settingsList = [
@ -77,6 +79,8 @@ class GetSettingsController extends Controller {
'session-prefix' => Setting::getSetting('session-prefix')->getValue(), 'session-prefix' => Setting::getSetting('session-prefix')->getValue(),
'tags' => Tag::getAll()->toArray(), 'tags' => Tag::getAll()->toArray(),
'mandatory-login' => Setting::getSetting('mandatory-login')->getValue(), 'mandatory-login' => Setting::getSetting('mandatory-login')->getValue(),
'default-department-id' => Setting::getSetting('default-department-id')->getValue(),
'default-is-locked' => Setting::getSetting('default-is-locked')->getValue()
]; ];
} }
} }

View File

@ -26,7 +26,8 @@ DataValidator::with('CustomValidations', true);
* @apiParam {String} title Title of the support center * @apiParam {String} title Title of the support center
* @apiParam {String} url Url of the frontend client. * @apiParam {String} url Url of the frontend client.
* @apiParam {Boolean} mandatory-login Indicates if the login is mandatory. * @apiParam {Boolean} mandatory-login Indicates if the login is mandatory.
* * @apiParam {Number} default-department-id Indicates the id of the default department
* @apiParam {Boolean} locked-department Indicates if the default department is locked or not
* @apiUse INVALID_LANGUAGE * @apiUse INVALID_LANGUAGE
* @apiUse INIT_SETTINGS_DONE * @apiUse INIT_SETTINGS_DONE
* *
@ -90,8 +91,10 @@ class InitSettingsController extends Controller {
'ticket-first-number' => Hashing::generateRandomNumber(100000, 999999), 'ticket-first-number' => Hashing::generateRandomNumber(100000, 999999),
'session-prefix' => 'opensupports-'.Hashing::generateRandomToken().'_', 'session-prefix' => 'opensupports-'.Hashing::generateRandomToken().'_',
'mail-template-header-image' => 'https://s3.amazonaws.com/opensupports/logo.png', 'mail-template-header-image' => 'https://s3.amazonaws.com/opensupports/logo.png',
'default-department-id' => 1,
'default-is-locked' => false,
'imap-token' => '', 'imap-token' => '',
'mandatory-login' => !!Controller::request('mandatory-login'), 'mandatory-login' => !!Controller::request('mandatory-login')
]); ]);
} }
@ -119,7 +122,6 @@ class InitSettingsController extends Controller {
private function storeSettings($settings) { private function storeSettings($settings) {
foreach ($settings as $settingName => $settingValue) { foreach ($settings as $settingName => $settingValue) {
$setting = new Setting(); $setting = new Setting();
$setting->setProperties([ $setting->setProperties([
'name' => $settingName, 'name' => $settingName,
'value' => $settingValue 'value' => $settingValue
@ -151,6 +153,7 @@ class InitSettingsController extends Controller {
foreach ($departments as $departmentName) { foreach ($departments as $departmentName) {
$department = new Department(); $department = new Department();
$department->name = $departmentName; $department->name = $departmentName;
$department->private = 0;
$department->store(); $department->store();
} }
} }

View File

@ -62,11 +62,11 @@ class CreateController extends Controller {
'error' => ERRORS::INVALID_CONTENT 'error' => ERRORS::INVALID_CONTENT
], ],
'departmentId' => [ 'departmentId' => [
'validation' => DataValidator::dataStoreId('department'), 'validation' => DataValidator::oneOf(DataValidator::dataStoreId('department'), DataValidator::nullType()),
'error' => ERRORS::INVALID_DEPARTMENT 'error' => ERRORS::INVALID_DEPARTMENT
], ],
'language' => [ 'language' => [
'validation' => DataValidator::in(Language::getSupportedLanguages()), 'validation' => DataValidator::oneOf(DataValidator::in(Language::getSupportedLanguages()), DataValidator::nullType()),
'error' => ERRORS::INVALID_LANGUAGE 'error' => ERRORS::INVALID_LANGUAGE
] ]
] ]
@ -159,9 +159,12 @@ class CreateController extends Controller {
$signupController->validations(); $signupController->validations();
$signupController->handler(); $signupController->handler();
} }
private function storeTicket() { private function storeTicket() {
$department = Department::getDataStore($this->departmentId); $department = Department::getDataStore($this->getCorrectDepartmentId());
$author = $this->getAuthor(); $author = $this->getAuthor();
$this->language = $this->getCorrectLanguage();
$ticket = new Ticket(); $ticket = new Ticket();
$fileUploader = FileUploader::getInstance(); $fileUploader = FileUploader::getInstance();
@ -200,6 +203,26 @@ class CreateController extends Controller {
$this->ticketNumber = $ticket->ticketNumber; $this->ticketNumber = $ticket->ticketNumber;
} }
private function getCorrectLanguage() {
if($this->language){
return $this->language;
}else{
return Setting::getSetting('language')->getValue();
}
}
private function getCorrectDepartmentId(){
$defaultDepartmentId = Setting::getSetting('default-department-id')->getValue();
$isLocked = Setting::getSetting('default-is-locked')->getValue();
$validDepartment = Department::getDataStore($defaultDepartmentId)->id;
if (Controller::isStaffLogged()) {
if ($this->departmentId) $validDepartment = $this->departmentId;
} else {
if (!$isLocked && $this->departmentId) $validDepartment = $this->departmentId;
}
return $validDepartment;
}
private function getAuthor() { private function getAuthor() {
if(Controller::getLoggedUser()->email) { if(Controller::getLoggedUser()->email) {
return Controller::getLoggedUser(); return Controller::getLoggedUser();

View File

@ -219,6 +219,14 @@
* @apiDefine INVALID_FILE * @apiDefine INVALID_FILE
* @apiError {String} INVALID_FILE The file is invalid or max size exceeded. * @apiError {String} INVALID_FILE The file is invalid or max size exceeded.
*/ */
/**
* @apiDefine INVALID_DEFAULT_DEPARTMENT
* @apiError {String} INVALID_DEFAULT_DEPARTMENT The default department id is invalid.
*/
/**
* @apiDefine CAN_NOT_DELETE_DEFAULT_DEPARTMENT
* @apiError {String} CAN_NOT_DELETE_DEFAULT_DEPARTMENT The default department can not be deleted.
*/
/** /**
* @apiDefine DATABASE_CONNECTION * @apiDefine DATABASE_CONNECTION
* @apiError {String} DATABASE_CONNECTION It's a database connection error. * @apiError {String} DATABASE_CONNECTION It's a database connection error.
@ -259,6 +267,10 @@
* @apiDefine DEPARTMENT_PRIVATE_TICKETS * @apiDefine DEPARTMENT_PRIVATE_TICKETS
* @apiError {String} DEPARTMENT_PRIVATE_TICKETS There are tickets for in department created by non-staff and it can't be private * @apiError {String} DEPARTMENT_PRIVATE_TICKETS There are tickets for in department created by non-staff and it can't be private
*/ */
/**
* @apiDefine DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE
* @apiError {String} DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE Default Department can not be private
*/
/** /**
* @apiDefine EMAIL_POLLING * @apiDefine EMAIL_POLLING
* @apiError {String} EMAIL_POLLING Email polling was unsuccesful * @apiError {String} EMAIL_POLLING Email polling was unsuccesful
@ -365,6 +377,8 @@ class ERRORS {
const INVALID_PERIOD = 'INVALID_PERIOD'; const INVALID_PERIOD = 'INVALID_PERIOD';
const NAME_ALREADY_USED = 'NAME_ALREADY_USED'; const NAME_ALREADY_USED = 'NAME_ALREADY_USED';
const INVALID_FILE = 'INVALID_FILE'; const INVALID_FILE = 'INVALID_FILE';
const INVALID_DEFAULT_DEPARTMENT = 'INVALID_DEFAULT_DEPARTMENT';
const CAN_NOT_DELETE_DEFAULT_DEPARTMENT = 'CAN_NOT_DELETE_DEFAULT_DEPARTMENT';
const DATABASE_CONNECTION = 'DATABASE_CONNECTION'; const DATABASE_CONNECTION = 'DATABASE_CONNECTION';
const DATABASE_CREATION = 'DATABASE_CREATION'; const DATABASE_CREATION = 'DATABASE_CREATION';
const SMTP_CONNECTION = 'SMTP_CONNECTION'; const SMTP_CONNECTION = 'SMTP_CONNECTION';
@ -376,6 +390,7 @@ class ERRORS {
const INVALID_TEXT_2 = 'INVALID_TEXT_2'; const INVALID_TEXT_2 = 'INVALID_TEXT_2';
const INVALID_TEXT_3 = 'INVALID_TEXT_3'; const INVALID_TEXT_3 = 'INVALID_TEXT_3';
const DEPARTMENT_PRIVATE_TICKETS = 'DEPARTMENT_PRIVATE_TICKETS'; const DEPARTMENT_PRIVATE_TICKETS = 'DEPARTMENT_PRIVATE_TICKETS';
const DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE = 'DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE';
const EMAIL_POLLING = 'EMAIL_POLLING'; const EMAIL_POLLING = 'EMAIL_POLLING';
const CUSTOM_FIELD_ALREADY_EXISTS = 'CUSTOM_FIELD_ALREADY_EXISTS'; const CUSTOM_FIELD_ALREADY_EXISTS = 'CUSTOM_FIELD_ALREADY_EXISTS';
const INVALID_CUSTOM_FIELD = 'INVALID_CUSTOM_FIELD'; const INVALID_CUSTOM_FIELD = 'INVALID_CUSTOM_FIELD';

View File

@ -76,4 +76,5 @@ require './system/custom-fields.rb'
require './ticket/get-authors.rb' require './ticket/get-authors.rb'
require './ticket/search.rb' require './ticket/search.rb'
require './system/mandatory-login.rb' require './system/mandatory-login.rb'
require './system/default-department.rb'
# require './system/get-stats.rb' # require './system/get-stats.rb'

View File

@ -141,4 +141,20 @@ class Scripts
csrf_token: $csrf_token csrf_token: $csrf_token
}) })
end end
def self.createDepartment(nameDepartment = 'validnameDepartment')
request('/system/add-department', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
name: nameDepartment
})
end
def self.updateLockedDepartmentSetting(value = 0)
request('/system/edit-settings', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
"default-is-locked" => value
})
end
end end

View File

@ -0,0 +1,269 @@
describe '/system/default-department' do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
it 'should fail if try to turn a private department default' do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
privatedepartment = $database.getRow('department', 1, 'private')
result = request('/system/edit-settings', {
"csrf_userid" => $csrf_userid,
"csrf_token" => $csrf_token,
"default-department-id" => privatedepartment['id']
})
(result['status']).should.equal('fail')
(result['message']).should.equal('INVALID_DEFAULT_DEPARTMENT')
end
it 'should edit locked setting' do
result = request('/system/edit-settings', {
"csrf_userid" => $csrf_userid,
"csrf_token" => $csrf_token,
"default-is-locked" => 1
})
(result['status']).should.equal('success')
row = $database.getRow('setting', 'default-is-locked', 'name')
(row['value']).should.equal('1')
end
it 'should fail if default-department-id does not exist' do
request('/user/logout')
Scripts.login($staff[:email], $staff[:password], true)
result= request('/system/edit-settings', {
"csrf_userid" => $csrf_userid,
"csrf_token" => $csrf_token,
"default-department-id" => 1111
})
(result['status']).should.equal('fail')
(result['message']).should.equal('INVALID_DEFAULT_DEPARTMENT')
end
it 'should set a new default deparment' do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
publicdepartment = $database.getRow('department', 'Suggestions', 'name')
result = request('/system/edit-settings', {
"csrf_userid" => $csrf_userid,
"csrf_token" => $csrf_token,
"default-department-id" => publicdepartment['id']
})
(result['status']).should.equal('success')
end
it 'should fail if try to delete the default department' do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
defaultDepartment = $database.getRow('setting', 'default-department-id', 'name')
transferDepartment = $database.getRow('department','<b>new department</b>','name')
result = request('/system/delete-department', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
departmentId: defaultDepartment['value'],
transferDepartmentId: transferDepartment['id']
})
(result['status']).should.equal('fail')
(result['message']).should.equal('CAN_NOT_DELETE_DEFAULT_DEPARTMENT')
end
it 'should fail if try to edit default department into private' do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
defaultDepartmentId = $database.getRow('setting', 'default-department-id', 'name')
department = $database.getRow('department',defaultDepartmentId['value'],'id')
result = request('/system/edit-department', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
departmentId: department['id'],
name: department['name'],
private: true
})
(result['status']).should.equal('fail')
(result['message']).should.equal('DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE')
end
it 'should create ticket in default department if Staff does not give department with locked on' do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
Scripts.updateLockedDepartmentSetting(1)
result = request('/ticket/create', {
title: 'Night King',
content: 'Arya sucks',
language: 'en',
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
row = $database.getRow('ticket', 'Night King', 'title')
setting = $database.getRow('setting', 'default-department-id','name')
(row['department_id']).should.equal(setting['value'].to_i)
end
it 'should create ticket in default department if staff does not give department with locked off'do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
Scripts.updateLockedDepartmentSetting(0)
result = request('/ticket/create', {
title: 'Night King2',
content: 'Arya sucks2',
language: 'en',
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
row = $database.getRow('ticket', 'Night King2', 'title')
setting = $database.getRow('setting', 'default-department-id','name')
(row['department_id']).should.equal(setting['value'].to_i)
end
it 'should create ticket in selected department if staff give department and lockd is off'do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
Scripts.updateLockedDepartmentSetting(0)
result = request('/ticket/create', {
title: 'Night King3',
content: 'Arya sucks3',
language: 'en',
departmentId: 1,
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
row = $database.getRow('ticket', 'Night King3', 'title')
(row['department_id']).should.equal(1)
end
it 'should create ticket in selected department if staff give department and locked is on' do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
Scripts.updateLockedDepartmentSetting(1)
result = request('/ticket/create', {
title: 'Night King4',
content: 'Arya sucks4',
language: 'en',
departmentId: 1,
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
row = $database.getRow('ticket', 'Night King4', 'title')
(row['department_id']).should.equal(1)
end
it 'should create ticket on default department if user does not give department and locked is on' do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
Scripts.updateLockedDepartmentSetting(1)
request('/user/logout')
Scripts.login('user@os4.com', 'loginpass')
result = request('/ticket/create', {
title: 'Night King5',
content: 'Arya sucks5',
language: 'en',
departmentId: 5,
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
(result['status']).should.equal('success')
row = $database.getRow('ticket', 'Night King5', 'title')
setting = $database.getRow('setting', 'default-department-id','name')
(row['department_id']).should.equal(setting['value'].to_i)
end
it 'should create ticket on default department if user does not give department and locked is off'do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
Scripts.updateLockedDepartmentSetting(0)
request('/user/logout')
Scripts.login('user@os4.com', 'loginpass')
result = request('/ticket/create', {
title: 'Night King6',
content: 'Arya sucks6',
language: 'en',
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
row = $database.getRow('ticket', 'Night King6', 'title')
setting = $database.getRow('setting', 'default-department-id','name')
(row['department_id']).should.equal(setting['value'].to_i)
end
it 'should create ticket on selected department if user give department and locked is off'do
request('/user/logout')
Scripts.login('staff@opensupports.com', 'staff', true)
Scripts.updateLockedDepartmentSetting(0)
request('/user/logout')
Scripts.login('user@os4.com', 'loginpass')
result = request('/ticket/create', {
title: 'Night King16',
content: 'Arya sucks16',
language: 'en',
departmentId: 1,
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
row = $database.getRow('ticket', 'Night King16', 'title')
(row['department_id']).should.equal(1)
end
it 'should create ticket on default leanguage if user does not pass language'do
$database.query('update setting set value="ru" where name="language";')
request('/user/logout')
Scripts.login('user@os4.com', 'loginpass')
result = request('/ticket/create', {
title: 'Danny Dragon',
content: 'They do not get to choose',
departmentId: 1,
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
ticket = $database.getRow('ticket', 'Danny Dragon', 'title')
defaultLanguage = $database.getRow('setting', 'language', 'name')
(ticket['language']).should.equal(defaultLanguage['value'])
result['status'].should.equal('success')
$database.query('update setting set value="en" where name="language";')
end
end

View File

@ -12,7 +12,8 @@ describe'system/edit-settings' do
"allow-attachments" => 1, "allow-attachments" => 1,
"max-size" => 2, "max-size" => 2,
"language" => 'en', "language" => 'en',
"server-email" => 'testemail@hotmail.com' "server-email" => 'testemail@hotmail.com',
"default-is-locked" => 1
}) })
(result['status']).should.equal('success') (result['status']).should.equal('success')
@ -34,7 +35,8 @@ describe'system/edit-settings' do
row = $database.getRow('setting', 'server-email', 'name') row = $database.getRow('setting', 'server-email', 'name')
(row['value']).should.equal('testemail@hotmail.com') (row['value']).should.equal('testemail@hotmail.com')
row = $database.getRow('setting', 'default-is-locked', 'name')
(row['value']).should.equal('1')
request('/user/logout') request('/user/logout')
end end
it 'should fail if supported languages are invalid' do it 'should fail if supported languages are invalid' do
@ -94,6 +96,8 @@ describe'system/edit-settings' do
lastLog = $database.getLastRow('log') lastLog = $database.getLastRow('log')
(lastLog['type']).should.equal('EDIT_SETTINGS') (lastLog['type']).should.equal('EDIT_SETTINGS')
Scripts.updateLockedDepartmentSetting(0);
request('/user/logout') request('/user/logout')
end end
end end

View File

@ -6,6 +6,8 @@ describe '/system/get-settings' do
(result['data']['language']).should.equal('en') (result['data']['language']).should.equal('en')
(result['data']['departments'][0]['name']).should.equal('Help and Support') (result['data']['departments'][0]['name']).should.equal('Help and Support')
(result['data']['mandatory-login']).should.equal('1') (result['data']['mandatory-login']).should.equal('1')
(result['data']['default-department-id']).should.equal('1')
(result['data']['default-is-locked']).should.equal('0')
(result['data']['allowedLanguages'][0]).should.equal('en') (result['data']['allowedLanguages'][0]).should.equal('en')
(result['data']['allowedLanguages'][1]).should.equal('es') (result['data']['allowedLanguages'][1]).should.equal('es')
(result['data']['allowedLanguages'][2]).should.equal('de') (result['data']['allowedLanguages'][2]).should.equal('de')

View File

@ -28,6 +28,12 @@ describe '/system/init-settings' do
lang = $database.getRow('setting', 'language', 'name') lang = $database.getRow('setting', 'language', 'name')
(lang['value']).should.equal('en') (lang['value']).should.equal('en')
default = $database.getRow('setting', 'default-department-id', 'name')
(default['value']).should.equal('1')
locked = $database.getRow('setting', 'default-is-locked', 'name')
(locked['value']).should.equal('0')
result = request('/system/init-admin', { result = request('/system/init-admin', {
name: 'Emilia Clarke', name: 'Emilia Clarke',

View File

@ -34,7 +34,6 @@ describe '/user/get' do
}) })
ticket = $database.getRow('ticket', @ticketNumber, 'ticket_number') ticket = $database.getRow('ticket', @ticketNumber, 'ticket_number')
(result['status']).should.equal('success') (result['status']).should.equal('success')
(result['data']['name']).should.equal('User Get') (result['data']['name']).should.equal('User Get')
(result['data']['email']).should.equal('user_get@os4.com') (result['data']['email']).should.equal('user_get@os4.com')