Merge branch 'next' into next-auth

This commit is contained in:
Wyatt Johnson
2018-10-29 17:39:06 -06:00
121 changed files with 904 additions and 972 deletions
+7 -7
View File
@@ -11,12 +11,12 @@ import {
encodeActionCounts,
invertEncodedActionCounts,
} from "talk-server/models/action";
import { updateAssetActionCounts } from "talk-server/models/asset";
import {
retrieveComment,
updateCommentActionCounts,
} from "talk-server/models/comment";
import { Comment } from "talk-server/models/comment";
import { updateStoryActionCounts } from "talk-server/models/story";
import { Tenant } from "talk-server/models/tenant";
import { User } from "talk-server/models/user";
@@ -47,11 +47,11 @@ export async function addCommentActions(
actionCounts
);
// Update the Asset with the updated action counts.
await updateAssetActionCounts(
// Update the Story with the updated action counts.
await updateStoryActionCounts(
mongo,
tenant.id,
comment.asset_id,
comment.story_id,
actionCounts
);
@@ -109,11 +109,11 @@ export async function removeCommentAction(
actionCounts
);
// Update the Asset with the updated action counts.
await updateAssetActionCounts(
// Update the Story with the updated action counts.
await updateStoryActionCounts(
mongo,
tenant.id,
comment.asset_id,
comment.story_id,
actionCounts
);
+19 -19
View File
@@ -2,10 +2,6 @@ import { Db } from "mongodb";
import { Omit } from "talk-common/types";
import { ACTION_ITEM_TYPE, CreateActionInput } from "talk-server/models/action";
import {
retrieveAsset,
updateCommentStatusCount,
} from "talk-server/models/asset";
import {
createComment,
CreateCommentInput,
@@ -14,6 +10,10 @@ import {
pushChildCommentIDOntoParent,
retrieveComment,
} from "talk-server/models/comment";
import {
retrieveStory,
updateCommentStatusCount,
} from "talk-server/models/story";
import { Tenant } from "talk-server/models/tenant";
import { User } from "talk-server/models/user";
import { addCommentActions } from "talk-server/services/comments/actions";
@@ -32,14 +32,14 @@ export async function create(
input: CreateComment,
req?: Request
) {
// Grab the asset that we'll use to check moderation pieces with.
const asset = await retrieveAsset(mongo, tenant.id, input.asset_id);
if (!asset) {
// Grab the story that we'll use to check moderation pieces with.
const story = await retrieveStory(mongo, tenant.id, input.story_id);
if (!story) {
// TODO: (wyattjoh) return better error.
throw new Error("asset referenced does not exist");
throw new Error("story referenced does not exist");
}
// TODO: (wyattjoh) Check that the asset was visible.
// TODO: (wyattjoh) Check that the story was visible.
const grandparentIDs: string[] = [];
if (input.parent_id) {
@@ -62,7 +62,7 @@ export async function create(
// Run the comment through the moderation phases.
const { actions, status, metadata } = await processForModeration({
asset,
story,
tenant,
comment: input,
author,
@@ -104,8 +104,8 @@ export async function create(
);
}
// Increment the status count for the particular status on the Asset.
await updateCommentStatusCount(mongo, tenant.id, asset.id, {
// Increment the status count for the particular status on the Story.
await updateCommentStatusCount(mongo, tenant.id, story.id, {
[status]: 1,
});
@@ -131,16 +131,16 @@ export async function edit(
throw new Error("comment not found");
}
// Grab the asset that we'll use to check moderation pieces with.
const asset = await retrieveAsset(mongo, tenant.id, comment.asset_id);
if (!asset) {
// Grab the story that we'll use to check moderation pieces with.
const story = await retrieveStory(mongo, tenant.id, comment.story_id);
if (!story) {
// TODO: (wyattjoh) return better error.
throw new Error("asset referenced does not exist");
throw new Error("story referenced does not exist");
}
// Run the comment through the moderation phases.
const { status, metadata, actions } = await processForModeration({
asset,
story,
tenant,
comment: input,
author,
@@ -185,9 +185,9 @@ export async function edit(
}
if (comment.status !== editedComment.status) {
// Increment the status count for the particular status on the Asset, and
// Increment the status count for the particular status on the Story, and
// decrement the status on the comment's previous status.
await updateCommentStatusCount(mongo, tenant.id, asset.id, {
await updateCommentStatusCount(mongo, tenant.id, story.id, {
[comment.status]: -1,
[editedComment.status]: 1,
});
@@ -1,8 +1,8 @@
import { Omit, Promiseable } from "talk-common/types";
import { GQLCOMMENT_STATUS } from "talk-server/graph/tenant/schema/__generated__/types";
import { CreateActionInput } from "talk-server/models/action";
import { Asset } from "talk-server/models/asset";
import { Comment } from "talk-server/models/comment";
import { Story } from "talk-server/models/story";
import { Tenant } from "talk-server/models/tenant";
import { User } from "talk-server/models/user";
import { Request } from "talk-server/types/express";
@@ -18,7 +18,7 @@ export interface PhaseResult {
}
export interface ModerationPhaseContext {
asset: Asset;
story: Story;
tenant: Tenant;
comment: Partial<Comment>;
author: User;
@@ -1,15 +0,0 @@
import {
IntermediateModerationPhase,
IntermediatePhaseResult,
} from "talk-server/services/comments/moderation";
// This phase checks to see if the asset being processed is closed or not.
export const assetClosed: IntermediateModerationPhase = ({
asset,
}): IntermediatePhaseResult | void => {
// Check to see if the asset has closed commenting...
if (asset.closedAt && asset.closedAt.valueOf() <= Date.now()) {
// TODO: (wyattjoh) return better error.
throw new Error("asset is currently closed for commenting");
}
};
@@ -35,7 +35,7 @@ const testCharCount = (
};
export const commentLength: IntermediateModerationPhase = ({
asset,
story,
tenant,
comment,
}): IntermediatePhaseResult | void => {
@@ -44,7 +44,7 @@ export const commentLength: IntermediateModerationPhase = ({
// Reject if the comment is too long or too short.
if (
testCharCount(tenant, length) ||
(asset.settings && testCharCount(asset.settings, length))
(story.settings && testCharCount(story.settings, length))
) {
return {
status: GQLCOMMENT_STATUS.REJECTED,
@@ -8,13 +8,13 @@ const testDisabledCommenting = (settings: Partial<ModerationSettings>) =>
settings.disableCommenting;
export const commentingDisabled: IntermediateModerationPhase = ({
asset,
story,
tenant,
}): IntermediatePhaseResult | void => {
// Check to see if the asset has closed commenting.
// Check to see if the story has closed commenting.
if (
testDisabledCommenting(tenant) ||
(asset.settings && testDisabledCommenting(asset.settings))
(story.settings && testDisabledCommenting(story.settings))
) {
// TODO: (wyattjoh) return better error.
throw new Error("commenting has been disabled tenant wide");
@@ -1,6 +1,5 @@
import { IntermediateModerationPhase } from "talk-server/services/comments/moderation";
import { assetClosed } from "./assetClosed";
import { commentingDisabled } from "./commentingDisabled";
import { commentLength } from "./commentLength";
import { karma } from "./karma";
@@ -8,6 +7,7 @@ import { links } from "./links";
import { preModerate } from "./preModerate";
import { spam } from "./spam";
import { staff } from "./staff";
import { storyClosed } from "./storyClosed";
import { toxic } from "./toxic";
import { wordList } from "./wordList";
@@ -16,7 +16,7 @@ import { wordList } from "./wordList";
*/
export const moderationPhases: IntermediateModerationPhase[] = [
commentLength,
assetClosed,
storyClosed,
commentingDisabled,
wordList,
staff,
@@ -25,14 +25,14 @@ const testPremodLinksEnable = (
// This phase checks the comment if it has any links in it if the check is
// enabled.
export const links: IntermediateModerationPhase = ({
asset,
story,
tenant,
comment,
}): IntermediatePhaseResult | void => {
if (
comment.body &&
(testPremodLinksEnable(tenant, comment.body) ||
(asset.settings && testPremodLinksEnable(asset.settings, comment.body)))
(story.settings && testPremodLinksEnable(story.settings, comment.body)))
) {
// Add the flag related to Trust to the comment.
return {
@@ -14,16 +14,16 @@ const testModerationMode = (settings: Partial<ModerationSettings>) =>
// This phase checks to see if the settings have premod enabled, if they do,
// the comment is premod, otherwise, it's just none.
export const preModerate: IntermediateModerationPhase = ({
asset,
story,
tenant,
}): IntermediatePhaseResult | void => {
// If the settings say that we're in premod mode, then the comment is in
// premod status.
// TODO: (wyattjoh) pull from the asset settings.
// TODO: (wyattjoh) pull from the story settings.
if (
testModerationMode(tenant) ||
(asset.settings && testModerationMode(asset.settings))
(story.settings && testModerationMode(story.settings))
) {
return {
status: GQLCOMMENT_STATUS.PREMOD,
@@ -12,7 +12,7 @@ import {
} from "talk-server/services/comments/moderation";
export const spam: IntermediateModerationPhase = async ({
asset,
story,
tenant,
comment,
author,
@@ -96,7 +96,7 @@ export const spam: IntermediateModerationPhase = async ({
referrer, // REQUIRED
user_agent: userAgent, // REQUIRED
comment_content: comment.body,
permalink: asset.url,
permalink: story.url,
comment_author: author.displayName || author.username || "",
comment_type: "comment",
is_test: false,
@@ -1,16 +1,16 @@
import { Asset } from "talk-server/models/asset";
import { Comment } from "talk-server/models/comment";
import { Story } from "talk-server/models/story";
import { Tenant } from "talk-server/models/tenant";
import { User } from "talk-server/models/user";
import { assetClosed } from "talk-server/services/comments/moderation/phases/assetClosed";
import { storyClosed } from "talk-server/services/comments/moderation/phases/storyClosed";
describe("assetClosed", () => {
it("throws an error when the asset is closed", () => {
const asset = { closedAt: new Date() };
describe("storyClosed", () => {
it("throws an error when the story is closed", () => {
const story = { closedAt: new Date() };
expect(() =>
assetClosed({
asset: asset as Asset,
storyClosed({
story: story as Story,
tenant: (null as any) as Tenant,
comment: (null as any) as Comment,
author: (null as any) as User,
@@ -18,12 +18,12 @@ describe("assetClosed", () => {
).toThrow();
});
it("does not throw an error when the asset is not closed", () => {
it("does not throw an error when the story is not closed", () => {
const now = new Date();
expect(
assetClosed({
asset: { closedAt: new Date(now.getTime() + 60000) } as Asset,
storyClosed({
story: { closedAt: new Date(now.getTime() + 60000) } as Story,
tenant: (null as any) as Tenant,
comment: (null as any) as Comment,
author: (null as any) as User,
@@ -31,8 +31,8 @@ describe("assetClosed", () => {
).toBeUndefined();
expect(
assetClosed({
asset: {} as Asset,
storyClosed({
story: {} as Story,
tenant: (null as any) as Tenant,
comment: (null as any) as Comment,
author: (null as any) as User,
@@ -0,0 +1,15 @@
import {
IntermediateModerationPhase,
IntermediatePhaseResult,
} from "talk-server/services/comments/moderation";
// This phase checks to see if the story being processed is closed or not.
export const storyClosed: IntermediateModerationPhase = ({
story,
}): IntermediatePhaseResult | void => {
// Check to see if the story has closed commenting...
if (story.closedAt && story.closedAt.valueOf() <= Date.now()) {
// TODO: (wyattjoh) return better error.
throw new Error("story is currently closed for commenting");
}
};
@@ -19,7 +19,7 @@ export const wordList: IntermediateModerationPhase = ({
return;
}
// Decide the status based on whether or not the current asset/settings
// Decide the status based on whether or not the current story/settings
// has pre-mod enabled or not. If the comment was rejected based on the
// wordList, then reject it, otherwise if the moderation setting is
// premod, set it to `premod`.
@@ -8,7 +8,7 @@ import titleScraper from "metascraper-title";
import { Db } from "mongodb";
import logger from "talk-server/logger";
import { updateAsset } from "talk-server/models/asset";
import { updateStory } from "talk-server/models/story";
import Task from "talk-server/services/queue/Task";
import { modifiedScraper } from "./rules/modified";
import { sectionScraper } from "./rules/section";
@@ -20,8 +20,8 @@ export interface ScrapeProcessorOptions {
}
export interface ScraperData {
assetID: string;
assetURL: string;
storyID: string;
storyURL: string;
tenantID: string;
}
@@ -30,17 +30,17 @@ const createJobProcessor = (
scraper: Scraper
) => async (job: Job<ScraperData>) => {
// Pull out the job data.
const { assetID: id, assetURL: url, tenantID } = job.data;
const { storyID: id, storyURL: url, tenantID } = job.data;
logger.debug(
{
job_id: job.id,
job_name: JOB_NAME,
asset_id: id,
asset_url: url,
story_id: id,
story_url: url,
tenant_id: tenantID,
},
"starting to scrap the asset"
"starting to scrap the story"
);
// Get the metadata from the scraped html.
@@ -50,17 +50,17 @@ const createJobProcessor = (
{
job_id: job.id,
job_name: JOB_NAME,
asset_id: id,
asset_url: url,
story_id: id,
story_url: url,
tenant_id: tenantID,
},
"asset at specified url not found, can not scrape"
"story at specified url not found, can not scrape"
);
return;
}
// Update the Asset with the scraped details.
const asset = await updateAsset(options.mongo, tenantID, id, {
// Update the Story with the scraped details.
const story = await updateStory(options.mongo, tenantID, id, {
title: meta.title || undefined,
description: meta.description || undefined,
image: meta.image ? meta.image : undefined,
@@ -70,16 +70,16 @@ const createJobProcessor = (
section: meta.section || undefined,
scraped: new Date(),
});
if (!asset) {
if (!story) {
logger.error(
{
job_id: job.id,
job_name: JOB_NAME,
asset_id: id,
asset_url: url,
story_id: id,
story_url: url,
tenant_id: tenantID,
},
"asset at specified id not found, can not update with metadata"
"story at specified id not found, can not update with metadata"
);
return;
}
@@ -88,11 +88,11 @@ const createJobProcessor = (
{
job_id: job.id,
job_name: JOB_NAME,
asset_id: asset.id,
asset_url: url,
story_id: story.id,
story_url: url,
tenant_id: tenantID,
},
"scraped the asset"
"scraped the story"
);
};
@@ -1,35 +1,35 @@
import { Db } from "mongodb";
import {
findOrCreateAsset,
FindOrCreateAssetInput,
} from "talk-server/models/asset";
findOrCreateStory,
FindOrCreateStoryInput,
} from "talk-server/models/story";
import { Tenant } from "talk-server/models/tenant";
import Task from "talk-server/services/queue/Task";
import { ScraperData } from "talk-server/services/queue/tasks/scraper";
export type FindOrCreateAsset = FindOrCreateAssetInput;
export type FindOrCreateStory = FindOrCreateStoryInput;
export async function findOrCreate(
db: Db,
tenant: Tenant,
input: FindOrCreateAsset,
input: FindOrCreateStory,
scraper: Task<ScraperData>
) {
// TODO: check to see if the tenant has enabled lazy asset creation.
// TODO: check to see if the tenant has enabled lazy story creation.
const asset = await findOrCreateAsset(db, tenant.id, input);
if (!asset) {
const story = await findOrCreateStory(db, tenant.id, input);
if (!story) {
return null;
}
if (!asset.scraped) {
if (!story.scraped) {
await scraper.add({
assetID: asset.id,
assetURL: asset.url,
storyID: story.id,
storyURL: story.url,
tenantID: tenant.id,
});
}
return asset;
return story;
}