diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 88913f429..74360d57f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2991,9 +2991,6 @@ packages: formidable@3.5.2: resolution: {integrity: sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==} - formidable@3.5.2: - resolution: {integrity: sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==} - forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -7713,12 +7710,6 @@ snapshots: hexoid: 2.0.0 once: 1.4.0 - formidable@3.5.2: - dependencies: - dezalgo: 1.0.4 - hexoid: 2.0.0 - once: 1.4.0 - forwarded@0.2.0: {} fresh@0.5.2: {} diff --git a/src/locales/de.json b/src/locales/de.json index 92e203ef2..f0d333abb 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -82,7 +82,9 @@ "pad.settings.colorcheck": "Autorenfarben anzeigen", "pad.settings.linenocheck": "Zeilennummern", "pad.settings.rtlcheck": "Inhalt von rechts nach links lesen?", - "pad.settings.fontType": "Schriftart:", + "pad.settings.delete": "Pad löschen", + "pad.delete.confirm": "Möchtest du dieses Pad wirklich löschen?", + "pad.settings.fontType": "Schriftart:", "pad.settings.fontType.normal": "Normal", "pad.settings.language": "Sprache:", "pad.settings.about": "Über", diff --git a/src/locales/en.json b/src/locales/en.json index 5737fab00..5305a7025 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -72,6 +72,8 @@ "pad.settings.fontType": "Font type:", "pad.settings.fontType.normal": "Normal", "pad.settings.language": "Language:", + "pad.settings.deletePad": "Delete Pad", + "pad.delete.confirm": "Do you really want to delete this pad?", "pad.settings.about": "About", "pad.settings.poweredBy": "Powered by", diff --git a/src/node/handler/PadMessageHandler.ts b/src/node/handler/PadMessageHandler.ts index 9f1c9e86b..ca5e7e6e2 100644 --- a/src/node/handler/PadMessageHandler.ts +++ b/src/node/handler/PadMessageHandler.ts @@ -43,7 +43,7 @@ import {RateLimiterMemory} from 'rate-limiter-flexible'; import {ChangesetRequest, PadUserInfo, SocketClientRequest} from "../types/SocketClientRequest"; import {APool, AText, PadAuthor, PadType} from "../types/PadType"; import {ChangeSet} from "../types/ChangeSet"; -import {ChatMessageMessage, ClientReadyMessage, ClientSaveRevisionMessage, ClientSuggestUserName, ClientUserChangesMessage, ClientVarMessage, CustomMessage, UserNewInfoMessage} from "../../static/js/types/SocketIOMessage"; +import {ChatMessageMessage, ClientReadyMessage, ClientSaveRevisionMessage, ClientSuggestUserName, ClientUserChangesMessage, ClientVarMessage, CustomMessage, PadDeleteMessage, UserNewInfoMessage} from "../../static/js/types/SocketIOMessage"; import {Builder} from "../../static/js/Builder"; const webaccess = require('../hooks/express/webaccess'); const { checkValidRev } = require('../utils/checkValidRev'); @@ -211,6 +211,45 @@ exports.handleDisconnect = async (socket:any) => { }); }; + +const handlePadDelete = async (socket: any, padDeleteMessage: PadDeleteMessage) => { + const session = sessioninfos[socket.id]; + if (!session || !session.author || !session.padId) throw new Error('session not ready'); + if (await padManager.doesPadExist(padDeleteMessage.data.padId)) { + const retrievedPad = await padManager.getPad(padDeleteMessage.data.padId) + // Only the one doing the first revision can delete the pad, otherwise people could troll a lot + const firstContributor = await retrievedPad.getRevisionAuthor(0) + if (session.author === firstContributor) { + retrievedPad.remove() + } else { + + type ShoutMessage = { + message: string, + sticky: boolean, + } + + const messageToShout: ShoutMessage = { + message: 'You are not the creator of this pad, so you cannot delete it', + sticky: false + } + const messageToSend = { + type: "COLLABROOM", + data: { + type: "shoutMessage", + payload: { + message: messageToShout, + timestamp: Date.now() + } + } + } + socket.emit('shout', + messageToSend + ) + } + } +} + + /** * Handles a message from a user * @param socket the socket.io Socket object for the client @@ -350,6 +389,7 @@ exports.handleMessage = async (socket:any, message: ClientVarMessage) => { stats.counter('pendingEdits').inc(); await padChannels.enqueue(thisSession.padId, {socket, message}); break; + case 'PAD_DELETE': await handlePadDelete(socket, message.data as unknown as PadDeleteMessage); break; case 'USERINFO_UPDATE': await handleUserInfoUpdate(socket, message as unknown as UserNewInfoMessage); break; case 'CHAT_MESSAGE': await handleChatMessage(socket, message as unknown as ChatMessageMessage); break; case 'GET_CHAT_MESSAGES': await handleGetChatMessages(socket, message); break; diff --git a/src/static/js/pad_editor.ts b/src/static/js/pad_editor.ts index 362412f2f..a68217a88 100644 --- a/src/static/js/pad_editor.ts +++ b/src/static/js/pad_editor.ts @@ -75,11 +75,20 @@ const padeditor = (() => { padutils.setCheckbox($('#options-rtlcheck'), ('rtl' === html10n.getDirection())); }); + + // font family change $('#viewfontmenu').on('change', () => { pad.changeViewOption('padFontFamily', $('#viewfontmenu').val()); }); + // delete pad + $('#delete-pad').on('click', () => { + if (window.confirm(html10n.get('pad.delete.confirm'))) { + pad.collabClient.sendMessage({type: 'PAD_DELETE', data:{padId: pad.getPadId()}}); + } + }) + // Language html10n.bind('localized', () => { $('#languagemenu').val(html10n.getLanguage()); diff --git a/src/static/js/types/SocketIOMessage.ts b/src/static/js/types/SocketIOMessage.ts index 9c9ffea7f..f2b8cfc14 100644 --- a/src/static/js/types/SocketIOMessage.ts +++ b/src/static/js/types/SocketIOMessage.ts @@ -192,6 +192,14 @@ export type ClientSaveRevisionMessage = { type: 'SAVE_REVISION' } + +export type PadDeleteMessage = { + type: 'PAD_DELETE' + data: { + padId: string + } +} + export type GetChatMessageMessage = { type: 'GET_CHAT_MESSAGES', start: number, @@ -283,7 +291,7 @@ export type ChangesetRequestMessage = { export type CollabroomMessage = { type: 'COLLABROOM' - data: ClientSendUserInfoUpdate | ClientUserChangesMessage | ChatMessageMessage | GetChatMessageMessage | ClientSaveRevisionMessage | ClientMessageMessage + data: ClientSendUserInfoUpdate | ClientUserChangesMessage | ChatMessageMessage | GetChatMessageMessage | ClientSaveRevisionMessage | ClientMessageMessage | PadDeleteMessage } export type ClientVarMessage = | ClientVarData | ClientDisconnectedMessage | ClientReadyMessage| ChangesetRequestMessage | CollabroomMessage | CustomMessage diff --git a/src/static/skins/colibris/src/components/popup.css b/src/static/skins/colibris/src/components/popup.css index 0fe67e50f..04f47e3a5 100644 --- a/src/static/skins/colibris/src/components/popup.css +++ b/src/static/skins/colibris/src/components/popup.css @@ -81,3 +81,7 @@ .skin-variant-container { text-transform: capitalize; } + +#delete-pad { + background-color: #ff7b72; +} diff --git a/src/templates/pad.html b/src/templates/pad.html index c3e253791..6dd9a0ef8 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -164,10 +164,10 @@

<% e.end_block(); %> - +

About

Powered by - Etherpad + Etherpad <% if (settings.exposeVersion) { %>(commit <%=settings.getGitCommit()%>)<% } %> diff --git a/src/tests/backend/common.ts b/src/tests/backend/common.ts index 4f3937546..271fb43d4 100644 --- a/src/tests/backend/common.ts +++ b/src/tests/backend/common.ts @@ -250,6 +250,19 @@ export const sendUserChanges = async (socket:any, data:any) => await sendMessage }, }); + +/* + * Convenience function to send a delete pad request. + */ +export const sendPadDelete = async (socket:any, data:any) => await sendMessage(socket, { + type: 'PAD_DELETE', + component: 'pad', + data: { + padId: data.padId + }, +}); + + /** * Convenience function that waits for an ACCEPT_COMMIT message. Asserts that the new revision * matches the expected revision. diff --git a/ui/pad.html b/ui/pad.html index 6b34d7e9a..e11541943 100644 --- a/ui/pad.html +++ b/ui/pad.html @@ -385,7 +385,7 @@

- +

About

Powered by Etherpad