refs #5941 feat: when error can send email to support #1670
|
@ -0,0 +1,63 @@
|
||||||
|
const smtp = require('vn-print/core/smtp');
|
||||||
|
const config = require('vn-print/core/config');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('sendToSupport', {
|
||||||
|
description: 'Send mail to support',
|
||||||
|
accessType: 'WRITE',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'reason',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The reason'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'additionalData',
|
||||||
|
type: 'object',
|
||||||
|
required: true,
|
||||||
|
description: 'The additional data'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/send-to-support`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.sendToSupport = async(ctx, reason, additionalData) => {
|
||||||
|
const emailUser =
|
||||||
|
await Self.app.models.EmailUser.findById(ctx.req.accessToken.userId, {fields: ['email']});
|
||||||
|
|
||||||
|
let html = `<strong>Motivo</strong>:<br/>${reason}<br/>`;
|
||||||
|
|
||||||
|
for (const data in additionalData)
|
||||||
|
html += `<strong>${data}</strong>:<br/>${tryParse(additionalData[data])}<br/>`;
|
||||||
|
|
||||||
|
const subjectReason = JSON.parse(additionalData?.httpRequest)?.data?.error;
|
||||||
|
smtp.send({
|
||||||
|
to: config.app.reportEmail,
|
||||||
|
replyTo: emailUser.email,
|
||||||
|
subject:
|
||||||
|
'[Support-Salix] ' +
|
||||||
|
additionalData?.frontPath + ' ' +
|
||||||
|
subjectReason?.name + ':' +
|
||||||
|
subjectReason?.message,
|
||||||
|
html
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function tryParse(value) {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
value = JSON.parse(value);
|
||||||
|
} catch {}
|
||||||
|
return JSON.stringify(value, null, ' ').split('\n').join('<br>');
|
||||||
|
} catch {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,4 +1,5 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/osticket/osTicketReportEmail')(Self);
|
require('../methods/osticket/osTicketReportEmail')(Self);
|
||||||
require('../methods/osticket/closeTicket')(Self);
|
require('../methods/osticket/closeTicket')(Self);
|
||||||
|
require('../methods/osticket/sendToSupport')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,3 +55,4 @@ import './datalist';
|
||||||
import './contextmenu';
|
import './contextmenu';
|
||||||
import './rating';
|
import './rating';
|
||||||
import './smart-table';
|
import './smart-table';
|
||||||
|
import './support-dialog';
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
<div id="shapes"></div>
|
<div id="shapes"></div>
|
||||||
|
<vn-support-dialog
|
||||||
|
vn-id="support-dialog"
|
||||||
|
additional-data="$ctrl.additionalData">
|
||||||
|
</vn-support-dialog>
|
||||||
|
|
|
@ -27,6 +27,18 @@ export default class Controller extends Component {
|
||||||
setTimeout(() => element.classList.add('shown'), 30);
|
setTimeout(() => element.classList.add('shown'), 30);
|
||||||
shape.element = element;
|
shape.element = element;
|
||||||
|
|
||||||
|
if (data.additionalData) {
|
||||||
|
this.additionalData = data.additionalData;
|
||||||
|
let supportButton = document.createElement('i');
|
||||||
|
supportButton.setAttribute('class', 'material-icons clickable');
|
||||||
|
supportButton.addEventListener('click', () => this.$.supportDialog.show());
|
||||||
|
element.appendChild(supportButton);
|
||||||
|
|
||||||
|
let buttonIcon = 'support_agent';
|
||||||
|
buttonIcon = document.createTextNode(buttonIcon);
|
||||||
|
supportButton.appendChild(buttonIcon);
|
||||||
|
}
|
||||||
|
|
||||||
if (shape.type)
|
if (shape.type)
|
||||||
element.classList.add(shape.type);
|
element.classList.add(shape.type);
|
||||||
|
|
||||||
|
@ -95,7 +107,7 @@ export default class Controller extends Component {
|
||||||
|
|
||||||
clearTimeout(shape.hideTimeout);
|
clearTimeout(shape.hideTimeout);
|
||||||
shape.hideTimeout = setTimeout(
|
shape.hideTimeout = setTimeout(
|
||||||
() => this.hide(shape), shape.timeout || 3000);
|
() => this.hide(shape), shape.timeout || 5000);
|
||||||
|
|
||||||
this.lastShape = shape;
|
this.lastShape = shape;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,15 @@ vn-snackbar .shape {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 12px 25px 12px 12px;
|
padding: 12px 25px 12px 12px;
|
||||||
|
display: flex ;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
& > .text {
|
& > .text {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
vn-chip {
|
vn-chip {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -16px;
|
left: -16px;
|
||||||
top: -16px;
|
top: -16px;
|
||||||
|
@ -64,4 +68,12 @@ vn-snackbar .shape {
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0
|
right: 0
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
.clickable{
|
||||||
|
background-color: $color-main;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<tpl-body>
|
||||||
|
<section>
|
||||||
|
<h5 class="vn-py-sm" translate>Send cau</h5>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-textarea vn-one
|
||||||
|
label="ExplainReason"
|
||||||
|
ng-model="$ctrl.reason"
|
||||||
|
rows="2"
|
||||||
|
required="true">
|
||||||
|
</vn-textarea>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal>
|
||||||
|
<span>
|
||||||
|
{{'By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.' | translate}}
|
||||||
|
</span>
|
||||||
|
</vn-horizontal>
|
||||||
|
</section>
|
||||||
|
</tpl-body>
|
||||||
|
<tpl-buttons>
|
||||||
|
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||||
|
<button response="accept" translate>Send</button>
|
||||||
|
</tpl-buttons>
|
|
@ -0,0 +1,27 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import Dialog from '../dialog';
|
||||||
|
|
||||||
|
export default class Controller extends Dialog {
|
||||||
|
constructor($element, $, $transclude) {
|
||||||
|
super($element, $, $transclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
responseHandler(response) {
|
||||||
|
this.$http.post('Ostickets/send-to-support', {
|
||||||
|
reason: this.reason,
|
||||||
|
additionalData: this.additionalData
|
||||||
|
})
|
||||||
|
.then(() => super.responseHandler(response))
|
||||||
|
.then(() => this.vnApp.showSuccess(this.$t('Email sended!')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.$inject = ['$element', '$scope', '$transclude'];
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnSupportDialog', {
|
||||||
|
slotTemplate: require('./index.html'),
|
||||||
|
controller: Controller,
|
||||||
|
bindings: {
|
||||||
|
additionalData: '<?'
|
||||||
|
}
|
||||||
|
});
|
|
@ -13,4 +13,5 @@ Finalize: Finalize
|
||||||
Previous: Back
|
Previous: Back
|
||||||
Load more: Load more
|
Load more: Load more
|
||||||
Auto-scroll interrupted, please adjust the search: Auto-scroll interrupted, please adjust the search
|
Auto-scroll interrupted, please adjust the search: Auto-scroll interrupted, please adjust the search
|
||||||
General search: General search
|
General search: General search
|
||||||
|
ExplainReason: Explain the reason why this error should not occur
|
||||||
|
|
|
@ -64,3 +64,6 @@ No results found: Sin resultados
|
||||||
No data: Sin datos
|
No data: Sin datos
|
||||||
Undo changes: Deshacer cambios
|
Undo changes: Deshacer cambios
|
||||||
Load more results: Cargar más resultados
|
Load more results: Cargar más resultados
|
||||||
|
Send cau: Enviar cau
|
||||||
|
By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc
|
||||||
|
ExplainReason: Explique el motivo por el que no deberia aparecer este fallo
|
||||||
|
|
|
@ -23,9 +23,9 @@ export default class App {
|
||||||
this.logger.showSuccess(message);
|
this.logger.showSuccess(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
showError(message) {
|
showError(message, additionalData) {
|
||||||
if (this.logger)
|
if (this.logger)
|
||||||
this.logger.showError(message);
|
this.logger.showError(message, additionalData);
|
||||||
}
|
}
|
||||||
|
|
||||||
pushLoader() {
|
pushLoader() {
|
||||||
|
|
|
@ -25,15 +25,15 @@ export default class App extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessage(message) {
|
showMessage(message) {
|
||||||
this.$.snackbar.show({message: message});
|
this.$.snackbar.show({message});
|
||||||
}
|
}
|
||||||
|
|
||||||
showSuccess(message) {
|
showSuccess(message) {
|
||||||
this.$.snackbar.showSuccess({message: message});
|
this.$.snackbar.showSuccess({message});
|
||||||
}
|
}
|
||||||
|
|
||||||
showError(message) {
|
showError(message, additionalData) {
|
||||||
this.$.snackbar.showError({message: message});
|
this.$.snackbar.showError({message, additionalData});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,13 @@ function $exceptionHandler(vnApp, $window, $state, $injector) {
|
||||||
|
|
||||||
if (messageT)
|
if (messageT)
|
||||||
message = $translate.instant(messageT);
|
message = $translate.instant(messageT);
|
||||||
vnApp.showError(message);
|
|
||||||
|
const additonalData = {
|
||||||
|
frontPath: $state.current.name,
|
||||||
|
httpRequest: cause?.replace('Possibly unhandled rejection: ', ''),
|
||||||
|
backError: exception
|
||||||
|
};
|
||||||
|
vnApp.showError(message, additonalData);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
ngModule.factory('$exceptionHandler', $exceptionHandler);
|
ngModule.factory('$exceptionHandler', $exceptionHandler);
|
||||||
|
|
Loading…
Reference in New Issue