diff --git a/.eslintignore b/.eslintignore
index 50d3f7109..47a26f579 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -2,33 +2,4 @@
dist
docs
node_modules
-plugins/*
public
-
-!plugins/talk-plugin-akismet
-!plugins/talk-plugin-auth
-!plugins/talk-plugin-author-menu
-!plugins/talk-plugin-comment-content
-!plugins/talk-plugin-deep-reply-count
-!plugins/talk-plugin-facebook-auth
-!plugins/talk-plugin-featured-comments
-!plugins/talk-plugin-flag-details
-!plugins/talk-plugin-ignore-user
-!plugins/talk-plugin-like
-!plugins/talk-plugin-love
-!plugins/talk-plugin-member-since
-!plugins/talk-plugin-mod
-!plugins/talk-plugin-moderation-actions
-!plugins/talk-plugin-offtopic
-!plugins/talk-plugin-permalink
-!plugins/talk-plugin-remember-sort
-!plugins/talk-plugin-respect
-!plugins/talk-plugin-sort-most-liked
-!plugins/talk-plugin-sort-most-loved
-!plugins/talk-plugin-sort-most-replied
-!plugins/talk-plugin-sort-most-respected
-!plugins/talk-plugin-sort-newest
-!plugins/talk-plugin-sort-oldest
-!plugins/talk-plugin-subscriber
-!plugins/talk-plugin-toxic-comments
-!plugins/talk-plugin-viewing-options
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index a27a08f15..11b6af551 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,35 +23,39 @@ browserstack.err
plugins.json
plugins/*
+
!plugins/talk-plugin-akismet
-!plugins/talk-plugin-facebook-auth
!plugins/talk-plugin-auth
-!plugins/talk-plugin-respect
-!plugins/talk-plugin-offtopic
-!plugins/talk-plugin-like
-!plugins/talk-plugin-mod
-!plugins/talk-plugin-love
-!plugins/talk-plugin-viewing-options
+!plugins/talk-plugin-author-menu
!plugins/talk-plugin-comment-content
-!plugins/talk-plugin-permalink
+!plugins/talk-plugin-deep-reply-count
+!plugins/talk-plugin-facebook-auth
!plugins/talk-plugin-featured-comments
-!plugins/talk-plugin-toxic-comments
-!plugins/talk-plugin-sort-newest
-!plugins/talk-plugin-sort-oldest
-!plugins/talk-plugin-sort-most-replied
+!plugins/talk-plugin-flag-details
+!plugins/talk-plugin-google-auth
+!plugins/talk-plugin-ignore-user
+!plugins/talk-plugin-like
+!plugins/talk-plugin-love
+!plugins/talk-plugin-member-since
+!plugins/talk-plugin-mod
+!plugins/talk-plugin-moderation-actions
+!plugins/talk-plugin-notifications
+!plugins/talk-plugin-notifications-category-reply
+!plugins/talk-plugin-offtopic
+!plugins/talk-plugin-permalink
+!plugins/talk-plugin-profile-settings
+!plugins/talk-plugin-remember-sort
+!plugins/talk-plugin-respect
+!plugins/talk-plugin-slack-notifications
!plugins/talk-plugin-sort-most-liked
!plugins/talk-plugin-sort-most-loved
+!plugins/talk-plugin-sort-most-replied
!plugins/talk-plugin-sort-most-respected
-!plugins/talk-plugin-author-menu
-!plugins/talk-plugin-member-since
-!plugins/talk-plugin-ignore-user
-!plugins/talk-plugin-moderation-actions
-!plugins/talk-plugin-toxic-comments
-!plugins/talk-plugin-remember-sort
-!plugins/talk-plugin-deep-reply-count
+!plugins/talk-plugin-sort-newest
+!plugins/talk-plugin-sort-oldest
!plugins/talk-plugin-subscriber
-!plugins/talk-plugin-flag-details
-!plugins/talk-plugin-slack-notifications
+!plugins/talk-plugin-toxic-comments
+!plugins/talk-plugin-viewing-options
**/node_modules/*
yarn-error.log
diff --git a/.lintstagedrc.json b/.lintstagedrc.json
new file mode 100644
index 000000000..9c9500651
--- /dev/null
+++ b/.lintstagedrc.json
@@ -0,0 +1,13 @@
+{
+ "linters": {
+ "*.js": [
+ "git-exec-and-restage eslint --fix --"
+ ],
+ "bin/cli*": [
+ "git-exec-and-restage eslint --fix --"
+ ],
+ "*.yml": [
+ "yamllint"
+ ]
+ }
+}
diff --git a/.nsprc b/.nsprc
index 583560bdd..da6cb9865 100644
--- a/.nsprc
+++ b/.nsprc
@@ -1,6 +1,7 @@
{
"exceptions": [
"https://nodesecurity.io/advisories/531",
- "https://nodesecurity.io/advisories/532"
+ "https://nodesecurity.io/advisories/532",
+ "https://nodesecurity.io/advisories/566"
]
}
diff --git a/Dockerfile b/Dockerfile
index 95aa74d8a..4d0fea440 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -18,7 +18,6 @@ ENV NODE_ENV production
# Install app dependencies and build static assets.
RUN yarn global add node-gyp && \
yarn install --frozen-lockfile && \
- cli plugins reconcile && \
yarn build && \
yarn cache clean
diff --git a/app.js b/app.js
index e962e41ff..c2bf9648d 100644
--- a/app.js
+++ b/app.js
@@ -1,7 +1,6 @@
const express = require('express');
const morgan = require('morgan');
const path = require('path');
-const uuid = require('uuid');
const merge = require('lodash/merge');
const helmet = require('helmet');
const plugins = require('./services/plugins');
@@ -13,13 +12,6 @@ const { ENABLE_TRACING, APOLLO_ENGINE_KEY, PORT } = require('./config');
const app = express();
-// Request Identity Middleware
-app.use((req, res, next) => {
- req.id = uuid.v4();
-
- next();
-});
-
//==============================================================================
// PLUGIN PRE APPLICATION MIDDLEWARE
//==============================================================================
diff --git a/bin/cli-jobs b/bin/cli-jobs
index 672a5a70d..a9599213d 100755
--- a/bin/cli-jobs
+++ b/bin/cli-jobs
@@ -6,8 +6,7 @@
const util = require('./util');
const program = require('commander');
-const scraper = require('../services/scraper');
-const mailer = require('../services/mailer');
+const jobs = require('../jobs');
const mongoose = require('../services/mongoose');
const kue = require('../services/kue');
@@ -21,11 +20,8 @@ function processJobs() {
// started.
util.onshutdown([() => kue.Task.shutdown()]);
- // Start the scraper processor.
- scraper.process();
-
- // Start the mail processor.
- mailer.process();
+ // Start the jobs processor.
+ jobs.process();
}
/**
diff --git a/bin/cli-plugins b/bin/cli-plugins
index 883682ede..ee331bff2 100755
--- a/bin/cli-plugins
+++ b/bin/cli-plugins
@@ -135,18 +135,11 @@ function reconcilePackages({ quiet = false, upgradeRemote = false }) {
return { local, fetchable, upgradable };
}
-async function reconcileRemotePlugins({ skipLocal, dryRun, upgradeRemote }) {
- console.log(
- `\n[${skipLocal ? '1/2' : '2/3'}] ${emoji.get(
- 'mag'
- )} Reconciling plugins...`.yellow
- );
+async function reconcileRemotePlugins({ dryRun, upgradeRemote }) {
+ console.log(`\n['1/2'] ${emoji.get('mag')} Reconciling plugins...`.yellow);
const { fetchable, upgradable } = reconcilePackages({ upgradeRemote });
- console.log(
- `[${skipLocal ? '2/2' : '3/3'}] ${emoji.get('truck')} Fetching plugins...\n`
- .yellow
- );
+ console.log(`['2/2'] ${emoji.get('truck')} Fetching plugins...\n`.yellow);
if (fetchable.length > 0) {
console.log(
@@ -206,98 +199,41 @@ async function reconcileRemotePlugins({ skipLocal, dryRun, upgradeRemote }) {
return { upgradable, fetchable };
}
-async function reconcileLocalPlugins({ skipRemote, dryRun }) {
- console.log(
- `\n[${skipRemote ? '1/1' : '1/3'}] ${emoji.get(
- 'pick'
- )} Installing local plugin dependencies...\n`.yellow
- );
- const { local } = reconcilePackages({ quiet: true });
-
- for (let i in local) {
- let { name } = local[i];
-
- if (!fs.existsSync(path.join(dir, 'plugins', name, 'package.json'))) {
- continue;
- }
-
- let wd = path.join(dir, 'plugins', name);
-
- console.log(`$ cd ${wd.cyan} && yarn`);
-
- if (!dryRun) {
- let args = [];
-
- let output = spawn.sync('yarn', args, {
- stdio: ['ignore', 'pipe', 'inherit'],
- cwd: wd,
- });
-
- if (output.status) {
- throw new Error(
- 'Could not install local plugin dependencies, errors occurred during install'
- );
- }
-
- console.log(output.stdout.toString());
- }
- }
-}
-
// This traverses the local plugins and installs any dependencies listed there,
// this only is really needed for plugins that are installed via docker because
// core plugins will have their dependencies already included in core.
-async function reconcilePluginDeps({
- skipLocal,
- skipRemote,
- dryRun,
- upgradeRemote,
-}) {
+async function reconcilePluginDeps({ dryRun, upgradeRemote }) {
try {
let startTime = new Date();
- // We don't need to do anything if we skip everything....
- if (skipLocal && skipRemote) {
- return;
- }
-
- // Traverse local plugins and install dependencies if enabled.
- if (!skipLocal) {
- await reconcileLocalPlugins({ skipRemote, dryRun });
- }
-
// Locate any external plugins and install them.
- if (!skipRemote) {
- const results = await reconcileRemotePlugins({
- skipLocal,
- skipRemote,
- dryRun,
- upgradeRemote,
- });
+ const results = await reconcileRemotePlugins({
+ dryRun,
+ upgradeRemote,
+ });
- let status;
- if (dryRun) {
- status = '[dry-run] success'.green;
- } else {
- status = 'success'.green;
- }
-
- let message;
- if (results.upgradable.length === 0 && results.fetchable.length === 0) {
- message = 'Already up-to-date.';
- } else if (results.upgradable.length === 0) {
- message = `Fetched ${results.fetchable.length} new plugins.`;
- } else if (results.fetchable.length === 0) {
- message = `Upgraded ${results.upgradable.length} new plugins.`;
- } else {
- message = `Fetched ${results.fetchable.length} new plugins, upgraded ${
- results.upgradable.length
- } plugins.`;
- }
-
- console.log(`\n${status} ${message}`);
+ let status;
+ if (dryRun) {
+ status = '[dry-run] success'.green;
+ } else {
+ status = 'success'.green;
}
+ let message;
+ if (results.upgradable.length === 0 && results.fetchable.length === 0) {
+ message = 'Already up-to-date.';
+ } else if (results.upgradable.length === 0) {
+ message = `Fetched ${results.fetchable.length} new plugins.`;
+ } else if (results.fetchable.length === 0) {
+ message = `Upgraded ${results.upgradable.length} new plugins.`;
+ } else {
+ message = `Fetched ${results.fetchable.length} new plugins, upgraded ${
+ results.upgradable.length
+ } plugins.`;
+ }
+
+ console.log(`\n${status} ${message}`);
+
let endTime = new Date();
let totalTime = ((endTime.getTime() - startTime.getTime()) / 1000).toFixed(
@@ -440,16 +376,12 @@ program
program
.command('reconcile')
- .description(
- 'reconciles local plugin dependencies and downloads external plugins'
- )
+ .description('reconciles dependencies by downloading external plugins')
.option('-u, --upgrade-remote', 'upgrades remote dependencies')
.option(
'-d, --dry-run',
'does not actually change anything on the filesystem acts only as a simulation'
)
- .option('--skip-local', 'skips the local dependancy reconciliation')
- .option('--skip-remote', 'skips the remote plugin reconciliation')
.action(reconcilePluginDeps);
program.parse(process.argv);
diff --git a/client/coral-admin/src/components/AccountHistory.css b/client/coral-admin/src/components/AccountHistory.css
index 09b324f08..fbd1027d1 100644
--- a/client/coral-admin/src/components/AccountHistory.css
+++ b/client/coral-admin/src/components/AccountHistory.css
@@ -15,6 +15,10 @@
}
}
+.username {
+ word-break: break-all;
+}
+
.headerRowItem {
color: #595959;
font-weight: bold;
diff --git a/client/coral-admin/src/components/AccountHistory.js b/client/coral-admin/src/components/AccountHistory.js
index 52f3af92d..a16b334ca 100644
--- a/client/coral-admin/src/components/AccountHistory.js
+++ b/client/coral-admin/src/components/AccountHistory.js
@@ -5,7 +5,10 @@ import styles from './AccountHistory.css';
import cn from 'classnames';
import flatten from 'lodash/flatten';
import orderBy from 'lodash/orderBy';
+import has from 'lodash/has';
import moment from 'moment';
+import t from 'coral-framework/services/i18n';
+import { Icon } from 'coral-ui';
const buildUserHistory = (userState = {}) => {
return orderBy(
@@ -29,31 +32,39 @@ const readableDuration = (startDate, endDate) => {
const durAsHours = dur.asHours().toFixed(0);
return durAsHours > 23
- ? `${durAsDays} ${durAsDays > 1 ? 'days' : 'day'}`
- : `${durAsHours} ${durAsHours > 1 ? 'hours' : 'hour'}`;
+ ? durAsDays > 1
+ ? t('suspenduser.days', durAsDays)
+ : t('suspenduser.day', durAsDays)
+ : durAsHours > 1
+ ? t('suspenduser.hours', durAsHours)
+ : t('suspenduser.hour', durAsHours);
};
const buildActionResponse = (typename, created_at, until, status) => {
switch (typename) {
case 'UsernameStatusHistory':
- return `Username ${status}`;
+ return t('account_history.username_status', status);
case 'BannedStatusHistory':
- return status ? 'User banned' : 'Ban removed';
+ return status
+ ? t('account_history.user_banned')
+ : t('account_history.ban_removed');
case 'SuspensionStatusHistory':
return until
- ? `Suspended, ${readableDuration(created_at, until)}`
- : 'Suspension removed';
+ ? t('account_history.suspended', readableDuration(created_at, until))
+ : t('account_history.suspension_removed');
default:
return '-';
}
};
-const getModerationValue = (userId, assignedBy = {}) => {
- if (assignedBy && userId !== assignedBy.id) {
- return assignedBy.username;
- }
- return 'SYSTEM';
-};
+const getModerationValue = assignedBy =>
+ has(assignedBy, 'username') ? (
+ assignedBy.username
+ ) : (
+
+
{emailAddress}
: null} +{emailAddress}
: null} -- {t('user_no_comment')} -
- )} -