From 02374345e1e12bd5398e187ed4f481a072d638c9 Mon Sep 17 00:00:00 2001 From: okbel Date: Fri, 23 Feb 2018 15:35:14 -0300 Subject: [PATCH] Adding README.md, modifying mutation, changing htmlBody to richTextBody to make it generic --- client/coral-framework/graphql/mutations.js | 28 -------------- .../client/components/CommentContent.js | 4 +- .../client/components/Editor.js | 8 ++-- .../client/containers/CommentContent.js | 2 +- .../client/index.js | 38 ++++++++++++++++--- plugins/talk-plugin-rich-text/README.md | 24 ++++++++++++ plugins/talk-plugin-rich-text/server/hooks.js | 14 +++---- .../talk-plugin-rich-text/server/resolvers.js | 2 +- .../server/typeDefs.graphql | 6 +-- 9 files changed, 75 insertions(+), 51 deletions(-) diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index ffa139abc..f34a2cc88 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -1,6 +1,5 @@ import { gql } from 'react-apollo'; import withMutation from '../hocs/withMutation'; -import update from 'immutability-helper'; function convertItemType(item_type) { switch (item_type) { @@ -459,33 +458,6 @@ export const withEditComment = withMutation( asset_id, edit, }, - update: proxy => { - const editCommentFragment = gql` - fragment Talk_EditComment on Comment { - body - htmlBody - } - `; - - const fragmentId = `Comment_${id}`; - - const data = proxy.readFragment({ - fragment: editCommentFragment, - id: fragmentId, - }); - - const updated = update(data, { - htmlBody: { - $set: edit.htmlBody, - }, - }); - - proxy.writeFragment({ - fragment: editCommentFragment, - id: fragmentId, - data: updated, - }); - }, }); }, }), diff --git a/plugins/talk-plugin-rich-text-pell/client/components/CommentContent.js b/plugins/talk-plugin-rich-text-pell/client/components/CommentContent.js index 49f2572df..7e4a202bc 100644 --- a/plugins/talk-plugin-rich-text-pell/client/components/CommentContent.js +++ b/plugins/talk-plugin-rich-text-pell/client/components/CommentContent.js @@ -5,10 +5,10 @@ import { pluginName } from '../../package.json'; class CommentContent extends React.Component { render() { const { comment } = this.props; - return comment.htmlBody ? ( + return comment.richTextBody ? (
) : (
{comment.body}
diff --git a/plugins/talk-plugin-rich-text-pell/client/components/Editor.js b/plugins/talk-plugin-rich-text-pell/client/components/Editor.js index 0800950e8..e85c48731 100644 --- a/plugins/talk-plugin-rich-text-pell/client/components/Editor.js +++ b/plugins/talk-plugin-rich-text-pell/client/components/Editor.js @@ -15,10 +15,10 @@ class Editor extends React.Component { init({ element: this.ref, - onChange: htmlBody => { + onChange: richTextBody => { // We want to save the original comment body const originalBody = this.ref.childNodes[1].innerText; - onChange(originalBody, { htmlBody }); + onChange(originalBody, { richTextBody }); }, actions, classes: { @@ -37,8 +37,8 @@ class Editor extends React.Component { }); // To edit comments and have the previous html comment - if (this.props.comment && this.props.comment.htmlBody) { - this.ref.content.innerHTML = this.props.comment.htmlBody; + if (this.props.comment && this.props.comment.richTextBody) { + this.ref.content.innerHTML = this.props.comment.richTextBody; } } diff --git a/plugins/talk-plugin-rich-text-pell/client/containers/CommentContent.js b/plugins/talk-plugin-rich-text-pell/client/containers/CommentContent.js index ac6f2de78..8bd36da23 100644 --- a/plugins/talk-plugin-rich-text-pell/client/containers/CommentContent.js +++ b/plugins/talk-plugin-rich-text-pell/client/containers/CommentContent.js @@ -6,7 +6,7 @@ export default withFragments({ comment: gql` fragment TalkPluginRTE_CommentContent_comment on Comment { body - htmlBody + richTextBody } `, })(CommentContent); diff --git a/plugins/talk-plugin-rich-text-pell/client/index.js b/plugins/talk-plugin-rich-text-pell/client/index.js index 1f357de77..84d6e7da9 100644 --- a/plugins/talk-plugin-rich-text-pell/client/index.js +++ b/plugins/talk-plugin-rich-text-pell/client/index.js @@ -1,4 +1,5 @@ import Editor from './components/Editor'; +import update from 'immutability-helper'; import CommentContent from './containers/CommentContent'; import { gql } from 'react-apollo'; @@ -11,14 +12,14 @@ export default { CreateCommentResponse: gql` fragment TalkRTE_CreateCommentResponse on CreateCommentResponse { comment { - htmlBody + richTextBody } } `, EditCommentResponse: gql` fragment TalkRTE_EditCommentResponse on EditCommentResponse { comment { - htmlBody + richTextBody } } `, @@ -29,21 +30,48 @@ export default { optimisticResponse: { createComment: { comment: { - htmlBody: input.htmlBody, + richTextBody: input.richTextBody, }, }, }, }; }, - EditComment: ({ variables: { edit } }) => { + EditComment: ({ variables: { id, edit } }) => { return { optimisticResponse: { editComment: { comment: { - htmlBody: edit.htmlBody, + richTextBody: edit.richTextBody, }, }, }, + update: proxy => { + const editCommentFragment = gql` + fragment Talk_EditComment on Comment { + body + richTextBody + } + `; + + const fragmentId = `Comment_${id}`; + + const data = proxy.readFragment({ + fragment: editCommentFragment, + id: fragmentId, + }); + + const updated = update(data, { + richTextBody: { + $set: edit.richTextBody, + }, + }); + + proxy.writeFragment({ + fragment: editCommentFragment, + id: fragmentId, + data: updated, + }); + }, }; }, }, diff --git a/plugins/talk-plugin-rich-text/README.md b/plugins/talk-plugin-rich-text/README.md index e69de29bb..ce85a23b0 100644 --- a/plugins/talk-plugin-rich-text/README.md +++ b/plugins/talk-plugin-rich-text/README.md @@ -0,0 +1,24 @@ +# Talk Plugin Rich Text +Enables secure rich text support server-side. + + +## Installation +Add `talk-plugin-rich-text` to the `plugins.json` in your Talk installation. Remember to add this in the `server` property since this plugin only covers the server side. To add frontend support consider using `talk-plugin-rich-text-pell`. + +## How does this work? +This plugin uses the `comment.metadata` field to store the `richTextBody`. By adding `richTextBody` to the schema we can later on resolve it as part of the comment. The original `comment.body` is never touched. Using the `metadata` field allow us to build plugins that are not invasive to the core and also test the capabilities of our plugin framework. We encourage you to see the files and check how easy is to build plugins! If you have any feedback, please let us know. + +## Configuration +There is a `config.js` in the root folder. This file contains the recommended settings. + +### `highlightLinks` +A `boolean` to highlight links. Set it to `false` to turn it off. + +### `linkify` +Settings for highlighting links. These will only apply if `higlightLinks` is set to `true`. + +### `dompurify` +Rules to sanitize html input. We use [DOMPurify] (https://github.com/cure53/DOMPurify) to prevent web attacks and XSS. Here is the complete list of [settings] (https://github.com/cure53/DOMPurify) + +## `jsdom` +In order to run html in the server we need [jsdom](https://github.com/jsdom/jsdom). Usually you wouldn’t need to modify this settings. diff --git a/plugins/talk-plugin-rich-text/server/hooks.js b/plugins/talk-plugin-rich-text/server/hooks.js index 0dfcd054c..f0bbe33ab 100644 --- a/plugins/talk-plugin-rich-text/server/hooks.js +++ b/plugins/talk-plugin-rich-text/server/hooks.js @@ -3,14 +3,14 @@ const DOMPurify = require('./DOMPurify'); const linkify = require('linkifyjs/html'); const config = require('./config'); -const inputCleanup = ({ htmlBody }) => { - // htmlBody needs to be present in the request - if (!htmlBody) { - throw new Error('htmlBody not present in the request'); +const inputCleanup = ({ richTextBody }) => { + // richTextBody needs to be present in the request + if (!richTextBody) { + throw new Error('`richTextBody` field not present in the request'); } // Let's sanitize the body - let cleanInput = DOMPurify.sanitize(htmlBody); + let cleanInput = DOMPurify.sanitize(richTextBody); // Highlighting links if (config.highlightLinks) { @@ -26,7 +26,7 @@ module.exports = { async pre(_, { input }, _context, _info) { // Adding the clean body to the comment.metadata field input.metadata = merge(get(input, 'metadata'), { - htmlBody: inputCleanup(input), + richTextBody: inputCleanup(input), }); }, }, @@ -34,7 +34,7 @@ module.exports = { async pre(_, { edit }, _context, _info) { // Adding the clean body to the coment.metadata field edit.metadata = merge(get(edit, 'metadata'), { - htmlBody: inputCleanup(edit), + richTextBody: inputCleanup(edit), }); }, }, diff --git a/plugins/talk-plugin-rich-text/server/resolvers.js b/plugins/talk-plugin-rich-text/server/resolvers.js index 015f39cb9..4b7ec276e 100644 --- a/plugins/talk-plugin-rich-text/server/resolvers.js +++ b/plugins/talk-plugin-rich-text/server/resolvers.js @@ -1,5 +1,5 @@ module.exports = { Comment: { - htmlBody: comment => comment.metadata.htmlBody, + richTextBody: comment => comment.metadata.richTextBody, }, }; diff --git a/plugins/talk-plugin-rich-text/server/typeDefs.graphql b/plugins/talk-plugin-rich-text/server/typeDefs.graphql index f5db2fd88..7a60a24c3 100644 --- a/plugins/talk-plugin-rich-text/server/typeDefs.graphql +++ b/plugins/talk-plugin-rich-text/server/typeDefs.graphql @@ -1,11 +1,11 @@ input CreateCommentInput { - htmlBody: String + richTextBody: String } input EditCommentInput { - htmlBody: String + richTextBody: String } type Comment { - htmlBody: String + richTextBody: String } \ No newline at end of file