Add certification page
parent
d9332e7d03
commit
8c48626f03
|
@ -865,14 +865,53 @@ common.init.push((function() {
|
|||
}
|
||||
next();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function handleActionClick() {
|
||||
$(this)
|
||||
.parent()
|
||||
.find('.disabled')
|
||||
.removeClass('disabled');
|
||||
function handleActionClick(e) {
|
||||
var props = common.challengeSeed[0] ||
|
||||
{ stepIndex: [] };
|
||||
|
||||
var $el = $(this);
|
||||
var index = +$el.attr('id');
|
||||
var propIndex = props.stepIndex.indexOf(index);
|
||||
|
||||
if (propIndex === -1) {
|
||||
return $el
|
||||
.parent()
|
||||
.find('.disabled')
|
||||
.removeClass('disabled');
|
||||
}
|
||||
|
||||
// an API action
|
||||
// prevent link from opening
|
||||
e.preventDefault();
|
||||
var prop = props.properties[propIndex];
|
||||
var api = props.apis[propIndex];
|
||||
if (common[prop]) {
|
||||
return $el
|
||||
.parent()
|
||||
.find('.disabled')
|
||||
.removeClass('disabled');
|
||||
}
|
||||
$
|
||||
.post(api)
|
||||
.done(function(data) {
|
||||
// assume a boolean indicates passing
|
||||
if (typeof data === 'boolean') {
|
||||
return $el
|
||||
.parent()
|
||||
.find('.disabled')
|
||||
.removeClass('disabled');
|
||||
}
|
||||
// assume api returns string when fails
|
||||
$el
|
||||
.parent()
|
||||
.find('.disabled')
|
||||
.replaceWith('<p>' + data + '</p>');
|
||||
})
|
||||
.fail(function() {
|
||||
console.log('failed');
|
||||
});
|
||||
}
|
||||
|
||||
function handleFinishClick(e) {
|
||||
|
|
|
@ -102,14 +102,31 @@
|
|||
},
|
||||
"isLocked": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
"default": false,
|
||||
"description": "Campers profile does not show challenges to the public"
|
||||
},
|
||||
"currentChallenge": {
|
||||
"type": {}
|
||||
},
|
||||
"isUniqMigrated": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
"default": false,
|
||||
"description": "Campers completedChallenges array is free of duplicates"
|
||||
},
|
||||
"isHonest": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Camper has signed academic honesty policy"
|
||||
},
|
||||
"isFrontEndCert": {
|
||||
"type": "boolean",
|
||||
"defaut": false,
|
||||
"description": "Camper is front end certified"
|
||||
},
|
||||
"isFullStackCert": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Campers is full stack certified"
|
||||
},
|
||||
"completedChallenges": {
|
||||
"type": [
|
||||
|
|
Binary file not shown.
|
@ -5,14 +5,25 @@
|
|||
{
|
||||
"id": "561add10cb82ac38a17513be",
|
||||
"title": "Claim Your Front End Development Certificate",
|
||||
"difficulty": 0.00,
|
||||
"challengeSeed": [],
|
||||
"challengeSeed": [
|
||||
{
|
||||
"properties": ["isHonest", "isFrontEndCert"],
|
||||
"apis": ["/certificate/honest", "/certificate/verify/front-end"],
|
||||
"stepIndex": [0, 1]
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
[
|
||||
"http://i.imgur.com/RlEk2IF.jpg",
|
||||
"a picture of Free Code Camp's 4 benefits: Get connected, Learn JavaScript, Build your Portfolio, Help nonprofits",
|
||||
"Welcome to Free Code Camp. We're an open source community of busy people who learn to code and help nonprofits.",
|
||||
""
|
||||
"#"
|
||||
],
|
||||
[
|
||||
"http://i.imgur.com/RlEk2IF.jpg",
|
||||
"a picture of Free Code Camp's 4 benefits: Get connected, Learn JavaScript, Build your Portfolio, Help nonprofits",
|
||||
"Welcome to Free Code Camp. We're an open source community of busy people who learn to code and help nonprofits.",
|
||||
"#"
|
||||
]
|
||||
],
|
||||
"type": "Waypoint",
|
||||
|
|
|
@ -6,13 +6,25 @@
|
|||
"id": "660add10cb82ac38a17513be",
|
||||
"title": "Claim Your Full Stack Development Certificate",
|
||||
"difficulty": 0.00,
|
||||
"challengeSeed": [],
|
||||
"challengeSeed": [
|
||||
{
|
||||
"properties": ["isHonest", "isFullStackCert"],
|
||||
"apis": ["/certificate/honest", "/certificate/verify/full-stack"],
|
||||
"stepIndex": [0, 1]
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
[
|
||||
"http://i.imgur.com/RlEk2IF.jpg",
|
||||
"a picture of Free Code Camp's 4 benefits: Get connected, Learn JavaScript, Build your Portfolio, Help nonprofits",
|
||||
"Welcome to Free Code Camp. We're an open source community of busy people who learn to code and help nonprofits.",
|
||||
""
|
||||
"#"
|
||||
],
|
||||
[
|
||||
"http://i.imgur.com/RlEk2IF.jpg",
|
||||
"a picture of Free Code Camp's 4 benefits: Get connected, Learn JavaScript, Build your Portfolio, Help nonprofits",
|
||||
"Welcome to Free Code Camp. We're an open source community of busy people who learn to code and help nonprofits.",
|
||||
"#"
|
||||
]
|
||||
],
|
||||
"type": "Waypoint",
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
import _ from 'lodash';
|
||||
import dedent from 'dedent';
|
||||
import { Observable } from 'rx';
|
||||
import debugFactory from 'debug';
|
||||
|
||||
import {
|
||||
ifNoUser401,
|
||||
ifNoUserSend
|
||||
} from '../utils/middleware';
|
||||
|
||||
import {
|
||||
saveUser,
|
||||
observeQuery
|
||||
} from '../utils/rx';
|
||||
|
||||
const frontEndChallangeId = '561add10cb82ac38a17513be';
|
||||
const fullStackChallangeId = '660add10cb82ac38a17513be';
|
||||
const debug = debugFactory('freecc:certification');
|
||||
const sendMessageToNonUser = ifNoUserSend(
|
||||
'must be logged in to complete.'
|
||||
);
|
||||
|
||||
function isCertified(frontEndIds, { completedChallenges, isFrontEndCert }) {
|
||||
if (isFrontEndCert) {
|
||||
return true;
|
||||
}
|
||||
return _.every(frontEndIds, ({ id }) => _.some(completedChallenges, { id }));
|
||||
}
|
||||
|
||||
export default function certificate(app) {
|
||||
const router = app.loopback.Router();
|
||||
const { Challenge } = app.models;
|
||||
|
||||
const frontEndChallangeIds$ = observeQuery(
|
||||
Challenge,
|
||||
'findById',
|
||||
frontEndChallangeId,
|
||||
{
|
||||
tests: true
|
||||
}
|
||||
)
|
||||
.map(({ tests = [] }) => tests)
|
||||
.shareReplay();
|
||||
|
||||
const fullStackChallangeIds$ = observeQuery(
|
||||
Challenge,
|
||||
'findById',
|
||||
fullStackChallangeId,
|
||||
{
|
||||
tests: true
|
||||
}
|
||||
)
|
||||
.map(({ tests = [] }) => tests)
|
||||
.shareReplay();
|
||||
|
||||
router.post(
|
||||
'/certificate/verify/front-end',
|
||||
ifNoUser401,
|
||||
verifyCert
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/certificate/verify/full-stack',
|
||||
ifNoUser401,
|
||||
verifyCert
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/certificate/honest',
|
||||
sendMessageToNonUser,
|
||||
postHonest
|
||||
);
|
||||
|
||||
app.use(router);
|
||||
|
||||
function verifyCert(req, res, next) {
|
||||
const isFront = req.path.split('/').pop() === 'front-end';
|
||||
Observable.just({})
|
||||
.flatMap(() => {
|
||||
if (isFront) {
|
||||
return frontEndChallangeIds$;
|
||||
}
|
||||
return fullStackChallangeIds$;
|
||||
})
|
||||
.flatMap((tests) => {
|
||||
const { user } = req;
|
||||
if (
|
||||
isFront && !user.isFrontEndCert && isCertified(tests, user) ||
|
||||
!isFront && !user.isFullStackCert && isCertified(tests, user)
|
||||
) {
|
||||
debug('certified');
|
||||
if (isFront) {
|
||||
user.isFrontEndCert = true;
|
||||
} else {
|
||||
user.isFullStackCert = true;
|
||||
}
|
||||
return saveUser(user);
|
||||
}
|
||||
return Observable.just(user);
|
||||
})
|
||||
.subscribe(
|
||||
user => {
|
||||
if (
|
||||
isFront && user.isFrontEndCert ||
|
||||
!isFront && user.isFullStackCert
|
||||
) {
|
||||
return res.status(200).send(true);
|
||||
}
|
||||
return res.status(200).send(
|
||||
dedent`
|
||||
Looks like you have not completed the neccessary steps,
|
||||
Please return the map
|
||||
`
|
||||
);
|
||||
},
|
||||
next
|
||||
);
|
||||
}
|
||||
|
||||
function postHonest(req, res, next) {
|
||||
const { user } = req;
|
||||
user.isHonest = true;
|
||||
saveUser(user)
|
||||
.subscribe(
|
||||
(user) => {
|
||||
res.status(200).send(!!user.isHonest);
|
||||
},
|
||||
next
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,11 +9,10 @@ import utils from '../utils';
|
|||
import {
|
||||
saveUser,
|
||||
observeMethod,
|
||||
observableQueryFromModel
|
||||
observeQuery
|
||||
} from '../utils/rx';
|
||||
|
||||
import {
|
||||
userMigration,
|
||||
ifNoUserSend
|
||||
} from '../utils/middleware';
|
||||
|
||||
|
@ -147,8 +146,6 @@ module.exports = function(app) {
|
|||
completedBonfire
|
||||
);
|
||||
|
||||
// the follow routes are covered by userMigration
|
||||
router.use(userMigration);
|
||||
router.get('/map', challengeMap);
|
||||
router.get(
|
||||
'/challenges/next-challenge',
|
||||
|
@ -330,7 +327,7 @@ module.exports = function(app) {
|
|||
challengeType: 5
|
||||
};
|
||||
|
||||
observableQueryFromModel(
|
||||
observeQuery(
|
||||
User,
|
||||
'findOne',
|
||||
{ where: { username: ('' + completedWith).toLowerCase() } }
|
||||
|
@ -458,7 +455,7 @@ module.exports = function(app) {
|
|||
verified: false
|
||||
};
|
||||
|
||||
observableQueryFromModel(
|
||||
observeQuery(
|
||||
User,
|
||||
'findOne',
|
||||
{ where: { username: completedWith.toLowerCase() } }
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import _ from 'lodash';
|
||||
import dedent from 'dedent';
|
||||
import moment from 'moment';
|
||||
import { Observable } from 'rx';
|
||||
import debugFactory from 'debug';
|
||||
|
||||
import { ifNoUser401, ifNoUserRedirectTo } from '../utils/middleware';
|
||||
import { observeQuery } from '../utils/rx';
|
||||
|
||||
const debug = debugFactory('freecc:boot:user');
|
||||
const daysBetween = 1.5;
|
||||
|
@ -52,7 +55,16 @@ function dayDiff([head, tail]) {
|
|||
module.exports = function(app) {
|
||||
var router = app.loopback.Router();
|
||||
var User = app.models.User;
|
||||
// var Story = app.models.Story;
|
||||
function findUserByUsername$(username, fields) {
|
||||
return observeQuery(
|
||||
User,
|
||||
'findOne',
|
||||
{
|
||||
where: { username },
|
||||
fields
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
router.get('/login', function(req, res) {
|
||||
res.redirect(301, '/signin');
|
||||
|
@ -85,7 +97,18 @@ module.exports = function(app) {
|
|||
);
|
||||
router.get('/vote1', vote1);
|
||||
router.get('/vote2', vote2);
|
||||
// Ensure this is the last route!
|
||||
|
||||
// Ensure these are the last routes!
|
||||
router.get(
|
||||
'/:username/front-end-certification',
|
||||
showCert
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/:username/full-stack-certification',
|
||||
showCert
|
||||
);
|
||||
|
||||
router.get('/:username', returnUser);
|
||||
|
||||
app.use(router);
|
||||
|
@ -184,14 +207,20 @@ module.exports = function(app) {
|
|||
return (obj.name || '').match(/^Waypoint/i);
|
||||
});
|
||||
|
||||
debug('user is fec', profileUser.isFrontEndCert);
|
||||
res.render('account/show', {
|
||||
title: 'Camper ' + profileUser.username + '\'s portfolio',
|
||||
username: profileUser.username,
|
||||
name: profileUser.name,
|
||||
|
||||
isMigrationGrandfathered: profileUser.isMigrationGrandfathered,
|
||||
isGithubCool: profileUser.isGithubCool,
|
||||
isLocked: !!profileUser.isLocked,
|
||||
|
||||
isFrontEndCert: profileUser.isFrontEndCert,
|
||||
isFullStackCert: profileUser.isFullStackCert,
|
||||
isHonest: profileUser.isHonest,
|
||||
|
||||
location: profileUser.location,
|
||||
calender: data,
|
||||
|
||||
|
@ -216,6 +245,62 @@ module.exports = function(app) {
|
|||
);
|
||||
}
|
||||
|
||||
function showCert(req, res, next) {
|
||||
const username = req.params.username.toLowerCase();
|
||||
const { user } = req;
|
||||
const showFront = req.path.split('/').pop() === 'front-end-certification';
|
||||
Observable.just(user)
|
||||
.flatMap(user => {
|
||||
if (user && user.username === username) {
|
||||
return Observable.just(user);
|
||||
}
|
||||
return findUserByUsername$(username, {
|
||||
isFrontEndCert: true,
|
||||
isFullStackCert: true,
|
||||
completedChallenges: true,
|
||||
username: true,
|
||||
name: true
|
||||
});
|
||||
})
|
||||
.subscribe(
|
||||
(user) => {
|
||||
if (!user) {
|
||||
req.flash('errors', {
|
||||
msg: `404: We couldn't find the user ${username}`
|
||||
});
|
||||
return res.redirect('/');
|
||||
}
|
||||
if (
|
||||
showFront && user.isFrontEndCert ||
|
||||
!showFront && user.isFullStackCert
|
||||
) {
|
||||
var { completedDate } = _.find(user.completedChallenges, {
|
||||
id: '561add10cb82ac38a17513be'
|
||||
});
|
||||
|
||||
return res.render(
|
||||
showFront ?
|
||||
'certificate/front-end.jade' :
|
||||
'certificate/full-stack.jade',
|
||||
{
|
||||
username: user.username,
|
||||
date: moment(new Date(completedDate))
|
||||
.format('MMMM, Do YYYY'),
|
||||
name: user.name
|
||||
}
|
||||
);
|
||||
}
|
||||
req.flash('errors', {
|
||||
msg: showFront ?
|
||||
`Looks like user ${username} is not Front End certified` :
|
||||
`Looks like user ${username} is not Full Stack certified`
|
||||
});
|
||||
res.redirect('/map');
|
||||
},
|
||||
next
|
||||
);
|
||||
}
|
||||
|
||||
function toggleLockdownMode(req, res, next) {
|
||||
if (req.user.isLocked === true) {
|
||||
req.user.isLocked = false;
|
||||
|
@ -297,11 +382,6 @@ module.exports = function(app) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /forgot
|
||||
* Create a random token, then the send user an email with a reset link.
|
||||
*/
|
||||
|
||||
function postForgot(req, res) {
|
||||
const errors = req.validationErrors();
|
||||
const email = req.body.email.toLowerCase();
|
||||
|
|
|
@ -1,60 +1,24 @@
|
|||
var R = require('ramda');
|
||||
|
||||
/*
|
||||
* Middleware to migrate users from fragmented challenge structure to unified
|
||||
* challenge structure
|
||||
*
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns null
|
||||
*/
|
||||
exports.userMigration = function userMigration(req, res, next) {
|
||||
if (!req.user || req.user.completedChallenges.length !== 0) {
|
||||
return next();
|
||||
}
|
||||
req.user.completedChallenges = R.filter(function(elem) {
|
||||
// getting rid of undefined
|
||||
return elem;
|
||||
}, R.concat(
|
||||
req.user.completedCoursewares,
|
||||
req.user.completedBonfires.map(function(bonfire) {
|
||||
return ({
|
||||
completedDate: bonfire.completedDate,
|
||||
id: bonfire.id,
|
||||
name: bonfire.name,
|
||||
completedWith: bonfire.completedWith,
|
||||
solution: bonfire.solution,
|
||||
githubLink: '',
|
||||
verified: false,
|
||||
challengeType: 5
|
||||
});
|
||||
})
|
||||
)
|
||||
);
|
||||
return next();
|
||||
};
|
||||
|
||||
exports.ifNoUserRedirectTo = function ifNoUserRedirectTo(url) {
|
||||
export function ifNoUserRedirectTo(url) {
|
||||
return function(req, res, next) {
|
||||
if (req.user) {
|
||||
return next();
|
||||
}
|
||||
return res.redirect(url);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
exports.ifNoUserSend = function ifNoUserSend(sendThis) {
|
||||
export function ifNoUserSend(sendThis) {
|
||||
return function(req, res, next) {
|
||||
if (req.user) {
|
||||
return next();
|
||||
}
|
||||
return res.status(200).send(sendThis);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
exports.ifNoUser401 = function ifNoUser401(req, res, next) {
|
||||
export function ifNoUser401(req, res, next) {
|
||||
if (req.user) {
|
||||
return next();
|
||||
}
|
||||
return res.status(401).end();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
var Rx = require('rx');
|
||||
var debug = require('debug')('freecc:rxUtils');
|
||||
import Rx from 'rx';
|
||||
import debugFactory from 'debug';
|
||||
|
||||
exports.saveInstance = function saveInstance(instance) {
|
||||
const debug = debugFactory('freecc:rxUtils');
|
||||
|
||||
export function saveInstance(instance) {
|
||||
return new Rx.Observable.create(function(observer) {
|
||||
if (!instance || typeof instance.save !== 'function') {
|
||||
debug('no instance or save method');
|
||||
|
@ -17,16 +19,15 @@ exports.saveInstance = function saveInstance(instance) {
|
|||
observer.onCompleted();
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// alias saveInstance
|
||||
exports.saveUser = exports.saveInstance;
|
||||
export const saveUser = saveInstance;
|
||||
|
||||
exports.observeQuery = exports.observableQueryFromModel =
|
||||
function observableQueryFromModel(Model, method, query) {
|
||||
return Rx.Observable.fromNodeCallback(Model[method], Model)(query);
|
||||
};
|
||||
export function observeQuery(Model, method, query) {
|
||||
return Rx.Observable.fromNodeCallback(Model[method], Model)(query);
|
||||
}
|
||||
|
||||
exports.observeMethod = function observeMethod(context, methodName) {
|
||||
export function observeMethod(context, methodName) {
|
||||
return Rx.Observable.fromNodeCallback(context[methodName], context);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -58,8 +58,13 @@ block content
|
|||
h1.flat-top.wrappable= name
|
||||
h1.flat-top.wrappable= location
|
||||
h1.flat-top.text-primary= "[ " + (progressTimestamps.length) + " ]"
|
||||
if isFrontEndCert
|
||||
a.btn.btn-primary(href='/' + username + '/front-end-certification') View My Front End Development Certification
|
||||
if isFullStackCert
|
||||
.button-spacer
|
||||
a.btn.btn-success(href='/' + username + '/full-stack-certification') View My Full Stack Development Certification
|
||||
if (user && user.username !== username)
|
||||
a.btn.btn-lg.btn-block.btn-twitter.btn-link-social(href='/link/twitter')
|
||||
a.btn.btn-lg.btn-block.btn-twitter.btn-link-social(href='/leaderboard/add?username=#{username}')
|
||||
i.fa.fa-plus-square
|
||||
| Add them to my personal leaderboard
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
style.
|
||||
@font-face {
|
||||
font-family: "Sax Mono";
|
||||
src: url("/fonts/saxmono.ttf") format("truetype");
|
||||
}
|
||||
|
||||
body {
|
||||
display: inline-block;
|
||||
font-family: "Sax Mono", monospace;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.img-abs {
|
||||
left 0;
|
||||
position: relative;
|
||||
top: 0;
|
||||
width: 2000px
|
||||
}
|
||||
|
||||
.cert-name {
|
||||
font-size: 64px;
|
||||
left: 1000px;
|
||||
position: absolute;
|
||||
top: 704px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.cert-date {
|
||||
font-size: 60px;
|
||||
left: 760px;
|
||||
position: absolute;
|
||||
top: 1004.8px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.cert-link {
|
||||
font-size: 22px;
|
||||
left: 120px;
|
||||
position: absolute;
|
||||
top: 1488px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
include font
|
||||
#name.cert-name= name
|
||||
img#cert.img-abs(src='http://i.imgur.com/ToFZKBd.jpg')
|
||||
.cert-date= date
|
||||
.cert-link verify this certification at: http://freecodecamp.com/#{username}/front-end-certification
|
||||
include script
|
|
@ -0,0 +1,6 @@
|
|||
include font
|
||||
#name.cert-name= name
|
||||
img#cert.img-abs(src='http://i.imgur.com/Z4PgjBQ.jpg')
|
||||
.cert-date= date
|
||||
.cert-link verify this certification at: http://freecodecamp.com/#{username}/full-stack-certification
|
||||
include script
|
|
@ -0,0 +1,7 @@
|
|||
extends ../layout
|
||||
block content
|
||||
.panel.panel-info
|
||||
.panel-heading.text-center
|
||||
h1 Certificate
|
||||
.panel-body
|
||||
p foo
|
|
@ -0,0 +1,8 @@
|
|||
script.
|
||||
(function() {
|
||||
var containerWidth = document.getElementById('cert').offsetWidth;
|
||||
var nameDiv = document.getElementById('name');
|
||||
var nameWidth = nameDiv.offsetWidth;
|
||||
console.log(containerWidth, nameWidth);
|
||||
nameDiv.style.left = ((containerWidth - nameWidth) / 2) + 15;
|
||||
})();
|
|
@ -9,7 +9,7 @@ block content
|
|||
.caption
|
||||
p.large-p= step[2]
|
||||
if step[3]
|
||||
a.btn.btn-block.btn-primary.challenge-step-btn-action(href='#{step[3]}' target='_blank') Go To Link
|
||||
a.btn.btn-block.btn-primary.challenge-step-btn-action(id='#{index}' href='#{step[3]}' target='_blank') Go To Link
|
||||
if index + 1 === description.length
|
||||
.btn.btn-block.btn-primary.challenge-step-btn-finish(id='last' class=step[3] ? 'disabled' : '') Finish challenge
|
||||
else
|
||||
|
@ -32,8 +32,12 @@ block content
|
|||
a.btn.btn-lg.btn-primary.btn-block(href='/challenges/next-challenge?id=' + challengeId) Go to my next challenge
|
||||
script(src=rev('/js', 'commonFramework.js'))
|
||||
script.
|
||||
var common = common || { init: [] };
|
||||
var common = window.common || { init: [] };
|
||||
common.challengeId = !{JSON.stringify(challengeId)};
|
||||
common.challengeName = !{JSON.stringify(name)};
|
||||
common.challengeType = 7;
|
||||
common.dashedName = !{JSON.stringify(dashedName || '')};
|
||||
common.isHonest = !{JSON.stringify(isHonest || false)};
|
||||
common.isFrontEndCert = !{JSON.stringify(isFrontEndCert || false)};
|
||||
common.isFullStackCert = !{JSON.stringify(isFullStackCert || false)};
|
||||
common.challengeSeed = !{JSON.stringify(challengeSeed || [])};
|
||||
|
|
Loading…
Reference in New Issue