Feature(challenges): add code-uri utils

Fix(nav): points nav item propTypes
This commit is contained in:
Berkeley Martinez
2016-08-14 23:22:34 -07:00
parent 5fb2802e32
commit 3f3aab3ff7
4 changed files with 117 additions and 32 deletions

64
client/utils/code-uri.js Normal file
View File

@ -0,0 +1,64 @@
import flow from 'lodash/flow';
import { decodeFcc } from '../../common/utils/encode-decode';
const queryRegex = /^(\?|#\?)/;
export function legacyIsInQuery(query, decode) {
let decoded;
try {
decoded = decode(query);
} catch (err) {
return false;
}
if (!decoded || typeof decoded.split !== 'function') {
return false;
}
return decoded
.replace(queryRegex, '')
.split('&')
.reduce(function(found, param) {
var key = param.split('=')[0];
if (key === 'solution') {
return true;
}
return found;
}, false);
}
export function getKeyInQuery(query, keyToFind = '') {
return query
.split('&')
.reduce((oldValue, param) => {
const key = param.split('=')[0];
const value = param
.split('=')
.slice(1)
.join('=');
if (key === keyToFind) {
return value;
}
return oldValue;
}, null);
}
export function getLegacySolutionFromQuery(query = '', decode) {
return flow(
getKeyInQuery,
decode,
decodeFcc
)(query, 'solution');
}
export function getCodeUri({ location, decodeURIComponent }) {
let query;
if (
location.search &&
legacyIsInQuery(location.search, decodeURIComponent)
) {
query = location.search.replace(/^\?/, '');
} else {
return null;
}
return getLegacySolutionFromQuery(query, decodeURIComponent);
}

View File

@ -7,8 +7,8 @@ export default React.createClass({
'aria-controls': React.PropTypes.string,
className: React.PropTypes.string,
href: React.PropTypes.string,
onClick: React.PropTypes.func.isRequired,
points: React.PropTypes.func,
onClick: React.PropTypes.func,
points: React.PropTypes.number,
title: React.PropTypes.node
},

View File

@ -1,42 +1,17 @@
import { compose } from 'redux';
import flow from 'lodash/flow';
import { bonfire, html, js } from '../../utils/challengeTypes';
import { decodeScriptTags } from '../../../utils/encode-decode';
import protect from '../../utils/empty-protector';
export function encodeScriptTags(value) {
return value
.replace(/<script>/gi, 'fccss')
.replace(/<\/script>/gi, 'fcces');
}
export function decodeSafeTags(value) {
return value
.replace(/fccss/gi, '<script>')
.replace(/fcces/gi, '</script>');
}
export function encodeFormAction(value) {
return value.replace(
/<form[^>]*>/,
val => val.replace(/action(\s*?)=/, 'fccfaa$1=')
);
}
export function decodeFccfaaAttr(value) {
return value.replace(
/<form[^>]*>/,
val => val.replace(/fccfaa(\s*?)=/, 'action$1=')
);
}
export function arrayToString(seedData = ['']) {
seedData = Array.isArray(seedData) ? seedData : [seedData];
return seedData.reduce((seed, line) => '' + seed + line + '\n', '\n');
}
export function buildSeed({ challengeSeed = [] } = {}) {
return compose(
decodeSafeTags,
arrayToString
return flow(
arrayToString,
decodeScriptTags
)(challengeSeed);
}

View File

@ -0,0 +1,46 @@
import flow from 'lodash/flow';
// we don't store loop protect disable key
export function removeNoprotect(val) {
return val.replace(/noprotect/gi, '');
}
export function encodeScriptTags(val) {
return val
.replace(/<script>/gi, 'fccss')
.replace(/<\/script>/gi, 'fcces');
}
export function decodeScriptTags(val) {
return val
.replace(/fccss/gi, '<script>')
.replace(/fcces/gi, '</script>');
}
export function encodeFormAction(val) {
return val.replace(
// look for attributes in a form
/<form[^>]*>/,
// val is the string within the opening form tag
// look for an `action` attribute, replace it with a fcc tag
val => val.replace(/action(\s*?)=/, 'fccfaa$1=')
);
}
export function decodeFormAction(val) {
return val.replace(
/<form[^>]*>/,
val => val.replace(/fccfaa(\s*?)=/, 'action$1=')
);
}
export const encodeFcc = flow([
removeNoprotect,
encodeFormAction,
encodeScriptTags
]);
export const decodeFcc = flow([
decodeFormAction,
decodeScriptTags
]);