From cc99edf05d2cca6b39e60da7a9970eae96b2f18b Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Tue, 30 Jan 2024 11:36:50 -0800 Subject: [PATCH 01/10] Use find instead of index for staff/admin roles --- packages/server/seeds/dev/ref/users.js | 35 ++++++++++++++------------ 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/server/seeds/dev/ref/users.js b/packages/server/seeds/dev/ref/users.js index 991611872..ffd048163 100644 --- a/packages/server/seeds/dev/ref/users.js +++ b/packages/server/seeds/dev/ref/users.js @@ -4,6 +4,9 @@ const agencies = require('./agencies'); const roles = require('./roles'); const tenants = require('./tenants'); +const adminRole = roles.find(({ name }) => name === 'admin'); +const staffRole = roles.find(({ name }) => name === 'staff'); + const usdrAgency = agencies.find((a) => a.abbreviation === 'USDR'); const usdrSubAgency = agencies.find((a) => a.abbreviation === 'TSDR'); const nevadaAgency = agencies.find((a) => a.abbreviation === 'NV'); @@ -21,7 +24,7 @@ module.exports = [ email: 'alex@usdigitalresponse.org', name: 'Alex Allain', agency_id: usdrAgency.id, - role_id: roles[0].id, + role_id: adminRole.id, tenant_id: usdrTenant.id, }, { @@ -29,7 +32,7 @@ module.exports = [ email: 'mindy@usdigitalresponse.org', // fake email for testing name: 'Mindy Huang', agency_id: usdrAgency.id, - role_id: roles[0].id, + role_id: adminRole.id, tenant_id: usdrTenant.id, }, { @@ -37,7 +40,7 @@ module.exports = [ email: 'joecomeau01@gmail.com', name: 'Joe Comeau', agency_id: usdrAgency.id, - role_id: roles[0].id, + role_id: adminRole.id, tenant_id: usdrTenant.id, }, { @@ -45,7 +48,7 @@ module.exports = [ email: 'asridhar@usdigitalresponse.org', name: 'Aditya Sridhar', agency_id: usdrAgency.id, - role_id: roles[0].id, + role_id: adminRole.id, tenant_id: usdrTenant.id, }, { @@ -53,7 +56,7 @@ module.exports = [ email: 'thendrickson@usdigitalresponse.org', name: 'Tyler Hendrickson', agency_id: usdrAgency.id, - role_id: roles[0].id, + role_id: adminRole.id, tenant_id: usdrTenant.id, }, { @@ -61,7 +64,7 @@ module.exports = [ email: 'user1@nv.gov', // fake email for testing name: 'nv.gov User 1', agency_id: nevadaAgency.id, - role_id: roles[1].id, + role_id: staffRole.id, tenant_id: nevadaenant.id, }, { @@ -69,7 +72,7 @@ module.exports = [ email: 'user2@nv.gov', // fake email for testing name: 'nv.gov User 2', agency_id: nevadaAgency.id, - role_id: roles[1].id, + role_id: staffRole.id, tenant_id: nevadaenant.id, }, { @@ -77,7 +80,7 @@ module.exports = [ email: 'user3@nv.gov', // fake email for testing name: 'nv.gov User 3', agency_id: nevadaAgency.id, - role_id: roles[1].id, + role_id: staffRole.id, tenant_id: nevadaenant.id, }, { @@ -85,7 +88,7 @@ module.exports = [ email: 'user1@npo.nv.gov', // fake email for testing name: 'npo.nv.gov User 1', agency_id: procurementAgency.id, - role_id: roles[1].id, + role_id: staffRole.id, tenant_id: procurementTenant.id, }, { @@ -93,7 +96,7 @@ module.exports = [ email: 'user2@npo.nv.gov', // fake email for testing name: 'npo.nv.gov User 2', agency_id: procurementAgency.id, - role_id: roles[1].id, + role_id: staffRole.id, tenant_id: procurementTenant.id, }, { @@ -101,7 +104,7 @@ module.exports = [ email: 'user3@npo.nv.gov', // fake email for testing name: 'npo.nv.gov User 3', agency_id: procurementAgency.id, - role_id: roles[1].id, + role_id: staffRole.id, tenant_id: procurementTenant.id, }, { @@ -109,7 +112,7 @@ module.exports = [ email: 'user1@dallas.gov', // fake email for testing name: 'dallas.gov User 1', agency_id: dallasAgency.id, - role_id: roles[0].id, + role_id: adminRole.id, tenant_id: dallasTenant.id, }, { @@ -117,7 +120,7 @@ module.exports = [ email: 'admin1@nv.gov', // fake email for testing name: 'nv.gov Admin User 1', agency_id: nevadaAgency.id, - role_id: roles[0].id, + role_id: adminRole.id, tenant_id: nevadaenant.id, }, { @@ -125,7 +128,7 @@ module.exports = [ email: 'mindy+testsub@usdigitalresponse.org', name: 'USDR tenant sub agency user', agency_id: usdrSubAgency.id, - role_id: roles[1].id, + role_id: staffRole.id, tenant_id: usdrTenant.id, }, { @@ -133,7 +136,7 @@ module.exports = [ email: 'nat.hillard.usdr@gmail.com', name: 'Nat Hillard', agency_id: usdrSubAgency.id, - role_id: roles[0].id, + role_id: adminRole.id, tenant_id: usdrTenant.id, }, { @@ -141,7 +144,7 @@ module.exports = [ email: 'admin1@usdigitalresponse.org', name: 'USDR tenant sub agency admin', agency_id: usdrSubAgency.id, - role_id: roles[1].id, + role_id: staffRole.id, tenant_id: usdrTenant.id, }, ]; From 6407912a10c4d4e6f0cd7a1f880a57a32f8ee54e Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Tue, 30 Jan 2024 11:37:13 -0800 Subject: [PATCH 02/10] Add generic admin and staff roles --- packages/server/seeds/dev/ref/users.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/server/seeds/dev/ref/users.js b/packages/server/seeds/dev/ref/users.js index ffd048163..613cd99f0 100644 --- a/packages/server/seeds/dev/ref/users.js +++ b/packages/server/seeds/dev/ref/users.js @@ -147,4 +147,20 @@ module.exports = [ role_id: staffRole.id, tenant_id: usdrTenant.id, }, + { + id: 17, + email: 'admin@usdigitalresponse.org', + name: 'USDR Admin', + agency_id: usdrAgency.id, + role_id: adminRole.id, + tenant_id: usdrTenant.id, + }, + { + id: 18, + email: 'staff@usdigitalresponse.org', + name: 'USDR Staff', + agency_id: usdrAgency.id, + role_id: staffRole.id, + tenant_id: usdrTenant.id, + }, ]; From dbaa0f25a99da6723b71afa0b9c77a26b553d591 Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Tue, 30 Jan 2024 11:49:23 -0800 Subject: [PATCH 03/10] Make login link more visible in logs --- packages/server/src/lib/email.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/server/src/lib/email.js b/packages/server/src/lib/email.js index 9fb6db0fd..9f1048c22 100644 --- a/packages/server/src/lib/email.js +++ b/packages/server/src/lib/email.js @@ -77,7 +77,11 @@ function sendPassCode(email, passcode, httpOrigin, redirectTo) { ); if (process.env.DEV_LOGIN_LINK && process.env.NODE_ENV === 'development') { - console.log(`Login link generated: \x1b[32m${href}`); + const BLUE = '\x1b[34m'; + const message = `| Login link generated: ${href} |`; + console.log(`${BLUE}${'-'.repeat(message.length)}`); + console.log(`${BLUE}${message}`); + console.log(`${BLUE}${'-'.repeat(message.length)}`); } return module.exports.deliverEmail({ toAddress: email, From ec9216526116e2e202d16eea88afee3324e18432 Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Tue, 30 Jan 2024 11:54:49 -0800 Subject: [PATCH 04/10] Add docker setup instructions to cover logging in --- docker/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docker/README.md b/docker/README.md index 9ea38a0cb..144ba8221 100644 --- a/docker/README.md +++ b/docker/README.md @@ -22,8 +22,11 @@ steps to prepare your environment: 4. Run `docker compose up -d` to start the services in the background (the `-d` flag). 5. Install application dependencies via yarn: `docker compose exec app yarn`. 6. Visit http://localhost:8080 to confirm you see 'Grants Identification Tool' with a prompt to enter an email address. -If you see a blank screen, [review the logs](#cookbook-logs), you may need to [run a db migrate](#cookbook-db-migrate) and restart the app container. - + - If you see a blank screen, [review the logs](#cookbook-logs), you may need to [run a db migrate](#cookbook-db-migrate) and restart the app container. +7. To enable logging in, seed the DB with data and use one of the generic login emails + - Run the DB seed script: `docker compose exec app yarn db:seed` + - At the login page, enter either `admin@usdigitalresponse.org` or `staff@usdigitalresponse.org` + - Check the logs for a generated login URL `docker compose logs -f app` and open it! **Note:** Some systems may have Docker Compose installed as an integrated plugin for Docker, while others may have it installed as a standalone executable (e.g. via `pip install`). From 63ed516586452295976645c5be0d9c75d1f537c4 Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Tue, 30 Jan 2024 12:01:26 -0800 Subject: [PATCH 05/10] Add warning on setup gmail docs --- docs/setup-gmail.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/setup-gmail.md b/docs/setup-gmail.md index 79ee2348c..d6e152e0c 100644 --- a/docs/setup-gmail.md +++ b/docs/setup-gmail.md @@ -1,5 +1,8 @@ # GMail Setup +> [!WARNING] +> Email setup is generally not required for local development, unless you're directly working on email templates or sending. + Users log into the app by means of a single-use link that is sent to their email. In order to set your app up to send this email, you'll need to setup an App Password in Gmail. Visit: and set up an "App Password" (see screenshot below). *Note: Select "Mac" even if you're not using a Mac.* From 0cd53e4cec9fae9f0b78d53ecac7a5923001971d Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Tue, 30 Jan 2024 16:06:12 -0800 Subject: [PATCH 06/10] Update test to account for 2 additional users --- packages/server/__tests__/api/users.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/__tests__/api/users.test.js b/packages/server/__tests__/api/users.test.js index 0fc5c146a..d894a27e1 100644 --- a/packages/server/__tests__/api/users.test.js +++ b/packages/server/__tests__/api/users.test.js @@ -158,7 +158,7 @@ describe('`/api/users` endpoint', () => { const response = await fetchApi(`/users`, agencies.own, fetchOptions.admin); expect(response.statusText).to.equal('OK'); const json = await response.json(); - expect(json.length).to.equal(12); + expect(json.length).to.equal(14); }); it('lists users for an agency outside this user\'s hierarchy but in the same tenant', async () => { const response = await fetchApi(`/users`, agencies.offLimits, fetchOptions.admin); From e3ee1af7a3cbcc9ad8ec65e4f032c81f70baba69 Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Tue, 30 Jan 2024 16:16:39 -0800 Subject: [PATCH 07/10] Use clearly fake emails for dev logins --- docker/README.md | 2 +- packages/server/seeds/dev/ref/users.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/README.md b/docker/README.md index 144ba8221..752f51efb 100644 --- a/docker/README.md +++ b/docker/README.md @@ -25,7 +25,7 @@ steps to prepare your environment: - If you see a blank screen, [review the logs](#cookbook-logs), you may need to [run a db migrate](#cookbook-db-migrate) and restart the app container. 7. To enable logging in, seed the DB with data and use one of the generic login emails - Run the DB seed script: `docker compose exec app yarn db:seed` - - At the login page, enter either `admin@usdigitalresponse.org` or `staff@usdigitalresponse.org` + - At the login page, enter either `admin@example.com` or `staff@example.com` - Check the logs for a generated login URL `docker compose logs -f app` and open it! **Note:** Some systems may have Docker Compose installed as an integrated plugin for Docker, diff --git a/packages/server/seeds/dev/ref/users.js b/packages/server/seeds/dev/ref/users.js index 613cd99f0..4899ae81e 100644 --- a/packages/server/seeds/dev/ref/users.js +++ b/packages/server/seeds/dev/ref/users.js @@ -149,7 +149,7 @@ module.exports = [ }, { id: 17, - email: 'admin@usdigitalresponse.org', + email: 'admin@example.com', name: 'USDR Admin', agency_id: usdrAgency.id, role_id: adminRole.id, @@ -157,7 +157,7 @@ module.exports = [ }, { id: 18, - email: 'staff@usdigitalresponse.org', + email: 'staff@example.com', name: 'USDR Staff', agency_id: usdrAgency.id, role_id: staffRole.id, From 1bfb6b8f85bff5938f08b3bd5c74def9c27f5c02 Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Tue, 30 Jan 2024 16:22:11 -0800 Subject: [PATCH 08/10] Add a bit more warning to the gmail setup docs --- docs/setup-gmail.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/setup-gmail.md b/docs/setup-gmail.md index d6e152e0c..eb7163de2 100644 --- a/docs/setup-gmail.md +++ b/docs/setup-gmail.md @@ -1,7 +1,7 @@ # GMail Setup > [!WARNING] -> Email setup is generally not required for local development, unless you're directly working on email templates or sending. +> Email setup is generally not required for local development, unless you're directly working on email templates or sending. Note that with this setup you will send real emails — please ensure you don't have real external email addresses in your database that you could accidentally mail. Please revert these environment variables to disable email sending anytime you're not actively developing email. Users log into the app by means of a single-use link that is sent to their email. In order to set your app up to send this email, you'll need to setup an App Password in Gmail. From 6d7c7ddd362cd231035508b60a9d54e35f3099d2 Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Tue, 30 Jan 2024 16:30:52 -0800 Subject: [PATCH 09/10] Update tests to avoid duplicate email error --- packages/server/__tests__/api/agencies.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/__tests__/api/agencies.test.js b/packages/server/__tests__/api/agencies.test.js index e73cf3842..f8bbeca5b 100644 --- a/packages/server/__tests__/api/agencies.test.js +++ b/packages/server/__tests__/api/agencies.test.js @@ -90,7 +90,7 @@ describe('`/api/organizations/:organizationId/agencies` endpoint', () => { before(async () => { admin = await createUser({ name: 'Test Admin', - email: 'admin@example.com', + email: 'adminuser@example.com', agency_id: 0, tenant_id: 1, role_id: fixtures.roles.adminRole.id, @@ -130,7 +130,7 @@ describe('`/api/organizations/:organizationId/agencies` endpoint', () => { it('issues 400 Bad Request when agency has users', async () => { const blockingUser = await createUser({ name: 'Some One', - email: 'staff@example.com', + email: 'staffuser@example.com', agency_id: agency.id, tenant_id: agency.tenant_id, role_id: fixtures.roles.staffRole.id, From 60a90ba968b8a73ae4f716b94cb5a7417257c8c6 Mon Sep 17 00:00:00 2001 From: Jeff Mohan Date: Thu, 1 Feb 2024 12:04:00 -0800 Subject: [PATCH 10/10] Make test less brittle --- packages/server/__tests__/api/users.test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/server/__tests__/api/users.test.js b/packages/server/__tests__/api/users.test.js index d894a27e1..46a8b7b2c 100644 --- a/packages/server/__tests__/api/users.test.js +++ b/packages/server/__tests__/api/users.test.js @@ -1,6 +1,6 @@ const { expect } = require('chai'); const sinon = require('sinon'); -const { getSessionCookie, makeTestServer } = require('./utils'); +const { getSessionCookie, makeTestServer, knex } = require('./utils'); const email = require('../../src/lib/email'); const emailConstants = require('../../src/lib/email/constants'); @@ -158,7 +158,11 @@ describe('`/api/users` endpoint', () => { const response = await fetchApi(`/users`, agencies.own, fetchOptions.admin); expect(response.statusText).to.equal('OK'); const json = await response.json(); - expect(json.length).to.equal(14); + const ownAgency = await knex('agencies').where({ id: agencies.own }).first(); + const expectedUserCount = ( + await knex('users').where({ tenant_id: ownAgency.tenant_id }).count().first() + ).count; + expect(json.length).to.equal(parseInt(expectedUserCount, 10)); }); it('lists users for an agency outside this user\'s hierarchy but in the same tenant', async () => { const response = await fetchApi(`/users`, agencies.offLimits, fetchOptions.admin);