This commit is contained in:
Mendel Konikov
2019-01-22 22:08:29 -05:00
486 changed files with 18951 additions and 10394 deletions
@@ -5,4 +5,7 @@ import CheckSpamHook from '../components/CheckSpamHook';
const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch);
export default connect(null, mapDispatchToProps)(CheckSpamHook);
export default connect(
null,
mapDispatchToProps
)(CheckSpamHook);
+87 -65
View File
@@ -25,82 +25,104 @@ let enabled = true;
// }
// });
async function checkForSpam(ctx, { asset_id, body }) {
const req = ctx.parent.parent;
const loaders = ctx.loaders;
//If the key validation failed, then we can't run with the client.
if (!enabled) {
debug('not enabled, passing');
return;
}
let spam = false;
try {
const user_ip = get(req, 'ip', false);
if (!user_ip) {
debug('no ip on request');
return;
}
// Get some headers from the request.
const user_agent = req.get('User-Agent');
if (!user_agent || user_agent.length === 0) {
debug('no user agent on request');
return;
}
const referrer = req.get('Referrer');
if (!referrer || referrer.length === 0) {
debug('no referrer on request');
return;
}
// Get the Asset that the comment is being made against.
const asset = await loaders.Assets.getByID.load(asset_id);
if (!asset) {
debug('asset not found for new comment');
return;
}
// Send off the comment to Akismet to check to see what they say.
spam = await client.checkSpam({
user_ip,
user_agent,
referrer,
permalink: asset.url,
comment_type: 'comment',
comment_content: body,
is_test: false,
});
debug(`comment analyzed as ${spam ? 'being' : 'not being'} spam`);
return spam;
} catch (err) {
console.trace(err);
return;
}
}
function handlePositiveSpam(input) {
// Attach reason information for the flag being added.
input.status = 'SYSTEM_WITHHELD';
input.actions =
input.actions && input.actions.length >= 0 ? input.actions : [];
input.actions.push({
action_type: 'FLAG',
user_id: null,
group_id: 'SPAM_COMMENT',
metadata: {},
});
}
module.exports = {
RootMutation: {
createComment: {
async pre(_, { input }, { loaders, parent: req }) {
// If the key validation failed, then we can't run with the client.
if (!enabled) {
debug('not enabled, passing');
return;
editComment: {
pre: async (_, { asset_id, edit: { body }, edit }, ctx) => {
const spam = await checkForSpam(ctx, { asset_id, body });
if (spam) {
// Mark the comment as positive spam.
handlePositiveSpam(edit);
}
let spam = false;
try {
const user_ip = get(req, 'ip', false);
if (!user_ip) {
debug('no ip on request');
return;
},
},
createComment: {
pre: async (_, { input }, ctx) => {
const spam = await checkForSpam(ctx, input);
if (spam) {
if (input.checkSpam) {
throw new ErrSpam();
}
// Get some headers from the request.
const user_agent = req.get('User-Agent');
if (!user_agent || user_agent.length === 0) {
debug('no user agent on request');
return;
}
const referrer = req.get('Referrer');
if (!referrer || referrer.length === 0) {
debug('no referrer on request');
return;
}
// Get the Asset that the comment is being made against.
const asset = await loaders.Assets.getByID.load(input.asset_id);
if (!asset) {
debug('asset not found for new comment');
return;
}
// Send off the comment to Akismet to check to see what they say.
spam = await client.checkSpam({
user_ip,
user_agent,
referrer,
permalink: asset.url,
comment_type: 'comment',
comment_content: input.body,
is_test: true,
});
debug(`comment analyzed as ${spam ? 'being' : 'not being'} spam`);
} catch (err) {
console.trace(err);
return;
// Mark the comment as positive spam.
handlePositiveSpam(input);
}
// Attach scores to metadata.
input.metadata = merge({}, input.metadata || {}, {
akismet: spam,
});
if (spam) {
if (input.checkSpam) {
throw new ErrSpam();
}
// Attach reason information for the flag being added.
input.status = 'SYSTEM_WITHHELD';
input.actions =
input.actions && input.actions.length >= 0 ? input.actions : [];
input.actions.push({
action_type: 'FLAG',
user_id: null,
group_id: 'SPAM_COMMENT',
metadata: {},
});
}
},
},
},
@@ -75,7 +75,7 @@ class SignUp extends React.Component {
showErrors={!!emailError}
errorMsg={emailError}
onChange={this.handleEmailChange}
autocomplete="off"
autoComplete="off"
/>
<TextField
id="username"
@@ -86,8 +86,8 @@ class SignUp extends React.Component {
showErrors={!!usernameError}
errorMsg={usernameError}
onChange={this.handleUsernameChange}
autocomplete="off"
autocapitalize="none"
autoComplete="off"
autoCapitalize="none"
/>
<TextField
id="password"
@@ -99,7 +99,7 @@ class SignUp extends React.Component {
errorMsg={passwordError}
onChange={this.handlePasswordChange}
minLength="8"
autocomplete="off"
autoComplete="off"
/>
{passwordError && (
<span className={styles.hint}>
@@ -116,7 +116,7 @@ class SignUp extends React.Component {
errorMsg={passwordRepeatError}
onChange={this.handlePasswordRepeatChange}
minLength="8"
autocomplete="off"
autoComplete="off"
/>
<Slot
fill="talkPluginAuth.formField"
@@ -58,6 +58,9 @@ const mapDispatchToProps = dispatch =>
);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
connect(
mapStateToProps,
mapDispatchToProps
),
withForgotPassword
)(ForgotPasswordContainer);
@@ -50,4 +50,7 @@ const mapDispatchToProps = dispatch =>
dispatch
);
export default connect(mapStateToProps, mapDispatchToProps)(MainContainer);
export default connect(
mapStateToProps,
mapDispatchToProps
)(MainContainer);
@@ -59,6 +59,9 @@ const mapDispatchToProps = dispatch =>
);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
connect(
mapStateToProps,
mapDispatchToProps
),
withResendEmailConfirmation
)(ResendEmailConfirmatonContainer);
@@ -89,6 +89,9 @@ const mapDispatchToProps = dispatch =>
);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
connect(
mapStateToProps,
mapDispatchToProps
),
withSignIn
)(SignInContainer);
@@ -145,6 +145,9 @@ const mapDispatchToProps = dispatch =>
);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
connect(
mapStateToProps,
mapDispatchToProps
),
withSignUp
)(SignUpContainer);
@@ -58,7 +58,10 @@ const mapStateToProps = state => ({
});
export default compose(
connect(mapStateToProps, null),
connect(
mapStateToProps,
null
),
withSetUsername,
branch(props => !props.username, renderNothing)
)(SetUsernameDialogContainer);
@@ -11,4 +11,7 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch =>
bindActionCreators({ showSignInDialog }, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(SignInButton);
export default connect(
mapStateToProps,
mapDispatchToProps
)(SignInButton);
@@ -10,4 +10,7 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch => bindActionCreators({ logout }, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(UserBox);
export default connect(
mapStateToProps,
mapDispatchToProps
)(UserBox);
+106 -127
View File
@@ -15,6 +15,7 @@ ar:
or: "أو"
email: "البريد الإلكتروني"
password: "كلمة المرور"
password_error: "يجب أن تكون كلمة المرور 8 أحرف على الأقل."
forgot_your_pass: "نسيت كلمة المرور؟"
need_an_account: "تحتاج الى حساب؟"
register: "تسجيل"
@@ -43,6 +44,15 @@ ar:
username: اسم المستخدم
write_your_username: "عدل اسم المستخدم"
your_username: "يظهر اسم المستخدم في كل تعليق تنشره."
change_password:
change_password: "تغيير كلمة المرور"
passwords_dont_match: "كلمات المرور غير متطابقة"
required_field: "هذه الخانة مطلوبه"
forgot_password: "نسيت كلمة المرور؟"
save: "حفظ"
cancel: "إلغاء"
edit: "تصحيح"
changed_password_msg: "كلمة المرور الخاصة بك تم تغييرها بنجاح"
da:
talk-plugin-auth:
login:
@@ -135,39 +145,13 @@ en:
your_username: "Your username appears on every comment you post."
change_password:
change_password: "Change Password"
passwords_dont_match: "Passwords don`t match"
passwords_dont_match: "Passwords don't match"
required_field: "This field is required"
forgot_password: "Forgot your password?"
save: "Save"
cancel: "Cancel"
edit: "Edit"
changed_password_msg: "Changed Password - Your password has been successfully changed"
change_username:
change_username_note: "Usernames can be changed every 14 days"
save: "Save"
edit_profile: "Edit Profile"
cancel: "Cancel"
confirm_username_change: "Confirm Username Change"
description: "You are attempting to change your username. Your new username will appear on all of your past and future comments."
old_username: "Old Username"
new_username: "New Username"
bottom_note: "Note: You will not be able to change your username again for 14 days"
confirm_changes: "Confirm Changes"
username_does_not_match: "Username does not match"
cant_be_equal: "Your new {0} must be different to your current one"
change_username_attempt: "Username can't be updated. Usernames can be changed every 14 days"
change_email:
confirm_email_change: "Confirm Email Address Change"
description: "You are attempting to change your email address. Your new email address will be used for your login and to receive account notifications."
old_email: "Old Email Address"
new_email: "New Email Address"
enter_password: "Enter Password"
incorrect_password: "Incorrect Password"
confirm_change: "Confirm Change"
cancel: "Cancel"
change_email_msg: "Email Address Changed - Your email address has been successfully changed. This email address will now be used for signing in and email notifications."
changed_username_success_msg: "Username Changed - Your username has been successfully changed. You will not be able to change your user name for 14 days."
change_username_attempt: "Username can't be updated. Usernames can only be changed every 14 days."
changed_password_msg: "Your password has been successfully changed"
de:
talk-plugin-auth:
login:
@@ -235,7 +219,7 @@ es:
register: "Registrar"
sign_up: "Registro"
confirm_password: "Confirmar Contraseña"
username: "Nombre"
username: "Nombre de Usuario"
already_have_an_account: "¿Ya tienes una cuenta?"
recover_password: "Recuperar la contraseña"
email_in_use: "Este correo se encuentra en uso"
@@ -269,20 +253,6 @@ es:
cancel: "Cancelar"
edit: "Editar"
changed_password_msg: "Contraseña Actualizada - Tu contraseña ha sido exitosamente actualizada"
change_username:
change_username_note: "El usuario puede ser cambiado cada 14 días"
save: "Guardar"
edit_profile: "Editar Perfil"
cancel: "Cancelar"
confirm_username_change: "Confirmar Cambio de Usuario"
description: "Estás intentando cambiar tu usuario. Tu nuevo usuario aparecerá en todos tus pasados y futuros comentarios."
old_username: "Usuario viejo"
new_username: "Usuario nuevo"
bottom_note: "Nota: No podrás cambiar tu usuario por 14 días"
confirm_changes: "Confirmar Cambios"
username_does_not_match: "El usuario no coincide"
changed_username_success_msg: "Usuario Actualizado - Tu usuario ha sido exitosamente actualizado. No podrás cambiar el usuario por 14 días."
change_username_attempt: "El usuario no puede ser actualizado. Los usuarios pueden ser cambiados cada 14 días."
fr:
talk-plugin-auth:
login:
@@ -370,94 +340,103 @@ he:
write_your_username: "ערוך את שם המשתמש שלך"
your_username: "שם המשתמש שלך מופיע בכל תגובה שתפרסם."
nl_NL:
sign_in:
email_verify_cta: "Controleer je e-mailadres."
request_new_verify_email: "Vraag nieuwe bevestigingsemail aan"
verify_email: "Bedankt voor het aanmaken van een account! We hebben een email verstuurd naar het adres dat je hebt opgegeven om je account te verifiëren."
verify_email2: "Je account moet worden geverifiëerd voordat je kunt deelnemen in de community."
not_you: "Ben je dit niet?"
logged_in_as: "Ingelogd als"
facebook_sign_in: "Inloggen met Facebook"
facebook_sign_up: "Registreren met Facebook"
logout: "Uitloggen"
sign_in: "Inloggen"
sign_in_to_join: "Log in om deel te nemen"
or: "Of"
email: "E-mailadres"
password: "Wachtwoord"
forgot_your_pass: "Wachtwoord vergeten?"
need_an_account: "Heb je een account nodig?"
register: "Registreren"
sign_up: "Aanmelden"
confirm_password: "Bevestig wachtwoord"
username: "Gebruikersnaam"
already_have_an_account: "Heb je al een account?"
recover_password: "Wachtwoord herstellen"
email_in_use: "E-mailadres is al in gebruik"
email_or_username_in_use: "E-mailadres of gebruikersnaam is al in gebruik"
required_field: "Dit is een vereist veld"
passwords_dont_match: "Wachtwoorden komen niet overeen"
special_characters: "Gebruikersnamen kunnen alleen letters, cijfers en _ bevatten"
sign_in_to_comment: "Aanmelden om te reageren"
check_the_form: "Het formulier bevat ongeldige invoer, controleer je invoer"
createdisplay:
check_the_form: "Het formulier bevat ongeldige invoer, controleer je invoer"
continue: "Doorgaan met dezelfde Facebook gebruikersnaam"
error_create: "Fout opgetreden bij het wijzigen van de gebruikersnaam"
fake_comment_body: "Dit is een voorbeeldreactie. Lezers kunnen hun gedachten en meningen met newsrooms delen in het reactie-gedeelte"
fake_comment_date: "1 minuut geleden"
if_you_dont_change_your_name: "Wanneer je je gebruikersnaam nu niet wijzigt, zal je Facebook naam bij al je reacties komen te staan."
required_field: "Vereist veld"
save: Opslaan
special_characters: "Gebruikersnamen kunnen alleen letters, cijfers en _ bevatten"
username: Gebruikersnaam
write_your_username: "Wijzig je gebruikersnaam"
your_username: "Je gebruikersnaam verschijnt bij al je reacties."
talk-plugin-auth:
login:
email_verify_cta: "Controleer je e-mailadres."
request_new_verify_email: "Vraag nieuwe bevestigingsemail aan"
verify_email: "Bedankt voor het aanmaken van een account! We hebben een email verstuurd naar het adres dat je hebt opgegeven om je account te verifiëren."
verify_email2: "Je account moet worden geverifiëerd voordat je kunt deelnemen in de community."
not_you: "Ben je dit niet?"
logged_in_as: "Ingelogd als"
logout: "Uitloggen"
sign_in: "Inloggen"
sign_in_to_join: "Log in om deel te nemen"
or: "Of"
email: "E-mailadres"
password: "Wachtwoord"
password_error: "Wachtwoord moet minstens 8 karakters bevatten."
forgot_your_pass: "Wachtwoord vergeten?"
need_an_account: "Heb je een account nodig?"
register: "Registreren"
sign_up: "Aanmelden"
confirm_password: "Bevestig wachtwoord"
username: "Gebruikersnaam"
already_have_an_account: "Heb je al een account?"
recover_password: "Wachtwoord herstellen"
email_in_use: "E-mailadres is al in gebruik"
email_or_username_in_use: "E-mailadres of gebruikersnaam is al in gebruik"
required_field: "Dit is een vereist veld"
passwords_dont_match: "Wachtwoorden komen niet overeen"
special_characters: "Gebruikersnamen kunnen alleen letters, cijfers en _ bevatten"
sign_in_to_comment: "Aanmelden om te reageren"
check_the_form: "Het formulier bevat ongeldige invoer, controleer je invoer"
set_username_dialog:
check_the_form: "Het formulier bevat ongeldige invoer, controleer je invoer"
continue: "Doorgaan met dezelfde Facebook gebruikersnaam"
error_create: "Fout opgetreden bij het wijzigen van de gebruikersnaam"
fake_comment_body: "Dit is een voorbeeldreactie. Lezers kunnen hun gedachten en meningen met newsrooms delen in het reactie-gedeelte"
fake_comment_date: "1 minuut geleden"
if_you_dont_change_your_name: "Wanneer je je gebruikersnaam nu niet wijzigt, zal je Facebook naam bij al je reacties komen te staan."
required_field: "Vereist veld"
save: Opslaan
special_characters: "Gebruikersnamen kunnen alleen letters, cijfers en _ bevatten"
username: Gebruikersnaam
write_your_username: "Wijzig je gebruikersnaam"
your_username: "Je gebruikersnaam verschijnt bij al je reacties."
change_password:
change_password: "Wachtwoord Wijzigen"
passwords_dont_match: "Wachtwoorden komen niet overeen"
required_field: "Dit veld is verplicht"
forgot_password: "Wachtwoord vergeten?"
save: "Opslaan"
cancel: "Annuleren"
edit: "Wijzigen"
changed_password_msg: "Je wachtwoord is succesvol gewijzigd"
pt_BR:
talk-plugin-auth:
login:
email_verify_cta: "Please verify your email address."
request_new_verify_email: "Request another email"
verify_email: "Thank you for creating an account! We sent an email to the address you provided to verify your account."
verify_email2: "You must verify your account before engaging with the community."
not_you: "Not you?"
logged_in_as: "Signed in as"
facebook_sign_in: "Sign in with Facebook"
facebook_sign_up: "Sign up with Facebook"
logout: "Sign out"
sign_in: "Sign in"
sign_in_to_join: "Sign in to join the conversation"
or: "Or"
email: "Email Address"
password: "Password"
forgot_your_pass: "Forgot your password?"
need_an_account: "Need an account?"
register: "Register"
sign_up: "Sign Up"
confirm_password: "Confirm Password"
username: "Username"
already_have_an_account: "Already have an account?"
recover_password: "Recover password"
email_in_use: "Email address already in use"
email_or_username_in_use: "Email address or Username already in use"
required_field: "This field is required"
passwords_dont_match: "Passwords don't match."
special_characters: "Usernames can contain letters, numbers and _ only"
sign_in_to_comment: "Sign in to comment"
check_the_form: "Invalid Form. Please, check the fields"
already_have_an_account: "Já possui uma conta?"
check_the_form: "Formulário inválido. Por favor confira os campos"
confirm_password: "Confirmar senha"
email: "Endereço de email"
email_in_use: "Endereço de email já está em uso"
email_or_username_in_use: "Endereço de email ou nome de usuário já em uso"
email_verify_cta: "Por favor verifique seu endereço de email."
facebook_sign_in: "Entrar com o Facebook"
facebook_sign_up: "Cadastrar com o Facebook"
forgot_your_pass: "Esqueceu sua senha?"
request_new_verify_email: "Solicite outro email"
verify_email: "Obrigado por criar uma conta! Enviamos um email para o endereço de email informado para verificar sua conta."
verify_email2: "Você deve verificar sua conta antes de participar da comunidade."
logged_in_as: "Logado como"
logout: "Sair"
need_an_account: "Precisa de uma conta?"
not_you: "Não é você?"
or: "Ou"
password: "Senha"
passwords_dont_match: "As senhas não conferem."
recover_password: "Recuperar senha"
register: "Registrar"
required_field: "Esse campo é obrigatório"
sign_in: "Entrar"
sign_in_to_comment: "Entre para comentar"
sign_in_to_join: "Entre para participar da conversa"
sign_up: "Inscreva-se"
special_characters: "Nome de usuário contem somente letras, números and _"
username: "Nome de usuário"
set_username_dialog:
check_the_form: "Invalid Form. Please check the fields"
continue: "Continue with the same Facebook username"
error_create: "Error when changing username"
fake_comment_body: "This is an example comment. Readers can share their thoughts and opinions with newsrooms in the comments section."
fake_comment_date: "1 minute ago"
if_you_dont_change_your_name: "If you don't change your username at this step your Facebook display name will appear alongside of all your comments."
required_field: "Required field"
save: Save
special_characters: "Usernames can contain letters numbers and _ only"
username: Username
write_your_username: "Edit your username"
your_username: "Your username appears on every comment you post."
check_the_form: "Formulário inválido. Por favor confira os campos"
continue: "Continue com o mesmo nome de usuário do Facebook"
error_create: "Erro ao trocar o nome de usuário"
fake_comment_body: "Esse é um comentário de exemplo. Leitores podem compartilhar pensamentos e opiniões na seção de comentários."
fake_comment_date: "1 minuto atrás"
if_you_dont_change_your_name: "Se você não mudar seu nome de usuário neste ponto do processo, o nome que está no seu Facebook irá aparecer junto de todos os seus comentários"
required_field: "Campo obrigatório"
save: Salvar
special_characters: "Nome de usuários podem conter somente letras números e _"
username: Nome de usuário
write_your_username: "Edite seu nome de usuário"
your_username: "Seu nome de usuário aparece em cada comentário feito."
zh_CN:
talk-plugin-auth:
login:
@@ -122,7 +122,10 @@ const withAuthorNameFragments = withFragments({
});
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
connect(
mapStateToProps,
mapDispatchToProps
),
withAuthorNameFragments
);
@@ -85,7 +85,13 @@ module.exports = {
}),
resolvers: {
Comment: {
deepReplyCount({ id }, args, { loaders: { Comments } }) {
deepReplyCount(
{ id },
args,
{
loaders: { Comments },
}
) {
return Comments.getDeepCount.load(id);
},
},
@@ -29,6 +29,8 @@ Configuration:
guide. This is only required while the `talk-plugin-facebook-auth` plugin is
enabled.
_NOTE: FabceBook auth requires your site to use `https` (SSL) not `http`. If your site is not `https` you can not use this plugin!_
## GDPR Compliance
In order to facilitate compliance with the
@@ -1,3 +1,5 @@
import { handlePopupAuth } from 'plugin-api/beta/client/utils';
export const loginWithFacebook = () => (dispatch, _, { rest }) => {
window.location = `${rest.uri}/auth/facebook`;
handlePopupAuth(`${rest.uri}/auth/facebook`);
};
@@ -6,4 +6,7 @@ import FacebookButton from '../components/FacebookButton';
const mapDispatchToProps = dispatch =>
bindActionCreators({ onClick: loginWithFacebook }, dispatch);
export default connect(null, mapDispatchToProps)(FacebookButton);
export default connect(
null,
mapDispatchToProps
)(FacebookButton);
@@ -5,6 +5,7 @@ import translations from './translations.yml';
export default {
translations,
slots: {
authExternalAdminSignIn: [SignIn],
authExternalSignIn: [SignIn],
authExternalSignUp: [SignUp],
},
@@ -2,6 +2,10 @@ ar:
talk-plugin-facebook-auth:
sign_in: "تسجيل الدخول عبر حساب الفيسبوك"
sign_up: "اشترك عبر حساب الفيسبوك"
de:
talk-plugin-facebook-auth:
sign_in: "Mit Facebook anmelden"
sign_up: "Mit Facebook registrieren"
en:
talk-plugin-facebook-auth:
sign_in: "Sign in with Facebook"
@@ -18,6 +22,10 @@ he:
talk-plugin-facebook-auth:
sign_in: "התחבר עם פייסבוק"
sign_up: "הרשם עם פייסבוק"
nl_NL:
talk-plugin-facebook-auth:
sign_in: "Inloggen met Facebook"
sign_up: "Registreren met Facebook"
zh_CN:
talk-plugin-facebook-auth:
sign_in: "使用 Facebook 帐号"
@@ -26,7 +34,3 @@ zh_TW:
talk-plugin-facebook-auth:
sign_in: "使用 Facebook 帳號"
sign_up: "使用 Facebook 帳號"
de:
talk-plugin-facebook-auth:
sign_in: "Mit Facebook anmelden"
sign_up: "Mit Facebook registrieren"
@@ -27,7 +27,7 @@ module.exports = passport => {
try {
const { id, provider, displayName } = profile;
user = await UsersService.findOrCreateExternalUser(
user = await UsersService.upsertSocialUser(
req.context,
id,
provider,
@@ -5,7 +5,11 @@ module.exports = router => {
*/
router.get('/api/v1/auth/facebook', (req, res, next) => {
const {
connectors: { services: { Passport: { passport } } },
connectors: {
services: {
Passport: { passport },
},
},
} = req.context;
return passport.authenticate('facebook', {
@@ -22,7 +26,9 @@ module.exports = router => {
router.get('/api/v1/auth/facebook/callback', (req, res, next) => {
const {
connectors: {
services: { Passport: { passport, HandleAuthPopupCallback } },
services: {
Passport: { passport, HandleAuthPopupCallback },
},
},
} = req.context;
@@ -5,7 +5,13 @@ import { t } from 'plugin-api/beta/client/services';
import { Icon } from 'plugin-api/beta/client/components/ui';
export default ({ className = '' }) => (
<div className={cn(styles.tooltip, className)}>
<div
className={cn(
styles.tooltip,
className,
'talk-plugin-featured-comments-tooltip'
)}
>
<Icon name="info_outline" className={styles.icon} />
<h3 className={styles.headline}>
{t('talk-plugin-featured-comments.featured_comments')}:
@@ -19,7 +19,10 @@ const mapDispatchToProps = dispatch =>
);
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
connect(
mapStateToProps,
mapDispatchToProps
),
withTags('featured')
);
@@ -13,7 +13,10 @@ const mapDispatchToProps = dispatch =>
);
const enhance = compose(
connect(null, mapDispatchToProps),
connect(
null,
mapDispatchToProps
),
withTags('featured')
);
@@ -12,7 +12,13 @@ class ModIndicatorSubscription extends React.Component {
document: COMMENT_FEATURED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { commentFeatured: { comment } } } }
{
subscriptionData: {
data: {
commentFeatured: { comment },
},
},
}
) => {
return this.props.handleCommentChange(prev, comment);
},
@@ -21,7 +27,13 @@ class ModIndicatorSubscription extends React.Component {
document: COMMENT_UNFEATURED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { commentUnfeatured: { comment } } } }
{
subscriptionData: {
data: {
commentUnfeatured: { comment },
},
},
}
) => {
return this.props.handleCommentChange(prev, comment);
},
@@ -28,7 +28,13 @@ class ModSubscription extends React.Component {
},
updateQuery: (
prev,
{ subscriptionData: { data: { commentFeatured: { user, comment } } } }
{
subscriptionData: {
data: {
commentFeatured: { user, comment },
},
},
}
) => {
const notifyText =
this.props.user.id === user.id
@@ -50,7 +56,9 @@ class ModSubscription extends React.Component {
prev,
{
subscriptionData: {
data: { commentUnfeatured: { user, comment } },
data: {
commentUnfeatured: { user, comment },
},
},
}
) => {
@@ -117,7 +125,10 @@ const mapStateToProps = state => ({
});
export default compose(
connect(mapStateToProps, null),
connect(
mapStateToProps,
null
),
withVariables,
withSubscribeToMore
)(ModSubscription);
@@ -22,7 +22,10 @@ const fragments = {
`,
};
const enhance = compose(
connect(null, mapDispatchToProps),
connect(
null,
mapDispatchToProps
),
withTags('featured', { fragments })
);
@@ -90,7 +90,10 @@ const mapDispatchToProps = dispatch =>
);
const enhance = compose(
connect(null, mapDispatchToProps),
connect(
null,
mapDispatchToProps
),
withFetchMore,
withVariables,
withFragments({
@@ -62,7 +62,7 @@ es:
talk-plugin-featured-comments:
un_feature: Desmarcar
feature: Remarcar
featured: Remarcado
featured: Remarcados
featured_comments: Comentarios Remarcados
go_to_conversation: Ir al comentario
tooltip_description: Comentarios seleccionados por nuestro equipo que valen la pena ser leidos
@@ -117,19 +117,19 @@ nl_NL:
yes_feature_comment: Ja, reactie uitlichten.
pt_BR:
talk-plugin-featured-comments:
un_feature: Un-Feature
feature: Feature
featured: Featured
featured_comments: Featured Comments
go_to_conversation: Go to conversation
tooltip_description: Comments selected by our team as worth reading
notify_self_featured: 'The comment from {0} is now featured and approved'
notify_featured: '{0} featured and approved comment "{1}"'
notify_unfeatured: '{0} unfeatured comment "{1}"'
feature_comment: Feature comment?
are_you_sure: Are you sure you would like to feature this comment?
cancel: Cancel
yes_feature_comment: Yes, feature comment
un_feature: Desfazer
feature: Destacar
featured: Destacado
featured_comments: Comentários destacados
go_to_conversation: Ir para conversa
tooltip_description: Vale a pena ler os comentários selecionados pelo nosso time
notify_self_featured: 'O comentário do {0} está em destaque e aprovado'
notify_featured: '{0} destacou e aprovou o comentário "{1}"'
notify_unfeatured: '{0} Desmarcar comentário "{1}"'
feature_comment: Destacar comentário?
are_you_sure: Você tem certeza que deseja destacar esse comentário?
cancel: Cancelar
yes_feature_comment: Sim, destacar comentário
zh_CN:
talk-plugin-featured-comments:
un_feature: "取消精选"
+16 -4
View File
@@ -59,8 +59,14 @@ module.exports = {
addTag: {
async post(
obj,
{ tag: { name, id, item_type } },
{ user, mutators: { Comment }, pubsub }
{
tag: { name, id, item_type },
},
{
user,
mutators: { Comment },
pubsub,
}
) {
if (name === 'FEATURED' && item_type === 'COMMENTS') {
const comment = await Comment.setStatus({
@@ -76,8 +82,14 @@ module.exports = {
removeTag: {
async post(
obj,
{ tag: { name, id, item_type } },
{ user, loaders: { Comments }, pubsub }
{
tag: { name, id, item_type },
},
{
user,
loaders: { Comments },
pubsub,
}
) {
if (name === 'FEATURED' && item_type === 'COMMENTS') {
const comment = await Comments.get.load(id);
@@ -10,7 +10,12 @@ import {
class FlagDetails extends Component {
render() {
const { comment: { actions }, more, root, comment } = this.props;
const {
comment: { actions },
more,
root,
comment,
} = this.props;
const flagActions =
actions && actions.filter(a => a.__typename === 'FlagAction');
@@ -5,7 +5,10 @@ import styles from './UserFlagDetails.css';
class UserFlagDetails extends Component {
render() {
const { comment: { actions }, viewUserDetail } = this.props;
const {
comment: { actions },
viewUserDetail,
} = this.props;
const flagActions =
actions && actions.filter(a => a.__typename === 'FlagAction');
@@ -15,7 +15,10 @@ const mapDispatchToProps = dispatch => ({
});
const enhance = compose(
connect(null, mapDispatchToProps),
connect(
null,
mapDispatchToProps
),
withFragments({
comment: gql`
fragment CoralAdmin_UserFlagDetails_comment on Comment {
@@ -1,3 +1,5 @@
import { handlePopupAuth } from 'plugin-api/beta/client/utils';
export const loginWithGoogle = () => (dispatch, _, { rest }) => {
window.location = `${rest.uri}/auth/google`;
handlePopupAuth(`${rest.uri}/auth/google`);
};
@@ -6,4 +6,7 @@ import GoogleButton from '../components/GoogleButton';
const mapDispatchToProps = dispatch =>
bindActionCreators({ onClick: loginWithGoogle }, dispatch);
export default connect(null, mapDispatchToProps)(GoogleButton);
export default connect(
null,
mapDispatchToProps
)(GoogleButton);
@@ -5,6 +5,7 @@ import translations from './translations.yml';
export default {
translations,
slots: {
authExternalAdminSignIn: [SignIn],
authExternalSignIn: [SignIn],
authExternalSignUp: [SignUp],
},
@@ -8,21 +8,25 @@ en:
sign_up: "Sign up with Google"
es:
talk-plugin-google-auth:
google_sign_in: "Entrar con Google"
google_sign_up: "Registrarse con Google"
sign_in: "Entrar con Google"
sign_up: "Registrarse con Google"
fr:
talk-plugin-google-auth:
google_sign_in: "Connectez-vous avec Google"
google_sign_up: "Inscrivez-vous avec Google"
en:
sign_in: "Connectez-vous avec Google"
sign_up: "Inscrivez-vous avec Google"
he:
talk-plugin-google-auth:
sign_in: "התחבר עם גוגל"
sign_up: "הרשם עם גוגל"
nl_NL:
talk-plugin-google-auth:
sign_in: "Inloggen met Google"
sign_up: "Registeren met Google"
zh_CN:
talk-plugin-google-auth:
google_sign_in: "使用 Google 帐号"
google_sign_up: "使用 Google 帐号"
sign_in: "使用 Google 帐号"
sign_up: "使用 Google 帐号"
zh_TW:
talk-plugin-google-auth:
google_sign_in: "使用 Google 帳號"
google_sign_up: "使用 Google 帳號"
sign_in: "使用 Google 帳號"
sign_up: "使用 Google 帳號"
@@ -26,7 +26,7 @@ module.exports = passport => {
try {
const { id, provider, displayName } = profile;
user = await UsersService.findOrCreateExternalUser(
user = await UsersService.upsertSocialUser(
req.context,
id,
provider,
@@ -45,7 +45,10 @@ const withIgnoreUserActionFragments = withFragments({
});
const enhance = compose(
connect(null, mapDispatchToProps),
connect(
null,
mapDispatchToProps
),
withIgnoreUserActionFragments,
excludeIf(({ root: { me }, comment }) => !me || me.id === comment.user.id)
);
@@ -65,7 +65,10 @@ const withIgnoreUserConfirmationFragments = withFragments({
});
const enhance = compose(
connect(null, mapDispatchToProps),
connect(
null,
mapDispatchToProps
),
withIgnoreUserConfirmationFragments,
withIgnoreUser
);
@@ -37,6 +37,9 @@ const withIgnoredUserSectionFragments = withFragments({
`,
});
const enhance = compose(withIgnoredUserSectionFragments, withStopIgnoringUser);
const enhance = compose(
withIgnoredUserSectionFragments,
withStopIgnoringUser
);
export default enhance(IgnoredUserSectionContainer);
@@ -1,5 +1,6 @@
ar:
talk-plugin-ignore-user:
blank_info: أنت لا تتجاهل حاليًا أي مستخدم
section_title: المستخدمون الذين تم تجاهلهم
section_info: لأنك تجاهلت المعلقين التاليين، يتم إخفاء تعليقاتهم.
stop_ignoring: إيقاف التجاهل
@@ -25,6 +26,7 @@ da:
confirmation_title: Ignore {0}?
de:
talk-plugin-ignore-user:
blank_info: Sie ignorieren derzeit keine Nutzer
section_title: Ignorierte Nutzer
section_info: Weil Sie die folgenden Nutzer ignorieren, sind deren Kommentare versteckt.
stop_ignoring: Ignorieren beenden
@@ -35,30 +37,32 @@ de:
confirmation_title: "{0} ignorieren?"
en:
talk-plugin-ignore-user:
blank_info: You are currently not ignoring any users
section_title: Ignored users
section_info: Because you ignored the following commenters, their comments are hidden.
stop_ignoring: Stop ignoring
ignore_user: Ignore User
cancel: Cancel
confirmation: |
When you ignore a user, all comments they wrote on the site will be hidden from you. You can
undo this later from My Profile.
notify_success: |
You are now ignoring {0}. You can undo this action from My Profile.
confirmation_title: Ignore {0}?
es:
talk-plugin-ignore-user:
section_title: "Usuarios ignorados"
section_info: Because you ignored the following commenters, their comments are hidden.
stop_ignoring: "No ignorar más"
ignore_user: Ignore User
cancel: Cancel
confirmation: |
When you ignore a user, all comments they wrote on the site will be hidden from you. You can
undo this later from My Profile.
notify_success: |
You are now ignoring {0}. You can undo this action from My Profile.
confirmation_title: Ignore {0}?
es:
talk-plugin-ignore-user:
section_title: "Usuarios ignorados"
blank_info: Actualmente no ignoras a ningún usuario
section_info: Debido a que ignoró a los siguientes comentaristas, sus comentarios están ocultos.
stop_ignoring: "No ignorar más"
ignore_user: Ignorar usuario
cancel: Cancelar
confirmation: |
Cuando ignora a un usuario, todos los comentarios que escribió en el sitio estarán ocultos.
Puede deshacer esto más tarde desde Mi Perfil.
notify_success: |
Ahora estás ignorando a {0}. Puede deshacer esta acción desde Mi Perfil.
confirmation_title: Ignorar a {0}?
fr:
talk-plugin-ignore-user:
section_title: "Utilisateurs ignorés"
@@ -99,17 +103,18 @@ nl_NL:
confirmation_title: Negeer {0}?
pt_BR:
talk-plugin-ignore-user:
blank_info: Atualmente você não está ignorando nenhum usuário
section_title: "Usuários ignorados"
section_info: "Porque você ignorou os seguintes comentadores, seus comentários estão ocultos."
stop_ignoring: "Pare de ignorar"
ignore_user: Ignore User
cancel: Cancel
confirmation: |
When you ignore a user, all comments they wrote on the site will be hidden from you. You can
undo this later from My Profile.
stop_ignoring: "Parar de ignorar"
ignore_user: Ignorar usuário
cancel: Cancelar
confirmation:
Quando você ignora um usuário, todos os comentários que ele ele(a) escreveu não serão exibidos para você. Você pode
desfazer isso depois no Meu Perfil
notify_success: |
You are now ignoring {0}. You can undo this action from My Profile.
confirmation_title: Ignore {0}?
Agora você está ignorando {0}. Você pode desfazer essa ação em Meu Perfil.
confirmation_title: Ignorar {0}?
zh_CN:
talk-plugin-ignore-user:
section_title: "被忽略用户"
@@ -0,0 +1,9 @@
import * as actions from './constants';
export const startAttach = () => ({
type: actions.START_ATTACH,
});
export const finishAttach = () => ({
type: actions.FINISH_ATTACH,
});
@@ -1,15 +1,3 @@
.dialog {
border: none;
box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2);
width: 320px;
top: 50%;
transform: translateY(-50%);
padding: 20px;
border-radius: 4px;
font-family: Helvetica,Helvetica Neue,Verdana,sans-serif;
color:#3B4A53;
}
.title {
font-size: 1.3em;
margin: 15px 0;
@@ -28,7 +16,7 @@
margin: 20px 0;
list-style: none;
}
.item {
display: flex;
margin-bottom: 20px;
@@ -46,37 +34,21 @@
font-size: 1.3em;
}
}
.button {
color: #787D80;
border-radius: 2px;
background-color: transparent;
height: 30px;
font-size: 0.9em;
line-height: normal;
width: 100%;
display: inline-block;
text-align: center;
line-height: 30px;
font-size: 1em;
background-color: #3498DB;
color: white;
&:hover {
background-color: #eaeaea;
cursor: pointer;
}
&.cancel {
background-color: transparent;
color: #787D80;
}
&.proceed {
background-color: #3498DB;
color: white;
}
&.danger {
background-color: #FA4643;
color: white;
}
}
}
@@ -0,0 +1,127 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './AddEmailForm.css';
import { Icon } from 'plugin-api/beta/client/components/ui';
import InputField from '../InputField';
import { t } from 'plugin-api/beta/client/services';
import {
composeValidators,
required,
verifyEmail,
confirmEmail,
verifyPassword,
confirmPassword,
} from 'coral-framework/lib/validation';
import { Form, Field } from 'react-final-form';
const AddEmailContent = ({ onSubmit }) => (
<div>
<h4 className={styles.title}>
{t('talk-plugin-local-auth.add_email.content.title')}
</h4>
<p className={styles.description}>
{t('talk-plugin-local-auth.add_email.content.description')}
</p>
<ul className={styles.list}>
<li className={styles.item}>
<Icon name="done" className={styles.itemIcon} />
<span className={styles.text}>
{t('talk-plugin-local-auth.add_email.content.item_1')}
</span>
</li>
<li className={styles.item}>
<Icon name="done" className={styles.itemIcon} />
<span className={styles.text}>
{t('talk-plugin-local-auth.add_email.content.item_2')}
</span>
</li>
<li className={styles.item}>
<Icon name="done" className={styles.itemIcon} />
<span className={styles.text}>
{t('talk-plugin-local-auth.add_email.content.item_3')}
</span>
</li>
</ul>
<Form onSubmit={onSubmit}>
{({ handleSubmit, submitting }) => (
<form autoComplete="off" onSubmit={handleSubmit}>
<Field
name="email"
validate={composeValidators(required, verifyEmail)}
>
{({ input, meta }) => (
<InputField
label={t(
'talk-plugin-local-auth.add_email.enter_email_address'
)}
name={input.name}
onChange={input.onChange}
value={input.value}
errorMsg={meta.error}
showError={meta.touched}
columnDisplay
/>
)}
</Field>
<Field name="confirmEmail" validate={confirmEmail('email')}>
{({ input, meta }) => (
<InputField
label={t(
'talk-plugin-local-auth.add_email.confirm_email_address'
)}
name={input.name}
onChange={input.onChange}
value={input.value}
errorMsg={meta.error}
showError={meta.touched}
columnDisplay
/>
)}
</Field>
<Field
name="password"
validate={composeValidators(required, verifyPassword)}
>
{({ input, meta }) => (
<InputField
label={t('talk-plugin-local-auth.add_email.insert_password')}
name={input.name}
onChange={input.onChange}
value={input.value}
errorMsg={meta.error}
showError={meta.touched}
type="password"
columnDisplay
/>
)}
</Field>
<Field name="confirmPassword" validate={confirmPassword('password')}>
{({ input, meta }) => (
<InputField
label={t('talk-plugin-local-auth.add_email.confirm_password')}
name={input.name}
onChange={input.onChange}
value={input.value}
errorMsg={meta.error}
showError={meta.touched}
type="password"
columnDisplay
/>
)}
</Field>
<div>
<button className={styles.button} disabled={submitting}>
{t('talk-plugin-local-auth.add_email.add_email_address')}
</button>
</div>
</form>
)}
</Form>
</div>
);
AddEmailContent.propTypes = {
onSubmit: PropTypes.func.isRequired,
};
export default AddEmailContent;
@@ -0,0 +1,11 @@
.root {
border: none;
box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2);
width: 320px;
top: 50%;
transform: translateY(-50%);
padding: 20px;
border-radius: 4px;
font-family: Helvetica,Helvetica Neue,Verdana,sans-serif;
color:#3B4A53;
}
@@ -0,0 +1,5 @@
import React from 'react';
import { Dialog } from 'plugin-api/beta/client/components/ui';
import styles from './Dialog.css';
export default props => <Dialog className={styles.root} {...props} />;
@@ -0,0 +1,29 @@
.title {
font-size: 1.3em;
margin: 15px 0;
text-align: center;
}
.description {
font-size: 1em;
line-height: 20px;
margin: 0;
margin-bottom: 15px;
}
.button {
color: #787D80;
border-radius: 2px;
height: 30px;
font-size: 0.9em;
width: 100%;
display: inline-block;
text-align: center;
font-size: 1em;
background-color: #3498DB;
color: white;
&:hover {
cursor: pointer;
}
}
@@ -1,10 +1,9 @@
import React from 'react';
import cn from 'classnames';
import PropTypes from 'prop-types';
import styles from './AddEmailAddressDialog.css';
import styles from './EmailAddressAdded.css';
import { t } from 'plugin-api/beta/client/services';
const EmailAddressAdded = ({ done }) => (
const EmailAddressAdded = ({ onDone }) => (
<div>
<h4 className={styles.title}>
{t('talk-plugin-local-auth.add_email.added.title')}
@@ -17,16 +16,16 @@ const EmailAddressAdded = ({ done }) => (
{t('talk-plugin-local-auth.add_email.added.description_2')}{' '}
<strong>{t('talk-plugin-local-auth.add_email.added.path')}</strong>.
</p>
<div className={styles.actions}>
<a className={cn(styles.button, styles.proceed)} onClick={done}>
<div>
<button className={styles.button} onClick={onDone}>
{t('talk-plugin-local-auth.add_email.done')}
</a>
</button>
</div>
</div>
);
EmailAddressAdded.propTypes = {
done: PropTypes.func.isRequired,
onDone: PropTypes.func.isRequired,
};
export default EmailAddressAdded;
@@ -0,0 +1,29 @@
.title {
font-size: 1.3em;
margin: 15px 0;
text-align: center;
}
.description {
font-size: 1em;
line-height: 20px;
margin: 0;
margin-bottom: 15px;
}
.button {
color: #787D80;
border-radius: 2px;
height: 30px;
font-size: 0.9em;
width: 100%;
display: inline-block;
text-align: center;
font-size: 1em;
background-color: #3498DB;
color: white;
&:hover {
cursor: pointer;
}
}
@@ -1,10 +1,9 @@
import React from 'react';
import cn from 'classnames';
import PropTypes from 'prop-types';
import styles from './AddEmailAddressDialog.css';
import styles from './VerifyEmailAddress.css';
import { t } from 'plugin-api/beta/client/services';
const VerifyEmailAddress = ({ emailAddress, done }) => (
const VerifyEmailAddress = ({ emailAddress, onDone }) => (
<div>
<h4 className={styles.title}>
{t('talk-plugin-local-auth.add_email.verify.title')}
@@ -12,17 +11,17 @@ const VerifyEmailAddress = ({ emailAddress, done }) => (
<p className={styles.description}>
{t('talk-plugin-local-auth.add_email.verify.description', emailAddress)}
</p>
<div className={styles.actions}>
<a className={cn(styles.button, styles.proceed)} onClick={done}>
<div>
<button className={styles.button} onClick={onDone}>
{t('talk-plugin-local-auth.add_email.done')}
</a>
</button>
</div>
</div>
);
VerifyEmailAddress.propTypes = {
emailAddress: PropTypes.string.isRequired,
done: PropTypes.func.isRequired,
onDone: PropTypes.func.isRequired,
};
export default VerifyEmailAddress;
@@ -0,0 +1,4 @@
export { default as AddEmailForm } from './AddEmailForm';
export { default as Dialog } from './Dialog';
export { default as EmailAddressAdded } from './EmailAddressAdded';
export { default as VerifyEmailAddress } from './VerifyEmailAddress';
@@ -1,166 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Dialog } from 'plugin-api/beta/client/components/ui';
import validate from 'coral-framework/helpers/validate';
import { getErrorMessages } from 'coral-framework/utils';
import styles from './AddEmailAddressDialog.css';
import { t } from 'plugin-api/beta/client/services';
import AddEmailContent from './AddEmailContent';
import VerifyEmailAddress from './VerifyEmailAddress';
import EmailAddressAdded from './EmailAddressAdded';
const initialState = {
step: 0,
showErrors: false,
errors: {},
formData: {
emailAddress: '',
confirmPassword: '',
confirmEmailAddress: '',
},
};
const validateRequired = v =>
v ? '' : t('talk-plugin-local-auth.add_email.required_field');
const validateRepeat = (key, msg) => (v, data) => (v !== data[key] ? msg : '');
const validateEmail = v =>
validateRequired(v) || !validate.email(v)
? t('talk-plugin-local-auth.add_email.invalid_email_address')
: '';
const validatePassword = v => validateRequired(v);
class AddEmailAddressDialog extends React.Component {
state = initialState;
fields = {
emailAddress: validateEmail,
confirmPassword: validatePassword,
confirmEmailAddress: validateRepeat(
'emailAddress',
t('talk-plugin-local-auth.add_email.confirm_email_address')
),
};
onChange = e => {
const { name, value } = e.target;
this.setState(
state => ({
formData: {
...state.formData,
[name]: value,
},
}),
() => {
this.validate();
}
);
};
validateField = (value, name) => {
const error = this.fields[name](value, this.state.formData);
if (error) {
this.addError({ [name]: error });
return false;
}
this.removeError(name);
return true;
};
addError = err => {
this.setState(({ errors }) => ({
errors: { ...errors, ...err },
}));
};
validate() {
let hasErrors = false;
Object.keys(this.state.formData).forEach(k => {
hasErrors = !this.validateField(this.state.formData[k], k) || hasErrors;
});
return !hasErrors;
}
removeError = errKey => {
this.setState(state => {
const { [errKey]: _, ...errors } = state.errors;
return {
errors,
};
});
};
showErrors = () => {
this.setState({
showErrors: true,
});
};
confirmChanges = async () => {
if (!this.validate()) {
this.showErrors();
return;
}
const { emailAddress, confirmPassword } = this.state.formData;
const { attachLocalAuth } = this.props;
try {
await attachLocalAuth({
email: emailAddress,
password: confirmPassword,
});
this.props.notify('success', 'Email Added!');
this.goToNextStep();
} catch (err) {
this.props.notify('error', getErrorMessages(err));
}
};
goToNextStep = () => {
this.setState(({ step }) => ({
step: step + 1,
}));
};
render() {
const { errors, formData, showErrors, step } = this.state;
const { root: { settings } } = this.props;
return (
<Dialog className={styles.dialog} open={true}>
{step === 0 && (
<AddEmailContent
formData={formData}
errors={errors}
showErrors={showErrors}
confirmChanges={this.confirmChanges}
onChange={this.onChange}
/>
)}
{step === 1 &&
!settings.requireEmailConfirmation && (
<EmailAddressAdded done={() => {}} />
)}
{step === 1 &&
settings.requireEmailConfirmation && (
<VerifyEmailAddress
emailAddress={formData.emailAddress}
done={() => {}}
/>
)}
</Dialog>
);
}
}
AddEmailAddressDialog.propTypes = {
attachLocalAuth: PropTypes.func.isRequired,
notify: PropTypes.func.isRequired,
root: PropTypes.object.isRequired,
};
export default AddEmailAddressDialog;
@@ -1,104 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './AddEmailAddressDialog.css';
import { Icon } from 'plugin-api/beta/client/components/ui';
import cn from 'classnames';
import InputField from './InputField';
import { t } from 'plugin-api/beta/client/services';
const AddEmailContent = ({
formData,
errors,
showErrors,
confirmChanges,
onChange,
}) => (
<div>
<h4 className={styles.title}>
{t('talk-plugin-local-auth.add_email.content.title')}
</h4>
<p className={styles.description}>
{t('talk-plugin-local-auth.add_email.content.description')}
</p>
<ul className={styles.list}>
<li className={styles.item}>
<Icon name="done" className={styles.itemIcon} />
<span className={styles.text}>
{t('talk-plugin-local-auth.add_email.content.item_1')}
</span>
</li>
<li className={styles.item}>
<Icon name="done" className={styles.itemIcon} />
<span className={styles.text}>
{t('talk-plugin-local-auth.add_email.content.item_2')}
</span>
</li>
<li className={styles.item}>
<Icon name="done" className={styles.itemIcon} />
<span className={styles.text}>
{t('talk-plugin-local-auth.add_email.content.item_3')}
</span>
</li>
</ul>
<form autoComplete="off">
<InputField
id="emailAddress"
label={t('talk-plugin-local-auth.add_email.enter_email_address')}
name="emailAddress"
type="email"
onChange={onChange}
value={formData.emailAddress}
hasError={!!errors.emailAddress}
errorMsg={errors.emailAddress}
showError={showErrors}
columnDisplay
showSuccess={false}
/>
<InputField
id="confirmEmailAddress"
label={t('talk-plugin-local-auth.add_email.confirm_email_address')}
name="confirmEmailAddress"
type="email"
onChange={onChange}
value={formData.confirmEmailAddress}
hasError={!!errors.confirmEmailAddress}
errorMsg={errors.confirmEmailAddress}
showError={showErrors}
columnDisplay
showSuccess={false}
/>
<InputField
id="confirmPassword"
label={t('talk-plugin-local-auth.add_email.insert_password')}
name="confirmPassword"
type="password"
onChange={onChange}
value={formData.confirmPassword}
hasError={!!errors.confirmPassword}
errorMsg={errors.confirmPassword}
showError={showErrors}
columnDisplay
showSuccess={false}
/>
<div className={styles.actions}>
<a
className={cn(styles.button, styles.proceed)}
onClick={confirmChanges}
>
{t('talk-plugin-local-auth.add_email.add_email_address')}
</a>
</div>
</form>
</div>
);
AddEmailContent.propTypes = {
formData: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired,
showErrors: PropTypes.bool.isRequired,
confirmChanges: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
};
export default AddEmailContent;
@@ -4,10 +4,74 @@ import styles from './ChangeEmailContentDialog.css';
import InputField from './InputField';
import { Button } from 'plugin-api/beta/client/components/ui';
import { t } from 'plugin-api/beta/client/services';
import validate from 'coral-framework/helpers/validate';
import errorMsj from 'coral-framework/helpers/error';
const initialState = {
showError: false,
formData: {
confirmPassword: '',
},
errors: {},
};
class ChangeEmailContentDialog extends React.Component {
state = {
showError: false,
state = initialState;
clearForm = () => {
this.setState(initialState);
};
addError = err => {
this.setState(({ errors }) => ({
errors: { ...errors, ...err },
}));
};
removeError = errKey => {
this.setState(state => {
const { [errKey]: _, ...errors } = state.errors;
return {
errors,
};
});
};
fieldValidation = (value, type, name) => {
if (!value.length) {
this.addError({
[name]: t('talk-plugin-local-auth.change_password.required_field'),
});
} else if (!validate[type](value)) {
this.addError({ [name]: errorMsj[type] });
} else {
this.removeError(name);
}
};
onChange = e => {
const { name, value, type, dataset } = e.target;
const validationType = dataset.validationType || type;
this.setState(
state => ({
formData: {
...state.formData,
[name]: value,
},
}),
() => {
this.fieldValidation(value, validationType, name);
}
);
};
hasError = err => {
return Object.keys(this.state.errors).indexOf(err) !== -1;
};
getError = errorKey => {
return this.state.errors[errorKey];
};
showError = () => {
@@ -16,24 +80,31 @@ class ChangeEmailContentDialog extends React.Component {
});
};
cancel = () => {
this.clearForm();
this.props.closeDialog();
};
confirmChanges = async e => {
e.preventDefault();
const { confirmPassword = '' } = this.state.formData;
if (this.formHasError()) {
this.showError();
return;
}
await this.props.save();
await this.props.save(confirmPassword);
this.props.next();
};
formHasError = () => this.props.hasError('confirmPassword');
formHasError = () => this.hasError('confirmPassword');
render() {
return (
<div>
<span className={styles.close} onClick={this.props.cancel}>
<span className={styles.close} onClick={this.cancel}>
×
</span>
<h1 className={styles.title}>
@@ -59,17 +130,17 @@ class ChangeEmailContentDialog extends React.Component {
label={t('talk-plugin-local-auth.change_email.enter_password')}
name="confirmPassword"
type="password"
onChange={this.props.onChange}
defaultValue=""
hasError={this.props.hasError('confirmPassword')}
errorMsg={this.props.getError('confirmPassword')}
onChange={this.onChange}
value={this.state.formData.confirmPassword}
hasError={this.hasError('confirmPassword')}
errorMsg={this.getError('confirmPassword')}
showError={this.state.showError}
columnDisplay
/>
<div className={styles.bottomActions}>
<Button
className={styles.cancel}
onClick={this.props.cancel}
onClick={this.cancel}
type="button"
>
{t('talk-plugin-local-auth.change_email.cancel')}
@@ -86,14 +157,11 @@ class ChangeEmailContentDialog extends React.Component {
}
ChangeEmailContentDialog.propTypes = {
save: PropTypes.func,
next: PropTypes.func,
cancel: PropTypes.func,
onChange: PropTypes.func,
save: PropTypes.func,
formData: PropTypes.object,
email: PropTypes.string,
hasError: PropTypes.func,
getError: PropTypes.func,
closeDialog: PropTypes.func,
};
export default ChangeEmailContentDialog;
@@ -135,7 +135,11 @@ class ChangePassword extends React.Component {
};
onForgotPassword = async () => {
const { root: { me: { email } } } = this.props;
const {
root: {
me: { email },
},
} = this.props;
try {
await this.props.forgotPassword(email);
@@ -185,7 +189,7 @@ class ChangePassword extends React.Component {
>
<InputField
id="oldPassword"
label="Old Password"
label={t('talk-plugin-local-auth.change_password.old_password')}
name="oldPassword"
type="password"
onChange={this.onChange}
@@ -205,7 +209,7 @@ class ChangePassword extends React.Component {
</InputField>
<InputField
id="newPassword"
label="New Password"
label={t('talk-plugin-local-auth.change_password.new_password')}
name="newPassword"
type="password"
onChange={this.onChange}
@@ -216,7 +220,9 @@ class ChangePassword extends React.Component {
/>
<InputField
id="confirmNewPassword"
label="Confirm New Password"
label={t(
'talk-plugin-local-auth.change_password.confirm_new_password'
)}
name="confirmNewPassword"
type="password"
onChange={this.onChange}
@@ -65,7 +65,7 @@ class ChangeUsernameContentDialog extends React.Component {
<form onSubmit={this.confirmChanges}>
<InputField
id="confirmNewUsername"
label="Re-enter new username"
label={t('talk-plugin-local-auth.change_username.re_enter')}
name="confirmNewUsername"
type="text"
onChange={this.props.onChange}
@@ -4,6 +4,7 @@ import cn from 'classnames';
import styles from './InputField.css';
import ErrorMessage from './ErrorMessage';
import { Icon } from 'plugin-api/beta/client/components/ui';
import uuid from 'uuid/v4';
const InputField = ({
id = '',
@@ -12,7 +13,6 @@ const InputField = ({
name = '',
onChange = () => {},
showError = true,
hasError = false,
errorMsg = '',
children,
columnDisplay = false,
@@ -27,12 +27,13 @@ const InputField = ({
...(value !== undefined ? { value } : {}),
...(defaultValue !== undefined ? { defaultValue } : {}),
};
const computedId = id || (label && uuid());
return (
<div className={styles.detailItem}>
<div className={cn(styles.detailItemContainer)}>
{label && (
<label className={styles.detailLabel} id={id}>
<label className={styles.detailLabel} id={computedId}>
{label}
</label>
)}
@@ -44,13 +45,13 @@ const InputField = ({
<div
className={cn(
styles.detailInput,
{ [styles.error]: hasError && showError },
{ [styles.error]: errorMsg && showError },
{ [styles.disabled]: disabled }
)}
>
{icon && <Icon name={icon} className={styles.detailIcon} />}
<input
id={id}
id={computedId}
type={type}
name={name}
className={styles.detailValue}
@@ -62,12 +63,12 @@ const InputField = ({
/>
</div>
<div className={styles.detailItemMessage}>
{!hasError &&
{!errorMsg &&
showSuccess &&
value && (
<Icon className={styles.checkIcon} name="check_circle" />
)}
{hasError && showError && <ErrorMessage>{errorMsg}</ErrorMessage>}
{errorMsg && showError && <ErrorMessage>{errorMsg}</ErrorMessage>}
</div>
</div>
</div>
@@ -87,7 +88,6 @@ InputField.propTypes = {
defaultValue: PropTypes.string,
icon: PropTypes.string,
showError: PropTypes.bool,
hasError: PropTypes.bool,
errorMsg: PropTypes.string,
children: PropTypes.node,
columnDisplay: PropTypes.bool,
@@ -0,0 +1,4 @@
import * as React from 'react';
const Label = props => <div {...props} />;
export default Label;
@@ -114,7 +114,11 @@ class Profile extends React.Component {
isSaveEnabled = () => {
const { formData } = this.state;
const { root: { me: { username, email } } } = this.props;
const {
root: {
me: { username, email },
},
} = this.props;
const formHasErrors = !!Object.keys(this.state.errors).length;
const validUsername =
formData.newUsername && formData.newUsername !== username;
@@ -138,8 +142,8 @@ class Profile extends React.Component {
}
};
saveEmail = async () => {
const { newEmail, confirmPassword } = this.state.formData;
saveEmail = async confirmPassword => {
const { newEmail } = this.state.formData;
try {
await this.props.updateEmailAddress({
@@ -166,12 +170,20 @@ class Profile extends React.Component {
render() {
const {
root: { me: { username, email, state: { status } } },
root: {
me: {
username,
email,
state: { status },
},
},
notify,
success: hasChangedUsername,
} = this.props;
const { editing, formData, showDialog } = this.state;
const usernameCanBeUpdated = canUsernameBeUpdated(status);
const usernameCanBeUpdated =
canUsernameBeUpdated(status) && !hasChangedUsername;
return (
<section
@@ -202,12 +214,10 @@ class Profile extends React.Component {
)}
<ChangeEmailContentDialog
save={this.saveEmail}
onChange={this.onChange}
formData={this.state.formData}
email={email}
enable={formData.newEmail && email !== formData.newEmail}
hasError={this.hasError}
getError={this.getError}
closeDialog={this.closeDialog}
/>
</ConfirmChangesDialog>
@@ -224,12 +234,23 @@ class Profile extends React.Component {
validationType="username"
disabled={!usernameCanBeUpdated}
columnDisplay
errorMsg={this.state.errors.newUsername}
>
<span className={styles.bottomText}>
{t(
'talk-plugin-local-auth.change_username.change_username_note'
<div className={styles.bottomText}>
<span>
{t(
'talk-plugin-local-auth.change_username.change_username_note'
)}
</span>
{!usernameCanBeUpdated && (
<b>
{' '}
{t(
'talk-plugin-local-auth.change_username.is_not_eligible'
)}
</b>
)}
</span>
</div>
</InputField>
<InputField
icon="email"
@@ -289,6 +310,7 @@ Profile.propTypes = {
notify: PropTypes.func.isRequired,
username: PropTypes.string,
emailAddress: PropTypes.string,
success: PropTypes.bool.isRequired,
};
export default Profile;
@@ -0,0 +1,4 @@
const prefix = 'TALK_LOCAL_AUTH';
export const START_ATTACH = `${prefix}_START_ATTACH`;
export const FINISH_ATTACH = `${prefix}_FINISH_ATTACH`;
@@ -1,12 +1,106 @@
import React from 'react';
import PropTypes from 'prop-types';
import { compose, gql } from 'react-apollo';
import { bindActionCreators } from 'redux';
import { connect, withFragments, excludeIf } from 'plugin-api/beta/client/hocs';
import AddEmailAddressDialog from '../components/AddEmailAddressDialog';
import { notify } from 'coral-framework/actions/notification';
import { withAttachLocalAuth } from '../hocs';
import { startAttach, finishAttach } from '../actions';
import get from 'lodash/get';
import { getErrorMessages } from 'coral-framework/utils';
import { t } from 'plugin-api/beta/client/services';
import {
Dialog,
AddEmailForm,
VerifyEmailAddress,
EmailAddressAdded,
} from '../components/AddEmailAddress';
const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch);
class AddEmailAddressDialog extends React.Component {
state = {
step: 0,
};
componentDidMount() {
this.props.startAttach();
document.body.style.minHeight = `${
document.getElementById('talk-plugin-local-auth-email-dialog')
.clientHeight
}px`;
}
componentWillUnmount() {
document.body.style.removeProperty('min-height');
}
handleDone = () => {
this.props.finishAttach();
};
handleSubmit = async ({ email, password }) => {
const { attachLocalAuth } = this.props;
try {
await attachLocalAuth({
email,
password,
});
this.props.notify(
'success',
t('talk-plugin-local-auth.add_email.added.alert')
);
this.goToNextStep();
} catch (err) {
this.props.notify('error', getErrorMessages(err));
}
};
goToNextStep = () => {
this.setState(({ step }) => ({
step: step + 1,
}));
};
render() {
const { step } = this.state;
const {
root: {
me: { email },
settings: { requireEmailConfirmation },
},
} = this.props;
return (
<Dialog open={true} id="talk-plugin-local-auth-email-dialog">
{step === 0 && <AddEmailForm onSubmit={this.handleSubmit} />}
{step === 1 &&
!requireEmailConfirmation && (
<EmailAddressAdded onDone={this.handleDone} />
)}
{step === 1 &&
requireEmailConfirmation && (
<VerifyEmailAddress emailAddress={email} onDone={this.handleDone} />
)}
</Dialog>
);
}
}
AddEmailAddressDialog.propTypes = {
attachLocalAuth: PropTypes.func.isRequired,
notify: PropTypes.func.isRequired,
startAttach: PropTypes.func.isRequired,
finishAttach: PropTypes.func.isRequired,
root: PropTypes.object,
};
const mapStateToProps = ({ talkPluginLocalAuth: state }) => ({
inProgress: state.inProgress,
});
const mapDispatchToProps = dispatch =>
bindActionCreators({ notify, startAttach, finishAttach }, dispatch);
const withData = withFragments({
root: gql`
@@ -14,6 +108,13 @@ const withData = withFragments({
me {
id
email
state {
status {
username {
status
}
}
}
}
settings {
requireEmailConfirmation
@@ -23,8 +124,16 @@ const withData = withFragments({
});
export default compose(
connect(null, mapDispatchToProps),
connect(
mapStateToProps,
mapDispatchToProps
),
withAttachLocalAuth,
withData,
excludeIf(({ root: { me } }) => !me || me.email)
excludeIf(
({ root: { me }, inProgress }) =>
!me ||
get(me, 'state.status.username.status') === 'UNSET' ||
(me.email && !inProgress)
)
)(AddEmailAddressDialog);
@@ -21,7 +21,10 @@ const withData = withFragments({
});
export default compose(
connect(null, mapDispatchToProps),
connect(
null,
mapDispatchToProps
),
withChangePassword,
withForgotPassword,
withData
@@ -32,7 +32,10 @@ const withData = withFragments({
});
export default compose(
connect(null, mapDispatchToProps),
connect(
null,
mapDispatchToProps
),
withSetUsername,
withUpdateEmailAddress,
withData
@@ -1,10 +1,12 @@
import ChangePassword from './containers/ChangePassword';
import AddEmailAddressDialog from './containers/AddEmailAddressDialog';
import Profile from './containers/Profile';
import translations from './translations.yml';
import translations from '../translations.yml';
import graphql from './graphql';
import reducer from './reducer';
export default {
reducer,
translations,
slots: {
profileHeader: [Profile],
@@ -0,0 +1,20 @@
import * as actions from './constants';
const initialState = {
inProgress: false,
};
export default function reducer(state = initialState, action) {
switch (action.type) {
case actions.START_ATTACH:
return {
inProgress: true,
};
case actions.FINISH_ATTACH:
return {
inProgress: false,
};
default:
return state;
}
}
@@ -1,87 +0,0 @@
en:
talk-plugin-local-auth:
change_password:
change_password: "Change Password"
passwords_dont_match: "Passwords don`t match"
required_field: "This field is required"
forgot_password: "Forgot your password?"
save: "Save"
cancel: "Cancel"
edit: "Edit"
changed_password_msg: "Changed Password - Your password has been successfully changed"
forgot_password_sent: "Forgot Password - We sent you an email to recover your password"
change_username:
change_username_note: "Usernames can only be changed once every 14 days. Your username is not currently eligible to be updated."
save: "Save"
edit_profile: "Edit Profile"
cancel: "Cancel"
confirm_username_change: "Confirm Username Change"
description: "You are attempting to change your username. Your new username will appear on all of your past and future comments."
old_username: "Old Username"
new_username: "New Username"
bottom_note: "Note: You will not be able to change your username again for 14 days"
confirm_changes: "Confirm Changes"
username_does_not_match: "Username does not match"
cant_be_equal: "Your new {0} must be different to your current one"
changed_username_success_msg: "Username Changed - Your username has been successfully changed. You will not be able to change your user name for 14 days."
change_username_attempt: "Username can't be updated. Usernames can only be changed every 14 days."
change_email:
confirm_email_change: "Confirm Email Address Change"
description: "You are attempting to change your email address. Your new email address will be used for your login and to receive account notifications."
old_email: "Old Email Address"
new_email: "New Email Address"
enter_password: "Enter Password"
incorrect_password: "Incorrect Password"
confirm_change: "Confirm Change"
cancel: "Cancel"
change_email_msg: "Email Address Changed - Your email address has been successfully changed. This email address will now be used for signing in and email notifications."
add_email:
add_email_address: "Add Email Address"
enter_email_address: "Enter Email Address:"
invalid_email_address: "Invalid Email address"
confirm_email_address: "Confirm Email Address:"
email_does_not_match: "Email Address does not match"
insert_password: "Insert Password:"
required_field: "This field is required"
done: "done"
content:
title: "Add an Email Address"
description: "For your added security, we require users to add an email address to their accounts. Your email address will be used to:"
item_1: "Receive updates regarding any changes to your account (email address, username, password, etc.)"
item_2: "Allow you to download your comments."
item_3: "Send comment notifications that you have chosen to receive."
verify:
title: "Verify Your Email Address"
description: "Weve sent an email to {0} to verify your account. You must verify your email address so that it can be used for account change confirmations and notifications."
added:
title: "Email Address Added"
description: "Your email address has been added to your account."
subtitle: "Need to change your email address?"
description_2: "You can change your account settings by visiting"
path: "My Profile > Settings"
es:
talk-plugin-local-auth:
change_password:
change_password: "Cambiar Contraseña"
passwords_dont_match: "Las contraseñas no coinciden"
required_field: "Este campo es requerido"
forgot_password: "Olvidaste tu contraseña?"
save: "Guardar"
cancel: "Cancelar"
edit: "Editar"
changed_password_msg: "Contraseña Actualizada - Tu contraseña ha sido exitosamente actualizada"
forgot_password_sent: "Contraseña Olvidada - Te enviamos un email para recuperar tu contraseña"
change_username:
change_username_note: "El usuario puede ser cambiado cada 14 días"
save: "Guardar"
edit_profile: "Editar Perfil"
cancel: "Cancelar"
confirm_username_change: "Confirmar Cambio de Usuario"
description: "Estás intentando cambiar tu usuario. Tu nuevo usuario aparecerá en todos tus pasados y futuros comentarios."
old_username: "Usuario viejo"
new_username: "Usuario nuevo"
bottom_note: "Nota: No podrás cambiar tu usuario por 14 días"
confirm_changes: "Confirmar Cambios"
username_does_not_match: "El usuario no coincide"
changed_username_success_msg: "Usuario Actualizado - Tu usuario ha sido exitosamente actualizado. No podrás cambiar el usuario por 14 días."
change_username_attempt: "El usuario no puede ser actualizado. Los usuarios pueden ser cambiados cada 14 días."
+1 -1
View File
@@ -4,7 +4,7 @@ const mutators = require('./server/mutators');
const path = require('path');
module.exports = {
translations: path.join(__dirname, 'server', 'translations.yml'),
translations: path.join(__dirname, 'translations.yml'),
typeDefs,
mutators,
resolvers,
@@ -18,7 +18,15 @@ async function updateUserEmailAddress(ctx, email, confirmPassword) {
const {
user,
loaders: { Settings },
connectors: { models: { User }, services: { Mailer, I18n, Users } },
connectors: {
models: { User },
services: {
Mailer,
I18n,
Users,
Utils: { getRedirectUri },
},
},
} = ctx;
// Ensure that the user has a local profile associated with their account.
@@ -27,7 +35,7 @@ async function updateUserEmailAddress(ctx, email, confirmPassword) {
}
// Ensure that the password provided matches what we have on file.
if (!await user.verifyPassword(confirmPassword)) {
if (!(await user.verifyPassword(confirmPassword))) {
throw new ErrIncorrectPassword();
}
@@ -74,14 +82,26 @@ async function updateUserEmailAddress(ctx, email, confirmPassword) {
subject: I18n.t('email.email_change_original.subject'),
});
// Try to get the root parent, and their redirect uri.
const redirectUri = getRedirectUri(ctx.rootParent);
// Send off the email to the new email address that we need to verify the new
// address.
await Users.sendEmailConfirmation(user, email);
await Users.sendEmailConfirmation(user, email, redirectUri);
}
// attachUserLocalAuth will attach a new local profile to an existing user.
async function attachUserLocalAuth(ctx, email, password) {
const { user, connectors: { models: { User }, services: { Users } } } = ctx;
const {
user,
connectors: {
models: { User },
services: {
Users,
Utils: { getRedirectUri },
},
},
} = ctx;
// Ensure that the current user doesn't already have a local account
// associated with them.
@@ -132,9 +152,12 @@ async function attachUserLocalAuth(ctx, email, password) {
throw new Error('local auth attachment failed due to unexpected reason');
}
// Try to get the root parent, and their redirect uri.
const redirectUri = getRedirectUri(ctx.rootParent);
// Send off the email to the new email address that we need to verify the
// new address.
await Users.sendEmailConfirmation(updatedUser, email);
await Users.sendEmailConfirmation(updatedUser, email, redirectUri);
} catch (err) {
if (err.code === 11000) {
throw new ErrEmailTaken();
@@ -1,9 +0,0 @@
en:
email:
email_change_original:
subject: Email change
body: Your email address has been changed from {0} to {1}. If you did not initiate this change, please contact {2}. # TODO: update translation
error:
NO_LOCAL_PROFILE: No existing email address is associated with this account.
LOCAL_PROFILE: An email address is already associated with this account.
INCORRECT_PASSWORD: Provided password was incorrect.
@@ -0,0 +1,454 @@
ar:
email:
email_change_original:
subject: تغيير البريد الإلكتروني
body: تم تغيير عنوان بريدك الإلكتروني من {0} إلى {1}. إذا لم تطلب هذا التغيير ، فيرجى الاتصال {2}.
error:
NO_LOCAL_PROFILE: لا يوجد عنوان بريد إلكتروني حالي مقترن بهذا الحساب.
LOCAL_PROFILE: هناك بريد إلكتروني مرتبط بهذا الحساب.
INCORRECT_PASSWORD: كلمة المرور المقدمة غير صحيحة.
talk-plugin-local-auth:
change_password:
change_password: "تغيير كلمة المرور"
passwords_dont_match: "كلمات المرور لا تتطابق"
required_field: "هذه الخانة مطلوبه"
forgot_password: "نسيت كلمة المرور؟"
old_password: "كلمة المرور القديمة"
new_password: "كلمة المرور الجديدة"
confirm_new_password: "تأكيد كلمة المرور الجديدة"
save: "حفظ"
cancel: "إلغاء"
edit: "تعديل"
changed_password_msg: "تغيير كلمة المرور - تم تغيير كلمة المرور الخاصة بك بنجاح"
forgot_password_sent: "نسيت كلمة المرور - لقد أرسلنا إليك رسالة بريد إلكتروني لاسترداد كلمة المرور الخاصة بك"
change_username:
change_username_note: "لا يمكن تغيير أسماء المستخدمين إلا مرة واحدة كل 14 يومًا."
is_not_eligible: "لا يمكنك حاليا تغيير اسم المستخدم الخاص بك."
save: "حفظ"
edit_profile: "تعديل الملف الشخصي"
cancel: "إلغاء"
confirm_username_change: "تأكيد تغيير اسم المستخدم"
description: "أنت تحاول تغيير اسم المستخدم الخاص بك. سوف يظهر اسم المستخدم الجديد الخاص بك على جميع تعليقاتك الماضية والتعليقات المستقبلية."
old_username: "اسم المستخدم القديم"
new_username: "اسم المستخدم الجديد"
re_enter: "أعد إدخال اسم مستخدم جديد"
bottom_note: "ملاحظة: لن تتمكن من تغيير اسم المستخدم الخاص بك مرة أخرى لمدة 14 يومًا"
confirm_changes: "تأكيد التغييرات"
username_does_not_match: "اسم المستخدم غير متطابق"
cant_be_equal: "يجب أن يكون {0} الجديد الخاص بك مختلفًا عن الحالي"
changed_username_success_msg: "اسم المستخدم تم تغييره - تم تغيير اسم المستخدم الخاص بك بنجاح. لن تتمكن من تغيير اسم المستخدم الخاص بك لمدة 14 يومًا."
change_username_attempt: "لا يمكن تحديث اسم المستخدم. لا يمكن تغيير أسماء المستخدمين إلا كل 14 يومًا."
change_email:
confirm_email_change: "تأكيد تغيير عنوان البريد الإلكتروني"
description: "أنت تحاول تغيير عنوان بريدك الإلكتروني. سيتم استخدام عنوان بريدك الإلكتروني الجديد لتسجيل الدخول ولتلقي إشعارات الحساب."
old_email: "عنوان البريد الإلكتروني القديم"
new_email: "عنوان البريد الإلكتروني الجديد"
enter_password: "أدخل كلمة المرور"
incorrect_password: "كلمة مرور خاطئة"
confirm_change: "تأكيد التغيير"
cancel: "إلغاء"
change_email_msg: "تم تغيير عنوان البريد الإلكتروني. سيتم استخدام عنوان البريد الإلكتروني هذا الآن لتسجيل الدخول ولإشعارات البريد الإلكتروني."
add_email:
add_email_address: "إضافة البريد الإلكتروني"
enter_email_address: "أدخل البريد الالكتروني:"
invalid_email_address: "البريد الإلكتروني غير صالح"
confirm_email_address: "أكد عنوان بريدك الإلكتروني:"
email_does_not_match: "عنوان البريد الإلكتروني غير مطابق"
insert_password: "إدخال كلمة المرور:"
confirm_password: "تأكيد كلمة المرور:"
required_field: "هذه الخانة مطلوبه"
done: "تم"
content:
title: "أضف عنوان بريد إلكتروني"
description: "لمزيد من الأمان ، نطلب من المستخدمين إضافة عنوان بريد إلكتروني إلى حساباتهم. سيتم استخدام عنوان بريدك الإلكتروني في:"
item_1: "تلقي التحديثات المتعلقة بأي تغييرات في حسابك (عنوان البريد الإلكتروني ، اسم المستخدم ، كلمة المرور ، إلخ.)"
item_2: "السماح لك بتنزيل تعليقاتك."
item_3: "إرسال إشعارات التعليقات التي اخترت استلامها."
verify:
title: "تحقق من عنوان البريد الإلكتروني الخاص بك"
description: "لقد أرسلنا رسالة إلكترونية إلى {0} لإثبات ملكية حسابك. يجب عليك التحقق من عنوان بريدك الإلكتروني حتى يمكن استخدامه لتأكيد تعديلات الحساب والإشعارات."
added:
title: "تمت إضافة عنوان البريد الالكتروني"
description: "تمت إضافة عنوان بريدك الإلكتروني إلى حسابك."
subtitle: "هل تحتاج إلى تغيير عنوان بريدك الإلكتروني؟"
description_2: "يمكنك تغيير إعدادات حسابك من خلال زيارة"
path: "ملفي > الإعدادات"
alert: "تمت إضافة البريد الإلكتروني!"
en:
email:
email_change_original:
subject: Email change
body: Your email address has been changed from {0} to {1}. If you did not request this change, please contact {2}.
error:
NO_LOCAL_PROFILE: No existing email address is associated with this account.
LOCAL_PROFILE: An email address is already associated with this account.
INCORRECT_PASSWORD: Provided password was incorrect.
talk-plugin-local-auth:
change_password:
change_password: "Change Password"
passwords_dont_match: "Passwords don`t match"
required_field: "This field is required"
forgot_password: "Forgot your password?"
old_password: "Old Password"
new_password: "New Password"
confirm_new_password: "Confirm New Password"
save: "Save"
cancel: "Cancel"
edit: "Edit"
changed_password_msg: "Changed Password - Your password has been successfully changed"
forgot_password_sent: "Forgot Password - We sent you an email to recover your password"
change_username:
change_username_note: "Usernames can only be changed once every 14 days."
is_not_eligible: "You cannot currently change your username."
save: "Save"
edit_profile: "Edit Profile"
cancel: "Cancel"
confirm_username_change: "Confirm Username Change"
description: "You are attempting to change your username. Your new username will appear on all of your past and future comments."
old_username: "Old Username"
new_username: "New Username"
re_enter: "Re-enter new username"
bottom_note: "Note: You will not be able to change your username again for 14 days"
confirm_changes: "Confirm Changes"
username_does_not_match: "Username does not match"
cant_be_equal: "Your new {0} must be different to your current one"
changed_username_success_msg: "Username Changed - Your username has been successfully changed. You will not be able to change your user name for 14 days."
change_username_attempt: "Username can't be updated. Usernames can only be changed every 14 days."
change_email:
confirm_email_change: "Confirm Email Address Change"
description: "You are attempting to change your email address. Your new email address will be used for your login and to receive account notifications."
old_email: "Old Email Address"
new_email: "New Email Address"
enter_password: "Enter Password"
incorrect_password: "Incorrect Password"
confirm_change: "Confirm Change"
cancel: "Cancel"
change_email_msg: "Email Address Changed. This email address will now be used for signing in and email notifications."
add_email:
add_email_address: "Add Email Address"
enter_email_address: "Enter Email Address:"
invalid_email_address: "Invalid Email address"
confirm_email_address: "Confirm Email Address:"
email_does_not_match: "Email Address does not match"
insert_password: "Insert Password:"
confirm_password: "Confirm Password:"
required_field: "This field is required"
done: "Done"
content:
title: "Add an Email Address"
description: "For your added security, we require users to add an email address to their accounts. Your email address will be used to:"
item_1: "Receive updates regarding any changes to your account (email address, username, password, etc.)"
item_2: "Allow you to download your comments."
item_3: "Send comment notifications that you have chosen to receive."
verify:
title: "Verify Your Email Address"
description: "Weve sent an email to {0} to verify your account. You must verify your email address so that it can be used for account change confirmations and notifications."
added:
title: "Email Address Added"
description: "Your email address has been added to your account."
subtitle: "Need to change your email address?"
description_2: "You can change your account settings by visiting"
path: "My Profile > Settings"
alert: "Email Added!"
pt_BR:
email:
email_change_original:
subject: Mudança de email
body: Seu endereço de email foi alterado de {0} para {1}. Se você não solicitou essa alteração, por favor contate {2}.
error:
NO_LOCAL_PROFILE: Nenhum email existente está vinculado a essa conta.
LOCAL_PROFILE: Já existe um endereço de email associado a essa conta.
INCORRECT_PASSWORD: A senha informada está incorreta.
talk-plugin-local-auth:
change_password:
change_password: "Mudar senha"
passwords_dont_match: "Senhas não conferem"
required_field: "Esse campo é obrigatório"
forgot_password: "Esqueceu sua senha?"
old_password: "Senha antiga"
new_password: "Nova senha"
confirm_new_password: "Confirme a nova senha"
save: "Salvar"
cancel: "Cancelar"
edit: "Editar"
changed_password_msg: "Senha alterada - Sua senha foi alterada com sucesso"
forgot_password_sent: "Esqueceu a senha - Nós enviamos um email para recuperação da senha"
change_username:
change_username_note: "Nomes de usuários só podem ser alterados uma vez a cada 14 dias"
is_not_eligible: "Seu nome de usuário não pode ser alterado."
save: "Salvar"
edit_profile: "Editar perfil"
cancel: "Cancelar"
confirm_username_change: "Confirmar alteração do nome de usuário"
description: "Você está tentando alterar seu nome de usuário. Seu novo nome de usuário irá aparecer em todos os comentários antigos e novos."
old_username: "Nome de usuário antigo"
new_username: "Nome de usuário novo"
re_enter: "Repita o novo usuário"
bottom_note: "Atenção: Não será possível alterar seu nome de usuário por 14 dias"
confirm_changes: "Confirmar mudanças"
username_does_not_match: "Nome de usuário não confere"
cant_be_equal: "Seu novo {0} deve ser diferente do atual"
changed_username_success_msg: "Nome de usuário alterado - Nome de usuário alterado com sucesso. Não será possível alterar por 14 dias."
change_username_attempt: "Usuário não pode ser alterado. Nome de usuário só pode ser alterado a cada 14 dias."
change_email:
confirm_email_change: "Confirmar alteração de email"
description: "Você está tentando alterar seu endereço de email. Seu novo email será usado para entrar na plataforma e receber avisos da sua conta."
old_email: "Endereço de email antigo"
new_email: "Endereço de email novo"
enter_password: "Digite a senha"
incorrect_password: "Senha incorreta"
confirm_change: "Confirmar alteração"
cancel: "Cancelar"
change_email_msg: "Endereço de email alterado. este endereço de email será usado para entrar e receber notificações de email."
add_email:
add_email_address: "Adicionar endereço de email"
enter_email_address: "Entre com o endereço de email:"
invalid_email_address: "Email inválido"
confirm_email_address: "Confirmar endereço de email:"
email_does_not_match: "Endereço de email não confere"
insert_password: "Insira a senha:"
confirm_password: "Confirmar senha:"
required_field: "Esse campo é obrigatório"
done: "Feito"
content:
title: "Adicione um endereço de email"
description: "Para a sua segurança, exigimos que os usuários adicionem um endereço de email para suas contas. Seu email será usado para:"
item_1: "Receba avisos de alterações na sua conta(endereço de email, usuário, senha, etc.)"
item_2: "Permitir que você baixe seus comentários."
item_3: "Envie notificações de comentários que você escolheu receber."
verify:
title: "Verifique seu endereço de email"
description: "Enviamos um email para {0} para verificar sua conta. Ele pode ser usado para confirmar alterações na conta e notificações."
added:
title: "Endereço de email adicionado"
description: "Seu endereço de email foi adicionado na sua conta."
subtitle: "Precisa alterar seu endereço de email?"
description_2: "Você pode alterar as configurações da sua conta em"
path: "Meu Perfil > Configurações"
alert: "Email adicionado!"
de:
email:
email_change_original:
subject: Änderung Ihrer E-Mail-Adresse
body: Ihre E-Mail-Adresse wurde von {0} zu {1} geändert. Falls Sie diese Änderung nicht selbst vorgenommen haben, kontaktieren Sie bitte zur Sicherheit {2}.
error:
NO_LOCAL_PROFILE: Mit diesem Benutzerkonto ist keine E-Mail-Adresse verbunden.
LOCAL_PROFILE: Es ist bereits eine bestätigte E-Mail-Adresse mit diesem Benutzerkonto verbunden.
INCORRECT_PASSWORD: Das Passwort war nicht korrekt.
talk-plugin-local-auth:
change_password:
change_password: "Passwort ändern"
passwords_dont_match: "Die Passwörter stimmen nicht überein"
required_field: "Diese Angabe ist erforderlich"
forgot_password: "Passwort vergessen?"
old_password: "Altes Passwort"
new_password: "Neues Passwort"
confirm_new_password: "Neues Passwort bestätigen"
save: "Speichern"
cancel: "Abbrechen"
edit: "Ändern"
changed_password_msg: "Passwort geändert - Ihr Passwort wurde erfolgreich geändert"
forgot_password_sent: "Passwort vergessen - Wir haben Ihnen eine E-Mail zum Zurücksetzen des Passwortes geschickt"
change_username:
change_username_note: "Nutzernamen können nur alle 14 Tage geändert werden."
is_not_eligible: "Sie können Ihren Nutzernamen derzeit nicht ändern."
save: "Speichern"
edit_profile: "Profil ändern"
cancel: "Abbrechen"
confirm_username_change: "Änderung des Nutzernamens bestätigen"
description: "Sie möchten Ihren Nutzernamen ändern: der neue Nutzername wird an allen alten und neuen Kommentaren erscheinen."
old_username: "Alter Nutzername"
new_username: "Neuer Nutzername"
re_enter: "Neuen Nutzernamen bestätigen"
bottom_note: "Achtung: die nächste Änderung des Nutzernamens ist erst nach 14 Tagen möglich"
confirm_changes: "Änderung bestätigen"
username_does_not_match: "Die Nutzernamen stimmen nicht überein"
cant_be_equal: "Der neue Nutzername {0} muss sich vom alten unterscheiden."
changed_username_success_msg: "Nutzername geändert - Ihr Nutzername wurde erfolgreich aktualisiert. Die nächste Änderung des Nutzernamens ist erst nach 14 Tagen möglich."
change_username_attempt: "Der Nutzername kann zur Zeit nicht aktualisiert werden. Änderungen sind nur nach jeweils 14 Tagen möglich."
change_email:
confirm_email_change: "Änderung der E-Mail-Adresse bestätigen"
description: "Sie versuchen, Ihre E-Mail-Adresse ändern: die neue E-Mail-Adresse wird zum Login sowie für Benachrichtigungen bzgl. Ihres Benutzerkontos verwendet."
old_email: "Alte E-Mail-Adresse"
new_email: "Neue E-Mail-Adresse"
enter_password: "Passwort"
incorrect_password: "Passwort nicht korrekt"
confirm_change: "Änderung bestätigen"
cancel: "Abbrechen"
change_email_msg: "E-Mail-Adresse erfolgreich aktualisiert - die neue E-Mail-Adresse ab sofort zum Anmelden und für Benachrichtigungen verwendet."
add_email:
add_email_address: "E-Mail-Adresse hinzufügen"
enter_email_address: "E-Mail-Adresse:"
invalid_email_address: "Ungültige E-Mail-Adresse"
confirm_email_address: "Bestätigung der E-Mail-Adresse:"
email_does_not_match: "Die E-Mail-Adressen stimmen nicht überein"
insert_password: "Passwort auswählen:"
required_field: "Dieses Feld ist erforderlich"
done: "Fertig"
content:
title: "E-Mail-Adresse hinzufügen"
description: "Aus Sicherheitsgründen benötigen wir eine E-Mail-Adresse zu jedem Benutzerkonto. Ihre E-Mail-Adresse wird für folgendes verwendet:"
item_1: "Benachrichtigungen über Änderungen am Benutzerkonto (Nutzername, E-Mail-Adresse, Passwort)"
item_2: "Ermöglicht den Download des eigenen Kommentar-Archivs"
item_3: "Kommentar-Benachrichtigungen erhalten, die Sie explizit angefordert haben"
verify:
title: "E-Mail-Adresse bestätigen"
description: "Wir haben eine E-Mail an {0} geschickt. Bitte bestätigen Sie Ihre E-Mail-Adresse, um damit Benachrichtigungen über Änderungen am Benutzerkonto zu erhalten."
added:
title: "E-Mail-Adresse hinzugefügt"
description: "Ihre E-Mail-Adresse wurde dem Benutzerkonto hinzugefügt."
subtitle: "Sie möchten Ihre E-Mail-Adresse ändern?"
description_2: "Sie können Ihre Konto-Einstellugen ändern unter"
path: "Mein Profil > Profil-Einstellungen"
alert: "E-Mail-Adresse hinzugefügt!"
es:
email:
email_change_original:
subject: Cambio de correo electrónico
body: Su dirección de correo electrónico ha cambiado de {0} a {1}. Si no solicitó este cambio, póngase en contacto con {2}.
error:
NO_LOCAL_PROFILE: No hay una dirección de correo electrónico asociada a esta cuenta.
LOCAL_PROFILE: Una dirección de correo electrónico ya está asociada a esta cuenta.
INCORRECT_PASSWORD: La contraseña dada fue incorrecta.
talk-plugin-local-auth:
change_password:
save: "Salvar"
cancel: "Cancelar"
edit: "Editar"
changed_password_msg: "Contraseña cambiada - Su contraseña ha sido cambiado"
forgot_password_sent: "Contraseña olvidada - Enviamos un email para recuperar la contraseña"
change_password: "Cambiar Contraseña"
passwords_dont_match: "Las contraseñas no coinciden"
required_field: "Este campo es requerido"
forgot_password: "Olvidaste tu contraseña?"
old_password: "Contraseña anterior"
new_password: "Contraseña nueva"
confirm_new_password: "Confirme contraseña nueva"
change_username:
change_username_note: "El usuario puede ser cambiado cada 14 días."
is_not_eligible: "Ahora mismo no se puede cambiar su nombre de usuario."
save: "Guardar"
edit_profile: "Editar Perfil"
cancel: "Cancelar"
confirm_username_change: "Confirmar Cambio de Usuario"
description: "Estás intentando cambiar tu usuario. Tu nuevo usuario aparecerá en todos tus pasados y futuros comentarios."
old_username: "Usuario anterior"
new_username: "Usuario nuevo"
re_enter: "Escriba usuario nuevo otra vez"
bottom_note: "Nota: No podrás cambiar tu usuario por 14 días"
confirm_changes: "Confirmar Cambios"
username_does_not_match: "El usuario no coincide"
cant_be_equal: "Tu nuev@ {0} tiene que ser diferente"
changed_username_success_msg: "Usuario Actualizado - Tu usuario ha sido exitosamente actualizado. No podrás cambiar el usuario por 14 días."
change_username_attempt: "El usuario no puede ser actualizado. Los usuarios pueden ser cambiados cada 14 días."
change_email:
confirm_email_change: "Confirmar cambio de dirección de correo electrónico"
description: "Está intentando cambiar su dirección de correo electrónico. Su nueva dirección de correo electrónico se usará para iniciar sesión y recibir notificaciones de la cuenta."
new_email: "Nueva dirección de correo electrónico"
enter_password: "Introducir la contraseña"
incorrect_password: "Contraseña incorrecta"
confirm_change: "Confirmar cambio"
cancel: "Cancelar"
change_email_msg: "Dirección de correo electrónico modificada. Esta dirección de correo electrónico ahora se utilizará para iniciar sesión y notificaciones por correo electrónico."
add_email:
add_email_address: "Confirmar"
enter_email_address: "Introducir la dirección de correo electrónico:"
invalid_email_address: "Dirección de correo electrónico no válida"
confirm_email_address: "Confirmar el correo:"
email_does_not_match: "La dirección de Email no coincide"
insert_password: "Insertar contraseña:"
confirm_password: "Confirmar contraseña:"
required_field: "Este campo es requerido"
done: "Hecho"
content:
title: "Agregar una dirección de correo electrónico"
description: "Para su seguridad adicional, solicitamos a los usuarios que agreguen una dirección de correo electrónico a sus cuentas. Su dirección de correo electrónico se usará para:"
item_1: "Recibe actualizaciones sobre cualquier cambio en tu cuenta (dirección de correo electrónico, nombre de usuario, contraseña, etc.)"
item_2: "Permitir que descargues tus comentarios."
item_3: "Envía notificaciones de comentarios que hayas elegido recibir."
verify:
title: "Verificar su dirección de correo electrónico"
description: "Hemos enviado un correo electrónico a {0} para verificar su cuenta. Debe verificar su dirección de correo electrónico para que se pueda usar para notificaciones y notificaciones de cambio de cuenta."
added:
title: "Dirección de correo electrónico agregada"
description: "Su dirección de correo electrónico ha sido agregada a su cuenta."
subtitle: "¿Necesita cambiar su dirección de correo electrónico?"
description_2: "Puedes cambiar la configuración de tu cuenta visitando"
path: "Mi perfil > Configuración"
alert: "¡Correo electrónico agregado!"
nl_NL:
email:
email_change_original:
subject: E-mailadres wijziging
body: "Je e-mailadres is gewijzigd van {0} naar {1}. Als je deze wijziging niet hebt aangevraagd, neem dan s.v.p. contact op: {2}."
error:
NO_LOCAL_PROFILE: Er is geen bestaand e-mailadres geassocieerd met dit account.
LOCAL_PROFILE: Er is reeds een e-mailadres geassocieerd met dit account.
INCORRECT_PASSWORD: Het opgegeven wachtwoord is onjuist.
talk-plugin-local-auth:
change_password:
change_password: "Wachtwoord wijzigen"
passwords_dont_match: "Wachtwoorden komen niet overeen"
required_field: "Dit veld is verplicht"
forgot_password: "Wachtwoord vergeten?"
old_password: "Oud Wachtwoord"
new_password: "Nieuw Wachtwoord"
confirm_new_password: "Bevestig Nieuw Wachtwoord"
save: "Opslaan"
cancel: "Annuleren"
edit: "Wijzigen"
changed_password_msg: "Wachtwoord Gewijzigd - Je wachtwoord is succesvol gewijzigd"
forgot_password_sent: "Wachtwoord Vergeten - We hebben je een e-mail gestuurd om je wachtwoord te herstellen"
change_username:
change_username_note: "Gebruikersnamen kunnen eens per 14 dagen worden gewijzigd."
is_not_eligible: "Je kunt je gebruikersnaam momenteel niet wijzigen."
save: "Opslaan"
edit_profile: "Profiel wijzigen"
cancel: "Annuleren"
confirm_username_change: "Bevestig Gebruikersnaam Wijziging"
description: "Je probeert je gebruikersnaam te wijzigen. Je nieuwe gebruikersnaam zal verschijnen bij al je huidige en toekomstige reacties."
old_username: "Oude Gebruikersnaam"
new_username: "Nieuwe Gebruikersnaam"
re_enter: "Voer je nieuwe gebruikersnaam opnieuw in"
bottom_note: "Let op: Je kan je gebruikersnaam niet opnieuw wijzigen in de komende 14 dagen."
confirm_changes: "Bevestig Wijzigingen"
username_does_not_match: "Gebruikersnaam komt niet overeen"
cant_be_equal: "Je nieuwe {0} moet verschillen van je huidige"
changed_username_success_msg: "Gebruikersnaam Gewijzigd - Je gebruikersnaam is succesvol gewijzigd. Je kan je gebruikersnaam niet wijzigen voor de komende 14 dagen."
change_username_attempt: "Gebruikersnaam kan niet worden gewijzigd. Gebruikersnamen kunnen eens per 14 dagen worden gewijzigd."
change_email:
confirm_email_change: "Bevestig E-mailadres Wijziging"
description: "Je probeert je e-mailadres te wijzigen. Je nieuwe e-mailadres zal worden gebruikt om in te loggen en voor het ontvangen van account notificaties."
old_email: "Oude E-mailadres"
new_email: "Nieuwe E-mailadres"
enter_password: "Wachtwoord Invoeren"
incorrect_password: "Ongeldig Wachtwoord"
confirm_change: "Bevestig Wijziging"
cancel: "Annuleren"
change_email_msg: "E-mailadres Gewijzigd. Dit E-mailadres zal nu worden gebruikt om in te loggen en voor het ontvangen van account notificaties."
add_email:
add_email_address: "E-mailadres Toevoegen"
enter_email_address: "E-mailadres Invoeren:"
invalid_email_address: "Ongeldig E-mailadres"
confirm_email_address: "Bevestig E-mailadres:"
email_does_not_match: "E-mailadres komt niet overeen"
insert_password: "Wachtwoord Invoeren:"
confirm_password: "Wachtwoord Bevestigen:"
required_field: "Dit veld is verplicht"
done: "Klaar"
content:
title: "Voeg een e-mailadres toe"
description: "Voor je veiligheid vragen we gebruikers om een e-mailadres toe te voegen aan hun account. Je e-mailadres zal worden gebruikt om:"
item_1: "Updates te ontvangen omtrent wijzigingen in je account (e-mailadres, gebruikersnaam, wachtwoord, etc.)"
item_2: "Je reacties te kunnen downloaden."
item_3: "Reactie notificaties te sturen indien je hebt gekozen deze te ontvangen."
verify:
title: "Bevestig Je E-mailadres"
description: "We hebben een e-mail gestuurd aan {0} om je account te bevestigen. Je moet je e-mailadres verifiëren zodat deze gebruikt kan worden voor bevestigingen omtrent account wijzigingen en voor notificaties."
added:
title: "E-mailadres Toegevoegd"
description: "Je e-mailadres is toegevoegd aan je account."
subtitle: "Wil je je e-mailadres wijzigen?"
description_2: "Je kan je account instellingen wijzigen door te gaan naar"
path: "Mijn Profiel > Instellingen"
alert: "E-mailadres Toegevoegd!"
@@ -28,8 +28,8 @@ he:
loved: אהבתי
nl_NL:
talk-plugin-love:
love: Ik hou er van
loved: Geliefd
love: Love
loved: Loved
pt_BR:
talk-plugin-love:
love: Love
@@ -21,10 +21,10 @@ he:
member_since: "חבר מאז"
nl_NL:
talk-plugin-member-since:
member_since: "Gebruiker sinds"
member_since: "Lid sinds"
pt_BR:
talk-plugin-member-since:
member_since: "Member Since"
member_since: "Membro desde"
zh_CN:
talk-plugin-member-since:
member_since: "成员加入日期"
@@ -15,7 +15,10 @@ class BanUserActionContainer extends React.Component {
};
render() {
const { root: { me }, comment } = this.props;
const {
root: { me },
comment,
} = this.props;
return me.id !== comment.user.id ? (
<BanUserAction onBanUser={this.onBanUser} comment={this.props.comment} />
) : null;
@@ -30,6 +33,11 @@ const mapDispatchToProps = dispatch =>
dispatch
);
const enhance = compose(connect(null, mapDispatchToProps));
const enhance = compose(
connect(
null,
mapDispatchToProps
)
);
export default enhance(BanUserActionContainer);
@@ -70,7 +70,10 @@ const mapDispatchToProps = dispatch =>
);
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
connect(
mapStateToProps,
mapDispatchToProps
),
withSetCommentStatus,
withBanUser
);
@@ -68,7 +68,10 @@ const mapDispatchToProps = dispatch =>
);
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
connect(
mapStateToProps,
mapDispatchToProps
),
withFragments({
root: gql`
fragment TalkModerationActions_root on RootQuery {
@@ -96,16 +96,16 @@ nl_NL:
ban_user_dialog_headline: "Gebruiker verbannen?"
pt_BR:
talk-plugin-moderation-actions:
reject_comment: "Reject"
approve_comment: "Approve"
approved_comment: "Approved"
moderation_actions: "Moderation Actions"
ban_user: "Ban User"
ban_user_dialog_sub: "Are you sure you would like to ban this user?"
ban_user_dialog_copy: "Note: Banning this user will also place this comment in the Rejected queue."
ban_user_dialog_cancel: "Cancel"
ban_user_dialog_yes: "Yes. Ban user"
ban_user_dialog_headline: "Ban User?"
reject_comment: "Rejeitar"
approve_comment: "Aprovar"
approved_comment: "Aprovado"
moderation_actions: "Ações"
ban_user: "Banir Usuário"
ban_user_dialog_sub: "Tem certeza que deseja banir esse usuário?"
ban_user_dialog_copy: "Nota: Banindo esse usuário também irá colocar esse comentário na fila de Rejeitado."
ban_user_dialog_cancel: "Cancelar"
ban_user_dialog_yes: "Sim. Banir usuário"
ban_user_dialog_headline: "Banir usuário?"
zh_CN:
talk-plugin-moderation-actions:
reject_comment: "拒绝"
@@ -1,3 +1,12 @@
ar:
talk-plugin-notifications-category-featured:
toggle_description: تعليقي تم تمييزه
en:
talk-plugin-notifications-category-featured:
toggle_description: My comment is featured
es:
talk-plugin-notifications-category-featured:
toggle_description: Mi comentario esta presentado
de:
talk-plugin-notifications-category-featured:
toggle_description: Mein Kommentar wird empfohlen
@@ -1,6 +1,25 @@
ar:
talk-plugin-notifications:
categories:
featured:
subject: "تميَزت واحدة من تعليقاتك على {0}"
body: "{0}\n
حدد أحد أعضاء فريقنا هذا التعليق ليتم عرضه كتعليق مميز للقراء الآخرين: {1}"
en:
talk-plugin-notifications:
categories:
featured:
subject: "One of your comments was featured on {0}"
body: "{0}\nA member of our team has selected this comment to be featured for other readers: {1}"
body: "{0}\nA member of our team has selected this comment to be featured for other readers: {1}"
es:
talk-plugin-notifications:
categories:
featured:
subject: "Uno de tus comentarios apareció en {0}"
body: "{0}\nUn miembro de nuestro equipo ha seleccionado este comentario para ser presentado por otros lectores: {1}"
de:
talk-plugin-notifications:
categories:
featured:
subject: "Einer Ihrer Kommentare wurde auf {0} hervorgehoben"
body: "{0}\nEin Mitglied unseres Teams hat diesen Kommentar ausgewählt, er wird jetzt für andere Leser besonders hervorgehoben: {1}"
@@ -1,3 +1,15 @@
ar:
talk-plugin-notifications-category-reply:
toggle_description: يتلقى تعليقي ردا
en:
talk-plugin-notifications-category-reply:
toggle_description: My comment receives a reply
es:
talk-plugin-notifications-category-reply:
toggle_description: Mi comentario recibe una respuesta
de:
talk-plugin-notifications-category-reply:
toggle_description: Jemand antwortet auf meinen Kommentar
nl_NL:
talk-plugin-notifications-category-reply:
toggle_description: Iemand antwoord op mijn reactie
@@ -1,6 +1,25 @@
ar:
talk-plugin-notifications:
categories:
reply:
subject: "رد شخص ما على تعليقك على {0}"
body: "{0}\n{1} رد على تعليقك
{2}"
en:
talk-plugin-notifications:
categories:
reply:
subject: "Someone has replied to your comment on {0}"
body: "{0}\n{1} replied to your comment: {2}"
body: "{0}\n{1} replied to your comment: {2}"
es:
talk-plugin-notifications:
categories:
reply:
subject: "Alguien ha respondido a tu comentario en {0}"
body: "{0}\n{1} respondió a tu comentario: {2}"
de:
talk-plugin-notifications:
categories:
reply:
subject: "Jemand hat bei {0} auf Ihren Kommentar geantwortet"
body: "{0}\n{1} antwortete auf Ihren Kommentar: {2}"
@@ -1,3 +1,15 @@
ar:
talk-plugin-notifications-category-staff:
toggle_description: يرد أحد الموظفين على تعليقي
en:
talk-plugin-notifications-category-staff:
toggle_description: A staff member replies to my comment
es:
talk-plugin-notifications-category-staff:
toggle_description: Un miembro del personal responde a mi comentario
de:
talk-plugin-notifications-category-staff:
toggle_description: Ein Redaktionsmitglied antwortet auf meinen Kommentar
nl_NL:
talk-plugin-notifications-category-staff:
toggle_description: Een redactielid antwoord op mijn reactie
@@ -1,6 +1,31 @@
ar:
talk-plugin-notifications:
categories:
staff:
subject: "شخص ما في {0} قد رد على تعليقك"
body: "{0}\n{1} يعمل ل
{2} وقد رد على تعليقك: {3}"
en:
talk-plugin-notifications:
categories:
staff:
subject: "Someone at {0} has replied to your comment"
body: "{0}\n{1} works for {2} and has replied to your comment: {3}"
body: "{0}\n{1} works for {2} and has replied to your comment: {3}"
es:
talk-plugin-notifications:
categories:
staff:
subject: "Alguien en {0} ha respondido a tu comentario"
body: "{0}\n{1} trabaja para {2} y ha respondido a tu comentario: {3}"
de:
talk-plugin-notifications:
categories:
staff:
subject: "Jemand hat bei {0} auf Ihren Kommentar geantwortet"
body: "{0}\n{1} arbeitet für {2} und hat auf Ihren Kommentar geantwortet: {3}"
nl_NL:
talk-plugin-notifications:
categories:
staff:
subject: "Iemand bij {0} heeft geantwoord op je reactie"
body: "{0}\n{1} werkt voor {2} en heeft geantwoord op je reactie: {3}"
@@ -1,4 +1,20 @@
ar:
talk-plugin-notifications:
digest_enum:
DAILY: في ملخص يومي
en:
talk-plugin-notifications:
digest_enum:
DAILY: In a daily digest
es:
talk-plugin-notifications:
digest_enum:
DAILY: En un resumen diario
de:
talk-plugin-notifications:
digest_enum:
DAILY: Einmal täglich
nl_NL:
talk-plugin-notifications:
digest_enum:
DAILY: In een dagelijkse samenvatting
@@ -1,4 +1,20 @@
ar:
talk-plugin-notifications:
digest_enum:
HOURLY: في ملخص كل ساعة
en:
talk-plugin-notifications:
digest_enum:
HOURLY: In an hourly digest
es:
talk-plugin-notifications:
digest_enum:
HOURLY: En un resumen por hora
de:
talk-plugin-notifications:
digest_enum:
HOURLY: Stündlich
nl_NL:
talk-plugin-notifications:
digest_enum:
HOURLY: In een uurlijkse samenvatting
@@ -73,7 +73,11 @@ const withSettingsToggle = settingsName => {
mutations: {
UpdateNotificationSettings: ({
variables: { input },
state: { auth: { user: { id } } },
state: {
auth: {
user: { id },
},
},
}) => ({
update: proxy => {
if (input[settingsName] === undefined) {
@@ -13,7 +13,11 @@ export default {
mutations: {
UpdateNotificationSettings: ({
variables: { input },
state: { auth: { user: { id } } },
state: {
auth: {
user: { id },
},
},
}) => ({
optimisticResponse: {
updateNotificationSettings: {
@@ -1,3 +1,21 @@
ar:
talk-plugin-notifications:
settings_title: إشعارات
settings_subtitle: تلقي الإشعارات متى
turn_off_all: لا أريد تلقي الإشعارات
banner_info:
title: التحقق من البريد الإلكتروني مطلوب
text: لتلقي إشعارات البريد الإلكتروني ، يجب أن يكون لديك عنوان بريد إلكتروني تم التحقق منه.
verify_now: تحقق من بريدك الالكتروني الآن
banner_success:
title: تم إرسال التحقق عبر البريد الإلكتروني
text: تم إرسال رسالة إلكترونية إلى {0} يحتوي على رابط التحقق.
banner_error:
title: خطأ
text: حدث خطأ في إرسال رسالة التحقق الخاصة بك. الرجاء معاودة المحاولة في وقت لاحق.
digest_option: إرسال الإشعارات
digest_enum:
NONE: فورا
en:
talk-plugin-notifications:
settings_title: Notifications
@@ -16,3 +34,57 @@ en:
digest_option: Send notifications
digest_enum:
NONE: Immediately
es:
talk-plugin-notifications:
settings_title: Notificaciones
settings_subtitle: Reciba notificaciones cuando
turn_off_all: No quiero recibir notificaciones
banner_info:
title: Se requiere verificación de correo electrónico
text: Para recibir notificaciones por correo electrónico, debe tener una dirección de correo electrónico verificada.
verify_now: Verifica tu correo electrónico ahora.
banner_success:
title: Verificación del correo electrónico enviada
text: Se envió un correo electrónico a {0} que contiene un enlace de verificación.
banner_error:
title: Error
text: Ha habido un error al enviar su correo electrónico de verificación. Por favor, inténtelo de nuevo más tarde.
digest_option: Enviar notificaciones
digest_enum:
NONE: Inmediatamente
de:
talk-plugin-notifications:
settings_title: Benachrichtigungen
settings_subtitle: Benachrichtige mich wenn
turn_off_all: Ich möchte keine Benachrichtigungen erhalten
banner_info:
title: Bestätigte E-Mail-Adresse benötigt
text: Um E-Mail-Benachrichtigungen zu erhalten, müssen Sie eine bestätigte E-Mail-Adresse haben.
verify_now: E-Mail-Adresse jetzt bestätigen
banner_success:
title: E-Mail-Bestätigungsanfrage verschickt
text: Eine E-Mail mit einem Bestätigungslink wurde an {0} geschickt.
banner_error:
title: Fehler
text: Beim Versand der Bestätigungsmail gab es einen Fehler. Bitte versuchen Sie es später erneut.
digest_option: Benachrichtigungen senden
digest_enum:
NONE: Sofort
nl_NL:
talk-plugin-notifications:
settings_title: Notificaties
settings_subtitle: Ontvang notificaties wanneer
turn_off_all: Ik wil geen notificaties ontvangen
banner_info:
title: E-mail bevestiging vereist
text: Je moet een geverifieerd e-mailadres hebben om e-mail notificaties te ontvangen
verify_now: Verifieer je e-mailadres nu
banner_success:
title: E-mail verificatie verzonden
text: Een e-mail met verificatielink is verstuurd naar {0}.
banner_error:
title: Fout
text: Er is een fout opgetreden tijdens het versturen van je verificatie e-mail. Probeer het later nog eens.
digest_option: Notificaties versturen
digest_enum:
NONE: Onmiddelijk
@@ -116,7 +116,12 @@ class NotificationManager {
try {
// Pull out some useful tools.
const {
connectors: { models: { User }, services: { I18n: { t } } },
connectors: {
models: { User },
services: {
I18n: { t },
},
},
} = ctx;
const organizationName = await getOrganizationName(ctx);
@@ -6,7 +6,10 @@ const { map, reduce } = require('lodash');
module.exports = connectors => {
const {
graph: { subscriptions: { getBroker }, Context },
graph: {
subscriptions: { getBroker },
Context,
},
services: { Mailer, Plugins },
} = connectors;
@@ -37,7 +37,11 @@ const queueNotifications = async (ctx, userID, notifications) => {
);
// Pull out some useful tools.
const { connectors: { models: { User } } } = ctx;
const {
connectors: {
models: { User },
},
} = ctx;
ctx.log.info(
{ notifications: notifications.length, userID },
@@ -67,7 +71,13 @@ const sendNotificationsBatch = async (ctx, notifications) => {
map(
notifications,
async ({ handler, notification: { userID, context } }) => {
const { connectors: { services: { I18n: { t } } } } = ctx;
const {
connectors: {
services: {
I18n: { t },
},
},
} = ctx;
const { category } = handler;
// Compose the subject for the email.
@@ -181,7 +191,9 @@ const USER_CONFIRMATION_QUERY = `
// returns undefined.
const filterVerifiedNotification = ctx => async notification => {
// Grab the user that we're supposed to be sending the notification to.
const { notification: { userID } } = notification;
const {
notification: { userID },
} = notification;
// Check their confirmed status. This should have already been hit by the
// loaders, so we shouldn't make any more database requests.
@@ -15,7 +15,12 @@ function reduceSettings(newSettings, newValue, key) {
* Update the user notification settings.
*/
async function updateNotificationSettings(ctx, settings) {
const { connectors: { models: { User } }, user } = ctx;
const {
connectors: {
models: { User },
},
user,
} = ctx;
// Generate the settings set object, and just exit if we haven't changed
// anything.
@@ -29,7 +34,9 @@ async function updateNotificationSettings(ctx, settings) {
}
module.exports = ctx => {
const { connectors: { errors: ErrNotAuthorized } } = ctx;
const {
connectors: { errors: ErrNotAuthorized },
} = ctx;
let mutators = {
User: {
@@ -16,7 +16,13 @@ module.exports = {
digestFrequency: settings => get(settings, 'digestFrequency', 'NONE'),
},
RootMutation: {
async updateNotificationSettings(obj, { input }, { mutators: { User } }) {
async updateNotificationSettings(
obj,
{ input },
{
mutators: { User },
}
) {
await User.updateNotificationSettings(input);
},
},
@@ -4,7 +4,7 @@ const { get, isEmpty, reduce } = require('lodash');
module.exports = router => {
router.get('/account/unsubscribe-notifications', (req, res) => {
res.render(path.join(__dirname, 'views/unsubscribe-notifications'));
res.render(path.join(__dirname, 'views/unsubscribe-notifications.njk'));
});
/**
@@ -12,7 +12,10 @@ module.exports = router => {
*/
const verifyToken = (req, res, next) => {
const {
connectors: { secrets: { jwt }, config: { JWT_ISSUER, JWT_AUDIENCE } },
connectors: {
secrets: { jwt },
config: { JWT_ISSUER, JWT_AUDIENCE },
},
} = req.context;
const { token: tokenString = '' } = req.body;
if (!tokenString) {
@@ -50,7 +53,11 @@ module.exports = router => {
'/api/v1/account/unsubscribe-notifications',
verifyToken,
async (req, res, next) => {
const { connectors: { models: { User } } } = req.context;
const {
connectors: {
models: { User },
},
} = req.context;
const { user: userID } = req.token;
try {
@@ -1,3 +1,17 @@
ar:
talk-plugin-notifications:
templates:
digest:
subject: "نشاطك الأخير للتعليق على {0}"
footer: "لقد تلقيت هذا الإشعار نظرًا لأنك معلق على {0} وتم تمكين تلقي الإشعارات."
links:
unsubscribe: "إلغاء الاشتراك في إشعارات التعليقات"
unsubscribe_page:
unsubscribe: "إلغاء الاشتراك في إشعارات التعليقات"
click_to_confirm: "انقر أدناه لتأكيد رغبتك في إلغاء الاشتراك من جميع الإشعارات"
confirm: "أكد"
are_unsubscribed: "أنت الآن غير مشترك في جميع الإشعارات."
token_invalid: "رابط إلغاء الاشتراك غير صالح ، انقر الرابط من بريد إلكتروني أحدث أو قم بزيارة جدول تعليقات وتسجيل الدخول لتغيير تفضيلات الإشعارات الخاصة بك"
en:
talk-plugin-notifications:
templates:
@@ -11,4 +25,32 @@ en:
click_to_confirm: "Click below to confirm that you would like to unsubscribe from all notifications"
confirm: "Confirm"
are_unsubscribed: "You are now unsubscribed from all notifications."
token_invalid: "Unsubscribe link is invalid, click the link from a more recent email or visit a comment stream and login to change your notification preferences"
token_invalid: "Unsubscribe link is invalid, click the link from a more recent email or visit a comment stream and login to change your notification preferences"
de:
talk-plugin-notifications:
templates:
digest:
subject: "Ihre Kommentaraktivität bei {0}"
footer: "Sie erhalten diese Benachrichtigung, weil Sie Community-Mitglied bei {0} sind und diese E-Mails abonniert haben."
links:
unsubscribe: "E-Mail-Benachrichtigungen abbestellen"
unsubscribe_page:
unsubscribe: "Kommentar-Benachrichtigungen abbestellen"
click_to_confirm: "Klicken Sie folgenden Link, um zu bestätigen, dass Sie alle Benachrichtigungen abbestellen möchten"
confirm: "Bestätigen"
are_unsubscribed: "Sie haben haben alle Benachrichtigungen erfolgreich abbestellt."
token_invalid: "Der Abbestell-Link ist ungültig. Klicken Sie den Link einer neueren E-Mail oder gehen Sie zu einem Kommentarbereich, melden Sie sich an und ändern Sie dort Ihre Benachrichtigungseinstellungen"
nl_NL:
talk-plugin-notifications:
templates:
digest:
subject: "Je recente reactie-activiteit op {0}"
footer: "Je hebt deze notificatie ontvangen omdat je een reageerder bent op {0} en je hebt je aangemeld om notificaties te ontvangen."
links:
unsubscribe: "Afmelden voor reactie notificaties"
unsubscribe_page:
unsubscribe: "Afmelden voor reactie notificaties"
click_to_confirm: "Klik onderstaande om te bevestigen dat je je wilt afmelden voor alle notificaties"
confirm: "Bevestigen"
are_unsubscribed: "Je bent nu afgemeld voor alle notificaties."
token_invalid: "Afmeldlink is ongeldig, klik de link van een recentere e-mail of bezoek een pagina met reacties en log in om je notificatie voorkeuren te wijzigen"
@@ -1,6 +1,8 @@
const getOrganizationName = async ctx => {
// Grab some useful tools.
const { loaders: { Settings } } = ctx;
const {
loaders: { Settings },
} = ctx;
// Get the settings.
const { organizationName = null } = await Settings.select('organizationName');
@@ -16,7 +18,13 @@ const getOrganizationName = async ctx => {
* @param {Mixed} context the notification context
*/
const getNotificationBody = async (ctx, handler, context) => {
const { connectors: { services: { I18n: { t } } } } = ctx;
const {
connectors: {
services: {
I18n: { t },
},
},
} = ctx;
const { category, hydrate = () => [] } = handler;
// Get the body replacement variables for the translation key.
@@ -1,64 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<title><%= t('talk-plugin-notifications.unsubscribe_page.unsubscribe') %></title>
<%- include(root + '/partials/head') %>
<link rel="stylesheet" href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css">
<link rel="stylesheet" href="<%= BASE_PATH %>public/css/admin.css">
</head>
<body class="confirm-email-page">
<div id="root">
<div class="error-console container"><%= t('talk-plugin-notifications.unsubscribe_page.token_invalid') %></div>
<div id="success" style="display:none;" class="legend container"><%= t('talk-plugin-notifications.unsubscribe_page.are_unsubscribed') %></div>
<form id="unsubscribe-form" class="container">
<legend class="legend"><%= t('talk-plugin-notifications.unsubscribe_page.click_to_confirm') %></legend>
<button type="submit"><%= t('talk-plugin-notifications.unsubscribe_page.confirm') %></button>
</form>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
var submitting = false;
var payload = JSON.stringify({token: location.hash.replace('#', '')});
function handleSubmit(e) {
e.preventDefault();
if (submitting) {
return;
}
submitting = true;
$('.error-console').removeClass('active');
$.ajax({
url: '<%= BASE_PATH %>api/v1/account/unsubscribe-notifications',
contentType: 'application/json',
method: 'POST',
data: payload,
}).then(function (success) {
$('#unsubscribe-form').fadeOut(function () {
$('#success').fadeIn();
});
}).catch(function () {
submitting = false;
$('.error-console').addClass('active');
});
}
$.ajax({
url: '<%= BASE_PATH %>api/v1/account/unsubscribe-notifications/verify',
contentType: 'application/json',
method: 'POST',
data: payload,
})
.then(function () {
$('#unsubscribe-form').fadeIn().on('submit', handleSubmit);
})
.catch(function () {
$('.error-console').addClass('active');
});
});
</script>
</body>
</html>
@@ -0,0 +1,68 @@
{% extends "templates/account.njk" %}
{% block title %}{{ t('talk-plugin-notifications.unsubscribe_page.unsubscribe') }}{% endblock %}
{% block css %}
{{ super() }}
<style nonce="{{ nonce }}" type="text/css">
#success { display:none; }
</style>
{% endblock %}
{% block html %}
<div id="root">
<div class="error-console container">{{ t('talk-plugin-notifications.unsubscribe_page.token_invalid') }}</div>
<div id="success" class="legend container">{{ t('talk-plugin-notifications.unsubscribe_page.are_unsubscribed') }}</div>
<form id="unsubscribe-form" class="container">
<legend class="legend">{{ t('talk-plugin-notifications.unsubscribe_page.click_to_confirm') }}</legend>
<button type="submit">{{ t('talk-plugin-notifications.unsubscribe_page.confirm') }}</button>
</form>
</div>
{% endblock %}
{% block js %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script nonce="{{ nonce }}" type="text/javascript">
$(function() {
var submitting = false;
var payload = JSON.stringify({token: location.hash.replace('#', '')});
function handleSubmit(e) {
e.preventDefault();
if (submitting) {
return;
}
submitting = true;
$('.error-console').removeClass('active');
$.ajax({
url: '{{ BASE_PATH }}api/v1/account/unsubscribe-notifications',
contentType: 'application/json',
method: 'POST',
data: payload,
}).then(function (success) {
$('#unsubscribe-form').fadeOut(function () {
$('#success').fadeIn();
});
}).catch(function () {
submitting = false;
$('.error-console').addClass('active');
});
}
$.ajax({
url: '{{ BASE_PATH }}api/v1/account/unsubscribe-notifications/verify',
contentType: 'application/json',
method: 'POST',
data: payload,
})
.then(function () {
$('#unsubscribe-form').fadeIn().on('submit', handleSubmit);
})
.catch(function () {
$('.error-console').addClass('active');
});
});
</script>
{% endblock %}
@@ -23,4 +23,7 @@ const mapDispatchToProps = dispatch =>
dispatch
);
export default connect(mapStateToProps, mapDispatchToProps)(OffTopicFilter);
export default connect(
mapStateToProps,
mapDispatchToProps
)(OffTopicFilter);
@@ -2,6 +2,7 @@ import React from 'react';
import cn from 'classnames';
import styles from './styles.css';
import { t } from 'plugin-api/beta/client/services';
import { buildCommentURL } from 'plugin-api/beta/client/utils';
import { ClickOutside } from 'plugin-api/beta/client/components';
import { Icon, Button } from 'plugin-api/beta/client/components/ui';
@@ -90,7 +91,7 @@ export default class PermalinkButton extends React.Component {
className={cn(styles.input, `${name}-copy-field`)}
type="text"
ref={input => (this.permalinkInput = input)}
defaultValue={`${asset.url}?commentId=${comment.id}`}
defaultValue={buildCommentURL(asset.url, comment.id)}
readOnly
/>
@@ -105,9 +106,9 @@ export default class PermalinkButton extends React.Component {
},
])}
>
{!copyFailure && !copySuccessful && 'Copy'}
{copySuccessful && 'Copied'}
{copyFailure && 'Not supported'}
{!copyFailure && !copySuccessful && t('common.copy')}
{copySuccessful && t('common.copied')}
{copyFailure && t('common.notsupported')}
</Button>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More