From 3dd33968f598e1753d84322eb9551a58d591e645 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Wed, 11 Dec 2024 17:17:42 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Improved=20various=20aspects=20of?= =?UTF-8?q?=20comments=20app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref https://linear.app/ghost/issue/PLG-300/ Full details available soon on https://ghost.org/changelog/ - removed `commentImprovements` labs flag conditionals --- apps/comments-ui/src/App.tsx | 21 +- apps/comments-ui/src/actions.ts | 75 +- .../src/components/content/Comment.test.jsx | 8 +- .../src/components/content/Comment.tsx | 74 +- .../src/components/content/Content.test.jsx | 4 +- .../src/components/content/Content.tsx | 87 +- .../components/content/Pagination.test.jsx | 32 + .../src/components/content/Pagination.tsx | 24 +- .../components/content/buttons/LikeButton.tsx | 52 +- .../content/buttons/ReplyButton.tsx | 9 +- .../context-menus/AuthorContextMenu.tsx | 15 +- .../context-menus/CommentContextMenu.test.jsx | 4 +- .../context-menus/CommentContextMenu.tsx | 20 +- .../src/components/content/forms/Form.tsx | 43 +- apps/comments-ui/test/e2e/actions.test.ts | 88 +- .../test/e2e/admin-moderation.test.ts | 405 +++--- .../test/e2e/autoclose-forms.test.ts | 4 +- apps/comments-ui/test/e2e/content.test.ts | 12 +- apps/comments-ui/test/e2e/cta.test.ts | 8 +- apps/comments-ui/test/e2e/pagination.test.ts | 9 +- apps/comments-ui/test/utils/MockedApi.ts | 4 +- .../serializers/output/mappers/comments.js | 23 +- ghost/core/core/server/models/comment.js | 87 +- .../admin/__snapshots__/comments.test.js.snap | 258 +--- .../core/test/e2e-api/admin/comments.test.js | 1174 ++++++++--------- .../__snapshots__/comments.test.js.snap | 248 ++-- .../e2e-api/members-comments/comments.test.js | 78 +- .../utils/serializers/output/mapper.test.js | 9 +- ghost/i18n/locales/af/comments.json | 3 +- ghost/i18n/locales/ar/comments.json | 3 +- ghost/i18n/locales/bg/comments.json | 3 +- ghost/i18n/locales/bn/comments.json | 3 +- ghost/i18n/locales/bs/comments.json | 3 +- ghost/i18n/locales/ca/comments.json | 3 +- ghost/i18n/locales/cs/comments.json | 3 +- ghost/i18n/locales/da/comments.json | 3 +- ghost/i18n/locales/de-CH/comments.json | 3 +- ghost/i18n/locales/de/comments.json | 3 +- ghost/i18n/locales/el/comments.json | 3 +- ghost/i18n/locales/en/comments.json | 3 +- ghost/i18n/locales/eo/comments.json | 3 +- ghost/i18n/locales/es/comments.json | 3 +- ghost/i18n/locales/et/comments.json | 3 +- ghost/i18n/locales/fa/comments.json | 3 +- ghost/i18n/locales/fi/comments.json | 3 +- ghost/i18n/locales/fr/comments.json | 3 +- ghost/i18n/locales/gd/comments.json | 3 +- ghost/i18n/locales/he/comments.json | 3 +- ghost/i18n/locales/hi/comments.json | 3 +- ghost/i18n/locales/hr/comments.json | 3 +- ghost/i18n/locales/hu/comments.json | 3 +- ghost/i18n/locales/id/comments.json | 3 +- ghost/i18n/locales/is/comments.json | 3 +- ghost/i18n/locales/it/comments.json | 3 +- ghost/i18n/locales/ja/comments.json | 3 +- ghost/i18n/locales/ko/comments.json | 3 +- ghost/i18n/locales/kz/comments.json | 3 +- ghost/i18n/locales/lt/comments.json | 3 +- ghost/i18n/locales/mk/comments.json | 3 +- ghost/i18n/locales/mn/comments.json | 3 +- ghost/i18n/locales/ms/comments.json | 3 +- ghost/i18n/locales/ne/comments.json | 3 +- ghost/i18n/locales/nl/comments.json | 3 +- ghost/i18n/locales/nn/comments.json | 3 +- ghost/i18n/locales/no/comments.json | 3 +- ghost/i18n/locales/pl/comments.json | 3 +- ghost/i18n/locales/pt-BR/comments.json | 3 +- ghost/i18n/locales/pt/comments.json | 3 +- ghost/i18n/locales/ro/comments.json | 3 +- ghost/i18n/locales/ru/comments.json | 3 +- ghost/i18n/locales/si/comments.json | 3 +- ghost/i18n/locales/sk/comments.json | 3 +- ghost/i18n/locales/sl/comments.json | 3 +- ghost/i18n/locales/sq/comments.json | 3 +- ghost/i18n/locales/sr-Cyrl/comments.json | 3 +- ghost/i18n/locales/sr/comments.json | 3 +- ghost/i18n/locales/sv/comments.json | 3 +- ghost/i18n/locales/sw/comments.json | 3 +- ghost/i18n/locales/ta/comments.json | 3 +- ghost/i18n/locales/th/comments.json | 3 +- ghost/i18n/locales/tr/comments.json | 3 +- ghost/i18n/locales/uk/comments.json | 3 +- ghost/i18n/locales/ur/comments.json | 3 +- ghost/i18n/locales/uz/comments.json | 3 +- ghost/i18n/locales/vi/comments.json | 3 +- ghost/i18n/locales/zh-Hant/comments.json | 3 +- ghost/i18n/locales/zh/comments.json | 3 +- 87 files changed, 1205 insertions(+), 1847 deletions(-) create mode 100644 apps/comments-ui/src/components/content/Pagination.test.jsx diff --git a/apps/comments-ui/src/App.tsx b/apps/comments-ui/src/App.tsx index 0e92cc4003..8a41cd317e 100644 --- a/apps/comments-ui/src/App.tsx +++ b/apps/comments-ui/src/App.tsx @@ -7,7 +7,7 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; import i18nLib from '@tryghost/i18n'; import setupGhostApi from './utils/api'; import {ActionHandler, SyncActionHandler, isSyncAction} from './actions'; -import {AppContext, DispatchActionType, EditableAppContext, LabsContextType} from './AppContext'; +import {AppContext, DispatchActionType, EditableAppContext} from './AppContext'; import {CommentsFrame} from './components/Frame'; import {setupAdminAPI} from './utils/adminApi'; import {useOptions} from './utils/options'; @@ -44,8 +44,6 @@ const App: React.FC = ({scriptTag}) => { }); }, [options]); - // const [adminApi, setAdminApi] = useState(null); - const setState = useCallback((newState: Partial | ((state: EditableAppContext) => Partial)) => { setFullState((state) => { if (typeof newState === 'function') { @@ -114,7 +112,7 @@ const App: React.FC = ({scriptTag}) => { let admin = null; try { admin = await adminApi.getUser(); - if (admin && state.labs.commentImprovements) { + if (admin) { // this is a bit of a hack, but we need to fetch the comments fully populated if the user is an admin const adminComments = await adminApi.browse({page: 1, postId: options.postId, order: state.order, memberUuid: state.member?.uuid}); setState({ @@ -141,14 +139,8 @@ const App: React.FC = ({scriptTag}) => { }; /** Fetch first few comments */ - const fetchComments = async (labs: LabsContextType) => { - let dataPromise; - if (labs?.commentImprovements) { - dataPromise = api.comments.browse({page: 1, postId: options.postId, order: state.order}); - } else { - dataPromise = api.comments.browse({page: 1, postId: options.postId}); - } - + const fetchComments = async () => { + const dataPromise = api.comments.browse({page: 1, postId: options.postId, order: state.order}); const countPromise = api.comments.count({postId: options.postId}); const [data, count] = await Promise.all([dataPromise, countPromise]); @@ -165,15 +157,14 @@ const App: React.FC = ({scriptTag}) => { try { // Fetch data from API, links, preview, dev sources const {member, labs} = await api.init(); - const {comments, pagination, count} = await fetchComments(labs); - const order = labs.commentImprovements ? 'count__likes desc, created_at desc' : 'created_at desc'; + const {comments, pagination, count} = await fetchComments(); const state = { member, initStatus: 'success', comments, pagination, commentCount: count, - order, + order: 'count__likes desc, created_at desc', labs: labs, commentsIsLoading: false, commentIdToHighlight: null diff --git a/apps/comments-ui/src/actions.ts b/apps/comments-ui/src/actions.ts index 47741d66e4..08ea37a240 100644 --- a/apps/comments-ui/src/actions.ts +++ b/apps/comments-ui/src/actions.ts @@ -9,7 +9,7 @@ async function loadMoreComments({state, api, options, order}: {state: EditableAp page = state.pagination.page + 1; } let data; - if (state.admin && state.adminApi && state.labs.commentImprovements) { + if (state.admin && state.adminApi) { data = await state.adminApi.browse({page, postId: options.postId, order: order || state.order, memberUuid: state.member?.uuid}); } else { data = await api.comments.browse({page, postId: options.postId, order: order || state.order}); @@ -33,7 +33,7 @@ async function setOrder({state, data: {order}, options, api, dispatchAction}: {s try { let data; - if (state.admin && state.adminApi && state.labs.commentImprovements) { + if (state.admin && state.adminApi) { data = await state.adminApi.browse({page: 1, postId: options.postId, order, memberUuid: state.member?.uuid}); } else { data = await api.comments.browse({page: 1, postId: options.postId, order}); @@ -54,7 +54,7 @@ async function setOrder({state, data: {order}, options, api, dispatchAction}: {s async function loadMoreReplies({state, api, data: {comment, limit}, isReply}: {state: EditableAppContext, api: GhostApi, data: {comment: any, limit?: number | 'all'}, isReply: boolean}): Promise> { let data; - if (state.admin && state.adminApi && state.labs.commentImprovements && !isReply) { // we don't want the admin api to load reply data for replying to a reply, so we pass isReply: true + if (state.admin && state.adminApi && !isReply) { // we don't want the admin api to load reply data for replying to a reply, so we pass isReply: true data = await state.adminApi.replies({commentId: comment.id, afterReplyId: comment.replies[comment.replies.length - 1]?.id, limit, memberUuid: state.member?.uuid}); } else { data = await api.comments.replies({commentId: comment.id, afterReplyId: comment.replies[comment.replies.length - 1]?.id, limit}); @@ -155,7 +155,7 @@ async function showComment({state, api, data: comment}: {state: EditableAppConte // We need to refetch the comment, to make sure we have an up to date HTML content // + all relations are loaded as the current member (not the admin) let data; - if (state.admin && state.adminApi && state.labs.commentImprovements) { + if (state.admin && state.adminApi) { data = await state.adminApi.read({commentId: comment.id, memberUuid: state.member?.uuid}); } else { data = await api.comments.read(comment.id); @@ -279,60 +279,29 @@ async function deleteComment({state, api, data: comment}: {state: EditableAppCon } }); - if (state.labs.commentImprovements) { - return { - comments: state.comments.map((c) => { - // If the comment has replies we want to keep it so the replies are - // still visible, but mark the comment as deleted. Otherwise remove it. - if (c.id === comment.id) { - if (c.replies.length > 0) { - return { - ...c, - status: 'deleted' - }; - } else { - return null; // Will be filtered out later - } - } - - const updatedReplies = c.replies.filter(r => r.id !== comment.id); - return { - ...c, - replies: updatedReplies - }; - }).filter(Boolean), - commentCount: state.commentCount - 1 - }; - } else { - return { - comments: state.comments.map((c) => { - const replies = c.replies.map((r) => { - if (r.id === comment.id) { - return { - ...r, - status: 'deleted' - }; - } - - return r; - }); - - if (c.id === comment.id) { + return { + comments: state.comments.map((c) => { + // If the comment has replies we want to keep it so the replies are + // still visible, but mark the comment as deleted. Otherwise remove it. + if (c.id === comment.id) { + if (c.replies.length > 0) { return { ...c, - status: 'deleted', - replies + status: 'deleted' }; + } else { + return null; // Will be filtered out later } + } - return { - ...c, - replies - }; - }), - commentCount: state.commentCount - 1 - }; - } + const updatedReplies = c.replies.filter(r => r.id !== comment.id); + return { + ...c, + replies: updatedReplies + }; + }).filter(Boolean), + commentCount: state.commentCount - 1 + }; } async function editComment({state, api, data: {comment, parent}}: {state: EditableAppContext, api: GhostApi, data: {comment: Partial & {id: string}, parent?: Comment}}) { diff --git a/apps/comments-ui/src/components/content/Comment.test.jsx b/apps/comments-ui/src/components/content/Comment.test.jsx index ed8516263d..fa32e698a1 100644 --- a/apps/comments-ui/src/components/content/Comment.test.jsx +++ b/apps/comments-ui/src/components/content/Comment.test.jsx @@ -32,7 +32,7 @@ describe('', function () { const parent = buildComment({ replies: [reply1, reply2] }); - const appContext = {comments: [parent], labs: {commentImprovements: true}}; + const appContext = {comments: [parent]}; contextualRender(, {appContext}); @@ -53,7 +53,7 @@ describe('', function () { const parent = buildComment({ replies: [reply1, reply2] }); - const appContext = {comments: [parent], labs: {commentImprovements: true}}; + const appContext = {comments: [parent]}; contextualRender(, {appContext}); @@ -74,7 +74,7 @@ describe('', function () { const parent = buildComment({ replies: [reply1, reply2] }); - const appContext = {comments: [parent], labs: {commentImprovements: true}}; + const appContext = {comments: [parent]}; contextualRender(, {appContext}); @@ -91,7 +91,7 @@ describe('', function () { const parent = buildComment({ replies: [reply2] }); - const appContext = {comments: [parent], labs: {commentImprovements: true}}; + const appContext = {comments: [parent]}; contextualRender(, {appContext}); diff --git a/apps/comments-ui/src/components/content/Comment.tsx b/apps/comments-ui/src/components/content/Comment.tsx index 0952090ddd..c936c64445 100644 --- a/apps/comments-ui/src/components/content/Comment.tsx +++ b/apps/comments-ui/src/components/content/Comment.tsx @@ -5,7 +5,7 @@ import Replies, {RepliesProps} from './Replies'; import ReplyButton from './buttons/ReplyButton'; import ReplyForm from './forms/ReplyForm'; import {Avatar, BlankAvatar} from './Avatar'; -import {Comment, OpenCommentForm, useAppContext, useLabs} from '../../AppContext'; +import {Comment, OpenCommentForm, useAppContext} from '../../AppContext'; import {Transition} from '@headlessui/react'; import {findCommentById, formatExplicitTime, getCommentInReplyToSnippet, getMemberNameFromComment} from '../../utils/helpers'; import {useCallback} from 'react'; @@ -39,8 +39,7 @@ const AnimatedComment: React.FC = ({comment, parent}) => { export const CommentComponent: React.FC = ({comment, parent}) => { const {dispatchAction, admin} = useAppContext(); - const labs = useLabs(); - const {showDeletedMessage, showHiddenMessage, showCommentContent} = useCommentVisibility(comment, admin, labs); + const {showDeletedMessage, showHiddenMessage, showCommentContent} = useCommentVisibility(comment, admin); const openEditMode = useCallback(() => { const newForm: OpenCommentForm = { @@ -53,39 +52,28 @@ export const CommentComponent: React.FC = ({comment, parent}) => { dispatchAction('openCommentForm', newForm); }, [comment.id, dispatchAction]); - if (showDeletedMessage) { + if (showDeletedMessage || showHiddenMessage) { return ; } else if (showCommentContent && !showHiddenMessage) { return ; - } else if (!labs.commentImprovements && comment.status !== 'published' || showHiddenMessage) { - return ; } return null; }; type CommentProps = AnimatedCommentProps; -const useCommentVisibility = (comment: Comment, admin: boolean, labs: {commentImprovements?: boolean}) => { +const useCommentVisibility = (comment: Comment, admin: boolean) => { const hasReplies = comment.replies && comment.replies.length > 0; const isDeleted = comment.status === 'deleted'; const isHidden = comment.status === 'hidden'; - if (labs?.commentImprovements) { - return { - // Show deleted message only when comment has replies (regardless of admin status) - showDeletedMessage: isDeleted && hasReplies, - // Show hidden message for non-admins when comment has replies - showHiddenMessage: hasReplies && isHidden && !admin, - // Show comment content if not deleted AND (is published OR admin viewing hidden) - showCommentContent: !isDeleted && (admin || comment.status === 'published') - }; - } - - // Original behavior when labs is false return { - showDeletedMessage: false, - showHiddenMessage: false, - showCommentContent: comment.status === 'published' + // Show deleted message only when comment has replies (regardless of admin status) + showDeletedMessage: isDeleted && hasReplies, + // Show hidden message for non-admins when comment has replies + showHiddenMessage: hasReplies && isHidden && !admin, + // Show comment content if not deleted AND (is published OR admin viewing hidden) + showCommentContent: !isDeleted && (admin || comment.status === 'published') }; }; @@ -94,10 +82,9 @@ type PublishedCommentProps = CommentProps & { } const PublishedComment: React.FC = ({comment, parent, openEditMode}) => { const {dispatchAction, openCommentForms, admin, commentIdToHighlight} = useAppContext(); - const labs = useLabs(); // Determine if the comment should be displayed with reduced opacity - const isHidden = labs.commentImprovements && admin && comment.status === 'hidden'; + const isHidden = admin && comment.status === 'hidden'; const hiddenClass = isHidden ? 'opacity-30' : ''; // Check if this comment is being edited @@ -171,11 +158,11 @@ type UnpublishedCommentProps = { openEditMode: () => void; } const UnpublishedComment: React.FC = ({comment, openEditMode}) => { - const {openCommentForms, t, labs, admin} = useAppContext(); + const {admin, openCommentForms, t} = useAppContext(); - const avatar = (labs.commentImprovements && admin && comment.status !== 'deleted') ? - : - ; + const avatar = (admin && comment.status !== 'deleted') + ? + : ; const hasReplies = comment.replies && comment.replies.length > 0; const notPublishedMessage = comment.status === 'hidden' ? @@ -322,10 +309,9 @@ type CommentHeaderProps = { const CommentHeader: React.FC = ({comment, className = ''}) => { const {member, t} = useAppContext(); - const labs = useLabs(); const createdAtRelative = useRelativeTime(comment.created_at); const memberExpertise = member && comment.member && comment.member.uuid === member.uuid ? member.expertise : comment?.member?.expertise; - const isReplyToReply = labs.commentImprovements && comment.in_reply_to_id && comment.in_reply_to_snippet; + const isReplyToReply = comment.in_reply_to_id && comment.in_reply_to_snippet; return ( <> @@ -395,39 +381,25 @@ type CommentMenuProps = { parent?: Comment; className?: string; }; -const CommentMenu: React.FC = ({comment, openReplyForm, highlightReplyButton, openEditMode, parent, className = ''}) => { - const {member, commentsEnabled, t, admin} = useAppContext(); - const labs = useLabs(); +const CommentMenu: React.FC = ({comment, openReplyForm, highlightReplyButton, openEditMode, className = ''}) => { + const {admin, t} = useAppContext(); - const paidOnly = commentsEnabled === 'paid'; - const isPaidMember = member && !!member.paid; - const canReply = member && (isPaidMember || !paidOnly) && (labs.commentImprovements ? true : !parent); - const isHiddenForAdmin = labs.commentImprovements && admin && comment.status === 'hidden'; - - if (isHiddenForAdmin) { + if (admin && comment.status === 'hidden') { return (
{t('Hidden for members')} {}
); - } - - return ( - labs.commentImprovements ? ( + } else { + return (
{} {} {}
- ) : ( -
- {} - {(canReply && )} - {} -
- ) - ); + ); + } }; // diff --git a/apps/comments-ui/src/components/content/Content.test.jsx b/apps/comments-ui/src/components/content/Content.test.jsx index fea4a78ad4..70984b2ab6 100644 --- a/apps/comments-ui/src/components/content/Content.test.jsx +++ b/apps/comments-ui/src/components/content/Content.test.jsx @@ -44,10 +44,10 @@ describe('', function () { expect(screen.queryByTestId('main-form')).toBeInTheDocument(); }); - it('renders no CTA or form when a reply form is open', function () { + it('renders main form when a reply form is open', function () { contextualRender(, {appContext: {member: {}, openFormCount: 1}}); expect(screen.queryByTestId('cta-box')).not.toBeInTheDocument(); - expect(screen.queryByTestId('main-form')).not.toBeInTheDocument(); + expect(screen.queryByTestId('main-form')).toBeInTheDocument(); }); }); }); diff --git a/apps/comments-ui/src/components/content/Content.tsx b/apps/comments-ui/src/components/content/Content.tsx index 15cb8f82ac..7e99199efb 100644 --- a/apps/comments-ui/src/components/content/Content.tsx +++ b/apps/comments-ui/src/components/content/Content.tsx @@ -10,16 +10,7 @@ import {useEffect} from 'react'; const Content = () => { const labs = useLabs(); - const {pagination, member, comments, commentCount, commentsEnabled, title, showCount, openFormCount, commentsIsLoading, t} = useAppContext(); - - let commentsElements; - const commentsDataset = comments; - - if (labs && labs.commentImprovements) { - commentsElements = commentsDataset.slice().map(comment => ); - } else { - commentsElements = commentsDataset.slice().reverse().map(comment => ); - } + const {pagination, member, comments, commentCount, commentsEnabled, title, showCount, commentsIsLoading, t} = useAppContext(); useEffect(() => { const elem = document.getElementById(ROOT_DIV_ID); @@ -42,60 +33,36 @@ const Content = () => { const isPaidOnly = commentsEnabled === 'paid'; const isPaidMember = member && !!member.paid; const isFirst = pagination?.total === 0; - const hasOpenReplyForms = openFormCount > 0; + + const commentsComponents = comments.slice().map(comment => ); return ( - labs.commentImprovements ? ( - <> - -
- {(member && (isPaidMember || !isPaidOnly)) ? ( - - ) : ( -
- -
- )} -
- {commentCount > 1 && ( -
- - {t('Sort by')}: - -
+ <> + +
+ {(member && (isPaidMember || !isPaidOnly)) ? ( + + ) : ( +
+ +
)} -
- {commentsElements} +
+ {commentCount > 1 && ( +
+ + {t('Sort by')}: +
- - { - labs?.testFlag ?
: null - } - - ) : ( - <> - - -
- {commentsElements} -
-
- {!hasOpenReplyForms - ? (member ? (isPaidMember || !isPaidOnly ? : -
- -
) : -
- -
) - : null - } -
- { - labs?.testFlag ?
: null // do not remove - } - - ) + )} +
+ {commentsComponents} +
+ + { + labs?.testFlag ?
: null + } + ); }; diff --git a/apps/comments-ui/src/components/content/Pagination.test.jsx b/apps/comments-ui/src/components/content/Pagination.test.jsx new file mode 100644 index 0000000000..7005ff1e88 --- /dev/null +++ b/apps/comments-ui/src/components/content/Pagination.test.jsx @@ -0,0 +1,32 @@ +import Pagination from './Pagination'; +import {AppContext} from '../../AppContext'; +import {render, screen} from '@testing-library/react'; + +const contextualRender = (ui, {appContext, ...renderOptions}) => { + const contextWithDefaults = { + t: (str, replacements) => { + if (replacements) { + return str.replace(/{{([^{}]*)}}/g, (_, key) => replacements[key]); + } + return str; + }, + ...appContext + }; + + return render( + {ui}, + renderOptions + ); +}; + +describe('', function () { + it('has correct text for 1 more', function () { + contextualRender(, {appContext: {pagination: {total: 4, page: 1, limit: 3}}}); + expect(screen.getByText('Load more (1)')).toBeInTheDocument(); + }); + + it('has correct text for x more', function () { + contextualRender(, {appContext: {pagination: {total: 6, page: 1, limit: 3}}}); + expect(screen.getByText('Load more (3)')).toBeInTheDocument(); + }); +}); diff --git a/apps/comments-ui/src/components/content/Pagination.tsx b/apps/comments-ui/src/components/content/Pagination.tsx index a6b116fcb3..e057595416 100644 --- a/apps/comments-ui/src/components/content/Pagination.tsx +++ b/apps/comments-ui/src/components/content/Pagination.tsx @@ -1,9 +1,8 @@ import {formatNumber} from '../../utils/helpers'; -import {useAppContext, useLabs} from '../../AppContext'; +import {useAppContext} from '../../AppContext'; const Pagination = () => { const {pagination, dispatchAction, t} = useAppContext(); - const labs = useLabs(); const loadMore = () => { dispatchAction('loadMoreComments', {}); @@ -13,27 +12,18 @@ const Pagination = () => { return null; } - const left = pagination.total - pagination.page * pagination.limit; + const commentsLeft = pagination.total - pagination.page * pagination.limit; - if (left <= 0) { + if (commentsLeft <= 0) { return null; } - // TODO: add i18n support for these strings when removing labs flag - const text = labs.commentImprovements - ? (left === 1 ? 'Load more (1)' : `Load more (${formatNumber(left)})`) - : (left === 1 ? t('Show 1 previous comment') : t('Show {{amount}} previous comments', {amount: formatNumber(left)})); + const text = t(`Load more ({{amount}})`, {amount: formatNumber(commentsLeft)}); return ( - labs.commentImprovements ? ( - - ) : ( - - ) + ); }; diff --git a/apps/comments-ui/src/components/content/buttons/LikeButton.tsx b/apps/comments-ui/src/components/content/buttons/LikeButton.tsx index 6cf22f8a6e..41e8bed49b 100644 --- a/apps/comments-ui/src/components/content/buttons/LikeButton.tsx +++ b/apps/comments-ui/src/components/content/buttons/LikeButton.tsx @@ -1,4 +1,4 @@ -import {Comment, useAppContext, useLabs} from '../../../AppContext'; +import {Comment, useAppContext} from '../../../AppContext'; import {ReactComponent as LikeIcon} from '../../../images/icons/like.svg'; import {useState} from 'react'; @@ -7,7 +7,6 @@ type Props = { }; const LikeButton: React.FC = ({comment}) => { const {dispatchAction, member, commentsEnabled} = useAppContext(); - const labs = useLabs(); const [animationClass, setAnimation] = useState(''); const paidOnly = commentsEnabled === 'paid'; @@ -15,13 +14,11 @@ const LikeButton: React.FC = ({comment}) => { const canLike = member && (isPaidMember || !paidOnly); const toggleLike = () => { - if (!canLike && labs && labs.commentImprovements) { + if (!canLike) { dispatchAction('openPopup', { type: 'ctaPopup' }); return; - } else if (!canLike) { - return; } if (!comment.liked) { @@ -35,39 +32,22 @@ const LikeButton: React.FC = ({comment}) => { } }; - // If can like: use - ); - } - return ( - - + ); }; diff --git a/apps/comments-ui/src/components/content/buttons/ReplyButton.tsx b/apps/comments-ui/src/components/content/buttons/ReplyButton.tsx index 5c398cfdde..6a058d90b5 100644 --- a/apps/comments-ui/src/components/content/buttons/ReplyButton.tsx +++ b/apps/comments-ui/src/components/content/buttons/ReplyButton.tsx @@ -1,5 +1,5 @@ import {ReactComponent as ReplyIcon} from '../../../images/icons/reply.svg'; -import {useAppContext, useLabs} from '../../../AppContext'; +import {useAppContext} from '../../../AppContext'; type Props = { disabled?: boolean; @@ -9,14 +9,13 @@ type Props = { const ReplyButton: React.FC = ({disabled, isReplying, openReplyForm}) => { const {member, t, dispatchAction, commentsEnabled} = useAppContext(); - const labs = useLabs(); const paidOnly = commentsEnabled === 'paid'; const isPaidMember = member && !!member.paid; const canReply = member && (isPaidMember || !paidOnly); const handleClick = () => { - if (!canReply && labs && labs.commentImprovements) { + if (!canReply) { dispatchAction('openPopup', { type: 'ctaPopup' }); @@ -25,10 +24,6 @@ const ReplyButton: React.FC = ({disabled, isReplying, openReplyForm}) => openReplyForm(); }; - if (!member && !labs?.commentImprovements) { - return null; - } - return ( } - {labs.commentImprovements ? ( - - ) : ( - - )} +
); @@ -183,9 +170,8 @@ type FormHeaderProps = { const FormHeader: React.FC = ({show, name, expertise, replyingToText, editName, editExpertise}) => { const {t} = useAppContext(); - const labs = useLabs(); - const isReplyingToReply = labs.commentImprovements && replyingToText; + const isReplyingToReply = !!replyingToText; return ( = ({ children }) => { const {member, dispatchAction} = useAppContext(); - const labs = useLabs(); const memberName = member?.name ?? comment?.member?.name; const memberExpertise = member?.expertise ?? comment?.member?.expertise; let openStyles = ''; if (isOpen) { - const isReplyToReply = labs.commentImprovements && !!openForm?.in_reply_to_snippet; + const isReplyToReply = !!openForm?.in_reply_to_snippet; openStyles = isReplyToReply ? 'pl-[1px] pt-[68px] sm:pl-[44px] sm:pt-[56px]' : 'pl-[1px] pt-[48px] sm:pl-[44px] sm:pt-[40px]'; } diff --git a/apps/comments-ui/test/e2e/actions.test.ts b/apps/comments-ui/test/e2e/actions.test.ts index 2811fd1a82..0654e81b78 100644 --- a/apps/comments-ui/test/e2e/actions.test.ts +++ b/apps/comments-ui/test/e2e/actions.test.ts @@ -10,9 +10,8 @@ test.describe('Actions', async () => { mockedApi, page, publication: 'Publisher Weekly', - labs: { - commentImprovements: labs - } + // always return `labs` value for any labs.x property access + labs: new Proxy({}, {get: () => labs}) }); } @@ -26,6 +25,7 @@ test.describe('Actions', async () => { }); test('Can like and unlike a comment', async ({page}) => { + // NOTE: comments are ordered by likes mockedApi.addComment({ html: '

This is comment 1

' }); @@ -43,7 +43,7 @@ test.describe('Actions', async () => { const {frame} = await initializeTest(page); // Check like button is not filled yet - const comment = frame.getByTestId('comment-component').nth(0); + const comment = frame.getByTestId('comment-component').nth(1); const likeButton = comment.getByTestId('like-button'); await expect(likeButton).toHaveCount(1); @@ -65,7 +65,7 @@ test.describe('Actions', async () => { await expect(likeButton).toHaveText('0'); // Check state for already liked comment - const secondComment = frame.getByTestId('comment-component').nth(1); + const secondComment = frame.getByTestId('comment-component').nth(0); const likeButton2 = secondComment.getByTestId('like-button'); await expect(likeButton2).toHaveCount(1); const icon2 = likeButton2.locator('svg'); @@ -120,7 +120,7 @@ test.describe('Actions', async () => { // Click button await replyButton.click(); - const editor = frame.getByTestId('form-editor'); + const editor = comment.getByTestId('form-editor'); await expect(editor).toBeVisible(); // Wait for focused await waitEditorFocused(editor); @@ -145,28 +145,8 @@ test.describe('Actions', async () => { await expect(frame.getByText('This is a reply 123')).toHaveCount(1); }); - test('Reply-to-reply action not shown without labs flag', async ({ - page - }) => { - mockedApi.addComment({ - html: '

This is comment 1

', - replies: [ - mockedApi.buildReply({ - html: '

This is a reply to 1

' - }) - ] - }); - - const {frame} = await initializeTest(page); - - const parentComment = frame.getByTestId('comment-component').nth(0); - const replyComment = parentComment.getByTestId('comment-component').nth(0); - - expect(replyComment.getByTestId('reply-button')).not.toBeVisible(); - }); - async function testReplyToReply(page) { - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const parentComment = frame.getByTestId('comment-component').nth(0); const replyComment = parentComment.getByTestId('comment-component').nth(0); @@ -174,7 +154,7 @@ test.describe('Actions', async () => { const replyReplyButton = replyComment.getByTestId('reply-button'); await replyReplyButton.click(); - const editor = frame.getByTestId('form-editor').nth(1); + const editor = parentComment.getByTestId('form-editor'); await expect(editor).toBeVisible(); await waitEditorFocused(editor); @@ -218,6 +198,20 @@ test.describe('Actions', async () => { await testReplyToReply(page); }); + test('Can reply to a reply with a deleted parent comment', async function ({page}) { + mockedApi.addComment({ + html: '

This is comment 1

', + status: 'deleted', + replies: [ + mockedApi.buildReply({ + html: '

This is a reply to 1

' + }) + ] + }); + + await testReplyToReply(page); + }); + test('Can highlight reply when clicking on reply to: snippet', async ({page}) => { mockedApi.addComment({ html: '

This is comment 1

', @@ -235,7 +229,7 @@ test.describe('Actions', async () => { ] }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); await frame.getByTestId('comment-in-reply-to').click(); @@ -274,7 +268,7 @@ test.describe('Actions', async () => { ] }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); await frame.getByTestId('comment-in-reply-to').click(); @@ -300,20 +294,6 @@ test.describe('Actions', async () => { await expect(markElement).not.toBeVisible(); }); - test('Can reply to a reply with a deleted parent comment', async function ({page}) { - mockedApi.addComment({ - html: '

This is comment 1

', - status: 'deleted', - replies: [ - mockedApi.buildReply({ - html: '

This is a reply to 1

' - }) - ] - }); - - await testReplyToReply(page); - }); - test('Can add expertise', async ({page}) => { mockedApi.setMember({name: 'John Doe', expertise: null}); @@ -370,7 +350,7 @@ test.describe('Actions', async () => { member: loggedInMember }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const comment = frame.getByTestId('comment-component').nth(0); const moreButton = comment.getByTestId('more-button').first(); @@ -399,7 +379,7 @@ test.describe('Actions', async () => { ] }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const comment = frame.getByTestId('comment-component').nth(0); const reply = comment.getByTestId('comment-component').nth(0); @@ -430,7 +410,7 @@ test.describe('Actions', async () => { ] }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const comment = frame.getByTestId('comment-component').nth(0); const moreButton = comment.getByTestId('more-button').first(); @@ -471,7 +451,7 @@ test.describe('Actions', async () => { html: '

This is comment 6

' }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const sortingForm = frame.getByTestId('comments-sorting-form'); @@ -501,7 +481,7 @@ test.describe('Actions', async () => { created_at: new Date('2022-02-01T00:00:00Z') }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const sortingForm = frame.getByTestId('comments-sorting-form'); @@ -538,7 +518,7 @@ test.describe('Actions', async () => { html: '

This is comment 6

' }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const sortingForm = frame.getByTestId('comments-sorting-form'); @@ -575,7 +555,7 @@ test.describe('Actions', async () => { created_at: new Date('2024-04-03T00:00:00Z') }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const sortingForm = await frame.getByTestId('comments-sorting-form'); @@ -618,7 +598,7 @@ test.describe('Actions', async () => { created_at: new Date('2024-04-03T00:00:00Z') }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const sortingForm = await frame.getByTestId('comments-sorting-form'); @@ -657,7 +637,7 @@ test.describe('Actions', async () => { created_at: new Date('2024-04-03T00:00:00Z') }); - const {frame} = await initializeTest(page, {labs: true}); + const {frame} = await initializeTest(page); const sortingForm = await frame.getByTestId('comments-sorting-form'); @@ -720,7 +700,7 @@ test.describe('Actions', async () => { await frame.getByTestId('edit').click(); // Verify the edit form is visible - await expect(frame.getByTestId('form-editor')).toBeVisible(); + await expect(parentComment.getByTestId('form-editor')).toBeVisible(); // Verify replies are still visible while editing await expect(replies[0]).toBeVisible(); diff --git a/apps/comments-ui/test/e2e/admin-moderation.test.ts b/apps/comments-ui/test/e2e/admin-moderation.test.ts index 334cda8ad9..cc464b0e54 100644 --- a/apps/comments-ui/test/e2e/admin-moderation.test.ts +++ b/apps/comments-ui/test/e2e/admin-moderation.test.ts @@ -28,7 +28,7 @@ test.describe('Admin moderation', async () => { mockedApi.setMember(options.member); if (options.labs) { - mockedApi.setLabs({commentImprovements: true}); + // enable specific labs flags here } return await initialize({ @@ -39,7 +39,7 @@ test.describe('Admin moderation', async () => { count: true, admin, labs: { - commentImprovements: options.labs + // enable specific labs flags here } }); } @@ -101,241 +101,216 @@ test.describe('Admin moderation', async () => { await expect(frame.getByTestId('hide-button')).toBeVisible(); }); - test('can hide and show comments', async ({page}) => { + test('member uuid are passed to admin browse api params', async ({page}) => { mockedApi.addComment({html: '

This is comment 1

'}); - mockedApi.addComment({html: '

This is comment 2

'}); + const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); + const {frame} = await initializeTest(page); + const comments = await frame.getByTestId('comment-component'); + await expect(comments).toHaveCount(1); + expect(adminBrowseSpy.called).toBe(true); + const lastCall = adminBrowseSpy.lastCall.args[0]; + const url = new URL(lastCall.request().url()); + expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); + }); + test('member uuid gets set when loading more comments', async ({page}) => { + // create 25 comments + for (let i = 0; i < 25; i++) { + mockedApi.addComment({html: `

This is comment ${i}

`}); + } + const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); + const {frame} = await initializeTest(page); + await frame.getByTestId('pagination-component').click(); + const lastCall = adminBrowseSpy.lastCall.args[0]; + const url = new URL(lastCall.request().url()); + expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); + }); + + test('member uuid gets set when changing order', async ({page}) => { + mockedApi.addComment({ + html: '

This is the oldest

', + created_at: new Date('2024-02-01T00:00:00Z') + }); + mockedApi.addComment({ + html: '

This is comment 2

', + created_at: new Date('2024-03-02T00:00:00Z') + }); + mockedApi.addComment({ + html: '

This is the newest comment

', + created_at: new Date('2024-04-03T00:00:00Z') + }); + + const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); const {frame} = await initializeTest(page); - // Click the hide button for 2nd comment + const sortingForm = await frame.getByTestId('comments-sorting-form'); + + await sortingForm.click(); + + const sortingDropdown = await frame.getByTestId( + 'comments-sorting-form-dropdown' + ); + + const optionSelect = await sortingDropdown.getByText('Newest'); + mockedApi.setDelay(100); + await optionSelect.click(); + const lastCall = adminBrowseSpy.lastCall.args[0]; + const url = new URL(lastCall.request().url()); + expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); + }); + + test('member uuid gets set when loading more replies', async ({page}) => { + mockedApi.addComment({ + html: '

This is comment 1

', + replies: [ + buildReply({html: '

This is reply 1

'}), + buildReply({html: '

This is reply 2

'}), + buildReply({html: '

This is reply 3

'}), + buildReply({html: '

This is reply 4

'}), + buildReply({html: '

This is reply 5

'}), + buildReply({html: '

This is reply 6

'}) + ] + }); + + const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'getReplies'); + const {frame} = await initializeTest(page); + const comments = await frame.getByTestId('comment-component'); + const comment = comments.nth(0); + await comment.getByTestId('reply-pagination-button').click(); + const lastCall = adminBrowseSpy.lastCall.args[0]; + const url = new URL(lastCall.request().url()); + expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); + }); + + test('member uuid gets set when reading a comment (after unhiding)', async ({page}) => { + mockedApi.addComment({html: '

This is comment 1

'}); + mockedApi.addComment({html: '

This is comment 2

', status: 'hidden'}); + const adminReadSpy = sinon.spy(mockedApi.adminRequestHandlers, 'getOrUpdateComment'); + const {frame} = await initializeTest(page); + const comments = await frame.getByTestId('comment-component'); + await expect(comments).toHaveCount(2); + await expect(comments.nth(1)).toContainText('Hidden for members'); + const moreButtons = comments.nth(1).getByTestId('more-button'); + await moreButtons.click(); + await moreButtons.getByTestId('show-button').click(); + await expect(comments.nth(1)).not.toContainText('Hidden for members'); + + const lastCall = adminReadSpy.lastCall.args[0]; + const url = new URL(lastCall.request().url()); + + expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); + }); + + test('hidden comments are not displayed for non-admins', async ({page}) => { + mockedApi.addComment({html: '

This is comment 1

'}); + mockedApi.addComment({html: '

This is comment 2

', status: 'hidden'}); + + const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); + + const {frame} = await initializeTest(page, {isAdmin: false}); + const comments = await frame.getByTestId('comment-component'); + await expect(comments).toHaveCount(1); + + expect(adminBrowseSpy.called).toBe(false); + }); + + test('hidden comments are displayed for admins', async ({page}) => { + mockedApi.addComment({html: '

This is comment 1

'}); + mockedApi.addComment({html: '

This is comment 2

', status: 'hidden'}); + + const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); + + const {frame} = await initializeTest(page); + const comments = await frame.getByTestId('comment-component'); + await expect(comments).toHaveCount(2); + await expect(comments.nth(1)).toContainText('Hidden for members'); + + expect(adminBrowseSpy.called).toBe(true); + }); + + test('can hide and show comments', async ({page}) => { + [1,2].forEach(i => mockedApi.addComment({html: `

This is comment ${i}

`})); + + const {frame} = await initializeTest(page); + const comments = await frame.getByTestId('comment-component'); + + // Hide the 2nd comment const moreButtons = frame.getByTestId('more-button'); await moreButtons.nth(1).click(); - await moreButtons.nth(1).getByTestId('hide-button').click(); + await moreButtons.nth(1).getByText('Hide comment').click(); - // comment becomes hidden - const comments = frame.getByTestId('comment-component'); const secondComment = comments.nth(1); - await expect(secondComment).toContainText('This comment has been hidden.'); - await expect(secondComment).not.toContainText('This is comment 2'); + await expect(secondComment).toContainText('Hidden for members'); - // can show it again + // Check can show it again await moreButtons.nth(1).click(); - await moreButtons.nth(1).getByTestId('show-button').click(); + await moreButtons.nth(1).getByText('Show comment').click(); await expect(secondComment).toContainText('This is comment 2'); }); - test.describe('commentImprovements', function () { - test('memeber uuid are passed to admin browse api params', async ({page}) => { - mockedApi.addComment({html: '

This is comment 1

'}); - const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); - const {frame} = await initializeTest(page, {labs: true}); - const comments = await frame.getByTestId('comment-component'); - await expect(comments).toHaveCount(1); - expect(adminBrowseSpy.called).toBe(true); - const lastCall = adminBrowseSpy.lastCall.args[0]; - const url = new URL(lastCall.request().url()); - expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); + test('can hide and show replies', async ({page}) => { + mockedApi.addComment({ + id: '1', + html: '

This is comment 1

', + replies: [ + buildReply({id: '2', html: '

This is reply 1

'}), + buildReply({id: '3', html: '

This is reply 2

'}) + ] }); - test('member uuid gets set when loading more comments', async ({page}) => { - // create 25 comments - for (let i = 0; i < 25; i++) { - mockedApi.addComment({html: `

This is comment ${i}

`}); - } - const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); - const {frame} = await initializeTest(page, {labs: true}); - await frame.getByTestId('pagination-component').click(); - const lastCall = adminBrowseSpy.lastCall.args[0]; - const url = new URL(lastCall.request().url()); - expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); + const {frame} = await initializeTest(page); + const comments = await frame.getByTestId('comment-component'); + const replyToHide = comments.nth(1); + + // Hide the 1st reply + await replyToHide.getByTestId('more-button').click(); + await replyToHide.getByTestId('hide-button').click(); + + await expect(replyToHide).toContainText('Hidden for members'); + + // Show it again + await replyToHide.getByTestId('more-button').click(); + await replyToHide.getByTestId('show-button').click(); + + await expect(replyToHide).not.toContainText('Hidden for members'); + }); + + test('updates in-reply-to snippets when hiding', async ({page}) => { + mockedApi.addComment({ + id: '1', + html: '

This is comment 1

', + replies: [ + buildReply({id: '2', html: '

This is reply 1

'}), + buildReply({id: '3', html: '

This is reply 2

', in_reply_to_id: '2', in_reply_to_snippet: 'This is reply 1'}), + buildReply({id: '4', html: '

This is reply 3

'}) + ] }); - test('member uuid gets set when changing order', async ({page}) => { - mockedApi.addComment({ - html: '

This is the oldest

', - created_at: new Date('2024-02-01T00:00:00Z') - }); - mockedApi.addComment({ - html: '

This is comment 2

', - created_at: new Date('2024-03-02T00:00:00Z') - }); - mockedApi.addComment({ - html: '

This is the newest comment

', - created_at: new Date('2024-04-03T00:00:00Z') - }); + const {frame} = await initializeTest(page); + const comments = await frame.getByTestId('comment-component'); + const replyToHide = comments.nth(1); + const inReplyToComment = comments.nth(2); - const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); - const {frame} = await initializeTest(page, {labs: true}); + // Hide the 1st reply + await replyToHide.getByTestId('more-button').click(); + await replyToHide.getByTestId('hide-button').click(); - const sortingForm = await frame.getByTestId('comments-sorting-form'); + await expect(inReplyToComment).toContainText('[removed]'); + await expect(inReplyToComment).not.toContainText('This is reply 1'); - await sortingForm.click(); + // Show it again + await replyToHide.getByTestId('more-button').click(); + await replyToHide.getByTestId('show-button').click(); - const sortingDropdown = await frame.getByTestId( - 'comments-sorting-form-dropdown' - ); + await expect(inReplyToComment).not.toContainText('[removed]'); + await expect(inReplyToComment).toContainText('This is reply 1'); + }); - const optionSelect = await sortingDropdown.getByText('Newest'); - mockedApi.setDelay(100); - await optionSelect.click(); - const lastCall = adminBrowseSpy.lastCall.args[0]; - const url = new URL(lastCall.request().url()); - expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); - }); + test('has correct comments count', async ({page}) => { + mockedApi.addComment({html: '

This is comment 1

', replies: [buildReply()]}); + mockedApi.addComment({html: '

This is comment 2

'}); - test('member uuid gets set when loading more replies', async ({page}) => { - mockedApi.addComment({ - html: '

This is comment 1

', - replies: [ - buildReply({html: '

This is reply 1

'}), - buildReply({html: '

This is reply 2

'}), - buildReply({html: '

This is reply 3

'}), - buildReply({html: '

This is reply 4

'}), - buildReply({html: '

This is reply 5

'}), - buildReply({html: '

This is reply 6

'}) - ] - }); - - const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'getReplies'); - const {frame} = await initializeTest(page, {labs: true}); - const comments = await frame.getByTestId('comment-component'); - const comment = comments.nth(0); - await comment.getByTestId('reply-pagination-button').click(); - const lastCall = adminBrowseSpy.lastCall.args[0]; - const url = new URL(lastCall.request().url()); - expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); - }); - - test('member uuid gets set when reading a comment (after unhiding)', async ({page}) => { - mockedApi.addComment({html: '

This is comment 1

'}); - mockedApi.addComment({html: '

This is comment 2

', status: 'hidden'}); - const adminReadSpy = sinon.spy(mockedApi.adminRequestHandlers, 'getOrUpdateComment'); - const {frame} = await initializeTest(page, {labs: true}); - const comments = await frame.getByTestId('comment-component'); - await expect(comments).toHaveCount(2); - await expect(comments.nth(1)).toContainText('Hidden for members'); - const moreButtons = comments.nth(1).getByTestId('more-button'); - await moreButtons.click(); - await moreButtons.getByTestId('show-button').click(); - await expect(comments.nth(1)).not.toContainText('Hidden for members'); - - const lastCall = adminReadSpy.lastCall.args[0]; - const url = new URL(lastCall.request().url()); - - expect(url.searchParams.get('impersonate_member_uuid')).toBe('12345'); - }); - - test('hidden comments are not displayed for non-admins', async ({page}) => { - mockedApi.addComment({html: '

This is comment 1

'}); - mockedApi.addComment({html: '

This is comment 2

', status: 'hidden'}); - - const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); - - const {frame} = await initializeTest(page, {isAdmin: false, labs: true}); - const comments = await frame.getByTestId('comment-component'); - await expect(comments).toHaveCount(1); - - expect(adminBrowseSpy.called).toBe(false); - }); - - test('hidden comments are displayed for admins', async ({page}) => { - mockedApi.addComment({html: '

This is comment 1

'}); - mockedApi.addComment({html: '

This is comment 2

', status: 'hidden'}); - - const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments'); - - const {frame} = await initializeTest(page, {labs: true}); - const comments = await frame.getByTestId('comment-component'); - await expect(comments).toHaveCount(2); - await expect(comments.nth(1)).toContainText('Hidden for members'); - - expect(adminBrowseSpy.called).toBe(true); - }); - - test('can hide and show comments', async ({page}) => { - [1,2].forEach(i => mockedApi.addComment({html: `

This is comment ${i}

`})); - - const {frame} = await initializeTest(page, {labs: true}); - const comments = await frame.getByTestId('comment-component'); - - // Hide the 2nd comment - const moreButtons = frame.getByTestId('more-button'); - await moreButtons.nth(1).click(); - await moreButtons.nth(1).getByText('Hide comment').click(); - - const secondComment = comments.nth(1); - await expect(secondComment).toContainText('Hidden for members'); - - // Check can show it again - await moreButtons.nth(1).click(); - await moreButtons.nth(1).getByText('Show comment').click(); - await expect(secondComment).toContainText('This is comment 2'); - }); - - test('can hide and show replies', async ({page}) => { - mockedApi.addComment({ - id: '1', - html: '

This is comment 1

', - replies: [ - buildReply({id: '2', html: '

This is reply 1

'}), - buildReply({id: '3', html: '

This is reply 2

'}) - ] - }); - - const {frame} = await initializeTest(page, {labs: true}); - const comments = await frame.getByTestId('comment-component'); - const replyToHide = comments.nth(1); - - // Hide the 1st reply - await replyToHide.getByTestId('more-button').click(); - await replyToHide.getByTestId('hide-button').click(); - - await expect(replyToHide).toContainText('Hidden for members'); - - // Show it again - await replyToHide.getByTestId('more-button').click(); - await replyToHide.getByTestId('show-button').click(); - - await expect(replyToHide).not.toContainText('Hidden for members'); - }); - - test('updates in-reply-to snippets when hiding', async ({page}) => { - mockedApi.addComment({ - id: '1', - html: '

This is comment 1

', - replies: [ - buildReply({id: '2', html: '

This is reply 1

'}), - buildReply({id: '3', html: '

This is reply 2

', in_reply_to_id: '2', in_reply_to_snippet: 'This is reply 1'}), - buildReply({id: '4', html: '

This is reply 3

'}) - ] - }); - - const {frame} = await initializeTest(page, {labs: true}); - const comments = await frame.getByTestId('comment-component'); - const replyToHide = comments.nth(1); - const inReplyToComment = comments.nth(2); - - // Hide the 1st reply - await replyToHide.getByTestId('more-button').click(); - await replyToHide.getByTestId('hide-button').click(); - - await expect(inReplyToComment).toContainText('[removed]'); - await expect(inReplyToComment).not.toContainText('This is reply 1'); - - // Show it again - await replyToHide.getByTestId('more-button').click(); - await replyToHide.getByTestId('show-button').click(); - - await expect(inReplyToComment).not.toContainText('[removed]'); - await expect(inReplyToComment).toContainText('This is reply 1'); - }); - - test('has correct comments count', async ({page}) => { - mockedApi.addComment({html: '

This is comment 1

', replies: [buildReply()]}); - mockedApi.addComment({html: '

This is comment 2

'}); - - const {frame} = await initializeTest(page, {labs: true}); - await expect(frame.getByTestId('count')).toContainText('3 comments'); - }); + const {frame} = await initializeTest(page); + await expect(frame.getByTestId('count')).toContainText('3 comments'); }); }); diff --git a/apps/comments-ui/test/e2e/autoclose-forms.test.ts b/apps/comments-ui/test/e2e/autoclose-forms.test.ts index a705d25069..b31f760fa6 100644 --- a/apps/comments-ui/test/e2e/autoclose-forms.test.ts +++ b/apps/comments-ui/test/e2e/autoclose-forms.test.ts @@ -26,9 +26,7 @@ test.describe('Autoclose forms', async () => { mockedApi, page, publication: 'Publisher weekly', - labs: { - commentImprovements: true - } + labs: {} })); }); diff --git a/apps/comments-ui/test/e2e/content.test.ts b/apps/comments-ui/test/e2e/content.test.ts index b3bce44d92..63c632a852 100644 --- a/apps/comments-ui/test/e2e/content.test.ts +++ b/apps/comments-ui/test/e2e/content.test.ts @@ -28,9 +28,7 @@ test.describe('Deleted and Hidden Content', async () => { mockedApi, page, publication: 'Publisher Weekly', - labs: { - commentImprovements: true - } + labs: {} }); const iframeElement = await page.locator('iframe[data-frame="admin-auth"]'); @@ -95,9 +93,7 @@ test.describe('Deleted and Hidden Content', async () => { mockedApi, page, publication: 'Publisher Weekly', - labs: { - commentImprovements: true - } + labs: {} }); await expect (frame.getByText('This is comment 2')).not.toBeVisible(); @@ -131,9 +127,7 @@ test.describe('Deleted and Hidden Content', async () => { mockedApi, page, publication: 'Publisher Weekly', - labs: { - commentImprovements: true - } + labs: {} }); await expect (frame.getByText('This is reply 1')).toBeVisible(); diff --git a/apps/comments-ui/test/e2e/cta.test.ts b/apps/comments-ui/test/e2e/cta.test.ts index 15fa51fed1..8dc437df2d 100644 --- a/apps/comments-ui/test/e2e/cta.test.ts +++ b/apps/comments-ui/test/e2e/cta.test.ts @@ -19,9 +19,9 @@ test.describe('CTA', async () => { await expect(ctaBox).toContainText('Become a member of Publisher Weekly to start commenting'); await expect(ctaBox).toContainText('Sign in'); - // Does not show the reply buttons if not logged in + // Show the reply buttons if not logged in const replyButton = frame.getByTestId('reply-button'); - await expect(replyButton).toHaveCount(0); + await expect(replyButton).toHaveCount(2); // Does not show the main form const form = frame.getByTestId('form'); @@ -66,9 +66,9 @@ test.describe('CTA', async () => { // Don't show sign in button await expect(ctaBox).not.toContainText('Sign in'); - // No replies or comments possible + // Shows replies buttons const replyButton = frame.getByTestId('reply-button'); - await expect(replyButton).toHaveCount(0); + await expect(replyButton).toHaveCount(2); const form = frame.getByTestId('form'); await expect(form).toHaveCount(0); diff --git a/apps/comments-ui/test/e2e/pagination.test.ts b/apps/comments-ui/test/e2e/pagination.test.ts index 59fa7d7e19..1ba49d4f8e 100644 --- a/apps/comments-ui/test/e2e/pagination.test.ts +++ b/apps/comments-ui/test/e2e/pagination.test.ts @@ -16,21 +16,22 @@ test.describe('Pagination', async () => { await expect(frame.getByTestId('pagination-component')).toBeVisible(); // Check text in pagination button - await expect(frame.getByTestId('pagination-component')).toContainText('Show 1 previous comment'); + await expect(frame.getByTestId('pagination-component')).toContainText('Load more (1)'); // Test total comments with test-id comment-component is 5 await expect(frame.getByTestId('comment-component')).toHaveCount(20); // Check only the first latest 20 comments are visible - await expect(frame.getByText('This is comment 1.')).not.toBeVisible(); + await expect(frame.getByText('This is comment 1.')).toBeVisible(); await expect(frame.getByText('This is comment 2.')).toBeVisible(); await expect(frame.getByText('This is comment 3.')).toBeVisible(); await expect(frame.getByText('This is comment 4.')).toBeVisible(); await expect(frame.getByText('This is comment 5.')).toBeVisible(); await expect(frame.getByText('This is comment 6.')).toBeVisible(); await expect(frame.getByText('This is comment 20.')).toBeVisible(); + await expect(frame.getByText('This is comment 21.')).not.toBeVisible(); - // + // // Click the pagination button await frame.getByTestId('pagination-component').click(); @@ -39,7 +40,7 @@ test.describe('Pagination', async () => { await expect(frame.getByTestId('comment-component')).toHaveCount(21); // Check comments 6 is visible - await expect(frame.getByText('This is comment 1.')).toBeVisible(); + await expect(frame.getByText('This is comment 21.')).toBeVisible(); // Check the pagination button is not visible await expect(frame.getByTestId('pagination-component')).not.toBeVisible(); diff --git a/apps/comments-ui/test/utils/MockedApi.ts b/apps/comments-ui/test/utils/MockedApi.ts index f35c04a4f9..9aeca70f3f 100644 --- a/apps/comments-ui/test/utils/MockedApi.ts +++ b/apps/comments-ui/test/utils/MockedApi.ts @@ -162,10 +162,10 @@ export class MockedApi { let filteredComments = this.comments; - if (this.labs.commentImprovements && !admin) { + if (!admin) { function filterPublishedComments(comments: any[] = []) { return comments - .filter(comment => comment.status === 'published') + .filter(comment => (comment.status === 'published' || comment.replies?.some(r => r.status === 'published'))) .map(comment => ({...comment, replies: filterPublishedComments(comment.replies)})); } diff --git a/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/comments.js b/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/comments.js index da63927e03..de24ba576c 100644 --- a/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/comments.js +++ b/ghost/core/core/server/api/endpoints/utils/serializers/output/mappers/comments.js @@ -2,7 +2,6 @@ const _ = require('lodash'); const utils = require('../../..'); const url = require('../utils/url'); const htmlToPlaintext = require('@tryghost/html-to-plaintext'); -const labs = require('../../../../../../../shared/labs'); const commentFields = [ 'id', @@ -48,20 +47,16 @@ const commentMapper = (model, frame) => { const isPublicRequest = utils.isMembersAPI(frame); - if (labs.isSet('commentImprovements')) { - if (jsonModel.inReplyTo && (jsonModel.inReplyTo.status === 'published' || (!isPublicRequest && jsonModel.inReplyTo.status === 'hidden'))) { - jsonModel.in_reply_to_snippet = htmlToPlaintext.commentSnippet(jsonModel.inReplyTo.html); - } else if (jsonModel.inReplyTo && jsonModel.inReplyTo.status !== 'published') { - jsonModel.in_reply_to_snippet = '[removed]'; - } else { - jsonModel.in_reply_to_snippet = null; - } - - if (!jsonModel.inReplyTo) { - jsonModel.in_reply_to_id = null; - } + if (jsonModel.inReplyTo && (jsonModel.inReplyTo.status === 'published' || (!isPublicRequest && jsonModel.inReplyTo.status === 'hidden'))) { + jsonModel.in_reply_to_snippet = htmlToPlaintext.commentSnippet(jsonModel.inReplyTo.html); + } else if (jsonModel.inReplyTo && jsonModel.inReplyTo.status !== 'published') { + jsonModel.in_reply_to_snippet = '[removed]'; } else { - delete jsonModel.in_reply_to_id; + jsonModel.in_reply_to_snippet = null; + } + + if (!jsonModel.inReplyTo) { + jsonModel.in_reply_to_id = null; } const response = _.pick(jsonModel, commentFields); diff --git a/ghost/core/core/server/models/comment.js b/ghost/core/core/server/models/comment.js index 55be161eb9..cb6503b0c7 100644 --- a/ghost/core/core/server/models/comment.js +++ b/ghost/core/core/server/models/comment.js @@ -3,7 +3,6 @@ const _ = require('lodash'); const errors = require('@tryghost/errors'); const tpl = require('@tryghost/tpl'); const {ValidationError} = require('@tryghost/errors'); -const labs = require('../../shared/labs'); const messages = { emptyComment: 'The body of a comment cannot be empty', @@ -62,43 +61,21 @@ const Comment = ghostBookshelf.Model.extend({ .query('limit', 3); }, - customQuery(qb) { - qb.where(function () { - this.whereNotIn('comments.status', ['hidden', 'deleted']) - .orWhereExists(function () { - this.select(1) - .from('comments as replies') - .whereRaw('replies.parent_id = comments.id') - .whereNotIn('replies.status', ['hidden', 'deleted']); - }); - }); - }, - - adminCustomQuery(qb) { - qb.where(function () { - this.whereNotIn('comments.status', ['deleted']) - .orWhereExists(function () { - this.select(1) - .from('comments as replies') - .whereRaw('replies.parent_id = comments.id') - .whereNotIn('replies.status', ['deleted']); - }); - }); - }, - + // Called by our filtered-collection bookshelf plugin applyCustomQuery(options) { - if (labs.isSet('commentImprovements')) { - if (!options.isAdmin) { // if it's an admin request, we don't need to apply the custom query - this.query((qb) => { - this.customQuery(qb, options); - }); - } - if (options.isAdmin) { - this.query((qb) => { - this.adminCustomQuery(qb, options); - }); - } - } + const excludedCommentStatuses = options.isAdmin ? ['deleted'] : ['hidden', 'deleted']; + + this.query((qb) => { + qb.where(function () { + this.whereNotIn('comments.status', excludedCommentStatuses) + .orWhereExists(function () { + this.select(1) + .from('comments as replies') + .whereRaw('replies.parent_id = comments.id') + .whereNotIn('replies.status', excludedCommentStatuses); + }); + }); + }); }, emitChange: function emitChange(event, options) { @@ -228,7 +205,7 @@ const Comment = ghostBookshelf.Model.extend({ // - public requests never return hidden or deleted replies // - admin requests never return deleted replies but do return hidden replies const repliesOptionIndex = withRelated.indexOf('replies'); - if (labs.isSet('commentImprovements') && repliesOptionIndex > -1) { + if (repliesOptionIndex > -1) { withRelated[repliesOptionIndex] = { replies: (qb) => { if (isAdmin) { @@ -297,31 +274,15 @@ const Comment = ghostBookshelf.Model.extend({ countRelations() { return { replies(modelOrCollection, options) { - if (labs.isSet('commentImprovements') && !options.isAdmin) { - modelOrCollection.query('columns', 'comments.*', (qb) => { - qb.count('replies.id') - .from('comments AS replies') - .whereRaw('replies.parent_id = comments.id') - .whereNotIn('replies.status', ['hidden', 'deleted']) - .as('count__replies'); - }); - } else { - modelOrCollection.query('columns', 'comments.*', (qb) => { - qb.count('replies.id') - .from('comments AS replies') - .whereRaw('replies.parent_id = comments.id') - .as('count__replies'); - }); - } - if (options.isAdmin && labs.isSet('commentImprovements')) { - modelOrCollection.query('columns', 'comments.*', (qb) => { - qb.count('replies.id') - .from('comments AS replies') - .whereRaw('replies.parent_id = comments.id') - .whereNotIn('replies.status', ['deleted']) - .as('count__replies'); - }); - } + const excludedCommentStatuses = options.isAdmin ? ['deleted'] : ['hidden', 'deleted']; + + modelOrCollection.query('columns', 'comments.*', (qb) => { + qb.count('replies.id') + .from('comments AS replies') + .whereRaw('replies.parent_id = comments.id') + .whereNotIn('replies.status', excludedCommentStatuses) + .as('count__replies'); + }); }, likes(modelOrCollection) { modelOrCollection.query('columns', 'comments.*', (qb) => { diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/comments.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/comments.test.js.snap index eaac91b8cd..89d51daffb 100644 --- a/ghost/core/test/e2e-api/admin/__snapshots__/comments.test.js.snap +++ b/ghost/core/test/e2e-api/admin/__snapshots__/comments.test.js.snap @@ -1,172 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Admin Comments API - commentImprovements off Hide Can hide comments 1: [body] 1`] = ` -Object { - "comments": Array [ - Object { - "count": Object { - "likes": Any, - "replies": 0, - }, - "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, - "edited_at": null, - "html": "

This is a comment

", - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "liked": Any, - "member": Object { - "avatar_image": null, - "expertise": null, - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "name": "Mr Egg", - "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, - }, - "replies": Array [], - "status": "published", - }, - ], -} -`; - -exports[`Admin Comments API - commentImprovements off Hide Can hide comments 2: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "361", - "content-type": "application/json; charset=utf-8", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "vary": "Accept-Encoding", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements off Hide Can hide comments 3: [body] 1`] = ` -Object { - "comments": Array [ - Object { - "count": Object { - "likes": Any, - "replies": 0, - }, - "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, - "edited_at": null, - "html": null, - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "liked": Any, - "member": Object { - "avatar_image": null, - "expertise": null, - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "name": "Mr Egg", - "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, - }, - "replies": Array [], - "status": "hidden", - }, - ], -} -`; - -exports[`Admin Comments API - commentImprovements off Hide Can hide comments 4: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "336", - "content-type": "application/json; charset=utf-8", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "vary": "Accept-Encoding", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements off Hide Can hide replies 1: [body] 1`] = ` -Object { - "comments": Array [ - Object { - "count": Object { - "likes": Any, - "replies": 0, - }, - "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, - "edited_at": null, - "html": "

This is a reply

", - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "liked": Any, - "member": Object { - "avatar_image": null, - "expertise": null, - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "name": null, - "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, - }, - "replies": Array [], - "status": "published", - }, - ], -} -`; - -exports[`Admin Comments API - commentImprovements off Hide Can hide replies 2: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "355", - "content-type": "application/json; charset=utf-8", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "vary": "Accept-Encoding", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements off Hide Can hide replies 3: [body] 1`] = ` -Object { - "comments": Array [ - Object { - "count": Object { - "likes": Any, - "replies": 0, - }, - "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, - "edited_at": null, - "html": null, - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "liked": Any, - "member": Object { - "avatar_image": null, - "expertise": null, - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "name": null, - "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, - }, - "replies": Array [], - "status": "hidden", - }, - ], -} -`; - -exports[`Admin Comments API - commentImprovements off Hide Can hide replies 4: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "332", - "content-type": "application/json; charset=utf-8", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "vary": "Accept-Encoding", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements off likes Can like a comment 1: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "x-cache-invalidate": "/api/members/comments/post/618ba1ffbe2896088840a6e1/", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements on Hide Can hide comments 1: [body] 1`] = ` +exports[`Admin Comments API Hide Can hide comments 1: [body] 1`] = ` Object { "comments": Array [ Object { @@ -195,7 +29,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Hide Can hide comments 2: [headers] 1`] = ` +exports[`Admin Comments API Hide Can hide comments 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -207,7 +41,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Hide Can hide comments 3: [body] 1`] = ` +exports[`Admin Comments API Hide Can hide comments 3: [body] 1`] = ` Object { "comments": Array [ Object { @@ -236,7 +70,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Hide Can hide comments 4: [headers] 1`] = ` +exports[`Admin Comments API Hide Can hide comments 4: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -248,7 +82,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Hide Can hide replies 1: [body] 1`] = ` +exports[`Admin Comments API Hide Can hide replies 1: [body] 1`] = ` Object { "comments": Array [ Object { @@ -277,7 +111,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Hide Can hide replies 2: [headers] 1`] = ` +exports[`Admin Comments API Hide Can hide replies 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -289,7 +123,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Hide Can hide replies 3: [body] 1`] = ` +exports[`Admin Comments API Hide Can hide replies 3: [body] 1`] = ` Object { "comments": Array [ Object { @@ -318,7 +152,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Hide Can hide replies 4: [headers] 1`] = ` +exports[`Admin Comments API Hide Can hide replies 4: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -330,7 +164,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Logged in member gets own likes via admin api can get comment liked status by impersonating member 1: [headers] 1`] = ` +exports[`Admin Comments API Logged in member gets own likes via admin api can get comment liked status by impersonating member via admin browse route 1: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -340,7 +174,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Logged in member gets own likes via admin api can get comment liked status by impersonating member via admin browse route 1: [headers] 1`] = ` +exports[`Admin Comments API Logged in member gets own likes via admin api can get comment liked status by impersonating member via admin get by comment id read route 1: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -350,77 +184,7 @@ Object { } `; -exports[`Admin Comments API - commentImprovements on Logged in member gets own likes via admin api can get comment liked status by impersonating member via admin get by comment id read route 1: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "x-cache-invalidate": "/api/members/comments/post/618ba1ffbe2896088840a6e1/", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements on Logged in member gets own likes via admin api can get comment liked status by impersonating member via admin get by comment read route 1: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "x-cache-invalidate": "/api/members/comments/post/618ba1ffbe2896088840a6e1/", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements on Logged in member gets own likes via admin api can get comment liked status by impersonating member via admin get by comment replies route 1: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "x-cache-invalidate": "/api/members/comments/post/618ba1ffbe2896088840a6e1/", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements on Logged in member gets own likes via admin api can get comment liked status by impersonating member via admin get by comment replies route 2: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "x-cache-invalidate": "/api/members/comments/post/618ba1ffbe2896088840a6e1/", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements on Logged in member gets own likes via admin api can get comment liked status by impersonating member via admin get by comment replies route 3: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "x-cache-invalidate": "/api/members/comments/post/618ba1ffbe2896088840a6e1/, /api/members/comments/67568ca99db975825f9772a5/replies/", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements on Logged in member likes via admin api can get comment liked status by impersonating member 1: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "x-cache-invalidate": "/api/members/comments/post/618ba1ffbe2896088840a6e1/", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements on can get logged in member likes via admin api Can like a comment 1: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "x-cache-invalidate": "/api/members/comments/post/618ba1ffbe2896088840a6e1/", - "x-powered-by": "Express", -} -`; - -exports[`Admin Comments API - commentImprovements on likes Can like a comment 1: [headers] 1`] = ` +exports[`Admin Comments API Logged in member gets own likes via admin api can get comment liked status by impersonating member via admin get by comment replies route 1: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", diff --git a/ghost/core/test/e2e-api/admin/comments.test.js b/ghost/core/test/e2e-api/admin/comments.test.js index 70a2efab8f..421e3ebf0d 100644 --- a/ghost/core/test/e2e-api/admin/comments.test.js +++ b/ghost/core/test/e2e-api/admin/comments.test.js @@ -100,673 +100,579 @@ async function getMemberComments(url, commentsMatcher = [membersCommentMatcher]) }); } -[true, false].forEach((enableCommentImprovements) => { - describe(`Admin Comments API - commentImprovements ${enableCommentImprovements ? 'on' : 'off'}`, function () { - before(async function () { - const agents = await agentProvider.getAgentsForMembers(); - adminApi = agents.adminAgent; - membersApi = agents.membersAgent; +describe(`Admin Comments API`, function () { + before(async function () { + const agents = await agentProvider.getAgentsForMembers(); + adminApi = agents.adminAgent; + membersApi = agents.membersAgent; - await fixtureManager.init('users', 'posts', 'members', 'comments'); + await fixtureManager.init('users', 'posts', 'members', 'comments'); - await adminApi.loginAsOwner(); + await adminApi.loginAsOwner(); - mockManager.mockSetting('comments_enabled', 'all'); - postId = fixtureManager.get('posts', 1).id; - }); + mockManager.mockSetting('comments_enabled', 'all'); + postId = fixtureManager.get('posts', 1).id; + }); - beforeEach(async function () { - // ensure we don't have data dependencies across tests - await dbUtils.truncate('comments'); - await dbUtils.truncate('comment_likes'); - await dbUtils.truncate('comment_reports'); + beforeEach(async function () { + // ensure we don't have data dependencies across tests + await dbUtils.truncate('comments'); + await dbUtils.truncate('comment_likes'); + await dbUtils.truncate('comment_reports'); + }); - if (!enableCommentImprovements) { - mockManager.mockLabsDisabled('commentImprovements'); - } - }); + after(function () { + mockManager.restore(); + }); - after(function () { - mockManager.restore(); - }); + describe('Hide', function () { + it('Can hide comments', async function () { + const commentToHide = await dbFns.addComment({member_id: fixtureManager.get('members', 0).id}); - describe('Hide', function () { - it('Can hide comments', async function () { - const commentToHide = await dbFns.addComment({member_id: fixtureManager.get('members', 0).id}); + const {body: {comments: [initialState]}} = await getMemberComments(`/api/comments/${commentToHide.id}/`); - const {body: {comments: [initialState]}} = await getMemberComments(`/api/comments/${commentToHide.id}/`); + assert.equal(initialState.status, 'published'); - assert.equal(initialState.status, 'published'); - - const res = await adminApi.put(`comments/${commentToHide.id}/`).body({ - comments: [{ - id: commentToHide.id, - status: 'hidden' - }] - }); - - assert.equal(res.headers['x-cache-invalidate'], `/api/members/comments/post/${postId}/`); - - const {body: {comments: [afterHiding]}} = await getMemberComments(`/api/comments/${commentToHide.id}/`); - - assert.equal(afterHiding.status, 'hidden'); - }); - - it('Can hide replies', async function () { - const {parent, replies: [commentToHide]} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - replies: [{ - member_id: fixtureManager.get('members', 1).id - }] - }); - - const {body: {comments: [initialState]}} = await getMemberComments(`/api/comments/${commentToHide.id}/`); - - assert.equal(initialState.status, 'published'); - - const res = await adminApi.put(`comments/${commentToHide.id}/`).body({ - comments: [{ - id: commentToHide.id, - status: 'hidden' - }] - }); - - assert.equal( - res.headers['x-cache-invalidate'], - `/api/members/comments/post/${postId}/, /api/members/comments/${parent.id}/replies/` - ); - - const {body: {comments: [afterHiding]}} = await getMemberComments(`/api/comments/${commentToHide.id}/`); - - assert.equal(afterHiding.status, 'hidden'); - }); - }); - - describe('browse by post', function () { - it('returns comments', async function () { - await dbFns.addComment({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'published' - }); - - await dbFns.addComment({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 2', - status: 'published' - }); - const res = await adminApi.get('/comments/post/' + postId + '/'); - assert.equal(res.body.comments.length, 2); - }); - - it('returns hidden comments (with html)', async function () { - await dbFns.addComment({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', + const res = await adminApi.put(`comments/${commentToHide.id}/`).body({ + comments: [{ + id: commentToHide.id, status: 'hidden' - }); - const res = await adminApi.get('/comments/post/' + postId + '/'); - - const hiddenComment = res.body.comments[0]; - assert.equal(hiddenComment.html, 'Comment 1'); + }] }); - it('returns hidden replies (with html)', async function () { - const {parent} = await dbFns.addCommentWithReplies({ + assert.equal(res.headers['x-cache-invalidate'], `/api/members/comments/post/${postId}/`); + + const {body: {comments: [afterHiding]}} = await getMemberComments(`/api/comments/${commentToHide.id}/`); + + assert.equal(afterHiding.status, 'hidden'); + }); + + it('Can hide replies', async function () { + const {parent, replies: [commentToHide]} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + replies: [{ + member_id: fixtureManager.get('members', 1).id + }] + }); + + const {body: {comments: [initialState]}} = await getMemberComments(`/api/comments/${commentToHide.id}/`); + + assert.equal(initialState.status, 'published'); + + const res = await adminApi.put(`comments/${commentToHide.id}/`).body({ + comments: [{ + id: commentToHide.id, + status: 'hidden' + }] + }); + + assert.equal( + res.headers['x-cache-invalidate'], + `/api/members/comments/post/${postId}/, /api/members/comments/${parent.id}/replies/` + ); + + const {body: {comments: [afterHiding]}} = await getMemberComments(`/api/comments/${commentToHide.id}/`); + + assert.equal(afterHiding.status, 'hidden'); + }); + }); + + describe('browse by post', function () { + it('returns comments', async function () { + await dbFns.addComment({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'published' + }); + + await dbFns.addComment({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 2', + status: 'published' + }); + const res = await adminApi.get('/comments/post/' + postId + '/'); + assert.equal(res.body.comments.length, 2); + }); + + it('returns hidden comments (with html)', async function () { + await dbFns.addComment({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'hidden' + }); + const res = await adminApi.get('/comments/post/' + postId + '/'); + + const hiddenComment = res.body.comments[0]; + assert.equal(hiddenComment.html, 'Comment 1'); + }); + + it('returns hidden replies (with html)', async function () { + const {parent} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + replies: [{ + member_id: fixtureManager.get('members', 1).id, + status: 'hidden' + }] + }); + + const res = await adminApi.get(`/comments/${parent.id}/`); + + const hiddenReply = res.body.comments[0].replies[0]; + assert.equal(hiddenReply.html, '

This is a reply

'); + }); + + it('returns hidden comments and hidden replies', async function () { + await dbFns.addCommentWithReplies({ + status: 'hidden', + member_id: fixtureManager.get('members', 0).id, + replies: [{ + member_id: fixtureManager.get('members', 1).id, + status: 'hidden' + }] + }); + + const res = await adminApi.get('/comments/post/' + postId + '/'); + + const hiddenComment = res.body.comments[0]; + assert.equal(hiddenComment.status, 'hidden'); + + const hiddenReply = res.body.comments[0].replies[0]; + assert.equal(hiddenReply.status, 'hidden'); + }); + + it('can load additional replies', async function () { + const {parent} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'published', + replies: [{ member_id: fixtureManager.get('members', 0).id, - replies: [{ - member_id: fixtureManager.get('members', 1).id, - status: 'hidden' - }] - }); - - const res = await adminApi.get(`/comments/${parent.id}/`); - - const hiddenReply = res.body.comments[0].replies[0]; - assert.equal(hiddenReply.html, '

This is a reply

'); + html: 'Reply 1', + status: 'published' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 2', + status: 'published' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 3', + status: 'published' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 4', + status: 'published' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 5', + status: 'published' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 6', + status: 'published' + }] }); - it('returns hidden comments and hidden replies', async function () { - await dbFns.addCommentWithReplies({ + const res = await adminApi.get('/comments/post/' + postId + '/'); + const item = res.body.comments.find(cmt => parent.id === cmt.id); + const lastReply = item.replies[item.replies.length - 1]; + const filter = encodeURIComponent(`id:>'${lastReply.id}'`); + const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`); + assert.equal(res2.body.comments.length, 3); + }); + + it('can load additional replies and includes hidden replies', async function () { + const {parent} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'published', + replies: [{ + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 1', + status: 'published' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 2', + status: 'hidden' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 3', + status: 'hidden' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 4', + status: 'hidden' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 5', + status: 'published' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 6', + status: 'published' + }] + }); + + const res = await adminApi.get('/comments/post/' + postId + '/'); + const item = res.body.comments.find(cmt => parent.id === cmt.id); + const lastReply = item.replies[item.replies.length - 1]; + const filter = encodeURIComponent(`id:>'${lastReply.id}'`); + const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`); + assert.equal(res2.body.comments.length, 3); + }); + + it('includes html string of replies', async function () { + const {parent} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'published', + replies: [{ + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 1', + status: 'published' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 2', + status: 'hidden' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 3', + status: 'hidden' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 4', + status: 'hidden' + }] + }); + + const res = await adminApi.get('/comments/post/' + postId + '/'); + const item = res.body.comments.find(cmt => parent.id === cmt.id); + const lastReply = item.replies[item.replies.length - 1]; + const filter = encodeURIComponent(`id:>'${lastReply.id}'`); + const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`); + assert.equal(res2.body.comments.length, 1); + assert.equal(res2.body.comments[0].html, 'Reply 4'); + }); + + it('Does return published replies', async function () { + const {parent} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + replies: [{ + member_id: fixtureManager.get('members', 1).id, + status: 'published' + }, { + member_id: fixtureManager.get('members', 2).id, + status: 'published' + }, { + member_id: fixtureManager.get('members', 3).id, + status: 'published' + }] + }); + + const res = await adminApi.get(`/comments/${parent.get('id')}/`); + res.body.comments[0].replies.length.should.eql(3); + res.body.comments[0].replies[0].member.should.be.an.Object().with.properties('id', 'uuid', 'name', 'avatar_image'); + res.body.comments[0].replies[0].should.be.an.Object().with.properties('id', 'html', 'status', 'created_at', 'member', 'count'); + }); + + it('ensure replies are always ordered from oldest to newest', async function () { + const {parent} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'published', + created_at: new Date('2021-01-01'), + replies: [{ + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 1', + status: 'published', + created_at: new Date('2022-01-01') + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 2', + status: 'published', + created_at: new Date('2022-01-02') + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 3', status: 'hidden', + created_at: new Date('2022-01-03') + }, { member_id: fixtureManager.get('members', 0).id, - replies: [{ - member_id: fixtureManager.get('members', 1).id, - status: 'hidden' - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - - const hiddenComment = res.body.comments[0]; - assert.equal(hiddenComment.status, 'hidden'); - - const hiddenReply = res.body.comments[0].replies[0]; - assert.equal(hiddenReply.status, 'hidden'); - }); - - it('can load additional replies', async function () { - const {parent} = await dbFns.addCommentWithReplies({ + html: 'Reply 4', + status: 'hidden', + created_at: new Date('2022-01-04') + }, { member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', + html: 'Reply 5', status: 'published', - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'published' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 2', - status: 'published' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 3', - status: 'published' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 4', - status: 'published' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 5', - status: 'published' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 6', - status: 'published' - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - const item = res.body.comments.find(cmt => parent.id === cmt.id); - const lastReply = item.replies[item.replies.length - 1]; - const filter = encodeURIComponent(`id:>'${lastReply.id}'`); - const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`); - assert.equal(res2.body.comments.length, 3); - }); - - it('can load additional replies and includes hidden replies', async function () { - const {parent} = await dbFns.addCommentWithReplies({ + created_at: new Date('2022-01-05') + }, { member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', + html: 'Reply 6', status: 'published', - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'published' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 2', - status: 'hidden' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 3', - status: 'hidden' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 4', - status: 'hidden' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 5', - status: 'published' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 6', - status: 'published' - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - const item = res.body.comments.find(cmt => parent.id === cmt.id); - const lastReply = item.replies[item.replies.length - 1]; - const filter = encodeURIComponent(`id:>'${lastReply.id}'`); - const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`); - assert.equal(res2.body.comments.length, 3); + created_at: new Date('2022-01-06') + }] }); - it('includes html string of replies', async function () { - const {parent} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'published', - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'published' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 2', - status: 'hidden' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 3', - status: 'hidden' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 4', - status: 'hidden' - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - const item = res.body.comments.find(cmt => parent.id === cmt.id); - const lastReply = item.replies[item.replies.length - 1]; - const filter = encodeURIComponent(`id:>'${lastReply.id}'`); - const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`); - assert.equal(res2.body.comments.length, 1); - assert.equal(res2.body.comments[0].html, 'Reply 4'); - }); - - it('Does return published replies', async function () { - const {parent} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - replies: [{ - member_id: fixtureManager.get('members', 1).id, - status: 'published' - }, { - member_id: fixtureManager.get('members', 2).id, - status: 'published' - }, { - member_id: fixtureManager.get('members', 3).id, - status: 'published' - }] - }); - - const res = await adminApi.get(`/comments/${parent.get('id')}/`); - res.body.comments[0].replies.length.should.eql(3); - res.body.comments[0].replies[0].member.should.be.an.Object().with.properties('id', 'uuid', 'name', 'avatar_image'); - res.body.comments[0].replies[0].should.be.an.Object().with.properties('id', 'html', 'status', 'created_at', 'member', 'count'); - }); - - it('ensure replies are always ordered from oldest to newest', async function () { - const {parent} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'published', - created_at: new Date('2021-01-01'), - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'published', - created_at: new Date('2022-01-01') - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 2', - status: 'published', - created_at: new Date('2022-01-02') - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 3', - status: 'hidden', - created_at: new Date('2022-01-03') - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 4', - status: 'hidden', - created_at: new Date('2022-01-04') - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 5', - status: 'published', - created_at: new Date('2022-01-05') - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 6', - status: 'published', - created_at: new Date('2022-01-06') - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - const item = res.body.comments.find(cmt => parent.id === cmt.id); - const lastReply = item.replies[item.replies.length - 1]; - const filter = encodeURIComponent(`id:>'${lastReply.id}'`); - const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=10&filter=${filter}`); - assert.equal(res2.body.comments.length, 3); - assert.equal(res2.body.comments[0].html, 'Reply 4'); - assert.equal(res2.body.comments[1].html, 'Reply 5'); - assert.equal(res2.body.comments[2].html, 'Reply 6'); - }); - - if (enableCommentImprovements) { - it('does not return deleted comments', async function () { - await dbFns.addComment({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'deleted' - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - assert.equal(res.body.comments.length, 0); - }); - - it('returns deleted comments if they have published replies', async function () { - await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'deleted', - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'published' - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - - const deletedComment = res.body.comments[0]; - assert.equal(deletedComment.html, 'Comment 1'); - - const publishedReply = res.body.comments[0].replies[0]; - assert.equal(publishedReply.html, 'Reply 1'); - }); - - it('does not return deleted comments with only deleted replies', async function () { - await dbFns.addComment({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'deleted' - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - assert.equal(res.body.comments.length, 0); - }); - } else { - it('returns deleted comments', async function () { - await dbFns.addComment({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'deleted' - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - assert.equal(res.body.comments.length, 1); - }); - } - - if (enableCommentImprovements) { - it('does not return deleted replies', async function () { - await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'published', - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'deleted' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 2', - status: 'hidden' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 3', - status: 'published' - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - const comment = res.body.comments[0]; - assert.equal(comment.replies.length, 2); - assert.notEqual(comment.replies[0].status, 'deleted'); - assert.notEqual(comment.replies[1].status, 'deleted'); - }); - } else { - it('returns deleted replies', async function () { - await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'published', - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'published' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 2', - status: 'deleted' - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - const comment = res.body.comments[0]; - assert.equal(comment.replies.length, 2); - }); - } - - // These tests check changes that only occur - // with the commentImprovements flag enabled - // - Ensure the opposite behaviour is tested as well - if (enableCommentImprovements) { - it('includes hidden replies but not deleted replies in count', async function () { - await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'published', - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'hidden' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 2', - status: 'deleted' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 3', - status: 'published' - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - const comment = res.body.comments[0]; - assert.equal(comment.count.replies, 2); - }); - } else { - it('includes all replies in count', async function () { - await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'published', - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'hidden' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 2', - status: 'deleted' - }, { - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 3', - status: 'published' - }] - }); - - const res = await adminApi.get('/comments/post/' + postId + '/'); - const comment = res.body.comments[0]; - assert.equal(comment.count.replies, 3); - }); - } - - if (enableCommentImprovements) { - it('includes in_reply_to_snippet for hidden replies', async function () { - const post = fixtureManager.get('posts', 1); - const {parent, replies: [inReplyTo]} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - post_id: post.id, - html: 'Comment 1', - status: 'published', - replies: [{ - member_id: fixtureManager.get('members', 0).id, - html: 'Reply 1', - status: 'hidden' - }] - }); - - await dbFns.addComment({ - member_id: fixtureManager.get('members', 0).id, - post_id: post.id, - parent_id: parent.id, - in_reply_to_id: inReplyTo.id, - html: 'Reply 2', - status: 'published' - }); - - const res = await adminApi.get('/comments/post/' + post.id + '/'); - const comment = res.body.comments[0]; - const reply = comment.replies[1]; - assert.equal(reply.in_reply_to_snippet, 'Reply 1'); - }); - } + const res = await adminApi.get('/comments/post/' + postId + '/'); + const item = res.body.comments.find(cmt => parent.id === cmt.id); + const lastReply = item.replies[item.replies.length - 1]; + const filter = encodeURIComponent(`id:>'${lastReply.id}'`); + const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=10&filter=${filter}`); + assert.equal(res2.body.comments.length, 3); + assert.equal(res2.body.comments[0].html, 'Reply 4'); + assert.equal(res2.body.comments[1].html, 'Reply 5'); + assert.equal(res2.body.comments[2].html, 'Reply 6'); }); - describe('get by id', function () { - it('can get a published comment', async function () { - const comment = await dbFns.addComment({ + it('does not return deleted comments', async function () { + await dbFns.addComment({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'deleted' + }); + + const res = await adminApi.get('/comments/post/' + postId + '/'); + assert.equal(res.body.comments.length, 0); + }); + + it('returns deleted comments if they have published replies', async function () { + await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'deleted', + replies: [{ member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', + html: 'Reply 1', status: 'published' - }); - - const res = await adminApi.get(`/comments/${comment.id}/`); - assert.equal(res.body.comments[0].html, 'Comment 1'); + }] }); - it('can get a hidden comment', async function () { - const comment = await dbFns.addComment({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'hidden' - }); + const res = await adminApi.get('/comments/post/' + postId + '/'); - const res = await adminApi.get(`/comments/${comment.id}/`); - assert.equal(res.body.comments[0].html, 'Comment 1'); - }); + const deletedComment = res.body.comments[0]; + assert.equal(deletedComment.html, 'Comment 1'); - // TODO: Should this be possible? - it('can get a deleted comment', async function () { - const comment = await dbFns.addComment({ - member_id: fixtureManager.get('members', 0).id, - html: 'Comment 1', - status: 'deleted' - }); - - const res = await adminApi.get(`/comments/${comment.id}/`); - assert.equal(res.body.comments[0].html, 'Comment 1'); - }); - - it('includes published replies', async function () { - const {parent} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - replies: [{ - member_id: fixtureManager.get('members', 1).id, - html: 'Reply 1', - status: 'published' - }] - }); - - const res = await adminApi.get(`/comments/${parent.id}/`); - const reply = res.body.comments[0].replies[0]; - assert.equal(reply.html, 'Reply 1'); - }); - - it('includes hidden replies', async function () { - const {parent} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - replies: [{ - member_id: fixtureManager.get('members', 1).id, - html: 'Reply 1', - status: 'hidden' - }] - }); - - const res = await adminApi.get(`/comments/${parent.id}/`); - const reply = res.body.comments[0].replies[0]; - assert.equal(reply.html, 'Reply 1'); - }); - - if (enableCommentImprovements) { - it('does not include deleted replies', async function () { - const {parent} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - replies: [{ - member_id: fixtureManager.get('members', 1).id, - html: 'Reply 1', - status: 'deleted' - }] - }); - - const res = await adminApi.get(`/comments/${parent.id}/`); - assert.equal(res.body.comments[0].replies.length, 0); - }); - } else { - it('includes deleted replies', async function () { - const {parent} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 0).id, - replies: [{ - member_id: fixtureManager.get('members', 1).id, - html: 'Reply 1', - status: 'deleted' - }] - }); - - const res = await adminApi.get(`/comments/${parent.id}/`); - const reply = res.body.comments[0].replies[0]; - assert.equal(reply.html, 'Reply 1'); - }); - } + const publishedReply = res.body.comments[0].replies[0]; + assert.equal(publishedReply.html, 'Reply 1'); }); - if (enableCommentImprovements) { - describe('Logged in member gets own likes via admin api', function () { - let comment; - let post; - this.beforeEach(async function () { - post = fixtureManager.get('posts', 1); - comment = await dbFns.addComment({ - post_id: post.id, - member_id: fixtureManager.get('members', 1).id - }); - await membersApi.loginAs(fixtureManager.get('members', 1).email); - - await membersApi - .post(`/api/comments/${comment.get('id')}/like/`) - .expectStatus(204) - .matchHeaderSnapshot({ - etag: anyEtag - }) - .expectEmptyBody(); - }); - it('can get comment liked status by impersonating member via admin browse route', async function () { - // Like the comment - const res = await adminApi.get(`/comments/post/${post.id}/?impersonate_member_uuid=${fixtureManager.get('members', 1).uuid}`); - res.body.comments[0].liked.should.eql(true); - }); - - it('can get comment liked status by impersonating member via admin get by comment id read route', async function () { - const res = await adminApi.get(`/comments/${comment.get('id')}/?impersonate_member_uuid=${fixtureManager.get('members', 1).uuid}`); - res.body.comments[0].liked.should.eql(true); - }); - - it('can get comment liked status by impersonating member via admin get by comment replies route', async function () { - const {parent, replies} = await dbFns.addCommentWithReplies({ - member_id: fixtureManager.get('members', 1).id, - replies: [{ - member_id: fixtureManager.get('members', 1).id - }] - }); - - await membersApi - .post(`/api/comments/${replies[0].id}/like/`) - .expectStatus(204) - .expectEmptyBody(); - - const res = await adminApi.get(`/comments/${parent.get('id')}/replies/?impersonate_member_uuid=${fixtureManager.get('members', 1).uuid}`); - res.body.comments[0].liked.should.eql(true); - }); + it('does not return deleted comments with only deleted replies', async function () { + await dbFns.addComment({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'deleted' }); - } + + const res = await adminApi.get('/comments/post/' + postId + '/'); + assert.equal(res.body.comments.length, 0); + }); + + it('does not return deleted replies', async function () { + await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'published', + replies: [{ + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 1', + status: 'deleted' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 2', + status: 'hidden' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 3', + status: 'published' + }] + }); + + const res = await adminApi.get('/comments/post/' + postId + '/'); + const comment = res.body.comments[0]; + assert.equal(comment.replies.length, 2); + assert.notEqual(comment.replies[0].status, 'deleted'); + assert.notEqual(comment.replies[1].status, 'deleted'); + }); + + it('includes hidden replies but not deleted replies in count', async function () { + await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'published', + replies: [{ + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 1', + status: 'hidden' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 2', + status: 'deleted' + }, { + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 3', + status: 'published' + }] + }); + + const res = await adminApi.get('/comments/post/' + postId + '/'); + const comment = res.body.comments[0]; + assert.equal(comment.count.replies, 2); + }); + it('includes in_reply_to_snippet for hidden replies', async function () { + const post = fixtureManager.get('posts', 1); + const {parent, replies: [inReplyTo]} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + post_id: post.id, + html: 'Comment 1', + status: 'published', + replies: [{ + member_id: fixtureManager.get('members', 0).id, + html: 'Reply 1', + status: 'hidden' + }] + }); + + await dbFns.addComment({ + member_id: fixtureManager.get('members', 0).id, + post_id: post.id, + parent_id: parent.id, + in_reply_to_id: inReplyTo.id, + html: 'Reply 2', + status: 'published' + }); + + const res = await adminApi.get('/comments/post/' + post.id + '/'); + const comment = res.body.comments[0]; + const reply = comment.replies[1]; + assert.equal(reply.in_reply_to_snippet, 'Reply 1'); + }); + }); + + describe('get by id', function () { + it('can get a published comment', async function () { + const comment = await dbFns.addComment({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'published' + }); + + const res = await adminApi.get(`/comments/${comment.id}/`); + assert.equal(res.body.comments[0].html, 'Comment 1'); + }); + + it('can get a hidden comment', async function () { + const comment = await dbFns.addComment({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'hidden' + }); + + const res = await adminApi.get(`/comments/${comment.id}/`); + assert.equal(res.body.comments[0].html, 'Comment 1'); + }); + + // TODO: Should this be possible? + it('can get a deleted comment', async function () { + const comment = await dbFns.addComment({ + member_id: fixtureManager.get('members', 0).id, + html: 'Comment 1', + status: 'deleted' + }); + + const res = await adminApi.get(`/comments/${comment.id}/`); + assert.equal(res.body.comments[0].html, 'Comment 1'); + }); + + it('includes published replies', async function () { + const {parent} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + replies: [{ + member_id: fixtureManager.get('members', 1).id, + html: 'Reply 1', + status: 'published' + }] + }); + + const res = await adminApi.get(`/comments/${parent.id}/`); + const reply = res.body.comments[0].replies[0]; + assert.equal(reply.html, 'Reply 1'); + }); + + it('includes hidden replies', async function () { + const {parent} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + replies: [{ + member_id: fixtureManager.get('members', 1).id, + html: 'Reply 1', + status: 'hidden' + }] + }); + + const res = await adminApi.get(`/comments/${parent.id}/`); + const reply = res.body.comments[0].replies[0]; + assert.equal(reply.html, 'Reply 1'); + }); + + it('does not include deleted replies', async function () { + const {parent} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 0).id, + replies: [{ + member_id: fixtureManager.get('members', 1).id, + html: 'Reply 1', + status: 'deleted' + }] + }); + + const res = await adminApi.get(`/comments/${parent.id}/`); + assert.equal(res.body.comments[0].replies.length, 0); + }); + }); + + describe('Logged in member gets own likes via admin api', function () { + let comment; + let post; + this.beforeEach(async function () { + post = fixtureManager.get('posts', 1); + comment = await dbFns.addComment({ + post_id: post.id, + member_id: fixtureManager.get('members', 1).id + }); + await membersApi.loginAs(fixtureManager.get('members', 1).email); + + await membersApi + .post(`/api/comments/${comment.get('id')}/like/`) + .expectStatus(204) + .matchHeaderSnapshot({ + etag: anyEtag + }) + .expectEmptyBody(); + }); + it('can get comment liked status by impersonating member via admin browse route', async function () { + // Like the comment + const res = await adminApi.get(`/comments/post/${post.id}/?impersonate_member_uuid=${fixtureManager.get('members', 1).uuid}`); + res.body.comments[0].liked.should.eql(true); + }); + + it('can get comment liked status by impersonating member via admin get by comment id read route', async function () { + const res = await adminApi.get(`/comments/${comment.get('id')}/?impersonate_member_uuid=${fixtureManager.get('members', 1).uuid}`); + res.body.comments[0].liked.should.eql(true); + }); + + it('can get comment liked status by impersonating member via admin get by comment replies route', async function () { + const {parent, replies} = await dbFns.addCommentWithReplies({ + member_id: fixtureManager.get('members', 1).id, + replies: [{ + member_id: fixtureManager.get('members', 1).id + }] + }); + + await membersApi + .post(`/api/comments/${replies[0].id}/like/`) + .expectStatus(204) + .expectEmptyBody(); + + const res = await adminApi.get(`/comments/${parent.get('id')}/replies/?impersonate_member_uuid=${fixtureManager.get('members', 1).uuid}`); + res.body.comments[0].liked.should.eql(true); + }); }); }); diff --git a/ghost/core/test/e2e-api/members-comments/__snapshots__/comments.test.js.snap b/ghost/core/test/e2e-api/members-comments/__snapshots__/comments.test.js.snap index 111a966fd3..ca34c45256 100644 --- a/ghost/core/test/e2e-api/members-comments/__snapshots__/comments.test.js.snap +++ b/ghost/core/test/e2e-api/members-comments/__snapshots__/comments.test.js.snap @@ -12,6 +12,8 @@ Object { "edited_at": null, "html": "

This is a message

New line

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -31,7 +33,7 @@ exports[`Comments API Tier-only posts Members with access Can comment on a post Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "379", + "content-length": "428", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -53,6 +55,8 @@ Object { "edited_at": null, "html": "This is a reply", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -72,7 +76,7 @@ exports[`Comments API Tier-only posts Members with access Can reply to a comment Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "348", + "content-length": "397", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -154,6 +158,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -174,6 +180,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -191,6 +199,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -222,7 +232,7 @@ exports[`Comments API when commenting enabled for all when authenticated Browsin Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1118", + "content-length": "1265", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -242,6 +252,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -259,6 +271,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -281,6 +295,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -310,7 +326,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can bro Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1118", + "content-length": "1265", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -330,6 +346,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -347,6 +365,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -369,6 +389,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -398,7 +420,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can bro Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1118", + "content-length": "1265", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -418,6 +440,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -438,6 +462,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -455,6 +481,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -486,7 +514,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can bro Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1118", + "content-length": "1265", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -506,6 +534,8 @@ Object { "edited_at": null, "html": "

This is a message

New line

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -525,7 +555,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can com Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "379", + "content-length": "428", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -547,6 +577,8 @@ Object { "edited_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, "html": "Updated comment", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -566,7 +598,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can edi Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "370", + "content-length": "419", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -617,6 +649,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -636,7 +670,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can lik Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "367", + "content-length": "416", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -666,6 +700,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -685,7 +721,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can lik Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "356", + "content-length": "405", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -705,6 +741,8 @@ Object { "edited_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, "html": "Illegal comment update", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -724,7 +762,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can not Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "377", + "content-length": "426", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -814,6 +852,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -833,7 +873,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can rem Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "357", + "content-length": "406", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -853,6 +893,8 @@ Object { "edited_at": null, "html": "This is a reply", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -872,7 +914,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can rep Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "348", + "content-length": "397", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -894,6 +936,8 @@ Object { "edited_at": null, "html": "This is a reply", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -913,7 +957,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can rep Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "348", + "content-length": "397", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -935,6 +979,8 @@ Object { "edited_at": null, "html": "This is a reply", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -954,7 +1000,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can rep Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "348", + "content-length": "397", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -976,6 +1022,8 @@ Object { "edited_at": null, "html": "This is a reply", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -995,7 +1043,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can rep Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "348", + "content-length": "397", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -1025,6 +1073,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1053,7 +1103,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can req Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "414", + "content-length": "463", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -1072,6 +1122,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1090,6 +1142,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1108,6 +1162,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1126,6 +1182,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1144,6 +1202,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1162,6 +1222,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1180,6 +1242,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1208,7 +1272,7 @@ exports[`Comments API when commenting enabled for all when authenticated Can ret Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "2313", + "content-length": "2656", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -1297,6 +1361,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1314,6 +1380,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1332,6 +1400,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1350,6 +1420,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -1371,7 +1443,7 @@ exports[`Comments API when commenting enabled for all when authenticated Limits Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1308", + "content-length": "1504", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -1379,7 +1451,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled doesn't count deleted or hidden comments in replies count 1: [body] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post doesn't count deleted or hidden comments in replies count 1: [body] 1`] = ` Object { "comments": Array [ Object { @@ -1439,7 +1511,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled doesn't count deleted or hidden comments in replies count 2: [headers] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post doesn't count deleted or hidden comments in replies count 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -1451,7 +1523,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes deleted comments 1: [body] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes deleted comments 1: [body] 1`] = ` Object { "comments": Array [], "meta": Object { @@ -1467,7 +1539,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes deleted comments 2: [headers] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes deleted comments 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -1479,7 +1551,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes deleted comments if all replies are hidden or deleted 1: [body] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes deleted comments if all replies are hidden or deleted 1: [body] 1`] = ` Object { "comments": Array [], "meta": Object { @@ -1495,7 +1567,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes deleted comments if all replies are hidden or deleted 2: [headers] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes deleted comments if all replies are hidden or deleted 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -1507,7 +1579,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes deleted replies 1: [body] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes deleted replies 1: [body] 1`] = ` Object { "comments": Array [ Object { @@ -1546,7 +1618,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes deleted replies 2: [headers] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes deleted replies 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -1558,7 +1630,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes hidden comments 1: [body] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes hidden comments 1: [body] 1`] = ` Object { "comments": Array [], "meta": Object { @@ -1574,7 +1646,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes hidden comments 2: [headers] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes hidden comments 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -1586,7 +1658,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes hidden comments if all replies are hidden or deleted 1: [body] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes hidden comments if all replies are hidden or deleted 1: [body] 1`] = ` Object { "comments": Array [], "meta": Object { @@ -1602,7 +1674,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes hidden comments if all replies are hidden or deleted 2: [headers] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes hidden comments if all replies are hidden or deleted 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -1614,7 +1686,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes hidden replies 1: [body] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes hidden replies 1: [body] 1`] = ` Object { "comments": Array [ Object { @@ -1653,7 +1725,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled excludes hidden replies 2: [headers] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post excludes hidden replies 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -1665,7 +1737,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled includes deleted comments if they have published replies 1: [body] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post includes deleted comments if they have published replies 1: [body] 1`] = ` Object { "comments": Array [ Object { @@ -1725,7 +1797,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled includes deleted comments if they have published replies 2: [headers] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post includes deleted comments if they have published replies 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -1737,7 +1809,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled includes hidden comments if they have published replies 1: [body] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post includes hidden comments if they have published replies 1: [body] 1`] = ` Object { "comments": Array [ Object { @@ -1797,7 +1869,7 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated browse by post when commentImprovements flag is enabled includes hidden comments if they have published replies 2: [headers] 1`] = ` +exports[`Comments API when commenting enabled for all when authenticated browse by post includes hidden comments if they have published replies 2: [headers] 1`] = ` Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", @@ -2030,88 +2102,6 @@ Object { } `; -exports[`Comments API when commenting enabled for all when authenticated replies to replies does not include in_reply_to_snippet for deleted comments 1: [body] 1`] = ` -Object { - "comments": Array [ - Object { - "count": Object { - "likes": Any, - "replies": 0, - }, - "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, - "edited_at": null, - "html": "

This is a comment

", - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "in_reply_to_id": Nullable, - "in_reply_to_snippet": null, - "liked": Any, - "member": Object { - "avatar_image": null, - "expertise": null, - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "name": null, - "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, - }, - "replies": Array [], - "status": "published", - }, - ], -} -`; - -exports[`Comments API when commenting enabled for all when authenticated replies to replies does not include in_reply_to_snippet for deleted comments 2: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "406", - "content-type": "application/json; charset=utf-8", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "vary": "Accept-Encoding", - "x-powered-by": "Express", -} -`; - -exports[`Comments API when commenting enabled for all when authenticated replies to replies does not include in_reply_to_snippet for hidden comments 1: [body] 1`] = ` -Object { - "comments": Array [ - Object { - "count": Object { - "likes": Any, - "replies": 0, - }, - "created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/, - "edited_at": null, - "html": "

This is a comment

", - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "in_reply_to_id": Nullable, - "in_reply_to_snippet": null, - "liked": Any, - "member": Object { - "avatar_image": null, - "expertise": null, - "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, - "name": null, - "uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, - }, - "replies": Array [], - "status": "published", - }, - ], -} -`; - -exports[`Comments API when commenting enabled for all when authenticated replies to replies does not include in_reply_to_snippet for hidden comments 2: [headers] 1`] = ` -Object { - "access-control-allow-origin": "*", - "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "406", - "content-type": "application/json; charset=utf-8", - "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, - "vary": "Accept-Encoding", - "x-powered-by": "Express", -} -`; - exports[`Comments API when commenting enabled for all when authenticated replies to replies has redacted in_reply_to_snippet when referenced comment is deleted 1: [body] 1`] = ` Object { "comments": Array [ @@ -2376,6 +2366,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -2393,6 +2385,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -2424,7 +2418,7 @@ exports[`Comments API when commenting enabled for all when not authenticated Can Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "764", + "content-length": "862", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -2444,6 +2438,8 @@ Object { "edited_at": null, "html": "

This is a comment

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -2461,6 +2457,8 @@ Object { "edited_at": null, "html": "

This is a reply

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -2492,7 +2490,7 @@ exports[`Comments API when commenting enabled for all when not authenticated Can Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "764", + "content-length": "862", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Accept-Encoding", @@ -2662,6 +2660,8 @@ Object { "edited_at": null, "html": "

This is a message

New line

", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -2681,7 +2681,7 @@ exports[`Comments API when paid only commenting Members with access Can comment Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "379", + "content-length": "428", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -2703,6 +2703,8 @@ Object { "edited_at": null, "html": "This is a reply", "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, + "in_reply_to_id": null, + "in_reply_to_snippet": null, "liked": Any, "member": Object { "avatar_image": null, @@ -2722,7 +2724,7 @@ exports[`Comments API when paid only commenting Members with access Can reply to Object { "access-control-allow-origin": "*", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "348", + "content-length": "397", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, diff --git a/ghost/core/test/e2e-api/members-comments/comments.test.js b/ghost/core/test/e2e-api/members-comments/comments.test.js index 142f472c99..1e88f8c7cf 100644 --- a/ghost/core/test/e2e-api/members-comments/comments.test.js +++ b/ghost/core/test/e2e-api/members-comments/comments.test.js @@ -7,7 +7,6 @@ const moment = require('moment-timezone'); const settingsCache = require('../../../core/shared/settings-cache'); const sinon = require('sinon'); const DomainEvents = require('@tryghost/domain-events'); -const {mockLabsEnabled, mockLabsDisabled} = require('../../utils/e2e-framework-mock-manager'); let membersAgent, membersAgent2, postId, postAuthorEmail, postTitle; @@ -351,8 +350,6 @@ describe('Comments API', function () { beforeEach(async function () { mockManager.mockMail(); - mockLabsDisabled('commentImprovements'); - // ensure we don't have data dependencies across tests await dbUtils.truncate('comments'); await dbUtils.truncate('comment_likes'); @@ -403,52 +400,44 @@ describe('Comments API', function () { ]); }); - describe('when commentImprovements flag is enabled', function () { - beforeEach(function () { - mockLabsEnabled('commentImprovements'); + it('excludes hidden comments', async function () { + const hiddenComment = await dbFns.addComment({ + post_id: postId, + member_id: fixtureManager.get('members', 2).id, + html: 'This is a hidden comment', + status: 'hidden' }); - it('excludes hidden comments', async function () { - const hiddenComment = await dbFns.addComment({ - post_id: postId, - member_id: fixtureManager.get('members', 2).id, - html: 'This is a hidden comment', - status: 'hidden' - }); + const data2 = await membersAgent + .get(`/api/comments/post/${postId}/`) + .expectStatus(200); - const data2 = await membersAgent - .get(`/api/comments/post/${postId}/`) - .expectStatus(200); + // check that hiddenComment.id is not in the response + should(data2.body.comments.map(c => c.id)).not.containEql(hiddenComment.id); + should(data2.body.comments.length).eql(0); + }); - // check that hiddenComment.id is not in the response - should(data2.body.comments.map(c => c.id)).not.containEql(hiddenComment.id); - should(data2.body.comments.length).eql(0); + it('excludes deleted comments', async function () { + await dbFns.addComment({ + post_id: postId, + member_id: fixtureManager.get('members', 2).id, + html: 'This is a deleted comment', + status: 'deleted' }); - it('excludes deleted comments', async function () { - // await mockManager.mockLabsEnabled('commentImprovements'); - await dbFns.addComment({ - post_id: postId, - member_id: fixtureManager.get('members', 2).id, - html: 'This is a deleted comment', - status: 'deleted' - }); + const data2 = await membersAgent + .get(`/api/comments/post/${postId}/`) + .expectStatus(200); - const data2 = await membersAgent - .get(`/api/comments/post/${postId}/`) - .expectStatus(200); - - // go through all comments and check if the deleted comment is not there - data2.body.comments.forEach((comment) => { - should(comment.html).not.eql('This is a deleted comment'); - }); - - data2.body.comments.length.should.eql(0); + // go through all comments and check if the deleted comment is not there + data2.body.comments.forEach((comment) => { + should(comment.html).not.eql('This is a deleted comment'); }); + + data2.body.comments.length.should.eql(0); }); it('shows hidden and deleted comment where there is a reply', async function () { - await mockManager.mockLabsEnabled('commentImprovements'); await setupBrowseCommentsData(); const hiddenComment = await dbFns.addComment({ post_id: postId, @@ -505,7 +494,6 @@ describe('Comments API', function () { }); it('Returns nothing if both parent and reply are hidden', async function () { - await mockManager.mockLabsEnabled('commentImprovements'); const hiddenComment = await dbFns.addComment({ post_id: postId, member_id: fixtureManager.get('members', 0).id, @@ -652,11 +640,7 @@ describe('Comments API', function () { should.not.exist(response.body.comments[0].unsubscribe_url); }); - describe('browse by post when commentImprovements flag is enabled', function () { - beforeEach(function () { - mockLabsEnabled('commentImprovements'); - }); - + describe('browse by post', function () { it('excludes deleted comments', async function () { await dbFns.addComment({ member_id: fixtureManager.get('members', 2).id, @@ -913,7 +897,6 @@ describe('Comments API', function () { }); it('hidden replies are not included in the count', async function () { - await mockManager.mockLabsEnabled('commentImprovements'); const {parent} = await dbFns.addCommentWithReplies({ member_id: fixtureManager.get('members', 0).id, replies: new Array(5).fill({ @@ -928,7 +911,6 @@ describe('Comments API', function () { }); it('deleted replies are not included in the count', async function () { - await mockManager.mockLabsEnabled('commentImprovements'); const {parent} = await dbFns.addCommentWithReplies({ member_id: fixtureManager.get('members', 0).id, replies: new Array(5).fill({ @@ -1335,10 +1317,6 @@ describe('Comments API', function () { }); describe('replies to replies', function () { - beforeEach(function () { - mockLabsEnabled('commentImprovements'); - }); - it('can browse comments with replies to replies', async function () { const {replies: [reply]} = await dbFns.addCommentWithReplies({ member_id: fixtureManager.get('members', 1).id, diff --git a/ghost/core/test/unit/api/canary/utils/serializers/output/mapper.test.js b/ghost/core/test/unit/api/canary/utils/serializers/output/mapper.test.js index 9f75597600..e8fa083803 100644 --- a/ghost/core/test/unit/api/canary/utils/serializers/output/mapper.test.js +++ b/ghost/core/test/unit/api/canary/utils/serializers/output/mapper.test.js @@ -8,7 +8,6 @@ const extraAttrsUtils = require('../../../../../../../core/server/api/endpoints/ const mappers = require('../../../../../../../core/server/api/endpoints/utils/serializers/output/mappers'); const memberAttribution = require('../../../../../../../core/server/services/member-attribution'); const htmlToPlaintext = require('@tryghost/html-to-plaintext'); -const labs = require('../../../../../../../core/shared/labs'); function createJsonModel(data) { return Object.assign(data, {toJSON: sinon.stub().returns(data)}); @@ -414,6 +413,8 @@ describe('Unit: utils/serializers/output/mappers', function () { data: { // same except the remove foo keys id: 'id1', + in_reply_to_id: null, + in_reply_to_snippet: null, status: 'status1', html: 'html1', created_at: 'created_at1', @@ -612,11 +613,7 @@ describe('Unit: utils/serializers/output/mappers', function () { }); }); - describe('Comment mapper (commentImprovements flag enabled)', function () { - beforeEach(function () { - sinon.stub(labs, 'isSet').returns(true); - }); - + describe('Comment mapper', function () { it('includes in_reply_to_snippet for published replies-to-replies', function () { const frame = {}; diff --git a/ghost/i18n/locales/af/comments.json b/ghost/i18n/locales/af/comments.json index 0a761a5016..1daed63e26 100644 --- a/ghost/i18n/locales/af/comments.json +++ b/ghost/i18n/locales/af/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Sluit aan by die bespreking", "Just now": "Sopas", + "Load more ({{amount}})": "", "Local resident": "Plaaslike inwoner", "Member discussion": "Lidmaat bespreking", "Name": "Naam", @@ -55,9 +56,7 @@ "Sent": "Gestuur", "Show": "Wys", "Show {{amount}} more replies": "Wys {{amount}} meer antwoorde", - "Show {{amount}} previous comments": "Wys {{amount}} vorige kommentaar", "Show 1 more reply": "Wys nog 1 antwoord", - "Show 1 previous comment": "Wys 1 vorige kommentaar", "Show comment": "Wys kommentaar", "Sign in": "Teken in", "Sign up now": "Sluit nou aan", diff --git a/ghost/i18n/locales/ar/comments.json b/ghost/i18n/locales/ar/comments.json index 9495b2bae2..326463a3a8 100644 --- a/ghost/i18n/locales/ar/comments.json +++ b/ghost/i18n/locales/ar/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "فلان الفلانى", "Join the discussion": "انضم للمحادثة", "Just now": "الآن", + "Load more ({{amount}})": "", "Local resident": "مقيم محلى", "Member discussion": "مناقشة الاعضاء", "Name": "الاسم", @@ -55,9 +56,7 @@ "Sent": "تم الارسال", "Show": "اظهر", "Show {{amount}} more replies": "اظهر {{amount}} ردود", - "Show {{amount}} previous comments": "اظهر {{amount}} تعليقات سابقة", "Show 1 more reply": "اظهر تعليق وحيد", - "Show 1 previous comment": "اظهر التعليق السابق", "Show comment": "اظهر التعليق", "Sign in": "تسجيل الدخول", "Sign up now": "قم بالتسجيل الآن", diff --git a/ghost/i18n/locales/bg/comments.json b/ghost/i18n/locales/bg/comments.json index 79d645a5cd..70667bf190 100644 --- a/ghost/i18n/locales/bg/comments.json +++ b/ghost/i18n/locales/bg/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Иван Иванов", "Join the discussion": "Участвайте в дискусията", "Just now": "Току-що", + "Load more ({{amount}})": "", "Local resident": "Местен жител", "Member discussion": "Дискусия за абонатите", "Name": "Име", @@ -55,9 +56,7 @@ "Sent": "Изпратен", "Show": "Показване", "Show {{amount}} more replies": "Покажи още {{amount}} отговора", - "Show {{amount}} previous comments": "Покажи {{amount}} предишни коментара", "Show 1 more reply": "Покажи още един отговор", - "Show 1 previous comment": "Покажи един предишен коментар", "Show comment": "Покажи коментар", "Sign in": "Вход", "Sign up now": "Регистрация", diff --git a/ghost/i18n/locales/bn/comments.json b/ghost/i18n/locales/bn/comments.json index 1a3ed3e5dd..c4b7d93ee4 100644 --- a/ghost/i18n/locales/bn/comments.json +++ b/ghost/i18n/locales/bn/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "শাহ নেওয়াজ", "Join the discussion": "আলোচনায় যোগ দিন", "Just now": "এখনই", + "Load more ({{amount}})": "", "Local resident": "স্থানীয় বাসিন্দা", "Member discussion": "সদস্য আলোচনা", "Name": "নাম", @@ -55,9 +56,7 @@ "Sent": "পাঠানো হয়েছে", "Show": "দেখান", "Show {{amount}} more replies": " আরো {{amount}}টি উত্তর দেখান", - "Show {{amount}} previous comments": "পূর্বের {{amount}}টি মন্তব্য দেখান", "Show 1 more reply": "১টি আরো উত্তর দেখান", - "Show 1 previous comment": "১টি পূর্বের মন্তব্য দেখান", "Show comment": "মন্তব্য দেখান", "Sign in": "সাইন ইন করুন", "Sign up now": "এখনই সাইন আপ করুন", diff --git a/ghost/i18n/locales/bs/comments.json b/ghost/i18n/locales/bs/comments.json index 11d9c780db..df2860c72e 100644 --- a/ghost/i18n/locales/bs/comments.json +++ b/ghost/i18n/locales/bs/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Vanja Larsić", "Join the discussion": "Pridruži se diskusiji", "Just now": "Upravo sada", + "Load more ({{amount}})": "", "Local resident": "Lokalni stanovnik", "Member discussion": "Diskusija članova", "Name": "Ime", @@ -55,9 +56,7 @@ "Sent": "Poslano", "Show": "Prikaži", "Show {{amount}} more replies": "Prikaži još {{amount}} odgovora", - "Show {{amount}} previous comments": "Prikaži prethodnih {{amount}} komentara", "Show 1 more reply": "Prikaži još jedan odgovor", - "Show 1 previous comment": "Prikaži prethodni komentar", "Show comment": "Prikaži komentar", "Sign in": "Prijavi se", "Sign up now": "Postani član", diff --git a/ghost/i18n/locales/ca/comments.json b/ghost/i18n/locales/ca/comments.json index 71aa588db4..27b063bda5 100644 --- a/ghost/i18n/locales/ca/comments.json +++ b/ghost/i18n/locales/ca/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Uneix-te al debat", "Just now": "Just ara", + "Load more ({{amount}})": "", "Local resident": "Resident local", "Member discussion": "Debat de membres", "Name": "Nom", @@ -55,9 +56,7 @@ "Sent": "Enviat", "Show": "Mostra", "Show {{amount}} more replies": "Mostra {{amount}} respostes més", - "Show {{amount}} previous comments": "Mostra {{amount}} comentaris previs", "Show 1 more reply": "Mostra 1 resposta més", - "Show 1 previous comment": "Mostra 1 comentari previ", "Show comment": "Mostra comentari", "Sign in": "Inicia sessió", "Sign up now": "Registra't ara", diff --git a/ghost/i18n/locales/cs/comments.json b/ghost/i18n/locales/cs/comments.json index af81d4f71e..b112f4cb22 100644 --- a/ghost/i18n/locales/cs/comments.json +++ b/ghost/i18n/locales/cs/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Připojte se k diskusi", "Just now": "Právě teď", + "Load more ({{amount}})": "", "Local resident": "Místní obyvatel", "Member discussion": "Diskuse členů", "Name": "Jméno", @@ -55,9 +56,7 @@ "Sent": "Odesláno", "Show": "Zobrazit", "Show {{amount}} more replies": "Zobrazit {{amount}} dalších odpovědí", - "Show {{amount}} previous comments": "Zobrazit {{amount}} předchozích komentářů", "Show 1 more reply": "Zobrazit 1 další odpověď", - "Show 1 previous comment": "Zobrazit 1 předchozí komentář", "Show comment": "Zobrazit komentář", "Sign in": "Přihlásit se", "Sign up now": "Zaregistrujte se nyní", diff --git a/ghost/i18n/locales/da/comments.json b/ghost/i18n/locales/da/comments.json index 0b9c48cab2..ed1105688f 100644 --- a/ghost/i18n/locales/da/comments.json +++ b/ghost/i18n/locales/da/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Bliv en del af diskussionen", "Just now": "Lige nu", + "Load more ({{amount}})": "", "Local resident": "Lokal borger", "Member discussion": "Medlemsdiskussion", "Name": "Navn", @@ -55,9 +56,7 @@ "Sent": "Sendt", "Show": "Vis", "Show {{amount}} more replies": "Vis {{amount}} flere svar", - "Show {{amount}} previous comments": "Vis {{amount}} tidligere kommentarer", "Show 1 more reply": "Vis 1 mere svar", - "Show 1 previous comment": "Vis 1 tidligere kommentar", "Show comment": "Vis kommentar", "Sign in": "Log ind", "Sign up now": "Tilmed dig nu", diff --git a/ghost/i18n/locales/de-CH/comments.json b/ghost/i18n/locales/de-CH/comments.json index 988fca41e2..15f12197ca 100644 --- a/ghost/i18n/locales/de-CH/comments.json +++ b/ghost/i18n/locales/de-CH/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "{{amount}} vorherige Kommentare anzeigen", "Show 1 more reply": "", - "Show 1 previous comment": "Einen vorherigen Kommentar anzeigen", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/de/comments.json b/ghost/i18n/locales/de/comments.json index 8c9cdaad93..ae344307c9 100644 --- a/ghost/i18n/locales/de/comments.json +++ b/ghost/i18n/locales/de/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Nimm an der Diskussion teil", "Just now": "Gerade eben", + "Load more ({{amount}})": "", "Local resident": "Ortsansässiger", "Member discussion": "Mitgliederdiskussion", "Name": "Name", @@ -55,9 +56,7 @@ "Sent": "Gesendet", "Show": "Anzeigen", "Show {{amount}} more replies": "{{amount}} weitere Antworten anzeigen", - "Show {{amount}} previous comments": "{{amount}} frühere Kommentare anzeigen", "Show 1 more reply": "1 weitere Antwort anzeigen", - "Show 1 previous comment": "1 vorherigen Kommentar anzeigen", "Show comment": "Kommentar anzeigen", "Sign in": "Einloggen", "Sign up now": "Jetzt registrieren", diff --git a/ghost/i18n/locales/el/comments.json b/ghost/i18n/locales/el/comments.json index 24ea21ec1f..28434caa3b 100644 --- a/ghost/i18n/locales/el/comments.json +++ b/ghost/i18n/locales/el/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Τζέιμι Λάρσον", "Join the discussion": "Συμμετοχή στη συζήτηση", "Just now": "Μόλις τώρα", + "Load more ({{amount}})": "", "Local resident": "Τοπικός κάτοικος", "Member discussion": "Συζήτηση μελών", "Name": "Όνομα", @@ -55,9 +56,7 @@ "Sent": "Απεστάλη", "Show": "Εμφάνιση", "Show {{amount}} more replies": "Εμφάνιση {{amount}} περισσότερων απαντήσεων", - "Show {{amount}} previous comments": "Εμφάνιση {{amount}} προηγούμενων σχολίων", "Show 1 more reply": "Εμφάνιση 1 ακόμα απάντησης", - "Show 1 previous comment": "Εμφάνιση 1 προηγούμενου σχολίου", "Show comment": "Εμφάνιση σχολίου", "Sign in": "Σύνδεση", "Sign up now": "Εγγραφείτε τώρα", diff --git a/ghost/i18n/locales/en/comments.json b/ghost/i18n/locales/en/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/en/comments.json +++ b/ghost/i18n/locales/en/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/eo/comments.json b/ghost/i18n/locales/eo/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/eo/comments.json +++ b/ghost/i18n/locales/eo/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/es/comments.json b/ghost/i18n/locales/es/comments.json index 161ba7c588..2c0444d6bf 100644 --- a/ghost/i18n/locales/es/comments.json +++ b/ghost/i18n/locales/es/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Únete a la discusión", "Just now": "Justo ahora", + "Load more ({{amount}})": "", "Local resident": "Residente local", "Member discussion": "Discusión de miembros", "Name": "Nombre", @@ -55,9 +56,7 @@ "Sent": "Enviar", "Show": "Mostrar", "Show {{amount}} more replies": "Mostrar {{amount}} respuestas más", - "Show {{amount}} previous comments": "Mostrar {{amount}} comentarios previos", "Show 1 more reply": "Mostrar 1 respuesta más", - "Show 1 previous comment": "Mostrar 1 comentario previo", "Show comment": "Mostrar comentario", "Sign in": "Inicia sesión", "Sign up now": "Regístrate ahora", diff --git a/ghost/i18n/locales/et/comments.json b/ghost/i18n/locales/et/comments.json index 9bfd030f86..0efd1ed4da 100644 --- a/ghost/i18n/locales/et/comments.json +++ b/ghost/i18n/locales/et/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Liitu aruteluga", "Just now": "Just praegu", + "Load more ({{amount}})": "", "Local resident": "Kohalik elanik", "Member discussion": "Liikmete arutelu", "Name": "Nimi", @@ -55,9 +56,7 @@ "Sent": "Saadetud", "Show": "Näita", "Show {{amount}} more replies": "Näita {{amount}} vastust veel", - "Show {{amount}} previous comments": "Näita {{amount}} eelmist kommentaari", "Show 1 more reply": "Näita 1 vastus veel", - "Show 1 previous comment": "Näita eelmist kommentaari", "Show comment": "Näita kommentaari", "Sign in": "Logi sisse", "Sign up now": "Registreeru nüüd", diff --git a/ghost/i18n/locales/fa/comments.json b/ghost/i18n/locales/fa/comments.json index 99d8a06e07..f8b5f7ac64 100644 --- a/ghost/i18n/locales/fa/comments.json +++ b/ghost/i18n/locales/fa/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "جیمی لارسن", "Join the discussion": "به گفتمان بپیوندید", "Just now": "پیوستن", + "Load more ({{amount}})": "", "Local resident": "ساکن محلی", "Member discussion": "گفتمان کاربران", "Name": "نام", @@ -55,9 +56,7 @@ "Sent": "ارسال شد", "Show": "نمایش", "Show {{amount}} more replies": "نمایش {{amount}} پاسخ بیشتر", - "Show {{amount}} previous comments": "نمایش {{amount}} دیدگاه قبل\u200cتر", "Show 1 more reply": "نمایش یک دیدگاه بیشتر", - "Show 1 previous comment": "نمایش یک دیدگاه قبل\u200cتر", "Show comment": "نمایش دیدگاه", "Sign in": "ورود به حساب", "Sign up now": "ایجاد حساب", diff --git a/ghost/i18n/locales/fi/comments.json b/ghost/i18n/locales/fi/comments.json index 891aae9b9f..f18e850760 100644 --- a/ghost/i18n/locales/fi/comments.json +++ b/ghost/i18n/locales/fi/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Liity keskusteluun", "Just now": "Juuri nyt", + "Load more ({{amount}})": "", "Local resident": "Paikallinen", "Member discussion": "Jäsenten keskustelu", "Name": "Nimi", @@ -55,9 +56,7 @@ "Sent": "Lähetetty", "Show": "Näytä", "Show {{amount}} more replies": "Näytä {{amount}} vastausta lisää ", - "Show {{amount}} previous comments": "Näytä {{amount}} edellistä kommenttia", "Show 1 more reply": "Näytä 1 vastaus lisää", - "Show 1 previous comment": "Näytä edellinen kommentti", "Show comment": "Näytä kommentti", "Sign in": "Kirjaudu sisään", "Sign up now": "Rekisteröidy nyt", diff --git a/ghost/i18n/locales/fr/comments.json b/ghost/i18n/locales/fr/comments.json index 29838d582b..74da5cd940 100644 --- a/ghost/i18n/locales/fr/comments.json +++ b/ghost/i18n/locales/fr/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jean Martin", "Join the discussion": "Rejoindre la discussion", "Just now": "À l'instant", + "Load more ({{amount}})": "", "Local resident": "Résident local", "Member discussion": "Discussion entre abonnés", "Name": "Nom", @@ -55,9 +56,7 @@ "Sent": "Envoyé", "Show": "Afficher", "Show {{amount}} more replies": "Afficher {{amount}} réponses supplémentaires", - "Show {{amount}} previous comments": "Afficher {{amount}} commentaires précédents", "Show 1 more reply": "Afficher 1 réponse supplémentaire", - "Show 1 previous comment": "Afficher 1 commentaire précédent", "Show comment": "Afficher le commentaire", "Sign in": "Se connecter", "Sign up now": "S'inscrire maintenant", diff --git a/ghost/i18n/locales/gd/comments.json b/ghost/i18n/locales/gd/comments.json index d9e7e244c3..e32e19e9e3 100644 --- a/ghost/i18n/locales/gd/comments.json +++ b/ghost/i18n/locales/gd/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Seamaidh Larson", "Join the discussion": "Gabh pàirt san deasbad", "Just now": "An-dràsta", + "Load more ({{amount}})": "", "Local resident": "Neach-còmhnaidh ionadail", "Member discussion": "Deasbad", "Name": "Ainm", @@ -55,9 +56,7 @@ "Sent": "Air a chur", "Show": "Seall", "Show {{amount}} more replies": "An àireamh de bheachdan a bharrachd a chìthear: {{amount}}", - "Show {{amount}} previous comments": "An àireamh de bheachdan roimhe a chìthear: {{amount}}", "Show 1 more reply": "Seall beachd a bharrachd", - "Show 1 previous comment": "Seall am beachd roimhe", "Show comment": "Seall am beachd", "Sign in": "Clàraich a-steach", "Sign up now": "Clàraich a-nis", diff --git a/ghost/i18n/locales/he/comments.json b/ghost/i18n/locales/he/comments.json index b269be2b9c..a5cf8637cb 100644 --- a/ghost/i18n/locales/he/comments.json +++ b/ghost/i18n/locales/he/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "ג׳יימי לרסון", "Join the discussion": "הצטרפו לדיון", "Just now": "ממש עכשיו", + "Load more ({{amount}})": "", "Local resident": "תושב מקומי", "Member discussion": "דיון חברים רשומים", "Name": "שם", @@ -55,9 +56,7 @@ "Sent": "שלחנו", "Show": "להציג", "Show {{amount}} more replies": "להציג עוד {{amount}} תגובות", - "Show {{amount}} previous comments": "להציג {{amount}} תגובות קודמות", "Show 1 more reply": "להציג תגובה נוספת", - "Show 1 previous comment": "להציג תגובה קודמת", "Show comment": "להציג תגובה", "Sign in": "היכנסו", "Sign up now": "הירשמו עכשיו", diff --git a/ghost/i18n/locales/hi/comments.json b/ghost/i18n/locales/hi/comments.json index d4f15c1eaa..35147a3e8e 100644 --- a/ghost/i18n/locales/hi/comments.json +++ b/ghost/i18n/locales/hi/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "राहुल शर्मा", "Join the discussion": "चर्चा में शामिल हों", "Just now": "अभी", + "Load more ({{amount}})": "", "Local resident": "स्थानीय निवासी", "Member discussion": "सदस्य चर्चा", "Name": "नाम", @@ -55,9 +56,7 @@ "Sent": "भेजा गया", "Show": "दिखाएं", "Show {{amount}} more replies": "{{amount}} और जवाब दिखाएं", - "Show {{amount}} previous comments": "{{amount}} पिछली टिप्पणियाँ दिखाएं", "Show 1 more reply": "1 और जवाब दिखाएं", - "Show 1 previous comment": "1 पिछली टिप्पणी दिखाएं", "Show comment": "टिप्पणी दिखाएं", "Sign in": "साइन इन करें", "Sign up now": "अभी साइन अप करें", diff --git a/ghost/i18n/locales/hr/comments.json b/ghost/i18n/locales/hr/comments.json index c41ed40f3e..336eae985b 100644 --- a/ghost/i18n/locales/hr/comments.json +++ b/ghost/i18n/locales/hr/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Pridruži se raspravi", "Just now": "Upravo sada", + "Load more ({{amount}})": "", "Local resident": "Lokalni stanovnik", "Member discussion": "Rasprava članova", "Name": "Ime", @@ -55,9 +56,7 @@ "Sent": "Poslano", "Show": "Prikaži", "Show {{amount}} more replies": "Prikaži još {{amount}} odgovora", - "Show {{amount}} previous comments": "Prikaži {{amount}} prethodnih komentara", "Show 1 more reply": "Prikaži još jedan odgovor", - "Show 1 previous comment": "Prikaži prethodan komentar", "Show comment": "Prikaži komentar", "Sign in": "Prijava", "Sign up now": "Registriraj se sada", diff --git a/ghost/i18n/locales/hu/comments.json b/ghost/i18n/locales/hu/comments.json index 7cfd08a48b..20901cfea3 100644 --- a/ghost/i18n/locales/hu/comments.json +++ b/ghost/i18n/locales/hu/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Kiss Sára", "Join the discussion": "Csatlakozzon a beszélgetéshez", "Just now": "Épp most", + "Load more ({{amount}})": "", "Local resident": "Helyi lakos", "Member discussion": "Hozzászólások", "Name": "Név", @@ -55,9 +56,7 @@ "Sent": "Elküldve", "Show": "Mutat", "Show {{amount}} more replies": "Mutass még {{amount}} választ", - "Show {{amount}} previous comments": "Mutass {{amount}} előző hozzászólást", "Show 1 more reply": "Mutass még egy választ", - "Show 1 previous comment": "Mutass még egy hozzászólást", "Show comment": "Hozzászólás mutatása", "Sign in": "Bejelentkezés", "Sign up now": "Regisztráljon most", diff --git a/ghost/i18n/locales/id/comments.json b/ghost/i18n/locales/id/comments.json index b616e86aea..464cd59e8e 100644 --- a/ghost/i18n/locales/id/comments.json +++ b/ghost/i18n/locales/id/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Sutan T. Alisjahbana", "Join the discussion": "Bergabung dalam diskusi", "Just now": "Baru saja", + "Load more ({{amount}})": "", "Local resident": "Penduduk lokal", "Member discussion": "Diskusi anggota", "Name": "Nama", @@ -55,9 +56,7 @@ "Sent": "Terkirim", "Show": "Tampilkan", "Show {{amount}} more replies": "Tampilkan {{amount}} balasan lainnya", - "Show {{amount}} previous comments": "Tampilkan {{amount}} komentar sebelumnya", "Show 1 more reply": "Tampilkan 1 balasan lainnya", - "Show 1 previous comment": "Tampilkan 1 komentar sebelumnya", "Show comment": "Tampilkan komentar", "Sign in": "Masuk", "Sign up now": "Daftar sekarang", diff --git a/ghost/i18n/locales/is/comments.json b/ghost/i18n/locales/is/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/is/comments.json +++ b/ghost/i18n/locales/is/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/it/comments.json b/ghost/i18n/locales/it/comments.json index d7a6a72773..fffd561357 100644 --- a/ghost/i18n/locales/it/comments.json +++ b/ghost/i18n/locales/it/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Andrea Rossi", "Join the discussion": "Partecipa alla discussione", "Just now": "Adesso", + "Load more ({{amount}})": "", "Local resident": "Paesano", "Member discussion": "Commenti", "Name": "Nome", @@ -55,9 +56,7 @@ "Sent": "Inviato", "Show": "Mostra", "Show {{amount}} more replies": "Mostra altre {{amount}} risposte", - "Show {{amount}} previous comments": "Mostra altri {{amount}} commenti", "Show 1 more reply": "Mostra un'altra risposta", - "Show 1 previous comment": "Mostra un commento precedente", "Show comment": "Mostra commento", "Sign in": "Accedi", "Sign up now": "Accedi ora", diff --git a/ghost/i18n/locales/ja/comments.json b/ghost/i18n/locales/ja/comments.json index 5857264271..f9287deda4 100644 --- a/ghost/i18n/locales/ja/comments.json +++ b/ghost/i18n/locales/ja/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "ジェイミー・ラーソン", "Join the discussion": "議論に参加する", "Just now": "今すぐ参加する", + "Load more ({{amount}})": "", "Local resident": "地元住民", "Member discussion": "メンバーによる議論", "Name": "名前", @@ -55,9 +56,7 @@ "Sent": "送信完了", "Show": "表示する", "Show {{amount}} more replies": "{{amount}}個の返信を表示する", - "Show {{amount}} previous comments": "前のコメントを{{amount}}個表示する", "Show 1 more reply": "返信をもう1つ表示する", - "Show 1 previous comment": "1つ前のコメントを表示する", "Show comment": "コメントを表示する", "Sign in": "ログイン", "Sign up now": "今すぐ新規登録する", diff --git a/ghost/i18n/locales/ko/comments.json b/ghost/i18n/locales/ko/comments.json index fdc89ce627..bacc7ec945 100644 --- a/ghost/i18n/locales/ko/comments.json +++ b/ghost/i18n/locales/ko/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "제이미 라슨", "Join the discussion": "댓글에 참여해 주세요", "Just now": "방금 전", + "Load more ({{amount}})": "", "Local resident": "지역 주민", "Member discussion": "회원들의 댓글", "Name": "이름", @@ -55,9 +56,7 @@ "Sent": "전송됨", "Show": "보기", "Show {{amount}} more replies": "{{amount}}개의 댓글 더 보기", - "Show {{amount}} previous comments": "{{amount}}개의 이전 댓글 보기", "Show 1 more reply": "1개의 댓글 더 보기", - "Show 1 previous comment": "1개의 이전 댓글 보기", "Show comment": "댓글 보기", "Sign in": "로그인", "Sign up now": "회원가입", diff --git a/ghost/i18n/locales/kz/comments.json b/ghost/i18n/locales/kz/comments.json index f37831ad19..cc3979d15c 100644 --- a/ghost/i18n/locales/kz/comments.json +++ b/ghost/i18n/locales/kz/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Пәленше Түгеншиев", "Join the discussion": "Талқыға қосылу", "Just now": "Дәл қазір", + "Load more ({{amount}})": "", "Local resident": "Жергілікті тұрғын", "Member discussion": "Мүшелер талқысы", "Name": "Есімі", @@ -55,9 +56,7 @@ "Sent": "Жіберілді", "Show": "Көрсету", "Show {{amount}} more replies": "Тағы {{amount}} жауапты көрсету", - "Show {{amount}} previous comments": "Алдыңғы {{amount}} пікірді көрсету", "Show 1 more reply": "Тағы 1 жауап көрсету", - "Show 1 previous comment": "Алдыңғы 1 пікірді көрсету", "Show comment": "Пікірді көрсету", "Sign in": "Кіру", "Sign up now": "Қазір тіркелу", diff --git a/ghost/i18n/locales/lt/comments.json b/ghost/i18n/locales/lt/comments.json index a6fdaac8d2..84a4e2a51b 100644 --- a/ghost/i18n/locales/lt/comments.json +++ b/ghost/i18n/locales/lt/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Vardenis Pavardenis", "Join the discussion": "Prisijunkite prie diskusijos", "Just now": "Ką tik", + "Load more ({{amount}})": "", "Local resident": "Vietinis gyventojas", "Member discussion": "Komentarai", "Name": "Vardas", @@ -55,9 +56,7 @@ "Sent": "Išsiųsta", "Show": "Rodyti", "Show {{amount}} more replies": "Rodyti daugiau atsakymų ({{amount}})", - "Show {{amount}} previous comments": "Rodyti ankstesnius komentarus ({{amount}})", "Show 1 more reply": "Rodyti dar 1 atsakymą", - "Show 1 previous comment": "Rodyti ankstesnį komentarą", "Show comment": "Rodyti komentarą", "Sign in": "Prisijungti", "Sign up now": "Registruotis", diff --git a/ghost/i18n/locales/mk/comments.json b/ghost/i18n/locales/mk/comments.json index 5739523a0d..1b8a1b01de 100644 --- a/ghost/i18n/locales/mk/comments.json +++ b/ghost/i18n/locales/mk/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Петар Петровски", "Join the discussion": "Приклучете се во разговорот", "Just now": "Штотуку", + "Load more ({{amount}})": "", "Local resident": "Локал жител", "Member discussion": "Разговор на членовите", "Name": "Име", @@ -55,9 +56,7 @@ "Sent": "Испратено", "Show": "Покажи", "Show {{amount}} more replies": "Покажи уште {{amount}} одговори", - "Show {{amount}} previous comments": "Покажи {{amount}} претходни коментари", "Show 1 more reply": "Покажи уште 1 одговор", - "Show 1 previous comment": "Покажи 1 претходен коментар", "Show comment": "Покажи коментар", "Sign in": "Најавете се", "Sign up now": "Регистрирајте се", diff --git a/ghost/i18n/locales/mn/comments.json b/ghost/i18n/locales/mn/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/mn/comments.json +++ b/ghost/i18n/locales/mn/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/ms/comments.json b/ghost/i18n/locales/ms/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/ms/comments.json +++ b/ghost/i18n/locales/ms/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/ne/comments.json b/ghost/i18n/locales/ne/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/ne/comments.json +++ b/ghost/i18n/locales/ne/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/nl/comments.json b/ghost/i18n/locales/nl/comments.json index 05f0e1ae17..f679eb923b 100644 --- a/ghost/i18n/locales/nl/comments.json +++ b/ghost/i18n/locales/nl/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jan Jansen", "Join the discussion": "Doe mee aan het gesprek", "Just now": "Zojuist", + "Load more ({{amount}})": "", "Local resident": "Lokale bewoner", "Member discussion": "Gesprek", "Name": "Naam", @@ -55,9 +56,7 @@ "Sent": "Verzonden", "Show": "Tonen", "Show {{amount}} more replies": "Toon {{amount}} extra antwoorden", - "Show {{amount}} previous comments": "Toon {{amount}} vorige reacties", "Show 1 more reply": "Toon nog 1 antwoord", - "Show 1 previous comment": "Toon 1 vorige reactie", "Show comment": "Toon reactie", "Sign in": "Inloggen", "Sign up now": "Registreren", diff --git a/ghost/i18n/locales/nn/comments.json b/ghost/i18n/locales/nn/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/nn/comments.json +++ b/ghost/i18n/locales/nn/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/no/comments.json b/ghost/i18n/locales/no/comments.json index 372e4fadea..ff8235d4c7 100644 --- a/ghost/i18n/locales/no/comments.json +++ b/ghost/i18n/locales/no/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Delta i diskusjonen", "Just now": "Akkurat nå", + "Load more ({{amount}})": "", "Local resident": "Lokal innbygger", "Member discussion": "Medlemsdiskusjon", "Name": "Navn", @@ -55,9 +56,7 @@ "Sent": "Sendt", "Show": "Vis", "Show {{amount}} more replies": "Vis {{amount}} flere svar", - "Show {{amount}} previous comments": "Vis {{amount}} tidligere kommentarer", "Show 1 more reply": "Vis ett svar til", - "Show 1 previous comment": "Vis én tidligere kommentar", "Show comment": "Vis kommentar", "Sign in": "Logg inn", "Sign up now": "Registrer deg nå", diff --git a/ghost/i18n/locales/pl/comments.json b/ghost/i18n/locales/pl/comments.json index 942f1a0bcc..674e828fed 100644 --- a/ghost/i18n/locales/pl/comments.json +++ b/ghost/i18n/locales/pl/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Dołącz do dyskusji", "Just now": "Przed chwilą", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "Członek dyskusji", "Name": "Imię", @@ -55,9 +56,7 @@ "Sent": "Wysłano", "Show": "Pokza", "Show {{amount}} more replies": "Pokaż {{amount}} kolejnych odpowiedzi", - "Show {{amount}} previous comments": "Pokaż {{amount}} poprzednich komentarzy", "Show 1 more reply": "Pokaż następną odpowiedź", - "Show 1 previous comment": "Pokaż poprzedni komentarz", "Show comment": "Pokaż komentarz", "Sign in": "Zaloguj się", "Sign up now": "Zarejestruj się", diff --git a/ghost/i18n/locales/pt-BR/comments.json b/ghost/i18n/locales/pt-BR/comments.json index 2892636092..b0c51c3875 100644 --- a/ghost/i18n/locales/pt-BR/comments.json +++ b/ghost/i18n/locales/pt-BR/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Participe da discussão", "Just now": "Agora mesmo", + "Load more ({{amount}})": "", "Local resident": "Residente local", "Member discussion": "Discussão entre membros", "Name": "Nome", @@ -55,9 +56,7 @@ "Sent": "Enviado", "Show": "Mostrar", "Show {{amount}} more replies": "Mostrar mais {{amount}} respostas", - "Show {{amount}} previous comments": "Mostrar {{amount}} comentários anteriores", "Show 1 more reply": "Mostrar 1 resposta adicional", - "Show 1 previous comment": "Mostrar 1 comentário anterior", "Show comment": "Mostrar comentário", "Sign in": "Entrar", "Sign up now": "Inscreva-se agora", diff --git a/ghost/i18n/locales/pt/comments.json b/ghost/i18n/locales/pt/comments.json index 7ee3545c0c..e5f1a10e29 100644 --- a/ghost/i18n/locales/pt/comments.json +++ b/ghost/i18n/locales/pt/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jane Doe", "Join the discussion": "Junte-se à discussão", "Just now": "Agora", + "Load more ({{amount}})": "", "Local resident": "Residente local", "Member discussion": "Discussão para membros", "Name": "Nome", @@ -55,9 +56,7 @@ "Sent": "Enviado", "Show": "Mostrar", "Show {{amount}} more replies": "Mostrar mais {{amount}} respostas", - "Show {{amount}} previous comments": "Mostrar os {{amount}} comentários anteriores", "Show 1 more reply": "Mostrar mais uma resposta", - "Show 1 previous comment": "Mostrar mais um comentário", "Show comment": "Mostrar comentário", "Sign in": "Registar", "Sign up now": "Registar agora", diff --git a/ghost/i18n/locales/ro/comments.json b/ghost/i18n/locales/ro/comments.json index 43232898e5..19633088ea 100644 --- a/ghost/i18n/locales/ro/comments.json +++ b/ghost/i18n/locales/ro/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Alătură-te discuției", "Just now": "Chiar acum", + "Load more ({{amount}})": "", "Local resident": "Rezident local", "Member discussion": "Discuție membrii", "Name": "Nume", @@ -55,9 +56,7 @@ "Sent": "Trimis", "Show": "Arată", "Show {{amount}} more replies": "Arată încă {{amount}} răspunsuri", - "Show {{amount}} previous comments": "Arată {{amount}} comentarii anterioare", "Show 1 more reply": "Arată încă un răspuns", - "Show 1 previous comment": "Arată un comentariu anterior", "Show comment": "Arată comentariul", "Sign in": "Autentificare", "Sign up now": "Înregistrează-te acum", diff --git a/ghost/i18n/locales/ru/comments.json b/ghost/i18n/locales/ru/comments.json index 0ae3ac2d85..59cb0874fd 100644 --- a/ghost/i18n/locales/ru/comments.json +++ b/ghost/i18n/locales/ru/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Павел Бид", "Join the discussion": "Присоединиться к обсуждению", "Just now": "Сейчас", + "Load more ({{amount}})": "", "Local resident": "Местный житель", "Member discussion": "Обсуждение участников", "Name": "Имя", @@ -55,9 +56,7 @@ "Sent": "Отправлено", "Show": "Показать", "Show {{amount}} more replies": "Показать ещё {{amount}} ответа(ов)", - "Show {{amount}} previous comments": "Показать ещё {{amount}} комментария(ев)", "Show 1 more reply": "Показать ответ", - "Show 1 previous comment": "Показать предыдущий комментарий", "Show comment": "Показать комментарий", "Sign in": "Войти", "Sign up now": "Зарегистрироваться", diff --git a/ghost/i18n/locales/si/comments.json b/ghost/i18n/locales/si/comments.json index 15c8cd3e6d..737a5f45d2 100644 --- a/ghost/i18n/locales/si/comments.json +++ b/ghost/i18n/locales/si/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "ජේමි ලාර්සන්", "Join the discussion": "සාකච්ඡාවට එක්වන්න", "Just now": "මේ දැ\u200bන්", + "Load more ({{amount}})": "", "Local resident": "දේශීය පදිංචි", "Member discussion": "සාමාජික සාකච්ඡාව", "Name": "න\u200bම", @@ -55,9 +56,7 @@ "Sent": "යැව්වා", "Show": "පෙන්වන්\u200bන", "Show {{amount}} more replies": "තවත් පිළිතුරු {{amount}} පෙන්වන්න", - "Show {{amount}} previous comments": "පෙර අදහස් {{amount}} පෙන්වන්න", "Show 1 more reply": "තවත් පිළිතුරු 1ක් පෙන්වන්න", - "Show 1 previous comment": "පෙර අදහස් 1ක් පෙන්වන්න", "Show comment": "අදහස පෙන්වන්න", "Sign in": "Sign in වෙන්\u200bන", "Sign up now": "දැන්ම Sign up වෙන්\u200bන", diff --git a/ghost/i18n/locales/sk/comments.json b/ghost/i18n/locales/sk/comments.json index 82846401ac..644f7bb442 100644 --- a/ghost/i18n/locales/sk/comments.json +++ b/ghost/i18n/locales/sk/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Zapojiť sa do diskusie", "Just now": "Teraz", + "Load more ({{amount}})": "", "Local resident": "Miestny obyvateľ", "Member discussion": "", "Name": "Meno", @@ -55,9 +56,7 @@ "Sent": "Odoslané", "Show": "Zobraziť", "Show {{amount}} more replies": "Zobraziť {{amount}} ďalších odpoveďí", - "Show {{amount}} previous comments": "Zobraziť {{amount}} predchádzajúcich komentárov", "Show 1 more reply": "Zobraziť 1 ďalšiu odpoveď", - "Show 1 previous comment": "Zobraziť 1 predchádzajúci komentár", "Show comment": "Zobraziť komentár", "Sign in": "Prihlásiť", "Sign up now": "Registrovať sa", diff --git a/ghost/i18n/locales/sl/comments.json b/ghost/i18n/locales/sl/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/sl/comments.json +++ b/ghost/i18n/locales/sl/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/sq/comments.json b/ghost/i18n/locales/sq/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/sq/comments.json +++ b/ghost/i18n/locales/sq/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/sr-Cyrl/comments.json b/ghost/i18n/locales/sr-Cyrl/comments.json index 26919dd71b..f1f910bd50 100644 --- a/ghost/i18n/locales/sr-Cyrl/comments.json +++ b/ghost/i18n/locales/sr-Cyrl/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Џејми Ларсон", "Join the discussion": "Придружите се дискусији", "Just now": "Управо сада", + "Load more ({{amount}})": "", "Local resident": "Мештанин", "Member discussion": "Дискусија чланова", "Name": "Име", @@ -55,9 +56,7 @@ "Sent": "Послато", "Show": "Прикажи", "Show {{amount}} more replies": "Прикажи још {{amount}} одговора", - "Show {{amount}} previous comments": "Прикажи претходна {{amount}} коментара", "Show 1 more reply": "Прикажи још 1 одговор", - "Show 1 previous comment": "Прикажи 1 претходни коментар", "Show comment": "Прикажи коментар", "Sign in": "Пријавите се", "Sign up now": "Пријавите се сада", diff --git a/ghost/i18n/locales/sr/comments.json b/ghost/i18n/locales/sr/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/sr/comments.json +++ b/ghost/i18n/locales/sr/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/sv/comments.json b/ghost/i18n/locales/sv/comments.json index 40675a14f1..d55c9662d7 100644 --- a/ghost/i18n/locales/sv/comments.json +++ b/ghost/i18n/locales/sv/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Anders Andersson", "Join the discussion": "Var med i diskussionen", "Just now": "Nu precis", + "Load more ({{amount}})": "", "Local resident": "Lokalboende", "Member discussion": "Medlemsdiskussion", "Name": "Namn", @@ -55,9 +56,7 @@ "Sent": "Skickad", "Show": "Visa", "Show {{amount}} more replies": "Visa {{amount}} fler svar", - "Show {{amount}} previous comments": "Visa {{amount}} tidigare kommentarer", "Show 1 more reply": "Visa 1 kommentar till", - "Show 1 previous comment": "Visa 1 tidigare kommentar", "Show comment": "Visa kommentar", "Sign in": "Logga in", "Sign up now": "Registrera dig nu", diff --git a/ghost/i18n/locales/sw/comments.json b/ghost/i18n/locales/sw/comments.json index 173f938652..af60586d09 100644 --- a/ghost/i18n/locales/sw/comments.json +++ b/ghost/i18n/locales/sw/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Jiunge na mjadala", "Just now": "Hivi sasa", + "Load more ({{amount}})": "", "Local resident": "Mkazi wa eneo", "Member discussion": "Mjadala wa wanachama", "Name": "Jina", @@ -55,9 +56,7 @@ "Sent": "Imetumwa", "Show": "Onyesha", "Show {{amount}} more replies": "Onyesha majibu {{amount}} zaidi", - "Show {{amount}} previous comments": "Onyesha maoni {{amount}} ya awali", "Show 1 more reply": "Onyesha jibu 1 zaidi", - "Show 1 previous comment": "Onyesha maoni 1 ya awali", "Show comment": "Onyesha maoni", "Sign in": "Ingia", "Sign up now": "Jisajili sasa", diff --git a/ghost/i18n/locales/ta/comments.json b/ghost/i18n/locales/ta/comments.json index 90a6774726..658d856903 100644 --- a/ghost/i18n/locales/ta/comments.json +++ b/ghost/i18n/locales/ta/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "ஜேமி லார்சன்", "Join the discussion": "கலந்துரையாடலில் சேரவும்", "Just now": "சற்றுமுன்னர்தான்", + "Load more ({{amount}})": "", "Local resident": "உள்ளூர்வாசி", "Member discussion": "உறுப்பினர் கருத்து", "Name": "பெயர்", @@ -55,9 +56,7 @@ "Sent": "அனுப்பப்பட்டது", "Show": "காட்டு", "Show {{amount}} more replies": "முந்தைய {{amount}} மேலும் பதில்கள்க் காட்டு", - "Show {{amount}} previous comments": "முந்தைய {{amount}} கருத்துகளைக் காட்டு", "Show 1 more reply": "மேலும் 1 பதிலைக் காட்டு", - "Show 1 previous comment": "முந்தைய 1 கருத்தைக் காட்டு", "Show comment": "கருத்தைக் காட்டு", "Sign in": "உள்நுழைக", "Sign up now": "இப்பொழுதே பதிவு செய்யுங்கள்", diff --git a/ghost/i18n/locales/th/comments.json b/ghost/i18n/locales/th/comments.json index 8524ae0459..3067ec2bba 100644 --- a/ghost/i18n/locales/th/comments.json +++ b/ghost/i18n/locales/th/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "กนกพัฒน์ สัณห์ฤทัย", "Join the discussion": "เข้าร่วมการสนทนา", "Just now": "ตอนนี้", + "Load more ({{amount}})": "", "Local resident": "ผู้อยู่อาศัยในท้องถิ่น", "Member discussion": "การสนทนาของสมาชิก", "Name": "ชื่อ", @@ -55,9 +56,7 @@ "Sent": "ส่งแล้ว", "Show": "แสดง", "Show {{amount}} more replies": "แสดง {{amount}} การตอบกลับเพิ่มเติม", - "Show {{amount}} previous comments": "แสดง {{amount}} ความคิดเห็นก่อนหน้า", "Show 1 more reply": "แสดงอีก 1 การตอบกลับ", - "Show 1 previous comment": "แสดง 1 ความคิดเห็น", "Show comment": "ดูความคิดเห็น", "Sign in": "ลงชื่อเข้าใช้", "Sign up now": "สมัครใช้งานตอนนี้เลย", diff --git a/ghost/i18n/locales/tr/comments.json b/ghost/i18n/locales/tr/comments.json index 70f8a55aeb..d970e0fb11 100644 --- a/ghost/i18n/locales/tr/comments.json +++ b/ghost/i18n/locales/tr/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Ad Soyad", "Join the discussion": "Tartışmaya katıl", "Just now": "Şu anda", + "Load more ({{amount}})": "", "Local resident": "Yerel sakini", "Member discussion": "Üye tartışması", "Name": "Ad", @@ -55,9 +56,7 @@ "Sent": "Gönderildi", "Show": "Göster", "Show {{amount}} more replies": "{{amount}} daha fazla yanıt göster", - "Show {{amount}} previous comments": "{{amount}} önceki yorumu göster", "Show 1 more reply": "1 cevap daha göster", - "Show 1 previous comment": "1 önceki yorumu göster", "Show comment": "Yorumu göster", "Sign in": "Giriş yap", "Sign up now": "Şimdi kayıt ol", diff --git a/ghost/i18n/locales/uk/comments.json b/ghost/i18n/locales/uk/comments.json index a311c51d74..969e2f5ac4 100644 --- a/ghost/i18n/locales/uk/comments.json +++ b/ghost/i18n/locales/uk/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Ваше імʼя", "Join the discussion": "Долучитися до обговорення", "Just now": "Прямо зараз", + "Load more ({{amount}})": "", "Local resident": "Місцевий експерт", "Member discussion": "Обговорення учасників", "Name": "Імʼя", @@ -55,9 +56,7 @@ "Sent": "Відправлено", "Show": "Показати", "Show {{amount}} more replies": "Показати ще {{amount}} відповідей", - "Show {{amount}} previous comments": "Показати {{amount}} попередніх коментарів", "Show 1 more reply": "Показати ще одну відповідь", - "Show 1 previous comment": "Показати один попередній коментар", "Show comment": "Показати коментар", "Sign in": "Увійти", "Sign up now": "Зареєструватись зараз", diff --git a/ghost/i18n/locales/ur/comments.json b/ghost/i18n/locales/ur/comments.json index 8d9535c6de..ec50838a13 100644 --- a/ghost/i18n/locales/ur/comments.json +++ b/ghost/i18n/locales/ur/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "جیمی لارسن", "Join the discussion": "تبادلے میں شامل ہوں", "Just now": "ابھی", + "Load more ({{amount}})": "", "Local resident": "مقامی رہائشی", "Member discussion": "رکن کا تبادلہ", "Name": "نام", @@ -55,9 +56,7 @@ "Sent": "بھیجا گیا", "Show": "دکھائیں", "Show {{amount}} more replies": "{{amount}} مزید جوابات دکھائیں", - "Show {{amount}} previous comments": "{{amount}} پچھلے تبادلات دکھائیں", "Show 1 more reply": "1 مزید جواب دکھائیں", - "Show 1 previous comment": "1 پچھلا تبادلہ دکھائیں", "Show comment": "تبادلہ دکھائیں", "Sign in": "سائن ان کریں", "Sign up now": "ابھی رجسٹر ہوں", diff --git a/ghost/i18n/locales/uz/comments.json b/ghost/i18n/locales/uz/comments.json index 00198101c8..8db42c11fd 100644 --- a/ghost/i18n/locales/uz/comments.json +++ b/ghost/i18n/locales/uz/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "", "Join the discussion": "", "Just now": "", + "Load more ({{amount}})": "", "Local resident": "", "Member discussion": "", "Name": "", @@ -55,9 +56,7 @@ "Sent": "", "Show": "", "Show {{amount}} more replies": "", - "Show {{amount}} previous comments": "", "Show 1 more reply": "", - "Show 1 previous comment": "", "Show comment": "", "Sign in": "", "Sign up now": "", diff --git a/ghost/i18n/locales/vi/comments.json b/ghost/i18n/locales/vi/comments.json index 230655f482..dc4840e63a 100644 --- a/ghost/i18n/locales/vi/comments.json +++ b/ghost/i18n/locales/vi/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "Tham gia thảo luận", "Just now": "Vừa xong", + "Load more ({{amount}})": "", "Local resident": "Cư dân địa phương", "Member discussion": "Thảo luận của thành viên", "Name": "Tên", @@ -55,9 +56,7 @@ "Sent": "Đã gửi", "Show": "Hiển thị", "Show {{amount}} more replies": "Xem {{amount}} trả lời khác", - "Show {{amount}} previous comments": "Đọc {{amount}} bình luận trước", "Show 1 more reply": "Xem 1 trả lời", - "Show 1 previous comment": "Đọc 1 bình luận trước", "Show comment": "Đọc bình luận", "Sign in": "Đăng nhập", "Sign up now": "Đăng ký ngay", diff --git a/ghost/i18n/locales/zh-Hant/comments.json b/ghost/i18n/locales/zh-Hant/comments.json index cb1053d6c7..48d6ec0fbb 100644 --- a/ghost/i18n/locales/zh-Hant/comments.json +++ b/ghost/i18n/locales/zh-Hant/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "加入討論", "Just now": "剛剛", + "Load more ({{amount}})": "", "Local resident": "本地居民", "Member discussion": "會員討論", "Name": "稱呼", @@ -55,9 +56,7 @@ "Sent": "已發送", "Show": "顯示", "Show {{amount}} more replies": "顯示後續 {{amount}} 則留言", - "Show {{amount}} previous comments": "顯示先前 {{amount}} 則留言", "Show 1 more reply": "顯示下一則留言", - "Show 1 previous comment": "顯示前一則留言", "Show comment": "顯示留言", "Sign in": "登錄", "Sign up now": "立即註冊", diff --git a/ghost/i18n/locales/zh/comments.json b/ghost/i18n/locales/zh/comments.json index a32cec75b8..b3d672bce6 100644 --- a/ghost/i18n/locales/zh/comments.json +++ b/ghost/i18n/locales/zh/comments.json @@ -35,6 +35,7 @@ "Jamie Larson": "Jamie Larson", "Join the discussion": "加入讨论", "Just now": "刚刚", + "Load more ({{amount}})": "", "Local resident": "本地居民", "Member discussion": "会员讨论", "Name": "称呼", @@ -55,9 +56,7 @@ "Sent": "已发送", "Show": "显示", "Show {{amount}} more replies": "显示后续{{amount}}条评论", - "Show {{amount}} previous comments": "显示先前{{amount}}条评论", "Show 1 more reply": "显示下一条评论", - "Show 1 previous comment": "显示前一条评论", "Show comment": "显示评论", "Sign in": "登录", "Sign up now": "立刻注册",