Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PP-13133 simplified account settings - edit service name #4282

Merged
merged 9 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/assets/sass/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@ $govuk-page-width: 1200px;
@import "components/additional-information";
@import "components/messages";
@import "components/spinner";
@import "components/service-settings";
35 changes: 35 additions & 0 deletions app/assets/sass/components/service-settings.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// https://getbem.com/naming/

.service-settings-nav {
@include govuk-font(16);
}

.service-settings-nav__h3 {
@include govuk-font(19);
@include govuk-typography-weight-regular();
margin: 0;
padding: govuk-spacing(2) govuk-spacing(3) govuk-spacing(2) 0;
color: govuk-colour("dark-grey");
}

.service-settings-nav__li {
@include govuk-font(16);
position: relative;
margin-bottom: govuk-spacing(1);
padding-top: govuk-spacing(1);
padding-bottom: govuk-spacing(1);
}

.service-settings-nav__li--active:before {
content: '';
position: absolute;
left: -14px;
top: 0;
height: 100%;
width: 4px;
background-color: $govuk-brand-colour;
}

.service-settings-nav__li--active {
@include govuk-typography-weight-bold();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const { response } = require('../../../../utils/response')

function get (req, res) {
return response(req, res, 'simplified-account/settings/email-notifications/index')
}

module.exports = {
get
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TODO
19 changes: 19 additions & 0 deletions app/controllers/simplified-account/settings/index.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const formatSimplifiedAccountPathsFor = require('../../../utils/simplified-account/format/format-simplified-account-paths-for')
const paths = require('../../../paths')
const { LIVE } = require('../../../models/go-live-stage')

function get (req, res) {
const account = req.account
const service = req.service
const isServiceAdmin = req.user.isAdminUserForService(service.externalId)

if (!isServiceAdmin || (account.type === 'test' && service.currentGoLiveStage === LIVE)) {
res.redirect(formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.emailNotifications.index, req.account.service_id, req.account.type))
} else {
res.redirect(formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.index, req.account.service_id, req.account.type))
}
}

module.exports = {
get
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const { expect } = require('chai')
const { LIVE, NOT_STARTED } = require('../../../models/go-live-stage')
const proxyquire = require('proxyquire')
const sinon = require('sinon')
const paths = require('../../../paths')
const formatSimplifiedAccountPathsFor = require('../../../utils/simplified-account/format/format-simplified-account-paths-for')

const LIVE_ACCOUNT_TYPE = 'live'
const TEST_ACCOUNT_TYPE = 'test'
const SERVICE_ID = 'service-id-123abc'

let req, res, indexController

const getController = () => {
return proxyquire('./index.controller', {})
}

describe('Controller: settings/index', () => {
describe('get', () => {
beforeEach(() => {
indexController = getController()
res = {
redirect: sinon.spy()
}
req = {
user: {
isAdminUserForService: () => false
},
account: {
service_id: SERVICE_ID,
type: TEST_ACCOUNT_TYPE
},
service: {
currentGoLiveStage: NOT_STARTED
}
}
})

it('should redirect to service name index for test account on service with no live account when user is an admin', () => {
req.user.isAdminUserForService = () => true
indexController.get(req, res)
expect(res.redirect.calledWith(formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.index, SERVICE_ID, TEST_ACCOUNT_TYPE))).to.be.true // eslint-disable-line
})

it('should redirect to email notifications index for test account on service with no live account when user is not an admin', () => {
indexController.get(req, res)
expect(res.redirect.calledWith(formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.emailNotifications.index, SERVICE_ID, TEST_ACCOUNT_TYPE))).to.be.true // eslint-disable-line
})

it('should redirect to service name index for live account when user is an admin', () => {
req.user.isAdminUserForService = () => true
req.account.type = 'live'
indexController.get(req, res)
expect(res.redirect.calledWith(formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.index, SERVICE_ID, LIVE_ACCOUNT_TYPE))).to.be.true // eslint-disable-line
})

it('should redirect to email notifications index for live account when user is not an admin', () => {
req.account.type = 'live'
indexController.get(req, res)
expect(res.redirect.calledWith(formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.emailNotifications.index, SERVICE_ID, LIVE_ACCOUNT_TYPE))).to.be.true // eslint-disable-line
})

it('should redirect to email notifications index for test account on service with live account when user is an admin', () => {
req.user.isAdminUserForService = () => true
req.service.currentGoLiveStage = LIVE
indexController.get(req, res)
expect(res.redirect.calledWith(formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.emailNotifications.index, SERVICE_ID, TEST_ACCOUNT_TYPE))).to.be.true // eslint-disable-line
})

it('should redirect to email notifications index for test account on service with live account when user is not an admin', () => {
req.service.currentGoLiveStage = LIVE
indexController.get(req, res)
expect(res.redirect.calledWith(formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.emailNotifications.index, SERVICE_ID, TEST_ACCOUNT_TYPE))).to.be.true // eslint-disable-line
})
nlsteers marked this conversation as resolved.
Show resolved Hide resolved
})
})
3 changes: 3 additions & 0 deletions app/controllers/simplified-account/settings/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports.index = require('./index.controller')
module.exports.serviceName = require('./service-name/service-name.controller')
module.exports.emailNotifications = require('./email-notifications/email-notifications.controller')
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const { body, validationResult } = require('express-validator')
const { SERVICE_NAME_MAX_LENGTH } = require('../../../../utils/validation/server-side-form-validations')
const { response } = require('../../../../utils/response')
const { updateServiceName } = require('../../../../services/service.service')
const paths = require('../../../../paths')
const formatSimplifiedAccountPathsFor = require('../../../../utils/simplified-account/format/format-simplified-account-paths-for')
const formatValidationErrors = require('../../../../utils/simplified-account/format/format-validation-errors')

function get (req, res) {
const context = {
service_name_en: req.service.serviceName.en,
service_name_cy: req.service.serviceName.cy,
manage_en: formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.edit, req.account.service_id, req.account.type),
manage_cy: formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.edit, req.account.service_id, req.account.type) + '?cy=true'
}
return response(req, res, 'simplified-account/settings/service-name/index', context)
}

function getEditServiceName (req, res) {
const editCy = req.query.cy === 'true'
const context = {
edit_cy: editCy,
back_link: formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.index, req.account.service_id, req.account.type),
submit_link: formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.edit, req.account.service_id, req.account.type)
}
if (editCy) {
Object.assign(context, { service_name: req.service.serviceName.cy })
} else {
Object.assign(context, { service_name: req.service.serviceName.en })
}
return response(req, res, 'simplified-account/settings/service-name/edit-service-name', context)
}

async function postEditServiceName (req, res) {
const editCy = req.body.cy === 'true'
const validations = [
body('service-name-input').trim().isLength({ max: SERVICE_NAME_MAX_LENGTH }).withMessage(`Service name must be ${SERVICE_NAME_MAX_LENGTH} characters or fewer`)
]
// we don't check presence for welsh names
if (!editCy) {
validations.push(body('service-name-input').trim().notEmpty().withMessage('Service name is required'))
}

await Promise.all(validations.map(validation => validation.run(req)))
const errors = validationResult(req)
if (!errors.isEmpty()) {
const formattedErrors = formatValidationErrors(errors)
return response(req, res, 'simplified-account/settings/service-name/edit-service-name', {
nlsteers marked this conversation as resolved.
Show resolved Hide resolved
errors: {
summary: formattedErrors.errorSummary,
formErrors: formattedErrors.formErrors
},
edit_cy: editCy,
service_name: req.body['service-name-input'],
back_link: formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.index, req.account.service_id, req.account.type),
submit_link: formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.edit, req.account.service_id, req.account.type)
})
}

const newServiceName = req.body['service-name-input']
editCy ? await updateServiceName(req.account.service_id, req.service.serviceName.en, newServiceName) : await updateServiceName(req.account.service_id, newServiceName, req.service.serviceName.cy)
res.redirect(formatSimplifiedAccountPathsFor(paths.simplifiedAccount.settings.serviceName.index, req.account.service_id, req.account.type))
}

module.exports = {
get,
getEditServiceName,
postEditServiceName
}
Loading