Commit 74ef0991 authored by Andrew Newdigate's avatar Andrew Newdigate

Merge branch 'develop' of github.com:troupe/gitter-webapp into develop

parents 1cc92bf2 e5f8efc8
......@@ -9,21 +9,18 @@ All rights reserved.
Please symlink pre-commit to .git/hooks/pre-commit to enable the pre-commit hooks.
Prerequisites
-------------
* node.js 0.10+ `brew install node`
* [Virtualbox](https://www.virtualbox.org/wiki/Downloads)
* [Kitematic](https://kitematic.com/) or `boot2docker` if you prefer
Getting Started
---------------
2. Open Kitematic and choose "Install Docker Commands" from the application menu.
3. In the root directory of the project run `./start` to start your services
4. `npm install`
5. `npm install -g gulp`
6. `gulp css` (compiles css)
7. `npm install -g nodemon`
8. `nodemon` (this will run node and restart when anything changes based on config in nodemon.json)
1. install prerequisites:
* kitematic, not docker-for-mac (it is incompatible with our start script)
* node js
* gulp (via npm)
2. run `./start` to download and start all the docker images for our databases
3. run `npm install`
4. run `npm run link` (you will get weird errors if you dont)
5. run `gulp`
6. run `node web` and go to localhost:5000
Data Upgrades
-------------
......
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure(2) do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
config.vm.box = "ubuntu/trusty64"
config.vm.box_url = "https://oss-binaries.phusionpassenger.com/vagrant/boxes/latest/ubuntu-14.04-amd64-vbox.box"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
config.vm.network "forwarded_port", guest: 5000, host: 5000
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
config.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
config.vm.provider "virtualbox" do |vb|
# Display the VirtualBox GUI when booting the machine
vb.gui = true
# Customize the amount of memory on the VM:
vb.memory = 2048
vb.cpus = 2
end
#
# View the documentation for the provider you are using for more
# information on available options.
# Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
# such as FTP and Heroku are also available. See the documentation at
# https://docs.vagrantup.com/v2/push/atlas.html for more information.
# config.push.define "atlas" do |push|
# push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
# end
# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
# config.vm.provision "shell", inline: <<-SHELL
# sudo apt-get update
# sudo apt-get install -y apache2
# SHELL
config.vm.provision "shell", path: "vagrant_provision.sh"
end
......@@ -66,8 +66,10 @@ mongosetup:
entrypoint: [ "/src/scripts/docker/mongo/mongo-setup.sh" ]
neo4j:
image: kbastani/docker-neo4j
image: neo4j:2.3.0
restart: always
environment:
NEO4J_AUTH: none
elasticsearch:
image: elasticsearch:1.4.2
......
......@@ -75,10 +75,12 @@ mongosetup:
entrypoint: [ "/src/scripts/docker/mongo/mongo-setup.sh" ]
neo4j:
image: kbastani/docker-neo4j
image: neo4j:2.3
restart: always
ports:
- "7474:7474"
environment:
NEO4J_AUTH: none
# The official elasticsearch:1.4.2 image with mapper-attachments and river-mongodb plugins
# https://github.com/soldotno/elasticsearch-river-mongodb/blob/master/Dockerfile
......
......@@ -24,6 +24,7 @@ var ForumCategorySchema = new Schema({
slug: { type: String, required: true },
forumId: { type: ObjectId, required: true },
order: { type: Number, "default": DEFAULT_CATEGORY_ORDER, required: false },
adminOnly: { type: Boolean },
_tv: { type: 'MongooseNumber', 'default': 0 },
}, { strict: "throw" });
......
......@@ -16,7 +16,8 @@ function createCategory(fixtureName, f) {
name: name,
slug: f.slug || slugify(name),
forumId: f.forum && f.forum._id,
order: f.order
order: f.order,
adminOnly: f.adminOnly
};
debug('Creating forum category %s with %j', fixtureName, doc);
......
......@@ -20,6 +20,7 @@ function createMessage(fixtureName, f) {
meta: f.meta,
sent: f.sent,
editedAt: f.editedAt,
pub: f.pub || false,
readBy: f.readBy,
});
}
......
......@@ -12,7 +12,7 @@ describe('forum-notification-events', function() {
describe('integration tests #slow', function() {
describe('notificationObserver multi', function() {
describe('notificationObserver with multiple events', function() {
var fixture = fixtureLoader.setup({
user1: {},
user2: {},
......@@ -41,7 +41,7 @@ describe('forum-notification-events', function() {
},
});
it('should raise notifications', function() {
it('should batch the notifications in order', function() {
var userId = fixture.user1._id;
var forumId = fixture.forum1._id;
......@@ -68,23 +68,21 @@ describe('forum-notification-events', function() {
})
.then(function(notifications) {
assert.strictEqual(notifications.length, 3);
// first is topic 1
assert.strictEqual(String(notifications[0].recipient._id), String(userId));
assert.strictEqual(notifications[0].data.forum.id, String(forumId));
assert.strictEqual(notifications[0].data.topic.id, String(topicId1));
assert.strictEqual(notifications[0].data.reply, undefined);
// second is topic 2
assert.strictEqual(String(notifications[1].recipient._id), String(userId));
assert.strictEqual(notifications[1].data.forum.id, String(forumId));
assert.strictEqual(notifications[1].data.topic.id, String(topicId2));
assert.strictEqual(notifications[1].data.reply, undefined);
// last is reply1
assert.strictEqual(String(notifications[2].recipient._id), String(userId));
assert.strictEqual(notifications[2].data.forum.id, String(forumId));
assert.strictEqual(notifications[2].data.topic.id, String(topicId1));
assert(!notifications[0].data.reply);
assert(!notifications[1].data.reply);
assert.strictEqual(notifications[2].data.reply.id, String(replyId));
notifications.forEach(function(notification) {
// Check that the user matches
assert.strictEqual(String(notification.recipient._id), String(userId));
// Check that the forum matches
assert.strictEqual(notification.data.forum.id, String(forumId));
});
});
});
});
......
......@@ -7,21 +7,21 @@ function AggregatedCommentStrategy() {
}
AggregatedCommentStrategy.prototype = {
map: function(item, authorUser, owningComment, owningTopic, owningForum) {
map: function(reply, authorUser, owningComment, owningTopic, owningForum) {
var owningTopicId = owningTopic.id || (owningTopic._id && owningTopic._id.toHexString());
return {
id: item.id || item._id && item._id.toHexString(),
id: reply.id || reply._id && reply._id.toHexString(),
body: {
text: item.text,
html: item.html
text: reply.text,
html: reply.html
},
user: this.userStrategy.map(authorUser),
sent: item.sent,
editedAt: item.editedAt,
sent: reply.sent,
editedAt: reply.editedAt,
// TODO: permalink?
uri: owningForum.uri + '/topic/' + owningTopicId + '/' + item.slug
uri: owningForum.uri + '/topic/' + owningTopicId + '/' + owningTopic.slug
};
},
......
......@@ -4,12 +4,12 @@ function AggregatedForumStrategy() {
}
AggregatedForumStrategy.prototype = {
map: function(item) {
map: function(forum) {
return {
id: item.id || item._id && item._id.toHexString(),
name: item.name,
uri: item.uri,
tags: item.tags
id: forum.id || forum._id && forum._id.toHexString(),
name: forum.name,
uri: forum.uri,
tags: forum.tags
};
},
......
......@@ -7,26 +7,26 @@ function AggregatedReplyStrategy() {
}
AggregatedReplyStrategy.prototype = {
map: function(item, authorUser, owningTopic, owningForum) {
map: function(reply, authorUser, owningTopic, owningForum) {
var owningTopicId = owningTopic.id || (owningTopic._id && owningTopic._id.toHexString());
return {
id: item.id || item._id && item._id.toHexString(),
id: reply.id || reply._id && reply._id.toHexString(),
body: {
text: item.text,
html: item.html,
text: reply.text,
html: reply.html,
},
user: this.userStrategy.map(authorUser),
commentsTotal: item.commentsTotal,
sent: item.sent,
editedAt: item.editedAt,
lastChanged: item.lastChanged,
lastModified: item.lastModified,
commentsTotal: reply.commentsTotal,
sent: reply.sent,
editedAt: reply.editedAt,
lastChanged: reply.lastChanged,
lastModified: reply.lastModified,
// TODO: permalink?
uri: owningForum.uri + '/topic/' + owningTopicId + '/' + item.slug
uri: owningForum.uri + '/topic/' + owningTopicId + '/' + owningTopic.slug
};
},
......
......@@ -7,29 +7,29 @@ function AggregatedTopicStrategy() {
}
AggregatedTopicStrategy.prototype = {
map: function(item, authorUser, owningForum) {
var id = item.id || item._id && item._id.toHexString();
map: function(topic, authorUser, owningForum) {
var id = topic.id || topic._id && topic._id.toHexString();
return {
id: id,
title: item.title,
slug: item.slug,
title: topic.title,
slug: topic.slug,
body: {
text: item.text,
html: item.html,
text: topic.text,
html: topic.html,
},
sticky: item.sticky,
tags: item.tags,
sticky: topic.sticky,
tags: topic.tags,
// category: this.mapCategory(topic.categoryId), Deal with Category
user: this.userStrategy.map(authorUser),
repliesTotal: item.repliesTotal,
sent: item.sent,
editedAt: item.editedAt,
lastChanged: item.lastChanged,
lastModified: item.lastModified,
repliesTotal: topic.repliesTotal,
sent: topic.sent,
editedAt: topic.editedAt,
lastChanged: topic.lastChanged,
lastModified: topic.lastModified,
// TODO: permalink?
uri: owningForum.uri + '/topic/' + id + '/' + item.slug
uri: owningForum.uri + '/topic/' + id + '/' + topic.slug
}
},
......
"use strict";
var assert = require('assert');
var fixtureLoader = require('gitter-web-test-utils/lib/test-fixtures');
var Strategy = require('../lib/notifications/aggregated-comment-strategy');
var assertStringifiedEqual = require('./assert-stringified-equal');
describe('aggregated-comment-strategy', function() {
var fixture = fixtureLoader.setup({
user: {},
forum: {},
category: {
forum: 'forum',
},
topic: {
user: 'user',
forum: 'forum',
category: 'category',
sent: new Date('2014-01-01T00:00:00.000Z')
},
reply: {
forum: 'forum',
category: 'category',
user: 'user',
topic: 'topic',
sent: new Date('2014-02-01T00:00:00.000Z')
},
comment1: {
forum: 'forum',
user: 'user',
topic: 'topic',
reply: 'reply',
sent: new Date('2014-03-01T00:00:00.000Z')
}
});
it('serializes correctly', function () {
var strategy = new Strategy();
var user = fixture.user;
var forum = fixture.forum;
var topic = fixture.topic;
var reply = fixture.reply;
var comment = fixture.comment;
var result = strategy.map(reply, user, comment, topic, forum);
assert.equal(result.user.id, user._id);
// dont bother testing the user serializer, just check that the user is there
delete result.user;
assertStringifiedEqual(result, {
id: reply._id,
body: {},
sent: "2014-02-01T00:00:00.000Z",
editedAt: null,
uri: forum.uri + "/topic/" + topic._id + "/" + topic.slug
});
});
});
"use strict";
var fixtureLoader = require('gitter-web-test-utils/lib/test-fixtures');
var Strategy = require('../lib/notifications/aggregated-forum-strategy');
var assertStringifiedEqual = require('./assert-stringified-equal');
describe('aggregated-forum-strategy', function() {
var fixture = fixtureLoader.setup({
forum: {}
});
it('serializes correctly', function () {
var strategy = new Strategy();
var forum = fixture.forum;
var result = strategy.map(forum);
assertStringifiedEqual(result, {
id: forum._id,
name: forum.name,
uri: forum.uri,
tags: []
});
});
});
"use strict";
var assert = require('assert');
var fixtureLoader = require('gitter-web-test-utils/lib/test-fixtures');
var Strategy = require('../lib/notifications/aggregated-reply-strategy');
var assertStringifiedEqual = require('./assert-stringified-equal');
describe('aggregated-reply-strategy', function() {
var fixture = fixtureLoader.setup({
user: {},
forum: {},
category: {
forum: 'forum',
},
topic: {
user: 'user',
forum: 'forum',
category: 'category',
sent: new Date('2014-01-01T00:00:00.000Z')
},
reply: {
forum: 'forum',
category: 'category',
user: 'user',
topic: 'topic',
sent: new Date('2014-02-01T00:00:00.000Z')
}
});
it('serializes correctly', function () {
var strategy = new Strategy();
var user = fixture.user;
var forum = fixture.forum;
var topic = fixture.topic;
var reply = fixture.reply;
var result = strategy.map(reply, user, topic, forum);
assert.equal(result.user.id, user._id);
// dont bother testing the user serializer, just check that the user is there
delete result.user;
assertStringifiedEqual(result, {
id: reply._id,
body: {},
commentsTotal: 0,
sent: "2014-02-01T00:00:00.000Z",
editedAt: null,
lastChanged: "2014-02-01T00:00:00.000Z",
lastModified: "2014-02-01T00:00:00.000Z",
uri: forum.uri + "/topic/" + topic._id + "/" + topic.slug
});
});
});
"use strict";
var assert = require('assert');
var fixtureLoader = require('gitter-web-test-utils/lib/test-fixtures');
var Strategy = require('../lib/notifications/aggregated-topic-strategy');
var assertStringifiedEqual = require('./assert-stringified-equal');
describe('aggregated-topic-strategy', function() {
var fixture = fixtureLoader.setup({
user: {},
forum: {},
category: {
forum: 'forum',
},
topic: {
user: 'user',
forum: 'forum',
category: 'category',
sent: new Date('2014-01-01T00:00:00.000Z')
}
});
it('serializes correctly', function () {
var strategy = new Strategy();
var user = fixture.user;
var forum = fixture.forum;
var topic = fixture.topic;
var result = strategy.map(topic, user, forum);
assert.equal(result.user.id, user._id);
// dont bother testing the user serializer, just check that the user is there
delete result.user;
assertStringifiedEqual(result, {
id: topic._id,
title: topic.title,
slug: topic.slug,
body: {},
sticky: 0,
tags: [],
repliesTotal: 0,
sent: "2014-01-01T00:00:00.000Z",
editedAt: null,
lastChanged: "2014-01-01T00:00:00.000Z",
lastModified: "2014-01-01T00:00:00.000Z",
uri: forum.uri + "/topic/" + topic._id + "/" + topic.slug
});
});
});
"use strict";
var assert = require('assert');
function assertStringifiedEqual(value, expected) {
assert.strictEqual(
JSON.stringify(value, null, ' '),
JSON.stringify(expected, null, ' '));
}
module.exports = assertStringifiedEqual;
......@@ -5,6 +5,7 @@ import { subscribe } from '../../../shared/dispatcher';
import {getIsSignedIn} from '../stores/current-user-store';
import frameUtils from 'gitter-web-frame-utils';
import { NAVIGATE_TO_FORUMS } from '../../../shared/constants/forum';
import * as navConstants from '../../../shared/constants/navigation';
import * as forumCatConstants from '../../../shared/constants/forum-categories';
import * as forumFilterConstants from '../../../shared/constants/forum-filters';
......@@ -29,6 +30,7 @@ var Router = Backbone.Router.extend({
constructor: function() {
this.model = new RouteModel();
subscribe(NAVIGATE_TO_FORUMS, this.navigateToForums, this);
subscribe(forumCatConstants.NAVIGATE_TO_CATEGORY, this.updateForumCategory, this);
subscribe(forumFilterConstants.NAVIGATE_TO_FILTER, this.updateForumFilter, this);
subscribe(forumTagConstants.NAVIGATE_TO_TAG, this.updateForumTag, this);
......@@ -109,20 +111,6 @@ var Router = Backbone.Router.extend({
window.scrollTo(0, 0);
},
navigateToCreateTopic(data) {
const { source } = data;
if(getIsSignedIn()) {
const groupUri = this.model.get('groupUri');
this.navigate(`/${groupUri}/topics/create-topic/~topics`, { trigger: true });
}
else {
requestSignIn(source);
return;
}
},
updateForumCategory(data){
var url = this.buildForumUrl(data.category);
this.navigate(url, { trigger: true });
......@@ -151,6 +139,25 @@ var Router = Backbone.Router.extend({
this.model.trigger(forumSortConstants.UPDATE_ACTIVE_SORT, { sort: val });
},
navigateToForums() {
var url = this.buildForumUrl();
this.navigate(url, { trigger: true });
},
navigateToCreateTopic(data) {
const { source } = data;
if(getIsSignedIn()) {
const groupUri = this.model.get('groupUri');
this.navigate(`/${groupUri}/topics/create-topic/~topics`, { trigger: true });
}