most pages under pseudo-nav behavior
[oweals/finalsclub.git] / app.js
diff --git a/app.js b/app.js
index 722e164d76d40103e57825360bf2c37687d93320..34b4c757e231f46fbf55bb658ba7accf667841b8 100644 (file)
--- a/app.js
+++ b/app.js
@@ -22,6 +22,7 @@ var hat                                       = require('hat');
 var connect                    = require( 'connect' );
 var Session                    = connect.middleware.session.Session;
 var parseCookie = connect.utils.parseCookie;
+var Backchannel = require('../bc/backchannel');
 
 // Depracated
 // Used for initial testing
@@ -439,6 +440,14 @@ function loadNote( req, res, next ) {
   });
 }
 
+function checkAjax( req, res, next ) {
+  if ( req.xhr ) {
+    next();
+  } else {
+    res.redirect( '/' );
+  }
+}
+
 // Dynamic Helpers are loaded automatically into views
 app.dynamicHelpers( {
   // express-messages is for flash messages for easy
@@ -474,54 +483,57 @@ app.get( '/', loadUser, function( req, res ) {
 // Used to display all available schools and any courses
 // in those schools.
 // Public with some private information
-app.get( '/schools', loadUser, function( req, res ) {
+app.get( '/schools', checkAjax, loadUser, function( req, res ) {
   var user = req.user;
 
+  var schoolList = [];
   // Find all schools and sort by name
   // XXX mongoose's documentation on sort is extremely poor, tread carefully
   School.find( {} ).sort( 'name', '1' ).run( function( err, schools ) {
     if( schools ) {
       // If schools are found, loop through them gathering any courses that are
       // associated with them and then render the page with that information.
-      async.forEach(
-        schools,
-        function( school, callback ) {
-          // Check if user is authorized with each school
-          school.authorize( user, function( authorized ) {
-            // This is used to display interface elements for those users
-            // that are are allowed to see them, for instance a 'New Course' button.
-            school.authorized = authorized;
-
-            // Find all courses for school by it's id and sort by name
-            Course.find( { 'school' : school._id } ).sort( 'name', '1' ).run( function( err, courses ) {
-              // If any courses are found, set them to the appropriate school, otherwise
-              // leave empty.
-              if( courses.length > 0 ) {
-                school.courses = courses.filter(function(course) {
-                  if (!course.deleted) return course;
-                });
-              } else {
-                school.courses = [];
-              }
-              // This tells async (the module) that each iteration of forEach is
-              // done and will continue to call the rest until they have all been
-              // completed, at which time the last function below will be called.
-              callback();
-            });
-          });
-        },
-        // After all schools and courses have been found, render them
-        function( err ) {
-          res.render( 'schools', { 'schools' : schools } );
-        }
-      );
+      res.json({ 'schools' : schools.map(function(school) {
+        return school.sanitized;
+      })})
     } else {
       // If no schools have been found, display none
-      res.render( 'schools', { 'schools' : [] } );
+      //res.render( 'schools', { 'schools' : [] } );
+      res.json({ 'schools' : [] });
     }
   });
 });
 
+app.get( '/school/:id', checkAjax, loadUser, loadSchool, function( req, res ) {
+  var school = req.school;
+  var user = req.user;
+
+  school.authorize( user, function( authorized ) {
+    // This is used to display interface elements for those users
+    // that are are allowed to see th)m, for instance a 'New Course' button.
+    var sanitizedSchool = school.sanitized;
+    sanitizedSchool.authorized = authorized;
+    // Find all courses for school by it's id and sort by name
+    Course.find( { 'school' : school._id } ).sort( 'name', '1' ).run( function( err, courses ) {
+      // If any courses are found, set them to the appropriate school, otherwise
+      // leave empty.
+      if( courses.length > 0 ) {
+        sanitizedSchool.courses = courses.filter(function(course) {
+          if (!course.deleted) return course;
+        }).map(function(course) {
+          return course.sanitized;
+        });
+      } else {
+        sanitizedSchool.courses = [];
+      }
+      // This tells async (the module) that each iteration of forEach is
+      // done and will continue to call the rest until they have all been
+      // completed, at which time the last function below will be called.
+      res.json({ 'school': sanitizedSchool })
+    });
+  });
+});
+
 // New course page
 // Displays form to create new course
 // Private, requires user to be authorized
@@ -1648,7 +1660,25 @@ app.get( '/archive/note/:id', loadUser, function( req, res ) {
 //
 // Data types:
 // Posts -  Posts are the main items in backchannel, useful for questions or discussion points
-//             [[ example object needed]]
+//             [[ example object needed with explanation E.G: 
+/*
+               Post: { postID: '999-1',
+                                 userID: '1234',
+                                 userName: 'Bob Jones',
+                                 userAffil: 'Instructor',
+                                 body: 'This is the text content of the post.',
+                                 comments: { {<commentObj>, <commentObj>, ...},
+                                 public: true,
+                                 votes:   [ <userID>, <userID>, ...],
+                                 reports: [ <userID>, <userID>, ...]
+                               }
+                 Comment: { body: 'foo bar', userName: 'Bob Jones', userAffil: 'Instructor' }
+               
+                 if anonymous: userName => 'Anonymous', userAffil => 'N/A'
+*/
+//
+//
+//
 // Comments - Comments are replies to posts, for clarification or answering questions
 //             [[ example object needed]]
 // Votes - Votes signifyg a users approval of a post
@@ -1669,6 +1699,7 @@ app.get( '/archive/note/:id', loadUser, function( req, res ) {
 //             [[ example needed ]]
 // reports - An array of user ids which are the users that reported the post
 //             [[ reports would be "this post is flagged as inappropriate"? ]]
+//             [[ bruml: consistent terminology needed ]]
 //
 // Posts and comments can be made anonymously. When a post is anonymous, the users info is stripped
 // from the post and the userName is set to Anonymous and the userAffil to N/A. This is to allow
@@ -1758,148 +1789,34 @@ io.set('authorization', function ( handshake, next ) {
   }
 });
 
-
-var backchannel = io
-.of( '/backchannel' )
-.on( 'connection', function( socket ) {
-
-  socket.on('subscribe', function(lecture, cb) {
-    socket.join(lecture);
+var backchannel = new Backchannel(app, io.of('/backchannel'), {
+  subscribe: function(lecture, send) {
     Post.find({'lecture': lecture}, function(err, posts) {
-      if (socket.handshake.user) {
-        cb(posts);
-      } else {
-        var posts = posts.filter(
-          function(post) {
-          if (post.public)
-            return post;
-        }
-        )
-        cb(posts)
-      }
+      send(posts);
     });
-  });
-
-  socket.on('post', function(res) {
+  },
+  post: function(fillPost) {
     var post = new Post;
-    var _post = res.post;
-    var lecture = res.lecture;
-    post.lecture = lecture;
-    if ( _post.anonymous ) {
-      post.userid              = 0;
-      post.userName    = 'Anonymous';
-      post.userAffil = 'N/A';
-    } else {
-      post.userName = _post.userName;
-      post.userAffil = _post.userAffil;
-    }
-
-    post.public = _post.public;
-    post.date = new Date();
-    post.body = _post.body;
-    post.votes = [];
-    post.reports = [];
-    post.save(function(err) {
-      if (err) {
-        // XXX some error handling
-        console.log(err);
-      } else {
-        if (post.public) {
-          backchannel.in(lecture).emit('post', post);
-        } else {
-          privateEmit(lecture, 'post', post);
-        }
-      }
+    fillPost(post, function(send) {
+      post.save(function(err) {
+        send();
+      });
     });
-  });
-
-  socket.on('vote', function(res) {
-    var vote = res.vote;
-    var lecture = res.lecture;
-    Post.findById(vote.parentid, function( err, post ) {
-      if (!err) {
-        if (post.votes.indexOf(vote.userid) == -1) {
-          post.votes.push(vote.userid);
-          post.save(function(err) {
-            if (err) {
-              // XXX error handling
-            } else {
-              if (post.public) {
-                backchannel.in(lecture).emit('vote', vote);
-              } else {
-                privteEmit(lecture, 'vote', vote);
-              }
-            }
-          });
-        }
-      }
-    })
-  });
-
-  socket.on('report', function(res) {
-    var report = res.report;
-    var lecture = res.lecture;
-    Post.findById(report.parentid, function( err, post ){
-      if (!err) {
-        if (post.reports.indexOf(report.userid) == -1) {
-          post.reports.push(report.userid);
-          post.save(function(err) {
-            if (err) {
-              // XXX error handling
-            } else {
-              if (post.public) {
-                backchannel.in(lecture).emit('report', report);
-              } else {
-                privateEmit(lecture, 'report', report);
-              }
-            }
-          });
-        }
-      }
-    })
-  });
-
-  socket.on('comment', function(res) {
-    var comment = res.comment;
-    var lecture = res.lecture;
-    console.log('anon', comment.anonymous);
-    if ( comment.anonymous ) {
-      comment.userid           = 0;
-      comment.userName = 'Anonymous';
-      comment.userAffil = 'N/A';
-    }
-    Post.findById(comment.parentid, function( err, post ) {
-      if (!err) {
-        post.comments.push(comment);
-        post.date = new Date();
+  },
+  items: function(postId, addItem) {
+    Post.findById(postId, function( err, post ) {
+      addItem(post, function(send) {
         post.save(function(err) {
-          if (err) {
-            console.log(err);
-          } else {
-            if (post.public) {
-              backchannel.in(lecture).emit('comment', comment);
-            } else {
-              privateEmit(lecture, 'comment', comment);
-            }
-          }
-        })
-      }
-    })
-  });
-
-  function privateEmit(lecture, event, data) {
-    backchannel.clients(lecture).forEach(function(socket) {
-      if (socket.handshake.user)
-        socket.emit(event, data);
+          send();
+        });
+      })
     })
   }
-
-  socket.on('disconnect', function() {
-    //delete clients[socket.id];
-  });
 });
 
 
+
+
 var counters = {};
 
 var counts = io