Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Activity Streams Boilerplate App Part 3 #4

Merged
merged 60 commits into from Sep 12, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
1497600
Fix to be able to use MongoLab
Aug 4, 2012
4216be3
Merge branch 'master' of github.com:ciberch/node-activities-boilerpla…
Aug 4, 2012
aff18ec
Changes to support offline mode
Aug 19, 2012
86228b1
Modal and Create Activity
Aug 19, 2012
550c923
Before backbone
Aug 23, 2012
efe3881
Bump version of activity-streams-mongoose
Aug 24, 2012
78d43c2
Defaults for Backbone Models - still not sure if I like having to def…
Aug 24, 2012
28e591c
Link the new activity-streams-mongoose which supports location. Testi…
Aug 24, 2012
d3c479f
Use a Backbone View for the activity list
Aug 25, 2012
637de99
Fix for bad glyphicons paths
Aug 25, 2012
573739f
Like event not firing yet
Aug 25, 2012
bf9766d
In progress synching via backbone models via socket.io
Aug 29, 2012
79246d7
Add user friendly date
Aug 29, 2012
b5417fd
Remove separator because it messes up with filters
Aug 30, 2012
0135d8e
Add a photo upload form to test with
Aug 30, 2012
041419c
Woohoo endpoints to upload and download pics via Mongo Grid. TODO: Ad…
Aug 30, 2012
0b08a50
Sample JSON response for stream
Aug 30, 2012
507c006
Make it work on Cloud Foundry
Aug 31, 2012
4673fca
Add GUIDs so there are no conflicts with file names
Aug 31, 2012
f16962a
ImageMagick never ceases to impress me - This is an initial commit wh…
Aug 31, 2012
e980d64
Cleanup code for photo ingestion
Aug 31, 2012
60f6ecc
Added code to resize to sm and xs using ImageMagick
Aug 31, 2012
7fa299f
Only authenticated users can upload photos
Aug 31, 2012
0569f6e
fix deprecation warning
Aug 31, 2012
a07f221
Switch to use Mongoose Auth so we persist the users
Sep 1, 2012
4be5e4b
Display a user friendly date
Sep 2, 2012
003a039
Use Backbone's model events for triggering re render of view. Leverag…
Sep 2, 2012
42d27c0
Lock down the everyauth gem to 2.x to it works with Mongoose-Auth
Sep 2, 2012
9471b92
Mongoose-Auth now fully working and saving common attributes to db
Sep 2, 2012
6cff8af
In case there is no object
Sep 5, 2012
109e12c
Use the new version of activity-streams-mongoose
Sep 5, 2012
fa5060a
Refactor MongoDB use to a separate module
Sep 5, 2012
fdc6b4c
Further cleanup to encapsulate all the asms logic
Sep 5, 2012
acc5f61
Normalized the data from the 3 different providers
Sep 5, 2012
3cc5c59
Reduce the number of start activities
Sep 5, 2012
10f7a4e
Make it Cloud Foundry ready
Sep 5, 2012
db37380
Get the user location from Twitter and Email from Facebook
Sep 7, 2012
8001e2d
Add validator for model
Sep 10, 2012
d353fc1
Reduce the number of options so I dont have to create so many jade te…
Sep 10, 2012
11df1c0
Use a more specific message so we can add handling other types of mes…
Sep 10, 2012
de83bb5
Use the latest activity-stream-mongoose module and shrinkwrap it to l…
Sep 10, 2012
2fb0314
Change the activity create form to render client side via Backbone so…
Sep 10, 2012
79af1d0
Handle trimming strings directly
Sep 10, 2012
5dba60e
Bubble up errors reading the stream and add more .js files to get min…
Sep 10, 2012
598a00e
Move the check for the user being logged in to index.jade
Sep 10, 2012
df9703a
Make it clear to users that they can also sign up with Twitter, Faceb…
Sep 10, 2012
8b8ba0f
Make the name only show on hover
Sep 10, 2012
48a0ed6
New jade templates for object types used in this app
Sep 10, 2012
fbd7263
New file to submit the photos via ajax
Sep 10, 2012
89e5b4b
Update default backbone sync to use socket.io and replace activity cr…
Sep 10, 2012
deb8ef6
Compiled jade and how to generate it
Sep 10, 2012
b3b2445
No need for that
Sep 10, 2012
4fb1255
Switch to using regular MongoDB now in version 2.0
Sep 11, 2012
0d5bd62
Fixed bug with object Types and actor types
Sep 11, 2012
835dabe
New grpahics
Sep 11, 2012
29334c8
New hero unit look and better photo uploader
Sep 11, 2012
d91081c
Better Sizes
Sep 11, 2012
f47c6da
Better instructions
Sep 11, 2012
2522723
Fix to align Like and Post button better as well as Timestamp
Sep 11, 2012
333378c
Switch to have filters which query the backend
Sep 11, 2012
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile
@@ -0,0 +1,6 @@
TESTS = $(shell find test/ -name '*.tobi.js' -o -name '*.test.js')

test:
@node_modules/.bin/mocha --reporter spec $(TESTS)

.PHONY: test
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -34,6 +34,13 @@ npm install
```

* Edit siteConfig.js if needed
* If you change the activities templates you need to regenerate the client side version of them, you can do this with `clientjade`

```bash
npm install -g clientjade
clientjade views/*.* > public/js/templates.js
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compile all jade templates into one js file for client side rendering

```

* Run locally

``` bash
Expand Down Expand Up @@ -80,6 +87,7 @@ vmc env-add $APP_NAME facebook_app_secret=fb_secret
vmc env-add $APP_NAME NODE_ENV=production
vmc env-add $APP_NAME twitter_consumer_key=twitter_key
vmc env-add $APP_NAME twitter_consumer_secret=twitter_secret
vmc env-add $APP_NAME TMP=tmp
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used by https://github.com/felixge/node-formidable which is used for processing uploaded photos

```

## Finally
Expand Down
1 change: 1 addition & 0 deletions cloudfoundry.json
@@ -0,0 +1 @@
{ "ignoreNodeModules" : true }
198 changes: 198 additions & 0 deletions lib/asms-client.js
@@ -0,0 +1,198 @@
module.exports = function(app, cf) {
var https = require('https');

var getUri = function(path) {
return app.siteConf.uri + path;
}

var defaultStream = "firehose";

// Setup the Asms DB and User Schema and Auth
var defaultAvatar = getUri('/img/codercat-sm.jpg');

var actorTypes = ['Person', 'Group', 'Application', 'Service'];
var objectTypes = ['Photo', 'Application', 'Article', 'Person', 'Place', 'Service'];
var verbs = ['Post', 'Favorite', 'Follow', 'Join', 'Like', 'Friend', 'Play', 'Save', 'Share', 'Tag', 'Create', 'Update', 'Read', 'Delete', 'Check In'];

var githubHash = {objectType: 'Service', displayName: 'GitHub', url: 'http://github.com', icon : {url: 'http://github.com/favicon.ico'}};
var facebookHash = {objectType: 'Service', displayName: 'Facebook', url: 'http://facebook.com', icon : {url: 'http://facebook.com/favicon.ico'}};
var twitterHash = {objectType: 'Service', displayName: 'Twitter', url: 'http://twitter.com', icon : {url: 'http://twitter.com/favicon.ico'}};

var streamLib = require('activity-streams-mongoose')({
mongoUrl: app.siteConf.mongoUrl,
redis: app.siteConf.redisOptions,
defaultActor: defaultAvatar
});

var authentication = new require('./authentication.js')(streamLib, app.siteConf);

// Moved normalization to only be done on pre save
streamLib.types.UserSchema.pre('save', function (next) {
var user = this;
var svcUrl = null;
if (user.fb && user.fb.id) {
user.displayName = user.fb.name.full;
asmsDB.ActivityObject.findOne().where('url', facebookHash.url).exec(function(err, doc){
if (err) throw err;
user.author = doc._id;
// Need to fetch the users image...
https.get({
'host': 'graph.facebook.com'
, 'path': '/me/picture?access_token='+ user.fb.accessToken
}, function(response) {
user.image = {url: response.headers.location};
next();
}).on('error', function(e) {
next();
});
})
} else {
if (user.github && user.github.id) {
user.displayName = user.github.name;
var avatar = 'http://1.gravatar.com/avatar/'+ user.github.gravatarId + '?s=48'
user.image = {url: avatar};
svcUrl = githubHash.url;
} else if (user.twit && user.twit.id) {
if (user.twit.geoEnabled && user.twit.location){
//"ÜT: 34.075755,-118.393416"
var parts = user.twit.location.substr(4).split(',');
user.location = {position: {latitude: parts[0],longitude: parts[1]}};
}
user.displayName = user.twit.name;
user.image = {url: user.twit.profileImageUrl};
user.url = user.twit.url;
svcUrl = twitterHash.url;
}

if(!user.actor) {
asmsDB.ActivityObject.findOne().where('url', svcUrl).exec(function(err, doc){
user.author = doc;
next();
});
} else {
next();
}
}
});

var asmsDB = new streamLib.DB(streamLib.db, streamLib.types);
streamLib.asmsDB = asmsDB;

// Setup default Objects
// TODO: Change to find or create by
var thisInstance = {objectType : "AppInstance"};
if (cf.app) {
thisInstance.image = {url: getUri('/img/cf-process.jpg')};
thisInstance.url = "http://" + cf.host + ":" + cf.port;
thisInstance.displayName = "App Instance " + cf.app['instance_index'] + " at " + thisInstance.url;
thisInstance.content = cf.app['instance_id']
} else {
thisInstance.displayName = "Instance 0 -- Local";
}

var appOwner = {displayName: app.siteConf.user_email, image:{url: getUri("/img/me.jpg")}};

var thisApp = new asmsDB.ActivityObject({
objectType: 'Application',
displayName: 'Activity Streams App',
url: app.siteConf.uri,
image:{url: getUri('/img/as-logo-sm.png')}
});

thisApp.save(function (err) {
if (err) throw err;
});

var thisProvider = new asmsDB.ActivityObject({
objectType: 'Service',
'displayName': 'Cloud Foundry',
icon:{url: 'http://www.cloudfoundry.com/images/favicon.ico'}
});
thisProvider.save(function(err){if (err) throw err});

var github = new asmsDB.ActivityObject(githubHash);
github.save(function(err){if (err) throw err});
var facebook = new asmsDB.ActivityObject(facebookHash);
facebook.save(function(err){if (err) throw err});
var twitter = new asmsDB.ActivityObject(twitterHash);
twitter.save(function(err){if (err) throw err});

var getCurrentUserObject = function(session) {
if (session.user) {
return session.user;
} else if(session.uid) {
var currentUser = {};
currentUser.displayName = session.uid;
currentUser.image = { url: defaultAvatar};
return currentUser;
}
return null;
}

var publishActivity = function(desiredStream, currentUser, actHash) {

if (!currentUser) throw("Cannot publish activity without an actor");
if (actHash && actHash.object && actHash.object.objectType && actHash.verb) {
actHash.actor = currentUser;

if (!actHash.title) {
actHash.title = actHash.verb + "ed a new " + actHash.object.objectType;
}

var act = new asmsDB.Activity(actHash);
// Send back the message to the users room.
act.publish(desiredStream);
} else {
console.log("Missing required parameters");
console.log(actHash);
throw(new Error("Missing required parameters"));
}
};

var getDistinct = function (req, res, next, term, init){
var key = 'used.' + term;
req[key] = init ? init : [];
asmsDB.Activity.distinct(term, {streams: req.session.desiredStream}, function(err, docs) {
if (!err && docs) {
_.each(docs, function(result){
req[key].push(result);
});
next();
} else {
next(new Error('Failed to fetch distinct ' + term));
}
});
}

return {
helpers: {
getUri: getUri,
getCurrentUserObject : getCurrentUserObject,
publishActivity : publishActivity,
getDistinct : getDistinct
},
default :{
owner: appOwner,
provider : thisProvider,
app: thisApp,
instance: thisInstance,
avatar: defaultAvatar,
stream : defaultStream
},
users : {
providers :{
facebook: facebook,
twitter: twitter,
github : github
}
},
streamLib : streamLib,
asmsDB: asmsDB,
authentication : authentication,
metadata: {
actorTypes: actorTypes,
objectTypes: objectTypes,
verbs: verbs
}
}
};