diff --git a/client/src/actions/admin-data-actions.js b/client/src/actions/admin-data-actions.js
index 94c9cde5..8926b1f4 100644
--- a/client/src/actions/admin-data-actions.js
+++ b/client/src/actions/admin-data-actions.js
@@ -12,12 +12,12 @@ export default {
};
},
- retrieveMyTickets() {
+ retrieveMyTickets(closed = 0) {
return {
type: 'MY_TICKETS',
payload: API.call({
path: '/staff/get-tickets',
- data: {}
+ data: {closed}
})
};
},
@@ -32,12 +32,12 @@ export default {
};
},
- retrieveAllTickets(page = 1) {
+ retrieveAllTickets(page = 1, query = '', closed = 0) {
return {
type: 'ALL_TICKETS',
payload: API.call({
path: '/staff/get-all-tickets',
- data: {page}
+ data: {page, query, closed}
})
};
},
diff --git a/client/src/app-components/ticket-list.js b/client/src/app-components/ticket-list.js
index c3d95be4..86ee0403 100644
--- a/client/src/app-components/ticket-list.js
+++ b/client/src/app-components/ticket-list.js
@@ -9,6 +9,7 @@ import Table from 'core-components/table';
import Button from 'core-components/button';
import Tooltip from 'core-components/tooltip';
import DropDown from 'core-components/drop-down';
+import Checkbox from 'core-components/checkbox';
class TicketList extends React.Component {
static propTypes = {
@@ -21,7 +22,9 @@ class TicketList extends React.Component {
type: React.PropTypes.oneOf([
'primary',
'secondary'
- ])
+ ]),
+ closedTicketsShown: React.PropTypes.bool,
+ onClosedTicketsShownChange: React.PropTypes.func
};
static defaultProps = {
@@ -30,7 +33,8 @@ class TicketList extends React.Component {
tickets: [],
departments: [],
ticketPath: '/dashboard/ticket/',
- type: 'primary'
+ type: 'primary',
+ closedTicketsShown: false
};
state = {
@@ -40,12 +44,20 @@ class TicketList extends React.Component {
render() {
return (
- {(this.props.type === 'secondary' && this.props.showDepartmentDropdown) ? this.renderDepartmentsDropDown() : null}
+
+ {(this.props.type === 'secondary' && this.props.showDepartmentDropdown) ? this.renderDepartmentsDropDown() : null}
+ {this.props.onClosedTicketsShownChange ? this.renderFilterCheckbox() : null}
+
);
}
+
+ renderFilterCheckbox() {
+ return
+ }
+
renderDepartmentsDropDown() {
return (
diff --git a/client/src/app-components/ticket-list.scss b/client/src/app-components/ticket-list.scss
index e0cb9ceb..33783043 100644
--- a/client/src/app-components/ticket-list.scss
+++ b/client/src/app-components/ticket-list.scss
@@ -2,8 +2,19 @@
.ticket-list {
- &__department-selector {
+ &__filters {
margin-bottom: 25px;
+ text-align: left;
+ }
+
+ &__department-selector {
+ display: inline-block;
+ margin-right: 25px;
+ text-align: center;
+ }
+
+ &__checkbox {
+ display: inline-block;
}
&__number {
@@ -52,4 +63,4 @@
&__priority-high {
background-color: $primary-red;
}
-}
\ No newline at end of file
+}
diff --git a/client/src/app-components/ticket-viewer.js b/client/src/app-components/ticket-viewer.js
index 7450ed1a..79cf0048 100644
--- a/client/src/app-components/ticket-viewer.js
+++ b/client/src/app-components/ticket-viewer.js
@@ -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 {
{ticket.events && ticket.events.map(this.renderTicketEvent.bind(this))}
- {(!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())?
: null}
);
}
@@ -226,7 +227,10 @@ class TicketViewer extends React.Component {
{(this.props.allowAttachments) ? : null}
{i18n('RESPOND_TICKET')}
-
+
+
+ {(this.showDeleteButton())? : null}
+
{(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
+ }
+ }).then(this.onTicketModification.bind(this));
+ }
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);
diff --git a/client/src/app-components/ticket-viewer.scss b/client/src/app-components/ticket-viewer.scss
index a1b3ac36..17de6a8c 100644
--- a/client/src/app-components/ticket-viewer.scss
+++ b/client/src/app-components/ticket-viewer.scss
@@ -97,4 +97,7 @@
}
}
+ &__delete-button {
+ margin-left: 10px;
+ }
}
diff --git a/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js b/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js
index ec6be25d..bbc7ef70 100644
--- a/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js
+++ b/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js
@@ -20,11 +20,12 @@ class AdminPanelAllTickets extends React.Component {
state = {
page: 1,
- query: ''
+ query: '',
+ closedTicketsShown: false
};
componentDidMount() {
- this.props.dispatch(AdminDataAction.retrieveAllTickets());
+ this.updateTicketList();
}
render() {
@@ -41,6 +42,14 @@ class AdminPanelAllTickets extends React.Component {
);
}
+ updateTicketList() {
+ this.props.dispatch(AdminDataAction.retrieveAllTickets(
+ this.state.page,
+ this.state.query,
+ this.state.closedTicketsShown*1
+ ));
+ }
+
getTicketListProps() {
return {
userId: this.props.userId,
@@ -52,28 +61,32 @@ class AdminPanelAllTickets extends React.Component {
ticketPath: '/admin/panel/tickets/view-ticket/',
onPageChange: this.onPageChange.bind(this),
page: this.state.page,
- pages: this.props.pages
+ pages: this.props.pages,
+ closedTicketsShown: this.state.closedTicketsShown,
+ onClosedTicketsShownChange: this.onClosedTicketsShownChange.bind(this)
};
}
- onSearch(query) {
- this.setState({query, page: 1});
+ onClosedTicketsShownChange() {
+ this.setState(function(state) {
+ return {
+ closedTicketsShown: !state.closedTicketsShown
+ };
+ }, () => {
+ this.updateTicketList();
+ });
+ }
- if(query) {
- this.props.dispatch(AdminDataAction.searchTickets(query));
- } else {
- this.props.dispatch(AdminDataAction.retrieveAllTickets());
- }
+ onSearch(query) {
+ this.setState({query, page: 1}, () => {
+ this.updateTicketList();
+ });
}
onPageChange(event) {
- this.setState({page: event.target.value});
-
- if(this.state.query) {
- this.props.dispatch(AdminDataAction.searchTickets(this.state.query, event.target.value));
- } else {
- this.props.dispatch(AdminDataAction.retrieveAllTickets(event.target.value));
- }
+ this.setState({page: event.target.value}, () => {
+ this.updateTicketList();
+ });
}
}
diff --git a/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js b/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js
index 2b85418b..a5f827ac 100644
--- a/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js
+++ b/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js
@@ -21,6 +21,10 @@ class AdminPanelMyTickets extends React.Component {
tickets: []
};
+ state = {
+ closedTicketsShown: false
+ };
+
componentDidMount() {
this.props.dispatch(AdminDataAction.retrieveMyTickets());
}
@@ -46,10 +50,22 @@ class AdminPanelMyTickets extends React.Component {
tickets: this.props.tickets,
type: 'secondary',
loading: this.props.loading,
- ticketPath: '/admin/panel/tickets/view-ticket/'
+ ticketPath: '/admin/panel/tickets/view-ticket/',
+ closedTicketsShown: this.state.closedTicketsShown,
+ onClosedTicketsShownChange: this.onClosedTicketsShownChange.bind(this)
};
}
+ onClosedTicketsShownChange() {
+ this.setState(function(state) {
+ return {
+ closedTicketsShown: !state.closedTicketsShown
+ };
+ }, () => {
+ this.props.dispatch(AdminDataAction.retrieveMyTickets(this.state.closedTicketsShown * 1));
+ });
+ }
+
onCreateTicket() {
ModalContainer.openModal(
diff --git a/client/src/data/languages/br.js b/client/src/data/languages/br.js
index d5679841..f3a89d5b 100644
--- a/client/src/data/languages/br.js
+++ b/client/src/data/languages/br.js
@@ -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',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'privado',
'ENABLE_USER': 'Ativar usuário',
'DISABLE_USER': 'Desativar usuário',
+ 'SHOW_CLOSED_TICKETS': 'Mostrar ingressos fechados',
'IMAGE_HEADER_URL': 'URL do cabeçalho da imagem',
'CHART_CREATE_TICKET': 'Chamados criados',
diff --git a/client/src/data/languages/cn.js b/client/src/data/languages/cn.js
index b2158680..0b62cb42 100644
--- a/client/src/data/languages/cn.js
+++ b/client/src/data/languages/cn.js
@@ -30,6 +30,7 @@ export default {
'RESPOND': '響應',
'RESPOND_TICKET': '響應故障單',
'CLOSE_TICKET': '關門票',
+ 'DELETE_TICKET': '删除票证',
'NO_ATTACHMENT': '沒有文件附件',
'STAFF': '員工',
'CUSTOMER': '顧客',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': '私人的',
'ENABLE_USER': '启用用户',
'DISABLE_USER': '禁用用户',
+ 'SHOW_CLOSED_TICKETS': '显示已关闭的门票',
'IMAGE_HEADER_URL': '图片标题网址',
'CHART_CREATE_TICKET': '已創建門票',
diff --git a/client/src/data/languages/de.js b/client/src/data/languages/de.js
index b291d9af..e7ec08a6 100644
--- a/client/src/data/languages/de.js
+++ b/client/src/data/languages/de.js
@@ -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',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'Privatgelände',
'ENABLE_USER': 'Benutzer aktivieren',
'DISABLE_USER': 'Benutzer deaktivieren',
+ 'SHOW_CLOSED_TICKETS': 'Geschlossene Tickets anzeigen',
'IMAGE_HEADER_URL': 'URL des Image-Headers',
'CHART_CREATE_TICKET': 'Tickets erstellt',
diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js
index 39ca0115..e5d90c44 100644
--- a/client/src/data/languages/en.js
+++ b/client/src/data/languages/en.js
@@ -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',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'Private',
'ENABLE_USER': 'Enable User',
'DISABLE_USER': 'Disable User',
+ 'SHOW_CLOSED_TICKETS': 'Show Closed Tickets',
'IMAGE_HEADER_URL': 'Image header URL',
'CHART_CREATE_TICKET': 'Tickets created',
diff --git a/client/src/data/languages/es.js b/client/src/data/languages/es.js
index aaf71692..d86b7ee5 100644
--- a/client/src/data/languages/es.js
+++ b/client/src/data/languages/es.js
@@ -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',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'privado',
'ENABLE_USER': 'Habilitar usuario',
'DISABLE_USER': 'Deshabilitar usuario',
+ 'SHOW_CLOSED_TICKETS': 'Mostrar Tickets Cerrados',
'IMAGE_HEADER_URL': 'URL del encabezado de la imagen',
'CHART_CREATE_TICKET': 'Tickets creados',
diff --git a/client/src/data/languages/fr.js b/client/src/data/languages/fr.js
index 480c5979..eb71b3ef 100644
--- a/client/src/data/languages/fr.js
+++ b/client/src/data/languages/fr.js
@@ -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',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'privé',
'ENABLE_USER': 'Activer l\'utilisateur',
'DISABLE_USER': 'Désactiver l\'utilisateur',
+ 'SHOW_CLOSED_TICKETS': 'Afficher les billets fermés',
'IMAGE_HEADER_URL': 'URL de l\'en-tête de l\'image',
'CHART_CREATE_TICKET': 'Tickets créés',
diff --git a/client/src/data/languages/gr.js b/client/src/data/languages/gr.js
index e5b97abb..0cf8a74c 100644
--- a/client/src/data/languages/gr.js
+++ b/client/src/data/languages/gr.js
@@ -30,6 +30,7 @@
'RESPOND': 'Απάντηση',
'RESPOND_TICKET': 'Απάντηση Εισιτηρίου',
'CLOSE_TICKET': 'κλειστό εισιτήριο',
+ 'DELETE_TICKET': 'Διαγραφή εισιτηρίου',
'NO_ATTACHMENT': 'Χωρίς Συνημμένα Αρχεία',
'STAFF': 'Προσωπικό',
'CUSTOMER': 'Πελάτης',
@@ -188,6 +189,7 @@
'PRIVATE': 'ιδιωτικός',
'ENABLE_USER': 'Ενεργοποίηση χρήστη',
'DISABLE_USER': 'Απενεργοποίηση χρήστη',
+ 'SHOW_CLOSED_TICKETS': 'Εμφάνιση κλειστών εισιτηρίων',
'IMAGE_HEADER_URL': 'Διεύθυνση URL κεφαλίδας εικόνας',
'CHART_CREATE_TICKET': 'Τα εισιτήρια δημιουργήθηκαν',
diff --git a/client/src/data/languages/in.js b/client/src/data/languages/in.js
index a5fe8524..b5957e12 100644
--- a/client/src/data/languages/in.js
+++ b/client/src/data/languages/in.js
@@ -30,6 +30,7 @@ export default {
'RESPOND': 'प्रतिक्रिया',
'RESPOND_TICKET': 'प्रतिक्रिया टिकट',
'CLOSE_TICKET': 'करीबी टिकट',
+ 'DELETE_TICKET': 'टिकट हटाएं',
'NO_ATTACHMENT': 'कोई फ़ाइल अनुलग्नक नहीं',
'STAFF': 'कर्मचारी',
'CUSTOMER': 'ग्राहक',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'निजी',
'ENABLE_USER': 'उपयोगकर्ता सक्षम करें',
'DISABLE_USER': 'उपयोगकर्ता को अक्षम करें',
+ 'SHOW_CLOSED_TICKETS': 'बंद टिकट दिखाएं',
'IMAGE_HEADER_URL': 'छवि शीर्षलेख यूआरएल',
'CHART_CREATE_TICKET': 'टिकट बनाया',
diff --git a/client/src/data/languages/it.js b/client/src/data/languages/it.js
index 86c9efb3..ecf97745 100644
--- a/client/src/data/languages/it.js
+++ b/client/src/data/languages/it.js
@@ -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',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'privato',
'ENABLE_USER': 'Abilita utente',
'DISABLE_USER': 'Disabilita utente',
+ 'SHOW_CLOSED_TICKETS': 'Mostra biglietti chiusi',
'IMAGE_HEADER_URL': 'URL dell\'intestazione dell\'immagine',
'CHART_CREATE_TICKET': 'Tickets creato',
diff --git a/client/src/data/languages/jp.js b/client/src/data/languages/jp.js
index 9cc7489e..868c6606 100644
--- a/client/src/data/languages/jp.js
+++ b/client/src/data/languages/jp.js
@@ -30,6 +30,7 @@ export default {
'RESPOND': '応答する',
'RESPOND_TICKET': 'チケット応答',
'CLOSE_TICKET': 'クローズチケット',
+ 'DELETE_TICKET': 'チケットを削除する',
'NO_ATTACHMENT': '添付ファイルがありません',
'STAFF': 'スタッフ',
'CUSTOMER': '顧客',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'プライベート',
'ENABLE_USER': 'ユーザーを有効にする',
'DISABLE_USER': 'ユーザーを無効にする',
+ 'SHOW_CLOSED_TICKETS': 'クローズドチケットを表示する',
'IMAGE_HEADER_URL': '画像のヘッダーURL',
'CHART_CREATE_TICKET': '作成されたチケット',
diff --git a/client/src/data/languages/nl.js b/client/src/data/languages/nl.js
index 72cea7e1..37fe968a 100644
--- a/client/src/data/languages/nl.js
+++ b/client/src/data/languages/nl.js
@@ -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',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'privaat',
'ENABLE_USER': 'Schakel gebruiker in',
'DISABLE_USER': 'Gebruiker uitschakelen',
+ 'SHOW_CLOSED_TICKETS': 'Toon gesloten tickets',
'IMAGE_HEADER_URL': 'Image header URL',
'CHART_CREATE_TICKET': 'Aangemaakte incidenten',
diff --git a/client/src/data/languages/pt.js b/client/src/data/languages/pt.js
index 7e323c17..462f65fb 100644
--- a/client/src/data/languages/pt.js
+++ b/client/src/data/languages/pt.js
@@ -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',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'privado',
'ENABLE_USER': 'Ativar usuário',
'DISABLE_USER': 'Desativar usuário',
+ 'SHOW_CLOSED_TICKETS': 'Mostrar ingressos fechados',
'IMAGE_HEADER_URL': 'URL do cabeçalho da imagem',
'CHART_CREATE_TICKET': 'Ingressos criados',
diff --git a/client/src/data/languages/ru.js b/client/src/data/languages/ru.js
index a4eb3f83..325859b1 100644
--- a/client/src/data/languages/ru.js
+++ b/client/src/data/languages/ru.js
@@ -30,6 +30,7 @@ export default {
'RESPOND': 'Отвечать',
'RESPOND_TICKET': 'Ответить билет',
'CLOSE_TICKET': 'закрыть билет',
+ 'DELETE_TICKET': 'Удалить билет',
'NO_ATTACHMENT': 'Нет вложений файлов',
'STAFF': 'Сотрудники',
'CUSTOMER': 'Клиент',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'частный',
'ENABLE_USER': 'Включить пользователя',
'DISABLE_USER': 'Отключить пользователя',
+ 'SHOW_CLOSED_TICKETS': 'Показать закрытые билеты',
'IMAGE_HEADER_URL': 'URL заголовка изображения',
'CHART_CREATE_TICKET': 'Билеты создано',
diff --git a/client/src/data/languages/tr.js b/client/src/data/languages/tr.js
index 47fbe9eb..c0b01802 100644
--- a/client/src/data/languages/tr.js
+++ b/client/src/data/languages/tr.js
@@ -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',
@@ -188,6 +189,7 @@ export default {
'PRIVATE': 'gizli',
'ENABLE_USER': 'Kullanıcıyı Etkinleştir',
'DISABLE_USER': 'Kullanıcıyı Devre Dışı Bırak',
+ 'SHOW_CLOSED_TICKETS': 'Kapalı Biletleri Göster',
'IMAGE_HEADER_URL': 'Resim başlığı URL\'si',
'CHART_CREATE_TICKET': 'Biletler oluşturuldu',
diff --git a/server/controllers/staff/get-all-tickets.php b/server/controllers/staff/get-all-tickets.php
index 03d2c8bf..7c38a489 100755
--- a/server/controllers/staff/get-all-tickets.php
+++ b/server/controllers/staff/get-all-tickets.php
@@ -2,18 +2,20 @@
use Respect\Validation\Validator as DataValidator;
/**
- * @api {post} /staff/get-all-tickets Get all tickets
+ * @api {post} /staff/get-all-tickets Get all tickets according to search
* @apiVersion 4.3.0
*
* @apiName Get all tickets
*
* @apiGroup Staff
*
- * @apiDescription This path retrieves all tickets.
+ * @apiDescription This path retrieves all tickets according to search and opened/closed filters.
*
* @apiPermission staff1
*
* @apiParam {Number} page The page number.
+ * @apiParam {String} query Query string to search.
+ * @apiParam {Boolean} closed Include closed tickets.
*
* @apiUse NO_PERMISSION
* @apiUse INVALID_PAGE
@@ -58,10 +60,24 @@ class GetAllTicketsStaffController extends Controller {
private function getTicketList() {
$page = Controller::request('page');
- $query = $this->getStaffDepartmentsQueryFilter();
- $query .= 'ORDER BY id DESC LIMIT 10 OFFSET ' . (($page-1)*10);
+ $query = $this->getSearchQuery();
+ $query .= $this->getStaffDepartmentsQueryFilter();
+ $query .= $this->getClosedFilter();
+ $query .= "ORDER BY CASE WHEN (title LIKE ?) THEN 1 ELSE 2 END ASC, id DESC LIMIT 10 OFFSET " . (($page-1)*10);
- return Ticket::find($query);
+ return Ticket::find($query, [
+ Controller::request('query') . '%',
+ '%' . Controller::request('query') . '%',
+ Controller::request('query') . '%'
+ ]);
+ }
+
+ private function getSearchQuery() {
+ $page = Controller::request('page');
+
+ $query = " (title LIKE ? OR title LIKE ?) AND ";
+
+ return $query;
}
private function getTotalPages() {
@@ -81,4 +97,13 @@ class GetAllTicketsStaffController extends Controller {
return $query;
}
+
+ private function getClosedFilter() {
+ $closed = Controller::request('closed')*1;
+ if ($closed) {
+ return '';
+ } else {
+ return " AND (closed = '0')";
+ }
+ }
}
diff --git a/server/controllers/staff/get-tickets.php b/server/controllers/staff/get-tickets.php
index 1f768042..137cb7eb 100755
--- a/server/controllers/staff/get-tickets.php
+++ b/server/controllers/staff/get-tickets.php
@@ -13,6 +13,8 @@ use Respect\Validation\Validator as DataValidator;
*
* @apiPermission staff1
*
+ * @apiParam {bool} closed Include closed tickets in the response.
+ *
* @apiUse NO_PERMISSION
*
* @apiSuccess {[Ticket](#api-Data_Structures-ObjectTicket)[]} data Array of tickets assigned to the staff
@@ -32,6 +34,11 @@ class GetTicketStaffController extends Controller {
public function handler() {
$user = Controller::getLoggedUser();
- Response::respondSuccess($user->sharedTicketList->toArray());
+ $closed = Controller::request('closed');
+ if ($closed) {
+ Response::respondSuccess($user->sharedTicketList->toArray());
+ } else {
+ Response::respondSuccess($user->withCondition('closed = ?', ['0'])->sharedTicketList->toArray());
+ }
}
-}
\ No newline at end of file
+}
diff --git a/server/controllers/ticket.php b/server/controllers/ticket.php
index 2c545a1b..2cce64c5 100755
--- a/server/controllers/ticket.php
+++ b/server/controllers/ticket.php
@@ -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();
\ No newline at end of file
+$ticketControllers->finalize();
diff --git a/server/controllers/ticket/delete.php b/server/controllers/ticket/delete.php
new file mode 100644
index 00000000..ee35d34c
--- /dev/null
+++ b/server/controllers/ticket/delete.php
@@ -0,0 +1,63 @@
+ 'user',
+ 'requestData' => [
+ 'ticketNumber' => [
+ 'validation' => DataValidator::validTicketNumber(),
+ 'error' => ERRORS::INVALID_TICKET
+ ]
+ ]
+ ];
+ }
+
+ public function handler() {
+ $user = Controller::getLoggedUser();
+ $ticket = Ticket::getByTicketNumber(Controller::request('ticketNumber'));
+ $ticketAuthor = $ticket->authorToArray();
+
+ if($ticket->owner) {
+ throw new Exception(ERRORS::NO_PERMISSION);
+ }
+
+ if(Controller::isStaffLogged() && $user->level < 3) {
+ throw new Exception(ERRORS::NO_PERMISSION);
+ }
+
+ if(!Controller::isStaffLogged() && ($user->email !== $ticketAuthor['email'] || $ticketAuthor['staff'])) {
+ throw new Exception(ERRORS::NO_PERMISSION);
+ }
+
+ $ticket->delete();
+
+ Response::respondSuccess();
+ }
+}
diff --git a/server/models/DataStore.php b/server/models/DataStore.php
index 43ec9d22..d4310fdc 100755
--- a/server/models/DataStore.php
+++ b/server/models/DataStore.php
@@ -150,6 +150,10 @@ abstract class DataStore {
}
}
+ public function withCondition($condition, $values) {
+ return new static($this->_bean->withCondition($condition, $values));
+ }
+
private function updateBeanProp($key, $value) {
if ($value instanceof DataStoreList) {
$this->_bean[$key] = $value->toBeanList();
diff --git a/server/models/Ticket.php b/server/models/Ticket.php
index 10f5c0d2..40597a44 100755
--- a/server/models/Ticket.php
+++ b/server/models/Ticket.php
@@ -90,17 +90,21 @@ class Ticket extends DataStore {
parent::store();
}
+ public function delete() {
+ parent::delete();
+ }
+
public function generateUniqueTicketNumber() {
$linearCongruentialGenerator = new LinearCongruentialGenerator();
- $ticketQuantity = Ticket::count();
- if ($ticketQuantity === 0) {
+ if (Ticket::count() === 0) {
$ticketNumber = Setting::getSetting('ticket-first-number')->value;
} else {
+ $lastTicketId = Ticket::findOne(' ORDER BY id DESC')->id;
$linearCongruentialGenerator->setGap(Setting::getSetting('ticket-gap')->value);
$linearCongruentialGenerator->setFirst(Setting::getSetting('ticket-first-number')->value);
- $ticketNumber = $linearCongruentialGenerator->generate($ticketQuantity);
+ $ticketNumber = $linearCongruentialGenerator->generate($lastTicketId + 1);
}
return $ticketNumber;
diff --git a/tests/init.rb b/tests/init.rb
index f4b8e84b..cd719892 100644
--- a/tests/init.rb
+++ b/tests/init.rb
@@ -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'
diff --git a/tests/scripts.rb b/tests/scripts.rb
index 50e0d8cb..64872afc 100644
--- a/tests/scripts.rb
+++ b/tests/scripts.rb
@@ -35,6 +35,17 @@ class Scripts
raise response['message']
end
end
+ def self.deleteStaff(staffId)
+ response = request('/staff/delete', {
+ staffId: staffId,
+ csrf_userid: $csrf_userid,
+ csrf_token: $csrf_token
+ })
+
+ if response['status'] === 'fail'
+ raise response['message']
+ end
+ end
def self.login(email = 'steve@jobs.com', password = 'custompassword', staff = false)
request('/user/logout')
diff --git a/tests/staff/assign-ticket.rb b/tests/staff/assign-ticket.rb
index 0af17f4b..64e612b4 100644
--- a/tests/staff/assign-ticket.rb
+++ b/tests/staff/assign-ticket.rb
@@ -31,10 +31,12 @@ describe '/staff/assign-ticket' do
(staff_ticket['ticket_id']).should.equal('1')
end
it 'should assign ticket if a staff choose another to assing a ticket ' do
+ staffId = $database.getRow('staff','ayra2@opensupports.com','email')['id']
+
ticket = $database.getRow('ticket', 3 , 'id')
result = request('/staff/assign-ticket', {
ticketNumber: ticket['ticket_number'],
- staffId:4,
+ staffId: staffId,
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
@@ -42,10 +44,9 @@ describe '/staff/assign-ticket' do
ticket = $database.getRow('ticket', 3 , 'id')
- (ticket['owner_id']).should.equal('4')
+ (ticket['owner_id']).should.equal(staffId)
(ticket['unread']).should.equal('1')
-
end
it 'should fail if ticket is already owned' do
diff --git a/tests/staff/delete.rb b/tests/staff/delete.rb
index 25ba48de..5bada355 100644
--- a/tests/staff/delete.rb
+++ b/tests/staff/delete.rb
@@ -1,28 +1,30 @@
describe'/staff/delete' do
request('/user/logout')
Scripts.login($staff[:email], $staff[:password], true)
+ @staffId = $database.getRow('staff','littlelannister@opensupports.com','email')['id']
it 'should delete staff member' do
result= request('/staff/delete', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
- staffId: 3
+ staffId: @staffId
})
(result['status']).should.equal('success')
- row = $database.getRow('staff', 3, 'id')
+ row = $database.getRow('staff', @staffId, 'id')
(row).should.equal(nil)
row = $database.getRow('department', 1, 'id')
(row['owners']).should.equal('3')
end
+
it 'should fail delete if staff member is does not exist' do
- result= request('/staff/delete', {
+ result = request('/staff/delete', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
- staffId: 3
+ staffId: @staffId
})
(result['status']).should.equal('fail')
@@ -31,4 +33,4 @@ describe'/staff/delete' do
row = $database.getRow('department', 1, 'id')
(row['owners']).should.equal('3')
end
-end
\ No newline at end of file
+end
diff --git a/tests/staff/edit.rb b/tests/staff/edit.rb
index 5c398936..f22bd6ac 100644
--- a/tests/staff/edit.rb
+++ b/tests/staff/edit.rb
@@ -3,23 +3,24 @@ describe'/staff/edit' do
Scripts.login($staff[:email], $staff[:password], true)
it 'should edit another staff member' do
+ staffId = $database.getRow('staff','tyrion@opensupports.com','email')['id']
result= request('/staff/edit', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
email: 'LittleLannister@opensupports.com',
level: 1,
departments: '[1, 2]',
- staffId: 3
+ staffId: staffId
})
(result['status']).should.equal('success')
- row = $database.getRow('staff', 3, 'id')
+ row = $database.getRow('staff', staffId, 'id')
(row['email']).should.equal('littlelannister@opensupports.com')
(row['level']).should.equal('1')
- rows = $database.getRow('department_staff', 3, 'staff_id')
+ rows = $database.getRow('department_staff', staffId, 'staff_id')
(rows['department_id']).should.equal('1')
@@ -28,7 +29,6 @@ describe'/staff/edit' do
row = $database.getRow('department', 2, 'id')
(row['owners']).should.equal('2')
-
end
it 'should edit staff member ' do
@@ -43,7 +43,7 @@ describe'/staff/edit' do
departments: '[1]'
})
- row = $database.getRow('staff', 'Arya Stark', 'name')
+ row = $database.getRow('staff', 'arya@opensupports.com', 'email')
result = request('/staff/edit', {
csrf_userid: $csrf_userid,
diff --git a/tests/staff/get-all.rb b/tests/staff/get-all.rb
index 6e1070d6..5f3d3267 100644
--- a/tests/staff/get-all.rb
+++ b/tests/staff/get-all.rb
@@ -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')
diff --git a/tests/staff/get-new-tickets.rb b/tests/staff/get-new-tickets.rb
index debe36f0..7561aa1b 100644
--- a/tests/staff/get-new-tickets.rb
+++ b/tests/staff/get-new-tickets.rb
@@ -3,14 +3,12 @@ describe '/staff/get-new-tickets' do
Scripts.login($staff[:email], $staff[:password], true)
it 'should get news tickets' do
-
result = request('/staff/get-new-tickets', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token
})
(result['status']).should.equal('success')
- (result['data'].size).should.equal(8)
-
+ (result['data'].size).should.equal(9)
end
end
diff --git a/tests/staff/get-tickets.rb b/tests/staff/get-tickets.rb
index cd896a6b..af0bce51 100644
--- a/tests/staff/get-tickets.rb
+++ b/tests/staff/get-tickets.rb
@@ -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
diff --git a/tests/staff/get.rb b/tests/staff/get.rb
index 6470ea25..b4d0cef5 100644
--- a/tests/staff/get.rb
+++ b/tests/staff/get.rb
@@ -16,10 +16,11 @@ describe '/staff/get/' do
(result['data']['sendEmailOnNewTicket']).should.equal('1')
end
it 'should return staff member data with staff Id' do
+ staff = $database.getRow('staff','tyrion@opensupports.com','email')
result = request('/staff/get', {
csrf_userid: $csrf_userid,
csrf_token: $csrf_token,
- staffId: 3
+ staffId: staff['id']
})
(result['status']).should.equal('success')
@@ -29,4 +30,4 @@ describe '/staff/get/' do
(result['data']['level']).should.equal('2')
(result['data']['sendEmailOnNewTicket']).should.equal('0')
end
-end
\ No newline at end of file
+end
diff --git a/tests/system/disable-user-system.rb b/tests/system/disable-user-system.rb
index e96adb56..703a71b4 100644
--- a/tests/system/disable-user-system.rb
+++ b/tests/system/disable-user-system.rb
@@ -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(40)
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(41)
end
diff --git a/tests/ticket/delete.rb b/tests/ticket/delete.rb
new file mode 100644
index 00000000..6b0c5acf
--- /dev/null
+++ b/tests/ticket/delete.rb
@@ -0,0 +1,114 @@
+describe '/ticket/delete' do
+
+ it 'should delete ticket if it is not assigned and is logged a staff lvl 3 ' do
+ request('/user/logout')
+ Scripts.login($staff[:email], $staff[:password], true)
+ Scripts.createTicket('ticket_to_delete')
+ ticket = $database.getRow('ticket', 'ticket_to_delete', '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('ticket_to_delete_2')
+ ticket = $database.getRow('ticket', 'ticket_to_delete_2', 'title');
+ result = request('/ticket/delete', {
+ ticketNumber: ticket['ticket_number'],
+ csrf_userid: $csrf_userid,
+ csrf_token: $csrf_token
+ })
+ (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('ticket_to_delete_3')
+ ticket = $database.getRow('ticket', 'ticket_to_delete_3', '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')
+ (result['message']).should.equal('NO_PERMISSION')
+ 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)
+ Scripts.createTicket('ticket_to_delete_4')
+
+ ticket = $database.getRow('ticket', 'ticket_to_delete_4', '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')
+ (result['message']).should.equal('NO_PERMISSION')
+
+ request('/user/logout')
+ Scripts.login($staff[:email], $staff[:password], true)
+ staff = $database.getRow('staff', 'ned@opensupports.com', 'email')
+ Scripts.deleteStaff(staff['id'])
+
+ staff = $database.getRow('staff', 'uselessstaff@opensupports.com', 'email')
+ Scripts.deleteStaff(staff['id'])
+ end
+end
diff --git a/tests/user/get-users-test.rb b/tests/user/get-users-test.rb
index a9049dac..b20bbec1 100644
--- a/tests/user/get-users-test.rb
+++ b/tests/user/get-users-test.rb
@@ -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