X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=app.js;h=ebe2d0c1c84dd436a418251ea9a10970b5348726;hb=a0b2a9a1dfe38969b3336d497f5c5667bb0c8a29;hp=2799c583dffecf8ebfb870ff52631e41485036b3;hpb=b271811558bbc7e918b8dc87c421a748f85ffb42;p=oweals%2Ffinalsclub.git diff --git a/app.js b/app.js index 2799c58..ebe2d0c 100644 --- a/app.js +++ b/app.js @@ -1,5 +1,5 @@ // FinalsClub Server -// +// // This file consists of the main webserver for FinalsClub.org // and is split between a standard CRUD style webserver and // a websocket based realtime webserver. @@ -22,7 +22,8 @@ var hat = require('hat'); var connect = require( 'connect' ); var Session = connect.middleware.session.Session; var parseCookie = connect.utils.parseCookie; -var Backchannel = require('../bc/backchannel'); +var Backchannel = require('./bc/backchannel'); + // Depracated // Used for initial testing @@ -33,11 +34,11 @@ var app = module.exports = express.createServer(); // Load Mongoose Schemas // The actual schemas are located in models.j -var User = mongoose.model( 'User' ); -var School = mongoose.model( 'School' ); -var Course = mongoose.model( 'Course' ); -var Lecture = mongoose.model( 'Lecture' ); -var Note = mongoose.model( 'Note' ); +var User = mongoose.model( 'User' ); +var School = mongoose.model( 'School' ); +var Course = mongoose.model( 'Course' ); +var Lecture = mongoose.model( 'Lecture' ); +var Note = mongoose.model( 'Note' ); // More schemas used for legacy data var ArchivedCourse = mongoose.model( 'ArchivedCourse' ); @@ -45,7 +46,7 @@ var ArchivedNote = mongoose.model( 'ArchivedNote' ); var ArchivedSubject = mongoose.model( 'ArchivedSubject' ); // XXX Not sure if necessary -var ObjectId = mongoose.SchemaTypes.ObjectId; +var ObjectId = mongoose.SchemaTypes.ObjectId; // Configuration // Use the environment variable DEV_EMAIL for testing @@ -89,7 +90,7 @@ app.configure( 'development', function() { // If a port wasn't set earlier, set to 3000 if ( !serverPort ) { serverPort = 3000; - } + } }); // Production configuration settings @@ -116,15 +117,18 @@ app.configure( 'production', function() { // Set to port 80 if not set through environment variables if ( !serverPort ) { serverPort = 80; - } + } }); // General Express configuration settings app.configure(function(){ + // Views are rendered from public/index.html and main.js except for the pad that surrounds EPL and BC + // FIXME: make all views exist inside of public/index.html // Views are housed in the views folder app.set( 'views', __dirname + '/views' ); // All templates use jade for rendering app.set( 'view engine', 'jade' ); + // Bodyparser is required to handle form submissions // without manually parsing them. app.use( express.bodyParser() ); @@ -134,6 +138,7 @@ app.configure(function(){ // Sessions are stored in mongodb which allows them // to be persisted even between server restarts. app.set( 'sessionStore', new mongoStore( { + 'db' : 'fc', 'url' : app.set( 'dbUri' ) })); @@ -157,18 +162,14 @@ app.configure(function(){ app.use( express.methodOverride() ); // Static files are loaded when no dynamic views match. app.use( express.static( __dirname + '/public' ) ); + // Sets the routers middleware to load after everything set // before it, but before static files. app.use( app.router ); app.use(express.logger({ format: ':method :url' })); - // This is the errorHandler set in configuration earlier - // being set to a variable to be used after all other - // middleware is loaded. Error handling should always - // come last or near the bottom. - var errorHandler = app.set( 'errorHandler' ); - - app.use( errorHandler ); + // This is the command to use the default express error logger/handler + app.use(express.errorHandler({ dumpExceptions: true })); }); @@ -291,6 +292,8 @@ function loadUser( req, res, next ) { res.redirect( '/' ); } + } else if('a'==='b'){ + console.log('never. in. behrlin.'); } else { // If no user record was found, then we store the requested // path they intended to view and redirect them after they @@ -312,9 +315,11 @@ function loadUser( req, res, next ) { // loadSchool is used to load a school by it's id function loadSchool( req, res, next ) { var user = req.user; - var schoolId = req.params.id; + var schoolName = req.params.name; + console.log( 'loading a school by id' ); - School.findById( schoolId, function( err, school ) { + School.findOne({'name': schoolName}).run( function( err, school ) { + //sys.puts(school); if( school ) { req.school = school; @@ -322,12 +327,39 @@ function loadSchool( req, res, next ) { // authorized to see or interact with anything related to that // school. school.authorize( user, function( authorized ){ - req.school.authorized = authorized; - next(); + req.school.authorized = authorized; }); + next(); + } else { + // If no school is found, display an appropriate error. + sendJson(res, {status: 'not_found', message: 'Invalid school specified!'} ); + } + }); +} + +function loadSchoolSlug( req, res, next ) { + var user = req.user; + var schoolSlug = req.params.slug; + + console.log("loading a school by slug"); + //console.log(schoolSlug); + + School.findOne({ 'slug': schoolSlug }, function( err, school ) { + console.log( school ); + if( school ) { + req.school = school; + + // If a school is found, the user is checked to see if they are + // authorized to see or interact with anything related to that + // school. + next() + //school.authorize( user, function( authorized ){ + //req.school.authorized = authorized; + //next(); + //}); } else { // If no school is found, display an appropriate error. - sendJson(res, {status: 'error', message: 'Invalid school specified!'} ); + sendJson(res, {status: 'not_found', message: 'Invalid school specified!'} ); } }); } @@ -351,7 +383,7 @@ function loadCourse( req, res, next ) { }); } else { // If no course is found, display an appropriate error. - sendJson(res, {status: 'error', message: 'Invalid course specified!'} ); + sendJson(res, {status: 'not_found', message: 'Invalid course specified!'} ); } }); } @@ -375,7 +407,7 @@ function loadLecture( req, res, next ) { }); } else { // If no lecture is found, display an appropriate error. - sendJson(res, {status: 'error', message: 'Invalid lecture specified!'} ); + sendJson(res, {status: 'not_found', message: 'Invalid lecture specified!'} ); } }); } @@ -460,7 +492,7 @@ app.dynamicHelpers( { }); function sendJson( res, obj ) { - res.header('Cache-Control', 'no-cache'); + res.header('Cache-Control', 'no-cache, no-store'); res.json(obj); } @@ -483,6 +515,8 @@ app.get( '/', loadUser, function( req, res ) { // in those schools. // Public with some private information app.get( '/schools', checkAjax, loadUser, function( req, res ) { + sys.puts('loading schools'); + console.log(req.user); var user = req.user; var schoolList = []; @@ -492,9 +526,27 @@ app.get( '/schools', checkAjax, loadUser, function( req, res ) { 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. - sendJson(res, { 'user': user.sanitized, 'schools' : schools.map(function(school) { - return school.sanitized; - })}) + var schools_todo = schools.length; + schools.map(function (school) { + Course.find( { 'school': school.id } ).run(function (err, courses) { + school.courses_length = courses.length + schools_todo -= 1; + if (schools_todo <= 0) { + sendJson(res, { 'user': user.sanitized, 'schools': schools.map( function(s) { + var school = { + _id: s._id, + name: s.name, + description: s.description, + url: s.url, + slug: s.slug, + courses: s.courses_length + }; + return school; + }) + }); + } + }); + }); } else { // If no schools have been found, display none //res.render( 'schools', { 'schools' : [] } ); @@ -503,9 +555,54 @@ app.get( '/schools', checkAjax, loadUser, function( req, res ) { }); }); -app.get( '/school/:id', checkAjax, loadUser, loadSchool, function( req, res ) { +app.get( '/school/:name', checkAjax, loadUser, loadSchool, function( req, res ) { + var school = req.school; + var user = req.user; + var courses; + console.log( 'loading a school by school/:id now name' ); + + //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; + var sanitizedSchool = { + _id: school.id, + name: school.name, + description: school.description, + url: school.url + }; + //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. + sys.puts(courses); + if( courses.length > 0 ) { + courses = courses.filter(function(course) { + if (!course.deleted) return course; + }).map(function(course) { + return course.sanitized; + }); + } else { + school.courses = []; + } + sanitizedSchool.courses = courses; + sys.puts(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. + sendJson(res, { 'school': sanitizedSchool, 'user': user.sanitized }) + }); + //}); +}); + +// FIXME: version of the same using school slugs instead of ids +// TODO: merge this with the :id funciton or depricate it +app.get( '/schoolslug/:slug', checkAjax, loadUser, loadSchoolSlug, function( req, res ) { var school = req.school; var user = req.user; + console.log( 'loading a schoolslug/:slug' ); school.authorize( user, function( authorized ) { // This is used to display interface elements for those users @@ -533,25 +630,9 @@ app.get( '/school/:id', checkAjax, loadUser, loadSchool, function( req, res ) { }); }); -// New course page -// Displays form to create new course -// Private, requires user to be authorized -app.get( '/:id/course/new', loadUser, loadSchool, function( req, res ) { - // Load school from middleware - var school = req.school; - - // If school was not loaded for whatever reason, or the user is not authorized - // then redirect to the main schools page. - if( ( ! school ) || ( ! school.authorized ) ) { - return res.redirect( '/schools' ); - } - - // If they are authorized and the school exists, then render the page - res.render( 'course/new', { 'school': school } ); -}); // Recieves new course form -app.post( '/:id/course/new', loadUser, loadSchool, function( req, res ) { +app.post( '/school/:id', checkAjax, loadUser, loadSchool, function( req, res ) { var school = req.school; // Creates new course from Course Schema var course = new Course; @@ -559,15 +640,16 @@ app.post( '/:id/course/new', loadUser, loadSchool, function( req, res ) { var instructorEmail = req.body.email.toLowerCase(); var instructorName = req.body.instructorName; - // If school doesn't exist or user is not authorized redirect to main schools page if( ( ! school ) || ( ! school.authorized ) ) { - res.redirect( '/schools' ); + return sendJson(res, {status: 'error', message: 'There was a problem trying to create a course'}) } - // If instructorEmail isn't set, or name isn't set, display error and re-render the page. - if ( !instructorEmail || !instructorName ) { - req.flash( 'error', 'Invalid parameters!' ) - return res.render( 'course/new' ); + if ( !instructorName ) { + return sendJson(res, {status: 'error', message: 'Invalid parameters!'} ) + } + + if ( ( instructorEmail === '' ) || ( !isValidEmail( instructorEmail ) ) ) { + return sendJson(res, {status: 'error', message:'Please enter a valid email'} ); } // Fill out the course with information from the form @@ -592,21 +674,13 @@ app.post( '/:id/course/new', loadUser, loadSchool, function( req, res ) { user.activated = false; - // Validate instructorEmail - // XXX Probably could be done before checking db - if ( ( user.email === '' ) || ( !isValidEmail( user.email ) ) ) { - req.flash( 'error', 'Please enter a valid email' ); - // XXX This needs to be fixed, this is not the proper flow - return res.redirect( '/register' ); - } // Once the new user information has been completed, save the user // to the database then email them the instructor welcome email. user.save(function( err ) { // If there was an error saving the instructor, prompt the user to fill out // the information again. if ( err ) { - req.flash( 'error', 'Invalid parameters!' ) - return res.render( 'course/new' ); + return sendJson(res, {status: 'error', message: 'Invalid parameters!'} ) } else { var message = { to : user.email, @@ -635,10 +709,7 @@ app.post( '/:id/course/new', loadUser, loadSchool, function( req, res ) { course.instructor = user._id; course.save( function( err ) { if( err ) { - // XXX better validation - req.flash( 'error', 'Invalid parameters!' ); - - return res.render( 'course/new' ); + return sendJson(res, {status: 'error', message: 'Invalid parameters!'} ) } else { // Once the course has been completed email the admin with information // on the course and new instructor @@ -666,7 +737,7 @@ app.post( '/:id/course/new', loadUser, loadSchool, function( req, res ) { // Redirect the user to the schools page where they can see // their new course. // XXX Redirect to the new course instead - res.redirect( '/schools' ); + return sendJson(res, {status: 'ok', message: 'Course created'} ) } }); } @@ -680,9 +751,7 @@ app.post( '/:id/course/new', loadUser, loadSchool, function( req, res ) { course.save( function( err ) { if( err ) { // XXX better validation - req.flash( 'error', 'Invalid parameters!' ); - - return res.render( 'course/new' ); + return sendJson(res, {status: 'error', message: 'Invalid parameters!'} ) } else { var message = { to : ADMIN_EMAIL, @@ -706,14 +775,13 @@ app.post( '/:id/course/new', loadUser, loadSchool, function( req, res ) { } }) // XXX Redirect to the new course instead - res.redirect( '/schools' ); + return sendJson(res, {status: 'ok', message: 'Course created'} ) } }); } else { // The existing user isn't an instructor, so the user is notified of the error // and the course isn't created. - req.flash( 'error', 'The existing user\'s email you entered is not an instructor' ); - res.render( 'course/new' ); + sendJson(res, {status: 'error', message: 'The existing user\'s email you entered is not an instructor'} ) } } }) @@ -727,18 +795,52 @@ app.get( '/course/:id', checkAjax, loadUser, loadCourse, function( req, res ) { // Check if the user is subscribed to the course // XXX Not currently used for anything - var subscribed = course.subscribed( userId ); + //var subscribed = course.subscribed( userId ); // Find lectures associated with this course and sort by name Lecture.find( { 'course' : course._id } ).sort( 'name', '1' ).run( function( err, lectures ) { // Get course instructor information using their id User.findById( course.instructor, function( err, instructor ) { // Render course and lectures - sendJson(res, { 'user': req.user.sanitized, 'course' : course.sanitized, 'instructor': instructor.sanitized, 'subscribed' : subscribed, 'lectures' : lectures.map(function(lecture) { return lecture.sanitized })} ); + var sanitizedInstructor = instructor.sanitized; + var sanitizedCourse = course.sanitized; + if (!course.authorized) { + delete sanitizedInstructor.email; + } else { + sanitizedCourse.authorized = course.authorized; + } + sendJson(res, { 'course' : sanitizedCourse, 'instructor': sanitizedInstructor, 'lectures' : lectures.map(function(lecture) { return lecture.sanitized })} ); }) }); }); +// Recieve New Lecture Form +app.post( '/course/:id', checkAjax, loadUser, loadCourse, function( req, res ) { + var course = req.course; + // Create new lecture from Lecture schema + var lecture = new Lecture; + + if( ( ! course ) || ( ! course.authorized ) ) { + return sendJson(res, {status: 'error', message: 'There was a problem trying to create a lecture'}) + } + + // Populate lecture with form data + lecture.name = req.body.name; + lecture.date = req.body.date; + lecture.course = course._id; + lecture.creator = req.user._id; + + // Save lecture to database + lecture.save( function( err ) { + if( err ) { + // XXX better validation + sendJson(res, {status: 'error', message: 'Invalid parameters!'} ); + } else { + sendJson(res, {status: 'ok', message: 'Created new lecture'} ); + } + }); +}); + // Edit Course app.get( '/course/:id/edit', loadUser, loadCourse, function( req, res) { var course = req.course; @@ -823,53 +925,7 @@ app.get( '/course/:id/unsubscribe', loadUser, loadCourse, function( req, res ) { }); }); -// Create new lecture -app.get( '/course/:id/lecture/new', loadUser, loadCourse, function( req, res ) { - var courseId = req.params.id; - var course = req.course; - var lecture = {}; - // If course isn't valid or user isn't authorized for course, redirect - if( ( ! course ) || ( ! course.authorized ) ) { - return res.redirect( '/course/' + courseId ); - } - - // Render new lecture form - res.render( 'lecture/new', { 'lecture' : lecture } ); -}); - -// Recieve New Lecture Form -app.post( '/course/:id/lecture/new', loadUser, loadCourse, function( req, res ) { - var courseId = req.params.id; - var course = req.course; - // Create new lecture from Lecture schema - var lecture = new Lecture; - - if( ( ! course ) || ( ! course.authorized ) ) { - res.redirect( '/course/' + courseId ); - - return; - } - - // Populate lecture with form data - lecture.name = req.body.name; - lecture.date = req.body.date; - lecture.course = course._id; - lecture.creator = req.user._id; - - // Save lecture to database - lecture.save( function( err ) { - if( err ) { - // XXX better validation - req.flash( 'error', 'Invalid parameters!' ); - - res.render( 'lecture/new', { 'lecture' : lecture } ); - } else { - // XXX Redirect to new lecture instead - res.redirect( '/course/' + course._id ); - } - }); -}); // Display individual lecture and related notes @@ -891,11 +947,17 @@ app.get( '/lecture/:id', checkAjax, loadUser, loadLecture, function( req, res ) if ( note.public ) return note; }) } + var sanitizedInstructor = instructor.sanitized; + var sanitizedLecture = lecture.sanitized; + if (!lecture.authorized) { + delete sanitizedInstructor.email; + } else { + sanitizedLecture.authorized = lecture.authorized; + } sendJson(res, { - 'lecture' : lecture.sanitized, + 'lecture' : sanitizedLecture, 'course' : course.sanitized, - 'instructor' : instructor.sanitized, - 'user' : req.user.sanitized, + 'instructor' : sanitizedInstructor, 'notes' : notes.map(function(note) { return note.sanitized; }) @@ -903,35 +965,18 @@ app.get( '/lecture/:id', checkAjax, loadUser, loadLecture, function( req, res ) }); }) } else { - sendJson(res, { status: 'error', msg: 'This course is orphaned' }) + sendJson(res, { status: 'not_found', msg: 'This course is orphaned' }) } }); }); -// Display new note form -app.get( '/lecture/:id/notes/new', loadUser, loadLecture, function( req, res ) { - var lectureId = req.params.id; - var lecture = req.lecture; - var note = {}; - - if( ( ! lecture ) || ( ! lecture.authorized ) ) { - res.redirect( '/lecture/' + lectureId ); - - return; - } - - res.render( 'notes/new', { 'note' : note } ); -}); // Recieve new note form -app.post( '/lecture/:id/notes/new', loadUser, loadLecture, function( req, res ) { - var lectureId = req.params.id; +app.post( '/lecture/:id', checkAjax, loadUser, loadLecture, function( req, res ) { var lecture = req.lecture; if( ( ! lecture ) || ( ! lecture.authorized ) ) { - res.redirect( '/lecture/' + lectureId ); - - return; + return sendJson(res, {status: 'error', message: 'There was a problem trying to create a note pad'}) } // Create note from Note schema @@ -948,12 +993,9 @@ app.post( '/lecture/:id/notes/new', loadUser, loadLecture, function( req, res ) note.save( function( err ) { if( err ) { // XXX better validation - req.flash( 'error', 'Invalid parameters!' ); - - res.render( 'notes/new', { 'note' : note } ); + sendJson(res, {status: 'error', message: 'There was a problem trying to create a note pad'}) } else { - // XXX Redirect to new note instead - res.redirect( '/lecture/' + lecture._id ); + sendJson(res, {status: 'ok', message: 'Successfully created a new note pad'}) } }); }); @@ -1055,6 +1097,7 @@ app.get( '/note/:id', /*checkAjax,*/ loadUser, loadNote, function( req, res ) { }); // Static pages and redirects +/* app.get( '/about', loadUser, function( req, res ) { res.redirect( 'http://blog.finalsclub.org/about.html' ); }); @@ -1078,6 +1121,7 @@ app.get( '/contact', loadUser, function( req, res ) { app.get( '/privacy', loadUser, function( req, res ) { res.render( 'static/privacy' ); }); +*/ // Authentication routes @@ -1085,33 +1129,37 @@ app.get( '/privacy', loadUser, function( req, res ) { // and other user authentication purposes // Render login page +/* app.get( '/login', function( req, res ) { log3("get login page") res.render( 'login' ); }); +*/ + +app.get( '/checkuser', checkAjax, loadUser, function( req, res ) { + sendJson(res, {user: req.user.sanitized}); +}); // Recieve login form -app.post( '/login', function( req, res ) { +app.post( '/login', checkAjax, function( req, res ) { var email = req.body.email; var password = req.body.password; log3("post login ...") // Find user from email User.findOne( { 'email' : email.toLowerCase() }, function( err, user ) { - log3(err) - log3(user) + log3(err) + log3(user) // If user exists, check if activated, if not notify them and send them to // the login form if( user ) { if( ! user.activated ) { // (undocumented) markdown-esque link functionality in req.flash - req.flash( 'error', 'This account isn\'t activated. Check your inbox or [click here](/resendActivation) to resend the activation email.' ); - req.session.activateCode = user._id; + sendJson(res, {status: 'error', message: 'This account isn\'t activated.'} ); - res.render( 'login' ); } else { // If user is activated, check if their password is correct if( user.authenticate( password ) ) { @@ -1129,42 +1177,30 @@ app.post( '/login', function( req, res ) { req.session.email = email; // alert the successful login - req.flash( 'info', 'Successfully logged in!' ); + sendJson(res, {status: 'ok', message:'Successfully logged in!'} ); // redirect to profile if we don't have a stashed request - res.redirect( redirect || '/profile' ); + //res.redirect( redirect || '/profile' ); }); } else { // Notify user of bad login - req.flash( 'error', 'Invalid login!' ); + sendJson(res, {status: 'error', message: 'Invalid login!'} ); - res.render( 'login' ); + //res.render( 'login' ); } } } else { // Notify user of bad login log3("bad login") - req.flash( 'error', 'Invalid login!' ); + sendJson(res, {status: 'error', message: 'Invalid login!'} ); - res.render( 'login' ); + //res.render( 'login' ); } }); }); -// Request reset password -app.get( '/resetpw', function( req, res ) { - log3("get resetpw page"); - res.render( 'resetpw' ); -}); - -// Display reset password from requested email -app.get( '/resetpw/:id', function( req, res ) { - var resetPassCode = req.params.id - res.render( 'resetpw', { 'verify': true, 'resetPassCode' : resetPassCode } ); -}); - // Recieve reset password request form -app.post( '/resetpw', function( req, res ) { +app.post( '/resetpass', checkAjax, function( req, res ) { log3("post resetpw"); var email = req.body.email @@ -1209,17 +1245,17 @@ app.post( '/resetpw', function( req, res ) { }); // Render request success page - res.render( 'resetpw-success', { 'email' : email } ); + sendJson(res, {status: 'ok', message: 'Your password has been reset. An email has been sent to ' + email }) }); } else { // Notify of error - res.render( 'resetpw-error', { 'email' : email } ); + sendJson(res, {status: 'error', message: 'We were unable to reset the password using that email address. Please try again.' }) } }); }); // Recieve reset password form -app.post( '/resetpw/:id', function( req, res ) { +app.post( '/resetpw/:id', checkAjax, function( req, res ) { log3("post resetpw.code"); var resetPassCode = req.params.id var email = req.body.email @@ -1235,19 +1271,19 @@ app.post( '/resetpw/:id', function( req, res ) { var valid = user.resetPassword(resetPassCode, pass1, pass2); if (valid) { user.save( function( err ) { - res.render( 'resetpw-success', { 'verify' : true, 'email' : email, 'resetPassCode' : resetPassCode } ); - }); + sendJson(res, {status: 'ok', message: 'Your password has been reset. You can now login with your the new password you just created.'}) + }); } } - // If there was a problem, notify user if (!valid) { - res.render( 'resetpw-error', { 'verify' : true, 'email' : email } ); + sendJson(res, {status: 'error', message: 'We were unable to reset the password. Please try again.' }) } }); }); // Display registration page +/* app.get( '/register', function( req, res ) { log3("get reg page"); @@ -1256,9 +1292,10 @@ app.get( '/register', function( req, res ) { res.render( 'register', { 'schools' : schools } ); }) }); +*/ // Recieve registration form -app.post( '/register', function( req, res ) { +app.post( '/register', checkAjax, function( req, res ) { var sid = req.sessionId; // Create new user from User schema @@ -1268,30 +1305,27 @@ app.post( '/register', function( req, res ) { user.email = req.body.email.toLowerCase(); user.password = req.body.password; user.session = sid; - // If school is set to other, then fill in school as what the - // user entered - user.school = req.body.school === 'Other' ? req.body.otherSchool : req.body.school; + // If school is set to other, then fill in school as what the user entered + user.school = req.body.school === 'Other' ? req.body.otherSchool : req.body.school; user.name = req.body.name; user.affil = req.body.affil; user.activated = false; // Validate email if ( ( user.email === '' ) || ( !isValidEmail( user.email ) ) ) { - req.flash( 'error', 'Please enter a valid email' ); - return res.redirect( '/register' ); + return sendJson(res, {status: 'error', message: 'Please enter a valid email'} ); } // Check if password is greater than 6 characters, otherwise notify user if ( req.body.password.length < 6 ) { - req.flash( 'error', 'Please enter a password longer than eight characters' ); - return res.redirect( '/register' ); + return sendJson(res, {status: 'error', message: 'Please enter a password longer than eight characters'} ); } // Pull out hostname from email var hostname = user.email.split( '@' ).pop(); // Check if email is from one of the special domains - if( /^(finalsclub.org|sleepless.com)$/.test( hostname ) ) { + if( /^(finalsclub.org)$/.test( hostname ) ) { user.admin = true; } @@ -1305,19 +1339,15 @@ app.post( '/register', function( req, res ) { User.findOne({ 'email' : user.email }, function(err, result ) { if (result.activated) { // If activated, make sure they know how to contact the admin - req.flash( 'error', 'There is already someone registered with this email, if this is in error contact info@finalsclub.org for help' ) - return res.redirect( '/register' ) + return sendJson(res, {status: 'error', message: 'There is already someone registered with this email, if this is in error contact info@finalsclub.org for help'} ); } else { // If not activated, direct them to the resendActivation page - req.flash( 'error', 'There is already someone registered with this email, if this is you, please check your email for the activation code' ) - return res.redirect( '/resendActivation' ) + return sendJson(res, {status: 'error', message: 'There is already someone registered with this email, if this is you, please check your email for the activation code'} ); } }); } else { // If any other type of error, prompt them to enter the registration again - req.flash( 'error', 'An error occurred during registration.' ); - - return res.redirect( '/register' ); + return sendJson(res, {status: 'error', message: 'An error occurred during registration.'} ); } } else { // send user activation email @@ -1338,8 +1368,7 @@ app.post( '/register', function( req, res ) { school.save( function( err ) { log3('school.save() done'); // Notify user that they have been added to the school - req.flash( 'info', 'You have automatically been added to the ' + school.name + ' network. Please check your email for the activation link' ); - res.redirect( '/' ); + sendJson(res, {status: 'ok', message: 'You have automatically been added to the ' + school.name + ' network. Please check your email for the activation link'} ); }); // Construct admin email about user registration var message = { @@ -1356,8 +1385,7 @@ app.post( '/register', function( req, res ) { // If there isn't a match, send associated welcome message sendUserWelcome( user, false ); // Tell user to check for activation link - req.flash( 'info', 'Your account has been created, please check your email for the activation link' ) - res.redirect( '/' ); + sendJson(res, {status: 'ok', message: 'Your account has been created, please check your email for the activation link'} ); // Construct admin email about user registration var message = { 'to' : ADMIN_EMAIL, @@ -1406,21 +1434,19 @@ app.get( '/resendActivation', function( req, res ) { }); // Display activation page -app.get( '/activate/:code', function( req, res ) { +app.get( '/activate/:code', checkAjax, function( req, res ) { var code = req.params.code; // XXX could break this out into a middleware if( ! code ) { - res.redirect( '/' ); + return sendJson(res, {status:'error', message: 'Invalid activation code!'} ); } // Find user by activation code User.findById( code, function( err, user ) { if( err || ! user ) { // If not found, notify user of invalid code - req.flash( 'error', 'Invalid activation code!' ); - - res.redirect( '/' ); + sendJson(res, {status:'error', message:'Invalid activation code!'} ); } else { // If valid, then activate user user.activated = true; @@ -1432,13 +1458,9 @@ app.get( '/activate/:code', function( req, res ) { // Save user to database user.save( function( err ) { if( err ) { - req.flash( 'error', 'Unable to activate account.' ); - - res.redirect( '/' ); + sendJson(res, {status: 'error', message: 'Unable to activate account.'} ); } else { - req.flash( 'info', 'Account successfully activated. Please complete your profile.' ); - - res.redirect( '/profile' ); + sendJson(res, {status: 'info', message: 'Account successfully activated. Please complete your profile.'} ); } }); }); @@ -1447,7 +1469,8 @@ app.get( '/activate/:code', function( req, res ) { }); // Logut user -app.get( '/logout', function( req, res ) { +app.get( '/logout', checkAjax, function( req, res ) { + sys.puts("logging out"); var sid = req.sessionID; // Find user by session id @@ -1458,23 +1481,16 @@ app.get( '/logout', function( req, res ) { // Save user to database user.save( function( err ) { - res.redirect( '/' ); + sendJson(res, {status: 'ok', message: 'Successfully logged out'}); }); } else { - res.redirect( '/' ); + sendJson(res, {status: 'ok', message: ''}); } }); }); -// Display users profile page -app.get( '/profile', loadUser, loggedIn, function( req, res ) { - var user = req.user; - - res.render( 'profile/index', { 'user' : user } ); -}); - // Recieve profile edit page form -app.post( '/profile', loadUser, loggedIn, function( req, res ) { +app.post( '/profile', checkAjax, loadUser, loggedIn, function( req, res ) { var user = req.user; var fields = req.body; @@ -1482,17 +1498,13 @@ app.post( '/profile', loadUser, loggedIn, function( req, res ) { var wasComplete = user.isComplete; if( ! fields.name ) { - req.flash( 'error', 'Please enter a valid name!' ); - - error = true; + return sendJson(res, {status: 'error', message: 'Please enter a valid name!'} ); } else { user.name = fields.name; } if( [ 'Student', 'Teachers Assistant' ].indexOf( fields.affiliation ) == -1 ) { - req.flash( 'error', 'Please select a valid affiliation!' ); - - error = true; + return sendJson(res, {status: 'error', message: 'Please select a valid affiliation!'} ); } else { user.affil = fields.affiliation; } @@ -1505,41 +1517,29 @@ app.post( '/profile', loadUser, loggedIn, function( req, res ) { user.password = fields.newPassword; } else { - req.flash( 'error', 'Mismatch in new password!' ); - - error = true; + return sendJson(res, {status: 'error', message: 'Mismatch in new password!'} ); } } else { - req.flash( 'error', 'Please supply your existing password.' ); - - error = true; + return sendJson(res, {status: 'error', message: 'Please supply your existing password.'} ); } } - user.major = fields.major; - user.bio = fields.bio; + user.major = fields.major; + user.bio = fields.bio; user.showName = ( fields.showName ? true : false ); - if( ! error ) { - user.save( function( err ) { - if( err ) { - req.flash( 'error', 'Unable to save user profile!' ); + user.save( function( err ) { + if( err ) { + sendJson(res, {status: 'error', message: 'Unable to save user profile!'} ); + } else { + if( ( user.isComplete ) && ( ! wasComplete ) ) { + sendJson(res, {status: 'ok', message: 'Your account is now fully activated. Thank you for joining FinalsClub!'} ); } else { - if( ( user.isComplete ) && ( ! wasComplete ) ) { - req.flash( 'info', 'Your account is now fully activated. Thank you for joining FinalsClub!' ); - - res.redirect( '/' ); - } else { - res.render( 'info', 'Your profile was successfully updated!' ); - - res.render( 'profile/index', { 'user' : user } ); - } + sendJson(res, {status:'ok', message:'Your profile was successfully updated!'} ); } - }); - } else { - res.render( 'profile/index', { 'user' : user } ); - } + } + }); }); @@ -1548,8 +1548,8 @@ app.post( '/profile', loadUser, loggedIn, function( req, res ) { function loadSubject( req, res, next ) { if( url.parse( req.url ).pathname.match(/subject/) ) { ArchivedSubject.findOne({id: req.params.id }, function(err, subject) { - if ( err ) { - sendJson(res, {status: 'error', message: 'Subject with this ID does not exist'} ) + if ( err || !subject) { + sendJson(res, {status: 'not_found', message: 'Subject with this ID does not exist'} ) } else { req.subject = subject; next() @@ -1563,8 +1563,8 @@ function loadSubject( req, res, next ) { function loadOldCourse( req, res, next ) { if( url.parse( req.url ).pathname.match(/course/) ) { ArchivedCourse.findOne({id: req.params.id }, function(err, course) { - if ( err ) { - sendJson(res, {status: 'error', message: 'Course with this ID does not exist'} ) + if ( err || !course ) { + sendJson(res, {status: 'not_found', message: 'Course with this ID does not exist'} ) } else { req.course = course; next() @@ -1597,13 +1597,13 @@ app.get( '/learn', loadUser, function( req, res ) { res.render( 'archive/learn', { 'courses' : featuredCourses } ); }) -app.get( '/learn/random', loadUser, function( req, res ) { - res.redirect( '/archive/course/'+ featuredCourses[Math.floor(Math.random()*featuredCourses.length)].id); +app.get( '/learn/random', checkAjax, function( req, res ) { + sendJson(res, {status: 'ok', data: '/archive/course/'+ featuredCourses[Math.floor(Math.random()*featuredCourses.length)].id }); }) app.get( '/archive', checkAjax, loadUser, function( req, res ) { ArchivedSubject.find({}).sort( 'name', '1' ).run( function( err, subjects ) { - if ( err ) { + if ( err || subjects.length === 0) { sendJson(res, {status: 'error', message: 'There was a problem gathering the archived courses, please try again later.'} ); } else { sendJson(res, { 'subjects' : subjects, 'user': req.user.sanitized } ); @@ -1613,8 +1613,8 @@ app.get( '/archive', checkAjax, loadUser, function( req, res ) { app.get( '/archive/subject/:id', checkAjax, loadUser, loadSubject, function( req, res ) { ArchivedCourse.find({subject_id: req.params.id}).sort('name', '1').run(function(err, courses) { - if ( err ) { - sendJson(res, {status: 'error', message: 'There are no archived courses'} ); + if ( err || courses.length === 0 ) { + sendJson(res, {status: 'not_found', message: 'There are no archived courses'} ); } else { sendJson(res, { 'courses' : courses, 'subject': req.subject, 'user': req.user.sanitized } ); } @@ -1623,22 +1623,24 @@ app.get( '/archive/subject/:id', checkAjax, loadUser, loadSubject, function( req app.get( '/archive/course/:id', checkAjax, loadUser, loadOldCourse, function( req, res ) { ArchivedNote.find({course_id: req.params.id}).sort('name', '1').run(function(err, notes) { - if ( err ) { - sendJson(res, {status: 'error', message: 'There are no notes in this course'} ); + if ( err || notes.length === 0) { + sendJson(res, {status: 'not_found', message: 'There are no notes in this course'} ); } else { - sendJson(res, { 'notes' : notes, 'course' : req.course, 'user': req.user.sanitized } ); + notes = notes.map(function(note) { return note.sanitized }); + sendJson(res, { 'notes': notes, 'course' : req.course, 'user': req.user.sanitized } ); } }) }) app.get( '/archive/note/:id', checkAjax, loadUser, function( req, res ) { + console.log( "id="+req.params.id) ArchivedNote.findById(req.params.id, function(err, note) { - if ( err ) { - sendJson(res, {status: 'error', message: 'This is not a valid id for a note'} ); + if ( err || !note ) { + sendJson(res, {status: 'not_found', message: 'This is not a valid id for a note'} ); } else { ArchivedCourse.findOne({id: note.course_id}, function(err, course) { - if ( err ) { - sendJson(res, {status: 'error', message: 'There is no course for this note'} ) + if ( err || !course ) { + sendJson(res, {status: 'not_found', message: 'There is no course for this note'} ) } else { sendJson(res, { 'layout' : 'notesLayout', 'note' : note, 'course': course, 'user': req.user.sanitized } ); } @@ -1794,6 +1796,7 @@ io.set('authorization', function ( handshake, next ) { }); var backchannel = new Backchannel(app, io.of('/backchannel'), { + // TODO: if lecture belongs to course (find pinker's courseId) pass a 'no-answers' true/false subscribe: function(lecture, send) { Post.find({'lecture': lecture}, function(err, posts) { send(posts); @@ -1913,8 +1916,8 @@ process.on('uncaughtException', function (e) { // Launch -mongoose.connect( app.set( 'dbUri' ) ); -mongoose.connection.db.serverConfig.connection.autoReconnect = true +// mongoose now exepects a mongo url +mongoose.connect( 'mongodb://localhost/fc' ); // FIXME: make relative to hostname var mailer = new Mailer( app.set('awsAccessKey'), app.set('awsSecretKey') ); @@ -1934,3 +1937,5 @@ function isValidEmail(email) { var re = /[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/; return email.match(re); } + +// Facebook connect