Skip to content
This repository was archived by the owner on Apr 6, 2022. It is now read-only.
2 changes: 1 addition & 1 deletion packages/documents/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"isomorphic-unfetch": "^2.0.0"
},
"dependencies": {
"@project-r/styleguide": "^5.71.7",
"@project-r/styleguide": "^5.75.0",
"@project-r/template-newsletter": "^1.5.0",
"apollo-modules-node": "^0.1.4",
"check-env": "^1.3.0",
Expand Down
20 changes: 16 additions & 4 deletions servers/republik/graphql/resolvers/Comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { Roles } = require('@orbiting/backend-modules-auth')
const { transformUser } = require('@orbiting/backend-modules-auth')
const crypto = require('crypto')
const { portrait: getPortrait } = require('./User')
const remark = require('../../lib/remark')

const {
DISPLAY_AUTHOR_SECRET
Expand All @@ -10,6 +11,11 @@ if (!DISPLAY_AUTHOR_SECRET) {
throw new Error('missing required DISPLAY_AUTHOR_SECRET')
}

const textForComment = ({ userId, content, published, adminUnpublished }, user) =>
(!published || adminUnpublished) && (!user || userId !== user.id)
? null
: content

module.exports = {
discussion: ({ discussionId }, args, { pgdb }) =>
pgdb.public.discussions.findOne({ id: discussionId }),
Expand All @@ -22,10 +28,16 @@ module.exports = {
? adminUnpublished
: null,

content: ({ userId, content, published, adminUnpublished }, args, { user, t }) =>
(!published || adminUnpublished) && (!user || userId !== user.id)
? null
: content,
content: (comment, args, context) => {
const text = textForComment(comment, context && context.user)
if (!text) {
return text
}
return remark.parse(text)
},

text: (comment, args, { user }) =>
textForComment(comment, user),

score: comment =>
comment.upVotes - comment.downVotes,
Expand Down
24 changes: 14 additions & 10 deletions servers/republik/graphql/resolvers/Discussion/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const _ = {
const {
published: getPublished,
adminUnpublished: getAdminUnpublished,
content: getContent,
author: getAuthor,
displayAuthor: getDisplayAuthor
} = require('../Comment')
Expand Down Expand Up @@ -62,11 +61,12 @@ const measureTree = comment => {
// recursively sort tree
// each node with children gets a topValue based on
// node[sortKey] || topChild[topValue] || topChild[sortKey]
// thus topValue bubbles up the tree, ensuring consistent sorting.
const deepSortTree = (comment, ascDesc, sortKey, topValue, topIds) => {
// thus topValue bubbles up the tree
// this behaviour can be disabled with the last param set to false
const deepSortTree = (comment, ascDesc, sortKey, topValue, topIds, bubbleSort = true) => {
const { comments } = comment
if (comments.nodes.length > 0) {
comments.nodes.forEach(c => deepSortTree(c, ascDesc, sortKey, topValue, topIds))
comments.nodes.forEach(c => deepSortTree(c, ascDesc, sortKey, topValue, topIds, bubbleSort))
comment.comments = {
...comments,
nodes: comments.nodes.sort(
Expand All @@ -78,10 +78,12 @@ const deepSortTree = (comment, ascDesc, sortKey, topValue, topIds) => {
const firstChild = comment.comments.nodes[0]
comment.topValue = topIds && topIds.includes(comment.id)
? topValue
: [
comment[sortKey],
firstChild.topValue || firstChild[sortKey]
].sort((a, b) => ascDesc(a, b))[0]
: bubbleSort
? [
comment[sortKey],
firstChild.topValue || firstChild[sortKey]
].sort((a, b) => ascDesc(a, b))[0]
: null
}
}
return comment
Expand Down Expand Up @@ -181,7 +183,6 @@ const decorateTree = async (_comment, coveredComments, discussion, context) => {
...c,
published: getPublished(c, {}, context),
adminUnpublished: getAdminUnpublished(c, {}, context),
content: getContent(c, {}, context),
author: getAuthor(c, {}, preResolvedContext),
displayAuthor: getDisplayAuthor(c, {}, preResolvedContext)
}
Expand Down Expand Up @@ -296,6 +297,8 @@ module.exports = async (discussion, args, context, info) => {
'HOT': 'hotness'
}
const sortKey = sortKeyMap[orderBy]
const bubbleSort = sortKey !== 'createdAt' // bubbling values for sort is disabled for createdAt

const compare =
(a, b) => // topValue set by deepSortTree // index for stable sort
ascDesc(a.topValue || a[sortKey], b.topValue || b[sortKey]) || ascending(a.index, b.index)
Expand All @@ -318,7 +321,8 @@ module.exports = async (discussion, args, context, info) => {
topValue,
focusComment && focusComment.parentIds
? [...focusComment.parentIds, focusComment.id]
: null
: null,
bubbleSort
)

if (exceptIds) { // exceptIds are always on first level
Expand Down
5 changes: 3 additions & 2 deletions servers/republik/graphql/schema-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,9 @@ type Comment {
parent: Comment
parentIds: [ID!]!
comments: CommentConnection!
# maybe becomes mdast/JSON later
content: String
# mdast
content: JSON
text: String
published: Boolean!
adminUnpublished: Boolean
upVotes: Int!
Expand Down
13 changes: 11 additions & 2 deletions servers/republik/lib/Notifications.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const { displayAuthor: getDisplayAuthor } = require('../graphql/resolvers/Comment')
const {
displayAuthor: getDisplayAuthor,
content: getContent
} = require('../graphql/resolvers/Comment')
const { transformUser } = require('@orbiting/backend-modules-auth')

const commentSchema = require('@project-r/styleguide/lib/templates/Comment/email').default()
const { renderEmail } = require('mdast-react-render/lib/email')

const {
DEFAULT_MAIL_FROM_ADDRESS,
DEFAULT_MAIL_FROM_NAME,
Expand Down Expand Up @@ -79,6 +85,9 @@ const submitComment = async (comment, discussion, context) => {
context
)

const contentMdast = getContent(comment)
const htmlContent = renderEmail(contentMdast, commentSchema, { doctype: '' })

const shortBody = comment.content.length > 128
? `${comment.content.substring(0, 128)}...`
: comment.content
Expand Down Expand Up @@ -138,7 +147,7 @@ const submitComment = async (comment, discussion, context) => {
content: `${discussionUrl}?mute=1`
},
{ name: 'CONTENT',
content: comment.content
content: htmlContent
},
{ name: 'URL',
content: commentUrl
Expand Down
17 changes: 17 additions & 0 deletions servers/republik/lib/remark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const unified = require('unified')
const remarkParse = require('remark-parse')
const remarkBreaks = require('remark-breaks')

// https://github.com/remarkjs/remark/tree/master/packages/remark-parse#turning-off-a-tokenizer
delete remarkParse.Parser.prototype.blockTokenizers.table

const parser = unified()
.use(remarkParse, {
position: false,
commonmark: true,
gfm: true,
footnotes: false
})
.use(remarkBreaks)

module.exports.parse = md => parser.runSync(parser.parse(md))
4 changes: 4 additions & 0 deletions servers/republik/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"private": true,
"license": "AGPL-3.0",
"dependencies": {
"@project-r/styleguide": "^5.75.0",
"@slack/client": "^4.1.0",
"apollo-modules-node": "^0.1.4",
"d3-array": "^1.2.1",
Expand All @@ -27,9 +28,12 @@
"lodash": "^4.17.5",
"moment": "^2.22.0",
"openpgp": "^3.0.3",
"remark-breaks": "^1.0.0",
"remark-parse": "^5.0.0",
"sharp": "^0.20.1",
"slugify": "^1.2.9",
"stripe": "^5.8.0",
"unified": "^6.1.6",
"uuid": "^3.2.1"
},
"scripts": {
Expand Down
34 changes: 29 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
stringify-entities "^1.3.1"
unified "^6.1.5"

"@project-r/styleguide@^5.71.7":
version "5.71.7"
resolved "https://registry.yarnpkg.com/@project-r/styleguide/-/styleguide-5.71.7.tgz#868c529557c2d75b9d8adbefdd32c571d5579d46"
"@project-r/styleguide@^5.75.0":
version "5.75.0"
resolved "https://registry.yarnpkg.com/@project-r/styleguide/-/styleguide-5.75.0.tgz#ebe3307233d5117b0471337b6cb2646cf6e3eccb"
dependencies:
react-icons "^2.2.7"

Expand Down Expand Up @@ -4916,7 +4916,7 @@ parse-database-url@~0.3.0:
dependencies:
mongodb-uri ">= 0.9.7"

parse-entities@^1.0.2, parse-entities@^1.1.1:
parse-entities@^1.0.2, parse-entities@^1.1.0, parse-entities@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.1.1.tgz#8112d88471319f27abae4d64964b122fe4e1b890"
dependencies:
Expand Down Expand Up @@ -5584,6 +5584,10 @@ registry-url@^3.0.3:
dependencies:
rc "^1.0.1"

remark-breaks@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/remark-breaks/-/remark-breaks-1.0.0.tgz#f7d701d14cf6cf6f225ff93f1c3a10b3c353a9a3"

remark-frontmatter@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/remark-frontmatter/-/remark-frontmatter-1.2.0.tgz#67905d178c0fe531ed12c57b98759f101fc2c1b5"
Expand Down Expand Up @@ -5611,6 +5615,26 @@ remark-parse@^4.0.0:
vfile-location "^2.0.0"
xtend "^4.0.1"

remark-parse@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95"
dependencies:
collapse-white-space "^1.0.2"
is-alphabetical "^1.0.0"
is-decimal "^1.0.0"
is-whitespace-character "^1.0.0"
is-word-character "^1.0.0"
markdown-escapes "^1.0.0"
parse-entities "^1.1.0"
repeat-string "^1.5.4"
state-toggle "^1.0.0"
trim "0.0.1"
trim-trailing-lines "^1.0.0"
unherit "^1.0.4"
unist-util-remove-position "^1.0.0"
vfile-location "^2.0.0"
xtend "^4.0.1"

remark-stringify@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-4.0.0.tgz#4431884c0418f112da44991b4e356cfe37facd87"
Expand Down Expand Up @@ -6745,7 +6769,7 @@ unherit@^1.0.4:
inherits "^2.0.1"
xtend "^4.0.1"

unified@^6.1.5:
unified@^6.1.5, unified@^6.1.6:
version "6.1.6"
resolved "https://registry.yarnpkg.com/unified/-/unified-6.1.6.tgz#5ea7f807a0898f1f8acdeefe5f25faa010cc42b1"
dependencies:
Expand Down