diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..13ef57c654 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +indent_style = space +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[package.json] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/app.js b/app.js index 0e84883155..f22e0a2aee 100644 --- a/app.js +++ b/app.js @@ -440,6 +440,8 @@ app.get( coursewareController.returnIndividualCourseware ); app.post('/completed-courseware/', coursewareController.completedCourseware); +app.post('/completed-zipline-or-basejump', + coursewareController.completedZiplineOrBasejump); // Unique Check API route app.get('/api/checkUniqueUsername/:username', userController.checkUniqueUsername); diff --git a/controllers/bonfire.js b/controllers/bonfire.js index ac6ce0a893..5a4e7904c3 100644 --- a/controllers/bonfire.js +++ b/controllers/bonfire.js @@ -3,6 +3,7 @@ var _ = require('lodash'), Bonfire = require('./../models/Bonfire'), User = require('./../models/User'), resources = require('./resources'), + MDNlinks = require('./../seed_data/bonfireMDNlinks'), R = require('ramda'); MDNlinks = require('./../seed_data/bonfireMDNlinks'); @@ -161,18 +162,18 @@ function randomString() { /** * Helper function to populate the MDN links array. -*/ + */ function getMDNlinks(links) { - // takes in an array of links, which are strings - var populatedLinks = []; + // takes in an array of links, which are strings + var populatedLinks = []; - // for each key value, push the corresponding link from the MDNlinks object into a new array - links.forEach(function(value, index) { - populatedLinks.push(MDNlinks[value]); - }); + // for each key value, push the corresponding link from the MDNlinks object into a new array + links.forEach(function(value, index) { + populatedLinks.push(MDNlinks[value]); + }); - return populatedLinks; + return populatedLinks; }; @@ -182,15 +183,15 @@ function getMDNlinks(links) { exports.testBonfire = function(req, res) { var bonfireName = req.body.name, - bonfireTests = req.body.tests, - bonfireDifficulty = req.body.difficulty, - bonfireDescription = req.body.description, - bonfireChallengeSeed = req.body.challengeSeed; - bonfireTests = bonfireTests.split('\r\n'); - bonfireDescription = bonfireDescription.split('\r\n'); - bonfireTests.filter(getRidOfEmpties); - bonfireDescription.filter(getRidOfEmpties); - bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', ''); + bonfireTests = req.body.tests, + bonfireDifficulty = req.body.difficulty, + bonfireDescription = req.body.description, + bonfireChallengeSeed = req.body.challengeSeed; + bonfireTests = bonfireTests.split('\r\n'); + bonfireDescription = bonfireDescription.split('\r\n'); + bonfireTests.filter(getRidOfEmpties); + bonfireDescription.filter(getRidOfEmpties); + bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', ''); res.render('bonfire/show', { completedWith: null, @@ -223,15 +224,15 @@ exports.publicGenerator = function(req, res) { exports.generateChallenge = function(req, res) { var bonfireName = req.body.name, - bonfireTests = req.body.tests, - bonfireDifficulty = req.body.difficulty, - bonfireDescription = req.body.description, - bonfireChallengeSeed = req.body.challengeSeed; - bonfireTests = bonfireTests.split('\r\n'); - bonfireDescription = bonfireDescription.split('\r\n'); - bonfireTests.filter(getRidOfEmpties); - bonfireDescription.filter(getRidOfEmpties); - bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', ''); + bonfireTests = req.body.tests, + bonfireDifficulty = req.body.difficulty, + bonfireDescription = req.body.description, + bonfireChallengeSeed = req.body.challengeSeed; + bonfireTests = bonfireTests.split('\r\n'); + bonfireDescription = bonfireDescription.split('\r\n'); + bonfireTests.filter(getRidOfEmpties); + bonfireDescription.filter(getRidOfEmpties); + bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', ''); var response = { diff --git a/controllers/courseware.js b/controllers/courseware.js index f32e14b0c5..82987ea7a7 100644 --- a/controllers/courseware.js +++ b/controllers/courseware.js @@ -100,7 +100,8 @@ exports.returnIndividualCourseware = function(req, res, next) { phrase: resources.randomPhrase(), compliment: resources.randomCompliment(), coursewareHash: courseware._id, - environment: resources.whichEnvironment() + environment: resources.whichEnvironment(), + challengeType: courseware.challengeType }); }, @@ -117,7 +118,7 @@ exports.returnIndividualCourseware = function(req, res, next) { phrase: resources.randomPhrase(), compliment: resources.randomCompliment(), coursewareHash: courseware._id, - + challengeType: courseware.challengeType }); }, @@ -133,7 +134,7 @@ exports.returnIndividualCourseware = function(req, res, next) { phrase: resources.randomPhrase(), compliment: resources.randomCompliment(), coursewareHash: courseware._id, - challengeType: 'video' + challengeType: courseware.challengeType }); }, @@ -160,16 +161,16 @@ exports.returnIndividualCourseware = function(req, res, next) { exports.testCourseware = function(req, res) { var coursewareName = req.body.name, - coursewareTests = req.body.tests, - coursewareDifficulty = req.body.difficulty, - coursewareDescription = req.body.description, - coursewareEntryPoint = req.body.challengeEntryPoint, - coursewareChallengeSeed = req.body.challengeSeed; - coursewareTests = coursewareTests.split('\r\n'); - coursewareDescription = coursewareDescription.split('\r\n'); - coursewareTests.filter(getRidOfEmpties); - coursewareDescription.filter(getRidOfEmpties); - coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', ''); + coursewareTests = req.body.tests, + coursewareDifficulty = req.body.difficulty, + coursewareDescription = req.body.description, + coursewareEntryPoint = req.body.challengeEntryPoint, + coursewareChallengeSeed = req.body.challengeSeed; + coursewareTests = coursewareTests.split('\r\n'); + coursewareDescription = coursewareDescription.split('\r\n'); + coursewareTests.filter(getRidOfEmpties); + coursewareDescription.filter(getRidOfEmpties); + coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', ''); res.render('courseware/show', { completedWith: null, title: coursewareName, @@ -233,7 +234,9 @@ exports.completedCourseware = function (req, res, next) { req.user.completedCoursewares.push({ _id: coursewareHash, completedDate: isCompletedDate, - name: req.body.coursewareInfo.coursewareName + name: req.body.coursewareInfo.coursewareName, + solution: null, + githubLink: null }); var index = req.user.completedCoursewares.indexOf(coursewareHash); @@ -247,19 +250,26 @@ exports.completedCourseware = function (req, res, next) { return next(err); } if (user) { - res.send(true); + res.sendStatus(200); } }); }; exports.completedZiplineOrBasejump = function (req, res, next) { - var isCompletedWith = req.body.bonfireInfo.completedWith || false; + debug('Inside controller for completed zipline or basejump with data %s', + req.body.coursewareInfo); + var isCompletedWith = req.body.coursewareInfo.completedWith || false; var isCompletedDate = Math.round(+new Date()); var coursewareHash = req.body.coursewareInfo.coursewareHash; - var solutionLink = req.body.coursewareInfo.solutionLink; - if (!solutionLink) { - // flash error and redirect - return next(new Error('No solution provided')); + var solutionLink = req.body.coursewareInfo.publicURL; + var githubLink = req.body.coursewareInfo.challengeType === 4 + ? req.body.coursewareInfo.githubURL : true; + if (!solutionLink || !githubLink) { + req.flash('errors', { + msg: 'You haven\'t supplied the necessary URLs for us to inspect ' + + 'your work.' + }); + return res.sendStatus(403); } if (isCompletedWith) { @@ -275,37 +285,47 @@ exports.completedZiplineOrBasejump = function (req, res, next) { } pairedWith = pairedWith.pop(); - index = pairedWith.uncompletedCoursewares.indexOf(coursewareHash); - if (index > -1) { - pairedWith.progressTimestamps.push(Date.now() || 0); - pairedWith.uncompletedCoursewares.splice(index, 1); - } - - pairedWith.completedCoursewares.push({ - _id: coursewareHash, - completedWith: req.user._id, - completedDate: isCompletedDate, - solution: solutionLink - }); req.user.completedCoursewares.push({ _id: coursewareHash, completedWith: pairedWith._id, completedDate: isCompletedDate, - solution: solutionLink + solution: solutionLink, + githubLink: githubLink }); req.user.save(function (err, user) { if (err) { return next(err); } + debug('this is the user object returned %s,' + + ' this is the req.user._id %s, ' + + 'this is the pairedWith._id %s', user, req.user._id, pairedWith._id); + debug(req.user._id.toString() === pairedWith._id.toString()); + if (req.user._id.toString() === pairedWith._id.toString()) { + return res.sendStatus(200); + } + index = pairedWith.uncompletedCoursewares.indexOf(coursewareHash); + if (index > -1) { + pairedWith.progressTimestamps.push(Date.now() || 0); + pairedWith.uncompletedCoursewares.splice(index, 1); + + } + + pairedWith.completedCoursewares.push({ + _id: coursewareHash, + completedWith: req.user._id, + completedDate: isCompletedDate, + solution: solutionLink, + githubLink: githubLink + }); pairedWith.save(function (err, paired) { if (err) { return next(err); } if (user && paired) { - return res.send(true); + return res.sendStatus(200); } }); }); @@ -317,10 +337,11 @@ exports.completedZiplineOrBasejump = function (req, res, next) { _id: coursewareHash, completedWith: null, completedDate: isCompletedDate, - solution: solutionLink + solution: solutionLink, + githubLink: githubLink }); - var index = req.user.uncompletedCourse.indexOf(coursewareHash); + var index = req.user.uncompletedCoursewares.indexOf(coursewareHash); if (index > -1) { req.user.progressTimestamps.push(Date.now() || 0); req.user.uncompletedCoursewares.splice(index, 1); @@ -331,8 +352,7 @@ exports.completedZiplineOrBasejump = function (req, res, next) { return next(err); } if (user) { - debug('Saving user'); - return res.send(true); + return res.sendStatus(200); } }); } diff --git a/controllers/resources.js b/controllers/resources.js index 886d4a17ed..1c1da1d056 100644 --- a/controllers/resources.js +++ b/controllers/resources.js @@ -176,6 +176,21 @@ module.exports = { }); }, + trelloCalls: function(req, res, next) { + request('https://trello.com/1/boards/BA3xVpz9/cards?key=' + secrets.trello.key, function(err, status, trello) { + if (err) { return next(err); } + trello = (status && status.statusCode === 200) ? (JSON.parse(trello)) : "Can't connect to to Trello"; + res.end(JSON.stringify(trello)); + }); + }, + bloggerCalls: function(req, res, next) { + request('https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/posts?key=' + secrets.blogger.key, function (err, status, blog) { + if (err) { return next(err); } + blog = (status && status.statusCode === 200) ? JSON.parse(blog) : "Can't connect to Blogger"; + res.end(JSON.stringify(blog)); + }); + }, + about: function(req, res, next) { if (req.user) { if (!req.user.profile.picture || req.user.profile.picture === "https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png") { @@ -183,8 +198,9 @@ module.exports = { req.user.save(); } } - var date1 = new Date('10/15/2014'); + var date1 = new Date("10/15/2014"); var date2 = new Date(); + var progressTimestamps = req.user.progressTimestamps; var now = Date.now() || 0; @@ -231,6 +247,7 @@ module.exports = { if (progressTimestamps[progressTimestamps.length - 1] <= (now - 43200)) { req.user.progressTimestamps.push(now); } + var timeDiff = Math.abs(date2.getTime() - date1.getTime()); var daysRunning = Math.ceil(timeDiff / (1000 * 3600 * 24)); var announcements = resources.announcements; @@ -259,6 +276,7 @@ module.exports = { }); }, + randomPhrase: function() { var phrases = resources.phrases; return phrases[Math.floor(Math.random() * phrases.length)]; diff --git a/models/User.js b/models/User.js index 1e1d828853..a05e6640ec 100644 --- a/models/User.js +++ b/models/User.js @@ -347,7 +347,10 @@ var userSchema = new mongoose.Schema({ { completedDate: Long, _id: String, - name: String + name: String, + completedWith: String, + solution: String, + githubLink: String } ], currentStreak: { diff --git a/public/js/main.js b/public/js/main.js index d87a768178..9e57f48afb 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,381 +1,424 @@ $(document).ready(function() { - var challengeName = typeof challengeName !== undefined ? challengeName : 'Untitled'; - if (challengeName) { - ga('send', 'event', 'Challenge', 'load', challengeName); - } + var challengeName = typeof challengeName !== undefined ? challengeName : 'Untitled'; + if (challengeName) { + ga('send', 'event', 'Challenge', 'load', challengeName); + } - // When introducing a new announcement, change the localStorage attribute - // and the HTML located in the footer - if (!localStorage || !localStorage.nodeSchoolAnnouncement) { - $('#announcementModal').modal('show'); - localStorage.fccShowAnnouncement = "true"; - } + // When introducing a new announcement, change the localStorage attribute + // and the HTML located in the footer + if (!localStorage || !localStorage.nodeSchoolAnnouncement) { + $('#announcementModal').modal('show'); + localStorage.fccShowAnnouncement = "true"; + } - var CSRF_HEADER = 'X-CSRF-Token'; + var CSRF_HEADER = 'X-CSRF-Token'; - var setCSRFToken = function(securityToken) { - jQuery.ajaxPrefilter(function(options, _, xhr) { - if (!xhr.crossDomain) { - xhr.setRequestHeader(CSRF_HEADER, securityToken); - } - }); - }; - - setCSRFToken($('meta[name="csrf-token"]').attr('content')); - - $('.start-challenge').on('click', function() { - $(this).parent().remove(); - $('.challenge-content') - .removeClass('hidden-element') - .addClass('animated fadeInDown'); - }); - - //$('.completed-challenge').on('click', function() { - // $('#complete-challenge-dialog').modal('show'); - // // Only post to server if there is an authenticated user - // if ($('.signup-btn-nav').length < 1) { - // l = location.pathname.split('/'); - // cn = l[l.length - 1]; - // $.ajax({ - // type: 'POST', - // data: {challengeNumber: cn}, - // url: '/completed-challenge/' - // }); - // } - //}); - - - function completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash) { - $('#complete-bonfire-dialog').modal('show'); - // Only post to server if there is an authenticated user - if ($('.signup-btn-nav').length < 1) { - - $.post( - '/completed-bonfire', - { - bonfireInfo: { - completedWith : didCompleteWith, - solution: bonfireSolution, - bonfireHash: thisBonfireHash - } - }, - function(res) { - if (res) { - window.location.href = '/bonfires' - } - }); - } - } - - $('.next-bonfire-button').on('click', function() { - var bonfireSolution = myCodeMirror.getValue(); - var thisBonfireHash = passedBonfireHash || null; - var didCompleteWith = $('#completed-with').val() || null; - completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash); - - }); - - $('#completed-courseware').on('click', function() { - $('#complete-courseware-dialog').modal('show'); - }); - - $('#complete-courseware-dialog').on('keypress', function(e) { - if (e.ctrlKey && e.keyCode == 13) { - $('#next-courseware-button').click(); + var setCSRFToken = function(securityToken) { + jQuery.ajaxPrefilter(function(options, _, xhr) { + if (!xhr.crossDomain) { + xhr.setRequestHeader(CSRF_HEADER, securityToken); } }); + }; - $('#complete-bonfire-dialog').on('hidden.bs.modal', function() { - editor.focus(); - }); + setCSRFToken($('meta[name="csrf-token"]').attr('content')); - $('#all-bonfires-dialog').on('hidden.bs.modal', function() { - editor.focus(); - }); + $('.start-challenge').on('click', function() { + $(this).parent().remove(); + $('.challenge-content') + .removeClass('hidden-element') + .addClass('animated fadeInDown'); + }); - $('#showAllCoursewares').on('click', function() { - $('#all-coursewares-dialog').modal('show'); - }); - - $('#all-coursewares-dialog').on('hidden.bs.modal', function() { - editor.focus(); - }); + //$('.completed-challenge').on('click', function() { + // $('#complete-challenge-dialog').modal('show'); + // // Only post to server if there is an authenticated user + // if ($('.signup-btn-nav').length < 1) { + // l = location.pathname.split('/'); + // cn = l[l.length - 1]; + // $.ajax({ + // type: 'POST', + // data: {challengeNumber: cn}, + // url: '/completed-challenge/' + // }); + // } + //}); - $('#complete-courseware-dialog').on('hidden.bs.modal', function() { - editor.focus(); - }); - $('#next-courseware-button').on('click', function() { - console.log(passedCoursewareHash); - if ($('.signup-btn-nav').length < 1) { - $.post( - '/completed-courseware/', - { - coursewareInfo: { - coursewareHash: passedCoursewareHash, - coursewareName: passedCoursewareName - } - }).success( - function(res) { - if (res) { - window.location.href = '/challenges'; - } - } - ); + function completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash) { + $('#complete-bonfire-dialog').modal('show'); + // Only post to server if there is an authenticated user + if ($('.signup-btn-nav').length < 1) { - } - }); + $.post( + '/completed-bonfire', + { + bonfireInfo: { + completedWith : didCompleteWith, + solution: bonfireSolution, + bonfireHash: thisBonfireHash + } + }, + function(res) { + if (res) { + window.location.href = '/bonfires' + } + }); + } + } + $('.next-bonfire-button').on('click', function() { + var bonfireSolution = myCodeMirror.getValue(); + var thisBonfireHash = passedBonfireHash || null; + var didCompleteWith = $('#completed-with').val() || null; + completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash); - $('.all-challenges').on('click', function() { - $('#all-challenges-dialog').modal('show'); - }); + }); - $('#showAllButton').on('click', function() { - $('#all-bonfires-dialog').modal('show'); - }); + $('#completed-courseware').on('click', function() { + $('#complete-courseware-dialog').modal('show'); + }); - $('.next-challenge-button').on('click', function() { - l = location.pathname.split('/'); - window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1); - }); + $('#completed-zipline-or-basejump').on('click', function() { + $('#complete-zipline-or-basejump-dialog').modal('show'); + }); + $('#complete-bonfire-dialog').on('hidden.bs.modal', function() { + editor.focus(); + }); - // Bonfire instructions functions - $('#more-info').on('click', function() { - ga('send', 'event', 'Challenge', 'more-info', challengeName); - $('#brief-instructions').hide(); - $('#long-instructions').show().removeClass('hide'); + $('#all-bonfires-dialog').on('hidden.bs.modal', function() { + editor.focus(); + }); - }); - $('#less-info').on('click', function() { - $('#brief-instructions').show(); - $('#long-instructions').hide(); - }); + $('#showAllCoursewares').on('click', function() { + $('#all-coursewares-dialog').modal('show'); + }); - var upvoteHandler = function () { - if (typeof user == "undefined" || !user) { - window.location.href = '/signin'; - return; - } - var _id = storyId; - $('#upvote').unbind('click'); - var alreadyUpvoted = false; - for (var i = 0; i < upVotes.length; i++) { - if (upVotes[i].upVotedBy === user._id) { - alreadyUpvoted = true; - break; + $('#all-coursewares-dialog').on('hidden.bs.modal', function() { + editor.focus(); + }); + + $('#complete-courseware-dialog').on('hidden.bs.modal', function() { + editor.focus(); + }); + $('#next-courseware-button').on('click', function() { + console.log(passedCoursewareHash); + if ($('.signup-btn-nav').length < 1) { + switch (challengeType) { + case 0: + case 1: + case 2: + $.post( + '/completed-courseware/', + { + coursewareInfo: { + coursewareHash: passedCoursewareHash, + coursewareName: passedCoursewareName + } + }).success( + function(res) { + if (res) { + window.location.href = '/challenges'; + } } - } - if (!alreadyUpvoted) { - $.post('/stories/upvote', - { - data: { - id: _id, - upVoter: user - } - }) - .fail(function (xhr, textStatus, errorThrown) { - $('#upvote').bind('click', upvoteHandler); - }) - .done(function (data, textStatus, xhr) { - $('#upvote').text('Upvoted!').addClass('disabled'); - - $('#storyRank').text(data.rank + " points"); - }); - } - }; - $('#upvote').on('click', upvoteHandler); - - - var storySubmitButtonHandler = function storySubmitButtonHandler() { - - var link = $('#story-url').val(); - var headline = $('#story-title').val(); - var description = $('#description-box').val(); - var userDataForUpvote = { - upVotedBy: user._id, - upVotedByUsername: user.profile.username - }; - $('#story-submit').unbind('click'); - $.post('/stories/', + ); + break; + case 3: + var didCompleteWith = $('#completed-with').val() || null; + var publicURL = $('#public-url').val() || null; + $.post( + '/completed-zipline-or-basejump/', { - data: { - link: link, - headline: headline, - timePosted: Date.now(), - description: description, - storyMetaDescription: storyMetaDescription, - rank: 1, - upVotes: [userDataForUpvote], - author: { - picture: user.profile.picture, - userId: user._id, - username: user.profile.username - }, - comments: [], - image: storyImage - } - }) - .fail(function (xhr, textStatus, errorThrown) { - $('#story-submit').bind('click', storySubmitButtonHandler); - }) - .done(function (data, textStatus, xhr) { - window.location = '/stories/' + JSON.parse(data).storyLink; + coursewareInfo: { + coursewareHash: passedCoursewareHash, + coursewareName: passedCoursewareName, + completedWith: didCompleteWith, + publicURL: publicURL, + challengeType: challengeType + } + }).success( + function() { + window.location.href = '/challenges'; + }).fail( + function() { + window.location.href = '/challenges'; }); - - }; - - $('#story-submit').on('click', storySubmitButtonHandler); - - var commentSubmitButtonHandler = function commentSubmitButtonHandler() { - $('comment-button').unbind('click'); - var data = $('#comment-box').val(); - - $('#comment-button').attr('disabled', 'disabled'); - $.post('/stories/comment/', + break; + case 4: + var didCompleteWith = $('#completed-with').val() || null; + var publicURL = $('#public-url').val() || null; + var githubURL = $('#github-url').val() || null; + $.post( + '/completed-zipline-or-basejump/', { - data: { - associatedPost: storyId, - body: data, - author: { - picture: user.profile.picture, - userId: user._id, - username: user.profile.username - } - } - }) - .fail(function (xhr, textStatus, errorThrown) { - $('#comment-button').attr('disabled', false); - }) - .done(function (data, textStatus, xhr) { - window.location.reload(); + coursewareInfo: { + coursewareHash: passedCoursewareHash, + coursewareName: passedCoursewareName, + completedWith: didCompleteWith, + publicURL: publicURL, + githubURL: githubURL, + challengeType: challengeType + } + }).success(function() { + window.location.href = '/challenges'; + }).fail(function() { + window.location.replace(window.location.href); }); + break; + default: + break; + } + } + }); + + + $('.all-challenges').on('click', function() { + $('#all-challenges-dialog').modal('show'); + }); + + $('#showAllButton').on('click', function() { + $('#all-bonfires-dialog').modal('show'); + }); + + $('.next-challenge-button').on('click', function() { + l = location.pathname.split('/'); + window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1); + }); + + +// Bonfire instructions functions + $('#more-info').on('click', function() { + ga('send', 'event', 'Challenge', 'more-info', challengeName); + $('#brief-instructions').hide(); + $('#long-instructions').show().removeClass('hide'); + + }); + $('#less-info').on('click', function() { + $('#brief-instructions').show(); + $('#long-instructions').hide(); + }); + + var upvoteHandler = function () { + var _id = storyId; + $('#upvote').unbind('click'); + var alreadyUpvoted = false; + for (var i = 0; i < upVotes.length; i++) { + if (upVotes[i].upVotedBy === user._id) { + alreadyUpvoted = true; + break; + } + } + if (!alreadyUpvoted) { + $.post('/stories/upvote', + { + data: { + id: _id, + upVoter: user + } + }) + .fail(function (xhr, textStatus, errorThrown) { + $('#upvote').bind('click', upvoteHandler); + }) + .done(function (data, textStatus, xhr) { + $('#upvote').text('Upvoted!').addClass('disabled'); + + $('#storyRank').text(data.rank + " points"); + }); + } + }; + $('#upvote').on('click', upvoteHandler); + + + var storySubmitButtonHandler = function storySubmitButtonHandler() { + + var link = $('#story-url').val(); + var headline = $('#story-title').val(); + var description = $('#description-box').val(); + var userDataForUpvote = { + upVotedBy: user._id, + upVotedByUsername: user.profile.username }; + $('#story-submit').unbind('click'); + $.post('/stories/', + { + data: { + link: link, + headline: headline, + timePosted: Date.now(), + description: description, + storyMetaDescription: storyMetaDescription, + rank: 1, + upVotes: [userDataForUpvote], + author: { + picture: user.profile.picture, + userId: user._id, + username: user.profile.username + }, + comments: [], + image: storyImage + } + }) + .fail(function (xhr, textStatus, errorThrown) { + $('#story-submit').bind('click', storySubmitButtonHandler); + }) + .done(function (data, textStatus, xhr) { + window.location = '/stories/' + JSON.parse(data).storyLink; + }); - $('#comment-button').on('click', commentSubmitButtonHandler); + }; + + $('#story-submit').on('click', storySubmitButtonHandler); + + var commentSubmitButtonHandler = function commentSubmitButtonHandler() { + $('comment-button').unbind('click'); + var data = $('#comment-box').val(); + + $('#comment-button').attr('disabled', 'disabled'); + $.post('/stories/comment/', + { + data: { + associatedPost: storyId, + body: data, + author: { + picture: user.profile.picture, + userId: user._id, + username: user.profile.username + } + } + }) + .fail(function (xhr, textStatus, errorThrown) { + $('#comment-button').attr('disabled', false); + }) + .done(function (data, textStatus, xhr) { + window.location.reload(); + }); + + }; + + $('#comment-button').on('click', commentSubmitButtonHandler); }); var profileValidation = angular.module('profileValidation',['ui.bootstrap']); profileValidation.controller('profileValidationController', ['$scope', '$http', - function($scope, $http) { - $http.get('/account/api').success(function(data) { - $scope.user = data.user; - $scope.user.profile.username = $scope.user.profile.username ? $scope.user.profile.username.toLowerCase() : undefined; - $scope.storedUsername = data.user.profile.username; - $scope.storedEmail = data.user.email; - $scope.user.email = $scope.user.email ? $scope.user.email.toLowerCase() : undefined; - $scope.user.profile.twitterHandle = $scope.user.profile.twitterHandle ? $scope.user.profile.twitterHandle.toLowerCase() : undefined; - $scope.asyncComplete = true; - }); - } + function($scope, $http) { + $http.get('/account/api').success(function(data) { + $scope.user = data.user; + $scope.user.profile.username = $scope.user.profile.username ? $scope.user.profile.username.toLowerCase() : undefined; + $scope.storedUsername = data.user.profile.username; + $scope.storedEmail = data.user.email; + $scope.user.email = $scope.user.email ? $scope.user.email.toLowerCase() : undefined; + $scope.user.profile.twitterHandle = $scope.user.profile.twitterHandle ? $scope.user.profile.twitterHandle.toLowerCase() : undefined; + $scope.asyncComplete = true; + }); + } ]); profileValidation.controller('pairedWithController', ['$scope', - function($scope) { - $scope.existingUser = null; - } + function($scope) { + $scope.existingUser = null; + } ]); profileValidation.controller('emailSignUpController', ['$scope', - function($scope) { + function($scope) { - } + } ]); profileValidation.controller('emailSignInController', ['$scope', - function($scope) { + function($scope) { - } + } ]); profileValidation.controller('URLSubmitController', ['$scope', - function($scope) { + function($scope) { - } + } ]); profileValidation.controller('nonprofitFormController', ['$scope', - function($scope) { + function($scope) { - } + } ]); profileValidation.controller('doneWithFirst100HoursFormController', ['$scope', - function($scope) { + function($scope) { - } + } ]); profileValidation.controller('submitStoryController', ['$scope', - function($scope) { + function($scope) { - } + } ]); profileValidation.directive('uniqueUsername',['$http',function($http) { - return { - restrict: 'A', - require: 'ngModel', - link: function (scope, element, attrs, ngModel) { - element.bind("keyup", function (event) { - ngModel.$setValidity('unique', true); - if (element.val()) { - $http.get("/api/checkUniqueUsername/" + element.val()).success(function (data) { - if (element.val() == scope.storedUsername) { - ngModel.$setValidity('unique', true); - } else if (data) { - ngModel.$setValidity('unique', false); - } - }); - } - }); + return { + restrict: 'A', + require: 'ngModel', + link: function (scope, element, attrs, ngModel) { + element.bind("keyup", function (event) { + ngModel.$setValidity('unique', true); + if (element.val()) { + $http.get("/api/checkUniqueUsername/" + element.val()).success(function (data) { + if (element.val() == scope.storedUsername) { + ngModel.$setValidity('unique', true); + } else if (data) { + ngModel.$setValidity('unique', false); + } + }); } + }); } + } }]); profileValidation.directive('existingUsername', ['$http', function($http) { - return { - restrict: 'A', - require: 'ngModel', - link: function (scope, element, attrs, ngModel) { - element.bind("keyup", function (event) { - if (element.val().length > 0) { - ngModel.$setValidity('exists', false); - } else { - element.removeClass('ng-dirty'); - ngModel.$setPristine(); - } - if (element.val()) { - $http - .get("/api/checkExistingUsername/" + element.val()) - .success(function (data) { - ngModel.$setValidity('exists', data); - }); - } + return { + restrict: 'A', + require: 'ngModel', + link: function (scope, element, attrs, ngModel) { + element.bind("keyup", function (event) { + if (element.val().length > 0) { + ngModel.$setValidity('exists', false); + } else { + element.removeClass('ng-dirty'); + ngModel.$setPristine(); + } + if (element.val()) { + $http + .get("/api/checkExistingUsername/" + element.val()) + .success(function (data) { + ngModel.$setValidity('exists', data); }); } + }); } + } }]); profileValidation.directive('uniqueEmail', ['$http', function($http) { - return { - restrict: 'A', - require: 'ngModel', - link: function getUnique (scope, element, attrs, ngModel) { - element.bind("keyup", function (event) { - ngModel.$setValidity('unique', true); - if (element.val()) { - $http.get("/api/checkUniqueEmail/" + encodeURIComponent(element.val())).success(function (data) { - if (element.val() == scope.storedEmail) { - ngModel.$setValidity('unique', true); - } else if (data) { - ngModel.$setValidity('unique', false); - } - }); - }; - }); - } + return { + restrict: 'A', + require: 'ngModel', + link: function getUnique (scope, element, attrs, ngModel) { + element.bind("keyup", function (event) { + ngModel.$setValidity('unique', true); + if (element.val()) { + $http.get("/api/checkUniqueEmail/" + encodeURIComponent(element.val())).success(function (data) { + if (element.val() == scope.storedEmail) { + ngModel.$setValidity('unique', true); + } else if (data) { + ngModel.$setValidity('unique', false); + } + }); + }; + }); } + } }]); diff --git a/views/bonfire/show.jade b/views/bonfire/show.jade index 7b1cdb3ac7..f72ef0dc4e 100644 --- a/views/bonfire/show.jade +++ b/views/bonfire/show.jade @@ -15,7 +15,7 @@ block content script(src='/js/lib/codemirror/mode/javascript/javascript.js') script(src='/js/lib/jailed/jailed.js') script(src='/js/lib/bonfire/bonfireInit.js') - script(src="https://cdn.jsdelivr.net/ramda/0.10.0/ramda.min.js") + script(src='/js/lib/ramda/ramda.min.js') .row @@ -80,7 +80,7 @@ block content #less-info.btn.btn-primary.btn-block.btn-primary-ghost span.ion-arrow-up-b | Less information - + #submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter) #showAllButton.btn.btn-info.btn-big.btn-block Show all bonfires br @@ -147,17 +147,7 @@ block content .modal-body include ../partials/bonfires script. - $.ajax({ - url: 'https://api-ssl.bitly.com/v3/shorten?access_token=75e7931a19befaafcf108021b6d597e554b2c5c3&longUrl=http%3A%2F%2Ffreecodecamp.com%2Fbonfires%2F' + dashed + '&format=txt' - }) - .success( - function (data) { - console.log(data); - url = "https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=" + data + "&hashtags=LearnToCode, JavaScript"; - $('.btn-twitter').attr('href', url); - } - ); var MDNlinks = !{JSON.stringify(MDNlinks)}; if (!MDNlinks.length) { $('#MDN-links').addClass('collapse'); - } \ No newline at end of file + } diff --git a/views/coursewares/showHTML.jade b/views/coursewares/showHTML.jade index 9966844e3a..7ad3530f9b 100644 --- a/views/coursewares/showHTML.jade +++ b/views/coursewares/showHTML.jade @@ -60,6 +60,7 @@ block content var challengeName = !{JSON.stringify(name)}; var passedCoursewareName = challengeName; var prodOrDev = !{JSON.stringify(environment)}; + var challengeType = !{JSON.stringify(challengeType)}; var started = Math.floor(Date.now()); .col-xs-12.col-sm-12.col-md-5.col-lg-6 #mainEditorPanel @@ -81,4 +82,4 @@ block content .animated.zoomInDown.delay-half span.completion-icon.ion-checkmark-circled.text-primary a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress - script(src="/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js") \ No newline at end of file + script(src="/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js") diff --git a/views/coursewares/showJS.jade b/views/coursewares/showJS.jade index 182d25a69a..3e33ee4a4b 100644 --- a/views/coursewares/showJS.jade +++ b/views/coursewares/showJS.jade @@ -47,6 +47,7 @@ block content var challengeSeed = !{JSON.stringify(challengeSeed)}; var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; var challengeName = !{JSON.stringify(name)}; + var challengeType = !{JSON.stringify(challengeType)}; var passedCoursewareName = challengeName; var started = Math.floor(Date.now()); @@ -72,4 +73,4 @@ block content i.fa.fa-twitter   = phrase - else - a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress \ No newline at end of file + a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress diff --git a/views/coursewares/showVideo.jade b/views/coursewares/showVideo.jade index fa85520616..b6264c395a 100644 --- a/views/coursewares/showVideo.jade +++ b/views/coursewares/showVideo.jade @@ -27,6 +27,7 @@ block content var challengeName = !{JSON.stringify(name)}; var passedCoursewareName = challengeName; var started = Math.floor(Date.now()); + var challengeType = !{JSON.stringify(challengeType)}; #complete-courseware-dialog.modal(tabindex='-1') .modal-dialog.animated.zoomIn.fast-animation .modal-content @@ -46,10 +47,8 @@ block content a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress h1 #{name} script. - var challengeName = !{JSON.stringify(name)}; - var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; $('body').on('keypress', function(e) { if (e.ctrlKey && e.keyCode == 13) { $('#complete-courseware-dialog').modal('show'); } - }); \ No newline at end of file + }); diff --git a/views/coursewares/showZiplineOrBasejump.jade b/views/coursewares/showZiplineOrBasejump.jade index c5df3c03ac..d547ab3019 100644 --- a/views/coursewares/showZiplineOrBasejump.jade +++ b/views/coursewares/showZiplineOrBasejump.jade @@ -13,7 +13,7 @@ block content iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}') br - if (user) - a.btn.btn-primary.btn-lg.btn-block#completed-courseware I've completed this challenge (ctrl + enter) + a.btn.btn-primary.btn-lg.btn-block#completed-zipline-or-basejump I've completed this challenge (ctrl + enter) script. var userLoggedIn = true; - else @@ -26,6 +26,7 @@ block content var challengeName = !{JSON.stringify(name)}; var passedCoursewareName = challengeName; var started = Math.floor(Date.now()); + var challengeType = !{JSON.stringify(challengeType)}; #complete-zipline-or-basejump-dialog.modal(tabindex='-1') .modal-dialog.animated.zoomIn.fast-animation .modal-content @@ -40,34 +41,32 @@ block content .form-group.text-center .col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2.animated.fadeIn - // extra field to distract password tools like lastpass from injecting css into our username field - input.form-control(ng-show="false") - if (challengeType === 'zipline') - input.form-control#public-url(name="codepenUrl", placeholder="http://codepen.io/your-pen-here", autofocus) - else - input.form-control#public-url(name="depoloymentUrl", placeholder="http://yourapp.com", autofocus) - input.form-control#github-url(name="githubUrl", placeholder="http://github.com/camper/project") + // extra field to distract password tools like lastpass from injecting css into our username field + input.form-control(ng-show="false") + if (challengeType === 3) + input.form-control#public-url(name="codepenUrl", placeholder="http://codepen.io/your-pen-here", autofocus) + else + input.form-control#public-url(name="depoloymentUrl", placeholder="http://yourapp.com", autofocus) + input.form-control#github-url(name="githubUrl", placeholder="http://github.com/camper/project") - input.form-control#completed-with(name="existingUser", placeholder="If you paired, enter your pair's username here", existing-username='', ng-model="existingUser") - .col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2(ng-cloak, ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0") - alert(type='danger') - span.ion-close-circled - | Username not found + input.form-control#completed-with(name="existingUser", placeholder="If you paired, enter your pair's username here", existing-username='', ng-model="existingUser") + .col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2(ng-cloak, ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0") + alert(type='danger') + span.ion-close-circled + | Username not found - a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-bonfire-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next bonfire (ctrl + enter) - - - - if (user.progressTimestamps.length > 2) - a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(target="_blank") - i.fa.fa-twitter   - = phrase + if (user) + a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next challenge (ctrl + enter) + + - if (user.progressTimestamps.length > 2) + a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(target="_blank") + i.fa.fa-twitter   + = phrase - else a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress script. - var challengeName = !{JSON.stringify(name)}; - var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; $('body').on('keypress', function(e) { if (e.ctrlKey && e.keyCode == 13) { - $('#complete-courseware-dialog').modal('show'); + $('#complete-zipline-or-basejump-dialog').modal('show'); } - }); \ No newline at end of file + }); diff --git a/views/partials/bonfires.jade b/views/partials/bonfires.jade index 3b59e6c8e5..2c219e089b 100644 --- a/views/partials/bonfires.jade +++ b/views/partials/bonfires.jade @@ -1,5 +1,6 @@ h3 ol#bonfireList + script(src='/js/lib/ramda/ramda.min.js') script. var getLinkedName = function getLinkedName(name) { return name.toLowerCase().replace(/\s/g, '-'); @@ -20,4 +21,4 @@ h3 $(li).appendTo($('#bonfireList')); } - }); \ No newline at end of file + });