From c20aa1697c663109de4c7c47b3d153f580fead84 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Sun, 25 Jan 2015 23:10:05 -0800 Subject: [PATCH] generator now publishes directly to a view where you can interact with your new bonfire --- app.js | 2 + controllers/bonfire.js | 65 +++++----- models/Bonfire.js | 4 +- public/js/lib/bonfire/bonfireFramework.js | 3 +- seed_data/bonfires.json | 138 ++++++++++++---------- views/bonfire/bonfire.jade | 6 + views/bonfire/public-generator.jade | 44 +++++++ 7 files changed, 170 insertions(+), 92 deletions(-) create mode 100644 views/bonfire/public-generator.jade diff --git a/app.js b/app.js index 24b87bf777..279c24b74f 100644 --- a/app.js +++ b/app.js @@ -263,6 +263,8 @@ app.get( app.get('/bonfires', bonfireController.returnBonfire); app.get('/bonfire/generator', bonfireController.returnGenerator); app.post('/bonfire/generator', bonfireController.generateChallenge); +app.get('/bonfire/public-generator', bonfireController.publicGenerator); +app.post('/bonfire/public-generator', bonfireController.testBonfire) // Unique Check API route app.get('/api/checkUniqueUsername/:username', userController.checkUniqueUsername); diff --git a/controllers/bonfire.js b/controllers/bonfire.js index 264c688281..079aad96b1 100644 --- a/controllers/bonfire.js +++ b/controllers/bonfire.js @@ -15,7 +15,7 @@ exports.index = function(req, res) { title: 'Learn to code with Bonfire' }); - Bonfire.find({}, null, { sort: { bonfireNumber: 1 } }, function(err, c) { + Bonfire.find({}, null, { sort: { difficulty: 1 } }, function(err, c) { if (err) { debug('bonfire err: ', err); next(err); @@ -49,8 +49,7 @@ exports.returnBonfire = function(req, res, next) { completedWith: null, title: bonfire[bonfireNumber].name, name: bonfire[bonfireNumber].name, - number: bonfire[bonfireNumber].bonfireNumber, - difficulty: bonfire[bonfireNumber].difficulty, + difficulty: +bonfire[bonfireNumber].difficulty, brief: bonfire[bonfireNumber].description[0], details: bonfire[bonfireNumber].description.slice(1), tests: bonfire[bonfireNumber].tests, @@ -71,7 +70,7 @@ exports.returnIndividualBonfire = function(req, res, next) { var bonfireNumber = parseInt(req.params.bonfireNumber) || 0; if (bonfireNumber > highestBonfireNumber) { bonfireNumber = 0; } - Bonfire.find({}, null, { sort: { bonfireNumber: 1 } }, function(err, bonfire) { + Bonfire.find({}, null, { sort: { difficulty: 1 } }, function(err, bonfire) { if (err) { next(err); } @@ -79,8 +78,7 @@ exports.returnIndividualBonfire = function(req, res, next) { completedWith: null, title: bonfire[bonfireNumber].name, name: bonfire[bonfireNumber].name, - number: bonfire[bonfireNumber].bonfireNumber, - difficulty: bonfire[bonfireNumber].difficulty, + difficulty: +bonfire[bonfireNumber].difficulty, brief: bonfire[bonfireNumber].description[0], details: bonfire[bonfireNumber].description.slice(1), tests: bonfire[bonfireNumber].tests, @@ -134,25 +132,33 @@ function randomString() { */ exports.testBonfire = function(req, res) { - // TODO: Add stuff here to parse posted variables and feed them back to bonfire playground - var candidateTitle = req.body.bonfireInfo.title; - var candidateName = req.body.bonfireInfo.name; - var candidateDifficulty = req.body.bonfireInfo.difficulty; - var candidateBrief = req.body.bonfireInfo.brief; - var candidateDetails = req.body.bonfireInfo.details; - var candidateTests = req.body.bonfireInfo.tests; - var candidateChallengeSeed = req.body.bonfireInfo.challengeSeed; - var candidateChallengeEntryPoint = req.body.bonfireInfo.challengeSeed; - res.render('bonfire/bonfire', { - title: candidateTitle, - name: candidateName, - difficulty: candidateDifficulty, - brief: candidateBrief, - details: candidateDetails, - tests: candidateTests, - challengeSeed: candidateChallengeSeed, - challengeEntryPoint: candidateChallengeEntryPoint, - bonfireHash: bonfire[bonfireNumber]._id + var bonfireName = req.body.name, + bonfireTests = req.body.tests, + bonfireDifficulty = req.body.difficulty, + bonfireDescription = req.body.description, + bonfireEntryPoint = req.body.challengeEntryPoint, + 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, + title: bonfireName, + difficulty: +bonfireDifficulty, + brief: bonfireDescription[0], + details: bonfireDescription.slice(1), + tests: bonfireTests, + challengeSeed: bonfireChallengeSeed, + challengeEntryPoint: bonfireEntryPoint, + cc: req.user ? req.user.bonfiresHash : undefined, + points: req.user ? req.user.points : undefined, + verb: resources.randomVerb(), + phrase: resources.randomPhrase(), + compliment: resources.randomCompliment(), + bonfires: [], + bonfireHash: "test" }); }; @@ -162,6 +168,10 @@ function getRidOfEmpties(elem) { } } +exports.publicGenerator = function(req, res) { + res.render('bonfire/public-generator'); +} + exports.generateChallenge = function(req, res) { var bonfireName = req.body.name, bonfireTests = req.body.tests, @@ -177,14 +187,13 @@ exports.generateChallenge = function(req, res) { var response = { + _id: randomString(), name: bonfireName, - tests: bonfireTests, difficulty: bonfireDifficulty, description: bonfireDescription, challengeEntryPoint: bonfireEntryPoint, challengeSeed: bonfireChallengeSeed, - bonfireNumber: 0, - _id: randomString() + tests: bonfireTests }; res.send(response); } diff --git a/models/Bonfire.js b/models/Bonfire.js index dd0cff31d7..5cb531547e 100644 --- a/models/Bonfire.js +++ b/models/Bonfire.js @@ -12,14 +12,12 @@ var bonfireSchema = new mongoose.Schema({ type: String, unique: true }, - difficulty: Number, + difficulty: String, description: Array, tests: Array, challengeSeed: String, - bonfireNumber: Number, challengeEntryPoint: String, challengeEntryPointNegate: String - }); module.exports = mongoose.model('Bonfire', bonfireSchema); diff --git a/public/js/lib/bonfire/bonfireFramework.js b/public/js/lib/bonfire/bonfireFramework.js index d5dc8860af..3d9f68b6b5 100644 --- a/public/js/lib/bonfire/bonfireFramework.js +++ b/public/js/lib/bonfire/bonfireFramework.js @@ -216,7 +216,8 @@ var runTests = function(err, data) { userTests.forEach(function(test, ix, arr){ try { if (test) { - var output = eval(reassembleTest(test, data)); + var test = JSON.stringify(reassembleTest(test, data)); + var output = eval(test); } } catch(error) { allTestsPassed = false; diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 6b04e83164..bf8412d639 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -2,7 +2,7 @@ { "_id" : "7123c8c441eddfaeb5bdef0d", "name": "Meet Bonfire", - "difficulty": 1, + "difficulty": "0", "description": [ "Click the button below for further instructions.", "Your goal is to fix the failing test.", @@ -15,12 +15,11 @@ ], "challengeSeed": "function meetBonfire(argument) {\n // Good luck!\n console.log(\"you can read this function's argument in the developer tools\", argument);\n\nreturn false;\n}\n\n", "challengeEntryPoint": "meetBonfire(\"You can do this!\");", - "bonfireNumber": 0 }, { "_id" : "aaa48de84e1ecc7c742e1124", "name": "Check for Palindromes", - "difficulty": 1, + "difficulty": "1", "description": [ "Return 'true' if a given string is a palindrome.", "A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation and case.", @@ -39,12 +38,11 @@ ], "challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n", "challengeEntryPoint": "palindrome(\"eye\");", - "bonfireNumber": 1 }, { "_id" : "ff0395860f5d3034dc0bfc94", "name": "Validate US Telephone Numbers", - "difficulty": 3, + "difficulty": "3", "description": [ "Return true if the passed string is a valid US phone number", "The user may fill out the form field any way they choose as long as it is a valid US number. The following are all valid formats for US numbers:", @@ -77,76 +75,96 @@ ], "challengeSeed": "function telephoneCheck(str) {\n // Good luck!\n return true;\n}\n\n", "challengeEntryPoint": "telephoneCheck(\"555-555-5555\");", - "bonfireNumber": 2 }, { + "_id": "202eed8fc186c8434cb6d618", "name": "Reverse a String", + "difficulty": "1", "tests": [ "expect(reverseString('hello')).to.be.a('String');", "expect(reverseString('hello')).to.equal('olleh');", "expect(reverseString('Howdy')).to.equal('ydwoH');", "expect(reverseString('Greetings from Earth')).to.equal('htraE morf sgniteerG');" ], - "difficulty": "1", "description": [ - "Reverse the provided string. ", + "Reverse the provided string.", "You may need to turn the string into an array before you can reverse it.", "Your result must be a string." ], "challengeEntryPoint": "reverseString('hello');", "challengeSeed": "function reverseString(str) {\n return str;\r\n}", - "bonfireNumber": 0, - "_id": "202eed8fc186c8434cb6d618" }, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + "_id": "302f7aae1aa3152a5b413bca", + "name": "Factorialize a Number", + "tests": [ + "expect(factorialize(5)).to.be.a(\"Number\");", + "expect(factorialize(5)).to.equal(120);", + "expect(factorialize(10)).to.equal(3628800);", + "expect(factorialize(20)).to.equal(2432902008176640000);" + ], + "difficulty": "1", + "description": [ + "Return the factorial of the provided integer.", + "If the integer is represented with the letter n, a factorial is the product of all positive integers less than or equal to n.", + "Factorials are often represented with the shorthand notation n!", + "For example: 5! = 1 * 2 * 3 * 4 * 5 = 120f" + ], + "challengeSeed": "function factorialize(num) {\n return num;\r\n}", + "challengeEntryPoint": "factorialize(5);" + }, + { + "_id": "a26cbbe9ad8655a977e1ceb5", + "name": "Find the Longest Word in a String", + "difficulty": "1", + "description": [ + "Return the length of the longest word in the provided sentence.", + "Your response should be a number." + ], + "challengeEntryPoint": "findLongestWord('The quick brown fox jumped over the lazy dog');", + "challengeSeed": "function findLongestWord(str) {\n return str.length;\r\n}", + "tests": [ + "expect(findLongestWord('The quick brown fox jumped over the lazy dog')).to.be.a('Number');", + "expect(findLongestWord('The quick brown fox jumped over the lazy dog')).to.equal(6);", + "expect(findLongestWord('May the force be with you')).to.equal(5);", + "expect(findLongestWord('Google do a barrel roll')).to.equal(6);", + "expect(findLongestWord('What is the average airspeed velocity of an unladen swallow')).to.equal(8);" + ] + }, + { + "_id": "3566b1109230028080c9345d", + "name": "Sum All Numbers in a Range", + "difficulty": "2", + "description": [ + "We'll pass you an array of two numbers. Return the sum those two numbers and all numbers between them.", + "The lowest number will not always come first." + ], + "challengeEntryPoint": "sumAll([1, 4]);", + "challengeSeed": "function sumAll(arr) {\n return(1);\r\n}", + "tests": [ + "expect(sumAll([1, 4])).to.be.a('Number');", + "expect(sumAll([1, 4])).to.equal(10);", + "expect(sumAll([4, 1])).to.equal(10);", + "expect(sumAll([5, 10])).to.equal(45);", + "expect(sumAll([10, 5])).to.equal(45);" + ] + }, + { + "_id": "fb6137d4e35944e21037b769", + "name": "Title Case a Sentence", + "difficulty": "1", + "description": [ + "Return the provided string with the first letter of each word capitalized.", + "For the purpose of this exercise, you should also capitalize connecting words like 'the' and 'of'." + ], + "challengeEntryPoint": "titleCase(\"I'm a little tea pot\")", + "challengeSeed": "function titleCase(str) {\n return str;\r\n}", + "tests": [ + "expect(titleCase(\"I'm a little tea pot\")).to.be.a('String');", + "expect(titleCase(\"I'm a little tea pot\")).to.equal(\"I'm A Little Tea Pot\");", + "expect(titleCase(\"sHoRt AnD sToUt\")).to.equal(\"Short And Stout\");", + "expect(titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\")).to.equal(\"Here Is My Handle Here Is My Spout\");" + ] + } ] diff --git a/views/bonfire/bonfire.jade b/views/bonfire/bonfire.jade index 62894f1630..ff07aee175 100644 --- a/views/bonfire/bonfire.jade +++ b/views/bonfire/bonfire.jade @@ -15,6 +15,12 @@ block content script(src='/js/lib/jailed/jailed.js') script(src='/js/lib/bonfire/bonfireInit.js') .row + script(type="text/javascript"). + var tests = !{JSON.stringify(tests)}; + var challengeSeed = !{JSON.stringify(challengeSeed)}; + var challengeEntryPoint = !{JSON.stringify(challengeEntryPoint)}; + var title = !{JSON.stringify(title)}; + #mainEditorPanel.col-sm-12.col-md-7.col-xs-12 .panel.panel-primary.panel-bonfire .panel-heading.text-center Playground diff --git a/views/bonfire/public-generator.jade b/views/bonfire/public-generator.jade new file mode 100644 index 0000000000..13750a9b4d --- /dev/null +++ b/views/bonfire/public-generator.jade @@ -0,0 +1,44 @@ +extends ../layout +block content + .row + .col-md-offset-2.col-md-8.col-lg-offset-2.col-lg-8.text-center + h1 JSON generator for bonfire challenges - just fill the form out and get the correct format back + .col-xs-12.col-sm-12.col-md-offset-3.col-md-6.col-lg-offset-3-col-lg-6 + .panel + form.form-horizontal(method="POST", action="/bonfire/public-generator", name="bonfireInfo") + .form-group + label.col-sm-2.control-label(for='name') name: + .col-sm-10 + input#name.form-control(type='text', placeholder='name', name="name") + .form-group + label.col-sm-2.control-label(for='difficultyField') difficulty: + .col-sm-10 + label.radio-inline 1 + input#inlineRadio1(type='radio', name='difficulty', value='1') + label.radio-inline 2 + input#inlineRadio2(type='radio', name='difficulty', value='2') + label.radio-inline 3 + input#inlineRadio3(type='radio', name='difficulty', value='3') + label.radio-inline 4 + input#inlineRadio4(type='radio', name='difficulty', value='4') + label.radio-inline 5 + input#inlineRadio5(type='radio', name='difficulty', value='5') + .form-group + label.col-sm-2.control-label.wrappable(for='description') description: + .col-sm-10 + textarea#description.form-control(name="description", placeholder="Separate sentences by exactly one space only. Do not add in line breaks.") + .form-group + label.col-sm-2.control-label.wrappable(for='challengeSeed') challengeSeed: + .col-sm-10 + textarea#challengeSeed.form-control(name="challengeSeed", rows=5) + .form-group + label.col-sm-2.control-label.wrappable(for='challengeEntryPoint') challenge entrypoint: + .col-sm-10 + textarea#name.form-control(name="challengeEntryPoint", rows=1, type='text', placeholder="palindrome(\"eye\");") + .form-group + label.col-sm-2.control-label.wrappable(for='tests') tests: + .col-sm-10 + textarea#tests.form-control(name="tests", rows=5, placeholder="Separate tests by a newline.") + .form-group + .col-sm-offset-2.col-sm-10 + input.btn.btn-default(type='submit', value="submit")