Просмотр исходного кода

Merge pull request #5171 from overleaf/jpa-web-launchpad-de-ng

[web] de-ng launchpad page

GitOrigin-RevId: 0a8939ac8716bd099d9e8c2be0a281f24274e48d
Jakob Ackermann 4 лет назад
Родитель
Сommit
f06f1e2b96

+ 1 - 1
services/web/frontend/js/features/form-helpers/hydrate-form.js

@@ -146,7 +146,7 @@ function formSentHelper(el) {
   })
 }
 
-function toggleDisplay(hide, show) {
+export function toggleDisplay(hide, show) {
   hide.forEach(el => {
     el.hidden = true
   })

+ 5 - 11
services/web/modules/launchpad/app/src/LaunchpadController.js

@@ -102,7 +102,9 @@ module.exports = LaunchpadController = {
     const { email } = req.body
     if (!email) {
       logger.log({}, 'no email address supplied')
-      return res.sendStatus(400)
+      return res.status(400).json({
+        message: 'no email address supplied',
+      })
     }
     logger.log({ email }, 'sending test email')
     const emailOptions = { to: email }
@@ -114,7 +116,7 @@ module.exports = LaunchpadController = {
         return next(err)
       }
       logger.log({ email }, 'sent test email')
-      return res.sendStatus(201)
+      res.json({ message: res.locals.translate('email_sent') })
     })
   },
 
@@ -245,19 +247,11 @@ module.exports = LaunchpadController = {
                 return next(err)
               }
 
-              AuthenticationController.setRedirectInSession(req, '/launchpad')
               logger.log(
                 { email, user_id: user._id },
                 'created first admin account'
               )
-              return res.json({
-                redir: '',
-                id: user._id.toString(),
-                first_name: user.first_name,
-                last_name: user.last_name,
-                email: user.email,
-                created: Date.now(),
-              })
+              res.json({ redir: '/launchpad' })
             }
           )
         }

+ 158 - 196
services/web/modules/launchpad/app/views/launchpad.pug

@@ -1,24 +1,37 @@
-extends ../../../../app/views/layout
+extends ../../../../app/views/layout-marketing
+
+mixin launchpad-check(section)
+	div(data-ol-launchpad-check=section)
+		span(data-ol-inflight="pending")
+			i.fa.fa-fw.fa-spinner.fa-spin
+			span  #{translate('checking')}
+	
+		span(hidden data-ol-inflight="idle")
+			div(data-ol-result="success")
+				i.fa.fa-check
+				span  #{translate('ok')}
+				button.btn.btn-inline-link
+					span.text-danger  #{translate('retry')}
+			div(hidden data-ol-result="error")
+				i.fa.fa-exclamation
+				span  #{translate('error')}
+				button.btn.btn-inline-link
+					span.text-danger  #{translate('retry')}
+				div.alert.alert-danger
+					span(data-ol-error)
+
+block vars
+	- entrypoint = 'modules/launchpad/pages/launchpad'
+	- metadata = metadata || {}
 
 block append meta
 	meta(name="ol-adminUserExists" data-type="boolean" content=adminUserExists)
 	meta(name="ol-ideJsPath" content=buildJsPath('ide.js'))
-	meta(name="ol-authMethod" content=authMethod)
 
 block content
 	script(type="text/javascript", nonce=scriptNonce, src=(wsUrl || '/socket.io') + '/socket.io.js')
 
-	style.
-		hr { margin-bottom: 5px; }
-		.status-check {
-			margin-bottom: 15px;
-		}
-		.alert { margin-top: 15px; margin-bottom: 15px; }
-		a small { cursor: pointer; color: #a93529; }
-		.launchpad-body img { width: 150px; margin-top: 15px; }
-
-
-	.content.content-alt(ng-controller="LaunchpadController")
+	.content.content-alt
 		.container(ng-cloak)
 			.row
 				.col-md-8.col-md-offset-2
@@ -36,191 +49,133 @@ block content
 
 
 								<!-- create first admin form -->
-								.row(ng-if="shouldShowAdminForm()")
-									.col-md-12
-										h2 #{translate('create_first_admin_account')}
-
-										// Local Auth Form
-										div(ng-if="authMethod == 'local'")
-											form(async-form="register", name="registerForm", on-success="onCreateAdminSuccess"
-													on-error="onCreateAdminError"
-													action="/launchpad/register_admin", method="POST", ng-cloak)
-												input(name='_csrf', type='hidden', value=csrfToken)
-												form-messages(for="registerForm")
-												.form-group
-													label(for='email') #{translate("email")}
-													input.form-control(
-														type='email',
-														name='email',
-														placeholder="email@example.com"
-														required,
-														ng-model="email",
-														ng-model-options="{ updateOn: 'blur' }",
-														autofocus="true"
-													)
-													span.small.text-primary(ng-show="registerForm.email.$invalid && registerForm.email.$dirty")
-														| #{translate("must_be_email_address")}
-												.form-group
-													label(for='password') #{translate("password")}
-													input.form-control#passwordField(
-														type='password',
-														name='password',
-														placeholder="********",
-														required,
-														ng-model="password",
-														complex-password
-													)
-													span.small.text-primary(ng-show="registerForm.password.$error.complexPassword",
-																									ng-bind-html="complexPasswordErrorMessage")
-												.actions
-													button.btn-primary.btn(
-														type='submit'
-														ng-disabled="registerForm.inflight || registerForm.password.$error.required|| registerForm.password.$error.complexPassword || createAdminSuccess"
-													)
-														span(ng-show="!registerForm.inflight") #{translate("register")}
-														span(ng-show="registerForm.inflight") #{translate("registering")}…
-
-										// Ldap Form
-										div(ng-if="authMethod == 'ldap'")
-											h3 #{translate('ldap')}
-											p
-												| #{translate('ldap_create_admin_instructions')}
-
-											form(async-form="register", name="registerLdapForm", on-success="onCreateAdminSuccess"
-													on-error="onCreateAdminError"
-													action="/launchpad/register_ldap_admin", method="POST", ng-cloak)
-												input(name='_csrf', type='hidden', value=csrfToken)
-												form-messages(for="registerLdapForm")
-												.form-group
-													label(for='email') #{translate("email")}
-													input.form-control(
-														type='email',
-														name='email',
-														placeholder="email@example.com"
-														required,
-														ng-model="email",
-														ng-model-options="{ updateOn: 'blur' }",
-														autofocus="true"
-													)
-													span.small.text-primary(ng-show="registerLdapForm.email.$invalid && registerLdapForm.email.$dirty")
-														| #{translate("must_be_email_address")}
-												.actions
-													button.btn-primary.btn(
-														type='submit'
-														ng-disabled="registerLdapForm.inflight || registerLdapForm.password.$error.required|| registerLdapForm.password.$error.complexPassword || createAdminSuccess"
-													)
-														span(ng-show="!registerLdapForm.inflight") #{translate("register")}
-														span(ng-show="registerLdapForm.inflight") #{translate("registering")}…
-
-
-										// Saml Form
-										div(ng-if="authMethod == 'saml'")
-											h3 #{translate('saml')}
-											p
-												| #{translate('saml_create_admin_instructions')}
-
-											form(async-form="register", name="registerSamlForm", on-success="onCreateAdminSuccess"
-													on-error="onCreateAdminError"
-													action="/launchpad/register_saml_admin", method="POST", ng-cloak)
-												input(name='_csrf', type='hidden', value=csrfToken)
-												form-messages(for="registerSamlForm")
-												.form-group
-													label(for='email') #{translate("email")}
-													input.form-control(
-														type='email',
-														name='email',
-														placeholder="email@example.com"
-														required,
-														ng-model="email",
-														ng-model-options="{ updateOn: 'blur' }",
-														autofocus="true"
-													)
-													span.small.text-primary(ng-show="registerSamlForm.email.$invalid && registerSamlForm.email.$dirty")
-														| #{translate("must_be_email_address")}
-												.actions
-													button.btn-primary.btn(
-														type='submit'
-														ng-disabled="registerSamlForm.inflight || registerSamlForm.password.$error.required|| registerSamlForm.password.$error.complexPassword || createAdminSuccess"
-													)
-														span(ng-show="!registerSamlForm.inflight") #{translate("register")}
-														span(ng-show="registerSamlForm.inflight") #{translate("registering")}…
-
-
-										<!-- success message -->
-										.row(ng-if="createAdminSuccess")
-											.col-md-12.text-center
-												.alert.alert-success
-													| !{translate('admin_user_created_message', {link: '/login?redir=/launchpad'})}
-
-										<!-- error message -->
-										.row(ng-if="createAdminError")
-											.col-md-12.text-center
-												.alert.alert-danger
-													| #{translate('generic_something_went_wrong')}
-
-										br
-
-									<!-- status indicators -->
-								div(ng-if="!shouldShowAdminForm()")
+								if !adminUserExists
+									.row(data-ol-not-sent)
+										.col-md-12
+											h2 #{translate('create_first_admin_account')}
+
+											// Local Auth Form
+											if authMethod === 'local'
+												form(
+													data-ol-async-form
+													data-ol-register-admin
+													action="/launchpad/register_admin"
+													method="POST"
+												)
+													input(name='_csrf', type='hidden', value=csrfToken)
+													div(data-ol-form-messages)
+													.form-group
+														label(for='email') #{translate("email")}
+														input.form-control(
+															type='email',
+															name='email',
+															placeholder="email@example.com"
+															required,
+															autofocus="true"
+														)
+													.form-group
+														label(for='password') #{translate("password")}
+														input.form-control#passwordField(
+															type='password',
+															name='password',
+															placeholder="********",
+															required,
+														)
+													.actions
+														button.btn-primary.btn(
+															type='submit'
+															data-ol-disabled-inflight
+														)
+															span(data-ol-inflight="idle") #{translate("register")}
+															span(hidden data-ol-inflight="pending") #{translate("registering")}…
+
+											// Ldap Form
+											if authMethod === 'ldap'
+												h3 #{translate('ldap')}
+												p
+													| #{translate('ldap_create_admin_instructions')}
+
+												form(
+													data-ol-async-form
+													data-ol-register-admin
+													action="/launchpad/register_ldap_admin"
+													method="POST"
+												)
+													input(name='_csrf', type='hidden', value=csrfToken)
+													div(data-ol-form-messages)
+													.form-group
+														label(for='email') #{translate("email")}
+														input.form-control(
+															type='email',
+															name='email',
+															placeholder="email@example.com"
+															required,
+															autofocus="true"
+														)
+													.actions
+														button.btn-primary.btn(
+															type='submit'
+															data-ol-disabled-inflight
+														)
+															span(data-ol-inflight="idle") #{translate("register")}
+															span(hidden data-ol-inflight="pending") #{translate("registering")}…
+
+											// Saml Form
+											if authMethod === 'saml'
+												h3 #{translate('saml')}
+												p
+													| #{translate('saml_create_admin_instructions')}
+
+												form(
+													data-ol-async-form
+													data-ol-register-admin
+													action="/launchpad/register_saml_admin"
+													method="POST"
+												)
+													input(name='_csrf', type='hidden', value=csrfToken)
+													div(data-ol-form-messages)
+													.form-group
+														label(for='email') #{translate("email")}
+														input.form-control(
+															type='email',
+															name='email',
+															placeholder="email@example.com"
+															required,
+															autofocus="true"
+														)
+													.actions
+														button.btn-primary.btn(
+															type='submit'
+															data-ol-disabled-inflight
+														)
+															span(data-ol-inflight="idle") #{translate("register")}
+															span(hidden data-ol-inflight="pending") #{translate("registering")}…
+
+									br
+
+								<!-- status indicators -->
+								if adminUserExists
 									.row
 										.col-md-12.status-indicators
 
 											h2 #{translate('status_checks')}
 
 											<!-- ide js -->
-											.row.status-check
+											.row.row-spaced-small
 												.col-sm-5
 													| #{translate('editor_resources')}
 												.col-sm-7
-													div(ng-switch="statusChecks.ideJs.status")
-
-														span(ng-switch-when="inflight")
-															i.fa.fa-fw.fa-spinner.fa-spin
-															span &nbsp;#{translate('checking')}
-
-														span(ng-switch-when="ok")
-															i.fa.fa-check
-															span &nbsp;#{translate('ok')}
-															a(ng-click="tryFetchIdeJs()")
-																small &nbsp;#{translate('retry')}
-
-														span(ng-switch-when="error")
-															i.fa.fa-exclamation
-															span &nbsp;#{translate('error')}
-															a(ng-click="tryFetchIdeJs()")
-																small &nbsp;#{translate('retry')}
-															div.alert.alert-danger
-																| {{ statusChecks.ideJs.error }}
-
+													+launchpad-check('ide')
 
 											<!-- websocket -->
-											.row.status-check
+											.row.row-spaced-small
 												.col-sm-5
 													| #{translate('websockets')}
 												.col-sm-7
-													div(ng-switch="statusChecks.websocket.status")
-
-														span(ng-switch-when="inflight")
-															i.fa.fa-fw.fa-spinner.fa-spin
-															span &nbsp;#{translate('checking')}
-
-														span(ng-switch-when="ok")
-															i.fa.fa-check
-															span &nbsp;#{translate('ok')}
-															a(ng-click="tryOpenWebSocket()")
-																small &nbsp;#{translate('retry')}
-
-														span(ng-switch-when="error")
-															i.fa.fa-exclamation
-															span &nbsp;#{translate('error')}
-															a(ng-click="tryOpenWebSocket()")
-																small &nbsp;#{translate('retry')}
-															div.alert.alert-danger
-																| {{ statusChecks.websocket.error }}
-
+													+launchpad-check('websocket')
 
 									<!-- break -->
-									hr
+									hr.thin
 
 									<!-- other actions -->
 									.row
@@ -228,26 +183,33 @@ block content
 											h2 #{translate('other_actions')}
 
 											h3 #{translate('send_test_email')}
-											form.form
+											form.form(
+												data-ol-async-form
+												action="/launchpad/send_test_email"
+												method="POST"
+											)
 												.form-group
-													label(for="emailInput") Email
-													input(type="text", name="emailInput" ng-model="testEmail.emailAddress").form-control
-												button(ng-click="sendTestEmail()", ng-disabled="testEmail.inflight").btn.btn-primary
-													span(ng-show="!testEmail.inflight") #{translate("send")}
-													span(ng-show="testEmail.inflight") #{translate("sending")}…
-											div(ng-if="testEmail.status == 'ok'")
-												.alert.alert-success
-													| #{translate('email_sent')}
-											div(ng-if="testEmail.status == 'error'")
-												.alert.alert-danger
-													| #{translate('generic_something_went_wrong')}
-
+													label(for="email") Email
+													input.form-control(
+														type="text"
+														id="email"
+														name="email"
+														required
+													)
+												button.btn-primary.btn(
+													type='submit'
+													data-ol-disabled-inflight
+												)
+													span(data-ol-inflight="idle") #{translate("send")}
+													span(hidden data-ol-inflight="pending") #{translate("sending")}…
 
+												p
+													div(data-ol-form-messages)
 
 
 
 									<!-- break -->
-									hr
+									hr.thin
 
 
 									<!-- Go to app -->

+ 0 - 157
services/web/modules/launchpad/frontend/js/main/controllers/LaunchpadController.js

@@ -1,157 +0,0 @@
-/* global io */
-
-/* eslint-disable
-    max-len,
-    no-return-assign,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../../../../../../frontend/js/base'
-
-export default App.controller(
-  'LaunchpadController',
-  function ($scope, $http, $timeout) {
-    $scope.adminUserExists = window.data.adminUserExists
-    $scope.ideJsPath = window.data.ideJsPath
-    $scope.authMethod = window.data.authMethod
-
-    $scope.createAdminSuccess = null
-    $scope.createAdminError = null
-
-    $scope.statusChecks = {
-      ideJs: { status: 'inflight', error: null },
-      websocket: { status: 'inflight', error: null },
-      healthCheck: { status: 'inflight', error: null },
-    }
-
-    $scope.testEmail = {
-      emailAddress: '',
-      inflight: false,
-      status: null, // | 'ok' | 'success'
-    }
-
-    $scope.shouldShowAdminForm = () => !$scope.adminUserExists
-
-    $scope.onCreateAdminSuccess = function (response) {
-      const { status } = response
-      if (status >= 200 && status < 300) {
-        return ($scope.createAdminSuccess = true)
-      }
-    }
-
-    $scope.onCreateAdminError = () => ($scope.createAdminError = true)
-
-    $scope.sendTestEmail = function () {
-      $scope.testEmail.inflight = true
-      $scope.testEmail.status = null
-      return $http
-        .post('/launchpad/send_test_email', {
-          email: $scope.testEmail.emailAddress,
-          _csrf: window.csrfToken,
-        })
-        .then(function (response) {
-          const { status } = response
-          $scope.testEmail.inflight = false
-          if (status >= 200 && status < 300) {
-            return ($scope.testEmail.status = 'ok')
-          }
-        })
-        .catch(function () {
-          $scope.testEmail.inflight = false
-          return ($scope.testEmail.status = 'error')
-        })
-    }
-
-    $scope.tryFetchIdeJs = function () {
-      $scope.statusChecks.ideJs.status = 'inflight'
-      return $timeout(
-        () =>
-          $http
-            .get($scope.ideJsPath)
-            .then(function (response) {
-              const { status } = response
-              if (status >= 200 && status < 300) {
-                return ($scope.statusChecks.ideJs.status = 'ok')
-              }
-            })
-            .catch(function (response) {
-              const { status } = response
-              $scope.statusChecks.ideJs.status = 'error'
-              return ($scope.statusChecks.ideJs.error = new Error(
-                `Http status: ${status}`
-              ))
-            }),
-
-        1000
-      )
-    }
-
-    $scope.tryOpenWebSocket = function () {
-      $scope.statusChecks.websocket.status = 'inflight'
-      return $timeout(function () {
-        if (typeof io === 'undefined' || io === null) {
-          $scope.statusChecks.websocket.status = 'error'
-          $scope.statusChecks.websocket.error = 'socket.io not loaded'
-          return
-        }
-        const socket = io.connect(null, {
-          reconnect: false,
-          'connect timeout': 30 * 1000,
-          'force new connection': true,
-        })
-
-        socket.on('connectionAccepted', function () {
-          $scope.statusChecks.websocket.status = 'ok'
-          return $scope.$apply(function () {})
-        })
-
-        socket.on('connectionRejected', function (err) {
-          $scope.statusChecks.websocket.status = 'error'
-          $scope.statusChecks.websocket.error = err
-          return $scope.$apply(function () {})
-        })
-
-        return socket.on('connect_failed', function (err) {
-          $scope.statusChecks.websocket.status = 'error'
-          $scope.statusChecks.websocket.error = err
-          return $scope.$apply(function () {})
-        })
-      }, 1000)
-    }
-
-    $scope.tryHealthCheck = function () {
-      $scope.statusChecks.healthCheck.status = 'inflight'
-      return $http
-        .get('/health_check')
-        .then(function (response) {
-          const { status } = response
-          if (status >= 200 && status < 300) {
-            return ($scope.statusChecks.healthCheck.status = 'ok')
-          }
-        })
-        .catch(function (response) {
-          const { status } = response
-          $scope.statusChecks.healthCheck.status = 'error'
-          return ($scope.statusChecks.healthCheck.error = new Error(
-            `Http status: ${status}`
-          ))
-        })
-    }
-
-    $scope.runStatusChecks = function () {
-      $timeout(() => $scope.tryFetchIdeJs(), 1000)
-      return $timeout(() => $scope.tryOpenWebSocket(), 2000)
-    }
-
-    // kick off the status checks on load
-    if ($scope.adminUserExists) {
-      return $scope.runStatusChecks()
-    }
-  }
-)

+ 0 - 3
services/web/modules/launchpad/frontend/js/main/index.js

@@ -1,3 +0,0 @@
-// TODO: This file was created by bulk-decaffeinate.
-// Sanity-check the conversion and remove this comment.
-import './controllers/LaunchpadController'

+ 88 - 0
services/web/modules/launchpad/frontend/js/pages/launchpad.js

@@ -0,0 +1,88 @@
+/* global io */
+import '../../../../../frontend/js/marketing'
+import {
+  inflightHelper,
+  toggleDisplay,
+} from '../../../../../frontend/js/features/form-helpers/hydrate-form'
+import getMeta from '../../../../../frontend/js/utils/meta'
+
+function setUpStatusIndicator(el, fn) {
+  inflightHelper(el)
+
+  const displaySuccess = el.querySelectorAll('[data-ol-result="success"]')
+  const displayError = el.querySelectorAll('[data-ol-result="error"]')
+
+  // The checks are very lightweight and do not appear to do anything
+  //  from looking at the UI. Add an artificial delay of 1s to show that
+  //  we are actually doing something. :)
+  const artificialProgressDelay = 1000
+
+  function run() {
+    setTimeout(() => {
+      fn()
+        .then(() => {
+          toggleDisplay(displayError, displaySuccess)
+        })
+        .catch(error => {
+          el.querySelector('[data-ol-error]').textContent = error.message
+          toggleDisplay(displaySuccess, displayError)
+        })
+        .finally(() => {
+          el.dispatchEvent(new Event('idle'))
+        })
+    }, artificialProgressDelay)
+  }
+
+  el.querySelectorAll('button').forEach(retryBtn => {
+    retryBtn.addEventListener('click', function (e) {
+      e.preventDefault()
+      el.dispatchEvent(new Event('pending'))
+      run()
+    })
+  })
+
+  run()
+}
+
+function setUpStatusIndicators() {
+  setUpStatusIndicator(
+    document.querySelector('[data-ol-launchpad-check="websocket"]'),
+    () => {
+      const timeout = 10 * 1000
+      const socket = io.connect(null, {
+        reconnect: false,
+        'connect timeout': timeout,
+        'force new connection': true,
+      })
+      return new Promise((resolve, reject) => {
+        setTimeout(() => reject(new Error('timed out')), timeout)
+        socket.on('connectionAccepted', function () {
+          resolve()
+        })
+        socket.on('connectionRejected', function (err) {
+          reject(new Error(err && err.message))
+        })
+        socket.on('connect_failed', function (err) {
+          reject(new Error(err && err.message))
+        })
+      }).finally(() => {
+        socket.disconnect()
+      })
+    }
+  )
+
+  setUpStatusIndicator(
+    document.querySelector('[data-ol-launchpad-check="ide"]'),
+    () => {
+      return fetch(getMeta('ol-ideJsPath')).then(res => {
+        if (!res.ok) {
+          throw new Error(`Http status: ${res.status}`)
+        }
+      })
+    }
+  )
+}
+
+if (getMeta('ol-adminUserExists')) {
+  setUpStatusIndicators()
+}

+ 1 - 3
services/web/modules/launchpad/test/acceptance/src/LaunchpadTests.js

@@ -37,9 +37,7 @@ describe('Launchpad', function () {
       },
     })
     expect(postResponse.statusCode).to.equal(200)
-    expect(postResponse.body.redir).to.equal('')
-    expect(postResponse.body.email).to.equal(adminEmail)
-    expect(postResponse.body.id).to.exist
+    expect(postResponse.body).to.deep.equal({ redir: '/launchpad' })
 
     // Try to load the page again
     const secondPageResponse = await user.request.get('/launchpad', {

+ 21 - 25
services/web/modules/launchpad/test/unit/src/LaunchpadControllerTests.js

@@ -53,9 +53,16 @@ describe('LaunchpadController', function () {
     this.res = {
       render: sinon.stub(),
       redirect: sinon.stub(),
+      json: sinon.stub(),
       send: sinon.stub(),
       sendStatus: sinon.stub(),
+      locals: {
+        translate(key) {
+          return key
+        },
+      },
     }
+    this.res.status = sinon.stub().returns(this.res)
 
     return (this.next = sinon.stub())
   })
@@ -252,10 +259,13 @@ describe('LaunchpadController', function () {
       return (this.next = sinon.stub())
     })
 
-    it('should produce a 201 response', function () {
+    it('should produce a 200 response', function () {
       this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
-      this.res.sendStatus.callCount.should.equal(1)
-      return this.res.sendStatus.calledWith(201).should.equal(true)
+      this.res.json
+        .calledWith({
+          message: 'email_sent',
+        })
+        .should.equal(true)
     })
 
     it('should not call next with an error', function () {
@@ -292,8 +302,12 @@ describe('LaunchpadController', function () {
 
       it('should produce a 400 response', function () {
         this.LaunchpadController.sendTestEmail(this.req, this.res, this.next)
-        this.res.sendStatus.callCount.should.equal(1)
-        return this.res.sendStatus.calledWith(400).should.equal(true)
+        this.res.status.calledWith(400).should.equal(true)
+        this.res.json
+          .calledWith({
+            message: 'no email address supplied',
+          })
+          .should.equal(true)
       })
     })
   })
@@ -337,7 +351,7 @@ describe('LaunchpadController', function () {
 
       it('should send back a json response', function () {
         this.res.json.callCount.should.equal(1)
-        return expect(this.res.json.lastCall.args[0].email).to.equal(this.email)
+        expect(this.res.json).to.have.been.calledWith({ redir: '/launchpad' })
       })
 
       it('should have checked for existing admins', function () {
@@ -365,15 +379,6 @@ describe('LaunchpadController', function () {
           )
           .should.equal(true)
       })
-
-      it('should have set a redirect in session', function () {
-        this.AuthenticationController.setRedirectInSession.callCount.should.equal(
-          1
-        )
-        return this.AuthenticationController.setRedirectInSession
-          .calledWith(this.req, '/launchpad')
-          .should.equal(true)
-      })
     })
 
     describe('when no email is supplied', function () {
@@ -648,7 +653,7 @@ describe('LaunchpadController', function () {
 
       it('should send back a json response', function () {
         this.res.json.callCount.should.equal(1)
-        return expect(this.res.json.lastCall.args[0].email).to.equal(this.email)
+        expect(this.res.json).to.have.been.calledWith({ redir: '/launchpad' })
       })
 
       it('should have checked for existing admins', function () {
@@ -675,15 +680,6 @@ describe('LaunchpadController', function () {
           )
           .should.equal(true)
       })
-
-      it('should have set a redirect in session', function () {
-        this.AuthenticationController.setRedirectInSession.callCount.should.equal(
-          1
-        )
-        return this.AuthenticationController.setRedirectInSession
-          .calledWith(this.req, '/launchpad')
-          .should.equal(true)
-      })
     })
   })