generator now publishes directly to a view where you can interact with your new bonfire

This commit is contained in:
Michael Q Larson
2015-01-25 23:10:05 -08:00
parent 7c6cbbf221
commit c20aa1697c
7 changed files with 170 additions and 92 deletions

2
app.js
View File

@ -263,6 +263,8 @@ app.get(
app.get('/bonfires', bonfireController.returnBonfire); app.get('/bonfires', bonfireController.returnBonfire);
app.get('/bonfire/generator', bonfireController.returnGenerator); app.get('/bonfire/generator', bonfireController.returnGenerator);
app.post('/bonfire/generator', bonfireController.generateChallenge); app.post('/bonfire/generator', bonfireController.generateChallenge);
app.get('/bonfire/public-generator', bonfireController.publicGenerator);
app.post('/bonfire/public-generator', bonfireController.testBonfire)
// Unique Check API route // Unique Check API route
app.get('/api/checkUniqueUsername/:username', userController.checkUniqueUsername); app.get('/api/checkUniqueUsername/:username', userController.checkUniqueUsername);

View File

@ -15,7 +15,7 @@ exports.index = function(req, res) {
title: 'Learn to code with Bonfire' 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) { if (err) {
debug('bonfire err: ', err); debug('bonfire err: ', err);
next(err); next(err);
@ -49,8 +49,7 @@ exports.returnBonfire = function(req, res, next) {
completedWith: null, completedWith: null,
title: bonfire[bonfireNumber].name, title: bonfire[bonfireNumber].name,
name: bonfire[bonfireNumber].name, name: bonfire[bonfireNumber].name,
number: bonfire[bonfireNumber].bonfireNumber, difficulty: +bonfire[bonfireNumber].difficulty,
difficulty: bonfire[bonfireNumber].difficulty,
brief: bonfire[bonfireNumber].description[0], brief: bonfire[bonfireNumber].description[0],
details: bonfire[bonfireNumber].description.slice(1), details: bonfire[bonfireNumber].description.slice(1),
tests: bonfire[bonfireNumber].tests, tests: bonfire[bonfireNumber].tests,
@ -71,7 +70,7 @@ exports.returnIndividualBonfire = function(req, res, next) {
var bonfireNumber = parseInt(req.params.bonfireNumber) || 0; var bonfireNumber = parseInt(req.params.bonfireNumber) || 0;
if (bonfireNumber > highestBonfireNumber) { 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) { if (err) {
next(err); next(err);
} }
@ -79,8 +78,7 @@ exports.returnIndividualBonfire = function(req, res, next) {
completedWith: null, completedWith: null,
title: bonfire[bonfireNumber].name, title: bonfire[bonfireNumber].name,
name: bonfire[bonfireNumber].name, name: bonfire[bonfireNumber].name,
number: bonfire[bonfireNumber].bonfireNumber, difficulty: +bonfire[bonfireNumber].difficulty,
difficulty: bonfire[bonfireNumber].difficulty,
brief: bonfire[bonfireNumber].description[0], brief: bonfire[bonfireNumber].description[0],
details: bonfire[bonfireNumber].description.slice(1), details: bonfire[bonfireNumber].description.slice(1),
tests: bonfire[bonfireNumber].tests, tests: bonfire[bonfireNumber].tests,
@ -134,25 +132,33 @@ function randomString() {
*/ */
exports.testBonfire = function(req, res) { exports.testBonfire = function(req, res) {
// TODO: Add stuff here to parse posted variables and feed them back to bonfire playground var bonfireName = req.body.name,
var candidateTitle = req.body.bonfireInfo.title; bonfireTests = req.body.tests,
var candidateName = req.body.bonfireInfo.name; bonfireDifficulty = req.body.difficulty,
var candidateDifficulty = req.body.bonfireInfo.difficulty; bonfireDescription = req.body.description,
var candidateBrief = req.body.bonfireInfo.brief; bonfireEntryPoint = req.body.challengeEntryPoint,
var candidateDetails = req.body.bonfireInfo.details; bonfireChallengeSeed = req.body.challengeSeed;
var candidateTests = req.body.bonfireInfo.tests; bonfireTests = bonfireTests.split('\r\n');
var candidateChallengeSeed = req.body.bonfireInfo.challengeSeed; bonfireDescription = bonfireDescription.split('\r\n');
var candidateChallengeEntryPoint = req.body.bonfireInfo.challengeSeed; bonfireTests.filter(getRidOfEmpties);
res.render('bonfire/bonfire', { bonfireDescription.filter(getRidOfEmpties);
title: candidateTitle, bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', '');
name: candidateName, res.render('bonfire/show', {
difficulty: candidateDifficulty, completedWith: null,
brief: candidateBrief, title: bonfireName,
details: candidateDetails, difficulty: +bonfireDifficulty,
tests: candidateTests, brief: bonfireDescription[0],
challengeSeed: candidateChallengeSeed, details: bonfireDescription.slice(1),
challengeEntryPoint: candidateChallengeEntryPoint, tests: bonfireTests,
bonfireHash: bonfire[bonfireNumber]._id 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) { exports.generateChallenge = function(req, res) {
var bonfireName = req.body.name, var bonfireName = req.body.name,
bonfireTests = req.body.tests, bonfireTests = req.body.tests,
@ -177,14 +187,13 @@ exports.generateChallenge = function(req, res) {
var response = { var response = {
_id: randomString(),
name: bonfireName, name: bonfireName,
tests: bonfireTests,
difficulty: bonfireDifficulty, difficulty: bonfireDifficulty,
description: bonfireDescription, description: bonfireDescription,
challengeEntryPoint: bonfireEntryPoint, challengeEntryPoint: bonfireEntryPoint,
challengeSeed: bonfireChallengeSeed, challengeSeed: bonfireChallengeSeed,
bonfireNumber: 0, tests: bonfireTests
_id: randomString()
}; };
res.send(response); res.send(response);
} }

View File

@ -12,14 +12,12 @@ var bonfireSchema = new mongoose.Schema({
type: String, type: String,
unique: true unique: true
}, },
difficulty: Number, difficulty: String,
description: Array, description: Array,
tests: Array, tests: Array,
challengeSeed: String, challengeSeed: String,
bonfireNumber: Number,
challengeEntryPoint: String, challengeEntryPoint: String,
challengeEntryPointNegate: String challengeEntryPointNegate: String
}); });
module.exports = mongoose.model('Bonfire', bonfireSchema); module.exports = mongoose.model('Bonfire', bonfireSchema);

View File

@ -216,7 +216,8 @@ var runTests = function(err, data) {
userTests.forEach(function(test, ix, arr){ userTests.forEach(function(test, ix, arr){
try { try {
if (test) { if (test) {
var output = eval(reassembleTest(test, data)); var test = JSON.stringify(reassembleTest(test, data));
var output = eval(test);
} }
} catch(error) { } catch(error) {
allTestsPassed = false; allTestsPassed = false;

View File

@ -2,7 +2,7 @@
{ {
"_id" : "7123c8c441eddfaeb5bdef0d", "_id" : "7123c8c441eddfaeb5bdef0d",
"name": "Meet Bonfire", "name": "Meet Bonfire",
"difficulty": 1, "difficulty": "0",
"description": [ "description": [
"Click the button below for further instructions.", "Click the button below for further instructions.",
"Your goal is to fix the failing test.", "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", "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!\");", "challengeEntryPoint": "meetBonfire(\"You can do this!\");",
"bonfireNumber": 0
}, },
{ {
"_id" : "aaa48de84e1ecc7c742e1124", "_id" : "aaa48de84e1ecc7c742e1124",
"name": "Check for Palindromes", "name": "Check for Palindromes",
"difficulty": 1, "difficulty": "1",
"description": [ "description": [
"Return 'true' if a given string is a palindrome.", "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.", "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", "challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n",
"challengeEntryPoint": "palindrome(\"eye\");", "challengeEntryPoint": "palindrome(\"eye\");",
"bonfireNumber": 1
}, },
{ {
"_id" : "ff0395860f5d3034dc0bfc94", "_id" : "ff0395860f5d3034dc0bfc94",
"name": "Validate US Telephone Numbers", "name": "Validate US Telephone Numbers",
"difficulty": 3, "difficulty": "3",
"description": [ "description": [
"Return true if the passed string is a valid US phone number", "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:", "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", "challengeSeed": "function telephoneCheck(str) {\n // Good luck!\n return true;\n}\n\n",
"challengeEntryPoint": "telephoneCheck(\"555-555-5555\");", "challengeEntryPoint": "telephoneCheck(\"555-555-5555\");",
"bonfireNumber": 2
}, },
{ {
"_id": "202eed8fc186c8434cb6d618",
"name": "Reverse a String", "name": "Reverse a String",
"difficulty": "1",
"tests": [ "tests": [
"expect(reverseString('hello')).to.be.a('String');", "expect(reverseString('hello')).to.be.a('String');",
"expect(reverseString('hello')).to.equal('olleh');", "expect(reverseString('hello')).to.equal('olleh');",
"expect(reverseString('Howdy')).to.equal('ydwoH');", "expect(reverseString('Howdy')).to.equal('ydwoH');",
"expect(reverseString('Greetings from Earth')).to.equal('htraE morf sgniteerG');" "expect(reverseString('Greetings from Earth')).to.equal('htraE morf sgniteerG');"
], ],
"difficulty": "1",
"description": [ "description": [
"Reverse the provided string. ", "Reverse the provided string.",
"You may need to turn the string into an array before you can reverse it.", "You may need to turn the string into an array before you can reverse it.",
"Your result must be a string." "Your result must be a string."
], ],
"challengeEntryPoint": "reverseString('hello');", "challengeEntryPoint": "reverseString('hello');",
"challengeSeed": "function reverseString(str) {\n return str;\r\n}", "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\");"
]
}
] ]

View File

@ -15,6 +15,12 @@ block content
script(src='/js/lib/jailed/jailed.js') script(src='/js/lib/jailed/jailed.js')
script(src='/js/lib/bonfire/bonfireInit.js') script(src='/js/lib/bonfire/bonfireInit.js')
.row .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 #mainEditorPanel.col-sm-12.col-md-7.col-xs-12
.panel.panel-primary.panel-bonfire .panel.panel-primary.panel-bonfire
.panel-heading.text-center Playground .panel-heading.text-center Playground

View File

@ -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")