Upgrade web view system with auto timeout
This commit is contained in:
parent
44a1200084
commit
50d9c78b45
|
@ -194,9 +194,8 @@ export const onWorkerComplete = async (workerMessage: MessageEvent<SolvedRoll>,
|
||||||
const respMessage: Embed[] = [
|
const respMessage: Embed[] = [
|
||||||
{
|
{
|
||||||
color: infoColor1,
|
color: infoColor1,
|
||||||
description: `This message contains information for a previous roll.\nPlease click on "<@${botId}> *Click to see attachment*" above this message to see the previous roll.
|
description: `**This message contains information for a previous roll.**
|
||||||
|
Please click on "<@${botId}> *Click to see attachment*" above this message to see the previous roll.`,
|
||||||
As anyone with the Web View link can view the roll, Web View is disabled by default for privacy. Click the button below to enable Web View and generate a link for this roll.`,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -292,8 +292,22 @@ export const toggleWebView = (attachmentMessage: DiscordenoMessage, ownerId: str
|
||||||
...attachmentMessage.embeds[0],
|
...attachmentMessage.embeds[0],
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'Web View:',
|
name: 'Web View Link:',
|
||||||
value: enableWebView ? `[Open Web View](${config.api.publicDomain}api/webview?c=${attachmentMessage.channelId}&m=${attachmentMessage.id})` : `Web View is ${disabledStr}.`,
|
value: enableWebView
|
||||||
|
? `[Open Web View](${config.api.publicDomain}api/webview?c=${attachmentMessage.channelId}&m=${attachmentMessage.id}#${new Date().getTime()}#${ownerId})`
|
||||||
|
: `Web View is ${disabledStr}.\n- Click the button below to enable Web View and generate a link for this roll.`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: enableWebView ? 'Web View Status:' : 'What is Web View?',
|
||||||
|
value: enableWebView
|
||||||
|
? `For privacy, Web View will automatically time out on this roll <t:${
|
||||||
|
Math.floor(
|
||||||
|
(new Date().getTime() + 1_000 * 60 * 60) / 1000,
|
||||||
|
)
|
||||||
|
}:R>. The link will still show on this message after it has timed out, so clicking on the link after it has been timed out will show an error and remove the link.`
|
||||||
|
: '- Web View is a system for viewing extremely large or complex rolls with full formatting.\n- As anyone with the Web View link can view the roll, Web View is disabled by default for privacy.',
|
||||||
|
inline: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { STATUS_CODE, STATUS_TEXT } from '@std/http/status';
|
||||||
|
|
||||||
import config from '~config';
|
import config from '~config';
|
||||||
|
|
||||||
import { disabledStr } from 'artigen/utils/embeds.ts';
|
import { disabledStr, toggleWebView } from 'artigen/utils/embeds.ts';
|
||||||
|
|
||||||
import utils from 'utils/utils.ts';
|
import utils from 'utils/utils.ts';
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ interface ModernUserHOTFIX extends User {
|
||||||
const converter = new showdown.Converter({
|
const converter = new showdown.Converter({
|
||||||
emoji: true,
|
emoji: true,
|
||||||
underline: true,
|
underline: true,
|
||||||
|
openLinksInNewWindow: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Utilize the pre-existing stylesheets, do a little tweaking to make it ours
|
// Utilize the pre-existing stylesheets, do a little tweaking to make it ours
|
||||||
|
@ -71,13 +72,39 @@ font-weight: 900;
|
||||||
${str}
|
${str}
|
||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`;
|
||||||
|
|
||||||
|
const headerHeight = '3rem';
|
||||||
|
const wrapHeader = (
|
||||||
|
str: string,
|
||||||
|
) =>
|
||||||
|
`<header id="fileBtns" style="display: flex; align-items: center; height: ${headerHeight}; line-height: ${headerHeight}; font-size: 1.5rem;">
|
||||||
|
<a href="https://discord.burne99.com/TheArtificer/" target="_blank" rel="noopener">${config.name} Roll Web View</a>
|
||||||
|
${str}
|
||||||
|
</header>`;
|
||||||
const centerHTML = (str: string) => `<center>${str}</center>`;
|
const centerHTML = (str: string) => `<center>${str}</center>`;
|
||||||
|
|
||||||
const badRequestMD = '# Invalid URL for Web View!';
|
const badRequestHTML = wrapBasic(`${wrapHeader('')}${centerHTML(converter.makeHtml('# Invalid URL for Web View!'))}`);
|
||||||
const badRequestHTML = wrapBasic(centerHTML(converter.makeHtml(badRequestMD)));
|
const badMessageHTML = wrapBasic(
|
||||||
|
`${wrapHeader('')}${
|
||||||
|
centerHTML(
|
||||||
|
converter.makeHtml(`# Discord Attachment message malformed or corrupt!
|
||||||
|
Not sure how this happened, but Web View was unable to read the required data to generate the formatted output.`),
|
||||||
|
)
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
const notAuthorizedHTML = wrapBasic(`${wrapHeader('')}${centerHTML(converter.makeHtml('# Web View is Disabled for this roll!'))}`);
|
||||||
|
|
||||||
const notAuthorizedMD = '# Web View is Disabled for this roll!';
|
const oldHTML = (guildId: bigint | string, channelId: bigint, messageId: bigint) =>
|
||||||
const notAuthorizedHTML = wrapBasic(centerHTML(converter.makeHtml(notAuthorizedMD)));
|
wrapBasic(
|
||||||
|
`${wrapHeader('')}${
|
||||||
|
centerHTML(
|
||||||
|
converter.makeHtml(`# Web View has been Disabled for this roll!
|
||||||
|
For privacy, Web View automatically disables itself 1 hour after being enabled.
|
||||||
|
|
||||||
|
Need to see this roll in Web View again? Head back to [this message](https://discord.com/channels/${guildId}/${channelId}/${messageId}) and click the \`Enable Web View\` button.`),
|
||||||
|
)
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
|
||||||
const failedToGetAttachmentMD = '# Failed to get attachment from Discord!';
|
const failedToGetAttachmentMD = '# Failed to get attachment from Discord!';
|
||||||
const failedToGetAttachmentHTML = wrapBasic(centerHTML(converter.makeHtml(failedToGetAttachmentMD)));
|
const failedToGetAttachmentHTML = wrapBasic(centerHTML(converter.makeHtml(failedToGetAttachmentMD)));
|
||||||
|
@ -87,23 +114,21 @@ interface HtmlResp {
|
||||||
html: string;
|
html: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerHeight = '3rem';
|
|
||||||
const generatePage = (files: HtmlResp[]): string =>
|
const generatePage = (files: HtmlResp[]): string =>
|
||||||
wrapBasic(`<header id="fileBtns" style="display: flex; align-items: center; height: ${headerHeight}; line-height: ${headerHeight}; font-size: 1.5rem;">
|
wrapBasic(`${
|
||||||
<a href="https://discord.burne99.com/TheArtificer/" target="_blank" rel="noopener">${config.name} Roll Web View</a>
|
wrapHeader(`<span style="margin-left: auto; font-family: 'Play', sans-serif; font-size: 1rem;">Available Files:</span>
|
||||||
<span style="margin-left: auto; font-family: 'Play', sans-serif; font-size: 1rem;">Available Files:</span>
|
|
||||||
${
|
${
|
||||||
files
|
files
|
||||||
.map(
|
.map(
|
||||||
(f, idx) =>
|
(f, idx) =>
|
||||||
`<button style="margin-left: 1rem;" id="${f.name}-btn" class="${
|
`<button style="margin-left: 1rem;" id="${f.name}-btn" class="${
|
||||||
idx === 0 ? 'selected' : ''
|
idx === 0 ? 'selected' : ''
|
||||||
}" onclick="for (var child of document.getElementById('fileBody').children) {child.style.display = 'none'} document.getElementById('${f.name}').style.display = 'block'; for (var child of document.getElementById('fileBtns').children) {child.className = ''} document.getElementById('${f.name}-btn').className = 'selected';">${f.name}</button>`,
|
}" onclick="for (var child of document.getElementById('fileBody').children) {child.style.display = 'none'} document.getElementById('${f.name}').style.display = 'block'; for (var child of document.getElementById('fileBtns').children) {child.className = ''} document.getElementById('${f.name}-btn').className = 'selected';">${f.name}</button>`,
|
||||||
)
|
)
|
||||||
.join('')
|
.join('')
|
||||||
|
}
|
||||||
|
<button style="margin-left: auto;" onclick="document.getElementById('fileBody').style.whiteSpace = (document.getElementById('fileBody').style.whiteSpace === 'pre' ? 'pre-wrap' : 'pre')">Toggle Word Wrap</button>`)
|
||||||
}
|
}
|
||||||
<button style="margin-left: auto;" onclick="document.getElementById('fileBody').style.whiteSpace = (document.getElementById('fileBody').style.whiteSpace === 'pre' ? 'pre-wrap' : 'pre')">Toggle Word Wrap</button>
|
|
||||||
</header>
|
|
||||||
<div id="fileBody" style="height: calc(100vh - ${headerHeight}); margin: 0 0.5rem; overflow: auto; white-space: pre-wrap; font-family: 'Roboto', sans-serif; font-weight: 300;">
|
<div id="fileBody" style="height: calc(100vh - ${headerHeight}); margin: 0 0.5rem; overflow: auto; white-space: pre-wrap; font-family: 'Roboto', sans-serif; font-weight: 300;">
|
||||||
${files.map((f, idx) => `<div id="${f.name}" style="display: ${idx === 0 ? 'block' : 'none'};">${f.html}</div>`).join('')}
|
${files.map((f, idx) => `<div id="${f.name}" style="display: ${idx === 0 ? 'block' : 'none'};">${f.html}</div>`).join('')}
|
||||||
</div>`);
|
</div>`);
|
||||||
|
@ -149,11 +174,19 @@ export const generateWebView = async (query: Map<string, string>): Promise<Respo
|
||||||
|
|
||||||
const attachmentMessage = await getMessage(channelId, messageId).catch((e) => utils.commonLoggers.messageGetError('webView.ts:23', channelId, messageId, e));
|
const attachmentMessage = await getMessage(channelId, messageId).catch((e) => utils.commonLoggers.messageGetError('webView.ts:23', channelId, messageId, e));
|
||||||
const discordAttachments = attachmentMessage?.attachments ?? [];
|
const discordAttachments = attachmentMessage?.attachments ?? [];
|
||||||
const embed = attachmentMessage?.embeds.shift();
|
const embed = attachmentMessage?.embeds[0];
|
||||||
const webViewField = embed?.fields?.shift();
|
|
||||||
|
|
||||||
if (!attachmentMessage || discordAttachments.length === 0 || !embed || !webViewField) {
|
if (!attachmentMessage || discordAttachments.length === 0 || !embed || !embed.fields?.length) {
|
||||||
return new Response(badRequestHTML, {
|
return new Response(badMessageHTML, {
|
||||||
|
status: STATUS_CODE.BadRequest,
|
||||||
|
statusText: STATUS_TEXT[STATUS_CODE.BadRequest],
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const webViewField = embed.fields[0];
|
||||||
|
if (!webViewField.value) {
|
||||||
|
return new Response(badMessageHTML, {
|
||||||
status: STATUS_CODE.BadRequest,
|
status: STATUS_CODE.BadRequest,
|
||||||
statusText: STATUS_TEXT[STATUS_CODE.BadRequest],
|
statusText: STATUS_TEXT[STATUS_CODE.BadRequest],
|
||||||
headers,
|
headers,
|
||||||
|
@ -168,6 +201,27 @@ export const generateWebView = async (query: Map<string, string>): Promise<Respo
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hashParts = webViewField.value.replaceAll(')', '').split('#');
|
||||||
|
const webViewAge = parseInt(hashParts[1] ?? '0');
|
||||||
|
const ownerId = hashParts[2];
|
||||||
|
if (!ownerId || !webViewAge) {
|
||||||
|
return new Response(badMessageHTML, {
|
||||||
|
status: STATUS_CODE.BadRequest,
|
||||||
|
statusText: STATUS_TEXT[STATUS_CODE.BadRequest],
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const allowedAge = new Date().getTime() - 1_000 * 60 * 60;
|
||||||
|
if (webViewAge < allowedAge) {
|
||||||
|
toggleWebView(attachmentMessage, ownerId, false);
|
||||||
|
return new Response(oldHTML(attachmentMessage.guildId || '@me', attachmentMessage.channelId, attachmentMessage.id), {
|
||||||
|
status: STATUS_CODE.Gone,
|
||||||
|
statusText: STATUS_TEXT[STATUS_CODE.Gone],
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const htmlArr: HtmlResp[] = [];
|
const htmlArr: HtmlResp[] = [];
|
||||||
for (const discordAttachment of discordAttachments) {
|
for (const discordAttachment of discordAttachments) {
|
||||||
const attachment = await fetch(discordAttachment.url).catch((e) => log(LT.LOG, `Failed to get attachment: ${discordAttachment}`, e));
|
const attachment = await fetch(discordAttachment.url).catch((e) => log(LT.LOG, `Failed to get attachment: ${discordAttachment}`, e));
|
||||||
|
|
Loading…
Reference in New Issue