diff --git a/.gitignore b/.gitignore
index ade4e05..294b748 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,5 +5,6 @@ npm-debug.log
node_modules/
public/lib
app/tests/coverage/
+config/env
.bower-*/
-.idea/
\ No newline at end of file
+.idea/
diff --git a/Extended Keynotes b/Extended Keynotes
new file mode 100644
index 0000000..159d6b9
--- /dev/null
+++ b/Extended Keynotes
@@ -0,0 +1,48 @@
+Extended Keynotes and illistrators
+
+openwork
+ project
+ - create project
+ list notes
+ note
+ - create notes
+ profile
+ notifications
+ sign up
+ save email
+ tour
+ 1/7 what are projects for?
+ - share what you're working on in public
+ - a single space to talk about your community's ideas & feedback
+ - invite friends to work on projects with you
+ - let new homies dig into your work and collaborate right away
+ - see example
+ - see another example
+ 2/7 strt first project
+ - title
+ - sub-title
+ - description
+ - start
+ 3/7 invite people to project by email
+ - input
+ - add
+ 4/7 follow other projects
+ - project
+ - name
+ - description
+ - user
+ - follow button
+ 5/7 what is activity?
+ - here's your activity
+ - here's other activity
+ 6/7 make first post
+ - input
+ 7/7 follow other people
+ - person
+ - name
+ - bio
+ - follow button
+ end on profile
+
+portfolio
+ home (projects, contact)
\ No newline at end of file
diff --git a/Openwork.pdf b/Openwork.pdf
new file mode 100644
index 0000000..c8dd0da
Binary files /dev/null and b/Openwork.pdf differ
diff --git a/README.md b/README.md
index 8b1982a..47f5ae6 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,10 @@
## Openwork
-Welcome
\ No newline at end of file
+Welcome. We're building a public space to organize, share, and collaborate on any project. Somewhere to see what others are working on and the projects they contribute to, and then be able to jump in and collaborate instantly.
+
+Here's a simple prototype I made in keynote: https://github.com/thomasbeta/openwork/blob/master/Openwork.pdf
+
+This app is using [MEAN.JS Official Yeoman Generator](http://meanjs.org/). S/o to that project.
+
+## License
+
+[BSD license](http://opensource.org/licenses/bsd-license.php)
diff --git a/app/controllers/activities.server.controller.js b/app/controllers/activities.server.controller.js
new file mode 100644
index 0000000..a80d493
--- /dev/null
+++ b/app/controllers/activities.server.controller.js
@@ -0,0 +1,59 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var mongoose = require('mongoose'),
+ errorHandler = require('./errors.server.controller'),
+ Activity = mongoose.model('Activity');
+
+/**
+ * List of Activities
+ */
+exports.list = function(req, res) {
+ Activity.find().sort('-created').populate('user', 'displayName').exec(function(err, projects) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ res.jsonp(projects);
+ }
+ });
+};
+
+
+/**
+ * Create activity instance
+ */
+exports.create = function(obj) {
+ // config activity object with user, object id's, action type
+ // config activity string
+ // socket object
+
+ var ActivityObj = new Activity({
+ user: obj.userObj._id,
+ projectId: obj.projectId,
+ noteId: obj.noteId,
+ commentId: obj.commentId,
+ nestedCommentId: obj.nestedCommentId,
+ activityType: obj.activityType
+ });
+
+ if (obj.activityType === 1) {
+ ActivityObj.activityString = obj.userObj.username + ' created a new project called ' + obj.name;
+ } else if (obj.activityType === 2) {
+ ActivityObj.activityString = obj.userObj.username + ' created a new note called ' + obj.newNote.title;
+ }
+
+ ActivityObj.save(function(err) {
+ if (err) {
+ console.log(err);
+ } else {
+ // socket
+ console.log('string here');
+ console.log(ActivityObj.activityString);
+ }
+ });
+
+};
diff --git a/app/controllers/projects.server.controller.js b/app/controllers/projects.server.controller.js
new file mode 100644
index 0000000..a20c5ef
--- /dev/null
+++ b/app/controllers/projects.server.controller.js
@@ -0,0 +1,266 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var mongoose = require('mongoose'),
+ errorHandler = require('./errors.server.controller'),
+ Project = mongoose.model('Project'),
+ activityHandler = require('./activities.server.controller'),
+ _ = require('lodash');
+
+/**
+ * Create a Project
+ */
+exports.create = function(req, res) {
+ var project = new Project(req.body);
+ project.user = req.user;
+
+ project.save(function(err) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ project.activityType = 1;
+ project.userObj = req.user;
+ project.projectId = project._id;
+ activityHandler.create(project);
+ res.jsonp(project);
+ }
+ });
+};
+
+/**
+ * Show the current Project
+ */
+exports.read = function(req, res) {
+ res.jsonp(req.project);
+};
+
+/**
+ * Update a Project
+ */
+exports.update = function(req, res, next) {
+ Project.findById(req.body._id).exec(function(err, project) {
+ project.followers.push(req.user._id);
+ console.log(project.followers);
+ project.save(function(err, projectSaved) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ // projectSaved.followProject = true;
+ // projectSaved.activityType = 4;
+ // projectSaved.userObj = req.user;
+ // activityHandler.create(projectSaved);
+ // console.log('about to respond in followProject');
+ var obj = {
+ hey: 'hey'
+ };
+ res.jsonp(projectSaved);
+ }
+ });
+ });
+ // if (req.body.projectComment || req.body.newNote || req.body.noteComment || req.body.followProject ) {
+ // next();
+ // }
+ // console.log('in update');
+ // var project = req.project ;
+ // project = _.extend(project , req.body);
+ // console.log(req.body.updatedNote);
+ // project.updatedNote = req.body.updatedNote;
+ // console.log(project.updatedNote);
+ // var newNote = req.body.newNote;
+ // console.log('heres new note');
+
+ // project.save(function(err) {
+ // if (err) {
+ // return res.status(400).send({
+ // message: errorHandler.getErrorMessage(err)
+ // });
+ // } else {
+ // project
+ // .populate('user', 'username providerData.profile_image_url_https')
+ // .populate('notes.comments.user', 'username providerData.profile_image_url_https')
+ // .populate('notes.comments.comments.user', 'username providerData.profile_image_url_https')
+ // .populate('comments.user', 'username providerData.profile_image_url_https')
+ // .populate('comments.comments.user', 'username providerData.profile_image_url_https', function() {
+ // project.userObj = req.user;
+ // if (newNote) {
+ // project.newNote = project.notes[project.notes.length - 1];
+ // project.activityType = 2;
+ // activityHandler.create(project);
+ // }
+ // // else if (noteComment) {
+ // // project.projectId = project._id;
+ // // project.noteId = req.body.updatedNote;
+ // // }
+ // res.jsonp(project);
+ // });
+ // }
+ // });
+};
+
+/**
+ * Create a note
+ */
+exports.createProjectComment = function(req, res, next) {
+ console.log('in create 12');
+ if (req.body.newNote || req.body.noteComment || req.body.followProject ) {
+ next();
+ } else {
+ console.log('in create');
+ Project.findById(req.body._id)
+ .exec(function(err, project) {
+ project.comments.push(req.body.projectComment);
+ project.save(function(err, projectSaved) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ console.log('in else in cpc');
+ projectSaved
+ .populate('user', 'username providerData.profile_image_url_https')
+ .populate('notes.comments.user', 'username providerData.profile_image_url_https')
+ .populate('notes.comments.comments.user', 'username providerData.profile_image_url_https')
+ .populate('comments.user', 'username providerData.profile_image_url_https')
+ .populate('comments.comments.user', 'username providerData.profile_image_url_https', function() {
+ projectSaved.newComment = projectSaved.comments[projectSaved.comments.length - 1];
+ projectSaved.activityType = 3;
+ projectSaved.userObj = req.user;
+ activityHandler.create(projectSaved);
+ console.log('about to res');
+ res.jsonp(projectSaved);
+ });
+ }
+ });
+ });
+ }
+};
+
+/**
+ * Create a note
+ */
+exports.createNote = function(req, res, next) {
+ console.log('in create note');
+ if (req.body.noteComment || req.body.followProject ) {
+ next();
+ }
+
+
+ Project.findById(req.body._id).exec(function(err, project) {
+ project.notes.push(req.body.newNote);
+ project.save(function(err, projectSaved) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ projectSaved.newNote = projectSaved.notes[projectSaved.notes.length - 1];
+ projectSaved.activityType = 2;
+ projectSaved.userObj = req.user;
+ activityHandler.create(projectSaved);
+ console.log('about to res in note');
+ res.jsonp(projectSaved);
+ }
+ });
+ });
+};
+
+exports.createNoteComment = function(req, res, next) {
+ if (req.body.noteComment || req.body.projectComment || req.body.followProject ) {
+ next();
+ }
+};
+
+exports.followProject = function(req, res, next) {
+ var thisUser = req.user._id;
+
+ Project.findById(req.body._id).exec(function(err, project) {
+ project.followers.push(req.user._id);
+ console.log(project.followers);
+ project.save(function(err, projectSaved) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ // projectSaved.followProject = true;
+ // projectSaved.activityType = 4;
+ // projectSaved.userObj = req.user;
+ // activityHandler.create(projectSaved);
+ // console.log('about to respond in followProject');
+ var obj = {
+ hey: 'hey'
+ };
+ res.jsonp(obj);
+ }
+ });
+ });
+
+};
+
+/**
+ * Delete an Project
+ */
+exports.delete = function(req, res) {
+ var project = req.project ;
+
+ project.remove(function(err) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ res.jsonp(project);
+ }
+ });
+};
+
+/**
+ * List of Projects
+ */
+exports.list = function(req, res) {
+ Project.find().sort('-created').populate('user', 'displayName').exec(function(err, projects) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ res.jsonp(projects);
+ }
+ });
+};
+
+/**
+ * Project middleware
+ */
+exports.projectByID = function(req, res, next, id) {
+ Project.findById(id)
+ .populate('user', 'displayName')
+ .populate('user', 'username providerData.profile_image_url_https')
+ .populate('notes.comments.user', 'username providerData.profile_image_url_https')
+ .populate('notes.comments.comments.user', 'username providerData.profile_image_url_https')
+ .populate('comments.user', 'username providerData.profile_image_url_https')
+ .populate('comments.comments.user', 'username providerData.profile_image_url_https')
+ .exec(function(err, project) {
+ if (err) return next(err);
+ if (! project) return next(new Error('Failed to load Project ' + id));
+ req.project = project ;
+ next();
+ }
+ );
+};
+
+/**
+ * Project authorization middleware
+ */
+exports.hasAuthorization = function(req, res, next) {
+ if (req.project.user.id !== req.user.id) {
+ return res.status(403).send('User is not authorized');
+ }
+ next();
+};
diff --git a/app/controllers/projects.server.controller.js.orig b/app/controllers/projects.server.controller.js.orig
new file mode 100644
index 0000000..05bb50d
--- /dev/null
+++ b/app/controllers/projects.server.controller.js.orig
@@ -0,0 +1,134 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var mongoose = require('mongoose'),
+ errorHandler = require('./errors.server.controller'),
+ Project = mongoose.model('Project'),
+ _ = require('lodash');
+
+/**
+ * Create a Project
+ */
+exports.create = function(req, res) {
+ var project = new Project(req.body);
+ project.user = req.user;
+
+ project.save(function(err) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ res.jsonp(project);
+ }
+ });
+};
+
+/**
+ * Show the current Project
+ */
+exports.read = function(req, res) {
+ res.jsonp(req.project);
+ console.log(req.cookies);
+ console.log("##############");
+ console.log(res.req);
+
+
+};
+
+/**
+ * Update a Project
+ */
+exports.update = function(req, res) {
+ var project = req.project ;
+ project = _.extend(project , req.body);
+
+ project.save(function(err) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ project
+ .populate('user', 'username providerData.profile_image_url_https')
+ .populate('notes.comments.user', 'username providerData.profile_image_url_https')
+ .populate('notes.comments.comments.user', 'username providerData.profile_image_url_https')
+ .populate('comments.user', 'username providerData.profile_image_url_https')
+ .populate('comments.comments.user', 'username providerData.profile_image_url_https', function() {
+ res.jsonp(project);
+ });
+ }
+ });
+};
+
+/**
+ * Delete an Project
+ */
+exports.delete = function(req, res) {
+ var project = req.project ;
+
+ project.remove(function(err) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ res.jsonp(project);
+ }
+ });
+};
+
+/**
+ * List of Projects
+ */
+exports.list = function(req, res) {
+ Project.find().sort('-created').populate('user', 'displayName').exec(function(err, projects) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else {
+ res.jsonp(projects);
+ }
+ });
+};
+
+/**
+ * Project middleware
+ */
+<<<<<<< HEAD
+exports.projectByID = function(req, res, next, id) {
+ Project.findById(id).populate('user', 'displayName').exec(function(err, project) {
+ if (err) return next(err);
+ if (! project) return next(new Error('Failed to load Project ' + id));
+ req.project = project ;
+ next();
+ });
+=======
+exports.projectByID = function(req, res, next, id) {
+ Project.findById(id)
+ .populate('user', 'displayName')
+ .populate('user', 'username providerData.profile_image_url_https')
+ .populate('comments.user', 'username providerData.profile_image_url_https')
+ .populate('comments.comments.user', 'username providerData.profile_image_url_https')
+ .exec(function(err, project) {
+ if (err) return next(err);
+ if (! project) return next(new Error('Failed to load Project ' + id));
+ req.project = project ;
+ next();
+ }
+ );
+>>>>>>> 17b6eb845ed998f0575a0be6c0f993b4c357486f
+};
+
+/**
+ * Project authorization middleware
+ */
+exports.hasAuthorization = function(req, res, next) {
+ if (req.project.user.id !== req.user.id) {
+ return res.status(403).send('User is not authorized');
+ }
+ next();
+};
diff --git a/app/controllers/sockets.server.controller.js b/app/controllers/sockets.server.controller.js
new file mode 100644
index 0000000..e95429c
--- /dev/null
+++ b/app/controllers/sockets.server.controller.js
@@ -0,0 +1,53 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var mongoose = require('mongoose'),
+ errorHandler = require('./errors.server.controller'),
+ Socket = mongoose.model('Socket'),
+ _ = require('lodash');
+
+
+/**
+ * Find sockets older than 30 minutes and delete them.
+ */
+
+exports.removeOldSockets = function(req, res, next) {
+ var d = new Date();
+ d.setMinutes(d.getMinutes() - 30);
+ Socket.find({ created: { $lt: d }}).exec(function(err, theseSockets) {
+ theseSockets.forEach(function(callback, thisArg) {
+ theseSockets[thisArg].remove(function(err) {
+ if (err) {
+ console.log(err);
+ }
+ });
+ });
+ });
+
+ next();
+};
+
+/**
+ * Save a socket. If the user's onlineStatus is '1', next() to findOnline.
+ */
+exports.createSocket = function(req, res, next) {
+ var socket = new Socket(req);
+ socket.socketID = req.body.socketID;
+ socket.user = req.user;
+ socket.created = new Date();
+ socket.save(function(err) {
+ if (err) {
+ return res.status(400).send({
+ message: errorHandler.getErrorMessage(err)
+ });
+ } else if (req.user) {
+ console.log(socket);
+ res.jsonp(socket);
+ if (req.user.onlineStatus === '1') {
+ next();
+ }
+ }
+ });
+};
\ No newline at end of file
diff --git a/app/controllers/users/users.authentication.server.controller.js b/app/controllers/users/users.authentication.server.controller.js
index c15c8a1..c6b51a2 100644
--- a/app/controllers/users/users.authentication.server.controller.js
+++ b/app/controllers/users/users.authentication.server.controller.js
@@ -24,7 +24,7 @@ exports.signup = function(req, res) {
user.provider = 'local';
user.displayName = user.firstName + ' ' + user.lastName;
- // Then save the user
+ // Then save the user
user.save(function(err) {
if (err) {
return res.status(400).send({
@@ -50,6 +50,7 @@ exports.signup = function(req, res) {
* Signin after passport authentication
*/
exports.signin = function(req, res, next) {
+
passport.authenticate('local', function(err, user, info) {
if (err || !user) {
res.status(400).send(info);
@@ -63,8 +64,10 @@ exports.signin = function(req, res, next) {
res.status(400).send(err);
} else {
res.json(user);
+ console.log(user);
}
});
+
}
})(req, res, next);
};
@@ -203,4 +206,4 @@ exports.removeOAuthProvider = function(req, res, next) {
}
});
}
-};
\ No newline at end of file
+};
diff --git a/app/controllers/users/users.authorization.server.controller.js b/app/controllers/users/users.authorization.server.controller.js
index efa3b69..ae76171 100644
--- a/app/controllers/users/users.authorization.server.controller.js
+++ b/app/controllers/users/users.authorization.server.controller.js
@@ -18,6 +18,7 @@ exports.userByID = function(req, res, next, id) {
if (!user) return next(new Error('Failed to load User ' + id));
req.profile = user;
next();
+
});
};
@@ -51,4 +52,4 @@ exports.hasAuthorization = function(roles) {
}
});
};
-};
\ No newline at end of file
+};
diff --git a/app/controllers/users/users.profile.server.controller.js b/app/controllers/users/users.profile.server.controller.js
index dd38936..841d513 100644
--- a/app/controllers/users/users.profile.server.controller.js
+++ b/app/controllers/users/users.profile.server.controller.js
@@ -13,6 +13,7 @@ var _ = require('lodash'),
* Update user details
*/
exports.update = function(req, res) {
+
// Init Variables
var user = req.user;
var message = null;
@@ -53,4 +54,6 @@ exports.update = function(req, res) {
*/
exports.me = function(req, res) {
res.json(req.user || null);
-};
\ No newline at end of file
+ console.log(res);
+
+};
diff --git a/app/models/activity.server.model.js b/app/models/activity.server.model.js
new file mode 100644
index 0000000..e19ed6f
--- /dev/null
+++ b/app/models/activity.server.model.js
@@ -0,0 +1,34 @@
+var mongoose = require('mongoose'),
+ Schema = mongoose.Schema;
+
+var ActivitySchema = new Schema({
+ user: {
+ type: Schema.ObjectId,
+ ref: 'User'
+ },
+ activityType: {
+ type: Number
+ },
+ activityString: {
+ type: String
+ },
+ projectId: {
+ type: Schema.ObjectId,
+ ref: 'Project'
+ },
+ noteId: {
+ type: String
+ },
+ commentId: {
+ type: String
+ },
+ nestedCommentId: {
+ type: String
+ },
+ created: {
+ type: Date,
+ default: Date.now
+ }
+});
+
+mongoose.model('Activity', ActivitySchema);
\ No newline at end of file
diff --git a/app/models/project.server.model.js b/app/models/project.server.model.js
new file mode 100644
index 0000000..b07bc0d
--- /dev/null
+++ b/app/models/project.server.model.js
@@ -0,0 +1,99 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var mongoose = require('mongoose'),
+ Schema = mongoose.Schema;
+
+var NestedCommentSchema = new Schema({
+ text: {
+ type: String,
+ default: '',
+ trim: true
+ },
+ created: {
+ type: Date,
+ default: Date.now
+ },
+ user: {
+ type: Schema.ObjectId,
+ ref: 'User'
+ }
+});
+
+var CommentSchema = new Schema({
+ text: {
+ type: String,
+ default: '',
+ trim: true
+ },
+ created: {
+ type: Date,
+ default: Date.now
+ },
+ user: {
+ type: Schema.ObjectId,
+ ref: 'User'
+ },
+ comments: [NestedCommentSchema]
+});
+
+/**
+ * Notes Schema
+ */
+
+var NoteSchema = new Schema({
+ title: {
+ type: String,
+ required: 'Please fill Project name',
+ trim: true
+ },
+ content: {
+ type: String
+ },
+ user: {
+ type: Schema.ObjectId,
+ ref: 'User'
+ },
+ comments: [CommentSchema],
+ created: {
+ type: Date,
+ default: Date.now
+ }
+});
+
+/**
+ * Project Schema
+ */
+var ProjectSchema = new Schema({
+ name: {
+ type: String,
+ default: '',
+ required: 'Please fill Project name',
+ trim: true
+ },
+ description: {
+ type: String,
+ required: 'Please fill Project description'
+ },
+ created: {
+ type: Date,
+ default: Date.now
+ },
+ user: {
+ type: Schema.ObjectId,
+ ref: 'User'
+ },
+ notes: [NoteSchema],
+ comments: [CommentSchema],
+ followers: [{
+ type: Schema.ObjectId,
+ ref: 'User'
+ }],
+ updatedNote: {
+ type: String
+ }
+});
+
+mongoose.model('Project', ProjectSchema);
diff --git a/app/models/sockets.server.model.js b/app/models/sockets.server.model.js
new file mode 100644
index 0000000..5697f01
--- /dev/null
+++ b/app/models/sockets.server.model.js
@@ -0,0 +1,35 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var mongoose = require('mongoose'),
+ Schema = mongoose.Schema;
+
+/**
+ * Socket Schema
+ */
+var SocketSchema = new Schema({
+ socketID: {
+ type: String
+ },
+ name: {
+ type: String,
+ default: 'default',
+ trim: true
+ },
+ extraSockets: {
+ type: Number,
+ default: 0
+ },
+ created: {
+ type: Date,
+ default: Date.now
+ },
+ user: {
+ type: Schema.ObjectId,
+ ref: 'User'
+ }
+});
+
+mongoose.model('Socket', SocketSchema);
\ No newline at end of file
diff --git a/app/routes/activities.server.routes.js b/app/routes/activities.server.routes.js
new file mode 100644
index 0000000..1f772f0
--- /dev/null
+++ b/app/routes/activities.server.routes.js
@@ -0,0 +1,10 @@
+'use strict';
+
+module.exports = function(app) {
+ var activities = require('../../app/controllers/activities.server.controller');
+
+ // Projects Routes
+ app.route('/activities')
+ .get(activities.list);
+
+};
\ No newline at end of file
diff --git a/app/routes/core.server.routes.js b/app/routes/core.server.routes.js
index 1db9d40..50ada58 100644
--- a/app/routes/core.server.routes.js
+++ b/app/routes/core.server.routes.js
@@ -3,5 +3,11 @@
module.exports = function(app) {
// Root routing
var core = require('../../app/controllers/core.server.controller');
+ var sockets = require('../../app/controllers/sockets.server.controller');
+
app.route('/').get(core.index);
+
+ app.route('/sockets')
+ // .delete(sockets.find, sockets.deleteTwo)
+ .post(sockets.removeOldSockets, sockets.createSocket);
};
\ No newline at end of file
diff --git a/app/routes/projects.server.routes.js b/app/routes/projects.server.routes.js
new file mode 100644
index 0000000..851237a
--- /dev/null
+++ b/app/routes/projects.server.routes.js
@@ -0,0 +1,19 @@
+'use strict';
+
+module.exports = function(app) {
+ var users = require('../../app/controllers/users.server.controller');
+ var projects = require('../../app/controllers/projects.server.controller');
+
+ // Projects Routes
+ app.route('/projects')
+ .get(projects.list)
+ .post(users.requiresLogin, projects.create);
+
+ app.route('/projects/:projectId')
+ .get(projects.read)
+ .put(users.requiresLogin, projects.update, projects.createProjectComment, projects.createNote, projects.createNoteComment, projects.followProject)
+ .delete(users.requiresLogin, projects.hasAuthorization, projects.delete);
+
+ // Finish by binding the Project middleware
+ app.param('projectId', projects.projectByID);
+};
diff --git a/app/tests/project.server.model.test.js b/app/tests/project.server.model.test.js
new file mode 100644
index 0000000..ce9bba3
--- /dev/null
+++ b/app/tests/project.server.model.test.js
@@ -0,0 +1,64 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var should = require('should'),
+ mongoose = require('mongoose'),
+ User = mongoose.model('User'),
+ Project = mongoose.model('Project');
+
+/**
+ * Globals
+ */
+var user, project;
+
+/**
+ * Unit tests
+ */
+describe('Project Model Unit Tests:', function() {
+ beforeEach(function(done) {
+ user = new User({
+ firstName: 'Full',
+ lastName: 'Name',
+ displayName: 'Full Name',
+ email: 'test@test.com',
+ username: 'username',
+ password: 'password'
+ });
+
+ user.save(function() {
+ project = new Project({
+ name: 'Project Name',
+ user: user
+ });
+
+ done();
+ });
+ });
+
+ describe('Method Save', function() {
+ it('should be able to save without problems', function(done) {
+ return project.save(function(err) {
+ should.not.exist(err);
+ done();
+ });
+ });
+
+ it('should be able to show an error when try to save without name', function(done) {
+ project.name = '';
+
+ return project.save(function(err) {
+ should.exist(err);
+ done();
+ });
+ });
+ });
+
+ afterEach(function(done) {
+ Project.remove().exec();
+ User.remove().exec();
+
+ done();
+ });
+});
\ No newline at end of file
diff --git a/app/tests/project.server.routes.test.js b/app/tests/project.server.routes.test.js
new file mode 100644
index 0000000..94c14a2
--- /dev/null
+++ b/app/tests/project.server.routes.test.js
@@ -0,0 +1,268 @@
+'use strict';
+
+var should = require('should'),
+ request = require('supertest'),
+ app = require('../../server'),
+ mongoose = require('mongoose'),
+ User = mongoose.model('User'),
+ Project = mongoose.model('Project'),
+ agent = request.agent(app);
+
+/**
+ * Globals
+ */
+var credentials, user, project;
+
+/**
+ * Project routes tests
+ */
+describe('Project CRUD tests', function() {
+ beforeEach(function(done) {
+ // Create user credentials
+ credentials = {
+ username: 'username',
+ password: 'password'
+ };
+
+ // Create a new user
+ user = new User({
+ firstName: 'Full',
+ lastName: 'Name',
+ displayName: 'Full Name',
+ email: 'test@test.com',
+ username: credentials.username,
+ password: credentials.password,
+ provider: 'local'
+ });
+
+ // Save a user to the test db and create new Project
+ user.save(function() {
+ project = {
+ name: 'Project Name'
+ };
+
+ done();
+ });
+ });
+
+ it('should be able to save Project instance if logged in', function(done) {
+ agent.post('/auth/signin')
+ .send(credentials)
+ .expect(200)
+ .end(function(signinErr, signinRes) {
+ // Handle signin error
+ if (signinErr) done(signinErr);
+
+ // Get the userId
+ var userId = user.id;
+
+ // Save a new Project
+ agent.post('/projects')
+ .send(project)
+ .expect(200)
+ .end(function(projectSaveErr, projectSaveRes) {
+ // Handle Project save error
+ if (projectSaveErr) done(projectSaveErr);
+
+ // Get a list of Projects
+ agent.get('/projects')
+ .end(function(projectsGetErr, projectsGetRes) {
+ // Handle Project save error
+ if (projectsGetErr) done(projectsGetErr);
+
+ // Get Projects list
+ var projects = projectsGetRes.body;
+
+ // Set assertions
+ (projects[0].user._id).should.equal(userId);
+ (projects[0].name).should.match('Project Name');
+
+ // Call the assertion callback
+ done();
+ });
+ });
+ });
+ });
+
+ it('should not be able to save Project instance if not logged in', function(done) {
+ agent.post('/projects')
+ .send(project)
+ .expect(401)
+ .end(function(projectSaveErr, projectSaveRes) {
+ // Call the assertion callback
+ done(projectSaveErr);
+ });
+ });
+
+ it('should not be able to save Project instance if no name is provided', function(done) {
+ // Invalidate name field
+ project.name = '';
+
+ agent.post('/auth/signin')
+ .send(credentials)
+ .expect(200)
+ .end(function(signinErr, signinRes) {
+ // Handle signin error
+ if (signinErr) done(signinErr);
+
+ // Get the userId
+ var userId = user.id;
+
+ // Save a new Project
+ agent.post('/projects')
+ .send(project)
+ .expect(400)
+ .end(function(projectSaveErr, projectSaveRes) {
+ // Set message assertion
+ (projectSaveRes.body.message).should.match('Please fill Project name');
+
+ // Handle Project save error
+ done(projectSaveErr);
+ });
+ });
+ });
+
+ it('should be able to update Project instance if signed in', function(done) {
+ agent.post('/auth/signin')
+ .send(credentials)
+ .expect(200)
+ .end(function(signinErr, signinRes) {
+ // Handle signin error
+ if (signinErr) done(signinErr);
+
+ // Get the userId
+ var userId = user.id;
+
+ // Save a new Project
+ agent.post('/projects')
+ .send(project)
+ .expect(200)
+ .end(function(projectSaveErr, projectSaveRes) {
+ // Handle Project save error
+ if (projectSaveErr) done(projectSaveErr);
+
+ // Update Project name
+ project.name = 'WHY YOU GOTTA BE SO MEAN?';
+
+ // Update existing Project
+ agent.put('/projects/' + projectSaveRes.body._id)
+ .send(project)
+ .expect(200)
+ .end(function(projectUpdateErr, projectUpdateRes) {
+ // Handle Project update error
+ if (projectUpdateErr) done(projectUpdateErr);
+
+ // Set assertions
+ (projectUpdateRes.body._id).should.equal(projectSaveRes.body._id);
+ (projectUpdateRes.body.name).should.match('WHY YOU GOTTA BE SO MEAN?');
+
+ // Call the assertion callback
+ done();
+ });
+ });
+ });
+ });
+
+ it('should be able to get a list of Projects if not signed in', function(done) {
+ // Create new Project model instance
+ var projectObj = new Project(project);
+
+ // Save the Project
+ projectObj.save(function() {
+ // Request Projects
+ request(app).get('/projects')
+ .end(function(req, res) {
+ // Set assertion
+ res.body.should.be.an.Array.with.lengthOf(1);
+
+ // Call the assertion callback
+ done();
+ });
+
+ });
+ });
+
+
+ it('should be able to get a single Project if not signed in', function(done) {
+ // Create new Project model instance
+ var projectObj = new Project(project);
+
+ // Save the Project
+ projectObj.save(function() {
+ request(app).get('/projects/' + projectObj._id)
+ .end(function(req, res) {
+ // Set assertion
+ res.body.should.be.an.Object.with.property('name', project.name);
+
+ // Call the assertion callback
+ done();
+ });
+ });
+ });
+
+ it('should be able to delete Project instance if signed in', function(done) {
+ agent.post('/auth/signin')
+ .send(credentials)
+ .expect(200)
+ .end(function(signinErr, signinRes) {
+ // Handle signin error
+ if (signinErr) done(signinErr);
+
+ // Get the userId
+ var userId = user.id;
+
+ // Save a new Project
+ agent.post('/projects')
+ .send(project)
+ .expect(200)
+ .end(function(projectSaveErr, projectSaveRes) {
+ // Handle Project save error
+ if (projectSaveErr) done(projectSaveErr);
+
+ // Delete existing Project
+ agent.delete('/projects/' + projectSaveRes.body._id)
+ .send(project)
+ .expect(200)
+ .end(function(projectDeleteErr, projectDeleteRes) {
+ // Handle Project error error
+ if (projectDeleteErr) done(projectDeleteErr);
+
+ // Set assertions
+ (projectDeleteRes.body._id).should.equal(projectSaveRes.body._id);
+
+ // Call the assertion callback
+ done();
+ });
+ });
+ });
+ });
+
+ it('should not be able to delete Project instance if not signed in', function(done) {
+ // Set Project user
+ project.user = user;
+
+ // Create new Project model instance
+ var projectObj = new Project(project);
+
+ // Save the Project
+ projectObj.save(function() {
+ // Try deleting Project
+ request(app).delete('/projects/' + projectObj._id)
+ .expect(401)
+ .end(function(projectDeleteErr, projectDeleteRes) {
+ // Set message assertion
+ (projectDeleteRes.body.message).should.match('User is not logged in');
+
+ // Handle Project error error
+ done(projectDeleteErr);
+ });
+
+ });
+ });
+
+ afterEach(function(done) {
+ User.remove().exec();
+ Project.remove().exec();
+ done();
+ });
+});
\ No newline at end of file
diff --git a/app/views/layout.server.view.html b/app/views/layout.server.view.html
index 9f47509..ecfbc7a 100644
--- a/app/views/layout.server.view.html
+++ b/app/views/layout.server.view.html
@@ -45,7 +45,7 @@
-
+
{% block content %}{% endblock %}
diff --git a/bower.json b/bower.json
index 59f657b..3d354a5 100644
--- a/bower.json
+++ b/bower.json
@@ -1,18 +1,26 @@
{
- "name": "openwork",
- "version": "0.0.1",
- "description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js",
- "dependencies": {
- "bootstrap": "~3",
- "angular": "~1.2",
- "angular-resource": "~1.2",
- "angular-mocks": "~1.2",
- "angular-cookies": "~1.2",
- "angular-animate": "~1.2",
- "angular-touch": "~1.2",
- "angular-sanitize": "~1.2",
- "angular-bootstrap": "~0.11.2",
- "angular-ui-utils": "~0.1.1",
- "angular-ui-router": "~0.2.11"
- }
-}
\ No newline at end of file
+ "name": "openwork",
+ "version": "0.0.1",
+ "description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js",
+ "dependencies": {
+ "bootstrap": "~3",
+ "angular": "~1.2",
+ "angular-resource": "~1.2",
+ "angular-mocks": "~1.2",
+ "angular-cookies": "~1.2",
+ "angular-animate": "~1.2",
+ "angular-touch": "~1.2",
+ "angular-sanitize": "~1.2",
+ "angular-bootstrap": "~0.11.2",
+ "angular-ui-utils": "~0.1.1",
+ "angular-ui-router": "~0.2.11",
+ "moment": "~2.10.3",
+ "angular-moment": "~0.10.1",
+ "angular-socket-io": "~0.7.0",
+ "socket.io-client": "~1.3.5",
+ "textAngular" : "~1.3",
+ "angular-sanitize" : "~1.2",
+ "font-awesome" : "~4",
+ "rangy" : "~1.2"
+ }
+}
diff --git a/config/env/all.js b/config/env/all.js
index 0524df5..190ef45 100644
--- a/config/env/all.js
+++ b/config/env/all.js
@@ -15,17 +15,28 @@ module.exports = {
css: [
'public/lib/bootstrap/dist/css/bootstrap.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.css',
+ 'public/lib/textangular/src/textAngular.css',
+ 'public/lib/font-awesome/css/font-awesome.min.css',
+
+
],
js: [
'public/lib/angular/angular.js',
- 'public/lib/angular-resource/angular-resource.js',
- 'public/lib/angular-cookies/angular-cookies.js',
- 'public/lib/angular-animate/angular-animate.js',
- 'public/lib/angular-touch/angular-touch.js',
- 'public/lib/angular-sanitize/angular-sanitize.js',
+ 'public/lib/angular-resource/angular-resource.js',
+ 'public/lib/angular-cookies/angular-cookies.js',
+ 'public/lib/angular-animate/angular-animate.js',
+ 'public/lib/angular-touch/angular-touch.js',
+ 'public/lib/angular-sanitize/angular-sanitize.js',
'public/lib/angular-ui-router/release/angular-ui-router.js',
'public/lib/angular-ui-utils/ui-utils.js',
- 'public/lib/angular-bootstrap/ui-bootstrap-tpls.js'
+ 'public/lib/angular-bootstrap/ui-bootstrap-tpls.js',
+ 'public/lib/moment/moment.js',
+ 'public/lib/angular-moment/angular-moment.js',
+ 'public/lib/angular-socket-io/socket.min.js',
+ 'public/lib/socket.io-client/socket.io.js',
+ 'public/lib/textangular/dist/textAngular-rangy.min.js',
+ 'public/lib/textangular/dist/textAngular-sanitize.min.js',
+ 'public/lib/textangular/dist/textAngular.min.js',
]
},
css: [
@@ -42,4 +53,4 @@ module.exports = {
'public/modules/*/tests/*.js'
]
}
-};
\ No newline at end of file
+};
diff --git a/config/env/development.js b/config/env/development.js
index 0114151..547c090 100644
--- a/config/env/development.js
+++ b/config/env/development.js
@@ -11,9 +11,9 @@ module.exports = {
callbackURL: '/auth/facebook/callback'
},
twitter: {
- clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
- clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
- callbackURL: '/auth/twitter/callback'
+ clientID: process.env.TWITTER_KEY || 'QGTMX4vOXpOYgToEFTLYaWhui',
+ clientSecret: process.env.TWITTER_SECRET || 'CA31zMWaO6g8YcRb2ue4t5MuF8f5B2PO3JNvTV9rkPfO18EK7B',
+ callbackURL: 'http://127.0.0.1/auth/twitter/callback'
},
google: {
clientID: process.env.GOOGLE_ID || 'APP_ID',
diff --git a/config/env/production.js b/config/env/production.js
index 1205ba8..687babc 100644
--- a/config/env/production.js
+++ b/config/env/production.js
@@ -7,17 +7,27 @@ module.exports = {
css: [
'public/lib/bootstrap/dist/css/bootstrap.min.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
+ 'public/lib/textangular/dist/textAngular.css',
],
js: [
'public/lib/angular/angular.min.js',
- 'public/lib/angular-resource/angular-resource.js',
- 'public/lib/angular-cookies/angular-cookies.js',
- 'public/lib/angular-animate/angular-animate.js',
- 'public/lib/angular-touch/angular-touch.js',
- 'public/lib/angular-sanitize/angular-sanitize.js',
+ 'public/lib/angular-resource/angular-resource.js',
+ 'public/lib/angular-cookies/angular-cookies.js',
+ 'public/lib/angular-animate/angular-animate.js',
+ 'public/lib/angular-touch/angular-touch.js',
+ 'public/lib/angular-sanitize/angular-sanitize.js',
'public/lib/angular-ui-router/release/angular-ui-router.min.js',
'public/lib/angular-ui-utils/ui-utils.min.js',
- 'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js'
+ 'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js',
+ 'public/lib/moment/min/moment.min.js',
+ 'public/lib/angular-moment/angular-moment.min.js',
+ 'public/lib/angular-socket-io/socket.min.js',
+ 'public/lib/socket.io-client/socket.io.js',
+ 'public/lib/textangular/dist/textAngular-rangy.min.js',
+ 'public/lib/textangular/dist/textAngular-sanitize.min.js',
+ 'public/lib/textangular/dist/textAngular.min.js',
+
+
]
},
css: 'public/dist/application.min.css',
diff --git a/config/express.js b/config/express.js
index 46cf0dc..de42205 100755
--- a/config/express.js
+++ b/config/express.js
@@ -26,6 +26,7 @@ var fs = require('fs'),
module.exports = function(db) {
// Initialize express app
var app = express();
+ var server = require('http').createServer(app);
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
@@ -41,7 +42,7 @@ module.exports = function(db) {
app.locals.cssFiles = config.getCSSAssets();
// Passing the request url to environment locals
- app.use(function(req, res, next) {
+ app.use(function(req, res, next) {///
res.locals.url = req.protocol + '://' + req.headers.host + req.url;
next();
});
@@ -121,7 +122,9 @@ module.exports = function(db) {
// Assume 'not found' in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.
app.use(function(err, req, res, next) {
// If the error object doesn't exists
- if (!err) return next();
+ if (!err) {
+ return next();
+ }
// Log it
console.error(err.stack);
@@ -158,6 +161,28 @@ module.exports = function(db) {
return httpsServer;
}
+ // Socket.io controls
+ var io = require('socket.io').listen(server);
+ var mongoose = require('mongoose');
+ // var socketData = mongoose.model('Socket');
+ // var socketCtrl = require('../app/controllers/sockets.server.controller.js');
+
+ console.log('yo');
+ io.on('connection', function(socket) {
+ console.log('in connection');
+ var socketID = socket.id;
+ io.to(socketID).emit('socketCon', socketID);
+
+ socket.on('project updated', function(data) {
+ io.sockets.emit('updated project', data);
+ });
+
+
+
+
+ });
+
+
// Return Express server instance
- return app;
+ return server;
};
\ No newline at end of file
diff --git a/config/express.js.orig b/config/express.js.orig
new file mode 100755
index 0000000..a790244
--- /dev/null
+++ b/config/express.js.orig
@@ -0,0 +1,186 @@
+'use strict';
+
+/**
+ * Module dependencies.
+ */
+var fs = require('fs'),
+ http = require('http'),
+ https = require('https'),
+ express = require('express'),
+ morgan = require('morgan'),
+ bodyParser = require('body-parser'),
+ session = require('express-session'),
+ compress = require('compression'),
+ methodOverride = require('method-override'),
+ cookieParser = require('cookie-parser'),
+ helmet = require('helmet'),
+ passport = require('passport'),
+ mongoStore = require('connect-mongo')({
+ session: session
+ }),
+ flash = require('connect-flash'),
+ config = require('./config'),
+ consolidate = require('consolidate'),
+ path = require('path');
+
+module.exports = function(db) {
+ // Initialize express app
+ var app = express();
+ var server = require('http').createServer(app);
+
+ // Globbing model files
+ config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
+ require(path.resolve(modelPath));
+ });
+
+ // Setting application local variables
+ app.locals.title = config.app.title;
+ app.locals.description = config.app.description;
+ app.locals.keywords = config.app.keywords;
+ app.locals.facebookAppId = config.facebook.clientID;
+ app.locals.jsFiles = config.getJavaScriptAssets();
+ app.locals.cssFiles = config.getCSSAssets();
+
+ // Passing the request url to environment locals
+ app.use(function(req, res, next) {
+ res.locals.url = req.protocol + '://' + req.headers.host + req.url;
+ next();
+ });
+
+ // Should be placed before express.static
+ app.use(compress({
+ filter: function(req, res) {
+ return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
+ },
+ level: 9
+ }));
+
+ // Showing stack errors
+ app.set('showStackError', true);
+
+ // Set swig as the template engine
+ app.engine('server.view.html', consolidate[config.templateEngine]);
+
+ // Set views path and view engine
+ app.set('view engine', 'server.view.html');
+ app.set('views', './app/views');
+
+ // Environment dependent middleware
+ if (process.env.NODE_ENV === 'development') {
+ // Enable logger (morgan)
+ app.use(morgan('dev'));
+
+ // Disable views cache
+ app.set('view cache', false);
+ } else if (process.env.NODE_ENV === 'production') {
+ app.locals.cache = 'memory';
+ }
+
+ // Request body parsing middleware should be above methodOverride
+ app.use(bodyParser.urlencoded({
+ extended: true
+ }));
+ app.use(bodyParser.json());
+ app.use(methodOverride());
+
+ // CookieParser should be above session
+ app.use(cookieParser());
+
+ // Express MongoDB session storage
+ app.use(session({
+ saveUninitialized: true,
+ resave: true,
+ secret: config.sessionSecret,
+ store: new mongoStore({
+ db: db.connection.db,
+ collection: config.sessionCollection
+ })
+ }));
+
+ // use passport session
+ app.use(passport.initialize());
+ app.use(passport.session());
+
+ // connect flash for flash messages
+ app.use(flash());
+
+ // Use helmet to secure Express headers
+ app.use(helmet.xframe());
+ app.use(helmet.xssFilter());
+ app.use(helmet.nosniff());
+ app.use(helmet.ienoopen());
+ app.disable('x-powered-by');
+
+ // Setting the app router and static folder
+ app.use(express.static(path.resolve('./public')));
+
+ // Globbing routing files
+ config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
+ require(path.resolve(routePath))(app);
+ });
+
+ // Assume 'not found' in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.
+ app.use(function(err, req, res, next) {
+ // If the error object doesn't exists
+ if (!err) {
+ return next();
+ }
+
+ // Log it
+ console.error(err.stack);
+
+ // Error page
+ res.status(500).render('500', {
+ error: err.stack
+ });
+ });
+
+ // Assume 404 since no middleware responded
+ app.use(function(req, res) {
+ res.status(404).render('404', {
+ url: req.originalUrl,
+ error: 'Not Found'
+ });
+ });
+
+ if (process.env.NODE_ENV === 'secure') {
+ // Log SSL usage
+ console.log('Securely using https protocol');
+
+ // Load SSL key and certificate
+ var privateKey = fs.readFileSync('./config/sslcerts/key.pem', 'utf8');
+ var certificate = fs.readFileSync('./config/sslcerts/cert.pem', 'utf8');
+
+ // Create HTTPS Server
+ var httpsServer = https.createServer({
+ key: privateKey,
+ cert: certificate
+ }, app);
+
+ // Return HTTPS server instance
+ return httpsServer;
+ }
+<<<<<<< HEAD
+ // Return Express server instance
+ return app;
+};
+=======
+
+ // Socket.io controls
+ var io = require('socket.io').listen(server);
+ var mongoose = require('mongoose');
+ // var socketData = mongoose.model('Socket');
+ // var socketCtrl = require('../app/controllers/sockets.server.controller.js');
+
+ console.log('yo');
+ io.on('connection', function(socket) {
+ console.log('in connection');
+ var socketID = socket.id;
+ io.to(socketID).emit('socketCon', socketID);
+ });
+
+
+ // Return Express server instance
+ return server;
+};
+>>>>>>> c4a7c21a883e8c37bc53b04412c33302ac359fa9
diff --git a/package.json b/package.json
old mode 100755
new mode 100644
index 3bfd5c9..0870bcb
--- a/package.json
+++ b/package.json
@@ -1,68 +1,69 @@
{
- "name": "openwork",
- "description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js",
- "version": "0.0.1",
- "author": "Openwork",
- "engines": {
- "node": "0.10.x",
- "npm": "1.4.x"
- },
- "scripts": {
- "start": "grunt",
- "test": "grunt test",
- "postinstall": "bower install --config.interactive=false"
- },
- "dependencies": {
- "express": "~4.10.1",
- "express-session": "~1.9.1",
- "body-parser": "~1.9.0",
- "cookie-parser": "~1.3.2",
- "compression": "~1.2.0",
- "method-override": "~2.3.0",
- "morgan": "~1.4.1",
- "connect-mongo": "~0.4.1",
- "connect-flash": "~0.1.1",
- "helmet": "~0.5.0",
- "consolidate": "~0.10.0",
- "swig": "~1.4.1",
- "mongoose": "~3.8.8",
- "passport": "~0.2.0",
- "passport-local": "~1.0.0",
- "passport-facebook": "~1.0.2",
- "passport-twitter": "~1.0.2",
- "passport-linkedin": "~0.1.3",
- "passport-google-oauth": "~0.1.5",
- "passport-github": "~0.1.5",
- "lodash": "~2.4.1",
- "forever": "~0.11.0",
- "bower": "~1.3.8",
- "grunt-cli": "~0.1.13",
- "glob": "~4.0.5",
- "async": "~0.9.0",
- "nodemailer": "~1.3.0",
- "chalk": "~0.5"
- },
- "devDependencies": {
- "supertest": "~0.14.0",
- "should": "~4.1.0",
- "grunt-env": "~0.4.1",
- "grunt-node-inspector": "~0.1.3",
- "grunt-contrib-watch": "~0.6.1",
- "grunt-contrib-jshint": "~0.10.0",
- "grunt-contrib-csslint": "^0.3.1",
- "grunt-ng-annotate": "~0.4.0",
- "grunt-contrib-uglify": "~0.6.0",
- "grunt-contrib-cssmin": "~0.10.0",
- "grunt-nodemon": "~0.3.0",
- "grunt-concurrent": "~1.0.0",
- "grunt-mocha-test": "~0.12.1",
- "grunt-karma": "~0.9.0",
- "load-grunt-tasks": "~1.0.0",
- "karma": "~0.12.0",
- "karma-jasmine": "~0.2.1",
- "karma-coverage": "~0.2.0",
- "karma-chrome-launcher": "~0.1.2",
- "karma-firefox-launcher": "~0.1.3",
- "karma-phantomjs-launcher": "~0.1.2"
- }
-}
\ No newline at end of file
+ "name": "openwork",
+ "description": "Full-Stack JavaScript with MongoDB, Express, AngularJS, and Node.js",
+ "version": "0.0.1",
+ "author": "Openwork",
+ "engines": {
+ "node": "0.10.x",
+ "npm": "1.4.x"
+ },
+ "scripts": {
+ "start": "grunt",
+ "test": "grunt test",
+ "postinstall": "bower install --config.interactive=false"
+ },
+ "dependencies": {
+ "async": "~0.9.0",
+ "body-parser": "~1.9.0",
+ "bower": "~1.3.8",
+ "chalk": "~0.5",
+ "compression": "~1.2.0",
+ "connect-flash": "~0.1.1",
+ "connect-mongo": "~0.4.1",
+ "consolidate": "~0.10.0",
+ "cookie-parser": "~1.3.2",
+ "express": "~4.10.1",
+ "express-session": "~1.9.1",
+ "forever": "~0.11.0",
+ "glob": "~4.0.5",
+ "grunt-cli": "~0.1.13",
+ "helmet": "~0.5.0",
+ "lodash": "~2.4.1",
+ "method-override": "~2.3.0",
+ "mongoose": "~3.8.8",
+ "morgan": "~1.4.1",
+ "nodemailer": "~1.3.0",
+ "passport": "~0.2.0",
+ "passport-facebook": "~1.0.2",
+ "passport-github": "~0.1.5",
+ "passport-google-oauth": "~0.1.5",
+ "passport-linkedin": "~0.1.3",
+ "passport-local": "~1.0.0",
+ "passport-twitter": "~1.0.2",
+ "socket.io": "^1.3.5",
+ "swig": "~1.4.1"
+ },
+ "devDependencies": {
+ "supertest": "~0.14.0",
+ "should": "~4.1.0",
+ "grunt-env": "~0.4.1",
+ "grunt-node-inspector": "~0.1.3",
+ "grunt-contrib-watch": "~0.6.1",
+ "grunt-contrib-jshint": "~0.10.0",
+ "grunt-contrib-csslint": "^0.3.1",
+ "grunt-ng-annotate": "~0.4.0",
+ "grunt-contrib-uglify": "~0.6.0",
+ "grunt-contrib-cssmin": "~0.10.0",
+ "grunt-nodemon": "~0.3.0",
+ "grunt-concurrent": "~1.0.0",
+ "grunt-mocha-test": "~0.12.1",
+ "grunt-karma": "~0.9.0",
+ "load-grunt-tasks": "~1.0.0",
+ "karma": "~0.12.0",
+ "karma-jasmine": "~0.2.1",
+ "karma-coverage": "~0.2.0",
+ "karma-chrome-launcher": "~0.1.2",
+ "karma-firefox-launcher": "~0.1.3",
+ "karma-phantomjs-launcher": "~0.1.2"
+ }
+}
diff --git a/public/application.js b/public/application.js
index 19bb411..b3fdbed 100644
--- a/public/application.js
+++ b/public/application.js
@@ -8,7 +8,25 @@ angular.module(ApplicationConfiguration.applicationModuleName).config(['$locatio
function($locationProvider) {
$locationProvider.hashPrefix('!');
}
-]);
+]
+// ,function($provide){
+// $provide.decorator('taOptions', ['taRegisterTool', '$delegate', function(taRegisterTool, taOptions){
+// // $delegate is the taOptions we are decorating
+// // register the tool with textAngular
+// taRegisterTool('colourRed', {
+// iconclass: "fa fa-square red",
+// action: function(){
+// this.$editor().wrapSelection('forecolor', 'red');
+// }
+// });
+// // add the button to the default toolbar definition
+// taOptions.toolbar[1].push('colourRed');
+// return taOptions;
+// }]);
+// }
+);
+
+
//Then define the init function for starting up the application
angular.element(document).ready(function() {
@@ -17,4 +35,4 @@ angular.element(document).ready(function() {
//Then init the app
angular.bootstrap(document, [ApplicationConfiguration.applicationModuleName]);
-});
\ No newline at end of file
+});
diff --git a/public/config.js b/public/config.js
index b727495..6c00a1c 100644
--- a/public/config.js
+++ b/public/config.js
@@ -4,7 +4,7 @@
var ApplicationConfiguration = (function() {
// Init module configuration options
var applicationModuleName = 'openwork';
- var applicationModuleVendorDependencies = ['ngResource', 'ngCookies', 'ngAnimate', 'ngTouch', 'ngSanitize', 'ui.router', 'ui.bootstrap', 'ui.utils'];
+ var applicationModuleVendorDependencies = ['textAngular','ngResource', 'ngCookies', 'ngAnimate', 'ngTouch', 'ngSanitize', 'ui.router', 'ui.bootstrap', 'ui.utils', 'btford.socket-io', 'angularMoment'];
// Add a new vertical module
var registerModule = function(moduleName, dependencies) {
@@ -20,4 +20,4 @@ var ApplicationConfiguration = (function() {
applicationModuleVendorDependencies: applicationModuleVendorDependencies,
registerModule: registerModule
};
-})();
\ No newline at end of file
+})();
diff --git a/public/modules/core/controllers/activity.client.controller.js b/public/modules/core/controllers/activity.client.controller.js
new file mode 100644
index 0000000..65a381a
--- /dev/null
+++ b/public/modules/core/controllers/activity.client.controller.js
@@ -0,0 +1,15 @@
+'use strict';
+
+angular.module('core')
+
+.controller('ActivityController', [ '$scope', 'Activities',
+ function($scope, Activities) {
+ console.log(Activities);
+ $scope.find = function() {
+ console.log(Activities);
+ $scope.activities = Activities.query();
+ };
+ $scope.find();
+
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/core/controllers/comments.client.controller.js b/public/modules/core/controllers/comments.client.controller.js
new file mode 100644
index 0000000..f57dcfa
--- /dev/null
+++ b/public/modules/core/controllers/comments.client.controller.js
@@ -0,0 +1,317 @@
+'use strict';
+
+angular.module('core')
+
+.controller('CommentsController', [ '$scope', 'Authentication', 'projectsObj', 'mySocket', 'Projects', '$stateParams', '$modal',
+ function($scope, Authentication, projectsObj, mySocket, Projects, $stateParams, $modal) {
+ $scope.authentication = Authentication;
+ $scope.commenting = false;
+ $scope.editing = false;
+
+ $scope.toggleCommenting = function() {
+ if (this.obj.commenting) {
+ this.obj.commenting = false;
+ $scope.commenting = false;
+ $scope.nestedCommentInput = false;
+ } else {
+ this.obj.commenting = true;
+ $scope.commenting = this.obj._id;
+ $scope.nestedCommentInput = this.nestedCommentInput;
+ }
+ };
+
+ // maybe set a watcher to obj.commentEdit?
+ $scope.startEditing = function() {
+ this.obj.editing = true;
+ this.obj.commentEdit = this.obj.text;
+ $scope.editing = this.obj._id;
+ };
+
+ $scope.startNestedEditing = function() {
+ this.obj.editing = true;
+ this.obj.commentEdit = this.obj.text;
+ };
+
+ $scope.addComment = function() {
+ var project = $scope.project;
+ if (false) {
+ console.log('other stuff in the future');
+ } else if ($stateParams.noteId) {
+ console.log(project);
+ if ($stateParams.noteId) {
+ console.log($scope);
+ var note = $scope.note;
+ note.comments.push({
+ text: $scope.commentInput,
+ user: Authentication.user._id
+ });
+ console.log(note);
+
+ // var noteIndex = project.notes.indexOf(note);
+ // console.log(noteIndex);
+ // if (!project.notes[noteIndex].comments) {
+ // project.notes[noteIndex].comments = [];
+ // }
+ // project.notes[noteIndex].comments.push({
+ // text: $scope.commentInput,
+ // user: Authentication.user._id
+ // });
+ project.updatedNote = $stateParams.noteId;
+ projectsObj.update(project);
+ console.log(project);
+ }
+
+ } else {
+ project.projectComment = {
+ text: $scope.commentInput,
+ user: Authentication.user._id
+ };
+ console.log(project);
+ projectsObj.update(project)
+ .then(function(result) {
+ $scope.commentInput = '';
+ });
+ }
+ };
+
+ $scope.removeComment = function() {
+ var modalInstance = $modal.open({
+ templateUrl: '/modules/core/views/deleteComment.client.view.html',
+ controller: 'deleteCommentController'
+ });
+
+ var that = this;
+
+ modalInstance.result.then(function (result) {
+ if (result === 'delete') {
+ $scope.editing = false;
+ var project = $scope.$parent.project;
+ var index;
+ if ($stateParams.noteId) {
+ index = $scope.note.comments.indexOf(that.obj);
+ $scope.note.comments.splice(index, 1);
+ project.updatedNote = $stateParams.noteId;
+ projectsObj.update(project)
+ .then(function(result) {
+ $scope.$parent.project = result;
+ });
+ } else {
+ index = project.comments.indexOf(that.obj);
+ project.comments.splice(index, 1);
+ project.updatedChat = true;
+ projectsObj.update(project)
+ .then(function(result) {
+ // $scope.$parent.project = result;
+ });
+ }
+ }
+ });
+
+ };
+
+ $scope.addNestedComment = function() {
+ this.obj.comments.push({
+ text: this.obj.nestedCommentInput,
+ user: Authentication.user._id
+ });
+ var that = this;
+
+ if ($stateParams.noteId) {
+ $scope.project.updatedNote = $scope.$parent.note._id;
+ projectsObj.update($scope.project);
+ } else if ($stateParams.projectId) {
+ $scope.project.updatedChat = true;
+ projectsObj.update($scope.project)
+ .then(function() {
+ that.obj.nestedCommentInput = '';
+ });
+ }
+ };
+
+ $scope.removeNestedComment = function() {
+ var index = this.$parent.obj.comments.indexOf(this.obj);
+ this.$parent.obj.comments.splice(index, 1);
+ if (!$stateParams.noteId) {
+ $scope.project.updatedChat = true;
+ }
+ $scope.editing = false;
+ projectsObj.update($scope.project)
+ .then(function(result) {
+ // $scope.project = result;
+ // $scope.$parent.project = result;
+ });
+ };
+
+ $scope.saveCommentEdit = function() {
+ this.obj.text = this.obj.commentEdit;
+ this.obj.editing = false;
+ $scope.editing = false;
+ if ($stateParams.noteId) {
+ $scope.project.updatedNote = $scope.note._id;
+ } else {
+ $scope.project.updatedChat = true;
+ }
+ projectsObj.update($scope.project);
+ };
+
+ $scope.cancelEdit = function() {
+ this.obj.editing = false;
+ $scope.editing = false;
+ };
+
+ mySocket.on('updated project', function(data) {
+ var project = new Projects(data),
+ obj,
+ viewing;
+
+ if ($scope.note) {
+ viewing = 'note';
+ obj = $scope.note.comments;
+ } else if (($scope.$parent.project) && ($scope.$parent.project._id === data._id)) {
+ viewing = 'project';
+ obj = $scope.$parent.project.comments;
+ }
+
+ if ($scope.commenting) {
+ var commenting = obj.filter(function(comment) {
+ return $scope.commenting === comment._id;
+ });
+
+ if (viewing === 'note') {
+ var commentingNote = data.notes.filter(function(note) {
+ return $scope.note._id === note._id;
+ });
+ var newNoteCommentingObj = commentingNote[0].comments.filter(function(comment) {
+ return $scope.commenting === comment._id;
+ });
+ newNoteCommentingObj[0].commenting = true;
+ newNoteCommentingObj[0].nestedCommentInput = commenting[0].nestedCommentInput;
+
+ } else if (viewing === 'project') {
+ var newProjectCommentingObj = data.comments.filter(function(comment) {
+ return $scope.commenting === comment._id;
+ });
+ newProjectCommentingObj[0].commenting = true;
+ newProjectCommentingObj[0].nestedCommentInput = commenting[0].nestedCommentInput;
+ }
+
+ }
+
+ if ($scope.editing) {
+ if (viewing === 'note') {
+ var editingNoteObj = $scope.note.comments.filter(function(comment) {
+ return $scope.editing === comment._id;
+ });
+ var note = project.notes.filter(function(projectNote) {
+ return $scope.note._id === projectNote._id;
+ });
+ console.log(note);
+ var newEditingNoteObj = note[0].comments.filter(function(comment) {
+ return $scope.editing === comment._id;
+ });
+ newEditingNoteObj[0].editing = true;
+ newEditingNoteObj[0].commentEdit = editingNoteObj[0].commentEdit;
+ } else if (viewing === 'project') {
+ var editingObj = $scope.$parent.project.comments.filter(function(comment) {
+ return $scope.editing === comment._id;
+ });
+ var newEditingObj = project.comments.filter(function(comment) {
+ return $scope.editing === comment._id;
+ });
+ newEditingObj[0].editing = true;
+ newEditingObj[0].commentEdit = editingObj[0].commentEdit;
+ }
+ }
+
+ // If people are commenting, editing a comment, or viewing nested comments, keep their state.
+ // if (($scope.$parent.project) && ($scope.$parent.project._id === data._id)) {
+
+ // }
+
+ // if (($scope.$parent.note) && ($scope.$parent.note._id === data.updatedNote)) {
+
+ // }
+
+ // if ($scope.commenting) {
+ // var commenting = project.comments.filter(function(comment) {
+ // return $scope.commenting === comment._id;
+ // });
+ // var scopeComment = $scope.$parent.project.comments.filter(function(comment) {
+ // return $scope.commenting === comment._id;
+ // });
+ // commenting[0].nestedCommentInput = scopeComment[0].nestedCommentInput;
+ // commenting[0].commenting = true;
+ // }
+
+ $scope.$parent.project = new Projects(data);
+
+ console.log(data);
+
+ if ($stateParams.noteId === data.updatedNote) {
+ console.log('looking at updated note');
+ var newNote = data.notes.filter(function(note) {
+ return $stateParams.noteId === note._id;
+ });
+
+ console.log(newNote[0]);
+
+ $scope.$parent.note = newNote[0];
+ }
+
+ // angular.forEach($scope.$parent.project.comments, function(comment, val) {
+ // comment.userPic = comment.user.providerData.profile_image_url_https;
+ // angular.forEach(comment.comments, function(comment, val) {
+ // comment.userPic = comment.user.providerData.profile_image_url_https;
+ // });
+ // });
+
+
+ // if ($scope.editing) {
+ // console.log($scope.editing);
+ // var editingObj = $scope.$parent.project.comments.filter(function(comment) {
+ // return $scope.editing === comment._id;
+ // });
+ // console.log(editingObj[0]);
+ // var newEditingObj = project.comments.filter(function(comment) {
+ // return $scope.editing === comment._id;
+ // });
+ // newEditingObj[0].editing = true;
+ // console.log(newEditingObj[0]);
+ // console.log($scope.commentInput);
+ // newEditingObj[0].commentInput = editingObj[0].commentInput;
+ // }
+
+ // if (($scope.$parent.note) && ($scope.$parent.note._id === data.updatedNote)) {
+ // console.log('in here too');
+ // var note = data.notes.filter(function(obj) {
+ // return obj._id === data.updatedNote;
+ // });
+ // if ($scope.commenting) {
+ // var commentingObj = note[0].comments.filter(function(comment) {
+ // return $scope.commenting === comment._id;
+ // });
+ // commentingObj[0].commenting = true;
+ // }
+ // if ($scope.editing) {
+ // var editingObj = $scope.$parent.note.comments.filter(function(comment) {
+ // return $scope.editing === comment._id;
+ // });
+ // console.log(editingObj[0]);
+ // var newEditingObj = note[0].comments.filter(function(comment) {
+ // return $scope.editing === comment._id;
+ // });
+ // newEditingObj[0].editing = true;
+ // newEditingObj[0].commentEdit = editingObj[0].commentEdit;
+ // }
+ // $scope.$parent.note = note[0];
+ // angular.forEach($scope.$parent.note.comments, function(comment, val) {
+ // comment.userPic = comment.user.providerData.profile_image_url_https;
+ // angular.forEach(comment.comments, function(comment, val) {
+ // comment.userPic = comment.user.providerData.profile_image_url_https;
+ // });
+ // });
+ // }
+ });
+
+ }
+]);
diff --git a/public/modules/core/controllers/comments.client.controller.js.orig b/public/modules/core/controllers/comments.client.controller.js.orig
new file mode 100644
index 0000000..4d790f9
--- /dev/null
+++ b/public/modules/core/controllers/comments.client.controller.js.orig
@@ -0,0 +1,339 @@
+'use strict';
+
+angular.module('core')
+
+.controller('CommentsController', [ '$scope', 'Authentication', 'projectsObj', 'mySocket', 'Projects', '$stateParams', '$modal',
+ function($scope, Authentication, projectsObj, mySocket, Projects, $stateParams, $modal) {
+ $scope.authentication = Authentication;
+ $scope.commenting = false;
+ $scope.editing = false;
+
+ $scope.toggleCommenting = function() {
+ if (this.obj.commenting) {
+ this.obj.commenting = false;
+ $scope.commenting = false;
+ $scope.nestedCommentInput = false;
+ } else {
+ this.obj.commenting = true;
+ $scope.commenting = this.obj._id;
+ $scope.nestedCommentInput = this.nestedCommentInput;
+ console.log(this.obj.nestedCommentInput);
+ }
+ };
+
+ // maybe set a watcher to obj.commentEdit?
+ $scope.startEditing = function() {
+ this.obj.editing = true;
+ this.obj.commentEdit = this.obj.text;
+ $scope.editing = this.obj._id;
+ };
+
+ $scope.startNestedEditing = function() {
+ this.obj.editing = true;
+ this.obj.commentEdit = this.obj.text;
+ };
+
+ $scope.addComment = function() {
+ var project = $scope.project;
+ if (false) {
+ console.log('other stuff in the future');
+ } else if ($stateParams.noteId) {
+ console.log(project);
+ if ($stateParams.noteId) {
+ console.log($scope);
+ var note = $scope.note;
+ note.comments.push({
+ text: $scope.commentInput,
+ user: Authentication.user._id
+ });
+ console.log(note);
+<<<<<<< HEAD
+ console.log(project.notes);
+
+||||||| merged common ancestors
+ console.log(project.notes);
+
+=======
+
+>>>>>>> projectWork
+ // var noteIndex = project.notes.indexOf(note);
+ // console.log(noteIndex);
+ // if (!project.notes[noteIndex].comments) {
+ // project.notes[noteIndex].comments = [];
+ // }
+ // project.notes[noteIndex].comments.push({
+ // text: $scope.commentInput,
+ // user: Authentication.user._id
+ // });
+ project.updatedNote = $stateParams.noteId;
+ projectsObj.update(project);
+ console.log(project);
+ }
+
+ } else {
+ if (!project.comments) {
+ project.comments = [];
+ }
+ project.comments.push({
+ text: $scope.commentInput,
+ user: Authentication.user._id
+ });
+ project.updatedChat = true;
+ projectsObj.update(project)
+ .then(function(result) {
+ $scope.commentInput = '';
+ });
+ }
+ };
+
+ $scope.removeComment = function() {
+ var modalInstance = $modal.open({
+ templateUrl: '/modules/core/views/deleteComment.client.view.html',
+ controller: 'deleteCommentController'
+ });
+
+ var that = this;
+
+ modalInstance.result.then(function (result) {
+ if (result === 'delete') {
+ $scope.editing = false;
+ var project = $scope.$parent.project;
+ var index;
+ if ($stateParams.noteId) {
+ index = $scope.note.comments.indexOf(that.obj);
+ $scope.note.comments.splice(index, 1);
+ project.updatedNote = $stateParams.noteId;
+ projectsObj.update(project)
+ .then(function(result) {
+ $scope.$parent.project = result;
+ });
+ } else {
+ index = project.comments.indexOf(that.obj);
+ project.comments.splice(index, 1);
+ project.updatedChat = true;
+ projectsObj.update(project)
+ .then(function(result) {
+ // $scope.$parent.project = result;
+ });
+ }
+ }
+ });
+
+ };
+
+ $scope.addNestedComment = function() {
+ this.obj.comments.push({
+ text: this.obj.nestedCommentInput,
+ user: Authentication.user._id
+ });
+ var that = this;
+
+ if ($stateParams.noteId) {
+ $scope.project.updatedNote = $scope.$parent.note._id;
+ projectsObj.update($scope.project);
+ } else if ($stateParams.projectId) {
+ $scope.project.updatedChat = true;
+ projectsObj.update($scope.project)
+ .then(function() {
+ that.obj.nestedCommentInput = '';
+ });
+ }
+ };
+
+ $scope.removeNestedComment = function() {
+ var index = this.$parent.obj.comments.indexOf(this.obj);
+ this.$parent.obj.comments.splice(index, 1);
+ if (!$stateParams.noteId) {
+ $scope.project.updatedChat = true;
+<<<<<<< HEAD
+ }
+||||||| merged common ancestors
+ }
+=======
+ }
+ $scope.editing = false;
+>>>>>>> projectWork
+ projectsObj.update($scope.project)
+ .then(function(result) {
+ // $scope.project = result;
+ // $scope.$parent.project = result;
+ });
+ };
+
+ $scope.saveCommentEdit = function() {
+ this.obj.text = this.obj.commentEdit;
+ this.obj.editing = false;
+ $scope.editing = false;
+ if ($stateParams.noteId) {
+ $scope.project.updatedNote = $scope.note._id;
+ } else {
+ $scope.project.updatedChat = true;
+ }
+ projectsObj.update($scope.project);
+ };
+
+ $scope.cancelEdit = function() {
+ this.obj.editing = false;
+ $scope.editing = false;
+ };
+
+ mySocket.on('updated project', function(data) {
+ var project = new Projects(data),
+ obj,
+ viewing;
+
+ if ($scope.note) {
+ viewing = 'note';
+ obj = $scope.note.comments;
+ } else if (($scope.$parent.project) && ($scope.$parent.project._id === data._id)) {
+ viewing = 'project';
+ obj = $scope.$parent.project.comments;
+ }
+
+ if ($scope.commenting) {
+ var commenting = obj.filter(function(comment) {
+ return $scope.commenting === comment._id;
+ });
+
+ if (viewing === 'note') {
+ var commentingNote = data.notes.filter(function(note) {
+ return $scope.note._id === note._id;
+ });
+ var newNoteCommentingObj = commentingNote[0].comments.filter(function(comment) {
+ return $scope.commenting === comment._id;
+ });
+ newNoteCommentingObj[0].commenting = true;
+ newNoteCommentingObj[0].nestedCommentInput = commenting[0].nestedCommentInput;
+
+ } else if (viewing === 'project') {
+ var newProjectCommentingObj = data.comments.filter(function(comment) {
+ return $scope.commenting === comment._id;
+ });
+ newProjectCommentingObj[0].commenting = true;
+ newProjectCommentingObj[0].nestedCommentInput = commenting[0].nestedCommentInput;
+ }
+
+ }
+
+ if ($scope.editing) {
+ if (viewing === 'note') {
+ var editingNoteObj = $scope.note.comments.filter(function(comment) {
+ return $scope.editing === comment._id;
+ });
+ var note = project.notes.filter(function(projectNote) {
+ return $scope.note._id === projectNote._id;
+ });
+ console.log(note);
+ var newEditingNoteObj = note[0].comments.filter(function(comment) {
+ return $scope.editing === comment._id;
+ });
+ newEditingNoteObj[0].editing = true;
+ newEditingNoteObj[0].commentEdit = editingNoteObj[0].commentEdit;
+ } else if (viewing === 'project') {
+ var editingObj = $scope.$parent.project.comments.filter(function(comment) {
+ return $scope.editing === comment._id;
+ });
+ var newEditingObj = project.comments.filter(function(comment) {
+ return $scope.editing === comment._id;
+ });
+ newEditingObj[0].editing = true;
+ newEditingObj[0].commentEdit = editingObj[0].commentEdit;
+ }
+ }
+
+ // If people are commenting, editing a comment, or viewing nested comments, keep their state.
+ // if (($scope.$parent.project) && ($scope.$parent.project._id === data._id)) {
+
+ // }
+
+ // if (($scope.$parent.note) && ($scope.$parent.note._id === data.updatedNote)) {
+
+ // }
+
+ // if ($scope.commenting) {
+ // var commenting = project.comments.filter(function(comment) {
+ // return $scope.commenting === comment._id;
+ // });
+ // var scopeComment = $scope.$parent.project.comments.filter(function(comment) {
+ // return $scope.commenting === comment._id;
+ // });
+ // commenting[0].nestedCommentInput = scopeComment[0].nestedCommentInput;
+ // commenting[0].commenting = true;
+ // }
+
+ // $scope.$parent.project = new Projects(data);
+
+<<<<<<< HEAD
+||||||| merged common ancestors
+ console.log(data);
+
+=======
+ console.log(data);
+
+ if ($stateParams.noteId === data.updatedNote) {
+ console.log('looking at updated note');
+ var newNote = data.notes.filter(function(note) {
+ return $stateParams.noteId === note._id;
+ });
+
+ $scope.$parent.note = newNote[0];
+ }
+
+>>>>>>> projectWork
+ // angular.forEach($scope.$parent.project.comments, function(comment, val) {
+ // comment.userPic = comment.user.providerData.profile_image_url_https;
+ // angular.forEach(comment.comments, function(comment, val) {
+ // comment.userPic = comment.user.providerData.profile_image_url_https;
+ // });
+ // });
+
+
+ // if ($scope.editing) {
+ // console.log($scope.editing);
+ // var editingObj = $scope.$parent.project.comments.filter(function(comment) {
+ // return $scope.editing === comment._id;
+ // });
+ // console.log(editingObj[0]);
+ // var newEditingObj = project.comments.filter(function(comment) {
+ // return $scope.editing === comment._id;
+ // });
+ // newEditingObj[0].editing = true;
+ // console.log(newEditingObj[0]);
+ // console.log($scope.commentInput);
+ // newEditingObj[0].commentInput = editingObj[0].commentInput;
+ // }
+
+ // if (($scope.$parent.note) && ($scope.$parent.note._id === data.updatedNote)) {
+ // console.log('in here too');
+ // var note = data.notes.filter(function(obj) {
+ // return obj._id === data.updatedNote;
+ // });
+ // if ($scope.commenting) {
+ // var commentingObj = note[0].comments.filter(function(comment) {
+ // return $scope.commenting === comment._id;
+ // });
+ // commentingObj[0].commenting = true;
+ // }
+ // if ($scope.editing) {
+ // var editingObj = $scope.$parent.note.comments.filter(function(comment) {
+ // return $scope.editing === comment._id;
+ // });
+ // console.log(editingObj[0]);
+ // var newEditingObj = note[0].comments.filter(function(comment) {
+ // return $scope.editing === comment._id;
+ // });
+ // newEditingObj[0].editing = true;
+ // newEditingObj[0].commentEdit = editingObj[0].commentEdit;
+ // }
+ // $scope.$parent.note = note[0];
+ // angular.forEach($scope.$parent.note.comments, function(comment, val) {
+ // comment.userPic = comment.user.providerData.profile_image_url_https;
+ // angular.forEach(comment.comments, function(comment, val) {
+ // comment.userPic = comment.user.providerData.profile_image_url_https;
+ // });
+ // });
+ // }
+ });
+
+ }
+]);
diff --git a/public/modules/core/controllers/deleteComment.client.controller.js b/public/modules/core/controllers/deleteComment.client.controller.js
new file mode 100644
index 0000000..b28f8aa
--- /dev/null
+++ b/public/modules/core/controllers/deleteComment.client.controller.js
@@ -0,0 +1,15 @@
+'use strict';
+
+angular.module('core')
+
+.controller('deleteCommentController', [ '$scope', '$modalInstance',
+ function($scope, $modalInstance) {
+ $scope.confirm = function() {
+ $modalInstance.close('delete');
+ };
+
+ $scope.nevermind = function() {
+ $modalInstance.close();
+ };
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/core/controllers/socket.client.controller.js b/public/modules/core/controllers/socket.client.controller.js
new file mode 100644
index 0000000..49698ed
--- /dev/null
+++ b/public/modules/core/controllers/socket.client.controller.js
@@ -0,0 +1,23 @@
+'use strict';
+
+angular.module('core')
+
+.controller('SocketsController', [ 'mySocket', 'Sockets', '$scope',
+ function(mySocket, Sockets, $scope) {
+ console.log('in sockets');
+
+ // Create new Socket
+ var create = function(socketID) {
+ var socket = new Sockets();
+ socket.socketID = socketID;
+ socket.$save(function(response) {
+ console.log(response);
+ });
+ };
+
+ mySocket.on('socketCon', function(sock) {
+ console.log(sock);
+ create(sock);
+ });
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/core/css/core.css b/public/modules/core/css/core.css
index c510891..6715e8f 100644
--- a/public/modules/core/css/core.css
+++ b/public/modules/core/css/core.css
@@ -1,3 +1,5 @@
+
+
.content {
margin-top: 50px;
}
@@ -12,4 +14,127 @@
}
.ng-valid.ng-dirty {
border-color: #78FA89;
-}
\ No newline at end of file
+}
+
+.comment {
+ margin-bottom: 15px;
+ position: relative;
+}
+
+.commentText {
+ position: relative;
+ left: 58px;
+ bottom: 13px;
+}
+
+.commentTime {
+ left: 5px;
+ bottom: 9px;
+ font-size: 11.5px;
+ position: relative;
+ color: #D3D3D3;
+}
+
+.trashCan {
+ width: 12.5px;
+ position: relative;
+ bottom: 12.5px;
+ left: 8px;
+}
+
+.tenPlusComments {
+ right: 4px;
+}
+
+.trashCan:hover {
+ cursor: pointer;
+}
+
+.editButton {
+ position: relative;
+ bottom: 16.5px;
+ left: 13px;
+ width: 17px;
+}
+
+.editButton:hover {
+ cursor: pointer;
+}
+
+.commentEdit {
+ position: relative;
+ bottom: 9px;
+ left: 57px;
+}
+
+.nestedComment {
+ margin-left: 57px;
+ margin-top: 11px;
+ font-size: 12.5px;
+}
+
+.nestedCommentText {
+ font-size: 12.5px;
+ position: relative;
+ bottom: 13px;
+ left: 48px;
+}
+
+.commentTrash {
+ bottom: 7px;
+ right: 8px;
+}
+
+.commentInput {
+ background-color: none;
+ resize: none;
+ margin-left: 5px;
+ width: 80%;
+}
+
+.commentInput:focus {
+ outline: none;
+ border: none;
+}
+
+.commentBubble {
+ height: 25px;
+ z-index: 2;
+ position: absolute;
+ right: .01px;
+ top: 23px;
+}
+
+.commentBubble:hover {
+ cursor: pointer;
+}
+
+.commentNumber {
+ font-size: 10px;
+ position: absolute;
+ right: 7px;
+ top: 26px;
+ color: black;
+ font-weight: 300;
+}
+
+.userPicture {
+ border-radius: 50%;
+ width: 40px;
+ height: 40px;
+}
+
+.smallUserPicture {
+ border-radius: 50%;
+ width: 29px;
+ height: 29px;
+}
+
+.createNote {
+ margin-bottom: 20px;
+}
+
+.ta-scroll-window {
+ min-height: 30px;
+ height: auto;
+}
diff --git a/public/modules/core/directives/comments.client.directive.js b/public/modules/core/directives/comments.client.directive.js
new file mode 100644
index 0000000..1946883
--- /dev/null
+++ b/public/modules/core/directives/comments.client.directive.js
@@ -0,0 +1,15 @@
+'use strict';
+
+angular.module('core')
+
+.directive('owComments', function () {
+ return {
+ restrict: 'EA',
+ scope: {
+ obj: '=obj',
+ project: '=project',
+ note: '=note'
+ },
+ templateUrl: '/modules/core/views/comments.client.view.html'
+ };
+});
\ No newline at end of file
diff --git a/public/modules/core/img/comment.png b/public/modules/core/img/comment.png
new file mode 100644
index 0000000..6671d69
Binary files /dev/null and b/public/modules/core/img/comment.png differ
diff --git a/public/modules/core/img/edit.png b/public/modules/core/img/edit.png
new file mode 100644
index 0000000..3c0e412
Binary files /dev/null and b/public/modules/core/img/edit.png differ
diff --git a/public/modules/core/img/trash.png b/public/modules/core/img/trash.png
new file mode 100644
index 0000000..e3387a0
Binary files /dev/null and b/public/modules/core/img/trash.png differ
diff --git a/public/modules/core/services/activity.client.service.js b/public/modules/core/services/activity.client.service.js
new file mode 100644
index 0000000..c1e146e
--- /dev/null
+++ b/public/modules/core/services/activity.client.service.js
@@ -0,0 +1,13 @@
+'use strict';
+
+//Sockets service used to communicate Sockets REST endpoints
+angular.module('core').factory('Activities', ['$resource',
+ function($resource) {
+ return $resource('activities/:activitiesId', { activityId: '@_id'
+ }, {
+ update: {
+ method: 'PUT'
+ }
+ });
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/core/services/momentCreator.client.service.js b/public/modules/core/services/momentCreator.client.service.js
new file mode 100644
index 0000000..4335e7d
--- /dev/null
+++ b/public/modules/core/services/momentCreator.client.service.js
@@ -0,0 +1,50 @@
+'use strict';
+
+angular.module('core')
+
+.factory('momentCreator', ['moment', '$q',
+ function (moment, $q) {
+ var MomentC = {};
+
+ MomentC.momentify = function(someMessages) {
+ var momentDefer = $q.defer();
+ var momentPromise = momentDefer.promise;
+
+ for (var r = 0; r < someMessages.length; r ++) {
+ someMessages[r].momentDate = moment(someMessages[r].created).fromNow();
+ var Com = (someMessages[r].momentDate.search('a minute')) + 1;
+ var Cm = (someMessages[r].momentDate.search('minutes')) + 1;
+ var Chour = (someMessages[r].momentDate.search('an hour')) + 1;
+ var Chours = (someMessages[r].momentDate.search('hours')) + 1;
+ var Cday = (someMessages[r].momentDate.search('an hour')) + 1;
+ var day = (someMessages[r].momentDate.search('a day')) + 1;
+ var days = (someMessages[r].momentDate.search('days')) + 1;
+
+ if (Cm) {
+ someMessages[r].momentDate = someMessages[r].momentDate.slice(0, Cm);
+ someMessages[r].momentDate = someMessages[r].momentDate.replace(/\s/g, '');
+ } else if (Com) {
+ someMessages[r].momentDate = '1m';
+ } else if (Chour) {
+ someMessages[r].momentDate = '1h';
+ } else if (Chours) {
+ someMessages[r].momentDate = someMessages[r].momentDate.slice(0, Chours);
+ someMessages[r].momentDate = someMessages[r].momentDate.replace(/\s/g, '');
+ } else if (day) {
+ someMessages[r].momentDate = '1d';
+ } else if (days) {
+ someMessages[r].momentDate = someMessages[r].momentDate.slice(0, days);
+ someMessages[r].momentDate = someMessages[r].momentDate.replace(/\s/g, '');
+ }
+
+ if ((r + 1) === someMessages.length) {
+ momentDefer.resolve();
+ }
+ }
+
+ return momentPromise;
+ };
+
+ return MomentC;
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/core/services/socket.client.service.js b/public/modules/core/services/socket.client.service.js
new file mode 100644
index 0000000..9b7ff8d
--- /dev/null
+++ b/public/modules/core/services/socket.client.service.js
@@ -0,0 +1,13 @@
+'use strict';
+
+//Sockets service used to communicate Sockets REST endpoints
+angular.module('core').factory('Sockets', ['$resource',
+ function($resource) {
+ return $resource('sockets/:socketId', { socketId: '@_id'
+ }, {
+ update: {
+ method: 'PUT'
+ }
+ });
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/core/services/socketFactory.client.service.js b/public/modules/core/services/socketFactory.client.service.js
new file mode 100644
index 0000000..9807c48
--- /dev/null
+++ b/public/modules/core/services/socketFactory.client.service.js
@@ -0,0 +1,7 @@
+'use strict';
+
+angular.module('core')
+
+.factory('mySocket', function(socketFactory) {
+ return socketFactory();
+});
\ No newline at end of file
diff --git a/public/modules/core/views/comments.client.view.html b/public/modules/core/views/comments.client.view.html
new file mode 100644
index 0000000..e05c410
--- /dev/null
+++ b/public/modules/core/views/comments.client.view.html
@@ -0,0 +1,61 @@
+
+
diff --git a/public/modules/core/views/comments.client.view.html.orig b/public/modules/core/views/comments.client.view.html.orig
new file mode 100644
index 0000000..1f92e6c
--- /dev/null
+++ b/public/modules/core/views/comments.client.view.html.orig
@@ -0,0 +1,72 @@
+
+
diff --git a/public/modules/core/views/deleteComment.client.view.html b/public/modules/core/views/deleteComment.client.view.html
new file mode 100644
index 0000000..1ae4b79
--- /dev/null
+++ b/public/modules/core/views/deleteComment.client.view.html
@@ -0,0 +1,8 @@
+
+
+are you sure you want to delete your comment?
+
+yep
+no, scratch that
+
+
\ No newline at end of file
diff --git a/public/modules/core/views/home.client.view.html b/public/modules/core/views/home.client.view.html
index 64b968b..114ad34 100644
--- a/public/modules/core/views/home.client.view.html
+++ b/public/modules/core/views/home.client.view.html
@@ -1,94 +1,5 @@
-
-
-
-
-
-
-
-
-
-
- Open-Source Full-Stack Solution For MEAN Applications
-
-
-
+
+
+ {{ obj.activityString }}
-
-
Congrats! You've configured and run the sample application.
-
MEAN.JS is a web application boilerplate, which means you should start changing everything :-)
-
This sample application tracks users and articles.
-
-
- Click
- Signup
- to get started.
-
-
- Configure your app to work with your social accounts, by editing the
- /config/env/*.js
- files.
-
-
- Edit your users module.
-
-
- Add new CRUD modules.
-
-
- Have fun...
-
-
-
-
-
-
- M ongoDB
-
-
MongoDB is a database. MongoDB's great manual is the place to get started with NoSQL and MongoDB.
-
-
-
-
-
- N ode.js
-
-
Node.js is a web server. Node's website and this stackOverflow thread offer excellent starting points to get to grasps with node.
-
-
-
-
MEAN.JS Documentation
-
- Once you're familiar with the foundation technology, check out the MEAN.JS Documentation:
-
-
-
- Enjoy & Keep Us Updated,
- The MEAN.JS Team.
\ No newline at end of file
diff --git a/public/modules/projects/config/projects.client.config.js b/public/modules/projects/config/projects.client.config.js
new file mode 100644
index 0000000..dba6c52
--- /dev/null
+++ b/public/modules/projects/config/projects.client.config.js
@@ -0,0 +1,11 @@
+'use strict';
+
+// Configuring the Articles module
+angular.module('projects').run(['Menus',
+ function(Menus) {
+ // Set top bar menu items
+ Menus.addMenuItem('topbar', 'Projects', 'projects', 'dropdown', '/projects(/create)?');
+ Menus.addSubMenuItem('topbar', 'projects', 'List Projects', 'projects');
+ Menus.addSubMenuItem('topbar', 'projects', 'New Project', 'projects/create');
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/projects/config/projects.client.routes.js b/public/modules/projects/config/projects.client.routes.js
new file mode 100644
index 0000000..5f8ff98
--- /dev/null
+++ b/public/modules/projects/config/projects.client.routes.js
@@ -0,0 +1,41 @@
+'use strict';
+
+//Setting up route
+angular.module('projects').config(['$stateProvider',
+ function($stateProvider) {
+ // Projects state routing
+ $stateProvider.
+ state('listProjects', {
+ url: '/projects',
+ templateUrl: 'modules/projects/views/list-projects.client.view.html'
+ }).
+ state('createProject', {
+ url: '/projects/create',
+ templateUrl: 'modules/projects/views/create-project.client.view.html'
+ }).
+ state('viewProject', {
+ url: '/projects/:projectId',
+ templateUrl: 'modules/projects/views/view-project.client.view.html'
+ }).
+ state('editProject', {
+ url: '/projects/:projectId/edit',
+ templateUrl: 'modules/projects/views/edit-project.client.view.html'
+ }).
+ state('createNote', {
+ url: '/projects/:projectId/notes/create',
+ templateUrl: 'modules/projects/views/create-note.client.view.html'
+ }).
+ state('listNotes', {
+ url: '/projects/:projectId/notes',
+ templateUrl: 'modules/projects/views/list-notes.client.view.html'
+ }).
+ state('viewNote', {
+ url: '/projects/:projectId/notes/:noteId',
+ templateUrl: 'modules/projects/views/view-note.client.view.html'
+ }).
+ state('editNote', {
+ url: '/projects/:projectId/notes/:noteId/edit',
+ templateUrl: 'modules/projects/views/edit-note.client.view.html'
+ });
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/projects/controllers/projects.client.controller.js b/public/modules/projects/controllers/projects.client.controller.js
new file mode 100755
index 0000000..05bbc88
--- /dev/null
+++ b/public/modules/projects/controllers/projects.client.controller.js
@@ -0,0 +1,167 @@
+'use strict';
+
+// Projects controller
+angular.module('projects').controller('ProjectsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Projects', 'projectsObj', 'mySocket', '$modal',
+ function($scope, $stateParams, $location, Authentication, Projects, projectsObj, mySocket, $modal) {
+ $scope.authentication = Authentication;
+
+ // Create new Project
+ $scope.create = function() {
+ var project = new Projects({
+ name: this.name,
+ description: this.description
+ });
+
+ projectsObj.create(project)
+ .then(function(result) {
+ return;
+ }, function(reason) {
+ $scope.error = reason;
+ });
+ };
+
+ // Update existing Project
+ $scope.update = function() {
+ var project = $scope.project;
+
+ projectsObj.update($scope.project)
+ .then(function(result) {
+ $location.path('projects/' + $scope.project._id);
+ }, function(reason) {
+ $scope.error = reason;
+ });
+ };
+
+ $scope.followProject = function() {
+ var project = $scope.project;
+ project.followProject = true;
+
+ Projects.update(project);
+ };
+
+ // Remove existing Project
+ $scope.remove = function(project) {
+ if ( project ) {
+ project.$remove();
+
+ for (var i in $scope.projects) {
+ if ($scope.projects [i] === project) {
+ $scope.projects.splice(i, 1);
+ }
+ }
+ } else {
+ $scope.project.$remove(function() {
+ $location.path('projects');
+ });
+ }
+ };
+
+ // Find a list of Projects
+ $scope.find = function() {
+ $scope.projects = Projects.query();
+ };
+
+ // Find existing Project
+ $scope.findOne = function() {
+ $scope.project = Projects.get({
+ projectId: $stateParams.projectId
+ });
+ };
+
+ // Publish note
+ $scope.publishNote = function() {
+ var project = $scope.project;
+ var newNote = {
+ title: $scope.noteTitle,
+ content: $scope.noteContent,
+ user: Authentication.user._id
+ };
+ // project.notes.push(newNote);
+ project.newNote = newNote;
+ projectsObj.update(project)
+ .then(function(result) {
+ $location.path('projects/' + result._id + '/notes/' + result.newNote._id);
+ }, function(reason) {
+ $scope.error = reason;
+ console.log($scope.error);
+ });
+ };
+
+ // Find project note
+ $scope.findNote = function() {
+ var findParams = { note: true };
+
+ projectsObj.find(findParams)
+ .then(function(result) {
+ $scope.project = result;
+ $scope.note = result.note;
+ });
+ };
+
+ // Update note
+ $scope.updateNote = function() {
+ var project = $scope.project;
+ var noteIndex = project.notes.indexOf($scope.note);
+ project.notes[noteIndex].title = $scope.note.title;
+ project.notes[noteIndex].content = $scope.note.content;
+ project.updatedNote = $scope.note._id;
+ projectsObj.update(project)
+ .then(function(result) {
+ $location.path('projects/' + $scope.project._id + '/notes/' + $scope.note._id);
+ }, function(reason) {
+ $scope.error = reason;
+ console.log($scope.error);
+ });
+ };
+
+ // Remove project
+ $scope.openRemoveModal = function() {
+ var modalInstance = $modal.open({
+ templateUrl: '/modules/projects/views/remove-project-modal.client.view.html',
+ controller: 'removeProjectController'
+ });
+
+
+ modalInstance.result.then(function(answer) {
+ projectsObj.remove($scope.project);
+ });
+ };
+
+ // Remove note
+ $scope.openRemoveNoteModal = function() {
+ var modalInstance = $modal.open({
+ templateUrl: '/modules/projects/views/remove-note-modal.client.view.html',
+ controller: 'removeNoteController'
+ });
+
+ modalInstance.result.then(function(answer) {
+ var index = $scope.project.notes.indexOf($scope.note);
+ $scope.project.notes.splice(index, 1);
+ projectsObj.update($scope.project);
+ $location.path('projects/' + $scope.project._id + '/notes');
+ });
+ };
+
+ // View next note
+ $scope.nextNote = function() {
+ var currentIndex = $scope.project.notes.indexOf($scope.note);
+ $location.path('projects/' + $scope.project._id + '/notes/' + $scope.project.notes[(currentIndex + 1)]._id);
+ $scope.findNote();
+ };
+
+ // View previous note
+ $scope.previousNote = function() {
+ var currentIndex = $scope.project.notes.indexOf($scope.note);
+ $location.path('projects/' + $scope.project._id + '/notes/' + $scope.project.notes[(currentIndex - 1)]._id);
+ $scope.findNote();
+ };
+
+ // Socket logic
+ mySocket.on('updated project', function(data) {
+ // if($stateParams.projectId === data._id) {
+ // $scope.project = data;
+ // }
+ });
+
+ }
+]);
diff --git a/public/modules/projects/controllers/removeNote.client.controller.js b/public/modules/projects/controllers/removeNote.client.controller.js
new file mode 100644
index 0000000..648ef87
--- /dev/null
+++ b/public/modules/projects/controllers/removeNote.client.controller.js
@@ -0,0 +1,15 @@
+'use strict';
+
+angular.module('projects')
+
+.controller('removeNoteController', [ '$scope', '$modalInstance',
+ function ($scope, $modalInstance) {
+ $scope.remove = function() {
+ $modalInstance.close('yep');
+ };
+
+ $scope.nevermind = function() {
+ $modalInstance.dismiss('nevermind');
+ };
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/projects/controllers/removeProject.client.controller.js b/public/modules/projects/controllers/removeProject.client.controller.js
new file mode 100644
index 0000000..17c7a76
--- /dev/null
+++ b/public/modules/projects/controllers/removeProject.client.controller.js
@@ -0,0 +1,16 @@
+'use strict';
+
+angular.module('projects')
+
+.controller('removeProjectController', [ '$scope', 'projectsObj', '$modalInstance',
+ function ($scope, projectsObj, $modalInstance) {
+ console.log('yo');
+ $scope.remove = function() {
+ $modalInstance.close('yep');
+ };
+
+ $scope.nevermind = function() {
+ $modalInstance.dismiss('nevermind');
+ };
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/projects/css/style.css b/public/modules/projects/css/style.css
new file mode 100644
index 0000000..1270eb7
--- /dev/null
+++ b/public/modules/projects/css/style.css
@@ -0,0 +1,3 @@
+.form-control {
+ height: 100%;
+}
diff --git a/public/modules/projects/projects.client.module.js b/public/modules/projects/projects.client.module.js
new file mode 100644
index 0000000..73fe41b
--- /dev/null
+++ b/public/modules/projects/projects.client.module.js
@@ -0,0 +1,4 @@
+'use strict';
+
+// Use applicaion configuration module to register a new module
+ApplicationConfiguration.registerModule('projects');
\ No newline at end of file
diff --git a/public/modules/projects/services/projects.client.service.js b/public/modules/projects/services/projects.client.service.js
new file mode 100644
index 0000000..6373d05
--- /dev/null
+++ b/public/modules/projects/services/projects.client.service.js
@@ -0,0 +1,13 @@
+'use strict';
+
+//Projects service used to communicate Projects REST endpoints
+angular.module('projects').factory('Projects', ['$resource',
+ function($resource) {
+ return $resource('projects/:projectId', { projectId: '@_id'
+ }, {
+ update: {
+ method: 'PUT'
+ }
+ });
+ }
+]);
\ No newline at end of file
diff --git a/public/modules/projects/services/projectsObj.client.service.js b/public/modules/projects/services/projectsObj.client.service.js
new file mode 100644
index 0000000..518841c
--- /dev/null
+++ b/public/modules/projects/services/projectsObj.client.service.js
@@ -0,0 +1,100 @@
+'use strict';
+
+angular.module('projects')
+
+.factory('projectsObj', ['Projects', '$location', '$q', '$stateParams', 'momentCreator', 'mySocket',
+ function(Projects, $location, $q, $stateParams, momentCreator, mySocket) {
+ var projectsObj = {};
+
+ // Create project
+ projectsObj.create = function(project) {
+ var createDefer = $q.defer();
+ var createPromise = createDefer.promise;
+
+ project.$save(function(response) {
+ console.log(response);
+ $location.path('projects/' + response._id);
+ return createDefer.resolve(response);
+ }, function(errorResponse) {
+ return createDefer.reject(errorResponse.data.message);
+ });
+
+ return createPromise;
+ };
+
+ // Remove project
+ projectsObj.remove = function(project) {
+ project.$remove(function() {
+ $location.path('projects');
+ });
+ };
+
+ // Update project
+ projectsObj.update = function(project) {
+ var updateDefer = $q.defer();
+ var updatePromise = updateDefer.promise;
+ var updatedNote = project.updatedNote;
+ var newNote = project.newNote;
+ var parentComment = project.parentComment;
+ var projectObj = new Projects(project);
+
+ projectObj.$update(function(response) {
+ mySocket.emit('project updated', projectObj);
+ updateDefer.resolve(projectObj);
+ }, function(errorResponse) {
+ updateDefer.reject(errorResponse.data.message);
+ });
+
+ return updatePromise;
+ };
+
+ // Find project
+ projectsObj.find = function(findParams) {
+ var findDefer = $q.defer();
+ var findPromise = findDefer.promise;
+
+ var project = Projects.get({
+ projectId: $stateParams.projectId,
+ noteId: $stateParams.noteId
+ }, function() {
+ if (findParams && findParams.chat) {
+ angular.forEach(project.comments, function(comment, key) {
+ comment.userPic = comment.user.providerData.profile_image_url_https;
+
+ angular.forEach(comment.comments, function(comment, key) {
+ comment.userPic = comment.user.providerData.profile_image_url_https;
+ });
+ momentCreator.momentify(comment.comments);
+
+ if ((key + 1) === project.comments.length) {
+ findDefer.resolve(project);
+ }
+ });
+
+
+ momentCreator.momentify(project.comments)
+ .then(function() {
+ findDefer.resolve(project);
+ });
+ if (project.comments.length < 1) {
+ findDefer.resolve(project);
+ }
+ } else if (findParams && findParams.note) {
+ var theNote = project.notes.filter(function(obj) {
+ return obj._id === $stateParams.noteId;
+ });
+
+ project.note = theNote[0];
+
+ findDefer.resolve(project);
+ } else {
+ findDefer.resolve(project);
+ }
+ });
+
+ return findPromise;
+ };
+
+ return projectsObj;
+ }
+]);
diff --git a/public/modules/projects/tests/projects.client.controller.test.js b/public/modules/projects/tests/projects.client.controller.test.js
new file mode 100644
index 0000000..2c5b29a
--- /dev/null
+++ b/public/modules/projects/tests/projects.client.controller.test.js
@@ -0,0 +1,163 @@
+'use strict';
+
+(function() {
+ // Projects Controller Spec
+ describe('Projects Controller Tests', function() {
+ // Initialize global variables
+ var ProjectsController,
+ scope,
+ $httpBackend,
+ $stateParams,
+ $location;
+
+ // The $resource service augments the response object with methods for updating and deleting the resource.
+ // If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
+ // the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher.
+ // When the toEqualData matcher compares two objects, it takes only object properties into
+ // account and ignores methods.
+ beforeEach(function() {
+ jasmine.addMatchers({
+ toEqualData: function(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ return {
+ pass: angular.equals(actual, expected)
+ };
+ }
+ };
+ }
+ });
+ });
+
+ // Then we can start by loading the main application module
+ beforeEach(module(ApplicationConfiguration.applicationModuleName));
+
+ // The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
+ // This allows us to inject a service but then attach it to a variable
+ // with the same name as the service.
+ beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
+ // Set a new global scope
+ scope = $rootScope.$new();
+
+ // Point global variables to injected services
+ $stateParams = _$stateParams_;
+ $httpBackend = _$httpBackend_;
+ $location = _$location_;
+
+ // Initialize the Projects controller.
+ ProjectsController = $controller('ProjectsController', {
+ $scope: scope
+ });
+ }));
+
+ it('$scope.find() should create an array with at least one Project object fetched from XHR', inject(function(Projects) {
+ // Create sample Project using the Projects service
+ var sampleProject = new Projects({
+ name: 'New Project'
+ });
+
+ // Create a sample Projects array that includes the new Project
+ var sampleProjects = [sampleProject];
+
+ // Set GET response
+ $httpBackend.expectGET('projects').respond(sampleProjects);
+
+ // Run controller functionality
+ scope.find();
+ $httpBackend.flush();
+
+ // Test scope value
+ expect(scope.projects).toEqualData(sampleProjects);
+ }));
+
+ it('$scope.findOne() should create an array with one Project object fetched from XHR using a projectId URL parameter', inject(function(Projects) {
+ // Define a sample Project object
+ var sampleProject = new Projects({
+ name: 'New Project'
+ });
+
+ // Set the URL parameter
+ $stateParams.projectId = '525a8422f6d0f87f0e407a33';
+
+ // Set GET response
+ $httpBackend.expectGET(/projects\/([0-9a-fA-F]{24})$/).respond(sampleProject);
+
+ // Run controller functionality
+ scope.findOne();
+ $httpBackend.flush();
+
+ // Test scope value
+ expect(scope.project).toEqualData(sampleProject);
+ }));
+
+ it('$scope.create() with valid form data should send a POST request with the form input values and then locate to new object URL', inject(function(Projects) {
+ // Create a sample Project object
+ var sampleProjectPostData = new Projects({
+ name: 'New Project'
+ });
+
+ // Create a sample Project response
+ var sampleProjectResponse = new Projects({
+ _id: '525cf20451979dea2c000001',
+ name: 'New Project'
+ });
+
+ // Fixture mock form input values
+ scope.name = 'New Project';
+
+ // Set POST response
+ $httpBackend.expectPOST('projects', sampleProjectPostData).respond(sampleProjectResponse);
+
+ // Run controller functionality
+ scope.create();
+ $httpBackend.flush();
+
+ // Test form inputs are reset
+ expect(scope.name).toEqual('');
+
+ // Test URL redirection after the Project was created
+ expect($location.path()).toBe('/projects/' + sampleProjectResponse._id);
+ }));
+
+ it('$scope.update() should update a valid Project', inject(function(Projects) {
+ // Define a sample Project put data
+ var sampleProjectPutData = new Projects({
+ _id: '525cf20451979dea2c000001',
+ name: 'New Project'
+ });
+
+ // Mock Project in scope
+ scope.project = sampleProjectPutData;
+
+ // Set PUT response
+ $httpBackend.expectPUT(/projects\/([0-9a-fA-F]{24})$/).respond();
+
+ // Run controller functionality
+ scope.update();
+ $httpBackend.flush();
+
+ // Test URL location to new object
+ expect($location.path()).toBe('/projects/' + sampleProjectPutData._id);
+ }));
+
+ it('$scope.remove() should send a DELETE request with a valid projectId and remove the Project from the scope', inject(function(Projects) {
+ // Create new Project object
+ var sampleProject = new Projects({
+ _id: '525a8422f6d0f87f0e407a33'
+ });
+
+ // Create new Projects array and include the Project
+ scope.projects = [sampleProject];
+
+ // Set expected DELETE response
+ $httpBackend.expectDELETE(/projects\/([0-9a-fA-F]{24})$/).respond(204);
+
+ // Run controller functionality
+ scope.remove(sampleProject);
+ $httpBackend.flush();
+
+ // Test array after successful delete
+ expect(scope.projects.length).toBe(0);
+ }));
+ });
+}());
\ No newline at end of file
diff --git a/public/modules/projects/views/create-note.client.view.html b/public/modules/projects/views/create-note.client.view.html
new file mode 100644
index 0000000..bc0a83a
--- /dev/null
+++ b/public/modules/projects/views/create-note.client.view.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+ Create Note
+ Title
+
+ Note
+
+
+ publish note
+
diff --git a/public/modules/projects/views/create-project.client.view.html b/public/modules/projects/views/create-project.client.view.html
new file mode 100644
index 0000000..690668e
--- /dev/null
+++ b/public/modules/projects/views/create-project.client.view.html
@@ -0,0 +1,26 @@
+
+
diff --git a/public/modules/projects/views/edit-note.client.view.html b/public/modules/projects/views/edit-note.client.view.html
new file mode 100644
index 0000000..9eeeae4
--- /dev/null
+++ b/public/modules/projects/views/edit-note.client.view.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ overview
+ notes
+ previous
+ next
+ create note
+ Editing Note
+ Title
+
+ Note
+
+
+
+
+
+
+
+
+ update note
+
+
+ remove note
+
+
+
diff --git a/public/modules/projects/views/edit-project.client.view.html b/public/modules/projects/views/edit-project.client.view.html
new file mode 100644
index 0000000..35d7854
--- /dev/null
+++ b/public/modules/projects/views/edit-project.client.view.html
@@ -0,0 +1,23 @@
+
\ No newline at end of file
diff --git a/public/modules/projects/views/list-notes.client.view.html b/public/modules/projects/views/list-notes.client.view.html
new file mode 100644
index 0000000..311034c
--- /dev/null
+++ b/public/modules/projects/views/list-notes.client.view.html
@@ -0,0 +1,19 @@
+
\ No newline at end of file
diff --git a/public/modules/projects/views/list-projects.client.view.html b/public/modules/projects/views/list-projects.client.view.html
new file mode 100644
index 0000000..a037d57
--- /dev/null
+++ b/public/modules/projects/views/list-projects.client.view.html
@@ -0,0 +1,19 @@
+
+
+
+
+ No Projects yet, why don't you
create one ?
+
+
\ No newline at end of file
diff --git a/public/modules/projects/views/remove-note-modal.client.view.html b/public/modules/projects/views/remove-note-modal.client.view.html
new file mode 100644
index 0000000..e2a9f2d
--- /dev/null
+++ b/public/modules/projects/views/remove-note-modal.client.view.html
@@ -0,0 +1,7 @@
+
+ sure you want to delete this note?
+
+
+ f ya
+ nope
+
\ No newline at end of file
diff --git a/public/modules/projects/views/remove-project-modal.client.view.html b/public/modules/projects/views/remove-project-modal.client.view.html
new file mode 100644
index 0000000..ea312c1
--- /dev/null
+++ b/public/modules/projects/views/remove-project-modal.client.view.html
@@ -0,0 +1,11 @@
+
+
+ hey, you sure you want to remove this project from openwork?
+
+
+ yes
+
+ no
+
+
+
\ No newline at end of file
diff --git a/public/modules/projects/views/view-note.client.view.html b/public/modules/projects/views/view-note.client.view.html
new file mode 100644
index 0000000..2d52138
--- /dev/null
+++ b/public/modules/projects/views/view-note.client.view.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ previous
+ next
+
+ edit
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/modules/projects/views/view-project.client.view.html b/public/modules/projects/views/view-project.client.view.html
new file mode 100644
index 0000000..9071883
--- /dev/null
+++ b/public/modules/projects/views/view-project.client.view.html
@@ -0,0 +1,21 @@
+
diff --git a/readme notes b/readme notes
new file mode 100644
index 0000000..b50f57b
--- /dev/null
+++ b/readme notes
@@ -0,0 +1,30 @@
+We're building a public space to organize, share, and collaborate on any project. Somewhere to see what others are working on and the projects they contribute to, and then be able to jump in and collaborate instantly.
+
+Right now we're prototyping in keynote and developing the app with MEANJS.
+
+##Prototype
+
+Open in keynote and go ⌥⌘P to make it full screen. Most things you'd expect to be able to click on work, otherwise you can use the arrow keys to cruise through the slides.
+
+##App
+
+We're developing the basic infastructure for a mean stack app.
+To run the app, cd into the app and run `npm install`. Then run `grunt`. The app will run on localhost:3000.
+
+The data structure:
+User objects store projects, activity around the site, and who/what the user is following
+users
+ projects
+ description
+ notes
+ comments
+ comments
+ activity
+ following
+
+all community activity saved with string, action type, users, and date
+activity
+ user
+ action type
+ string
+ date
\ No newline at end of file