Merge branch 'master' of github.com:guillegiu/opensupports into guillermo-master
This commit is contained in:
commit
11c4401bfc
|
@ -34,6 +34,7 @@ class TicketViewer extends React.Component {
|
|||
userId: React.PropTypes.number,
|
||||
userStaff: React.PropTypes.bool,
|
||||
userDepartments: React.PropTypes.array,
|
||||
userLevel: React.PropTypes.number
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -77,7 +78,7 @@ class TicketViewer extends React.Component {
|
|||
<div className="ticket-viewer__comments">
|
||||
{ticket.events && ticket.events.map(this.renderTicketEvent.bind(this))}
|
||||
</div>
|
||||
{(!this.props.ticket.closed && (this.props.editable || !this.props.assignmentAllowed)) ? this.renderResponseField() : null}
|
||||
{(!this.props.ticket.closed && (this.props.editable || !this.props.assignmentAllowed)) ? this.renderResponseField() : (this.showDeleteButton())? <Button size="medium" onClick={this.onDeleteTicketClick.bind(this)}>{i18n('DELETE_TICKET')}</Button> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -226,7 +227,10 @@ class TicketViewer extends React.Component {
|
|||
{(this.props.allowAttachments) ? <FormField name="file" field="file"/> : null}
|
||||
<div className="ticket-viewer__response-buttons">
|
||||
<SubmitButton type="secondary">{i18n('RESPOND_TICKET')}</SubmitButton>
|
||||
<Button size="medium" onClick={this.onCloseTicketClick.bind(this)}>{i18n('CLOSE_TICKET')}</Button>
|
||||
<div>
|
||||
<Button size="medium" onClick={this.onCloseTicketClick.bind(this)}>{i18n('CLOSE_TICKET')}</Button>
|
||||
{(this.showDeleteButton())? <Button className="ticket-viewer__delete-button" size="medium" onClick={this.onDeleteTicketClick.bind(this)}>{i18n('DELETE_TICKET')}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{(this.state.commentError) ? this.renderCommentError() : null}
|
||||
|
@ -339,6 +343,10 @@ class TicketViewer extends React.Component {
|
|||
event.preventDefault();
|
||||
AreYouSure.openModal(null, this.closeTicket.bind(this));
|
||||
}
|
||||
onDeleteTicketClick(event) {
|
||||
event.preventDefault();
|
||||
AreYouSure.openModal(null, this.deleteTicket.bind(this));
|
||||
}
|
||||
|
||||
reopenTicket() {
|
||||
API.call({
|
||||
|
@ -357,6 +365,14 @@ class TicketViewer extends React.Component {
|
|||
}
|
||||
}).then(this.onTicketModification.bind(this));
|
||||
}
|
||||
deleteTicket() {
|
||||
API.call({
|
||||
path: '/ticket/delete',
|
||||
data: {
|
||||
ticketNumber: this.props.ticket.ticketNumber
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
changeDepartment(index) {
|
||||
API.call({
|
||||
|
@ -459,6 +475,18 @@ class TicketViewer extends React.Component {
|
|||
|
||||
return staffAssignmentItems;
|
||||
}
|
||||
|
||||
showDeleteButton() {
|
||||
if(!this.props.ticket.owner) {
|
||||
if(this.props.userLevel == 3) return true;
|
||||
if(this.props.userId == this.props.ticket.author.id) {
|
||||
if((this.props.userStaff && this.props.ticket.author.staff) || (!this.props.userStaff && !this.props.ticket.author.staff)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default connect((store) => {
|
||||
|
@ -469,6 +497,7 @@ export default connect((store) => {
|
|||
staffMembers: store.adminData.staffMembers,
|
||||
staffMembersLoaded: store.adminData.staffMembersLoaded,
|
||||
allowAttachments: store.config['allow-attachments'],
|
||||
userSystemEnabled: store.config['user-system-enabled']
|
||||
userSystemEnabled: store.config['user-system-enabled'],
|
||||
userLevel: store.session.userLevel
|
||||
};
|
||||
})(TicketViewer);
|
||||
|
|
|
@ -97,4 +97,7 @@
|
|||
}
|
||||
|
||||
}
|
||||
&__delete-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'Responder',
|
||||
'RESPOND_TICKET': 'Responder chamado',
|
||||
'CLOSE_TICKET': 'Fechar ticket',
|
||||
'DELETE_TICKET': 'Apagar ticket',
|
||||
'NO_ATTACHMENT': 'Nenhum anexo',
|
||||
'STAFF': 'Equipe',
|
||||
'CUSTOMER': 'Cliente',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': '響應',
|
||||
'RESPOND_TICKET': '響應故障單',
|
||||
'CLOSE_TICKET': '關門票',
|
||||
'DELETE_TICKET': '删除票证',
|
||||
'NO_ATTACHMENT': '沒有文件附件',
|
||||
'STAFF': '員工',
|
||||
'CUSTOMER': '顧客',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'Antworten',
|
||||
'RESPOND_TICKET': 'Ticket beantworten',
|
||||
'CLOSE_TICKET': 'Ticket schließen',
|
||||
'DELETE_TICKET': 'Ticket löschen',
|
||||
'NO_ATTACHMENT': 'Keine Dateianlage',
|
||||
'STAFF': 'Personal',
|
||||
'CUSTOMER': 'Kunde',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'Respond',
|
||||
'RESPOND_TICKET': 'Respond Ticket',
|
||||
'CLOSE_TICKET': 'Close ticket',
|
||||
'DELETE_TICKET': 'Delete ticket',
|
||||
'NO_ATTACHMENT': 'No file attachment',
|
||||
'STAFF': 'Staff',
|
||||
'CUSTOMER': 'Customer',
|
||||
|
|
|
@ -21,15 +21,16 @@ export default {
|
|||
'VIEW_ARTICLES': 'Ver Artículos',
|
||||
'EDIT_PROFILE': 'Editar Perfil',
|
||||
'CLOSE_SESSION': 'Cerrar sesión',
|
||||
'CREATE_TICKET': 'Crear Ticket',
|
||||
'TICKET_LIST': 'Lista de Tickets',
|
||||
'CREATE_TICKET': 'Crear ticket',
|
||||
'TICKET_LIST': 'Lista de tickets',
|
||||
'SUPPORT_CENTER': 'Centro de Soporte',
|
||||
'DEPARTMENT': 'Departamento',
|
||||
'AUTHOR': 'Autor',
|
||||
'DATE': 'Fecha',
|
||||
'RESPOND': 'Responder',
|
||||
'RESPOND_TICKET': 'Responder Ticket',
|
||||
'CLOSE_TICKET': 'Cerrar Ticket',
|
||||
'RESPOND_TICKET': 'Responder ticket',
|
||||
'CLOSE_TICKET': 'Cerrar ticket',
|
||||
'DELETE_TICKET': 'Borrar ticket',
|
||||
'NO_ATTACHMENT': 'No hay archivo adjunto',
|
||||
'STAFF': 'Staff',
|
||||
'CUSTOMER': 'Cliente',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'Répondre',
|
||||
'RESPOND_TICKET': 'Répondre au ticket',
|
||||
'CLOSE_TICKET': 'Fermer ticket',
|
||||
'DELETE_TICKET': 'Supprimer le ticket',
|
||||
'NO_ATTACHMENT': 'Aucune pièce jointe',
|
||||
'STAFF': 'Administrateur',
|
||||
'CUSTOMER': 'Client',
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
'RESPOND': 'Απάντηση',
|
||||
'RESPOND_TICKET': 'Απάντηση Εισιτηρίου',
|
||||
'CLOSE_TICKET': 'κλειστό εισιτήριο',
|
||||
'DELETE_TICKET': 'Διαγραφή εισιτηρίου',
|
||||
'NO_ATTACHMENT': 'Χωρίς Συνημμένα Αρχεία',
|
||||
'STAFF': 'Προσωπικό',
|
||||
'CUSTOMER': 'Πελάτης',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'प्रतिक्रिया',
|
||||
'RESPOND_TICKET': 'प्रतिक्रिया टिकट',
|
||||
'CLOSE_TICKET': 'करीबी टिकट',
|
||||
'DELETE_TICKET': 'टिकट हटाएं',
|
||||
'NO_ATTACHMENT': 'कोई फ़ाइल अनुलग्नक नहीं',
|
||||
'STAFF': 'कर्मचारी',
|
||||
'CUSTOMER': 'ग्राहक',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'Rispondi',
|
||||
'RESPOND_TICKET': 'Rispondi al ticket',
|
||||
'CLOSE_TICKET': 'Ticket vicino',
|
||||
'DELETE_TICKET': 'Elimina ticket',
|
||||
'NO_ATTACHMENT': 'Nessun file allegato',
|
||||
'STAFF': 'Staff',
|
||||
'CUSTOMER': 'Customer',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': '応答する',
|
||||
'RESPOND_TICKET': 'チケット応答',
|
||||
'CLOSE_TICKET': 'クローズチケット',
|
||||
'DELETE_TICKET': 'チケットを削除する',
|
||||
'NO_ATTACHMENT': '添付ファイルがありません',
|
||||
'STAFF': 'スタッフ',
|
||||
'CUSTOMER': '顧客',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'Actie',
|
||||
'RESPOND_TICKET': 'Reageren',
|
||||
'CLOSE_TICKET': 'Sluit ticket',
|
||||
'DELETE_TICKET': 'Ticket verwijderen',
|
||||
'NO_ATTACHMENT': 'Geen bijlage',
|
||||
'STAFF': 'Management',
|
||||
'CUSTOMER': 'Klant',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'Responder',
|
||||
'RESPOND_TICKET': 'Respond Ticket',
|
||||
'CLOSE_TICKET': 'Fechar passagem',
|
||||
'DELETE_TICKET': 'Apagar ticket',
|
||||
'NO_ATTACHMENT': 'Nenhum anexo de arquivo',
|
||||
'STAFF': 'Funcionários',
|
||||
'CUSTOMER': 'Cliente',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'Отвечать',
|
||||
'RESPOND_TICKET': 'Ответить билет',
|
||||
'CLOSE_TICKET': 'закрыть билет',
|
||||
'DELETE_TICKET': 'Удалить билет',
|
||||
'NO_ATTACHMENT': 'Нет вложений файлов',
|
||||
'STAFF': 'Сотрудники',
|
||||
'CUSTOMER': 'Клиент',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
'RESPOND': 'Yanıtla',
|
||||
'RESPOND_TICKET': 'Bilete Gider',
|
||||
'CLOSE_TICKET': 'Yakın bilet',
|
||||
'DELETE_TICKET': 'Bilet sil',
|
||||
'NO_ATTACHMENT': 'Dosya eki yok',
|
||||
'STAFF': 'Personel',
|
||||
'CUSTOMER': 'Müşteri',
|
||||
|
|
|
@ -12,6 +12,7 @@ include 'ticket/close.php';
|
|||
include 'ticket/re-open.php';
|
||||
include 'ticket/change-priority.php';
|
||||
include 'ticket/seen.php';
|
||||
include 'ticket/delete.php';
|
||||
|
||||
$ticketControllers = new ControllerGroup();
|
||||
$ticketControllers->setGroupPath('/ticket');
|
||||
|
@ -29,5 +30,6 @@ $ticketControllers->addController(new CloseController);
|
|||
$ticketControllers->addController(new ReOpenController);
|
||||
$ticketControllers->addController(new ChangePriorityController);
|
||||
$ticketControllers->addController(new SeenController);
|
||||
$ticketControllers->addController(new DeleteController);
|
||||
|
||||
$ticketControllers->finalize();
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
use Respect\Validation\Validator as DataValidator;
|
||||
DataValidator::with('CustomValidations', true);
|
||||
|
||||
/**
|
||||
* @api {post} /ticket/delete Delete a ticket
|
||||
* @apiVersion 4.3.0
|
||||
*
|
||||
* @apiName Delete ticket
|
||||
*
|
||||
* @apiGroup Ticket
|
||||
*
|
||||
* @apiDescription This path deletes a ticket.
|
||||
*
|
||||
* @apiPermission user
|
||||
*
|
||||
* @apiParam {Number} ticketNumber The number of the ticket to delete.
|
||||
*
|
||||
* @apiUse NO_PERMISSION
|
||||
* @apiUse INVALID_TICKET
|
||||
*
|
||||
* @apiSuccess {Object} data Empty object
|
||||
*ulp d
|
||||
*/
|
||||
|
||||
class DeleteController extends Controller {
|
||||
const PATH = '/delete';
|
||||
const METHOD = 'POST';
|
||||
|
||||
public function validations() {
|
||||
return [
|
||||
'permission' => 'user',
|
||||
'requestData' => [
|
||||
'ticketNumber' => [
|
||||
'validation' => DataValidator::validTicketNumber(),
|
||||
'error' => ERRORS::INVALID_TICKET
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function handler() {
|
||||
$user = Controller::getLoggedUser();
|
||||
$ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber'));
|
||||
|
||||
if(Controller::isStaffLogged() && ($user->level < 3 || $ticket->owner)) {
|
||||
throw new Exception(ERRORS::NO_PERMISSION);
|
||||
}
|
||||
if(!Controller::isStaffLogged() && (($user->email !== $ticket->author->email) || $ticket->owner) ) {
|
||||
throw new Exception(ERRORS::NO_PERMISSION);
|
||||
}
|
||||
|
||||
$ticket->delete();
|
||||
|
||||
Response::respondSuccess();
|
||||
}
|
||||
}
|
|
@ -90,6 +90,10 @@ class Ticket extends DataStore {
|
|||
parent::store();
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
public function generateUniqueTicketNumber() {
|
||||
$linearCongruentialGenerator = new LinearCongruentialGenerator();
|
||||
$ticketQuantity = Ticket::count();
|
||||
|
|
|
@ -27,6 +27,7 @@ require './ticket/custom-response.rb'
|
|||
require './ticket/change-department.rb'
|
||||
require './ticket/close.rb'
|
||||
require './ticket/re-open.rb'
|
||||
require './ticket/delete.rb'
|
||||
require './staff/add.rb'
|
||||
require './staff/get.rb'
|
||||
require './staff/edit.rb'
|
||||
|
|
|
@ -35,6 +35,16 @@ class Scripts
|
|||
raise response['message']
|
||||
end
|
||||
end
|
||||
def self.deleteStaff(staffid)
|
||||
|
||||
response = request('/staff/delete', {
|
||||
:staffId => staffid
|
||||
})
|
||||
|
||||
if response['status'] === 'fail'
|
||||
raise response['message']
|
||||
end
|
||||
end
|
||||
|
||||
def self.login(email = 'steve@jobs.com', password = 'custompassword', staff = false)
|
||||
request('/user/logout')
|
||||
|
|
|
@ -20,7 +20,7 @@ describe'/staff/get-all' do
|
|||
(result['data'][0]['departments'][1]['name']).should.equal('Suggestions')
|
||||
(result['data'][0]['departments'][2]['id']).should.equal('3')
|
||||
(result['data'][0]['departments'][2]['name']).should.equal('Tech support')
|
||||
(result['data'][0]['assignedTickets']).should.equal(4)
|
||||
(result['data'][0]['assignedTickets']).should.equal(6)
|
||||
(result['data'][0]['closedTickets']).should.equal(0)
|
||||
|
||||
(result['data'][2]['name']).should.equal('Arya Stark')
|
||||
|
|
|
@ -10,7 +10,7 @@ describe '/staff/get-new-tickets' do
|
|||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
(result['data'].size).should.equal(8)
|
||||
(result['data'].size).should.equal(11)
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,6 +22,6 @@ describe '/staff/get-tickets' do
|
|||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
(result['data'].size).should.equal(3)
|
||||
(result['data'].size).should.equal(5)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ describe'system/disable-user-system' do
|
|||
|
||||
numberOftickets= $database.query("SELECT * FROM ticket WHERE author_id IS NULL AND author_email IS NOT NULL AND author_name IS NOT NULL")
|
||||
|
||||
(numberOftickets.num_rows).should.equal(39)
|
||||
(numberOftickets.num_rows).should.equal(41)
|
||||
|
||||
request('/user/logout')
|
||||
|
||||
|
@ -127,7 +127,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(40)
|
||||
(numberOftickets.num_rows).should.equal(42)
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
describe '/ticket/delete' do
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
Scripts.createTicket('tickettodelete')
|
||||
Scripts.createTicket('tickettodelete4')
|
||||
|
||||
# it 'should delete ticket if it is not assigned and is logged a staff lvl 3 ' do
|
||||
#
|
||||
#
|
||||
# ticket = $database.getRow('ticket', 'tickettodelete', 'title')
|
||||
#
|
||||
# request('/staff/add', {
|
||||
# csrf_userid: $csrf_userid,
|
||||
# csrf_token: $csrf_token,
|
||||
# name: 'Ned Stark',
|
||||
# password: 'headless',
|
||||
# email: 'ned@opensupports.com',
|
||||
# level: 3,
|
||||
# profilePic: '',
|
||||
# departments: '[1]'
|
||||
# })
|
||||
#
|
||||
# request('/user/logout')
|
||||
#
|
||||
# Scripts.login('ned@opensupports.com', 'headless', true)
|
||||
#
|
||||
# result = request('/ticket/delete', {
|
||||
# ticketNumber: ticket['ticket_number'],
|
||||
# csrf_userid: $csrf_userid,
|
||||
# csrf_token: $csrf_token
|
||||
# })
|
||||
#
|
||||
# (result['status']).should.equal('success')
|
||||
# end
|
||||
|
||||
it 'should delete ticket if it is yours and it is not assigned' do
|
||||
request('/user/logout')
|
||||
Scripts.createUser('deleter@opensupports.com', 'deleterpassword', 'Delter')
|
||||
Scripts.login('deleter@opensupports.com', 'deleterpassword')
|
||||
|
||||
Scripts.createTicket('tickettodelete2')
|
||||
ticket = $database.getRow('ticket', 'tickettodelete2', 'title');
|
||||
|
||||
result = request('/ticket/delete', {
|
||||
ticketNumber: ticket['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
puts result
|
||||
(result['status']).should.equal('success')
|
||||
end
|
||||
|
||||
it 'should not delete ticket if it is assigned' do
|
||||
request('/user/logout')
|
||||
Scripts.login('deleter@opensupports.com', 'deleterpassword')
|
||||
|
||||
Scripts.createTicket('tickettodelete3')
|
||||
ticket = $database.getRow('ticket', 'tickettodelete3', 'title');
|
||||
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
|
||||
result = request('/staff/assign-ticket', {
|
||||
ticketNumber: ticket['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
request('/user/logout')
|
||||
Scripts.login('deleter@opensupports.com', 'deleterpassword')
|
||||
|
||||
result = request('/ticket/delete', {
|
||||
ticketNumber: ticket['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
end
|
||||
|
||||
it 'should not delete ticket if the staff logged is not lvl 3' do
|
||||
request('/user/logout')
|
||||
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
|
||||
ticket = $database.getRow('ticket', 'tickettodelete4', 'title');
|
||||
|
||||
request('/staff/add', {
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token,
|
||||
name: 'Joan Chris',
|
||||
password: 'theyaregonnafireme',
|
||||
email: 'uselessstaff@opensupports.com',
|
||||
level: 2,
|
||||
profilePic: '',
|
||||
departments: '[1]'
|
||||
})
|
||||
request('/user/logout')
|
||||
|
||||
Scripts.login('uselessstaff@opensupports.com', 'theyaregonnafireme',true)
|
||||
|
||||
result = request('/ticket/delete', {
|
||||
ticketNumber: ticket['ticket_number'],
|
||||
csrf_userid: $csrf_userid,
|
||||
csrf_token: $csrf_token
|
||||
})
|
||||
|
||||
(result['status']).should.equal('fail')
|
||||
|
||||
end
|
||||
|
||||
request('/user/logout')
|
||||
Scripts.login($staff[:email], $staff[:password], true)
|
||||
staff = $database.getRow('staff', 'headless', 'password')
|
||||
Scripts.deleteStaff(staff['id'])
|
||||
|
||||
staff = $database.getRow('staff', 'theyaregonnafireme', 'password')
|
||||
Scripts.deleteStaff(staff['id'])
|
||||
|
||||
end
|
|
@ -36,7 +36,7 @@ describe '/user/get-users' do
|
|||
})
|
||||
|
||||
(result['status']).should.equal('success')
|
||||
(result['data']['users'].size).should.equal(5)
|
||||
(result['data']['users'].size).should.equal(6)
|
||||
end
|
||||
|
||||
it 'should get users with order by tickets and asc' do
|
||||
|
|
Loading…
Reference in New Issue