mirror of
https://github.com/wassname/talk.git
synced 2026-07-05 18:49:18 +08:00
Merge branch 'moderate-shortcuts' of https://github.com/gerardogalvez/talk into moderate-shortcuts
This commit is contained in:
@@ -10,5 +10,12 @@
|
||||
"transform-async-to-generator",
|
||||
"transform-react-jsx",
|
||||
"syntax-dynamic-import"
|
||||
]
|
||||
],
|
||||
"env": {
|
||||
"test": {
|
||||
"plugins": [
|
||||
["transform-es2015-modules-commonjs", "dynamic-import-node"]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,5 +45,6 @@ plugins/*
|
||||
!plugins/talk-plugin-deep-reply-count
|
||||
!plugins/talk-plugin-subscriber
|
||||
!plugins/talk-plugin-flag-details
|
||||
!plugins/talk-plugin-slack-notifications
|
||||
|
||||
**/node_modules/*
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
# Talk [](https://circleci.com/gh/coralproject/talk)
|
||||
|
||||
[](https://dashboard.heroku.com/new?template=https%3A%2F%2Fgithub.com%2Fcoralproject%2Ftalk&env[TALK_FACEBOOK_APP_ID]=ignore&env[TALK_FACEBOOK_APP_SECRET]=ignore)
|
||||
|
||||
Online comments are broken. Our open-source Talk tool rethinks how moderation, comment display, and conversation function, creating the opportunity for safer, smarter discussions around your work. [Read more about Talk here](https://coralproject.net/products/talk.html).
|
||||
|
||||
## Documentation
|
||||
Built with <3 by The Coral Project & Mozilla.
|
||||
|
||||
Developer Documentation & Setup Guides https://coralproject.github.io/talk/.
|
||||
## Getting Started
|
||||
|
||||
Check out our Docs: https://coralproject.github.io/talk/
|
||||
|
||||
## Relevant Links
|
||||
|
||||
|
||||
@@ -16,19 +16,18 @@
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
min-height: 58px;
|
||||
display: block;
|
||||
background-color: #696969;
|
||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
|
||||
}
|
||||
|
||||
.header > div {
|
||||
background-color: #696969;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
min-width: 1280px;
|
||||
width: 1280px;
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
|
||||
height: 58px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.layout {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
background-color: #FAFAFA;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
padding-bottom: 200px;
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.mainFlaggedContent {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
.container {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
|
||||
h3 {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
.Dashboard {
|
||||
display: flex;
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.heading {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
.container {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.leftColumn {
|
||||
|
||||
@@ -35,16 +35,23 @@ export class CountdownSeconds extends React.Component {
|
||||
const {until, classNameForMsRemaining} = this.props;
|
||||
const msRemaining = until - now;
|
||||
const secRemaining = msRemaining / 1000;
|
||||
const wholeSecRemaining = Math.floor(secRemaining);
|
||||
const plural = secRemaining !== 1;
|
||||
const units = t(plural ? 'edit_comment.seconds_plural' : 'edit_comment.second');
|
||||
const minRemaining = secRemaining / 60;
|
||||
const secToMinRemaining = secRemaining % 60;
|
||||
const wholeMinRemaining = Math.floor(minRemaining);
|
||||
const wholeSecRemaining = Math.floor(secToMinRemaining);
|
||||
const secUnit = t(wholeSecRemaining !== 1 ? 'edit_comment.seconds_plural' : 'edit_comment.second');
|
||||
const minUnit = t(wholeMinRemaining !== 1 ? 'edit_comment.minutes_plural' : 'edit_comment.minute');
|
||||
let classFromProp;
|
||||
if (typeof classNameForMsRemaining === 'function') {
|
||||
classFromProp = classNameForMsRemaining(msRemaining);
|
||||
}
|
||||
const text = wholeMinRemaining > 0
|
||||
? `${wholeMinRemaining} ${minUnit} ${wholeSecRemaining} ${secUnit}`
|
||||
: `${wholeSecRemaining} ${secUnit}`;
|
||||
|
||||
return (
|
||||
<span className={classFromProp}>
|
||||
{`${wholeSecRemaining} ${units}`}
|
||||
{text}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -270,6 +270,7 @@ button.comment__action-button[disabled],
|
||||
width: 75%;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ccc;
|
||||
max-width: calc(100% - 40px);
|
||||
}
|
||||
|
||||
/* Close comments */
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
import {expect} from 'chai';
|
||||
import Markdown from '../Markdown';
|
||||
|
||||
const render = (props) => shallow(<Markdown {...props} />);
|
||||
@@ -9,12 +8,12 @@ describe('Markdown', () => {
|
||||
it('should convert Markdown to html', () => {
|
||||
const wrapper = render({content: '*test*'});
|
||||
const html = wrapper.html();
|
||||
expect(html).to.contain('<em>');
|
||||
expect(html).toMatch('<em>');
|
||||
});
|
||||
|
||||
it('should set target="_parent" for links', () => {
|
||||
const wrapper = render({content: '[link](https://coralproject.net)'});
|
||||
const html = wrapper.html();
|
||||
expect(html).to.contain('target="_parent"');
|
||||
expect(html).toMatch('target="_parent"');
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,7 @@ import pt_BR from '../../../locales/pt_BR.yml';
|
||||
|
||||
// Translations are happening at https://translate.lingohub.com/the-coral-project/dashboard
|
||||
|
||||
const defaultLanguage = 'en';
|
||||
const defaultLanguage = process.env.TALK_DEFAULT_LANG;
|
||||
const translations = {...en, ...es, ...fr, ...pt_BR};
|
||||
|
||||
let lang;
|
||||
|
||||
@@ -85,8 +85,8 @@ export class CommentForm extends React.Component {
|
||||
render() {
|
||||
const {maxCharCount, submitEnabled, cancelButtonClassName, submitButtonClassName, charCountEnable, body, loadingState} = this.props;
|
||||
|
||||
const length = body.length;
|
||||
const isRespectingMaxCount = (length) => charCountEnable && maxCharCount && length > maxCharCount;
|
||||
const length = body.trim().length;
|
||||
const isRespectingMaxCount = (length) => charCountEnable && maxCharCount && length > maxCharCount;
|
||||
const disableSubmitButton = !length || isRespectingMaxCount(length) || !submitEnabled({body}) || loadingState === 'loading';
|
||||
const disableCancelButton = loadingState === 'loading';
|
||||
const disableTextArea = loadingState === 'loading';
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
import {expect} from 'chai';
|
||||
import CommentBox from '../CommentBox';
|
||||
|
||||
describe('CommentBox', () => {
|
||||
let comment;
|
||||
let render;
|
||||
beforeEach(() => {
|
||||
comment = {};
|
||||
const postItem = (item) => {
|
||||
comment.posted = item;
|
||||
return Promise.resolve(4);
|
||||
};
|
||||
render = shallow(<CommentBox
|
||||
postItem={postItem}
|
||||
updateItem={(e) => comment.text = e.target.value}
|
||||
item_id={'1'}
|
||||
comments={['1', '2', '3']}/>);
|
||||
});
|
||||
|
||||
it('should render the CommentBox appropriately', () => {
|
||||
expect(render.contains('<div class="CommentBox"')).to.be.true;
|
||||
expect(render.contains('<button class="postCommentButton"')).to.be.true;
|
||||
});
|
||||
});
|
||||
+14
-7
@@ -1,29 +1,36 @@
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
import {expect} from 'chai';
|
||||
import InfoBox from '../InfoBox';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
const render = (props) => shallow(<InfoBox {...props} />);
|
||||
|
||||
describe('InfoBox', () => {
|
||||
it('renders correctly', () => {
|
||||
const tree = renderer.create(
|
||||
<InfoBox content='test' enable/>
|
||||
).toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render hidden InfoBox', () => {
|
||||
const wrapper = render();
|
||||
const className = wrapper.prop('className');
|
||||
expect(className).to.include('-info');
|
||||
expect(className).to.include('hidden');
|
||||
expect(className).toMatch('-info');
|
||||
expect(className).toMatch('hidden');
|
||||
});
|
||||
|
||||
it('should render enabled InfoBox', () => {
|
||||
const wrapper = render({enable: true});
|
||||
const className = wrapper.prop('className');
|
||||
expect(className).to.include('-info');
|
||||
expect(className).to.not.include('hidden');
|
||||
expect(className).toMatch('-info');
|
||||
expect(className).not.toMatch('hidden');
|
||||
});
|
||||
|
||||
it('should render Markdown', () => {
|
||||
const wrapper = render({content: 'x'});
|
||||
const Markddown = wrapper.find('Markdown');
|
||||
expect(Markddown).to.have.length(1);
|
||||
expect(Markddown.prop('content')).to.equal('x');
|
||||
expect(Markddown).toHaveLength(1);
|
||||
expect(Markddown.prop('content')).toEqual('x');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`InfoBox renders correctly 1`] = `
|
||||
<div
|
||||
className="talk-plugin-infobox-info "
|
||||
>
|
||||
<div
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<p>test</p>
|
||||
",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
@@ -24,6 +24,10 @@ otherwise the application will fail to start.
|
||||
Configure the duration for which comment counts are cached for, parsed by
|
||||
[ms](https://www.npmjs.com/package/ms){:target="_blank"}. (Default `1hr`)
|
||||
|
||||
## TALK_DEFAULT_LANG
|
||||
|
||||
Specify the default translation language. (Default `en`)
|
||||
|
||||
## TALK_DEFAULT_STREAM_TAB
|
||||
|
||||
Specify the default stream tab in the admin. (Default `all`)
|
||||
@@ -439,4 +443,4 @@ Could be read as:
|
||||
again, then they must have two of their comments approved in order to get
|
||||
added back to the queue.
|
||||
- At the moment of writing, behavior is not attached to the flagging
|
||||
reliability, but it is recorded.
|
||||
reliability, but it is recorded.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
const path = require('path');
|
||||
const {pluginsPath} = require('./plugins');
|
||||
|
||||
const buildTargets = [
|
||||
'coral-admin',
|
||||
'coral-docs'
|
||||
];
|
||||
|
||||
const buildEmbeds = [
|
||||
'stream'
|
||||
];
|
||||
|
||||
// jest.config.js
|
||||
module.exports = {
|
||||
testMatch: ['**/client/**/__tests__/**/*.js?(x)'],
|
||||
setupTestFrameworkScriptFile: '<rootDir>/test/client/setupJest.js',
|
||||
modulePaths: [
|
||||
'<rootDir>/plugins',
|
||||
'<rootDir>/client',
|
||||
...buildTargets.map((target) => path.join('<rootDir>', 'client', target, 'src')),
|
||||
...buildEmbeds.map((embed) => path.join('<rootDir>', 'client', `coral-embed-${embed}`, 'src')),
|
||||
],
|
||||
moduleFileExtensions: ['js', 'jsx', 'json', 'yaml', 'yml'],
|
||||
moduleDirectories: ['node_modules'],
|
||||
|
||||
transform: {
|
||||
'^.+\\.jsx?$': 'babel-jest',
|
||||
'\\.ya?ml$': '<rootDir>/test/client/yamlTransformer.js'
|
||||
},
|
||||
|
||||
moduleNameMapper: {
|
||||
'^plugin-api\\/(.*)$': '<rootDir>/plugin-api/$1',
|
||||
'^plugins\\/(.*)$': '<rootDir>/plugins/$1',
|
||||
'^pluginsConfig$': pluginsPath,
|
||||
|
||||
'\\.(scss|css|less)$': 'identity-obj-proxy',
|
||||
'\\.(gif|ttf|eot|svg)$': '<rootDir>/test/client/fileMock.js'
|
||||
}
|
||||
};
|
||||
+3
-1
@@ -172,6 +172,8 @@ en:
|
||||
edit_window_timer_prefix: "Edit Window: "
|
||||
second: "second"
|
||||
seconds_plural: "seconds"
|
||||
minute: "minute"
|
||||
minutes_plural: "minutes"
|
||||
email:
|
||||
confirm:
|
||||
has_been_requested: "A email confirmation has been requested for the following account:"
|
||||
@@ -186,7 +188,7 @@ en:
|
||||
embedlink:
|
||||
copy: "Copy to Clipboard"
|
||||
error:
|
||||
COMMENT_TOO_SHORT: "Your comment must have something in it"
|
||||
COMMENT_TOO_SHORT: "Comments should be more than one character, please revise your comment and try again."
|
||||
NOT_AUTHORIZED: "You are not authorized to perform this action."
|
||||
NO_SPECIAL_CHARACTERS: "Usernames can contain letters numbers and _ only"
|
||||
PASSWORD_LENGTH: "Password is too short"
|
||||
|
||||
@@ -171,6 +171,8 @@ es:
|
||||
edit_window_timer_prefix: "Ventana Edición:"
|
||||
second: "segundo"
|
||||
seconds_plural: "segundos"
|
||||
minute: "minuto"
|
||||
minutes_plural: "minutos"
|
||||
email:
|
||||
confirm:
|
||||
has_been_requested: "Un correo de confirmación ha sido pedido para la siguiente cuenta:"
|
||||
|
||||
@@ -140,6 +140,8 @@ fr:
|
||||
edit_window_timer_prefix: "Fenêtre d'édition :"
|
||||
second: "seconde"
|
||||
seconds_plural: "secondes"
|
||||
minute: "minute"
|
||||
minutes_plural: "minutes"
|
||||
unexpected_error: "Erreur inattendue lors de l'enregistrement des modifications. Désolé !"
|
||||
embedlink:
|
||||
copy: "Copier dans le presse-papier"
|
||||
|
||||
+105
-94
@@ -1,122 +1,131 @@
|
||||
pt_BR:
|
||||
your_account_has_been_suspended: Sua conta foi temporariamente suspensa.
|
||||
your_account_has_been_banned: Sua conta foi banida.
|
||||
your_username_has_been_rejected: Sua conta foi suspensa porque seu nome de usuário foi considerado inapropriado. Para restaurar sua conta, insira um novo nome de usuário.
|
||||
your_username_has_been_rejected: Sua conta foi rejeitada porque seu nome de usuário foi considerado inapropriado. Para restaurar sua conta, insira um novo nome de usuário.
|
||||
embed_comments_tab: Comentários
|
||||
bandialog:
|
||||
are_you_sure: "Tem certeza de que gostaria de proibir a {0}?"
|
||||
ban_user: "Proibir o usuário?"
|
||||
banned_user: "Usuário proibido"
|
||||
are_you_sure: "Tem certeza de que gostaria de banir {0}?"
|
||||
ban_user: "Deseja banir o usuário?"
|
||||
banned_user: "Usuário banido"
|
||||
cancel: "Cancelar"
|
||||
note: "Nota: {0}"
|
||||
note_reject_comment: "Proibir esse usuário também colocará esse comentário na fila rejeitada."
|
||||
note_ban_user: "Proibir este usuário não os permitirá editar comentários ou remover qualquer coisa."
|
||||
yes_ban_user: "Sim, proiber o usuário"
|
||||
bio_offensive: "Essa bio é ofensiva"
|
||||
note_reject_comment: "Banir esse usuário também colocará esse comentário na fila rejeitada."
|
||||
note_ban_user: "Banir este usuário não os permitirá editar comentários ou remover qualquer coisa."
|
||||
yes_ban_user: "Sim, banir o usuário"
|
||||
bio_offensive: "Esse perfil é ofensiva"
|
||||
cancel: "Cancelar"
|
||||
characters_remaining: "caracteres restantes"
|
||||
comment:
|
||||
anon: "Anônimo"
|
||||
ban_user: "Proibir o usuário"
|
||||
comment: "Publicar um comentário"
|
||||
ban_user: "Banir o usuário"
|
||||
comment: "Escreva um comentário..."
|
||||
edited: Editado
|
||||
flagged: "marcado"
|
||||
flagged: "Marcado"
|
||||
view_context: "Veja o contexto"
|
||||
comment_box:
|
||||
post: "Publicar"
|
||||
post: "Enviar"
|
||||
cancel: "Cancelar"
|
||||
reply: "Responder"
|
||||
comment: "Publicar um comentário"
|
||||
comment: "Escreva um comentário..."
|
||||
name: "Nome"
|
||||
comment_post_notif: "Seu comentário foi postado."
|
||||
comment_post_notif_premod: "Obrigado por publicar seu comentário. Nossa equipe de moderação analisará seu comentário em breve."
|
||||
comment_post_banned_word: "O seu comentário contém uma ou mais palavras que não são permitidas, portanto, não serão publicadas. Se você acha que esta mensagem está incorreta, contate nossa equipe de moderação."
|
||||
comment_post_notif: "Seu comentário foi enviado."
|
||||
comment_post_notif_premod: "Obrigado por compartilhar sua opinião. Nossa equipe de moderação analisará seu comentário em breve."
|
||||
comment_post_banned_word: "Seu comentário não foi publicado porque contém conteúdo inadequado."
|
||||
characters_remaining: "caracteres restantes"
|
||||
comment_offensive: "Este comentário é ofensivo"
|
||||
comment_singular: Comentário
|
||||
comment_plural: Comentários
|
||||
comment_post_banned_word: "O seu comentário contém uma ou mais palavras que não são permitidas, portanto, não serão publicadas. Se você acha que esta mensagem está incorret a, contate nossa equipe de moderação."
|
||||
comment_post_banned_word: "Seu comentário não foi publicado porque contém conteúdo inadequado."
|
||||
comment_post_notif: "Seu comentário foi postado."
|
||||
comment_post_notif_premod: "Obrigado por publicar seu comentário. Nossa equipe de moderação analisará seu comentário em breve."
|
||||
comment_post_notif_premod: "Obrigado por compartilhar sua opinião. Nossa equipe de moderação analisará seu comentário em breve."
|
||||
common:
|
||||
copy: 'Copie'
|
||||
copy: 'Copiar'
|
||||
error: 'Ocorreu um erro.'
|
||||
reply: 'Resposta'
|
||||
replies: 'Respostas'
|
||||
reaction: 'Reação'
|
||||
reactions: 'Reações'
|
||||
story: 'Conversas'
|
||||
community:
|
||||
account_creation_date: "Data de criação da conta"
|
||||
active: Ativo
|
||||
admin: Administrador
|
||||
ads_marketing: "Isso parece anúncio/marketing"
|
||||
are_you_sure: "Você tem certeza de que gostaria de proibir a {0}?"
|
||||
ban_user: "Proibir o usuário?"
|
||||
banned: Proibida
|
||||
banned_user: "Usuário proibido"
|
||||
ads_marketing: "Este comentário parece anúncio"
|
||||
are_you_sure: "Você tem certeza de que gostaria de banir {0}?"
|
||||
ban_user: "Banir o usuário?"
|
||||
banned: Banido
|
||||
banned_user: "Usuário banido"
|
||||
cancel: Cancelar
|
||||
flaggedaccounts: "Nomes de usuários marcados"
|
||||
dont_like_username: "Descurtir usuário"
|
||||
flaggedaccounts: "Usuários marcados"
|
||||
flags: Marcadas
|
||||
impersonating: "Representação"
|
||||
loading: "Carregando resultados"
|
||||
moderator: Moderador
|
||||
newsroom_role: "Papel de empresa"
|
||||
no_flagged_accounts: "A fila de nomes de usuários marcados está atualmente vazia."
|
||||
newsroom_role: "Papel da empresa"
|
||||
no_flagged_accounts: "A fila de usuários marcados está atualmente vazia."
|
||||
no_results: "Nenhum usuário encontrado com esse nome de usuário ou e-mail. Eles estão se escondendo!"
|
||||
offensive: "Ofensivo"
|
||||
other: Outros
|
||||
people: Pessoas
|
||||
role: "Selecione um papel..."
|
||||
select_status: "Selecione um status..."
|
||||
staff: "Funcionários"
|
||||
status: Status
|
||||
spam_ads: "Spam/Ads"
|
||||
staff: "Equipe"
|
||||
status: Situação
|
||||
username_and_email: "Nome de usuário e email"
|
||||
yes_ban_user: "Sim, proibir esse usuário"
|
||||
yes_ban_user: "Sim, banir este usuário"
|
||||
configure:
|
||||
apply: Aplicar
|
||||
banned_word_text: "Os comentários que contenham essas palavras ou frases (não sensíveis a maiúsculas e minúsculas) serão automaticamente removidos do hilo de comentários. Digite uma palavra e pressione Enter ou Tab para adicionar. Opcionalmente cole uma lista separada por vírgulas."
|
||||
banned_word_text: "Os comentários que contenham essas palavras ou frases (não sensíveis a maiúsculas e minúsculas) serão automaticamente removidos da lista de comentários. Digite uma palavra e pressione Enter ou Tab para adicionar ou cole uma lista separada por vírgulas."
|
||||
banned_words_title: "Lista de palavras proibidas"
|
||||
close: "Fechar"
|
||||
close_after: "Feche os comentários após"
|
||||
close_stream: "Feche hilo de comentários"
|
||||
close_stream_configuration: "Esse hilo de comentários está fechado no momento. Ao abrir esse hilo de comentários, novos comentários podem ser enviados e exibidos."
|
||||
closed_comments_desc: "Escreva uma mensagem a ser exibida quando o seu hilo de comentários for fechado e deixando de aceitar comentários."
|
||||
closed_comments_label: "Escreve uma mensagem..."
|
||||
close_after: "Fechar comentários após"
|
||||
close_stream: "Fechar comentários"
|
||||
close_stream_configuration: "Comentários fechados no momento. Ao abrir comentários, novos comentários podem ser enviados e exibidos."
|
||||
closed_comments_desc: "Escreva uma mensagem a ser exibida quando os comentários estiverem fechados."
|
||||
closed_comments_label: "Escreva uma mensagem..."
|
||||
closed_stream_settings: "Mensagem de comentários fechados"
|
||||
comment_count_error: "Por favor insira um número válido."
|
||||
comment_count_header: "Limite o comprimento do comentário"
|
||||
comment_count_header: "Limite o tamanho do comentário"
|
||||
comment_count_text_post: caracteres
|
||||
comment_count_text_pre: "Os comentários serão limitados a"
|
||||
comment_settings: Configurações
|
||||
comment_stream: "Hilo de comentários"
|
||||
comment_stream_will_close: "O hilo de comentários será fechado"
|
||||
community: Comunidade
|
||||
comment_stream: "Lista de comentários"
|
||||
comment_stream_will_close: "Comentários fechados"
|
||||
community: Usuários
|
||||
configure: Configurar
|
||||
copy_and_paste: "Copie e cole o código abaixo em seu CMS para incorporar sua caixa de comentários em seus artigos."
|
||||
custom_css_url: "URL personalizado do CSS"
|
||||
custom_css_url_desc: "URL de uma folha de estilo CSS que irá substituir os estilos padrão dos comentários embutidos. Pode ser interno ou externo."
|
||||
custom_css_url: "URL para CSS customizado"
|
||||
custom_css_url_desc: "URL de uma folha de estilo CSS para substituir os estilos padrão dos comentários embutidos. Pode ser interno ou externo."
|
||||
dashboard: Painel de controle
|
||||
days: Dias
|
||||
description: "Como administrador, você pode personalizar as configurações do hilo de comentários para esta história:"
|
||||
domain_list_text: "Insira os domínios que você gostaria de permitir para o Talk, como o seu site de preparação ou site de produção (ej. localhost:3000 staging.domain.com domain.com)."
|
||||
description: "Como administrador, você pode personalizar as configurações da lista de comentários para esta história:"
|
||||
domain_list_text: "Insira os domínios que você gostaria de permitir para o Talk, como seus ambientes de desenvolvimento, teste ou produção (ej. localhost:3000 staging.domain.com domain.com)."
|
||||
domain_list_title: "Domínios permitidos"
|
||||
edit_comment_timeframe_heading: "Período de tempo para editar comentários"
|
||||
edit_comment_timeframe_text_pre: "Os comentadores terão"
|
||||
edit_comment_timeframe_text_pre: "Os usuários terão"
|
||||
edit_comment_timeframe_text_post: "segundos para editar seus comentários."
|
||||
embed_comment_stream: "Comentários embutidos"
|
||||
enable_premod_links_text: "Os moderadores devem aprovar qualquer comentário contendo um link antes de ser publicado."
|
||||
enable_premod_links_text: "Demandar aprovação de moderadores antes de publicar comentários com links."
|
||||
enable_pre_moderation: "Habilitar pré-moderação"
|
||||
enable_pre_moderation_text: "Os moderadores devem aprovar qualquer comentário antes de ser publicado."
|
||||
enable_pre_moderation_text: "Demandar aprovação de moderadores para todos os comentários."
|
||||
enable_premod_links: "Os moderadores devem aprovar qualquer comentário antes de ser publicado."
|
||||
enable_premod: "Habilitar pré-moderação"
|
||||
enable_premod_description: "Moderators must approve any comment before it is published."
|
||||
enable_premod_links_description: "Os moderadores devem aprovar qualquer comentário antes de ser publicado."
|
||||
enable_premod_description: "Demandar aprovação de moderadores para todos os comentários."
|
||||
enable_premod_links_description: "Demandar aprovação de moderadores antes de publicar comentários com links."
|
||||
enable_questionbox: "Faça uma pergunta aos leitores"
|
||||
enable_questionbox_description: "Esta pergunta aparecerá no topo deste hilo de comentários. Pergunte aos leitores sobre um determinado problema no artigo ou coloca questões de discussão, etc."
|
||||
enable_questionbox_description: "Esta pergunta aparecerá no topo da lista de comentários. Pergunte aos leitores sobre um determinado problema no artigo, abra o assunto para discussão, etc."
|
||||
hours: Horas
|
||||
include_comment_stream: "Incluir descrição de hilo de comentários para leitores"
|
||||
include_comment_stream: "Incluir descrição da lista comentários para leitores"
|
||||
include_comment_stream_desc: "Escreva uma mensagem para adicionar ao topo do seu hilo de comentários. Posicionar um tópico, incluem diretrizes comunitárias, etc."
|
||||
include_text: "Inclua seu texto aqui:"
|
||||
include_question_here: "Escreva sua pergunta aqui:"
|
||||
moderate: Moderar
|
||||
moderation_settings: "Configurações de moderação"
|
||||
open: "Abra"
|
||||
open_stream: "Abra hilo de comentários"
|
||||
open_stream_configuration: "Esse hilo de comentários está aberto no momento. Ao fechar este hilo de comentários, nenhum novo comentário pode ser enviado e todos os comentários anteriores ainda serão exibidos."
|
||||
open: "Abrir"
|
||||
open_stream: "Abrir comentários"
|
||||
open_stream_configuration: "Comentários abertos no momento. Ao fechar esta lista de comentários, nenhum novo comentário poderá ser enviado. Mas os comentários anteriores ainda serão exibidos."
|
||||
require_email_verification: "Requerer verificação de email"
|
||||
require_email_verification_text: "Novos usuários devem verificar seu e-mail antes de comentar"
|
||||
save_changes: "Salvar alterações"
|
||||
@@ -125,7 +134,7 @@ pt_BR:
|
||||
stories: Histórias
|
||||
stream_settings: "Configurações de comentários"
|
||||
suspect_word_title: "Lista de palavras suspeitas"
|
||||
suspect_word_text: "Os comentários que contenham essas palavras ou frases (não sensíveis a maiúsculas e minúsculas) serão destacados no hilo de comentários. Digite uma palavra e pressione Enter ou Tab para adicionar. Opcionalmente cole uma lista separada por vírgulas."
|
||||
suspect_word_text: "Os comentários que contenham essas palavras ou frases (não sensíveis a maiúsculas e minúsculas) serão automaticamente removidos da lista de comentários. Digite uma palavra e pressione Enter ou Tab para adicionar ou cole uma lista separada por vírgulas."
|
||||
tech_settings: "Configurações técnicas"
|
||||
title: "Configurar comentários"
|
||||
weeks: Semanas
|
||||
@@ -135,7 +144,7 @@ pt_BR:
|
||||
check_the_form: "Formulário inválido. Verifique as entradas do formulário."
|
||||
continue: "Continue com o mesmo nome de usuário do Facebook"
|
||||
error_create: "Erro ao alterar o nome de usuário"
|
||||
fake_comment_body: "Este é um exemplo de comentário. Os leitores podem compartilhar seus pensamentos e opiniões com as salas de redação na seção de comentários."
|
||||
fake_comment_body: "Este é um exemplo de comentário. Os leitores podem compartilhar seus pensamentos e opiniões com a redação na seção de comentários."
|
||||
fake_comment_date: "1 minuto atrás"
|
||||
if_you_dont_change_your_name: "Se você não alterar seu nome de usuário nesta etapa, seu nome de exibição do Facebook aparecerá ao lado de todos os seus comentários."
|
||||
required_field: "Requerido"
|
||||
@@ -145,30 +154,32 @@ pt_BR:
|
||||
write_your_username: "Edite seu nome de usuário"
|
||||
your_username: "Nosso nome de usuário aparece em todos os comentários que você publica."
|
||||
dashboard:
|
||||
auto_update: "Data automatically updates every five minutes or when you Reload."
|
||||
auto_update: "Atualizado autimaticamente a cada minutos ou após recarregamento."
|
||||
comment_count: comentários
|
||||
flags: Marcadas
|
||||
most_flags: "Histórias com a maioria das marcadas"
|
||||
most_conversations: "Histórias com a maioria das conversas"
|
||||
flags: Marcações
|
||||
most_flags: "Conversas com mais comentários marcados"
|
||||
most_conversations: "Conversas com mais comentários"
|
||||
next_update: "{0} minutos até a próxima atualização."
|
||||
no_activity: "Não houve nenhum comentário nos últimos cinco minutos."
|
||||
no_flags: "Não houve nenhuma marcada em nenhum lugar nos últimos 5 minutos. Hip Hip Uha!"
|
||||
no_likes: "Não houve gostos nos últimos 5 minutos."
|
||||
no_flags: "Não houve nenhum comentário marcado em nenhum lugar nos últimos 5 minutos. Hip Hip Uha!"
|
||||
no_likes: "Não houve reações nos últimos 5 minutos."
|
||||
done: Feito
|
||||
edit_comment:
|
||||
body_input_label: "Edite este comentário"
|
||||
save_button: "Salvar alterações"
|
||||
edit_window_expired: "Você não pode mais editar esse comentário. A janela de tempo para fazê-lo expirou. Por que não publicar outro?"
|
||||
edit_window_expired_close: "Fechar"
|
||||
edit_window_timer_prefix: "Para editar:"
|
||||
edit_window_timer_prefix: "Tempo para editar:"
|
||||
second: "segundo"
|
||||
seconds_plural: "segundos"
|
||||
minute: "minuto"
|
||||
minutes_plural: "minutos"
|
||||
email:
|
||||
confirm:
|
||||
has_been_requested: "Uma confirmação de e-mail foi solicitada para a seguinte conta:"
|
||||
to_confirm: "Para confirmar a conta, visite o seguinte link: "
|
||||
to_confirm: "Para confirmar a conta, visite este link: "
|
||||
confirm_email: "Confirme e-mail"
|
||||
if_you_did_not: "Se você não solicitou isso, você pode ignorar este e-mail com segurança."
|
||||
if_you_did_not: "Se você não solicitou isso, você pode ignorar este e-mail."
|
||||
subject: "Confirmação de e-mail"
|
||||
password_reset:
|
||||
we_received_a_request: "Recebemos um pedido para redefinir sua senha. Se você não solicitou esta alteração, pode ignorar este e-mail."
|
||||
@@ -177,7 +188,7 @@ pt_BR:
|
||||
embedlink:
|
||||
copy: "Copiar para área de transferência"
|
||||
error:
|
||||
COMMENT_TOO_SHORT: "Seu comentário deve conter palavras."
|
||||
COMMENT_TOO_SHORT: "Seu comentário precisar ter mais de um caracter. Revise seu comentário e envie novamente"
|
||||
NOT_AUTHORIZED: "Você não está autorizado a executar esta ação."
|
||||
NO_SPECIAL_CHARACTERS: "Nomes de usuários podem conter números de letras e _ somente"
|
||||
PASSWORD_LENGTH: "A senha é muito curta"
|
||||
@@ -189,7 +200,7 @@ pt_BR:
|
||||
SAME_USERNAME_PROVIDED: "Você deve enviar um nome de usuário diferente."
|
||||
EMAIL_IN_USE: "Endereço de e-mail já está em uso."
|
||||
EMAIL_REQUIRED: "É necessário o endereço de e-mail."
|
||||
LOGIN_MAXIMUM_EXCEEDED: "Você fez muitas tentativas de senha mal sucedidas. Por favor, espere."
|
||||
LOGIN_MAXIMUM_EXCEEDED: "Você fez muitas tentativas de senha mal sucedidas. Espere alguns instantes."
|
||||
PASSWORD_REQUIRED: "Você deve inserir uma senha."
|
||||
COMMENTING_CLOSED: "Os comentários já estão fechados."
|
||||
NOT_FOUND: "Recurso não encontrado"
|
||||
@@ -208,8 +219,8 @@ pt_BR:
|
||||
flag_reason: "Motivo do relatório (opcional)"
|
||||
flag_username: "Informe o nome de usuário"
|
||||
framework:
|
||||
banned_account_header: "Sua conta está atualmente proibida."
|
||||
banned_account_body: "Isso significa que você não pode gostar, informar ou escrever comentários."
|
||||
banned_account_header: "Sua conta está atualmente banida."
|
||||
banned_account_body: "Isso significa que você não pode curtir, informar ou escrever comentários."
|
||||
comment: comentário
|
||||
comment_is_ignored: "Este comentário está oculto porque você ignorou esse usuário."
|
||||
comments: comentários
|
||||
@@ -241,7 +252,7 @@ pt_BR:
|
||||
account: "contas marcadas"
|
||||
actions: Ações
|
||||
all: todos
|
||||
all_streams: "Todos os hilos"
|
||||
all_streams: "Todas as listas"
|
||||
notify_edited: '{0} editou o comentário "{1}"'
|
||||
notify_accepted: '{0} aprovou o comentário "{1}"'
|
||||
notify_rejected: '{0} rejeitou o comentário "{1}"'
|
||||
@@ -252,17 +263,17 @@ pt_BR:
|
||||
billion: B
|
||||
close: Fechar
|
||||
dont_like_username: "Eu não gosto desse nome de usuário"
|
||||
empty_queue: "Não há mais comentários para moderar! Você está todo apanhado. Vá tomar um ☕️"
|
||||
empty_queue: "Não há mais comentários para moderar! Aproveite para relaxar e esticar as pernas"
|
||||
flagged: marcado
|
||||
impersonating: Representação
|
||||
less_detail: "Menos detalhes"
|
||||
likes: gostos
|
||||
likes: Curtidas
|
||||
million: M
|
||||
mod_faster: "Moderado mais rápido com atalhos de teclado"
|
||||
mod_faster: "Modere mais rápido com atalhos de teclado"
|
||||
moderate: "Moderar →"
|
||||
more_detail: "Mais detalhes"
|
||||
new: "Novo"
|
||||
newest_first: "Mais novo primeiro"
|
||||
newest_first: "Mais novos primeiro"
|
||||
navigation: Navegação
|
||||
next_comment: "Vá para o próximo comentário"
|
||||
offensive: Ofensiva
|
||||
@@ -272,7 +283,7 @@ pt_BR:
|
||||
prev_comment: "Vá para o comentário anterior"
|
||||
reject: "Rejeitar"
|
||||
rejected: "Rejeitado"
|
||||
select_stream: "Selecione hilo"
|
||||
select_stream: "Selecione a lista"
|
||||
shift_key: "⇧"
|
||||
shortcuts: "Atalhos"
|
||||
show_shortcuts: "Ver atalhos"
|
||||
@@ -280,13 +291,13 @@ pt_BR:
|
||||
spam_ads: Spam/Anuncios
|
||||
thismenu: "Abra este menu"
|
||||
thousand: k
|
||||
try_these: "Tente esse"
|
||||
try_these: "Tente este"
|
||||
view_more_shortcuts: "Ver mais atalhos"
|
||||
my_comment_history: "Histórico de comentários"
|
||||
name: Nome
|
||||
no_agree_comment: "Eu não concordo com este comentário"
|
||||
no_like_bio: "Eu não gosto dessa biografia"
|
||||
no_like_username: "Eu não gosto desse nome de usuário"
|
||||
no_like_bio: "Eu não gosto dessa descrição de perfil"
|
||||
no_like_username: "Eu não gosto deste nome de usuário"
|
||||
other: Outro
|
||||
permalink: Link
|
||||
personal_info: "Este comentário revela informações de identificação pessoal"
|
||||
@@ -294,10 +305,10 @@ pt_BR:
|
||||
profile: Perfil
|
||||
profile_settings: "Configurações de perfil"
|
||||
reply: Responder
|
||||
report: Reportar
|
||||
report_notif: "Obrigado por reportar este comentário. Nossa equipe de moderação foi notificada e irá revisá-la em breve."
|
||||
report_notif_remove: "Seu marcado foi removido."
|
||||
reported: Reportado
|
||||
report: Denunciar
|
||||
report_notif: "Obrigado por denunciar este comentário. Nossa equipe de moderação foi notificada e irá revisá-la em breve."
|
||||
report_notif_remove: "O comentário que você denunciou foi removido."
|
||||
reported: Denunciado
|
||||
settings:
|
||||
from_settings_page: "Na página de Perfil, você pode ver seu histórico de comentários."
|
||||
my_comment_history: "Histórico de comentários"
|
||||
@@ -316,30 +327,30 @@ pt_BR:
|
||||
all: Todos
|
||||
article: História
|
||||
closed: Fechado
|
||||
empty_result: "Nenhum recurso corresponde a esta pesquisa. Talvez tente alargar a sua pesquisa?"
|
||||
filter_streams: "Filtra os hilos"
|
||||
empty_result: "Nenhum resultado encontrado para esta pesquisa. Que tal refazer a pesquisa com termos diferentes?"
|
||||
filter_streams: "Filtra as listas"
|
||||
newest: O mais novo
|
||||
oldest: O mais velho
|
||||
open: Aberto
|
||||
pubdate: "Data de publicação"
|
||||
search: Pesquisar
|
||||
sort_by: "Ordenar por"
|
||||
status: "Status do hilo"
|
||||
stream_status: "Status do hilo"
|
||||
status: "Situação dos comentários"
|
||||
stream_status: "Situação dos comentários"
|
||||
suspenduser:
|
||||
title_suspend: "Suspender usuário"
|
||||
description_suspend: "Você está suspendendo {0}. Este comentário irá para a fila Rejeitada, e {0} não poderá gostar, reportar, responder ou publicar até que o tempo de suspensão seja concluído."
|
||||
description_suspend: "Você está suspendendo {0}. Este comentário irá para a fila Rejeitada, e {0} não poderá gostar, denunciar, responder ou publicar até que o tempo de suspensão seja concluído."
|
||||
select_duration: "Selecione a duração da suspensão"
|
||||
one_hour: "1 hora"
|
||||
hours: "{0} horas"
|
||||
days: "{0} dias"
|
||||
cancel: "Cancelar"
|
||||
suspend_user: "Suspender usuário"
|
||||
email_message_suspend: "Querido/a {0},\n\nDe acordo com as diretrizes da comunidade de {1}, sua conta foi temporariamente suspensa. Durante a suspensão, você não poderá comentar, reportar ou se envolver com outros comentaristas. Por favor, volte para a conversa {2}."
|
||||
email_message_suspend: "Querido/a {0},\n\nDe acordo com as diretrizes da comunidade de {1}, sua conta foi temporariamente suspensa. Durante a suspensão, você não poderá comentar, denunciar ou se responder outros usuários(as). Por favor, volte para a conversa {2}."
|
||||
title_notify: "Notificar o usuário da suspensão temporária"
|
||||
notify_suspend_until: "O usuário {0} foi temporariamente suspenso. Esta suspensão terminará automaticamente {1}."
|
||||
description_notify: "Suspender este usuário temporariamente desativará sua conta e esconderá todos os seus comentários no site"
|
||||
write_message: "Escrive uma mensagem"
|
||||
write_message: "Escrever uma mensagem"
|
||||
send: Enviar
|
||||
reject_username:
|
||||
username: nome de usuário
|
||||
@@ -350,14 +361,14 @@ pt_BR:
|
||||
title_reject: "Percebemos que você rejeitou um nome de usuário"
|
||||
suspend_user: "Suspender usuário"
|
||||
yes_suspend: "Sim suspender"
|
||||
email_message_reject: "Outro membro da comunidade recentemente sinalizou seu nome de usuário para revisão. Por causa do seu conteúdo, seu nome de usuário foi rejeitado. Isso significa que você não pode mais comentar, gostar, ou reportar conteúdo até que você reescreva seu nome de usuário. Por favor envie-nos um e-mail se tiver dúvidas ou preocupações."
|
||||
email_message_reject: "Outro membro da comunidade recentemente sinalizou seu nome de usuário para revisão. Por causa do seu conteúdo, seu nome de usuário foi rejeitado. Isso significa que você não pode mais comentar, gostar, ou denunciar conteúdo até que você reescreva seu nome de usuário. Por favor envie-nos um e-mail se tiver dúvidas ou preocupações."
|
||||
write_message: "Escreve uma mensagem"
|
||||
send: Enviar
|
||||
thank_you: "Nós valorizamos sua segurança e feedback. Um moderador irá rever o seu relatório."
|
||||
thank_you: "Nós valorizamos sua segurança e opinião. Um moderador irá rever o seu relatório."
|
||||
user:
|
||||
bio_flags: "Marcadas para esta biografia"
|
||||
user_bio: "Biografia do usuário"
|
||||
username_flags: "Marcadas para este nome de usuário"
|
||||
bio_flags: "Marcadas para este perfil"
|
||||
user_bio: "Perfil do usuário"
|
||||
username_flags: "Marcadas para este usuário"
|
||||
user_impersonating: "Este usuário está representando"
|
||||
user_no_comment: "Você nunca deixou um comentário. Participe da conversa!"
|
||||
username_offensive: "Esse nome de usuário é ofensivo"
|
||||
|
||||
+12
-3
@@ -14,7 +14,8 @@
|
||||
"build-watch": "WEBPACK=TRUE NODE_ENV=development webpack --progress --config webpack.config.js --watch",
|
||||
"lint": "eslint --ext=.js --ext=.json bin/* .",
|
||||
"lint-fix": "yarn lint --fix",
|
||||
"test": "TEST_MODE=unit NODE_ENV=test mocha -R ${MOCHA_REPORTER:-spec}",
|
||||
"jest-watch": "TEST_MODE=unit NODE_ENV=test jest --watch",
|
||||
"test": "TEST_MODE=unit NODE_ENV=test jest && TEST_MODE=unit NODE_ENV=test mocha -R ${MOCHA_REPORTER:-spec}",
|
||||
"test-cover": "TEST_MODE=unit NODE_ENV=test istanbul cover _mocha --report text --check-coverage -- -R spec",
|
||||
"heroku-postbuild": "./bin/cli plugins reconcile && yarn build",
|
||||
"generate-introspection": "WEBPACK=TRUE NODE_ENV=test ./scripts/generateIntrospectionResult.js"
|
||||
@@ -159,6 +160,7 @@
|
||||
"react-redux": "^4.4.5",
|
||||
"react-router": "^3.0.0",
|
||||
"react-tagsinput": "^3.17.0",
|
||||
"react-test-renderer": "15.5",
|
||||
"react-toastify": "^1.5.0",
|
||||
"react-transition-group": "^1.1.3",
|
||||
"recompose": "^0.23.1",
|
||||
@@ -179,17 +181,24 @@
|
||||
"url-search-params": "^0.9.0",
|
||||
"uuid": "^3.1.0",
|
||||
"webpack": "^2.3.1",
|
||||
"webpack-sources": "^1.0.1",
|
||||
"yaml-loader": "^0.4.0",
|
||||
"yamljs": "^0.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@coralproject/eslint-config-talk": "^0.0.3",
|
||||
"@coralproject/eslint-config-talk": "^0.0.4",
|
||||
"babel-jest": "^21.2.0",
|
||||
"babel-plugin-dynamic-import-node": "^1.1.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
|
||||
"chai": "^3.5.0",
|
||||
"chai-as-promised": "^6.0.0",
|
||||
"chai-http": "^3.0.0",
|
||||
"enzyme": "^2.9.1",
|
||||
"enzyme": "^3.0.0",
|
||||
"enzyme-adapter-react-15": "^1.0.0",
|
||||
"eslint": "^4.5.0",
|
||||
"eslint-plugin-mocha": "^4.11.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^21.2.1",
|
||||
"mocha": "^3.1.2",
|
||||
"mocha-junit-reporter": "^1.12.1",
|
||||
"nodemon": "^1.11.0",
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './styles.css';
|
||||
import {Button} from 'plugin-api/beta/client/components/ui';
|
||||
import {Button, TextField} from 'plugin-api/beta/client/components/ui';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
class ForgotContent extends React.Component {
|
||||
|
||||
state = {value: ''};
|
||||
|
||||
handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.fetchForgotPassword(this.emailInput.value);
|
||||
this.props.fetchForgotPassword(this.state.value);
|
||||
};
|
||||
|
||||
handleChangeEmail = (e) => {
|
||||
const {value} = e.target;
|
||||
this.setState({value});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {changeView, auth} = this.props;
|
||||
const {passwordRequestSuccess, passwordRequestFailure} = auth;
|
||||
@@ -20,13 +29,14 @@ class ForgotContent extends React.Component {
|
||||
</div>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className={styles.textField}>
|
||||
<label htmlFor="email">{t('sign_in.email')}</label>
|
||||
<input
|
||||
ref={(input) => (this.emailInput = input)}
|
||||
type="text"
|
||||
<TextField
|
||||
type="email"
|
||||
style={{fontSize: 16}}
|
||||
id="email"
|
||||
name="email"
|
||||
label={t('sign_in.email')}
|
||||
onChange={this.handleChangeEmail}
|
||||
value={this.state.value}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
@@ -69,4 +79,10 @@ class ForgotContent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
ForgotContent.propTypes = {
|
||||
auth: PropTypes.object,
|
||||
changeView: PropTypes.func,
|
||||
fetchForgotPassword: PropTypes.func,
|
||||
};
|
||||
|
||||
export default ForgotContent;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "@coralproject/eslint-config-talk"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
const hooks = require('./server/hooks');
|
||||
|
||||
module.exports = {
|
||||
hooks,
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "@coralproject/talk-plugin-slack-notifications",
|
||||
"pluginName": "talk-plugin-slack-notifications",
|
||||
"version": "0.0.1",
|
||||
"description": "Posts new comments to Slack via a webhook",
|
||||
"main": "index.js",
|
||||
"author": "The Coral Project Team <coral@mozillafoundation.org>",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
const config = {
|
||||
SLACK_WEBHOOK_URL: process.env.TALK_SLACK_WEBHOOK_URL,
|
||||
SLACK_WEBHOOK_TIMEOUT: process.env.TALK_SLACK_WEBHOOK_TIMEOUT || 5000,
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV !== 'test' && !config.SLACK_WEBHOOK_URL) {
|
||||
// TODO this error should point users to Talk's Slack app once that's in place
|
||||
throw new Error('Please set the TALK_SLACK_WEBHOOK_URL environment variable to use the slack-notifications plugin.');
|
||||
}
|
||||
|
||||
module.exports = config;
|
||||
@@ -0,0 +1,46 @@
|
||||
const fetch = require('node-fetch');
|
||||
const {SLACK_WEBHOOK_URL, SLACK_WEBHOOK_TIMEOUT} = require('./config');
|
||||
const debug = require('debug')('talk:plugin:slack-notifications');
|
||||
|
||||
// We don't add the hooks during _test_ as the Slack API is not available.
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
return null;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RootMutation: {
|
||||
createComment: {
|
||||
async post(_, {input}, context, _info, result) {
|
||||
debug(`Posting notification to Slack webhook: ${SLACK_WEBHOOK_URL}`);
|
||||
const {
|
||||
comment: {
|
||||
body: text,
|
||||
created_at: createdAt
|
||||
}
|
||||
} = result;
|
||||
const username = context.user.username;
|
||||
process.nextTick(async () => {
|
||||
const response = await fetch(SLACK_WEBHOOK_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
timeout: SLACK_WEBHOOK_TIMEOUT,
|
||||
body: JSON.stringify({
|
||||
attachments: [{
|
||||
text: text,
|
||||
footer: `Comment by ${username}`,
|
||||
ts: Math.floor(Date.parse(createdAt) / 1000),
|
||||
}]
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const responseText = await response.text();
|
||||
console.trace(`Posting to Slack failed with HTTP code ${response.status} and body '${responseText}'`);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "@coralproject/eslint-config-talk/client"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = 'test-file-stub';
|
||||
@@ -0,0 +1,38 @@
|
||||
import Enzyme from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-15';
|
||||
|
||||
Enzyme.configure({adapter: new Adapter()});
|
||||
|
||||
// Storage Mock
|
||||
|
||||
// TODO: Some places in our code (e.g. translations) has a hardcoded dependency
|
||||
// to the local storage. Fixing it and we can remove this global mock.
|
||||
|
||||
function storageMock() {
|
||||
let storage = {};
|
||||
|
||||
return {
|
||||
setItem: function(key, value) {
|
||||
storage[key] = value || '';
|
||||
},
|
||||
getItem: function(key) {
|
||||
return key in storage ? storage[key] : null;
|
||||
},
|
||||
removeItem: function(key) {
|
||||
delete storage[key];
|
||||
},
|
||||
get length() {
|
||||
return Object.keys(storage).length;
|
||||
},
|
||||
key: function(i) {
|
||||
let keys = Object.keys(storage);
|
||||
return keys[i] || null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// mock the localStorage
|
||||
window.localStorage = storageMock();
|
||||
|
||||
// mock the sessionStorage
|
||||
window.sessionStorage = storageMock();
|
||||
@@ -0,0 +1,8 @@
|
||||
const yaml = require('yamljs');
|
||||
|
||||
module.exports = {
|
||||
process(src) {
|
||||
const data = yaml.parse(src);
|
||||
return `module.exports = ${JSON.stringify(data)};`;
|
||||
},
|
||||
};
|
||||
+2
-1
@@ -111,7 +111,8 @@ const config = {
|
||||
new webpack.EnvironmentPlugin({
|
||||
'TALK_PLUGINS_JSON': '{}',
|
||||
'TALK_THREADING_LEVEL': '3',
|
||||
'TALK_DEFAULT_STREAM_TAB': 'all'
|
||||
'TALK_DEFAULT_STREAM_TAB': 'all',
|
||||
'TALK_DEFAULT_LANG': 'en'
|
||||
})
|
||||
],
|
||||
resolveLoader: {
|
||||
|
||||
Reference in New Issue
Block a user