Super user feature (#841)
* add ruby tests * update ruby test * backend part * add get-supervised-ticket path and ruby tests * update search-authors path and custom validation to get-supervised-tickets * add supervised users components and css * add supervised-users messages * resolve minor bugs get super ticket, ruby tests and change file name * add supervisor options on user panel * change supervisor structure * add pagination dashboard supervisor tickets * change error name * add error to path edit-supervised-list * fix github comments * resolve github comment backend * add minor changes dashboard list tickets page
This commit is contained in:
parent
507be7bff2
commit
cd73606852
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "OpenSupports",
|
||||
"version": "4.2.0",
|
||||
"version": "4.7.0",
|
||||
"author": "Ivan Diaz <contact@opensupports.com>",
|
||||
"description": "Open source ticket system made with PHP and ReactJS",
|
||||
"repository": {
|
||||
|
|
|
@ -92,7 +92,7 @@ class TicketQueryFilters extends React.Component {
|
|||
}} />
|
||||
</div>
|
||||
<div className="ticket-query-filters__group__container">
|
||||
<span className="ticket-query-filters__title">Authors</span>
|
||||
<span className="ticket-query-filters__title">{i18n('AUTHORS')}</span>
|
||||
<FormField
|
||||
name="authors"
|
||||
field="autocomplete"
|
||||
|
|
|
@ -12,6 +12,7 @@ import Header from 'core-components/header';
|
|||
import Button from 'core-components/button';
|
||||
import Message from 'core-components/message';
|
||||
import InfoTooltip from 'core-components/info-tooltip';
|
||||
import Autocomplete from 'core-components/autocomplete';
|
||||
|
||||
class AdminPanelViewUser extends React.Component {
|
||||
|
||||
|
@ -23,7 +24,9 @@ class AdminPanelViewUser extends React.Component {
|
|||
customfields: [],
|
||||
invalid: false,
|
||||
loading: true,
|
||||
disabled: false
|
||||
disabled: false,
|
||||
userList: [],
|
||||
message: ''
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -80,6 +83,26 @@ class AdminPanelViewUser extends React.Component {
|
|||
</div>
|
||||
</div>
|
||||
<span className="separator" />
|
||||
<div className="admin-panel-view-user">
|
||||
<div className="admin-panel-view-user__supervised-users-header">{i18n('SUPERVISED_USER')}</div>
|
||||
<div className="admin-panel-view-user__supervised-users-content">
|
||||
<Autocomplete
|
||||
onChange={this.onChangeValues.bind(this)}
|
||||
getItemListFromQuery={this.searchUsers}
|
||||
values={this.transformUserListToAutocomplete()}
|
||||
/>
|
||||
<Button
|
||||
disabled = {this.state.loading}
|
||||
className="admin-panel-view-user__submit-button"
|
||||
onClick={this.onClickSupervisorUserButton.bind(this)}
|
||||
size="medium"
|
||||
>
|
||||
{i18n('UPDATE')}
|
||||
</Button>
|
||||
</div>
|
||||
{this.renderSupervisedUserMessage()}
|
||||
</div>
|
||||
<span className="separator" />
|
||||
<div className="admin-panel-view-user__tickets">
|
||||
<div className="admin-panel-view-user__tickets-title">{i18n('TICKETS')}</div>
|
||||
<TicketList {...this.getTicketListProps()}/>
|
||||
|
@ -87,6 +110,92 @@ class AdminPanelViewUser extends React.Component {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
renderSupervisedUserMessage(){
|
||||
if(this.state.message) {
|
||||
if(this.state.message != 'success'){
|
||||
return(
|
||||
<div className="admin-panel-view-user__supervised-users-message">
|
||||
<Message type="error">{i18n(this.state.message)}</Message>
|
||||
</div>
|
||||
)
|
||||
}else{
|
||||
return(
|
||||
<div className= "admin-panel-view-user__supervised-users-message">
|
||||
<Message type="success">{i18n('SUPERVISED_USERS_UPDATED')}</Message>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClickSupervisorUserButton(){
|
||||
this.setState({
|
||||
loading: true
|
||||
});
|
||||
|
||||
const userIdList = this.state.userList.map((item) => {
|
||||
return item.id;
|
||||
});
|
||||
|
||||
API.call({
|
||||
path: '/user/edit-supervised-list',
|
||||
data: {
|
||||
userIdList: JSON.stringify(userIdList),
|
||||
userId: this.props.params.userId
|
||||
}
|
||||
}).then(r => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
message: 'success'
|
||||
})
|
||||
}).catch((r) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
message: r.message
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
onChangeValues(newList) {
|
||||
this.setState({
|
||||
userList: newList
|
||||
});
|
||||
}
|
||||
searchUsers(query, blacklist = []) {
|
||||
return API.call({
|
||||
path: '/ticket/search-authors',
|
||||
data: {
|
||||
query: query,
|
||||
blackList: JSON.stringify(blacklist),
|
||||
searchUsers: 1
|
||||
}
|
||||
}).then(r => {
|
||||
return r.data.authors.map(author => {
|
||||
return {
|
||||
name: author.name,
|
||||
color: "gray",
|
||||
id: author.id*1,
|
||||
content: <div>{author.name}</div>,
|
||||
isStaff: false
|
||||
}});
|
||||
}).catch((r) => {
|
||||
console.log(r);
|
||||
});
|
||||
}
|
||||
|
||||
transformUserListToAutocomplete() {
|
||||
return(
|
||||
this.state.userList.map((user) => {
|
||||
return ({
|
||||
id: user.id*1,
|
||||
name: user.name,
|
||||
content: <div>{user.name}</div>,
|
||||
color: 'grey',
|
||||
isStaff: false
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
renderNotVerified() {
|
||||
return (
|
||||
|
@ -129,7 +238,8 @@ class AdminPanelViewUser extends React.Component {
|
|||
tickets: result.data.tickets,
|
||||
disabled: result.data.disabled,
|
||||
customfields: result.data.customfields,
|
||||
loading: false
|
||||
loading: false,
|
||||
userList: result.data.userList
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,28 @@
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
&__supervised-users-header {
|
||||
font-size: $font-size--md;
|
||||
margin-bottom: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__supervised-users-content {
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
align-items:flex-start;
|
||||
}
|
||||
|
||||
&__supervised-users-message {
|
||||
margin-top: 20px
|
||||
}
|
||||
|
||||
&__submit-button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
&__unverified {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,8 +4,13 @@ import {connect} from 'react-redux';
|
|||
import SessionActions from 'actions/session-actions';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
||||
import Header from 'core-components/header';
|
||||
import Form from 'core-components/form';
|
||||
import FormField from 'core-components/form-field';
|
||||
import Message from 'core-components/message';
|
||||
|
||||
import TicketList from 'app-components/ticket-list';
|
||||
|
||||
class DashboardListTicketsPage extends React.Component {
|
||||
|
@ -16,28 +21,101 @@ class DashboardListTicketsPage extends React.Component {
|
|||
static defaultProps = {
|
||||
tickets: []
|
||||
};
|
||||
|
||||
state = {
|
||||
tickets: [],
|
||||
pages: 1,
|
||||
page: 1,
|
||||
form:{
|
||||
users: [],
|
||||
ownTickets: true
|
||||
},
|
||||
message: ''
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.retrieveUserData();
|
||||
this.updateTicketList({users: [], ownTickets: true});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="dashboard-ticket-list">
|
||||
<Header title={i18n('TICKET_LIST')} description={i18n('TICKET_LIST_DESCRIPTION')} />
|
||||
<TicketList tickets={this.props.tickets} type="primary"/>
|
||||
{this.props.userUsers.length ? this.showSupervisorOptions() : null}
|
||||
<TicketList onPageChange={this.onPageChange.bind(this)} page={this.state.page} pages={this.state.pages} tickets={this.state.tickets} type="primary"/>
|
||||
{this.state.message ? <Message type="error" >{i18n(this.state.message)}</Message> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
retrieveUserData() {
|
||||
this.props.dispatch(SessionActions.getUserData());
|
||||
}
|
||||
onPageChange(e){
|
||||
this.updateTicketList({...this.state.form, page: e.target.value});
|
||||
}
|
||||
showSupervisorOptions(){
|
||||
return(
|
||||
<Form className="dashboard-ticket-list__supervisor-form" values={this.state.form} onChange={this.onFormChange.bind(this)}>
|
||||
<FormField label={i18n('SUPERVISED_USER')} name="users" field='autocomplete' fieldProps={{items: this.getUserItems()}}></FormField>
|
||||
<FormField className="dashboard-ticket-list__supervisor-form-checkbox" label={i18n('SHOW_MY_TICKETS')} name="ownTickets" field="checkbox"/>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
getUserItems() {
|
||||
let usersList = this.props.userUsers.map(user => {
|
||||
return {
|
||||
id: user.id*1,
|
||||
name: user.name,
|
||||
content: <div>{user.name}</div>,
|
||||
color: 'grey',
|
||||
isStaff: false
|
||||
};
|
||||
});
|
||||
return usersList;
|
||||
}
|
||||
|
||||
onFormChange(form){
|
||||
this.updateTicketList(form);
|
||||
this.setState({
|
||||
form
|
||||
});
|
||||
}
|
||||
|
||||
updateTicketList({users, page, ownTickets}) {
|
||||
let usersIds = users.map((item) => {
|
||||
return item.id
|
||||
})
|
||||
|
||||
API.call({
|
||||
path: 'user/get-supervised-tickets',
|
||||
data: {
|
||||
page,
|
||||
showOwnTickets: ownTickets*1,
|
||||
supervisedUsers: JSON.stringify(usersIds)
|
||||
}
|
||||
}).then((r) => {
|
||||
this.setState({
|
||||
tickets: r.data.tickets,
|
||||
pages: r.data.pages,
|
||||
page: r.data.page,
|
||||
message: ''
|
||||
})
|
||||
}).catch((r) => {
|
||||
this.setState({
|
||||
tickets: [],
|
||||
message: r.message
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default connect((store) => {
|
||||
return {
|
||||
tickets: store.session.userTickets
|
||||
userId: store.session.userId,
|
||||
userUsers: store.session.userUsers || []
|
||||
};
|
||||
})(DashboardListTicketsPage);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
.dashboard-ticket-list {
|
||||
|
||||
&__supervisor-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
&-checkbox {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -159,7 +159,6 @@ class Autocomplete extends React.Component {
|
|||
if(this.getDropdownList().length) {
|
||||
const selectedItem = this.getDropdownList()[e.index];
|
||||
const newList = [...this.getSelectedItems(), selectedItem];
|
||||
|
||||
this.setState({
|
||||
selectedItems: newList,
|
||||
inputValue: "",
|
||||
|
|
|
@ -26,9 +26,11 @@ export default {
|
|||
'CREATE_TICKET': 'Create Ticket',
|
||||
'TICKET_LIST': 'Ticket List',
|
||||
'SUPPORT_CENTER': 'Support Center',
|
||||
'SUPERVISED_USER': 'Supervised users',
|
||||
'DEPARTMENT': 'Department',
|
||||
'DEFAULT_DEPARTMENT': 'Default Department',
|
||||
'AUTHOR': 'Author',
|
||||
'AUTHORS': 'Authors',
|
||||
'DATE': 'Date',
|
||||
'RESPOND': 'Respond',
|
||||
'RESPOND_TICKET': 'Respond Ticket',
|
||||
|
@ -198,6 +200,7 @@ export default {
|
|||
'SUBJECT': 'Subject',
|
||||
'SEND_EMAIL_ON_NEW_TICKET': 'Send email on new ticket',
|
||||
'STAFF_UPDATED': 'Staff member has been updated',
|
||||
'SUPERVISED_USERS_UPDATED': 'Supervised users updated',
|
||||
'UPDATE': 'Update',
|
||||
'NEVER': 'Never',
|
||||
'HIMSELF': 'himself',
|
||||
|
@ -210,6 +213,7 @@ export default {
|
|||
'ENABLE_USER': 'Enable User',
|
||||
'DISABLE_USER': 'Disable User',
|
||||
'SHOW_CLOSED_TICKETS': 'Show Closed Tickets',
|
||||
'SHOW_MY_TICKETS': 'Show my tickets',
|
||||
'IMAGE_HEADER_URL': 'Image header URL',
|
||||
'IMAGE_HEADER_DESCRIPTION': 'Image that will be used as header of the email',
|
||||
'EMAIL_SETTINGS': 'Email Settings',
|
||||
|
@ -390,6 +394,8 @@ export default {
|
|||
'CURRENTLY_UNAVAILABLE': 'Currently unavailable',
|
||||
'CAN_NOT_DELETE_DEFAULT_DEPARTMENT': 'Default department can not be deleted',
|
||||
'INVALID_DEFAULT_DEPARTMENT': 'Default department choosen is invalid',
|
||||
'INVALID_SUPERVISED_USERS': 'Invalid supervised users',
|
||||
'SUPERVISOR_CAN_NOT_SUPERVISE_HIMSELF': 'Supervisor can not supervise himself',
|
||||
|
||||
//MESSAGES
|
||||
'SIGNUP_SUCCESS': 'You have registered successfully in our support system.',
|
||||
|
|
|
@ -106,7 +106,6 @@ class SessionReducer extends Reducer {
|
|||
onUserDataRetrieved(state, payload) {
|
||||
let userData = payload.data;
|
||||
sessionStore.storeUserData(payload.data);
|
||||
|
||||
return _.extend({}, state, {
|
||||
staff: userData.staff,
|
||||
userName: userData.name,
|
||||
|
@ -116,7 +115,8 @@ class SessionReducer extends Reducer {
|
|||
userDepartments: userData.departments,
|
||||
userTickets: userData.tickets,
|
||||
userSendEmailOnNewTicket: userData.sendEmailOnNewTicket * 1,
|
||||
userCustomFields: userData.customfields
|
||||
userCustomFields: userData.customfields,
|
||||
userUsers: userData.users
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ class DeleteDepartmentController extends Controller {
|
|||
|
||||
public function transferDepartmentTickets() {
|
||||
$tickets = Ticket::find('department_id = ?', [$this->departmentId]);
|
||||
$newDepartment = Department::getDataStore($this->transferDepartmentId);;
|
||||
$newDepartment = Department::getDataStore($this->transferDepartmentId);
|
||||
|
||||
foreach($tickets as $ticket) {
|
||||
$staffOwner = $ticket->owner;
|
||||
|
|
|
@ -5,7 +5,7 @@ DataValidator::with('CustomValidations', true);
|
|||
|
||||
/**
|
||||
* @api {post} /ticket/search-authors search authors of tickets
|
||||
* @apiVersion 4.6.1
|
||||
* @apiVersion 4.7
|
||||
*
|
||||
* @apiName Search authors
|
||||
*
|
||||
|
@ -41,6 +41,10 @@ class SearchAuthorsController extends Controller {
|
|||
'blackList' => [
|
||||
'validation' => DataValidator::oneOf(DataValidator::validAuthorsBlackList(),DataValidator::nullType()),
|
||||
'error' => ERRORS::INVALID_BLACK_LIST
|
||||
],
|
||||
'searchUsers' => [
|
||||
'validation' => DataValidator::oneOf(DataValidator::in(['0','1']),DataValidator::nullType()),
|
||||
'error' => ERRORS::INVALID_USER_SEARCH_OPTION
|
||||
]
|
||||
]
|
||||
];
|
||||
|
@ -48,31 +52,44 @@ class SearchAuthorsController extends Controller {
|
|||
|
||||
public function handler() {
|
||||
$query = Controller::request('query');
|
||||
$searchUser = Controller::request('searchUsers') ? Controller::request('searchUsers') : 0;
|
||||
|
||||
$authorsQuery = "SELECT id,name,level FROM staff " . $this->generateAuthorsIdQuery($query) . " LIMIT 10";
|
||||
$authorsMatch = RedBean::getAll($authorsQuery, [':query' => "%" .$query . "%",':queryAtBeginning' => $query . "%"] );
|
||||
$authors = [];
|
||||
if(!$searchUser){
|
||||
$sqlQuery = $this->generateAuthorsIdQuery($query);
|
||||
}else{
|
||||
$sqlQuery = $this->generateUsersIdQuery($query);
|
||||
}
|
||||
|
||||
foreach($authorsMatch as $authorMatch) {
|
||||
if($authorMatch['level'] >=1 && $authorMatch['level'] <= 3){
|
||||
$author = Staff::getDataStore($authorMatch['id']*1);
|
||||
$dataStoresMatch = RedBean::getAll($sqlQuery, [':query' => "%" .$query . "%",':queryAtBeginning' => $query . "%"] );
|
||||
|
||||
$list = [];
|
||||
foreach($dataStoresMatch as $dataStoreMatch) {
|
||||
if(!$searchUser && $dataStoreMatch['level'] >=1 && $dataStoreMatch['level'] <= 3){
|
||||
$dataStore = Staff::getDataStore($dataStoreMatch['id']*1);
|
||||
} else {
|
||||
$author = User::getDataStore($authorMatch['id']*1);
|
||||
$dataStore = User::getDataStore($dataStoreMatch['id']*1);
|
||||
}
|
||||
array_push($authors, $author->toArray(true));
|
||||
array_push($list, $dataStore->toArray(true));
|
||||
}
|
||||
Response::respondSuccess([
|
||||
'authors' => $authors
|
||||
'authors' => $list
|
||||
]);
|
||||
}
|
||||
public function generateAuthorsIdQuery($query) {
|
||||
if ($query){
|
||||
return "WHERE name LIKE :query " . $this->generateStaffBlackListQuery() . " UNION SELECT id,name,signup_date FROM user WHERE name LIKE :query " . $this->generateUserBlackListQuery() . " ORDER BY CASE WHEN (name LIKE :queryAtBeginning) THEN 1 ELSE 2 END ASC ";
|
||||
return "SELECT id,name, level FROM staff WHERE name LIKE :query " . $this->generateStaffBlackListQuery() . " UNION SELECT id,name,signup_date FROM user WHERE name LIKE :query " . $this->generateUserBlackListQuery() . " ORDER BY CASE WHEN (name LIKE :queryAtBeginning) THEN 1 ELSE 2 END ASC LIMIT 10";
|
||||
} else {
|
||||
return "WHERE 1=1 ". $this->generateStaffBlackListQuery() . " UNION SELECT id,name,signup_date FROM user WHERE 1=1". $this->generateUserBlackListQuery() ." ORDER BY id";
|
||||
return "SELECT id,name, level FROM staff WHERE 1=1 ". $this->generateStaffBlackListQuery() . " UNION SELECT id,name,signup_date FROM user WHERE 1=1". $this->generateUserBlackListQuery() ." ORDER BY id LIMIT 10";
|
||||
}
|
||||
}
|
||||
|
||||
public function generateUsersIdQuery($query) {
|
||||
if ($query){
|
||||
return "SELECT id FROM user WHERE name LIKE :query " . $this->generateUserBlackListQuery() . " ORDER BY CASE WHEN (name LIKE :queryAtBeginning) THEN 1 ELSE 2 END ASC LIMIT 10";
|
||||
} else {
|
||||
return "SELECT id FROM user WHERE 1=1 ". $this->generateUserBlackListQuery() ." ORDER BY id LIMIT 10";
|
||||
}
|
||||
}
|
||||
|
||||
public function generateStaffBlackListQuery(){
|
||||
$StaffBlackList = $this->getBlackListFiltered();
|
||||
return $this->generateBlackListQuery($StaffBlackList);
|
||||
|
|
|
@ -27,6 +27,7 @@ DataValidator::with('CustomValidations', true);
|
|||
* @apiParam {Number} page The number of the page of the tickets.
|
||||
* @apiParam {Object} orderBy A object {value, asc}with string and boolean to make a especific order of the search.
|
||||
* @apiParam {Number[]} owners The ids of the owners to make a custom search.
|
||||
* @apiParam {Boolean} supervisor Boolean to deteminate if a super-user is making the call.
|
||||
*
|
||||
* @apiUse NO_PERMISSION
|
||||
* @apiUse INVALID_TAG_FILTER
|
||||
|
@ -48,6 +49,7 @@ DataValidator::with('CustomValidations', true);
|
|||
class SearchController extends Controller {
|
||||
const PATH = '/search';
|
||||
const METHOD = 'POST';
|
||||
private $ignoreDeparmentFilter;
|
||||
|
||||
public function validations() {
|
||||
return [
|
||||
|
@ -102,6 +104,7 @@ class SearchController extends Controller {
|
|||
}
|
||||
|
||||
public function handler() {
|
||||
$this->ignoreDeparmentFilter = (bool)Controller::request('supervisor');
|
||||
|
||||
$allowedDepartmentsId = [];
|
||||
foreach (Controller::getLoggedUser()->sharedDepartmentList->toArray() as $department) {
|
||||
|
@ -124,7 +127,6 @@ class SearchController extends Controller {
|
|||
'staffId' => Controller::getLoggedUser()->id
|
||||
];
|
||||
|
||||
|
||||
$query = $this->getSQLQuery($inputs);
|
||||
$queryWithOrder = $this->getSQLQueryWithOrder($inputs);
|
||||
$totalCount = RedBean::getAll("SELECT COUNT(*) FROM (SELECT COUNT(*) " . $query . " ) AS T2", [':query' => "%" . $inputs['query'] . "%", ':queryAtBeginning' => $inputs['query'] . "%" ])[0]['COUNT(*)'];
|
||||
|
@ -180,7 +182,7 @@ class SearchController extends Controller {
|
|||
if(array_key_exists('unreadStaff',$inputs)) $this->setSeenFilter($inputs['unreadStaff'], $filters);
|
||||
if(array_key_exists('dateRange',$inputs)) $this->setDateFilter($inputs['dateRange'], $filters);
|
||||
if(array_key_exists('departments',$inputs) && array_key_exists('allowedDepartments',$inputs) && array_key_exists('staffId',$inputs)){
|
||||
$this->setDepartmentFilter($inputs['departments'],$inputs['allowedDepartments'], $inputs['staffId'], $filters);
|
||||
if(!$this->ignoreDeparmentFilter) $this->setDepartmentFilter($inputs['departments'],$inputs['allowedDepartments'], $inputs['staffId'], $filters);
|
||||
}
|
||||
if(array_key_exists('authors',$inputs)) $this->setAuthorFilter($inputs['authors'], $filters);
|
||||
if(array_key_exists('owners',$inputs)) $this->setOwnerFilter($inputs['owners'], $filters);
|
||||
|
|
|
@ -22,5 +22,7 @@ $userControllers->addController(new VerifyController);
|
|||
$userControllers->addController(new EnableUserController);
|
||||
$userControllers->addController(new DisableUserController);
|
||||
$userControllers->addController(new EditCustomFieldsController);
|
||||
$userControllers->addController(new EditSupervisedListController);
|
||||
$userControllers->addController(new GetSupervisedTicketController);
|
||||
|
||||
$userControllers->finalize();
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
use Respect\Validation\Validator as DataValidator;
|
||||
|
||||
/**
|
||||
* @api {post} /user/edit-supervised-list Edit user list
|
||||
* @apiVersion 4.7.0
|
||||
*
|
||||
* @apiName Edit user list
|
||||
*
|
||||
* @apiGroup User
|
||||
*
|
||||
* @apiDescription This path edits the user list of a user.
|
||||
*
|
||||
* @apiPermission staff1
|
||||
*
|
||||
* @apiParam {Number[]} userIdList The ids of the users.
|
||||
* @apiParam {Number} userId Id of the supervisor user.
|
||||
*
|
||||
* @apiUse NO_PERMISSION
|
||||
* @apiUse INVALID_LIST
|
||||
* @apiUse INVALID_USER
|
||||
* @apiUse SUPERVISOR_CAN_NOT_SUPERVISE_HIMSELF
|
||||
*
|
||||
* @apiSuccess {Object} data Empty object
|
||||
*
|
||||
*/
|
||||
|
||||
class EditSupervisedListController extends Controller {
|
||||
const PATH = '/edit-supervised-list';
|
||||
const METHOD = 'POST';
|
||||
|
||||
public function validations() {
|
||||
return [
|
||||
'permission' => 'staff_1',
|
||||
'requestData' => [
|
||||
'userIdList' => [
|
||||
'validation' => DataValidator::validUsersId(),
|
||||
'error' => ERRORS::INVALID_LIST
|
||||
],
|
||||
'userId' => [
|
||||
'validation' => DataValidator::dataStoreId('user'),
|
||||
'error' => ERRORS::INVALID_USER
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function handler() {
|
||||
$userIdList = $this->getUserIdListCleared();
|
||||
$superUser = User::getDataStore(Controller::request('userId'));
|
||||
|
||||
if(!$superUser->supervisedrelation) {
|
||||
$superUser->supervisedrelation = new Supervisedrelation();
|
||||
}
|
||||
|
||||
$superUser->supervisedrelation->sharedUserList->clear();
|
||||
foreach($userIdList as $userId) {
|
||||
$user = User::getDataStore($userId);
|
||||
|
||||
$superUser->supervisedrelation->sharedUserList->add($user);
|
||||
|
||||
}
|
||||
|
||||
$superUser->supervisedrelation->store();
|
||||
$superUser->store();
|
||||
|
||||
Response::respondSuccess();
|
||||
}
|
||||
|
||||
public function getUserIdListCleared(){
|
||||
$clearedList = array_unique(json_decode(Controller::request('userIdList')));
|
||||
$superUser = User::getDataStore(Controller::request('userId'));
|
||||
|
||||
foreach ($clearedList as $item) {
|
||||
if($item == $superUser->id) throw new Exception(ERRORS::SUPERVISOR_CAN_NOT_SUPERVISE_HIMSELF);
|
||||
}
|
||||
|
||||
return $clearedList;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
use Respect\Validation\Validator as DataValidator;
|
||||
|
||||
/**
|
||||
* @api {post} /user/get-supervised-tickets Get supervised tickets
|
||||
* @apiVersion 4.8.0
|
||||
*
|
||||
* @apiName Get supervised tickets
|
||||
*
|
||||
* @apiGroup User
|
||||
*
|
||||
* @apiDescription This path retrieves own and user supervisated tickets.
|
||||
*
|
||||
* @apiPermission user
|
||||
*
|
||||
* @apiParam {id[]} supervisedUsers arrays of users Ids.
|
||||
* @apiParam {boolean} showOwnTickets boolean to show or not current logged user tickets.
|
||||
* @apiParam {Number} page The number of the page of the tickets.
|
||||
*
|
||||
* @apiUse NO_PERMISSION
|
||||
* @apiUse INVALID_SUPERVISED_USERS
|
||||
*
|
||||
* @apiSuccess {Object} data Information about a tickets and quantity of pages.
|
||||
* @apiSuccess {[Ticket](#api-Data_Structures-ObjectTicket)[]} data.tickets Array of tickets assigned to the staff of the current page.
|
||||
* @apiSuccess {Number} data.page Number of current page.
|
||||
* @apiSuccess {Number} data.pages Quantity of pages.
|
||||
*
|
||||
*/
|
||||
|
||||
class GetSupervisedTicketController extends Controller {
|
||||
const PATH = '/get-supervised-tickets';
|
||||
const METHOD = 'POST';
|
||||
|
||||
public function validations() {
|
||||
return [
|
||||
'permission' => 'user',
|
||||
'requestData' => [
|
||||
'supervisedUsers' => [
|
||||
'validation' => DataValidator::oneOf(DataValidator::validUsersId(),DataValidator::nullType()),
|
||||
'error' => ERRORS:: INVALID_SUPERVISED_USERS
|
||||
],
|
||||
'page' => [
|
||||
'validation' => DataValidator::oneOf(DataValidator::numeric()->positive(),DataValidator::nullType()),
|
||||
'error' => ERRORS::INVALID_PAGE
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
private $authors;
|
||||
private $page;
|
||||
private $showOwnTickets;
|
||||
private $supervisedUserList;
|
||||
|
||||
public function handler() {
|
||||
$this->page = Controller::request('page') ? Controller::request('page') : 1;
|
||||
$this->showOwnTickets = (bool)Controller::request('showOwnTickets');
|
||||
$this->supervisedUserList = Controller::request('supervisedUsers')? json_decode(Controller::request('supervisedUsers')) : [];
|
||||
$this->authors = $this->createAuthorsArray();
|
||||
|
||||
if(!$this->canUserHandleSupervisedUsers()){
|
||||
throw new Exception(ERRORS::INVALID_SUPERVISED_USERS);
|
||||
}
|
||||
|
||||
$searchController = new SearchController(true);
|
||||
Controller::setDataRequester(function ($key) {
|
||||
switch ($key) {
|
||||
case 'authors':
|
||||
return json_encode($this->authors);
|
||||
case 'page' :
|
||||
return $this->page*1;
|
||||
case 'supervisor':
|
||||
return 1;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
if(empty($this->authors)) {
|
||||
Response::respondSuccess([]);
|
||||
}else{
|
||||
$searchController->handler();
|
||||
}
|
||||
}
|
||||
|
||||
public function canUserHandleSupervisedUsers() {
|
||||
$user = Controller::getLoggedUser();
|
||||
if(!$user->supervisedrelation && $this->supervisedUserList) return false;
|
||||
|
||||
if(!empty($this->supervisedUserList)){
|
||||
foreach($this->supervisedUserList as $supevisedUser) {
|
||||
if(!$user->supervisedrelation->sharedUserList->includesId($supevisedUser) && $supevisedUser != $user->id){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function createAuthorsArray(){
|
||||
$user = Controller::getLoggedUser();
|
||||
|
||||
$authors = [];
|
||||
|
||||
if(!empty($this->supervisedUserList)){
|
||||
foreach(array_unique($this->supervisedUserList) as $supervised){
|
||||
array_push($authors,['id'=> $supervised,'isStaff'=> 0]);
|
||||
}
|
||||
};
|
||||
|
||||
if(!in_array( $user->id, $this->supervisedUserList) && $this->showOwnTickets){
|
||||
array_push($authors,['id'=> $user->id*1,'isStaff'=> 0]);
|
||||
}
|
||||
return $authors;
|
||||
}
|
||||
}
|
|
@ -57,7 +57,6 @@ class GetUserByIdController extends Controller {
|
|||
$tickets->add($ticket);
|
||||
}
|
||||
}
|
||||
|
||||
Response::respondSuccess([
|
||||
'name' => $user->name,
|
||||
'email' => $user->email,
|
||||
|
@ -66,6 +65,7 @@ class GetUserByIdController extends Controller {
|
|||
'verified' => !$user->verificationToken,
|
||||
'disabled' => !!$user->disabled,
|
||||
'customfields' => $user->xownCustomfieldvalueList->toArray(),
|
||||
'userList' => $user->supervisedrelation ? $user->supervisedrelation->sharedUserList->toArray() : []
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ class GetUserController extends Controller {
|
|||
}
|
||||
|
||||
public function handler() {
|
||||
|
||||
if (Controller::isStaffLogged()) {
|
||||
throw new RequestException(ERRORS::INVALID_CREDENTIALS);
|
||||
return;
|
||||
|
@ -50,7 +51,7 @@ class GetUserController extends Controller {
|
|||
foreach($ticketList as $ticket) {
|
||||
$parsedTicketList[] = $ticket->toArray(true);
|
||||
}
|
||||
|
||||
|
||||
Response::respondSuccess([
|
||||
'name' => $user->name,
|
||||
'email' => $user->email,
|
||||
|
@ -58,6 +59,7 @@ class GetUserController extends Controller {
|
|||
'verified' => !$user->verificationToken,
|
||||
'tickets' => $parsedTicketList,
|
||||
'customfields' => $user->xownCustomfieldvalueList->toArray(),
|
||||
'users' => $user->supervisedrelation ? $user->supervisedrelation->sharedUserList->toArray() : null
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -267,6 +267,10 @@
|
|||
* @apiDefine DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE
|
||||
* @apiError {String} DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE Default Department can not be private
|
||||
*/
|
||||
/**
|
||||
* @apiDefine SUPERVISOR_CAN_NOT_SUPERVISE_HIMSELF
|
||||
* @apiError {String} SUPERVISOR_CAN_NOT_SUPERVISE_HIMSELF The supervisor cannot select himself
|
||||
*/
|
||||
/**
|
||||
* @apiDefine EMAIL_POLLING
|
||||
* @apiError {String} EMAIL_POLLING Email polling was unsuccesful
|
||||
|
@ -314,6 +318,10 @@
|
|||
/**
|
||||
* @apiDefine REGISTRATION_IS_DESACTIVATED
|
||||
* @apiError {String} REGISTRATION_IS_DESACTIVATED Registration is disactivated
|
||||
*/
|
||||
/**
|
||||
* @apiDefine INVALID_SUPERVISED_USERS
|
||||
* @apiError {String} INVALID_SUPERVISED_USERS supervised users are invalid
|
||||
*/
|
||||
|
||||
class ERRORS {
|
||||
|
@ -386,6 +394,7 @@ class ERRORS {
|
|||
const INVALID_TEXT_3 = 'INVALID_TEXT_3';
|
||||
const DEPARTMENT_PRIVATE_TICKETS = 'DEPARTMENT_PRIVATE_TICKETS';
|
||||
const DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE = 'DEFAULT_DEPARTMENT_CAN_NOT_BE_PRIVATE';
|
||||
const SUPERVISOR_CAN_NOT_SUPERVISE_HIMSELF = 'SUPERVISOR_CAN_NOT_SUPERVISE_HIMSELF';
|
||||
const EMAIL_POLLING = 'EMAIL_POLLING';
|
||||
const CUSTOM_FIELD_ALREADY_EXISTS = 'CUSTOM_FIELD_ALREADY_EXISTS';
|
||||
const INVALID_CUSTOM_FIELD = 'INVALID_CUSTOM_FIELD';
|
||||
|
@ -397,4 +406,6 @@ class ERRORS {
|
|||
const INVALID_API_KEY_TYPE = 'INVALID_API_KEY_TYPE';
|
||||
const MANDATORY_LOGIN_IS_DESACTIVATED = 'MANDATORY_LOGIN_IS_DESACTIVATED';
|
||||
const REGISTRATION_IS_DESACTIVATED = 'REGISTRATION_IS_DESACTIVATED';
|
||||
const INVALID_SUPERVISED_USERS = 'INVALID_SUPERVISED_USERS';
|
||||
const INVALID_USER_SEARCH_OPTION = 'INVALID_USER_SEARCH_OPTION';
|
||||
}
|
||||
|
|
|
@ -52,6 +52,12 @@ class DataStoreList implements IteratorAggregate {
|
|||
return empty($this->list);
|
||||
}
|
||||
|
||||
public function clear() {
|
||||
foreach($this->list as $index=>$item) {
|
||||
unset($this->list[$index]);
|
||||
}
|
||||
}
|
||||
|
||||
public function toBeanList() {
|
||||
$beanList = [];
|
||||
|
||||
|
@ -62,7 +68,7 @@ class DataStoreList implements IteratorAggregate {
|
|||
|
||||
return $beanList;
|
||||
}
|
||||
|
||||
|
||||
public function toArray($minimized = false) {
|
||||
$array = [];
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace CustomValidations;
|
||||
|
||||
use Respect\Validation\Rules\AbstractRule;
|
||||
|
||||
class ValidUsersId extends AbstractRule {
|
||||
public function validate($userIdList) {
|
||||
if(is_array(json_decode($userIdList))){
|
||||
foreach (json_decode($userIdList) as $userItem) {
|
||||
$author = \User::getDataStore($userItem);
|
||||
if($author->isNull()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -130,7 +130,7 @@ abstract class DataStore {
|
|||
$parsedProp = $this->_bean[$prop];
|
||||
}
|
||||
|
||||
if (strpos($prop, 'List')) {
|
||||
if (strpos($prop, 'List') || strpos($prop, 'shared') === 0) {
|
||||
$parsedProp = DataStoreList::getList($this->getListType($prop), $parsedProp);
|
||||
} else if ($parsedProp instanceof \RedBeanPHP\OODBBean) {
|
||||
$beanType = ucfirst($parsedProp->getPropertiesAndType()[1]);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
class Supervisedrelation extends DataStore {
|
||||
const TABLE = 'supervisedrelation';
|
||||
|
||||
public static function getProps() {
|
||||
return[
|
||||
'sharedUserList'
|
||||
];
|
||||
}
|
||||
|
||||
public function getDefaultProps() {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function toArray() {
|
||||
return [
|
||||
'supervisedrelation' => $this->sharedUserList
|
||||
];
|
||||
}
|
||||
}
|
|
@ -33,7 +33,9 @@ class User extends DataStore {
|
|||
'verificationToken',
|
||||
'disabled',
|
||||
'xownCustomfieldvalueList',
|
||||
'notRegistered'
|
||||
'notRegistered',
|
||||
'sharedUserList',
|
||||
'supervisedrelation'
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -47,12 +49,17 @@ class User extends DataStore {
|
|||
|
||||
public function canManageTicket(Ticket $ticket){
|
||||
$ticketNumberInstanceValidation = true;
|
||||
|
||||
$ticketOfSupervisedUser = false;
|
||||
|
||||
if($this->ticketNumber) {
|
||||
$ticketNumberInstanceValidation = $this->ticketNumber == $ticket->ticketNumber;
|
||||
}
|
||||
|
||||
return ($ticket->isAuthor($this) && $ticketNumberInstanceValidation);
|
||||
if($this->supervisedrelation){
|
||||
foreach( $this->supervisedrelation->sharedUserList as $user){
|
||||
if($ticket->isAuthor($user)) $ticketOfSupervisedUser = true;
|
||||
}
|
||||
}
|
||||
return (($ticket->isAuthor($this) || $ticketOfSupervisedUser) && $ticketNumberInstanceValidation);
|
||||
}
|
||||
|
||||
public function toArray($minimal = false) {
|
||||
|
@ -72,7 +79,8 @@ class User extends DataStore {
|
|||
'verified' => !$this->verificationToken,
|
||||
'disabled' => $this->disabled,
|
||||
'customfields' => $this->xownCustomfieldvalueList->toArray(),
|
||||
'notRegistered' => $this->notRegistered
|
||||
'notRegistered' => $this->notRegistered,
|
||||
'supervisedrelation' => $this->supervisedrelation
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,4 +77,6 @@ require './ticket/search.rb'
|
|||
require './ticket/get-authors.rb'
|
||||
require './system/mandatory-login.rb'
|
||||
require './system/default-department.rb'
|
||||
require './user/edit-supervised-list.rb'
|
||||
require './user/get-supervised-tickets.rb'
|
||||
# require './system/get-stats.rb'
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
describe '/staff/supervisor-user-list' do
|
||||
request('/user/logout')
|
||||
|
||||
Scripts.createUser('supervisor@opensupports.com', 'passwordOfSupervisor', 'Supervisor Guy')
|
||||
Scripts.createUser('usersupervised1@opensupports.com', 'usersupervised1', 'supervised Guy1')
|
||||
Scripts.createUser('usersupervised2@opensupports.com', 'usersupervised2', 'supervised Guy2')
|
||||
Scripts.createUser('usersupervised3@opensupports.com', 'usersupervised3', 'supervised Guy3')
|
||||
|
||||
Scripts.login('supervisor@opensupports.com', 'passwordOfSupervisor')
|
||||
Scripts.createTicket('titlecreateadbySUpervisor','contentoftitlecreateadbySUpervisor',1)
|
||||
Scripts.logout()
|
||||
|
||||
Scripts.login('usersupervised1@opensupports.com', 'usersupervised1')
|
||||
Scripts.createTicket('titlecreateadbyusersupervised1','contentoftitlecreateadbyusersupervised1',3)
|
||||
Scripts.logout()
|
||||
|
||||
Scripts.login('usersupervised2@opensupports.com', 'usersupervised2')
|
||||
Scripts.createTicket('titlecreateadbyusersupervised2','contentoftitlecreateadbyusersupervised2',1)
|
||||
Scripts.logout()
|
||||
|
||||
Scripts.login('usersupervised3@opensupports.com', 'usersupervised3')
|
||||
Scripts.createTicket('titlecreateadbyusersupervised3','contentoftitlecreateadbyusersupervised3',1)
|
||||
Scripts.logout()
|
||||
|
||||
supervisor = $database.getRow('user', 'supervisor@opensupports.com', 'email')
|
||||
user1 = $database.getRow('user', 'usersupervised1@opensupports.com', 'email')
|
||||
user2 = $database.getRow('user', 'usersupervised2@opensupports.com', 'email')
|
||||
user3 = $database.getRow('user', 'usersupervised3@opensupports.com', 'email')
|
||||
|
||||
ticketsupervisor = $database.getRow('ticket', 'titlecreateadbySUpervisor', 'title')
|
||||
ticketuser1 = $database.getRow('ticket', 'titlecreateadbyusersupervised1', 'title')
|
||||
ticketuser2 = $database.getRow('ticket', 'titlecreateadbyusersupervised2', 'title')
|
||||
ticketuser3 = $database.getRow('ticket', 'titlecreateadbyusersupervised3', 'title')
|
||||
it'should fail if a no-staff tryes to make the request'do
|
||||
request('/user/logout')
|
||||
Scripts.login('supervisor@opensupports.com', 'passwordOfSupervisor')
|
||||
|
||||
result = request('/user/edit-supervised-list', {
|
||||
userIdList: "[30,31,32]",
|
||||
userId: supervisor['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('NO_PERMISSION')
|
||||
|
||||
end
|
||||
|
||||
it 'should fail if userIdList is wrong' do
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
|
||||
result = request('/user/edit-supervised-list', {
|
||||
userIdList: "1",
|
||||
userId: supervisor['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_LIST')
|
||||
|
||||
result = request('/user/edit-supervised-list', {
|
||||
userIdList: "array",
|
||||
userId: supervisor['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_LIST')
|
||||
|
||||
result = request('/user/edit-supervised-list', {
|
||||
userIdList: "[30,31,32,666666]",
|
||||
userId: supervisor['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_LIST')
|
||||
end
|
||||
|
||||
it'should fail if userId is wrong'do
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
|
||||
result = request('/user/edit-supervised-list', {
|
||||
userIdList: "[30,31,32]",
|
||||
userId: 666,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_USER')
|
||||
end
|
||||
|
||||
it'should fail if supervisor is included in user-id-List'do
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
|
||||
result = request('/user/edit-supervised-list', {
|
||||
userIdList: "[30,31,29]",
|
||||
userId: supervisor['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('SUPERVISOR_CAN_NOT_SUPERVISE_HIMSELF')
|
||||
end
|
||||
|
||||
it'should create supervisor user'do
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
|
||||
result = request('/user/edit-supervised-list', {
|
||||
userIdList: "[30,31,32]",
|
||||
userId: supervisor['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
end
|
||||
|
||||
it 'should allow supervisor to access tickets from supervisated users' do
|
||||
request('/user/logout')
|
||||
Scripts.login('supervisor@opensupports.com', 'passwordOfSupervisor')
|
||||
result = request('/ticket/get', {
|
||||
ticketNumber: ticketsupervisor['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
result = request('/ticket/get', {
|
||||
ticketNumber: ticketuser1['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
result = request('/ticket/get', {
|
||||
ticketNumber: ticketuser2['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
result = request('/ticket/get', {
|
||||
ticketNumber: ticketuser3['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
end
|
||||
it 'should allow supervisor see only the new user list' do
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
|
||||
request('/user/edit-supervised-list', {
|
||||
userIdList: "[30]",
|
||||
userId: supervisor['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
|
||||
request('/user/logout')
|
||||
Scripts.login('supervisor@opensupports.com', 'passwordOfSupervisor')
|
||||
|
||||
result = request('/ticket/get', {
|
||||
ticketNumber: ticketsupervisor['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
result = request('/ticket/get', {
|
||||
ticketNumber: ticketuser1['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
result = request('/ticket/get', {
|
||||
ticketNumber: ticketuser2['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
(result['status']).should.equal('fail')
|
||||
|
||||
result = request('/ticket/get', {
|
||||
ticketNumber: ticketuser3['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
(result['status']).should.equal('fail')
|
||||
end
|
||||
end
|
|
@ -0,0 +1,231 @@
|
|||
describe '/user/get-supervised-tickets' do
|
||||
request('/user/logout')
|
||||
|
||||
supervisor = $database.getRow('user', 'supervisor@opensupports.com', 'email')
|
||||
user1 = $database.getRow('user', 'usersupervised1@opensupports.com', 'email')
|
||||
user2 = $database.getRow('user', 'usersupervised2@opensupports.com', 'email')
|
||||
|
||||
ticketsupervisor = $database.getRow('ticket', 'titlecreateadbySUpervisor', 'title')
|
||||
ticketuser1 = $database.getRow('ticket', 'titlecreateadbyusersupervised1', 'title')
|
||||
ticketuser2 = $database.getRow('ticket', 'titlecreateadbyusersupervised2', 'title')
|
||||
ticketuser3 = $database.getRow('ticket', 'titlecreateadbyusersupervised3', 'title')
|
||||
|
||||
|
||||
it 'should fail if supervised users are not valid' do
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
|
||||
result = request('/user/edit-supervised-list', {
|
||||
userIdList: "[30,32,31]",
|
||||
userId: supervisor['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
|
||||
request('/user/logout')
|
||||
Scripts.login('supervisor@opensupports.com', 'passwordOfSupervisor')
|
||||
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[1000,30]",
|
||||
showOwnTickets: 1,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_SUPERVISED_USERS')
|
||||
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[32,30,1]",
|
||||
showOwnTickets: 1,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_SUPERVISED_USERS')
|
||||
|
||||
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "32",
|
||||
showOwnTickets: 1,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_SUPERVISED_USERS')
|
||||
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "hello",
|
||||
showOwnTickets: 1,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_SUPERVISED_USERS')
|
||||
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[{'id' :29 , 'staff' true}]",
|
||||
showOwnTickets: 1,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_SUPERVISED_USERS')
|
||||
end
|
||||
|
||||
it 'should return the tickets of the authors searched' do
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[30,32,31]",
|
||||
showOwnTickets: 0,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
(result['data']['tickets'].size).should.equal(3)
|
||||
(result['data']['tickets'][0]['title']).should.equal(ticketuser3['title'])
|
||||
(result['data']['tickets'][1]['title']).should.equal(ticketuser2['title'])
|
||||
(result['data']['tickets'][2]['title']).should.equal(ticketuser1['title'])
|
||||
end
|
||||
it 'should return the tickets of the authors searched including logged user' do
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[30,32]",
|
||||
showOwnTickets: 1,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
(result['data']['tickets'].size).should.equal(3)
|
||||
(result['data']['tickets'][0]['title']).should.equal(ticketuser3['title'])
|
||||
(result['data']['tickets'][1]['title']).should.equal(ticketuser1['title'])
|
||||
(result['data']['tickets'][2]['title']).should.equal(ticketsupervisor['title'])
|
||||
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[30,32,29]",
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
(result['data']['tickets'].size).should.equal(3)
|
||||
(result['data']['tickets'][0]['title']).should.equal(ticketuser3['title'])
|
||||
(result['data']['tickets'][1]['title']).should.equal(ticketuser1['title'])
|
||||
(result['data']['tickets'][2]['title']).should.equal(ticketsupervisor['title'])
|
||||
end
|
||||
|
||||
it 'should return empty list if supervised users is empty and show own tickets off' do
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[]",
|
||||
showOwnTickets: 0,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
(result['data']).should.equal([])
|
||||
end
|
||||
it 'should works propertly if 2 supervisors has the same users' do
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
Scripts.createUser('supervisor2@opensupports.com', 'usersupervised2', 'supervisor Guy2')
|
||||
supervisor2 = $database.getRow('user', 'supervisor2@opensupports.com', 'email')
|
||||
|
||||
result = request('/user/edit-supervised-list', {
|
||||
userIdList: "[30,32,31]",
|
||||
userId: supervisor2['id'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
Scripts.login('supervisor@opensupports.com', 'passwordOfSupervisor')
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[30,32,31]",
|
||||
showOwnTickets: 0,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
(result['data']['tickets'].size).should.equal(3)
|
||||
(result['data']['tickets'][0]['title']).should.equal(ticketuser3['title'])
|
||||
(result['data']['tickets'][1]['title']).should.equal(ticketuser2['title'])
|
||||
(result['data']['tickets'][2]['title']).should.equal(ticketuser1['title'])
|
||||
Scripts.logout()
|
||||
|
||||
Scripts.login('supervisor2@opensupports.com', 'usersupervised2')
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[30,32,31]",
|
||||
showOwnTickets: 0,
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
(result['data']['tickets'].size).should.equal(3)
|
||||
(result['data']['tickets'][0]['title']).should.equal(ticketuser3['title'])
|
||||
(result['data']['tickets'][1]['title']).should.equal(ticketuser2['title'])
|
||||
(result['data']['tickets'][2]['title']).should.equal(ticketuser1['title'])
|
||||
Scripts.logout()
|
||||
|
||||
end
|
||||
|
||||
it 'should if supervised Users tryes to handle supervisor-ticket' do
|
||||
request('/user/logout')
|
||||
Scripts.login('usersupervised1@opensupports.com', 'usersupervised1')
|
||||
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[29]",
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_SUPERVISED_USERS')
|
||||
|
||||
request('/user/logout')
|
||||
Scripts.login('usersupervised2@opensupports.com', 'usersupervised2')
|
||||
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[29]",
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_SUPERVISED_USERS')
|
||||
|
||||
request('/user/logout')
|
||||
Scripts.login('usersupervised3@opensupports.com', 'usersupervised3')
|
||||
|
||||
result = request('/user/get-supervised-tickets', {
|
||||
supervisedUsers: "[29]",
|
||||
page: 1,
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
(result['message']).should.equal('INVALID_SUPERVISED_USERS')
|
||||
|
||||
end
|
||||
end
|
|
@ -3,7 +3,7 @@ use RedBeanPHP\Facade as RedBean;
|
|||
|
||||
/**
|
||||
* @api {OBJECT} MailTemplate MailTemplate
|
||||
* @apiVersion 4.3.2
|
||||
* @apiVersion 4.7
|
||||
* @apiGroup Data Structures
|
||||
* @apiParam {String} type The type of the mail template.
|
||||
* @apiParam {String} subject The subject of the mail template.
|
||||
|
|
Loading…
Reference in New Issue