Skip to content

Commit

Permalink
chore: update layout, api, web and dev setup (#381)
Browse files Browse the repository at this point in the history
  • Loading branch information
shaunwarman authored Apr 18, 2020
1 parent 823d70d commit 27df169
Show file tree
Hide file tree
Showing 13 changed files with 376 additions and 540 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"is-valid-npm-name": "^0.0.5",
"npm-conf": "^1.1.3",
"sao": "0.x",
"semver": "^7.1.3",
"semver": "^7.3.2",
"speakingurl": "^14.0.1",
"superb": "^4.0.0",
"update-notifier": "^4.1.0",
Expand All @@ -48,8 +48,8 @@
"eslint-config-xo-lass": "^1.0.3",
"eslint-plugin-compat": "^3.5.1",
"husky": "^3.1.0",
"lint-staged": "^10.1.1",
"nyc": "^15.0.0",
"lint-staged": "^10.1.3",
"nyc": "^15.0.1",
"remark-cli": "^8.0.0",
"remark-preset-github": "^1.0.0",
"supertest": "^4.0.2",
Expand Down
58 changes: 35 additions & 23 deletions template/app/views/layout.pug
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,28 @@ html(lang=locale).h-100

//- css file
block stylesheets
link(rel="stylesheet", href=manifest('css/app.css'))
if config.env === 'production'
link(rel="stylesheet", href=manifest('css/app.css') integrity=manifest('css/app.css', 'integrity'))
else
link(rel="stylesheet", href=manifest('css/app.css'))

body(role='document', class=['/register', '/login', config.verifyRoute].includes(ctx.pathWithoutLocale) ? 'pt-0' : '').d-flex.flex-column.h-100

//- spinner
block spinner
include spinner/spinner

//- navigation
block navigation
include _nav

//- body
main(role='main').flex-shrink-0
block body

//- footer
block footer
include _footer

block scripts
//- flash messaging (with koa-better-flash and sweetalert2)
Expand Down Expand Up @@ -102,31 +123,22 @@ html(lang=locale).h-100
};

//- polyfill environment
script(defer, src=`https://polyfill.io/v3/polyfill${config.env === 'production' ? '.min' : ''}.js?features=${polyfills.join(',')}`)
script(src=`https://polyfill.io/v3/polyfill${config.env === 'production' ? '.min' : ''}.js?features=${polyfills.join(',')}`)

//- factor bundle (common shared assets across all files)
script(defer, src=manifest('js/factor-bundle.js'))
if config.env === 'production'
script(src=manifest('factor-bundle.js') integrity=manifest('factor-bundle.js', 'integrity'))
else
script(src=manifest('factor-bundle.js'))

//- uncaught (handles errors, similar to TraceKit but with CabinJS + StackTrace.JS)
script(defer, src=manifest('js/uncaught.js'))
if config.env === 'production'
script(src=manifest('uncaught.js') integrity=manifest('uncaught.js', 'integrity'))
else
script(src=manifest('uncaught.js'))

//- scripts
script(defer, src=manifest('js/core.js'))

body(role='document', class=['/register', '/login', config.verifyRoute].includes(ctx.pathWithoutLocale) ? 'pt-0' : '').d-flex.flex-column.h-100

//- spinner
block spinner
include spinner/spinner

//- navigation
block navigation
include _nav

//- body
main(role='main').flex-shrink-0
block body

//- footer
block footer
include _footer
if config.env === 'production'
script(src=manifest('core.js') integrity=manifest('core.js', 'integrity'))
else
script(src=manifest('core.js'))
45 changes: 30 additions & 15 deletions template/app/views/my-account/security.pug
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,19 @@ block body
input(type="hidden", name="_csrf", value=ctx.csrf)
button(type='submit').btn.btn-primary.btn-block
i.fa.fa-download
= t(' Download')
= ' '
= t('Download')
.col-sm.offset-sm-1
button(type='button', data-toggle="clipboard", data-clipboard-target="#two-factor-recovery-keys").btn.btn-secondary.btn-block
i.fa.fa-clipboard
= t(' Copy')
= ' '
= t('Copy')
.modal-footer
p.text-muted.text-center.font-weight-bold: small= t('Store these in a safe place; they will let you recover your account, if necessary.')
button(data-toggle='modal', data-target='#modal-enable-2fa-verify', data-dismiss='modal', type='button').btn.btn-primary.btn-lg.float-right= t('Continue')
.form-check
input#recovery-keys-stored(type='checkbox', name="recovery-keys-stored", value='true' data-toggle='collapse' data-target='#recovery-key-submit')
label(for='recovery-keys-stored')= t('I have stored these recovery keys in a safe place')
#recovery-key-submit.collapse
button(data-toggle='modal', data-target='#modal-enable-2fa-verify', data-dismiss='modal', type='button').btn.btn-primary.btn-lg.float-right= t('Continue')
#modal-enable-2fa-verify(tabindex='-1', role='dialog').modal.fade
.modal-dialog(role='document')
.modal-content
Expand All @@ -44,22 +49,32 @@ block body
.modal-body
form(action=l('/my-account/setup-2fa'), method='POST').ajax-form.confirm-prompt
input(type="hidden", name="_csrf", value=ctx.csrf)
label(for='two-factor-step-one')
b= t('Step 1: ')
= t('Install an authenticator application on your mobile device.')
label(for='two-factor-step-two')
b= t('Step 2: ')
= t('Scan the following QR code in your authenticator app.')
img(src=qrcode, width=250, height=250, alt="").mx-auto.d-block
hr
.input-group.input-group-sm.floating-label.form-group
input(type='text', readonly, value=user[config.passport.fields.twoFactorToken]).form-control#two-factor-token
label(for='two-factor-token')= t('Two-Factor Token')
.input-group-append
button(type='button', data-toggle="clipboard", data-clipboard-target="#two-factor-token").btn.btn-primary
i.fa.fa-clipboard
= ' '
= t('Copy')
hr
p.lead.text-center.font-weight-bold= t('Enter the token generated from your app below:')
label(for='two-factor-step-three')
b= t('Step 3: ')
= t('Enter the token generated from your app below:')
.form-group.floating-label
input(type='text', name='token', required, placeholder=' ').form-control.form-control-lg#input-token
label(for='input-token') Verification Token
p.text-muted.text-center.text-uppercase.font-weight-bold: small: mark= t('Hint: Scan the QR code or use the URI above if necessary')
a.card-link.text-primary(data-toggle='collapse' data-target='#two-factor-token')= t('Can’t scan the QR code? Follow alternative steps')
#two-factor-token.collapse
hr
p.text-secondary= t('Scan the following QR code in your authenticator app.')
.input-group.input-group-sm.floating-label.form-group
input(type='text', readonly, value=user[config.passport.fields.twoFactorToken]).form-control#two-factor-token
.input-group-append
button(type='button', data-toggle="clipboard", data-clipboard-target="#two-factor-token").btn.btn-primary
i.fa.fa-clipboard
= ' '
= t('Copy')
hr
button(type='submit').btn.btn-lg.btn-block.btn-primary= t('Continue')
.container-fluid.py-3
.row.mt-1
Expand Down
9 changes: 3 additions & 6 deletions template/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,7 @@ const config = {
passwordValidator: (password, fn) => {
if (env.NODE_ENV === 'development') return fn();
const { score } = zxcvbn(password);
fn(
score < 3
? Boom.badRequest(phrases.INVALID_PASSWORD_STRENGTH)
: null
);
fn(score < 3 ? Boom.badRequest(phrases.INVALID_PASSWORD_STRENGTH) : null);
},
errorMessages: {
MissingPasswordError: phrases.PASSPORT_MISSING_PASSWORD_ERROR,
Expand Down Expand Up @@ -221,12 +217,13 @@ const logger = new Axe(config.logger);

// add manifest helper for rev-manifest.json support
config.manifest = path.join(config.buildDir, 'rev-manifest.json');
config.srimanifest = path.join(config.buildDir, 'sri-manifest.json');
config.views.locals.manifest = manifestRev({
prepend:
env.AWS_CLOUDFRONT_DOMAIN && env.NODE_ENV === 'production'
? `//${env.AWS_CLOUDFRONT_DOMAIN}/`
: '/',
manifest: config.manifest
manifest: config.srimanifest
});

// add global `config` object to be used by views
Expand Down
45 changes: 20 additions & 25 deletions template/gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const Mandarin = require('mandarin');
const _ = require('lodash');
const awscloudfront = require('gulp-awspublish-cloudfront');
const awspublish = require('gulp-awspublish');
const babel = require('gulp-babel');
const browserify = require('browserify');
const collapser = require('bundle-collapser/plugin');
const cssnano = require('cssnano');
Expand Down Expand Up @@ -37,6 +36,7 @@ const sourcemaps = require('gulp-sourcemaps');
const stylelint = require('stylelint');
const terser = require('gulp-terser');
const unassert = require('gulp-unassert');
const revSri = require('gulp-rev-sri');
const { lastRun, watch, series, parallel, src, dest } = require('gulp');

// explicitly set the compiler in case it were to change to dart
Expand Down Expand Up @@ -120,6 +120,7 @@ function img() {
.pipe(dest(config.buildBase))
.pipe(gulpif(DEV, lr(config.livereload)))
.pipe(gulpif(PROD, rev.manifest(config.manifest, manifestOptions)))
.pipe(gulpif(PROD, revSri({ base: config.buildBase })))
.pipe(gulpif(PROD, dest(config.buildBase)));
}

Expand Down Expand Up @@ -155,6 +156,7 @@ function css() {
.pipe(dest(config.buildBase))
.pipe(gulpif(DEV, lr(config.livereload)))
.pipe(gulpif(PROD, rev.manifest(config.manifest, manifestOptions)))
.pipe(gulpif(PROD, revSri({ base: config.buildBase })))
.pipe(gulpif(PROD, dest(config.buildBase)));
}

Expand All @@ -180,41 +182,36 @@ function eslint() {
async function bundle() {
// make build/js folder for compile task
await makeDir(path.join(config.buildBase, 'js'));
const ws = fs.createWriteStream(
path.join(config.buildBase, 'js', 'factor-bundle.js')
);
const paths = await globby('**/*.js', { cwd: 'assets/js' });
const b = browserify({
entries: paths.map(string => `assets/js/${string}`),
debug: true
});
return (
b
.plugin(collapser)
.plugin('factor-bundle', {
outputs: paths.map(string => path.join(config.buildBase, 'js', string))
})
.bundle()
// .bundle((err, buffer) => {
.pipe(
fs.createWriteStream(
path.join(config.buildBase, 'js', 'factor-bundle.js')
)
)
);
return b
.plugin(collapser)
.plugin('factor-bundle', {
outputs: paths.map(string => path.join(config.buildBase, 'js', string))
})
.bundle()
.pipe(ws)
.on('finish', compile);
}

async function compile() {
return src('build/js/**/*.js', {
since: lastRun(compile)
})
function compile() {
return src('build/js/**/*.js', { since: lastRun(compile) })
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(envify(env))
.pipe(unassert())
.pipe(babel())
.pipe(gulpif(PROD, terser()))
.pipe(gulpif(PROD, rev()))
.pipe(sourcemaps.write('./'))
.pipe(dest(config.buildBase))
.pipe(gulpif(DEV, lr(config.livereload)))
.pipe(gulpif(PROD, rev.manifest(config.manifest, manifestOptions)))
.pipe(gulpif(PROD, revSri({ base: config.buildBase })))
.pipe(gulpif(PROD, dest(config.buildBase)));
}

Expand All @@ -241,8 +238,6 @@ function clean() {
return del([config.buildBase]);
}

const js = series(bundle, compile);

async function markdown() {
const mandarin = new Mandarin({ i18n, logger });
const graceful = new Graceful({ redisClients: [mandarin.redisClient] });
Expand All @@ -254,13 +249,13 @@ const build = series(
clean,
parallel(
...(TEST ? [] : [xo, remark]),
parallel(img, static, markdown, series(scss, css), series(js, eslint))
parallel(img, static, markdown, series(scss, css), series(bundle, eslint))
)
);

module.exports = {
build,
js,
bundle,
publish,
markdown,
watch: () => {
Expand All @@ -269,7 +264,7 @@ module.exports = {
watch(Mandarin.DEFAULT_PATTERNS, markdown);
watch('assets/img/**/*', img);
watch('assets/css/**/*.scss', series(scss, css));
watch('assets/js/**/*.js', series(xo, js, eslint));
watch('assets/js/**/*.js', series(xo, bundle, eslint));
watch('app/views/**/*.pug', pug);
watch(staticAssets, static);
},
Expand Down
20 changes: 19 additions & 1 deletion template/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,23 @@
"Password was invalid.": "Password was invalid.",
"You can only request a password reset every 30 minutes. Please try again %s.": "You can only request a password reset every 30 minutes. Please try again %s.",
"Your support request has been sent successfully. You should hear from us soon. Thank you!": "Your support request has been sent successfully. You should hear from us soon. Thank you!",
"You have reached the limit for sending support requests. Please try again.": "You have reached the limit for sending support requests. Please try again."
"You have reached the limit for sending support requests. Please try again.": "You have reached the limit for sending support requests. Please try again.",
"Email address or password is incorrect.": "Email address or password is incorrect.",
"Dashboard &#124; <span class=\"notranslate\">Lad</span>": "Dashboard &#124; <span class=\"notranslate\">Lad</span>",
"Access your Lad account dashboard": "Access your Lad account dashboard",
"Verify email &#124; <span class=\"notranslate\">Lad</span>": "Verify email &#124; <span class=\"notranslate\">Lad</span>",
"Verify your Lad email": "Verify your Lad email",
"An email verification pin has been sent to your email address.": "An email verification pin has been sent to your email address.",
"Verify email": "Verify email",
"Enter the verification pin sent to your email address.": "Enter the verification pin sent to your email address.",
"Please enter a 6 digit verification pin.": "Please enter a 6 digit verification pin.",
"Verification pin": "Verification pin",
"Continue": "Continue",
"Didn't receive the email?": "Didn't receive the email?",
"Resend now": "Resend now",
"Use this verification pin:": "Use this verification pin:",
"This pin expires within 5 minutes.": "This pin expires within 5 minutes.",
"Verify now": "Verify now",
"If you did not submit this request, then please reply to let us know.": "If you did not submit this request, then please reply to let us know.",
"Verification pin:": "Verification pin:"
}
20 changes: 19 additions & 1 deletion template/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,23 @@
"Password was invalid.": "Password was invalid.",
"You can only request a password reset every 30 minutes. Please try again %s.": "You can only request a password reset every 30 minutes. Please try again %s.",
"Your support request has been sent successfully. You should hear from us soon. Thank you!": "Your support request has been sent successfully. You should hear from us soon. Thank you!",
"You have reached the limit for sending support requests. Please try again.": "You have reached the limit for sending support requests. Please try again."
"You have reached the limit for sending support requests. Please try again.": "You have reached the limit for sending support requests. Please try again.",
"Email address or password is incorrect.": "Email address or password is incorrect.",
"Dashboard &#124; <span class=\"notranslate\">Lad</span>": "Dashboard &#124; <span class=\"notranslate\">Lad</span>",
"Access your Lad account dashboard": "Access your Lad account dashboard",
"Verify email &#124; <span class=\"notranslate\">Lad</span>": "Verify email &#124; <span class=\"notranslate\">Lad</span>",
"Verify your Lad email": "Verify your Lad email",
"An email verification pin has been sent to your email address.": "An email verification pin has been sent to your email address.",
"Verify email": "Verify email",
"Enter the verification pin sent to your email address.": "Enter the verification pin sent to your email address.",
"Please enter a 6 digit verification pin.": "Please enter a 6 digit verification pin.",
"Verification pin": "Verification pin",
"Continue": "Continue",
"Didn't receive the email?": "Didn't receive the email?",
"Resend now": "Resend now",
"Use this verification pin:": "Use this verification pin:",
"This pin expires within 5 minutes.": "This pin expires within 5 minutes.",
"Verify now": "Verify now",
"If you did not submit this request, then please reply to let us know.": "If you did not submit this request, then please reply to let us know.",
"Verification pin:": "Verification pin:"
}
20 changes: 19 additions & 1 deletion template/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,23 @@
"Password was invalid.": "Password was invalid.",
"You can only request a password reset every 30 minutes. Please try again %s.": "You can only request a password reset every 30 minutes. Please try again %s.",
"Your support request has been sent successfully. You should hear from us soon. Thank you!": "Your support request has been sent successfully. You should hear from us soon. Thank you!",
"You have reached the limit for sending support requests. Please try again.": "You have reached the limit for sending support requests. Please try again."
"You have reached the limit for sending support requests. Please try again.": "You have reached the limit for sending support requests. Please try again.",
"Email address or password is incorrect.": "Email address or password is incorrect.",
"Dashboard &#124; <span class=\"notranslate\">Lad</span>": "Dashboard &#124; <span class=\"notranslate\">Lad</span>",
"Access your Lad account dashboard": "Access your Lad account dashboard",
"Verify email &#124; <span class=\"notranslate\">Lad</span>": "Verify email &#124; <span class=\"notranslate\">Lad</span>",
"Verify your Lad email": "Verify your Lad email",
"An email verification pin has been sent to your email address.": "An email verification pin has been sent to your email address.",
"Verify email": "Verify email",
"Enter the verification pin sent to your email address.": "Enter the verification pin sent to your email address.",
"Please enter a 6 digit verification pin.": "Please enter a 6 digit verification pin.",
"Verification pin": "Verification pin",
"Continue": "Continue",
"Didn't receive the email?": "Didn't receive the email?",
"Resend now": "Resend now",
"Use this verification pin:": "Use this verification pin:",
"This pin expires within 5 minutes.": "This pin expires within 5 minutes.",
"Verify now": "Verify now",
"If you did not submit this request, then please reply to let us know.": "If you did not submit this request, then please reply to let us know.",
"Verification pin:": "Verification pin:"
}
Loading

0 comments on commit 27df169

Please sign in to comment.