diff --git a/client/src/core-components/tooltip.scss b/client/src/core-components/tooltip.scss
index 857a917d..b9b4390b 100644
--- a/client/src/core-components/tooltip.scss
+++ b/client/src/core-components/tooltip.scss
@@ -8,12 +8,15 @@
cursor: default;
}
+ &__animated-container {
+ position: relative;
+ }
+
&__message {
position: absolute;
bottom: 100%;
- left: -25%;
margin-bottom: 15px;
- margin-left: -10px;
+ margin-left: -15px;
border: 0 solid rgba(0, 0, 0, 0.247059);
box-shadow: rgba(0, 0, 0, 0.247059) 0 -1px 4px;
border-radius: 4px;
diff --git a/client/src/data/fixtures/staff-fixtures.js b/client/src/data/fixtures/staff-fixtures.js
index dd6cae10..0de75e1f 100644
--- a/client/src/data/fixtures/staff-fixtures.js
+++ b/client/src/data/fixtures/staff-fixtures.js
@@ -1047,5 +1047,15 @@ module.exports = [
data: {}
};
}
+ },
+ {
+ path: '/staff/delete',
+ time: 100,
+ response: function () {
+ return {
+ status: 'success',
+ data: {}
+ };
+ }
}
];
diff --git a/client/src/data/fixtures/user-fixtures.js b/client/src/data/fixtures/user-fixtures.js
index d611956b..bf795b56 100644
--- a/client/src/data/fixtures/user-fixtures.js
+++ b/client/src/data/fixtures/user-fixtures.js
@@ -147,7 +147,7 @@ module.exports = [
email: 'kurt@currycurrylady.hs',
tickets: _.times(13).map(() => {
return {
- ticketNumber: '1185510000',
+ ticketNumber: '118551',
title: 'Lorem ipsum door',
content: 'I had a problem with the installation of the php server',
department: {
@@ -368,7 +368,7 @@ module.exports = [
{
ticketNumber: '445441',
title: 'Problem with installation',
- content: 'I had a problem with the installation of the php server',
+ content: 'In varius, tellus ut luctus vestibulum, orci erat commodo ligula, sit amet bibendum arcu libero sed magna. Suspendisse in ligula vitae ante placerat varius id in eros. Etiam commodo viverra nisi in ornare. Donec ullamcorper felis sapien, eu laoreet dolor tincidunt nec. Aliquam erat volutpat. Proin semper viverra purus eget facilisis. Proin fermentum et odio in elementum. Maecenas lacinia, massa consectetur gravida lacinia, nisl lectus tincidunt diam, ut viverra ipsum ex sit amet diam. Mauris ac massa turpis. Fusce ultrices venenatis vestibulum. In et nulla purus. Nullam porta vestibulum leo in dignissim. Duis id ullamcorper odio. Ut purus nulla, consequat lobortis volutpat quis, consequat et libero. Maecenas sit amet libero laoreet, dictum sapien at, hendrerit sapien.',
department: {
id: 2,
name: 'Technical Issues'
@@ -502,9 +502,7 @@ module.exports = [
name: 'Haskell Curry',
email: 'haskell@lambda.com'
},
- owner: {
- name: 'Steve Jobs'
- },
+ owner: null,
events: [
{
type: 'ASSIGN',
@@ -516,17 +514,6 @@ module.exports = [
staff: true
}
},
- {
- type: 'COMMENT',
- date: '201504090912',
- content: 'Do you have apache installed? It generally happens if you dont have apache.',
- author: {
- name: 'Emilia Clarke',
- email: 'jobs@steve.com',
- profilePic: 'http://www.opensupports.com/profilepic.jpg',
- staff: true
- }
- },
{
type: 'UN_ASSIGN',
date: '201504100924',
diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js
index 456ef833..b1472eee 100644
--- a/client/src/data/languages/en.js
+++ b/client/src/data/languages/en.js
@@ -30,6 +30,7 @@ export default {
'STAFF': 'Staff',
'CUSTOMER': 'Customer',
'YES': 'Yes',
+ 'NO': 'No',
'CANCEL': 'Cancel',
'MY_ACCOUNT': 'My Account',
'DASHBOARD': 'Dashboard',
@@ -114,6 +115,8 @@ export default {
'ADD_DEPARTMENT': 'Add department',
'UPDATE_DEPARTMENT': 'Update department',
'TRANSFER_TICKETS_TO': 'Transfer tickets to',
+ 'COMMENTS': 'Comments',
+ 'DELETE_STAFF_MEMBER': 'Delete staff member',
'MAINTENANCE_MODE': 'Maintenance mode',
//VIEW DESCRIPTIONS
@@ -137,6 +140,7 @@ export default {
'ADD_ARTICLE_DESCRIPTION': 'Here you can add an article that will be available for every user. It will be added inside the category {category}.',
'LIST_ARTICLES_DESCRIPTION': 'This is a list of articles that includes information about our services.',
'ADD_TOPIC_DESCRIPTION': 'Here you can add a topic that works as a category for articles.',
+ 'DELETE_ARTICLE_DESCRIPTION': 'You\'re going to delete this article for ever.',
'STAFF_MEMBERS_DESCRIPTION': 'Here you can see who are your staff members.',
'ADD_STAFF_DESCRIPTION': 'Here you can add staff members to your teams.',
'EDIT_STAFF_DESCRIPTION': 'Here you can edit information about a staff member.',
@@ -156,8 +160,14 @@ export default {
'PASSWORD_NOT_MATCH': 'Password does not match',
'INVALID_RECOVER': 'Invalid recover data',
'TICKET_SENT_ERROR': 'An error occurred while trying to create the ticket.',
+ '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',
+ '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.',
+ 'ERROR_BANNING_EMAIL': 'An error occurred while trying to ban the email.',
+ 'ERROR_RETRIEVING_ARTICLES': 'An error occurred while trying to retrieve articles.',
//MESSAGES
'SIGNUP_SUCCESS': 'You have registered successfully in our support system.',
@@ -171,5 +181,10 @@ export default {
'WILL_LOSE_CHANGES': 'You haven\'t save. Your changes will be lost.',
'WILL_DELETE_CUSTOM_RESPONSE': 'The custom response will be deleted.',
'WILL_DELETE_DEPARTMENT': 'The department will be deleted. All the tickets will be transfer to the department selected.',
- 'NO_STAFF_ASSIGNED': 'No staff member is assigned to this department.'
+ 'NO_STAFF_ASSIGNED': 'No staff member is assigned to this department.',
+ 'LEVEL_UPDATED': 'Level has been updated successfully.',
+ 'DEPARTMENTS_UPDATED': 'Departments have been updated successfully.',
+ 'FAILED_EDIT_STAFF': 'An error occurred while trying to edit staff member.',
+ 'EMAIL_BANNED_SUCCESSFULLY': 'Email has been banned successfully',
+ 'WILL_DELETE_STAFF': 'This staff member will be deleted and all its tickets will be unassigned.'
};
diff --git a/client/src/reducers/admin-data-reducer.js b/client/src/reducers/admin-data-reducer.js
index d3d753dc..30fc80f2 100644
--- a/client/src/reducers/admin-data-reducer.js
+++ b/client/src/reducers/admin-data-reducer.js
@@ -11,10 +11,15 @@ class AdminDataReducer extends Reducer {
customResponsesLoaded: false,
myTickets: [],
myTicketsLoaded: false,
+ myTicketsError: false,
+
newTickets: [],
newTicketsLoaded: false,
+ newTicketsError: false,
+
allTickets: [],
- allTicketsLoaded: false
+ allTicketsLoaded: false,
+ allTicketsError: false
};
}
@@ -22,11 +27,17 @@ class AdminDataReducer extends Reducer {
return {
'CUSTOM_RESPONSES_FULFILLED': this.onCustomResponses,
'SESSION_CHECKED': this.onSessionChecked,
+
'MY_TICKETS_FULFILLED': this.onMyTicketsRetrieved,
+ 'MY_TICKETS_REJECTED': this.onMyTicketsRejected,
'MY_TICKETS_PENDING': this.onMyTicketsPending,
+
'NEW_TICKETS_FULFILLED': this.onNewTicketsRetrieved,
+ 'NEW_TICKETS_REJECTED': this.onNewTicketsRejected,
'NEW_TICKETS_PENDING': this.onNewTicketsPending,
+
'ALL_TICKETS_FULFILLED': this.onAllTicketsRetrieved,
+ 'ALL_TICKETS_REJECTED': this.onAllTicketsRejected,
'ALL_TICKETS_PENDING': this.onAllTicketsPending
};
}
@@ -53,26 +64,42 @@ class AdminDataReducer extends Reducer {
return _.extend({}, state, {
myTickets: payload.data,
myTicketsLoaded: true
+ });
+ }
+
+ onMyTicketsRejected(state) {
+ return _.extend({}, state, {
+ myTicketsError: true,
+ myTicketsLoaded: true
})
}
onMyTicketsPending(state) {
return _.extend({}, state, {
+ myTicketsError: false,
myTicketsLoaded: false
- })
+ });
}
onNewTicketsRetrieved(state, payload) {
return _.extend({}, state, {
newTickets: payload.data,
newTicketsLoaded: true
- })
+ });
+ }
+
+ onNewTicketsRejected(state) {
+ return _.extend({}, state, {
+ newTicketsError: true,
+ newTicketsLoaded: false
+ });
}
onNewTicketsPending(state) {
return _.extend({}, state, {
+ newTicketsError: false,
newTicketsLoaded: false
- })
+ });
}
onAllTicketsRetrieved(state, payload) {
@@ -80,13 +107,21 @@ class AdminDataReducer extends Reducer {
allTickets: payload.data.tickets,
allTicketsPages: payload.data.pages,
allTicketsLoaded: true
- })
+ });
+ }
+
+ onAllTicketsRejected(state) {
+ return _.extend({}, state, {
+ allTicketsError: false,
+ allTicketsLoaded: false
+ });
}
onAllTicketsPending(state) {
return _.extend({}, state, {
+ allTicketsError: false,
allTicketsLoaded: false
- })
+ });
}
}
diff --git a/client/src/reducers/articles-reducer.js b/client/src/reducers/articles-reducer.js
index fcc5a537..5bdf9ace 100644
--- a/client/src/reducers/articles-reducer.js
+++ b/client/src/reducers/articles-reducer.js
@@ -9,6 +9,7 @@ class ArticlesReducer extends Reducer {
return {
retrieved: false,
loading: true,
+ errored: false,
topics: []
};
}
@@ -16,6 +17,7 @@ class ArticlesReducer extends Reducer {
getTypeHandlers() {
return {
'GET_ARTICLES_FULFILLED': this.onArticlesRetrieved,
+ 'GET_ARTICLES_REJECTED': this.onArticlesRejected,
'INIT_ARTICLES': this.onInitArticles
};
}
@@ -26,10 +28,19 @@ class ArticlesReducer extends Reducer {
return _.extend({}, state, {
retrieved: true,
loading: false,
+ errored: false,
topics: payload.data
});
}
+ onArticlesRejected(state) {
+ return _.extend({}, state, {
+ retrieved: true,
+ loading: false,
+ errored: true
+ });
+ }
+
onInitArticles(state) {
let topics = SessionStore.getItem('topics');
diff --git a/server/composer.json b/server/composer.json
index cd6c91e4..71e09ba2 100644
--- a/server/composer.json
+++ b/server/composer.json
@@ -1,10 +1,10 @@
{
"require": {
"slim/slim": "~2.0",
- "gabordemooij/redbean": "~4.2",
"respect/validation": "^1.1",
"phpmailer/phpmailer": "^5.2",
- "google/recaptcha": "~1.1"
+ "google/recaptcha": "~1.1",
+ "gabordemooij/redbean": "^4.3"
},
"require-dev": {
"phpunit/phpunit": "5.0.*"
diff --git a/server/controllers/staff/delete.php b/server/controllers/staff/delete.php
index cde02d0e..55ef0760 100644
--- a/server/controllers/staff/delete.php
+++ b/server/controllers/staff/delete.php
@@ -21,6 +21,11 @@ class DeleteStaffController extends Controller {
$staffId = Controller::request('staffId');
$staff = Staff::getDataStore($staffId);
+ if($staffId === Controller::getLoggedUser()->id) {
+ Response::respondError(ERRORS::INVALID_STAFF);
+ return;
+ }
+
foreach($staff->sharedTicketList as $ticket) {
$ticket->owner = null;
$ticket->true = true;
@@ -31,7 +36,6 @@ class DeleteStaffController extends Controller {
$department->owners--;
$department->store();
}
-
$staff->delete();
Response::respondSuccess();
diff --git a/server/controllers/staff/edit.php b/server/controllers/staff/edit.php
index f18c3f31..fef5f0fc 100644
--- a/server/controllers/staff/edit.php
+++ b/server/controllers/staff/edit.php
@@ -4,8 +4,7 @@ use Respect\Validation\Validator as DataValidator;
class EditStaffController extends Controller {
const PATH = '/edit';
- private $staffRow;
- private $staffId;
+ private $staffInstance;
public function validations() {
return [
@@ -15,14 +14,14 @@ class EditStaffController extends Controller {
}
public function handler() {
- $this->staffId = Controller::request('staffId');
+ $staffId = Controller::request('staffId');
- if(!$this->staffId) {
- $this->staffRow = Controller::getLoggedUser();
+ if(!$staffId) {
+ $this->staffInstance = Controller::getLoggedUser();
} else if(Controller::isStaffLogged(3)) {
- $this->staffRow = Staff::getDataStore($this->staffId, 'id');
+ $this->staffInstance = Staff::getDataStore($staffId, 'id');
- if($this->staffRow->isNull()) {
+ if($this->staffInstance->isNull()) {
Response::respondError(ERRORS::INVALID_STAFF);
return;
}
@@ -39,29 +38,29 @@ class EditStaffController extends Controller {
Response::respondSuccess();
}
- public function editInformation() {
+ private function editInformation() {
if(Controller::request('email')) {
- $this->staffRow->email = Controller::request('email');
+ $this->staffInstance->email = Controller::request('email');
}
if(Controller::request('password')) {
- $this->staffRow->password = Hashing::hashPassword(Controller::request('password'));
+ $this->staffInstance->password = Hashing::hashPassword(Controller::request('password'));
}
- if(Controller::request('level') && Controller::isStaffLogged(3)) {
- $this->staffRow->level = Controller::request('level');
+ if(Controller::request('level') && Controller::isStaffLogged(3) && Controller::request('staffId') !== Controller::getLoggedUser()->id) {
+ $this->staffInstance->level = Controller::request('level');
}
if(Controller::request('departments') && Controller::isStaffLogged(3)) {
- $this->staffRow->sharedDepartmentList = $this->getDepartmentList();
+ $this->staffInstance->sharedDepartmentList = $this->getDepartmentList();
}
- $this->staffRow->store();
+ $this->staffInstance->store();
}
- public function getDepartmentList() {
+ private function getDepartmentList() {
$listDepartments = new DataStoreList();
$departmentIds = json_decode(Controller::request('departments'));
@@ -73,8 +72,8 @@ class EditStaffController extends Controller {
return $listDepartments;
}
- public function updateDepartmentsOwners() {
- $list1 = $this->staffRow->sharedDepartmentList;
+ private function updateDepartmentsOwners() {
+ $list1 = $this->staffInstance->sharedDepartmentList;
$list2 = $this->getDepartmentList();
foreach ($list1 as $department1) {
diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php
index d9db4566..2f016ebf 100644
--- a/server/controllers/ticket/comment.php
+++ b/server/controllers/ticket/comment.php
@@ -13,7 +13,7 @@ class CommentController extends Controller {
'permission' => 'user',
'requestData' => [
'content' => [
- 'validation' => DataValidator::length(20, 500),
+ 'validation' => DataValidator::length(20, 5000),
'error' => ERRORS::INVALID_CONTENT
],
'ticketNumber' => [
diff --git a/server/controllers/ticket/create.php b/server/controllers/ticket/create.php
index 501b8896..d4d50853 100644
--- a/server/controllers/ticket/create.php
+++ b/server/controllers/ticket/create.php
@@ -20,7 +20,7 @@ class CreateController extends Controller {
'error' => ERRORS::INVALID_TITLE
],
'content' => [
- 'validation' => DataValidator::length(10, 500),
+ 'validation' => DataValidator::length(10, 5000),
'error' => ERRORS::INVALID_CONTENT
],
'departmentId' => [
diff --git a/tests/ticket/comment.rb b/tests/ticket/comment.rb
index 27222b87..9c39af38 100644
--- a/tests/ticket/comment.rb
+++ b/tests/ticket/comment.rb
@@ -32,7 +32,7 @@ describe '/ticket/comment/' do
it 'should fail if content is very long' do
long_text = ''
- 600.times {long_text << 'a'}
+ 6000.times {long_text << 'a'}
result = request('/ticket/comment', {
content: long_text,
diff --git a/tests/ticket/create.rb b/tests/ticket/create.rb
index 5789b53d..5b0b21dc 100644
--- a/tests/ticket/create.rb
+++ b/tests/ticket/create.rb
@@ -62,7 +62,7 @@ describe '/ticket/create' do
it 'should fail if content is very long' do
long_text = ''
- 600.times {long_text << 'a'}
+ 6000.times {long_text << 'a'}
result = request('/ticket/create',{
title: 'Winter is coming',