diff --git a/client/src/app-components/activity-row.js b/client/src/app-components/activity-row.js index 1b3da113..ef029498 100644 --- a/client/src/app-components/activity-row.js +++ b/client/src/app-components/activity-row.js @@ -19,6 +19,7 @@ class ActivityRow extends React.Component { 'RE_OPEN', 'DEPARTMENT_CHANGED', 'PRIORITY_CHANGED', + 'EDIT_TITLE', 'EDIT_COMMENT', 'EDIT_SETTINGS', @@ -60,6 +61,8 @@ class ActivityRow extends React.Component { 'DEPARTMENT_CHANGED', 'PRIORITY_CHANGED', 'COMMENT_EDITED', + 'EDIT_TITLE', + 'EDIT_COMMENT', ]; return ( @@ -113,6 +116,7 @@ class ActivityRow extends React.Component { 'RE_OPEN': 'unlock-alt', 'DEPARTMENT_CHANGED': 'exchange', 'PRIORITY_CHANGED': 'exclamation', + 'EDIT_TITLE': 'edit', 'EDIT_COMMENT': 'edit', 'EDIT_SETTINGS': 'wrench', diff --git a/client/src/app-components/ticket-list.js b/client/src/app-components/ticket-list.js index d23ecf0f..6f85dc43 100644 --- a/client/src/app-components/ticket-list.js +++ b/client/src/app-components/ticket-list.js @@ -274,4 +274,4 @@ export default connect((store) => { return { tags: store.config['tags'] }; -})(TicketList); \ No newline at end of file +})(TicketList); diff --git a/client/src/app-components/ticket-query-list.js b/client/src/app-components/ticket-query-list.js new file mode 100644 index 00000000..f28dbc3b --- /dev/null +++ b/client/src/app-components/ticket-query-list.js @@ -0,0 +1,90 @@ +import React from 'react'; +import _ from 'lodash'; + +import API from 'lib-app/api-call'; +import i18n from 'lib-app/i18n'; +import {connect} from 'react-redux'; + +import TicketList from 'app-components/ticket-list'; +import Message from 'core-components/message'; + +class TicketQueryList extends React.Component { + + state = { + tickets: [], + page: 1, + pages: 0, + error: null, + loading: true + }; + + componentDidMount() { + this.getTickets(); + } + + componentDidUpdate(prevProps) { + if (this.props.customList.title !== prevProps.customList.title) { + this.getTickets(); + } + } + + render() { + return ( +
+ {(this.state.error) ? {i18n('ERROR_RETRIEVING_TICKETS')} : } +
+ ); + } + + getTickets() { + this.setState({ + loading:true + }) + API.call({ + path: '/ticket/search', + data: { + page : this.state.page, + ...this.props.customList.filters + } + }).then((result) => { + this.setState({ + tickets: result.data.tickets, + page: result.data.page, + pages: result.data.pages, + error: null, + loading: false + }) + }).catch((result) => this.setState({ + loading: false, + error: result.message + })); + + } + + onPageChange(event) { + this.setState({page: event.target.value}, () => this.getTickets()); + } + + getTicketListProps () { + const {page,pages,loading,tickets} = this.state; + return { + userId: this.props.userId, + ticketPath: '/admin/panel/tickets/view-ticket/', + tickets, + page, + pages, + loading, + type: 'secondary', + showDepartmentDropdown: false, + closedTicketsShown: false, + onPageChange:this.onPageChange.bind(this) + }; + } + +} + +export default connect((store) => { + return { + userId: store.session.userId + }; +})(TicketQueryList); diff --git a/client/src/app-components/ticket-viewer.js b/client/src/app-components/ticket-viewer.js index f244e65b..7bb38a61 100644 --- a/client/src/app-components/ticket-viewer.js +++ b/client/src/app-components/ticket-viewer.js @@ -8,6 +8,7 @@ import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; import SessionStore from 'lib-app/session-store'; import MentionsParser from 'lib-app/mentions-parser'; +import history from 'lib-app/history'; import TicketEvent from 'app-components/ticket-event'; import AreYouSure from 'app-components/are-you-sure'; @@ -60,6 +61,9 @@ class TicketViewer extends React.Component { edit: false, editId: 0, tagSelectorLoading: false, + editTitle: false, + newTitle: this.props.ticket.title, + editTitleError: false, }; componentDidMount() { @@ -72,13 +76,7 @@ class TicketViewer extends React.Component { const ticket = this.props.ticket; return (
-
- #{ticket.ticketNumber} - {ticket.title} - - - -
+ {this.state.editTitle ? this.renderEditableTitle() : this.renderTitleHeader()} {this.props.editable ? this.renderEditableHeaders() : this.renderHeaders()}
+ #{ticketNumber} + {title} + + + + {((author.id == userId && author.staff == userStaff) || userStaff) ? this.renderEditTitleOption() : null} + {editedTitle ? this.renderEditedTitleText() : null } +
+ ) + } + + renderEditedTitleText(){ + return( +
{i18n('TITLE_EDITED')}
+ ) + } + + renderEditTitleOption() { + return( + + this.setState({editTitle: true})} /> + + ) + } + + renderEditableTitle(){ + return( +
+
+ this.setState({newTitle: e.target.value })} /> +
+ +
+ ) + } + renderEditableHeaders() { const ticket = this.props.ticket; const departments = this.getDepartmentsForTransfer(); @@ -403,6 +445,26 @@ class TicketViewer extends React.Component { AreYouSure.openModal(null, this.deleteTicket.bind(this)); } + changeTitle(){ + API.call({ + path: '/ticket/edit-title', + data: { + ticketNumber: this.props.ticket.ticketNumber, + title: this.state.newTitle + } + }).then(() => { + this.setState({ + editTitle: false, + editTitleError: false + }); + this.onTicketModification(); + }).catch((result) => { + this.setState({ + editTitleError: i18n(result.message) + }) + }); + } + reopenTicket() { API.call({ path: '/ticket/re-open', @@ -427,7 +489,10 @@ class TicketViewer extends React.Component { data: { ticketNumber: this.props.ticket.ticketNumber } - }).then(this.onTicketModification.bind(this)); + }).then((result) => { + this.onTicketModification(result); + history.push('/admin/panel/tickets/my-tickets/'); + }); } changeDepartment(index) { @@ -640,7 +705,6 @@ class TicketViewer extends React.Component { } export default connect((store) => { - return { userId: store.session.userId, userStaff: store.session.staff, diff --git a/client/src/app-components/ticket-viewer.scss b/client/src/app-components/ticket-viewer.scss index 17de6a8c..87b2f6fe 100644 --- a/client/src/app-components/ticket-viewer.scss +++ b/client/src/app-components/ticket-viewer.scss @@ -9,6 +9,42 @@ color: white; font-size: 16px; padding: 6px 0; + display: flex; + align-items:center; + justify-content:center; + position: relative; + &:hover { + .ticket-viewer__edit-title-icon { + color: $grey; + } + } + } + + &__edited-title-text { + font-style: italic; + font-size: 14px; + margin-left: 10px; + } + + &__edit-title-icon { + position: absolute; + color: #414A59; + right: 12px; + &:hover { + cursor:pointer; + } + } + + &___input-edit-title { + color: black; + align-items:center; + justify-content: center; + margin-bottom: 6px; + margin-right: 6px; + + .input__text { + height: 25px; + } } &__number { diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index 0419c0db..b9d43065 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -33,6 +33,7 @@ import AdminPanelMyAccount from 'app/admin/panel/dashboard/admin-panel-my-accoun import AdminPanelMyTickets from 'app/admin/panel/tickets/admin-panel-my-tickets'; import AdminPanelNewTickets from 'app/admin/panel/tickets/admin-panel-new-tickets'; import AdminPanelAllTickets from 'app/admin/panel/tickets/admin-panel-all-tickets'; +import AdminPanelSearchTickets from 'app/admin/panel/tickets/admin-panel-search-tickets'; import AdminPanelViewTicket from 'app/admin/panel/tickets/admin-panel-view-ticket'; import AdminPanelCustomResponses from 'app/admin/panel/tickets/admin-panel-custom-responses'; @@ -113,6 +114,7 @@ export default ( + diff --git a/client/src/app/admin/panel/admin-panel-menu.js b/client/src/app/admin/panel/admin-panel-menu.js index 4ab4ca79..9627947a 100644 --- a/client/src/app/admin/panel/admin-panel-menu.js +++ b/client/src/app/admin/panel/admin-panel-menu.js @@ -76,7 +76,7 @@ class AdminPanelMenu extends React.Component { getGroupItemIndex() { const group = this.getRoutes()[this.getGroupIndex()]; - const pathname = this.props.location.pathname; + const pathname = this.props.location.pathname + this.props.location.search; return _.findIndex(group.items, {path: pathname}); } @@ -90,7 +90,23 @@ class AdminPanelMenu extends React.Component { return (groupIndex === -1) ? 0 : groupIndex; } + getCustomlists() { + if(window.customTicketList){ + return window.customTicketList.map((item, index) => { + return { + name: item.title, + path: '/admin/panel/tickets/search-tickets?custom=' + index, + level: 1 + } + }) + } else { + return []; + } + } + getRoutes() { + const customLists = this.getCustomlists(); + return this.getItemsByFilteredByLevel(_.without([ { groupName: i18n('DASHBOARD'), @@ -135,7 +151,8 @@ class AdminPanelMenu extends React.Component { name: i18n('CUSTOM_RESPONSES'), path: '/admin/panel/tickets/custom-responses', level: 2 - } + }, + ...customLists ]) }, this.props.config['user-system-enabled'] ? { diff --git a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js index 39f769e0..0855e6e7 100644 --- a/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js +++ b/client/src/app/admin/panel/settings/admin-panel-advanced-settings.js @@ -153,7 +153,7 @@ class AdminPanelAdvancedSettings extends React.Component { ModalContainer.closeModal(); API.call({ path: '/system/add-api-key', - data: {name} + data: {name, type: 'REGISTRATION'} }).then(this.getAllKeys.bind(this)); } @@ -177,7 +177,7 @@ class AdminPanelAdvancedSettings extends React.Component { onRetrieveSuccess(result) { this.setState({ - APIKeys: result.data, + APIKeys: result.data.filter(key => key['type'] === 'REGISTRATION'), selectedAPIKey: -1 }); } diff --git a/client/src/app/admin/panel/tickets/admin-panel-search-tickets.js b/client/src/app/admin/panel/tickets/admin-panel-search-tickets.js new file mode 100644 index 00000000..f5726f2c --- /dev/null +++ b/client/src/app/admin/panel/tickets/admin-panel-search-tickets.js @@ -0,0 +1,34 @@ +import React from 'react'; +import {connect} from 'react-redux'; + +import i18n from 'lib-app/i18n'; + +import TicketQueryList from 'app-components/ticket-query-list'; + +import Header from 'core-components/header'; +import Message from 'core-components/message'; + +class AdminPanelSearchTickets extends React.Component { + + render() { + return ( +
+
+ {(this.props.error) ? {i18n('ERROR_RETRIEVING_TICKETS')} : } +
+ ); + } + + getFilters() { + let customList = (window.customTicketList && window.customTicketList[this.props.location.query.custom*1]) ? window.customTicketList[this.props.location.query.custom*1] : null + return { + ...customList + }; + } +} + +export default connect((store) => { + return { + error: store.adminData.allTicketsError + }; +})(AdminPanelSearchTickets); diff --git a/client/src/core-components/menu.js b/client/src/core-components/menu.js index 25cd805d..40ef6de2 100644 --- a/client/src/core-components/menu.js +++ b/client/src/core-components/menu.js @@ -140,4 +140,4 @@ class Menu extends React.Component { } } -export default Menu; \ No newline at end of file +export default Menu; diff --git a/client/src/core-components/menu.scss b/client/src/core-components/menu.scss index 64eab16c..d8b06c20 100644 --- a/client/src/core-components/menu.scss +++ b/client/src/core-components/menu.scss @@ -201,4 +201,4 @@ $transition: background-color 0.3s ease, color 0.3s ease; color: white; } } -} \ No newline at end of file +} diff --git a/client/src/core-components/pagination.js b/client/src/core-components/pagination.js index 4b4ad162..8ce28a8d 100644 --- a/client/src/core-components/pagination.js +++ b/client/src/core-components/pagination.js @@ -98,4 +98,4 @@ class Pagination extends React.Component { } } -export default Pagination; \ No newline at end of file +export default Pagination; diff --git a/client/src/core-components/table.js b/client/src/core-components/table.js index fe882f72..07c9f29f 100644 --- a/client/src/core-components/table.js +++ b/client/src/core-components/table.js @@ -55,7 +55,7 @@ class Table extends React.Component { 'table__header-column': true, [header.className]: (header.className) }; - + return ( {header.value} @@ -97,7 +97,7 @@ class Table extends React.Component { }; return ( - + {row[key]} ); } @@ -139,15 +139,15 @@ class Table extends React.Component { this.props.onPageChange({target: {value: index}}); } } - + getRowClass(row) { let classes = { 'table__row': true, 'table__row-highlighted': row.highlighted }; - + classes[row.className] = (row.className); - + return classNames(classes); } @@ -167,4 +167,4 @@ class Table extends React.Component { } } -export default Table; \ No newline at end of file +export default Table; diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 361dcb00..c1839ae1 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -91,9 +91,11 @@ export default { 'BAN_EMAIL': 'Ban email', 'EDIT_EMAIL': 'Edit email', 'EDIT_PASSWORD': 'Edit password', + 'EDIT_TITLE': 'Edit title', 'CHANGE_EMAIL': 'Change email', 'CHANGE_PASSWORD': 'Change password', 'NAME': 'Name', + 'SEARCH': 'Search', 'SIGNUP_DATE': 'Sign up date', 'SEARCH_USERS': 'Search users...', 'SEARCH_EMAIL': 'Search email...', @@ -232,7 +234,7 @@ export default { 'ACTIVITY_DEPARTMENT_CHANGED': 'changed department of ticket', 'ACTIVITY_PRIORITY_CHANGED': 'changed priority of ticket', 'ACTIVITY_EDIT_COMMENT': 'edited a comment of ticket', - + 'ACTIVITY_EDIT_TITLE': 'edited title of ticket', 'ACTIVITY_EDIT_SETTINGS': 'edited settings', 'ACTIVITY_SIGNUP': 'signed up', 'ACTIVITY_INVITE': 'invited user', @@ -297,6 +299,7 @@ export default { 'MY_TICKETS_DESCRIPTION': 'Here you can view the tickets you are responsible for.', 'NEW_TICKETS_DESCRIPTION': 'Here you can view all the new tickets that are not assigned by anyone.', 'ALL_TICKETS_DESCRIPTION': 'Here you can view the tickets of the departments you are assigned.', + 'SEARCH_TICKETS_DESCRIPTION': 'Here you can search tickets by specific filters', 'TICKET_VIEW_DESCRIPTION': 'This ticket has been sent by a customer. Here you can respond or assign the ticket', 'BAN_USERS_DESCRIPTION': 'Here you can see a list of banned emails, you can un-ban them or add more emails to the list.', 'LIST_USERS_DESCRIPTION': 'This is the list of users that are registered in this platform. You can search for someone in particular, delete it or ban it.', @@ -358,6 +361,7 @@ export default { 'TICKET_COMMENT_ERROR': 'An error occurred while trying to add the comment.', 'NO_PERMISSION': 'You\'ve no permission to access to this page.', 'INVALID_USER': 'User id is invalid', + 'INVALID_TITLE': 'invalid title', 'ERROR_RETRIEVING_TICKETS': 'An error occurred while trying to retrieve tickets.', 'ERROR_RETRIEVING_USERS': 'An error occurred while trying to retrieve users.', 'ERROR_RETRIEVING_BAN_LIST': 'An error occurred while trying to retrieve the list of banned emails.', @@ -406,6 +410,7 @@ export default { 'SERVER_CREDENTIALS_WORKING': 'Server credentials are working correctly', 'DELETE_CUSTOM_FIELD_SURE': 'Some users may be using this field. Are you sure you want to delete it?', + 'TITLE_EDITED': '(title edited)', 'COMMENT_EDITED': '(comment edited)', 'LAST_7_DAYS': 'Last 7 days', 'LAST_30_DAYS': 'Last 30 days', diff --git a/client/src/data/languages/pl.js b/client/src/data/languages/pl.js index ac44a9cf..a03bd8af 100644 --- a/client/src/data/languages/pl.js +++ b/client/src/data/languages/pl.js @@ -29,8 +29,8 @@ export default { 'DATE': 'Data', 'RESPOND': 'Odpowiedz', 'RESPOND_TICKET': 'Odpowiedź na zgłoszenie', - 'CLOSE_TICKET': 'blisko bilet', - 'DELETE_TICKET': 'Usuń bilet', + 'CLOSE_TICKET': 'Zamknij zgłoszenie', + 'DELETE_TICKET': 'Usuń zgłoszenie', 'NO_ATTACHMENT': 'Bez załącznika', 'STAFF': 'Personel', 'CUSTOMER': 'Klient', diff --git a/client/src/index.html b/client/src/index.html index 90c8c2e2..a00af5b1 100755 --- a/client/src/index.html +++ b/client/src/index.html @@ -12,7 +12,6 @@
- diff --git a/server/controllers/staff/get-all-tickets.php b/server/controllers/staff/get-all-tickets.php index 93a30975..a1530e8f 100755 --- a/server/controllers/staff/get-all-tickets.php +++ b/server/controllers/staff/get-all-tickets.php @@ -50,7 +50,7 @@ class GetAllTicketsStaffController extends Controller { ]); return; } - + Response::respondSuccess([ 'tickets' => $this->getTicketList()->toArray(true), 'pages' => $this->getTotalPages() diff --git a/server/controllers/system/add-api-key.php b/server/controllers/system/add-api-key.php index 38ef0861..fbb34107 100755 --- a/server/controllers/system/add-api-key.php +++ b/server/controllers/system/add-api-key.php @@ -14,10 +14,12 @@ use Respect\Validation\Validator as DataValidator; * @apiPermission staff3 * * @apiParam {String} name Name of the new APIKey. + * @apiParam {String} type Type of APIKey: "REGISTRATION" or "TICKET_CREATE" * * @apiUse NO_PERMISSION * @apiUse INVALID_NAME * @apiUse NAME_ALREADY_USED + * @apiUse INVALID_API_KEY_TYPE * * @apiSuccess {String} data Token of the APIKey. * @@ -34,6 +36,10 @@ class AddAPIKeyController extends Controller { 'name' => [ 'validation' => DataValidator::length(2, 55)->alnum(), 'error' => ERRORS::INVALID_NAME + ], + 'type' => [ + 'validation' => DataValidator::in(APIKey::TYPES), + 'error' => ERRORS::INVALID_API_KEY_TYPE ] ] ]; @@ -43,6 +49,7 @@ class AddAPIKeyController extends Controller { $apiInstance = new APIKey(); $name = Controller::request('name'); + $type = Controller::request('type'); $keyInstance = APIKey::getDataStore($name, 'name'); @@ -51,7 +58,8 @@ class AddAPIKeyController extends Controller { $apiInstance->setProperties([ 'name' => $name, - 'token' => $token + 'token' => $token, + 'type' => $type, ]); $apiInstance->store(); diff --git a/server/controllers/ticket.php b/server/controllers/ticket.php index 5afbf8d5..bc046c51 100755 --- a/server/controllers/ticket.php +++ b/server/controllers/ticket.php @@ -4,6 +4,7 @@ $ticketControllers->setGroupPath('/ticket'); $ticketControllers->addController(new CreateController); $ticketControllers->addController(new EditCommentController); +$ticketControllers->addController(new EditTitleController); $ticketControllers->addController(new CommentController); $ticketControllers->addController(new TicketGetController); $ticketControllers->addController(new CheckTicketController); @@ -23,5 +24,6 @@ $ticketControllers->addController(new DeleteTagController); $ticketControllers->addController(new GetTagsController); $ticketControllers->addController(new AddTagController); $ticketControllers->addController(new RemoveTagController); +$ticketControllers->addController(new SearchController); $ticketControllers->finalize(); diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php index 1ea18790..6fb76b28 100755 --- a/server/controllers/ticket/create.php +++ b/server/controllers/ticket/create.php @@ -75,7 +75,7 @@ class CreateController extends Controller { if(!Controller::isUserSystemEnabled() && !Controller::isStaffLogged()) { $validations['permission'] = 'any'; $validations['requestData']['captcha'] = [ - 'validation' => DataValidator::captcha(), + 'validation' => DataValidator::captcha(APIKey::TICKET_CREATE), 'error' => ERRORS::INVALID_CAPTCHA ]; $validations['requestData']['email'] = [ diff --git a/server/controllers/ticket/edit-comment.php b/server/controllers/ticket/edit-comment.php index c924694b..a0ffe1bf 100644 --- a/server/controllers/ticket/edit-comment.php +++ b/server/controllers/ticket/edit-comment.php @@ -20,6 +20,7 @@ DataValidator::with('CustomValidations', true); * * @apiUse NO_PERMISSION * @apiUse INVALID_CONTENT + * @apiUse INVALID_TOKEN * * @apiSuccess {Object} data Empty object * @@ -30,15 +31,39 @@ class EditCommentController extends Controller { const METHOD = 'POST'; public function validations() { - return [ - 'permission' => 'user', - 'requestData' => [ - 'content' => [ - 'validation' => DataValidator::length(10, 5000), - 'error' => ERRORS::INVALID_CONTENT + if(Controller::isUserSystemEnabled()){ + return [ + 'permission' => 'user', + 'requestData' => [ + 'content' => [ + 'validation' => DataValidator::length(10, 5000), + 'error' => ERRORS::INVALID_CONTENT + ], + 'ticketNumber' => [ + 'validation' => DataValidator::oneOf(DataValidator::validTicketNumber(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_TICKET + ] ] - ] - ]; + ]; + } else { + return [ + 'permission' => 'any', + 'requestData' => [ + 'content' => [ + 'validation' => DataValidator::length(10, 5000), + 'error' => ERRORS::INVALID_CONTENT + ], + 'ticketNumber' => [ + 'validation' => DataValidator::oneOf(DataValidator::validTicketNumber(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_TICKET + ], + 'csrf_token' => [ + 'validation' => DataValidator::equals(Session::getInstance()->getToken()), + 'error' => ERRORS::INVALID_TOKEN + ] + ] + ]; + } } public function handler() { @@ -49,7 +74,7 @@ class EditCommentController extends Controller { $ticketevent = Ticketevent::getTicketEvent(Controller::request('ticketEventId')); $ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber')); - if(!Controller::isStaffLogged() && ($user->id !== $ticketevent->authorUserId && $user->id !== $ticket->authorId ) ){ + if(Controller::isUserSystemEnabled() && !Controller::isStaffLogged() && ($user->id !== $ticketevent->authorUserId && $user->id !== $ticket->authorId ) ){ throw new RequestException(ERRORS::NO_PERMISSION); } diff --git a/server/controllers/ticket/edit-title.php b/server/controllers/ticket/edit-title.php new file mode 100644 index 00000000..f407d28d --- /dev/null +++ b/server/controllers/ticket/edit-title.php @@ -0,0 +1,86 @@ + 'user', + 'requestData' => [ + 'title' => [ + 'validation' => DataValidator::length(1, 200), + 'error' => ERRORS::INVALID_TITLE + ], + 'ticketNumber' => [ + 'validation' => DataValidator::validTicketNumber(), + 'error' => ERRORS::INVALID_TICKET + ] + ] + ]; + } else { + return [ + 'permission' => 'any', + 'requestData' => [ + 'title' => [ + 'validation' => DataValidator::length(1, 200), + 'error' => ERRORS::INVALID_TITLE + ], + 'ticketNumber' => [ + 'validation' => DataValidator::validTicketNumber(), + 'error' => ERRORS::INVALID_TICKET + ], + 'csrf_token' => [ + 'validation' => DataValidator::equals(Session::getInstance()->getToken()), + 'error' => ERRORS::INVALID_TOKEN + ] + ] + ]; + } + } + + public function handler() { + $user = Controller::getLoggedUser(); + $newtitle = Controller::request('title'); + $ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber')); + + if(Controller::isUserSystemEnabled() && !$user->canManageTicket($ticket)) { + throw new RequestException(ERRORS::NO_PERMISSION); + } + + $ticket->title = $newtitle; + $ticket->editedTitle = true; + $ticket->store(); + + $ticketNumber = $ticket->ticketNumber; + Log::createLog('EDIT_TITLE', $ticketNumber); + + Response::respondSuccess(); + } +} diff --git a/server/controllers/ticket/search.php b/server/controllers/ticket/search.php new file mode 100644 index 00000000..00431c34 --- /dev/null +++ b/server/controllers/ticket/search.php @@ -0,0 +1,348 @@ + 'staff_1', + 'requestData' => [ + 'page' => [ + 'validation' => DataValidator::oneOf(DataValidator::numeric()->positive(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_PAGE + ], + 'tags' => [ + 'validation' => DataValidator::oneOf(DataValidator::validTagsId(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_TAG_FILTER + ], + 'closed' => [ + 'validation' => DataValidator::oneOf(DataValidator::in(['0','1']),DataValidator::nullType()), + 'error' => ERRORS::INVALID_CLOSED_FILTER + ], + 'unreadStaff' => [ + 'validation' => DataValidator::oneOf(DataValidator::in(['0','1']),DataValidator::nullType()), + 'error' => ERRORS::INVALID_UNREAD_STAFF_FILTER + ], + 'priority' => [ + 'validation' => DataValidator::oneOf(DataValidator::validPriorities(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_PRIORITY_FILTER + ], + 'dateRange' => [ + 'validation' => DataValidator::oneOf(DataValidator::validDateRange(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_DATE_RANGE_FILTER + ], + 'departments' => [ + 'validation' => DataValidator::oneOf(DataValidator::validDepartmentsId(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_DEPARTMENT_FILTER + ], + 'authors' => [ + 'validation' => DataValidator::oneOf(DataValidator::validAuthorsId(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_AUTHOR_FILTER + ], + 'assigned' => [ + 'validation' => DataValidator::oneOf(DataValidator::in(['0','1']),DataValidator::nullType()), + 'error' => ERRORS::INVALID_ASSIGNED_FILTER + ], + 'orderBy' => [ + 'validation' => DataValidator::oneOf(DataValidator::validOrderBy(),DataValidator::nullType()), + 'error' => ERRORS::INVALID_ORDER_BY + ], + ] + ]; + } + + public function handler() { + $inputs = [ + 'closed' => Controller::request('closed'), + 'tags' => json_decode(Controller::request('tags')), + 'unreadStaff' => Controller::request('unreadStaff'), + 'priority' => json_decode(Controller::request('priority')), + 'dateRange' => json_decode(Controller::request('dateRange')), + 'departments' => json_decode(Controller::request('departments')), + 'authors' => json_decode(Controller::request('authors'),true), + 'assigned' => Controller::request('assigned'), + 'query' => Controller::request('query'), + 'orderBy' => json_decode(Controller::request('orderBy'),true), + 'page' => Controller::request('page'), + 'allowedDepartments' => Controller::getLoggedUser()->sharedDepartmentList->toArray(), + ]; + + + $query = $this->getSQLQuery($inputs); + $queryWithOrder = $this->getSQLQueryWithOrder($inputs); + $totalCount = RedBean::getAll("SELECT COUNT(*) FROM (SELECT COUNT(*) " . $query . " ) AS T2", [':query' => $inputs['query']])[0]['COUNT(*)']; + $ticketIdList = RedBean::getAll($queryWithOrder, [':query' => "%" . $inputs['query'] . "%"]); + $ticketList = []; + + foreach ($ticketIdList as $item) { + $ticket = Ticket::getDataStore($item['id']); + array_push($ticketList, $ticket->toArray()); + } + $ticketTableExists = RedBean::exec("select table_name from information_schema.tables where table_name = 'ticket';"); + + if($ticketTableExists){ + Response::respondSuccess([ + 'tickets' => $ticketList, + 'pages' => ceil($totalCount / 10), + 'page' => $inputs['page'] ? ($inputs['page']*1) : 1 + ]); + }else{ + Response::respondSuccess([]); + } + + } + + public function getSQLQuery($inputs) { + $tagsTableExists = RedBean::exec("select table_name from information_schema.tables where table_name = 'tag_ticket';"); + $ticketEventTableExists = RedBean::exec("select table_name from information_schema.tables where table_name = 'ticketevent';"); + + $taglistQuery = ( $tagsTableExists ? " LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id" : ''); + $ticketeventlistQuery = ( $ticketEventTableExists ? " LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id" : ''); + + $query = "FROM (ticket" . $taglistQuery . $ticketeventlistQuery .")"; + $filters = ""; + $this->setQueryFilters($inputs, $filters); + $query .= $filters . " GROUP BY ticket.id"; + return $query; + } + + public function getSQLQueryWithOrder($inputs) { + $query = $this->getSQLQuery($inputs); + $order = ""; + $query = "SELECT" . " ticket.id " . $query; + + $this->setQueryOrder($inputs, $order); + $inputs['page'] ? $page = $inputs['page'] : $page = 1 ; + $query .= $order ." LIMIT 10 OFFSET " . (($page-1)*10); + return $query; + } + + //FILTER + private function setQueryFilters($inputs, &$filters){ + if(array_key_exists('tags',$inputs)) $this->setTagFilter($inputs['tags'], $filters); + if(array_key_exists('closed',$inputs)) $this->setClosedFilter($inputs['closed'], $filters); + if(array_key_exists('assigned',$inputs)) $this->setAssignedFilter($inputs['assigned'], $filters); + if(array_key_exists('unreadStaff',$inputs)) $this->setSeenFilter($inputs['unreadStaff'], $filters); + if(array_key_exists('priority',$inputs)) $this->setPriorityFilter($inputs['priority'], $filters); + if(array_key_exists('dateRange',$inputs)) $this->setDateFilter($inputs['dateRange'], $filters); + if(array_key_exists('departments',$inputs)) $this->setDepartmentFilter($inputs['departments'],$inputs['allowedDepartments'], $filters); + if(array_key_exists('authors',$inputs)) $this->setAuthorFilter($inputs['authors'], $filters); + if(array_key_exists('query',$inputs)) $this->setStringFilter($inputs['query'], $filters); + if($filters != "") $filters = " WHERE " . $filters; + } + + private function setTagFilter($tagList, &$filters){ + $tagsTableExists = RedBean::exec("select table_name from information_schema.tables where table_name = 'tag_ticket';"); + + if($tagList && $tagsTableExists){ + $filters != "" ? $filters .= " and " : null; + + foreach($tagList as $key => $tag) { + + $key == 0 ? $filters .= " ( " : null; + ($key != 0 && $key != sizeof($tagList)) ? $filters .= " or " : null; + + $filters .= "tag_ticket.tag_id = " . $tag ; + } + $filters .= ")"; + } + } + public function setClosedFilter($closed, &$filters){ + if ($closed !== null) { + if ($filters != "") $filters .= " and "; + $filters .= "ticket.closed = " . $closed ; + } + } + private function setSeenFilter($unreadStaff, &$filters){ + if ($unreadStaff !== null) { + if ($filters != "") $filters .= " and "; + $filters .= "ticket.unread_staff = " . $unreadStaff; + } + } + private function setPriorityFilter($priorities, &$filters){ + if($priorities !== null){ + $first = TRUE; + if ($filters != "") $filters .= " and "; + foreach(array_unique($priorities) as $priority) { + + if($first){ + $filters .= " ( "; + $first = FALSE; + } else { + $filters .= " or "; + } + + if($priority == 0){ + $filters .= "ticket.priority = 'low'"; + }elseif($priority == 1){ + $filters .= "ticket.priority = 'medium'"; + }elseif($priority == 2){ + $filters .= "ticket.priority = 'high'"; + } + + + } + $priorities != "" ? $filters .= ") " : null; + } + + } + + private function setDateFilter($dateRange, &$filters){ + if ($dateRange !== null) { + if ($filters != "") $filters .= " and "; + + foreach($dateRange as $key => $date) { + $key == 0 ? ($filters .= "(ticket.date >= " . $date ): ($filters .= " and ticket.date <= " . $date . ")"); + } + } + } + + private function setDepartmentFilter($departments,$allowedDepartments, &$filters){ + $validDepartments = $this->generateValidDepartmentList($departments, $allowedDepartments); + if ($filters != "") $filters .= " and "; + $first = TRUE; + + foreach($validDepartments as $department) { + if($first){ + $filters .= " ( "; + $first = FALSE; + } else { + $filters .= " or "; + } + $filters .= "ticket.department_id = " . $department; + } + $filters .= ")"; + + } + + private function setAuthorFilter($authors, &$filters){ + if($authors !== null){ + $first = TRUE; + if ($filters != "") $filters .= " and "; + + foreach($authors as $author){ + + if($first){ + $filters .= " ( "; + $first = FALSE; + } else { + $filters .= " or "; + } + + if($author['staff']){ + $filters .= "ticket.author_staff_id = " . $author['id']; + } else { + $filters .= "ticket.author_id = " . $author['id']; + } + } + + $filters .= ")"; + + } + } + + private function setAssignedFilter($assigned, &$filters){ + if($assigned !== null){ + if ($filters != "") $filters .= " and "; + $key = ""; + $assigned == 0 ? $key = "IS NULL" : $key = "IS NOT NULL"; + $filters .= "ticket.owner_id " . $key; + } + } + + private function setStringFilter($search, &$filters){ + $ticketEventTableExists = RedBean::exec("select table_name from information_schema.tables where table_name = 'ticketevent';"); + + if($search !== null){ + if ($filters != "") $filters .= " and "; + $ticketevent = ( $ticketEventTableExists ? " or (ticketevent.type = 'COMMENT' and ticketevent.content LIKE :query)" : ""); + $filters .= " (ticket.title LIKE :query or ticket.content LIKE :query or ticket.ticket_number LIKE :query". $ticketevent ." )"; + }; + } + + private function generateValidDepartmentList($departments, $allowedDepartments){ + $result = []; + $managedDepartments = []; + if($departments == null) $departments = []; + foreach ($allowedDepartments as $department) { + array_push($managedDepartments,$department['id']); + } + $result = array_intersect($departments,$managedDepartments); + + if(empty($result)) $result = $managedDepartments; + + $result = array_unique($result); + + return $result; + } + + //ORDER + private function setQueryOrder($inputs, &$order){ + $order = " ORDER BY "; + if(array_key_exists('query',$inputs)) $this->setStringOrder($inputs['query'], $order); + if(array_key_exists('orderBy',$inputs)) $this->setEspecificOrder($inputs['orderBy'], $order); + $order .= "ticket.closed asc, ticket.owner_id asc, ticket.unread_staff asc, ticket.priority desc, ticket.date desc "; + } + private function setEspecificOrder($orderBy, &$order){ + if($orderBy !== null){ + $orientation = ($orderBy['asc'] ? " asc" : " desc" ); + $order .= "ticket." . $orderBy['value'] . $orientation . ","; + }; + } + private function setStringOrder($querysearch, &$order){ + $ticketEventTableExists = RedBean::exec("select table_name from information_schema.tables where table_name = 'ticketevent';"); + + if($querysearch !== null){ + $ticketeventOrder = ( $ticketEventTableExists ? " CASE WHEN (ticketevent.type = 'COMMENT' and ticketevent.content LIKE :query) THEN ticketevent.content END desc," : ""); + $order .= "CASE WHEN (ticket.ticket_number LIKE :query) THEN ticket.ticket_number END desc,CASE WHEN (ticket.title LIKE :query) THEN ticket.title END desc, CASE WHEN ( ticket.content LIKE :query) THEN ticket.content END desc," . $ticketeventOrder ; + } + } + +} diff --git a/server/controllers/user/signup.php b/server/controllers/user/signup.php index ec6736cb..12184a0b 100755 --- a/server/controllers/user/signup.php +++ b/server/controllers/user/signup.php @@ -72,7 +72,7 @@ class SignUpController extends Controller { if(!$this->csvImported) { $validations['requestData']['captcha'] = [ - 'validation' => DataValidator::captcha(), + 'validation' => DataValidator::captcha(APIKey::REGISTRATION), 'error' => ERRORS::INVALID_CAPTCHA ]; } @@ -103,6 +103,10 @@ class SignUpController extends Controller { throw new RequestException(ERRORS::NO_PERMISSION); } + if(!$apiKey->isNull() && $apiKey->type !== APIKey::REGISTRATION) { + throw new RequestException(ERRORS::INVALID_API_KEY_TYPE); + } + $userId = $this->createNewUserAndRetrieveId(); if(MailSender::getInstance()->isConnected()) { diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index 831086a9..34338349 100755 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -251,6 +251,10 @@ * @apiDefine INVALID_COLOR * @apiError {String} INVALID_COLOR The color should be in hexadecimal, preceded by a '#' */ +/** + * @apiDefine INVALID_API_KEY_TYPE + * @apiError {String} INVALID_API_KEY_TYPE Api key type is not one of the availables + */ class ERRORS { const INVALID_CREDENTIALS = 'INVALID_CREDENTIALS'; @@ -277,6 +281,15 @@ class ERRORS { const INVALID_PRIORITY = 'INVALID_PRIORITY'; const INVALID_PAGE = 'INVALID_PAGE'; const INVALID_QUERY = 'INVALID_QUERY'; + const INVALID_TAG_FILTER = 'INVALID_TAG_FILTER'; + const INVALID_CLOSED_FILTER = 'INVALID_CLOSED_FILTER'; + const INVALID_UNREAD_STAFF_FILTER = 'INVALID_UNREAD_STAFF_FILTER'; + const INVALID_PRIORITY_FILTER = 'INVALID_PRIORITY_FILTER'; + const INVALID_DATE_RANGE_FILTER = 'INVALID_DATE_RANGE_FILTER'; + const INVALID_DEPARTMENT_FILTER = 'INVALID_DEPARTMENT_FILTER'; + const INVALID_AUTHOR_FILTER = 'INVALID_AUTHOR_FILTER'; + const INVALID_ASSIGNED_FILTER = 'INVALID_ASSIGNED_FILTER'; + const INVALID_ORDER_BY = 'INVALID_ORDER_BY'; const INVALID_TOPIC = 'INVALID_TOPIC'; const INVALID_SEARCH = 'INVALID_SEARCH'; const INVALID_ORDER = 'INVALID_ORDER'; @@ -317,4 +330,5 @@ class ERRORS { const INVALID_CUSTOM_FIELD_OPTION = 'INVALID_CUSTOM_FIELD_OPTION'; const UNAVAILABLE_STATS = 'UNAVAILABLE_STATS'; const INVALID_COLOR = 'INVALID_COLOR'; + const INVALID_API_KEY_TYPE = 'INVALID_API_KEY_TYPE'; } diff --git a/server/libs/validations/captcha.php b/server/libs/validations/captcha.php index 7ac805c2..e37ca9fa 100755 --- a/server/libs/validations/captcha.php +++ b/server/libs/validations/captcha.php @@ -5,12 +5,22 @@ namespace CustomValidations; use Respect\Validation\Rules\AbstractRule; class Captcha extends AbstractRule { + private $dataStoreName; + + public function __construct($apiKeyType = '') { + if (in_array($apiKeyType, \APIKey::TYPES)) { + $this->apiKeyType = $apiKeyType; + } else if($apiKeyType) { + throw new \Exception(\ERRORS::INVALID_API_KEY_TYPE); + } + } public function validate($reCaptchaResponse) { $reCaptchaPrivateKey = \Setting::getSetting('recaptcha-private')->getValue(); $apiKey = \APIKey::getDataStore(\Controller::request('apiKey'), 'token'); - if (!$reCaptchaPrivateKey || !$apiKey->isNull()) return true; + if (!$reCaptchaPrivateKey) return true; + if (!$apiKey->isNull() && $apiKey->type === $apiKeyType) return true; $reCaptcha = new \ReCaptcha\ReCaptcha($reCaptchaPrivateKey); $reCaptchaValidation = $reCaptcha->verify($reCaptchaResponse, $_SERVER['REMOTE_ADDR']); diff --git a/server/libs/validations/validAuthorsId.php b/server/libs/validations/validAuthorsId.php new file mode 100644 index 00000000..3cda8229 --- /dev/null +++ b/server/libs/validations/validAuthorsId.php @@ -0,0 +1,23 @@ +staff){ + $author = \Staff::getDataStore($authorObject->id); + }else{ + $author = \User::getDataStore($authorObject->id); + } + if($author->isNull()) return false; + } + return true; + } + return false; + } +} \ No newline at end of file diff --git a/server/libs/validations/validDateRange.php b/server/libs/validations/validDateRange.php new file mode 100644 index 00000000..c2bb3f05 --- /dev/null +++ b/server/libs/validations/validDateRange.php @@ -0,0 +1,20 @@ +isNull()) return false; + } + return true; + } + return false; + } +} diff --git a/server/libs/validations/validOrderBy.php b/server/libs/validations/validOrderBy.php new file mode 100644 index 00000000..40babc27 --- /dev/null +++ b/server/libs/validations/validOrderBy.php @@ -0,0 +1,19 @@ +asc !== 1 && $object->asc !== 0) || !in_array($object->value, $values)) return false; + + return true; + } + } +} diff --git a/server/libs/validations/validPriorities.php b/server/libs/validations/validPriorities.php new file mode 100644 index 00000000..aa3ba658 --- /dev/null +++ b/server/libs/validations/validPriorities.php @@ -0,0 +1,19 @@ +isNull()) return false; + } + return true; + } + return false; + } +} \ No newline at end of file diff --git a/server/models/APIKey.php b/server/models/APIKey.php index 436b2b14..9cb1c4ff 100755 --- a/server/models/APIKey.php +++ b/server/models/APIKey.php @@ -9,18 +9,29 @@ class APIKey extends DataStore { const TABLE = 'apikey'; + const REGISTRATION = 'REGISTRATION'; + const TICKET_CREATE = 'TICKET_CREATE'; + const TYPES = [APIKey::REGISTRATION, APIKey::TICKET_CREATE]; public static function getProps() { return [ 'name', - 'token' + 'token', + 'type' + ]; + } + + public function getDefaultProps() { + return [ + 'type' => APIKey::REGISTRATION ]; } public function toArray() { return [ 'name' => $this->name, - 'token' => $this->token + 'token' => $this->token, + 'type' => $this->type ]; } } \ No newline at end of file diff --git a/server/models/Ticket.php b/server/models/Ticket.php index 5ad71589..991487fc 100755 --- a/server/models/Ticket.php +++ b/server/models/Ticket.php @@ -51,7 +51,8 @@ class Ticket extends DataStore { 'authorEmail', 'authorName', 'sharedTagList', - 'editedContent' + 'editedContent', + 'editedTitle' ); } @@ -132,7 +133,8 @@ class Ticket extends DataStore { 'owner' => $this->ownerToArray(), 'events' => $minimized ? [] : $this->eventsToArray(), 'tags' => $this->sharedTagList->toArray(true), - 'edited' => $this->editedContent + 'edited' => $this->editedContent, + 'editedTitle' => $this->editedTitle ]; } diff --git a/server/tests/__mocks__/APIKeyMock.php b/server/tests/__mocks__/APIKeyMock.php index 7ef32d77..70f5d0d8 100755 --- a/server/tests/__mocks__/APIKeyMock.php +++ b/server/tests/__mocks__/APIKeyMock.php @@ -2,6 +2,10 @@ include_once 'tests/__mocks__/NullDataStoreMock.php'; class APIKey extends \Mock { + const REGISTRATION = 'REGISTRATION'; + const TICKET_CREATE = 'TICKET_CREATE'; + const TYPES = [APIKey::REGISTRATION, APIKey::TICKET_CREATE]; + public static $functionList = array(); public static function initStubs() { diff --git a/server/tests/__mocks__/ControllerMock.php b/server/tests/__mocks__/ControllerMock.php index 7a4e8149..fa24452a 100755 --- a/server/tests/__mocks__/ControllerMock.php +++ b/server/tests/__mocks__/ControllerMock.php @@ -1,13 +1,19 @@ \Mock::stub()->returns(1) + ]); + Controller::$requestReturnMock = null; + $_SERVER['REMOTE_ADDR'] = 'MOCK_REMOTE'; + $this->searchController = new SearchController(); + } + + public function testTagsFilter() { + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'tags' => [] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'tags' => [0] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ( tag_ticket.tag_id = 0) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'tags' => [0,1,2] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ( tag_ticket.tag_id = 0 or tag_ticket.tag_id = 1 or tag_ticket.tag_id = 2) GROUP BY ticket.id' + ); + } + + public function testClosedFilter() { + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'closed'=> null + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id' + ); + + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'closed'=> 1 + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ticket.closed = 1 GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'closed'=> '0' + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ticket.closed = 0 GROUP BY ticket.id' + ); + } + public function testAssignedFilter(){ + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'assigned'=> null + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'assigned'=> '0' + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ticket.owner_id IS NULL GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'assigned'=> 1 + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ticket.owner_id IS NOT NULL GROUP BY ticket.id' + ); + } + public function testUnreadStaffFilter() { + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'unreadStaff' => null + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'unreadStaff' => '0' + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ticket.unread_staff = 0 GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'unreadStaff' => 1 + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ticket.unread_staff = 1 GROUP BY ticket.id' + ); + } + + public function testPriorityFilter() { + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'tags' => [] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'tags' => [1] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ( tag_ticket.tag_id = 1) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'tags' => [2,3] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ( tag_ticket.tag_id = 2 or tag_ticket.tag_id = 3) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'tags' => [1,2,3] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ( tag_ticket.tag_id = 1 or tag_ticket.tag_id = 2 or tag_ticket.tag_id = 3) GROUP BY ticket.id' + ); + } + + public function testdateRangeFilter() { + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'dateRange' => null + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'dateRange' => [1,2] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE (ticket.date >= 1 and ticket.date <= 2) GROUP BY ticket.id' + ); + } + + public function testDepartmentsFilter() { + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'departments' => null, + 'allowedDepartments' => [ + [ + 'id' => 2 + ], + [ + 'id' => 1 + ], + [ + 'id' => 3 + ] + ] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ( ticket.department_id = 2 or ticket.department_id = 1 or ticket.department_id = 3) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'departments' => [1], + 'allowedDepartments' => [ + [ + 'id' => 2 + ], + [ + 'id' => 1 + ], + [ + 'id' => 3 + ] + ] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ( ticket.department_id = 1) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'departments' => [1,2,3], + 'allowedDepartments' => [ + [ + 'id' => 2 + ], + [ + 'id' => 1 + ], + [ + 'id' => 3 + ] + ] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ( ticket.department_id = 1 or ticket.department_id = 2 or ticket.department_id = 3) GROUP BY ticket.id' + ); + } + + public function testAuthorsFilter() { + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'authors' => null + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id' + ); + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'authors' => [ + [ + 'id' => 1, + 'staff' => 1 + ], + [ + 'id' => 2, + 'staff' => 0 + ] + ] + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE ( ticket.author_staff_id = 1 or ticket.author_id = 2) GROUP BY ticket.id' + ); + } + + public function testQueryFilter() { + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'query' => null + ]), + 'FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id' + ); + + $this->assertEquals( + $this->searchController->getSQLQuery([ + 'query' => 'hello world' + ]), + "FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE (ticket.title LIKE :query or ticket.content LIKE :query or ticket.ticket_number LIKE :query or (ticketevent.type = 'COMMENT' and ticketevent.content LIKE :query) ) GROUP BY ticket.id" + + ); + } + public function testQueryWithOrder() { + $this->assertEquals( + $this->searchController->getSQLQueryWithOrder([ + 'page' => 1 + ]), + "SELECT ticket.id FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id ORDER BY ticket.closed asc, ticket.owner_id asc, ticket.unread_staff asc, ticket.priority desc, ticket.date desc LIMIT 10 OFFSET 0" + ); + + $this->assertEquals( + $this->searchController->getSQLQueryWithOrder([ + 'page' => 1, + 'query' => 'stark' + ]), + "SELECT ticket.id FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) WHERE (ticket.title LIKE :query or ticket.content LIKE :query or ticket.ticket_number LIKE :query or (ticketevent.type = 'COMMENT' and ticketevent.content LIKE :query) ) GROUP BY ticket.id ORDER BY CASE WHEN (ticket.ticket_number LIKE :query) THEN ticket.ticket_number END desc,CASE WHEN (ticket.title LIKE :query) THEN ticket.title END desc, CASE WHEN ( ticket.content LIKE :query) THEN ticket.content END desc, CASE WHEN (ticketevent.type = 'COMMENT' and ticketevent.content LIKE :query) THEN ticketevent.content END desc,ticket.closed asc, ticket.owner_id asc, ticket.unread_staff asc, ticket.priority desc, ticket.date desc LIMIT 10 OFFSET 0" + ); + + $this->assertEquals( + $this->searchController->getSQLQueryWithOrder([ + 'page' => 1, + 'orderBy' => ['value' => 'closed', 'asc' => 1] + ]), + "SELECT ticket.id FROM (ticket LEFT JOIN tag_ticket ON tag_ticket.ticket_id = ticket.id LEFT JOIN ticketevent ON ticketevent.ticket_id = ticket.id) GROUP BY ticket.id ORDER BY ticket.closed asc,ticket.closed asc, ticket.owner_id asc, ticket.unread_staff asc, ticket.priority desc, ticket.date desc LIMIT 10 OFFSET 0" + ); + } +} diff --git a/server/tests/controllers/user/loginTest.php b/server/tests/controllers/user/loginTest.php index 035aaa70..d9615ff3 100755 --- a/server/tests/controllers/user/loginTest.php +++ b/server/tests/controllers/user/loginTest.php @@ -35,9 +35,9 @@ class LoginControllerTest extends TestCase { public function testShouldCreateSessionAndRespondSuccessIfCredentialsAreValid() { Session::mockInstanceFunction('sessionExists', \Mock::stub()->returns(false)); + Controller::useValueReturn(); $this->loginController->handler(); - $this->assertTrue(!!Session::getInstance()->createSession->hasBeenCalledWithArgs('MOCK_ID', false)); $this->assertTrue(Response::get('respondSuccess')->hasBeenCalledWithArgs(array( 'userId' => 'MOCK_ID', diff --git a/tests/init.rb b/tests/init.rb index ffffdcb7..c4291800 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -56,11 +56,11 @@ require './system/edit-department.rb' require './system/delete-department.rb' require './staff/last-events.rb' # require './system/mail-templates.rb' -require './system/disable-registration.rb' -require './system/enable-registration.rb' require './system/add-api-key.rb' require './system/delete-api-key.rb' require './system/get-api-keys.rb' +require './system/disable-registration.rb' +require './system/enable-registration.rb' require './system/file-upload-download.rb' require './system/csv-import.rb' require './ticket/create-tag.rb' @@ -70,5 +70,7 @@ require './ticket/delete-tag.rb' require './ticket/add-tag.rb' require './ticket/delete-tag.rb' require './ticket/edit-comment.rb' +require './ticket/edit-title.rb' require './system/disable-user-system.rb' +require './ticket/search.rb' # require './system/get-stats.rb' diff --git a/tests/scripts.rb b/tests/scripts.rb index e0c7e24c..2e7a7715 100644 --- a/tests/scripts.rb +++ b/tests/scripts.rb @@ -97,11 +97,12 @@ class Scripts result['data'] end - def self.createAPIKey(name) + def self.createAPIKey(name, type) request('/system/add-api-key', { csrf_userid: $csrf_userid, csrf_token: $csrf_token, - name: name + name: name, + type: type }) end diff --git a/tests/staff/get-all.rb b/tests/staff/get-all.rb index dec7fdc5..f8571c71 100644 --- a/tests/staff/get-all.rb +++ b/tests/staff/get-all.rb @@ -10,14 +10,18 @@ describe'/staff/get-all' do (result['status']).should.equal('success') + result['data'][0]['departments'] = result['data'][0]['departments'].sort_by do |department| + department['id'].to_i + end + (result['data'][0]['name']).should.equal('Emilia Clarke') (result['data'][0]['email']).should.equal('staff@opensupports.com') (result['data'][0]['profilePic']).should.equal('') (result['data'][0]['level']).should.equal('3') - (result['data'][0]['departments'][0]['id']).should.equal('2') - (result['data'][0]['departments'][0]['name']).should.equal('useless private deapartment') - (result['data'][0]['departments'][1]['id']).should.equal('1') - (result['data'][0]['departments'][1]['name']).should.equal('Help and Support') + (result['data'][0]['departments'][0]['id']).should.equal('1') + (result['data'][0]['departments'][0]['name']).should.equal('Help and Support') + (result['data'][0]['departments'][1]['id']).should.equal('2') + (result['data'][0]['departments'][1]['name']).should.equal('useless private deapartment') (result['data'][0]['departments'][2]['id']).should.equal('3') (result['data'][0]['departments'][2]['name']).should.equal('Suggestions') (result['data'][0]['assignedTickets']).should.equal(10) diff --git a/tests/system/add-api-key.rb b/tests/system/add-api-key.rb index cf8c86d5..ecf2f431 100644 --- a/tests/system/add-api-key.rb +++ b/tests/system/add-api-key.rb @@ -1,30 +1,44 @@ describe'system/add-api-key' do - request('/user/logout') - Scripts.login($staff[:email], $staff[:password], true) + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) - it 'should add API key' do - result= request('/system/add-api-key', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - name: 'new API' - }) + it 'should add API key' do + result= request('/system/add-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new API', + type: 'REGISTRATION' + }) - (result['status']).should.equal('success') + (result['status']).should.equal('success') - row = $database.getRow('apikey', 1, 'id') + row = $database.getRow('apikey', 1, 'id') - (row['name']).should.equal('new API') - (result['data']).should.equal(row['token']) + (row['name']).should.equal('new API') + (result['data']).should.equal(row['token']) + end - end - it 'should not add API key' do - result= request('/system/add-api-key', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - name: 'new API' - }) + it 'should not add API key if name already used' do + result= request('/system/add-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new API', + type: 'REGISTRATION' + }) - (result['status']).should.equal('fail') - (result['message']).should.equal('NAME_ALREADY_USED') - end + (result['status']).should.equal('fail') + (result['message']).should.equal('NAME_ALREADY_USED') + end + + it 'should not add API key if invalid type is used' do + result= request('/system/add-api-key', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + name: 'new API2', + type: 'REGISTRATON' + }) + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_API_KEY_TYPE') + end end diff --git a/tests/system/disable-registration.rb b/tests/system/disable-registration.rb index 13e4c06c..539a29dc 100644 --- a/tests/system/disable-registration.rb +++ b/tests/system/disable-registration.rb @@ -1,6 +1,7 @@ describe'/system/disable-registration' do request('/user/logout') Scripts.login($staff[:email], $staff[:password], true) + api_key = Scripts.createAPIKey('registrationKey', 'REGISTRATION')['data'] it 'should not disable registration if password is not correct' do result= request('/system/disable-registration', { @@ -17,7 +18,7 @@ describe'/system/disable-registration' do end it 'should disable registration' do - result= request('/system/disable-registration', { + result = request('/system/disable-registration', { csrf_userid: $csrf_userid, csrf_token: $csrf_token, password: $staff[:password] @@ -31,13 +32,23 @@ describe'/system/disable-registration' do end it 'should not create user in database if registration is false' do - response = request('/user/signup', { + result = request('/user/signup', { :name => 'ponzio', :email => 'jc@ponziolandia.com', :password => 'tequila' }) - (response['status']).should.equal('fail') + (result['status']).should.equal('fail') + (result['message']).should.equal('NO_PERMISSION') + end + it 'should create user if using api key' do + result = request('/user/signup', { + :name => 'ponzio', + :email => 'jc@ponziolandia.com', + :password => 'tequila', + :apiKey => api_key + }) + (result['status']).should.equal('success') end end diff --git a/tests/system/disable-user-system.rb b/tests/system/disable-user-system.rb index 9ae8dd15..9550c0df 100644 --- a/tests/system/disable-user-system.rb +++ b/tests/system/disable-user-system.rb @@ -17,9 +17,9 @@ describe'system/disable-user-system' do row = $database.getRow('user', 1, 'id') (row).should.equal(nil) - numberOftickets= $database.query("SELECT * FROM ticket WHERE author_id IS NULL AND author_email IS NOT NULL AND author_name IS NOT NULL") + numberOftickets = $database.query("SELECT * FROM ticket WHERE author_id IS NULL AND author_email IS NOT NULL AND author_name IS NOT NULL") - (numberOftickets.num_rows).should.equal(51) + (numberOftickets.num_rows).should.equal(52) request('/user/logout') @@ -122,7 +122,7 @@ describe'system/disable-user-system' do (result['status']).should.equal('success') (result['data'].size).should.equal(10) end - + it 'should be able to get system logs as admin' do result = request('/system/get-logs', { page: 1, @@ -148,6 +148,21 @@ describe'system/disable-user-system' do (ticket['author_staff_id']).should.equal('1') end + it 'should be able to create a ticket using api' do + api_key = Scripts.createAPIKey('ticketCreateKey', 'TICKET_CREATE')['data'] + request('/user/logout') + result = request('/ticket/create', { + email: 'fromapi@testemail.com', + name: 'Random user', + title: 'created by api', + content: 'this ticket was created using anapi key while user system is disabled', + departmentId: 1, + language: 'en', + apiKey: api_key + }) + (result['status']).should.equal('success') + end + it 'should not disable the user system if it is already disabled 'do request('/user/logout') Scripts.login($staff[:email], $staff[:password], true) @@ -205,7 +220,7 @@ describe'system/disable-user-system' do numberOftickets= $database.query("SELECT * FROM ticket WHERE author_email IS NULL AND author_name IS NULL AND author_id IS NOT NULL" ) - (numberOftickets.num_rows).should.equal(53) + (numberOftickets.num_rows).should.equal(55) end it 'should not enable the user system' do diff --git a/tests/system/get-api-keys.rb b/tests/system/get-api-keys.rb index 518dc818..e6c62900 100644 --- a/tests/system/get-api-keys.rb +++ b/tests/system/get-api-keys.rb @@ -1,26 +1,25 @@ describe'system/get-api-keys' do - request('/user/logout') - Scripts.login($staff[:email], $staff[:password], true) + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) - it 'should get all API keys' do - Scripts.createAPIKey('namekey1') - Scripts.createAPIKey('namekey2') - Scripts.createAPIKey('namekey3') - Scripts.createAPIKey('namekey4') - Scripts.createAPIKey('namekey5') - - result = request('/system/get-api-keys', { - csrf_userid: $csrf_userid, - csrf_token: $csrf_token, - }) + it 'should get all API keys' do + Scripts.createAPIKey('namekey1', 'REGISTRATION') + Scripts.createAPIKey('namekey2', 'REGISTRATION') + Scripts.createAPIKey('namekey3', 'REGISTRATION') + Scripts.createAPIKey('namekey4', 'REGISTRATION') + Scripts.createAPIKey('namekey5', 'REGISTRATION') + + result = request('/system/get-api-keys', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + }) - (result['status']).should.equal('success') - (result['data'][0]['name']).should.equal('namekey1') - (result['data'][1]['name']).should.equal('namekey2') - (result['data'][2]['name']).should.equal('namekey3') - (result['data'][3]['name']).should.equal('namekey4') - (result['data'][4]['name']).should.equal('namekey5') - - end + (result['status']).should.equal('success') + (result['data'][0]['name']).should.equal('namekey1') + (result['data'][1]['name']).should.equal('namekey2') + (result['data'][2]['name']).should.equal('namekey3') + (result['data'][3]['name']).should.equal('namekey4') + (result['data'][4]['name']).should.equal('namekey5') + end end diff --git a/tests/system/get-settings.rb b/tests/system/get-settings.rb index 383d1207..84ac35bd 100644 --- a/tests/system/get-settings.rb +++ b/tests/system/get-settings.rb @@ -1,7 +1,7 @@ describe '/system/get-settings' do it 'should return correct values' do result = request('/system/get-settings') - + (result['status']).should.equal('success') (result['data']['language']).should.equal('en') (result['data']['departments'][0]['name']).should.equal('Help and Support') diff --git a/tests/ticket/edit-comment.rb b/tests/ticket/edit-comment.rb index 89b8d662..ae1093b9 100644 --- a/tests/ticket/edit-comment.rb +++ b/tests/ticket/edit-comment.rb @@ -15,7 +15,7 @@ describe '/ticket/edit-comment' do }) ticket = $database.getRow('ticket', 'ticket made by an user', 'title') - + (result['status']).should.equal('success') (ticket['content']).should.equal('content edited by the user') end diff --git a/tests/ticket/edit-title.rb b/tests/ticket/edit-title.rb new file mode 100644 index 00000000..2f1a3242 --- /dev/null +++ b/tests/ticket/edit-title.rb @@ -0,0 +1,76 @@ +describe '/ticket/edit-title' do + + request('/user/logout') + Scripts.login(); + Scripts.createTicket('Valar Morghulis','content of the ticket made by an user') + ticket = $database.getRow('ticket', 'Valar Morghulis', 'title') + ticketNumber = ticket['ticket_number'] + + it 'should fail change title of the ticket if the title is invalid' do + result = request('/ticket/edit-title', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + title: '', + ticketNumber: ticket['ticket_number'] + }) + + ticket = $database.getRow('ticket', ticketNumber, 'ticket_number') + + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_TITLE') + end + + it 'should change title of the ticket if the author user tries it' do + result = request('/ticket/edit-title', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + title: 'Valar dohaeris', + ticketNumber: ticket['ticket_number'] + }) + + ticket = $database.getRow('ticket', ticketNumber, 'ticket_number') + + (result['status']).should.equal('success') + (ticket['title']).should.equal('Valar dohaeris') + (ticket['edited_title']).should.equal('1') + end + + it 'should change the title of the ticket if staff is logged' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + result = request('/ticket/edit-title', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + title: 'Valar dohaeris by Staff', + ticketNumber: ticket['ticket_number'] + }) + + ticket = $database.getRow('ticket', ticketNumber, 'ticket_number') + + (result['status']).should.equal('success') + (ticket['title']).should.equal('Valar dohaeris by Staff') + (ticket['edited_title']).should.equal('1') + + end + + it 'should not change the title if the user is not the author' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + Scripts.createTicket('Winterfell') + ticket = $database.getRow('ticket', 'Winterfell', 'title') + + request('/user/logout') + Scripts.login() + + result = request('/ticket/edit-title', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + title: 'Casterly Rock', + ticketNumber: ticket['ticket_number'] + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('NO_PERMISSION') + end + +end diff --git a/tests/ticket/search.rb b/tests/ticket/search.rb new file mode 100644 index 00000000..2ae320d6 --- /dev/null +++ b/tests/ticket/search.rb @@ -0,0 +1,145 @@ +describe '/ticket/search' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + + it 'should fail if the page is invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: -1 + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_PAGE') + end + + it 'should fail if the tags are invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + tags: "[1,11,111,1111,11111,111111,1111111,11111111]" + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_TAG_FILTER') + end + + it 'should fail if the closed value is invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + closed: 3 + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_CLOSED_FILTER') + end + + it 'should fail if the unreadStaff value is invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + unreadStaff: 3 + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_UNREAD_STAFF_FILTER') + end + + it 'should fail if the priority values are invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + priority: "[0,1,5,6]" + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_PRIORITY_FILTER') + end + + it 'should fail if the priority' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + priority: "[0,1,),hi]" + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_PRIORITY_FILTER') + end + + it 'should fail if the dateRange values are invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + dateRange: "[11,69,()) ]" + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_DATE_RANGE_FILTER') + end + + it 'should fail if the departments are invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + departments: "[-1,-2,99]" + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_DEPARTMENT_FILTER') + end + + it 'should fail if the authors are invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + authors: "[{id:30001, staff: 1},{id:30,staff: 3}]" + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_AUTHOR_FILTER') + + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + authors: "[{id:'delete all)', staff: 1},{id:30,staff: 3}]" + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_AUTHOR_FILTER') + end + + it 'should fail if the assigned value is invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + assigned: 3 + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_ASSIGNED_FILTER') + end + + it 'should fail if the assigned value is invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + assigned: 11113 + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_ASSIGNED_FILTER') + end + + it 'should fail if the orderBy values are invalid' do + result = request('/ticket/search', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token, + page: 1, + orderBy: "{value: 'closeddd', asc: 11}" + }) + (result['status']).should.equal('fail') + (result['message']).should.equal('INVALID_ORDER_BY') + end +end