mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
@@ -0,0 +1,57 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
} from '../../../../helpers/api-v3-integration.helper';
|
||||||
|
|
||||||
|
describe('GET /export/inbox.html', () => {
|
||||||
|
let user;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
let otherUser = await generateUser({
|
||||||
|
'profile.name': 'Other User',
|
||||||
|
});
|
||||||
|
user = await generateUser({
|
||||||
|
'profile.name': 'Main User',
|
||||||
|
});
|
||||||
|
|
||||||
|
await otherUser.post('/members/send-private-message', {
|
||||||
|
toUserId: user.id,
|
||||||
|
message: ':smile: hi',
|
||||||
|
});
|
||||||
|
await user.post('/members/send-private-message', {
|
||||||
|
toUserId: otherUser.id,
|
||||||
|
message: '# Hello!',
|
||||||
|
});
|
||||||
|
await otherUser.post('/members/send-private-message', {
|
||||||
|
toUserId: user.id,
|
||||||
|
message: '* list 1\n* list 2\n * list 3 \n * [list with a link](http://example.com)',
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.sync();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an html page', async () => {
|
||||||
|
let res = await user.get('/export/inbox.html');
|
||||||
|
|
||||||
|
expect(res.substring(0, 100).indexOf('<!DOCTYPE html>')).to.equal(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the markdown messages as html', async () => {
|
||||||
|
let res = await user.get('/export/inbox.html');
|
||||||
|
|
||||||
|
expect(res).to.include('img class="habitica-emoji"');
|
||||||
|
expect(res).to.include('<h1>Hello!</h1>');
|
||||||
|
expect(res).to.include('<li>list 1</li>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sorts messages from newest to oldest', async () => {
|
||||||
|
let res = await user.get('/export/inbox.html');
|
||||||
|
|
||||||
|
let emojiPosition = res.indexOf('img class="habitica-emoji"');
|
||||||
|
let headingPosition = res.indexOf('<h1>Hello!</h1>');
|
||||||
|
let listPosition = res.indexOf('<li>list 1</li>');
|
||||||
|
|
||||||
|
expect(emojiPosition).to.be.greaterThan(headingPosition);
|
||||||
|
expect(headingPosition).to.be.greaterThan(listPosition);
|
||||||
|
expect(listPosition).to.be.greaterThan(-1); // make sure it exists at all
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -200,5 +200,10 @@
|
|||||||
"onlyGroupTasksCanBeAssigned": "Only group tasks can be assigned",
|
"onlyGroupTasksCanBeAssigned": "Only group tasks can be assigned",
|
||||||
"newChatMessagePlainNotification": "New message in <%= groupName %> by <%= authorName %>. Click here to open the chat page!",
|
"newChatMessagePlainNotification": "New message in <%= groupName %> by <%= authorName %>. Click here to open the chat page!",
|
||||||
"newChatMessageTitle": "New message in <%= groupName %>",
|
"newChatMessageTitle": "New message in <%= groupName %>",
|
||||||
|
"exportInbox": "Export Messages",
|
||||||
|
"exportInboxPopoverTitle": "Export your messages as HTML",
|
||||||
|
"exportInboxPopoverBody": "HTML allows easy reading of messages in a browser. For a machine-readable format, use Data > Export Data",
|
||||||
|
"to": "To:",
|
||||||
|
"from": "From:",
|
||||||
"desktopNotificationsText": "We need your permission to enable desktop notifications for new messages in party chat! Follow your browser's instructions to turn them on.<br><br>You'll receive these notifications only while you have Habitica open. If you decide you don't like them, they can be disabled in your browser's settings.<br><br>This box will close automatically when a decision is made."
|
"desktopNotificationsText": "We need your permission to enable desktop notifications for new messages in party chat! Follow your browser's instructions to turn them on.<br><br>You'll receive these notifications only while you have Habitica open. If you decide you don't like them, they can be disabled in your browser's settings.<br><br>This box will close automatically when a decision is made."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import nconf from 'nconf';
|
|||||||
import got from 'got';
|
import got from 'got';
|
||||||
import Bluebird from 'bluebird';
|
import Bluebird from 'bluebird';
|
||||||
import locals from '../../middlewares/locals';
|
import locals from '../../middlewares/locals';
|
||||||
|
import md from 'habitica-markdown';
|
||||||
import {
|
import {
|
||||||
S3,
|
S3,
|
||||||
} from '../../libs/aws';
|
} from '../../libs/aws';
|
||||||
@@ -243,4 +244,59 @@ api.exportUserAvatarPng = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {get} /export/inbox.html Export user private messages as HTML document
|
||||||
|
* @apiName ExportUserPrivateMessages
|
||||||
|
* @apiGroup DataExport
|
||||||
|
* @apiDescription NOTE: Part of the private API that may change at any time.
|
||||||
|
*
|
||||||
|
* @apiSuccess {String} An html page
|
||||||
|
*/
|
||||||
|
api.exportUserPrivateMessages = {
|
||||||
|
method: 'GET',
|
||||||
|
url: '/export/inbox.html',
|
||||||
|
middlewares: [authWithSession],
|
||||||
|
async handler (req, res) {
|
||||||
|
let user = res.locals.user;
|
||||||
|
|
||||||
|
const timezoneOffset = user.preferences.timezoneOffset;
|
||||||
|
const dateFormat = user.preferences.dateFormat.toUpperCase();
|
||||||
|
const TO = res.t('to');
|
||||||
|
const FROM = res.t('from');
|
||||||
|
|
||||||
|
let inbox = Object.keys(user.inbox.messages).map(key => user.inbox.messages[key]);
|
||||||
|
|
||||||
|
inbox = _.sortBy(inbox, function sortBy (num) {
|
||||||
|
return num.sort * -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
let messages = '<!DOCTYPE html><html><head></head><body>';
|
||||||
|
|
||||||
|
inbox.forEach((message, index) => {
|
||||||
|
let recipientLabel = message.sent ? TO : FROM;
|
||||||
|
let messageUser = message.user;
|
||||||
|
let timestamp = moment.utc(message.timestamp).zone(timezoneOffset).format(`${dateFormat} HH:mm:ss`);
|
||||||
|
let text = md.render(message.text);
|
||||||
|
index = `(${index + 1}/${inbox.length})`;
|
||||||
|
messages += `
|
||||||
|
<p>
|
||||||
|
${recipientLabel} <strong>${messageUser}</strong> ${timestamp}
|
||||||
|
${index}
|
||||||
|
<br />
|
||||||
|
${text}
|
||||||
|
</p>
|
||||||
|
<hr />`;
|
||||||
|
});
|
||||||
|
|
||||||
|
messages += '</body></html>';
|
||||||
|
|
||||||
|
res.set({
|
||||||
|
'Content-Type': 'text/html',
|
||||||
|
'Content-disposition': 'attachment; filename=inbox.html',
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).send(messages);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = api;
|
module.exports = api;
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ script(type='text/ng-template', id='partials/options.social.inbox.html')
|
|||||||
.form-inline
|
.form-inline
|
||||||
a.btn.btn-xs.btn-danger(ng-click='deleteAllMessages()')=env.t('clearAll')
|
a.btn.btn-xs.btn-danger(ng-click='deleteAllMessages()')=env.t('clearAll')
|
||||||
|
|
|
|
||||||
|
a.btn.btn-xs.btn-default(href='/export/inbox.html', popover=env.t('exportInboxPopoverBody'),
|
||||||
|
popover-title=env.t('exportInboxPopoverTitle'),
|
||||||
|
popover-trigger='mouseenter', popover-placement='right',
|
||||||
|
popover-append-to-body='true')=env.t('exportInbox')
|
||||||
|
|
|
||||||
.checkbox
|
.checkbox
|
||||||
label
|
label
|
||||||
input(type='checkbox', ng-model='user.inbox.optOut', ng-change='set({"inbox.optOut": user.inbox.optOut?true: false})')
|
input(type='checkbox', ng-model='user.inbox.optOut', ng-change='set({"inbox.optOut": user.inbox.optOut?true: false})')
|
||||||
|
|||||||
Reference in New Issue
Block a user