mirror of
https://github.com/wassname/talk.git
synced 2026-07-18 12:40:13 +08:00
Merge branch 'master' into events
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"linters": {
|
||||
"*.js": [
|
||||
"git-exec-and-restage eslint --fix --"
|
||||
],
|
||||
"bin/cli*": [
|
||||
"git-exec-and-restage eslint --fix --"
|
||||
],
|
||||
"*.yml": [
|
||||
"yamllint"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.username {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.headerRowItem {
|
||||
color: #595959;
|
||||
font-weight: bold;
|
||||
|
||||
@@ -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
|
||||
) : (
|
||||
<span>
|
||||
<Icon name="computer" /> {t('account_history.system')}
|
||||
</span>
|
||||
);
|
||||
|
||||
class AccountHistory extends React.Component {
|
||||
render() {
|
||||
@@ -68,9 +79,15 @@ class AccountHistory extends React.Component {
|
||||
'talk-admin-account-history-header-row'
|
||||
)}
|
||||
>
|
||||
<div className={styles.headerRowItem}>Date</div>
|
||||
<div className={styles.headerRowItem}>Action</div>
|
||||
<div className={styles.headerRowItem}>Moderation</div>
|
||||
<div className={styles.headerRowItem}>
|
||||
{t('account_history.date')}
|
||||
</div>
|
||||
<div className={styles.headerRowItem}>
|
||||
{t('account_history.action')}
|
||||
</div>
|
||||
<div className={styles.headerRowItem}>
|
||||
{t('account_history.taken_by')}
|
||||
</div>
|
||||
</div>
|
||||
{userHistory.map(
|
||||
({ __typename, created_at, assigned_by, until, status }) => (
|
||||
@@ -98,10 +115,11 @@ class AccountHistory extends React.Component {
|
||||
<div
|
||||
className={cn(
|
||||
styles.item,
|
||||
styles.username,
|
||||
'talk-admin-account-history-row-assigned-by'
|
||||
)}
|
||||
>
|
||||
{getModerationValue(user.id, assigned_by)}
|
||||
{getModerationValue(assigned_by)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ function parseAssetURL() {
|
||||
// Try to get the url from the canonical tag on the page.
|
||||
return document.querySelector('link[rel="canonical"]').href;
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
window.console.warn(
|
||||
'This page does not include a canonical link tag. Talk has inferred this asset_url from the window object. Query params have been stripped, which may cause a single thread to be present across multiple pages.'
|
||||
);
|
||||
|
||||
|
||||
@@ -432,6 +432,16 @@ da:
|
||||
all: "All"
|
||||
rejected: "Rejected"
|
||||
account_history: "Account History"
|
||||
account_history:
|
||||
user_banned: "User banned"
|
||||
ban_removed: "Ban removed"
|
||||
username_status: "Username {0}"
|
||||
suspended: "Suspended, {0}"
|
||||
suspension_removed: "Suspension removed"
|
||||
system: "System"
|
||||
date: "Date"
|
||||
action: "Action"
|
||||
taken_by: "Taken By"
|
||||
user_impersonating: "Denne bruger efterligner"
|
||||
user_no_comment: "Du har aldrig efterladt en kommentar. Deltag i samtalen"
|
||||
username_offensive: "Dette brugernavn er stødende"
|
||||
|
||||
@@ -431,6 +431,16 @@ de:
|
||||
all: "Alle"
|
||||
rejected: "Abgelehnte"
|
||||
account_history: "Konto-Verlauf"
|
||||
account_history:
|
||||
user_banned: "User banned"
|
||||
ban_removed: "Ban removed"
|
||||
username_status: "Username {0}"
|
||||
suspended: "Suspended, {0}"
|
||||
suspension_removed: "Suspension removed"
|
||||
system: "System"
|
||||
date: "Date"
|
||||
action: "Action"
|
||||
taken_by: "Taken By"
|
||||
user_impersonating: "Gibt sich für jemand anderen aus"
|
||||
user_no_comment: "Sie haben noch keinen Kommentar abgegeben. Teilen Sie Ihre Meinung mit uns!"
|
||||
username_offensive: "Dieser Nutzername ist unangemessen"
|
||||
|
||||
+13
-1
@@ -396,6 +396,8 @@ en:
|
||||
one_hour: "1 hour"
|
||||
hours: "{0} hours"
|
||||
days: "{0} days"
|
||||
hour: "{0} hours"
|
||||
day: "{0} days"
|
||||
cancel: "Cancel"
|
||||
suspend_user: "Suspend User"
|
||||
email_message_suspend: "Dear {0},\n\nIn accordance with {1}’s community guidelines, your account has been temporarily suspended. During the suspension, you will be unable to comment, flag or engage with fellow commenters. Please rejoin the conversation {2}."
|
||||
@@ -434,6 +436,16 @@ en:
|
||||
all: "All"
|
||||
rejected: "Rejected"
|
||||
account_history: "Account History"
|
||||
account_history:
|
||||
user_banned: "User banned"
|
||||
ban_removed: "Ban removed"
|
||||
username_status: "Username {0}"
|
||||
suspended: "Suspended, {0}"
|
||||
suspension_removed: "Suspension removed"
|
||||
system: "System"
|
||||
date: "Date"
|
||||
action: "Action"
|
||||
taken_by: "Taken By"
|
||||
user_impersonating: "This user is impersonating"
|
||||
user_no_comment: "You've never left a comment. Join the conversation!"
|
||||
username_offensive: "This username is offensive"
|
||||
@@ -462,4 +474,4 @@ en:
|
||||
close: "Close this Installer"
|
||||
admin_sidebar:
|
||||
view_options: "View Options"
|
||||
sort_comments: "Sort Comments"
|
||||
sort_comments: "Sort Comments"
|
||||
@@ -433,6 +433,16 @@ es:
|
||||
all: "All"
|
||||
rejected: "Rejected"
|
||||
account_history: "Account History"
|
||||
account_history:
|
||||
user_banned: "User banned"
|
||||
ban_removed: "Ban removed"
|
||||
username_status: "Username {0}"
|
||||
suspended: "Suspended, {0}"
|
||||
suspension_removed: "Suspension removed"
|
||||
system: "System"
|
||||
date: "Date"
|
||||
action: "Action"
|
||||
taken_by: "Taken By"
|
||||
user_impersonating: "Este usuario suplanta a alguien"
|
||||
user_no_comment: "No has dejado aún ningún comentario. ¡Únete a la conversación!"
|
||||
username_offensive: "Este nombre de usuario es ofensivo"
|
||||
|
||||
@@ -433,6 +433,16 @@ fr:
|
||||
all: "All"
|
||||
rejected: "Rejected"
|
||||
account_history: "Account History"
|
||||
account_history:
|
||||
user_banned: "User banned"
|
||||
ban_removed: "Ban removed"
|
||||
username_status: "Username {0}"
|
||||
suspended: "Suspended, {0}"
|
||||
suspension_removed: "Suspension removed"
|
||||
system: "System"
|
||||
date: "Date"
|
||||
action: "Action"
|
||||
taken_by: "Taken By"
|
||||
user_impersonating: "Cet utilisateur se fait passer pour quelqu'un d'autre"
|
||||
user_no_comment: "Vous n'avez jamais laissé de commentaire. Rejoignez la conversation !"
|
||||
username_offensive: "Ce nom d'utilisateur est offensant"
|
||||
|
||||
@@ -432,6 +432,16 @@ nl_NL:
|
||||
all: "Alle"
|
||||
rejected: "Afgewezen"
|
||||
account_history: "Accountgeschiedenis"
|
||||
account_history:
|
||||
user_banned: "User banned"
|
||||
ban_removed: "Ban removed"
|
||||
username_status: "Username {0}"
|
||||
suspended: "Suspended, {0}"
|
||||
suspension_removed: "Suspension removed"
|
||||
system: "System"
|
||||
date: "Date"
|
||||
action: "Action"
|
||||
taken_by: "Taken By"
|
||||
user_impersonating: "Deze gebruiker imiteert"
|
||||
user_no_comment: "Je hebt nog niet eerder gereageerd. Laat je mening horen!"
|
||||
username_offensive: "Dit is een aanstootgevende gebruikersnaam."
|
||||
|
||||
@@ -431,6 +431,16 @@ pt_BR:
|
||||
all: "All"
|
||||
rejected: "Rejected"
|
||||
account_history: "Account History"
|
||||
account_history:
|
||||
user_banned: "User banned"
|
||||
ban_removed: "Ban removed"
|
||||
username_status: "Username {0}"
|
||||
suspended: "Suspended, {0}"
|
||||
suspension_removed: "Suspension removed"
|
||||
system: "System"
|
||||
date: "Date"
|
||||
action: "Action"
|
||||
taken_by: "Taken By"
|
||||
user_impersonating: "Este usuário está representando"
|
||||
user_no_comment: "Você nunca deixou um comentário. Participe da conversa!"
|
||||
username_offensive: "Esse nome de usuário é ofensivo"
|
||||
|
||||
@@ -433,6 +433,16 @@ zh_CN:
|
||||
all: "All"
|
||||
rejected: "Rejected"
|
||||
account_history: "Account History"
|
||||
account_history:
|
||||
user_banned: "User banned"
|
||||
ban_removed: "Ban removed"
|
||||
username_status: "Username {0}"
|
||||
suspended: "Suspended, {0}"
|
||||
suspension_removed: "Suspension removed"
|
||||
system: "System"
|
||||
date: "Date"
|
||||
action: "Action"
|
||||
taken_by: "Taken By"
|
||||
user_impersonating: "冒名用户"
|
||||
user_no_comment: "您未曾发表评论。现在就来加入对话吧!"
|
||||
username_offensive: "用户名有冒犯性"
|
||||
|
||||
@@ -433,6 +433,16 @@ zh_TW:
|
||||
all: "All"
|
||||
rejected: "Rejected"
|
||||
account_history: "Account History"
|
||||
account_history:
|
||||
user_banned: "User banned"
|
||||
ban_removed: "Ban removed"
|
||||
username_status: "Username {0}"
|
||||
suspended: "Suspended, {0}"
|
||||
suspension_removed: "Suspension removed"
|
||||
system: "System"
|
||||
date: "Date"
|
||||
action: "Action"
|
||||
taken_by: "Taken By"
|
||||
user_impersonating: "此用戶正在冒充"
|
||||
user_no_comment: "您尚未評論過。加入對話吧!"
|
||||
username_offensive: "這個用戶名有冒犯性"
|
||||
|
||||
+7
-11
@@ -15,7 +15,7 @@
|
||||
"prebuild": "npm-run-all clean generate-introspection",
|
||||
"build": "NODE_ENV=production parallel-webpack --bail",
|
||||
"lint:yaml": "yamllint locales/*.yml",
|
||||
"lint:js": "eslint bin/* .",
|
||||
"lint:js": "eslint bin/cli* .",
|
||||
"lint": "npm-run-all lint:*",
|
||||
"plugins:reconcile": "./bin/cli plugins reconcile",
|
||||
"test": "npm-run-all test:client test:server",
|
||||
@@ -24,7 +24,9 @@
|
||||
"test:client:watch": "TEST_MODE=unit NODE_ENV=test jest --watch",
|
||||
"e2e": "./scripts/e2e.js",
|
||||
"e2e:ci": "./scripts/e2e-ci.sh",
|
||||
"heroku-postbuild": "npm-run-all plugins:reconcile build"
|
||||
"heroku-postbuild": "npm-run-all plugins:reconcile build",
|
||||
"precommit": "npm-run-all lint-staged",
|
||||
"lint-staged": "lint-staged"
|
||||
},
|
||||
"talk": {
|
||||
"migration": {
|
||||
@@ -196,6 +198,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@coralproject/eslint-config-talk": "^0.1.0",
|
||||
"@easyops/git-exec-and-restage": "^1.0.4",
|
||||
"babel-jest": "^21.2.0",
|
||||
"babel-plugin-dynamic-import-node": "^1.1.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
|
||||
@@ -208,14 +211,15 @@
|
||||
"enzyme-adapter-react-15": "^1.0.0",
|
||||
"eslint": "^4.5.0",
|
||||
"eslint-plugin-mocha": "^4.11.0",
|
||||
"husky": "^0.14.3",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"ip": "^1.1.5",
|
||||
"jest": "^21.2.1",
|
||||
"lint-staged": "^7.0.0",
|
||||
"mocha": "^3.1.2",
|
||||
"mocha-junit-reporter": "^1.12.1",
|
||||
"nightwatch": "^0.9.16",
|
||||
"nodemon": "^1.11.0",
|
||||
"pre-commit": "^1.2.2",
|
||||
"selenium-standalone": "^6.11.0",
|
||||
"sinon": "^3.2.1",
|
||||
"sinon-chai": "^2.13.0",
|
||||
@@ -223,13 +227,5 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"pre-commit": {
|
||||
"silent": false,
|
||||
"run": [
|
||||
"lint",
|
||||
"test:client",
|
||||
"test:server"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module.exports = router => {
|
||||
/**
|
||||
* Facebook auth endpoint, this will redirect the user immediately to facebook
|
||||
* Facebook auth endpoint, this will redirect the user immediately to Facebook
|
||||
* for authorization.
|
||||
*/
|
||||
router.get('/api/v1/auth/facebook', (req, res, next) => {
|
||||
@@ -16,7 +16,7 @@ module.exports = router => {
|
||||
});
|
||||
|
||||
/**
|
||||
* Facebook callback endpoint, this will send the user a html page designed to
|
||||
* Facebook callback endpoint, this will send the user a HTML page designed to
|
||||
* send back the user credentials upon successful login.
|
||||
*/
|
||||
router.get('/api/v1/auth/facebook/callback', (req, res, next) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ module.exports = router => {
|
||||
const { passport, HandleAuthPopupCallback } = require('services/passport');
|
||||
|
||||
/**
|
||||
* Google auth endpoint, this will redirect the user immediatly to google
|
||||
* Google auth endpoint, this will redirect the user immediately to Google
|
||||
* for authorization.
|
||||
*/
|
||||
router.get(
|
||||
@@ -16,10 +16,10 @@ module.exports = router => {
|
||||
|
||||
/**
|
||||
* Google callback endpoint, this will send the user a html page designed to
|
||||
* send back the user credentials upon sucesfull login.
|
||||
* send back the user credentials upon successful login.
|
||||
*/
|
||||
router.get('/api/v1/auth/google/callback', (req, res, next) => {
|
||||
// Perform the google login flow and pass the data back through the opener.
|
||||
// Perform the Google login flow and pass the data back through the opener.
|
||||
passport.authenticate(
|
||||
'google',
|
||||
{ session: false },
|
||||
|
||||
+3
-1
@@ -214,12 +214,14 @@ if (process.env.NODE_ENV === 'production') {
|
||||
toplevel: false,
|
||||
typeofs: false,
|
||||
unused: false,
|
||||
|
||||
// Switch off all types of compression except those needed to convince
|
||||
// react-devtools that we're using a production build
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
// Remove warnings + discard any console.* functions
|
||||
warnings: false,
|
||||
drop_console: true,
|
||||
},
|
||||
mangle: true,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user