Merge branch 'master' of https://github.com/coralproject/talk into reportedComments

Updating
This commit is contained in:
PepeFranco
2017-10-31 12:49:44 -06:00
16 changed files with 237 additions and 69 deletions
+7 -3
View File
@@ -4,8 +4,12 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing permissions and limitations under the License.
See the License for the specific language governing permissions
and limitations under the License.
+22 -31
View File
@@ -1,46 +1,37 @@
# Talk
# Talk · [![CircleCI](https://circleci.com/gh/coralproject/talk.svg?style=svg)](https://circleci.com/gh/coralproject/talk) · [![NSP Status](https://nodesecurity.io/orgs/coralproject/projects/07ce2e4c-99fb-48f8-b50b-69d2d2c081b8/badge)](https://nodesecurity.io/orgs/coralproject/projects/07ce2e4c-99fb-48f8-b50b-69d2d2c081b8) · [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md#pull-requests)
[![CircleCI](https://circleci.com/gh/coralproject/talk.svg?style=svg)](https://circleci.com/gh/coralproject/talk)
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](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)
[![NSP Status](https://nodesecurity.io/orgs/coralproject/projects/07ce2e4c-99fb-48f8-b50b-69d2d2c081b8/badge)](https://nodesecurity.io/orgs/coralproject/projects/07ce2e4c-99fb-48f8-b50b-69d2d2c081b8)
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).
Online comments are broken. Our open-source commenting platform, Talk, 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).
Built with <3 by The Coral Project & Mozilla.
## Getting Started
## Try Talk!
Check out our Docs: https://coralproject.github.io/talk/
You're just one click away from trying Talk - all you need is a Heroku account and a few minutes of your time.
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](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)
## Technical Documentation
From getting up and running, to advanced configuration, to how to scale Talk, our [Talk Technical Docs](https://coralproject.github.io/talk/) have everything you need to know.
## Product Guide
Learn more about Talk, including a deep dive into features for commenters and moderators, and FAQs in our [Talk Product Guide](https://coralproject.github.io/talk/how-talk-works).
## Relevant Links
- Blog: https://blog.coralproject.net/
- Community Forums: https://community.coralproject.net/
- Community Guides for Journalism: https://guides.coralproject.net/
- Project: https://coralproject.net/
- Roadmap: https://www.pivotaltracker.com/n/projects/1863625
- [Our Blog](https://blog.coralproject.net/)
- [Community Forums](https://community.coralproject.net/)
- [Community Guides for Journalism](https://guides.coralproject.net/)
- [More About Us](https://coralproject.net/)
- [Talk Roadmap](https://www.pivotaltracker.com/n/projects/1863625)
## End-to-End Testing
Talk uses [Nightwatch](http://nightwatchjs.org/) to write e2e tests. The testing infrastructure that allows us to run our tests in real browsers is provided with love by our friends at Browserstack.
Talk uses [Nightwatch](https://nightwatchjs.org/) as our e2e testing framework. The testing infrastructure that allows us to run our tests in real browsers is provided with love by our friends at [Browserstack](https://browserstack.com).
![](/public/img/browserstack_logo.png)
[![Browserstack](/public/img/browserstack_logo.png)](https://browserstack.com)
## License
Copyright 2017 Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied.
See the License for the specific language governing permissions
and limitations under the License.
Talk is released under the [Apache License, v2.0](/LICENSE).
+1 -1
View File
@@ -50,7 +50,7 @@ test:
- MOCHA_FILE=$CIRCLE_TEST_REPORTS/junit/test-results.xml MOCHA_REPORTER=mocha-junit-reporter yarn test
# Check dependancies using nsp.
- nsp check
# - yarn e2e-ci
- yarn e2e-ci
deployment:
release:
+20 -2
View File
@@ -26,18 +26,29 @@ const nightwatch_config = {
// Disable this, as it makes bs slow and brittle.
'browserstack.networkLogs': false,
}
'browserstack.resolution': '1600x1200',
},
screenshots : {
enabled: true,
on_failure: true,
on_error: true,
path: process.env.REPORTS_FOLDER || './test/e2e/reports',
},
},
chrome: {
desiredCapabilities: {
browser: 'chrome',
browser_version: '62',
os: 'Windows',
os_version: '10',
},
},
firefox: {
desiredCapabilities: {
browser: 'firefox',
browser_version: '56',
os: 'Windows',
os_version: '10',
},
},
safari: {
@@ -52,14 +63,21 @@ const nightwatch_config = {
desiredCapabilities: {
browser: 'internet explorer',
os: 'Windows',
os_version: '8.1',
os_version: '10',
browser_version: '11',
// The x64 bit IEDriver that is used by IE 11 has a known issue with sendKeys where
// it may enter incorrect keys (shift + key).
// This adds a delay for each character as temporary fix as advised from the browserstack support.
'browserstack.customSendKeys': 800,
},
},
edge: {
desiredCapabilities: {
browser: 'edge',
browser_version: '15',
os: 'Windows',
os_version: '10',
},
},
}
+4 -4
View File
@@ -9,13 +9,13 @@ module.exports = {
globals_path: './test/e2e/globals',
selenium: {
start_process: true,
server_path: 'node_modules/selenium-standalone/.selenium/selenium-server/3.5.3-server.jar',
server_path: 'node_modules/selenium-standalone/.selenium/selenium-server/3.6.0-server.jar',
log_path: './test/e2e/',
host: '127.0.0.1',
port: 6666,
cli_args: {
'webdriver.chrome.driver': 'node_modules/selenium-standalone/.selenium/chromedriver/2.32-x64-chromedriver',
'webdriver.gecko.driver': 'node_modules/selenium-standalone/.selenium/geckodriver/0.18.0-x64-geckodriver',
'webdriver.chrome.driver': 'node_modules/selenium-standalone/.selenium/chromedriver/2.33-x64-chromedriver',
'webdriver.gecko.driver': 'node_modules/selenium-standalone/.selenium/geckodriver/0.19.0-x64-geckodriver',
}
},
test_settings: {
@@ -43,7 +43,7 @@ module.exports = {
'chrome-headless': {
desiredCapabilities: {
chromeOptions : {
args: ['--headless', '--disable-gpu', 'window-size=1280,800'],
args: ['--headless', '--disable-gpu', 'window-size=1600,1200'],
},
},
},
+1 -1
View File
@@ -172,7 +172,7 @@
"redux": "^3.6.0",
"redux-thunk": "^2.1.0",
"resolve": "^1.4.0",
"selenium-standalone": "6.9.0",
"selenium-standalone": "^6.11.0",
"semver": "^5.4.1",
"simplemde": "^1.11.2",
"smoothscroll-polyfill": "^0.3.5",
+66 -11
View File
@@ -1,32 +1,87 @@
#!/bin/bash
CIRCLE_TEST_REPORTS=${CIRCLE_TEST_REPORTS:-./test/e2e/reports}
CIRCLE_BRANCH=${CIRCLE_BRANCH:-master}
# Amount of retries before failure.
E2E_MAX_RETRIES=${E2E_MAX_RETRIES:-1}
# Amount of seconds between tests.
E2E_SLEEP_BETWEEN_TESTS=${E2E_SLEEP_BETWEEN_TESTS:-1}
# Safari >= 8 has issues connecting to browserstack-local. Safari < 8 is too old.
BROWSERS="chrome firefox ie edge" #safari
if [[ "${CIRCLE_BRANCH}" == "master" ]]; then
# List of failed browsers.
failedBrowsers=
# List of succeeded browsers.
succeededBrowsers=
exitCode=0
browserstack() {
REPORTS_FOLDER="$CIRCLE_TEST_REPORTS/$1" yarn e2e-browserstack -- --env "$1"
# Current number of tries.
try=${2:-0}
echo "-- Start e2e for $1 #$try --"
REPORTS_FOLDER="$CIRCLE_TEST_REPORTS/$1" yarn e2e-browserstack --env "$1"
# Determine exit code.
result=$?
if [ "$result" -gt "0" ]
then
if [ "$result" -ne "0" ]; then
echo "-- Failed e2e for $1 #$try --"
# Try again until E2E_MAX_RETRIES is reached.
if [ "$try" -lt "$E2E_MAX_RETRIES" ]; then
let try=try+1
# Sleep a bit to let browserstack-local close properly.
sleep "$E2E_SLEEP_BETWEEN_TESTS"
browserstack "$1" "$try"
return
fi
# Failed, add to list of failed browsers.
failedBrowsers="$failedBrowsers $1"
# Remember exit code.
exitCode=$result
else
echo "-- Success e2e for $1 #$try --"
# Succeeded, add to list of succeeded browsers.
succeededBrowsers="$succeededBrowsers $1"
eval "browser_${1}_succeeded_at=$try"
fi
# Sleep a bit to let browserstack-local to close properly.
sleep 2
# Sleep a bit to let browserstack-local close properly.
sleep "$E2E_SLEEP_BETWEEN_TESTS"
}
# Test using browserstack.
browserstack chrome
browserstack firefox
browserstack ie
browserstack edge
for browser in $BROWSERS
do
browserstack "$browser"
done
# Safari >= 8 has issues connecting to browserstack-local. Safari < 8 is too old.
# browserstack safari
# Print information about succeeded browsers.
for x in $succeededBrowsers
do
echo "Succeeded $x at try #$(eval "echo \$browser_${x}_succeeded_at")"
done
# Print information about failed browsers.
for x in $failedBrowsers
do
echo "Failed $x"
done
exit $exitCode
else
# When browserstack is not available test locally using chrome headless.
+1
View File
@@ -0,0 +1 @@
<%= body.replace(/\n/g, '<br />') %>
+1
View File
@@ -0,0 +1 @@
<%= body %>
+20 -1
View File
@@ -398,7 +398,7 @@ module.exports = class UsersService {
// TODO: current updating status behavior is weird.
// once a user has been `APPROVED` its status cannot be
// changed anymore.
return UserModel.findOneAndUpdate({
const user = await UserModel.findOneAndUpdate({
id,
status: {
$ne: 'APPROVED'
@@ -410,6 +410,25 @@ module.exports = class UsersService {
}, {
new: true,
});
if (status === 'BANNED') {
let localProfile = user.profiles.find((profile) => profile.provider === 'local');
if (localProfile) {
const options =
{
template: 'banned', // needed to know which template to render!
locals: { // specifies the template locals.
body: 'In accordance with The Coral Projects community guidelines, your account has been banned. You are now longer allowed to comment, flag or engage with our community.'
},
subject: 'Your account has been banned',
to: localProfile.id // This only works if the user has registered via e-mail.
// We may want a standard way to access a user's e-mail address in the future
};
await MailerService.sendSimple(options);
}
}
return user;
}
/**
+7
View File
@@ -8,6 +8,11 @@ module.exports = {
},
getEmbedSection: function() {
this.waitForElementVisible('@iframe');
// Pause a bit to let iframe initialize in the hope that it'll
// fix https://www.browserstack.com/automate/builds/96419cf46e3d6376a36ae6d3f90934112df1ed91/sessions/224f1a1566c1c8c7859e2e76ece51862200f0173#automate_button
this.api.pause(200);
this.api.frame(iframeId);
this.expect.section('@embed').to.be.present;
return this.section.embed;
@@ -23,11 +28,13 @@ module.exports = {
embed: {
commands: [{
getProfileSection: function() {
this.waitForElementVisible('@profileTabButton');
this.click('@profileTabButton');
this.expect.section('@profile').to.be.present;
return this.section.profile;
},
getCommentsSection: function() {
this.waitForElementVisible('@commentsTabButton');
this.click('@commentsTabButton');
this.expect.section('@comments').to.be.present;
return this.section.comments;
+2 -4
View File
@@ -1,9 +1,9 @@
module.exports = {
'@tags': ['admin', 'login'],
beforeEach: (client) => {
client.resizeWindow(1024, 800);
},
},
'Admin logs in': (client) => {
const adminPage = client.page.admin();
const {testData: {admin}} = client.globals;
@@ -17,8 +17,6 @@ module.exports = {
.waitForElementVisible('@signInButton')
.click('@signInButton');
client.pause(3000);
adminPage
.waitForElementVisible('@moderationContainer');
},
+21 -7
View File
@@ -1,3 +1,5 @@
const SortedWindowHandler = require('../utils/SortedWindowHandler');
module.exports = {
'@tags': ['embedStream', 'login'],
'creates a new asset': (client) => {
@@ -18,16 +20,19 @@ module.exports = {
.navigate()
.getEmbedSection();
const windowHandler = new SortedWindowHandler(client);
embed
.waitForElementVisible('@signInButton')
.click('@signInButton');
client.pause(3000);
// Wait for window to be created
// https://www.browserstack.com/automate/builds/1ceccf4efb4683b7feb890f45a32b5922b40ed3f/sessions/17b1a79682bef2498cb0be86eac317a08c976b0a#automate_button
client.pause(200);
// Focusing on the Login PopUp
client.windowHandles((result) => {
const handle = result.value[1];
client.switchWindow(handle);
windowHandler.windowHandles((handles) => {
client.switchWindow(handles[1]);
});
const login = client.page.login();
@@ -45,10 +50,19 @@ module.exports = {
.waitForElementVisible('@loginButton')
.click('@loginButton');
// Give a tiny bit of time to let popup close.
client.pause(50);
if (client.capabilities.browserName === 'MicrosoftEdge') {
// More time for edge.
// https://www.browserstack.com/automate/builds/1ceccf4efb4683b7feb890f45a32b5922b40ed3f/sessions/7393dbfda8387e43b6d5851f359b0c07db414973
client.pause(1000);
}
// Focusing on the Embed Window
client.windowHandles((result) => {
const handle = result.value[0];
client.switchWindow(handle);
windowHandler.windowHandles((handles) => {
client.switchWindow(handles[0]);
});
},
'user posts a comment': (client) => {
+41
View File
@@ -0,0 +1,41 @@
/**
* SortedWindowHandler assists in making e2e tests more robust by returning
* deterministic window handles. An instance must be created before new windows
* are created and windowHandles must be called each time a window was created or
* closed.
*/
class SortedWindowHandler {
/**
* Constructor, must be called before new windows were created.
*/
constructor(client) {
this.client = client;
this.client.windowHandles((result) => {
this.handles = result.value;
if (this.handles.length > 2) {
throw new Error('SortedWindowHandler must be created before new windows were created.');
}
});
}
/**
* windowHandles will call given `callback` with an array of window handles.
*/
windowHandles(callback) {
this.client.windowHandles((result) => {
this.handles = this.handles.filter((handle) => result.value.includes(handle));
const remaining = result.value.filter((handle) => !this.handles.includes(handle));
if (remaining.length === 1) {
this.handles.push(remaining[0]);
}
if (remaining.length > 1) {
throw new Error('Cannot detect new window handle, because more than one windows was created.');
}
callback(this.handles);
});
}
}
module.exports = SortedWindowHandler;
+20 -1
View File
@@ -1,8 +1,11 @@
const UsersService = require('../../../services/users');
const SettingsService = require('../../../services/settings');
const MailerService = require('../../../services/mailer');
const chai = require('chai');
chai.use(require('chai-as-promised'));
const sinon = require('sinon');
chai.use(require('sinon-chai'));
const expect = chai.expect;
describe('services.UsersService', () => {
@@ -15,7 +18,7 @@ describe('services.UsersService', () => {
mockUsers = await UsersService.createLocalUsers([{
email: 'stampi@gmail.com',
username: 'Stampi',
password: '1Coral!-'
password: '1Coral!-',
}, {
email: 'sockmonster@gmail.com',
username: 'Sockmonster',
@@ -25,6 +28,12 @@ describe('services.UsersService', () => {
username: 'Marvel',
password: '3Coral!3'
}]);
sinon.spy(MailerService, 'sendSimple');
});
afterEach(() => {
MailerService.sendSimple.restore();
});
describe('#findById()', () => {
@@ -149,7 +158,11 @@ describe('services.UsersService', () => {
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('status', 'ACTIVE');
})
.then(() => {
expect(MailerService.sendSimple).to.not.have.been.called;
});
});
});
@@ -188,6 +201,12 @@ describe('services.UsersService', () => {
.then(() => UsersService.findById(mockUsers[0].id))
.then((user) => {
expect(user).to.have.property('status', 'BANNED');
})
.then(() => {
expect(MailerService.sendSimple).to.have.been.calledWithMatch({
template: 'banned',
to: mockUsers[0].profiles[0].id
});
});
});
+3 -3
View File
@@ -7953,9 +7953,9 @@ select@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
selenium-standalone@6.9.0:
version "6.9.0"
resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.9.0.tgz#5805f403c82b48b4e136d8a97f1832aad7852bd5"
selenium-standalone@^6.11.0:
version "6.11.0"
resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.11.0.tgz#eb21ff65f3b2ece75061b35d4f9e7572ac0280c2"
dependencies:
async "^2.1.4"
commander "^2.9.0"