Skip to content
This repository has been archived by the owner on Sep 21, 2023. It is now read-only.

Commit

Permalink
Fix build and clarify set up instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
jjjjjjjjjjjjjjjjjjjj committed Sep 20, 2023
1 parent 5f07cd1 commit ef9d5e3
Show file tree
Hide file tree
Showing 10 changed files with 51 additions and 27 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PGUSER=postgres
PGPASSWORD=postgres
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,7 @@ package-lock.json
# MacOS
.DS_Store

bin
# Environment variables
.env

bin
30 changes: 24 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Take home test for Node.js developers.

## The challenge

This challenge has been designed to measure your knowledge of Node.js, Express, Typescript and various technologies, like monorepos, databases and testing. For your exercise, you will be enhancing this API which serves as the backend for the Pleo app. Whenever a user of the app navigates to the expenses view, it calls this API to collect the list of expenses for that user.
This challenge has been designed to measure your knowledge of Node.js, Express, Typescript and various technologies, like monorepos, databases and testing. For your exercise, you will be enhancing this API which serves as the backend for a fictional Pleo app. Whenever a user of the app navigates to the expenses view, it calls this API to collect the list of expenses for that user.

Your objective is to write this new route to fetch the list of expenses for a given user. Right now that domain is empty, so you'll have to build everything from scratch- but you can look over at the user domain for inspiration. Please make sure that the endpoint scales adequately and supports paging, sorting and filtering. Additionally, we would also like you to write some tests for your route.

Expand All @@ -16,29 +16,47 @@ Fork this repo with your solution. Ideally, we'd like to see your progression th

Please let us know how long the challenge takes you. We're not looking for how speedy or lengthy you are. It's just really to give us a clearer idea of what you've produced in the time you decided to take. Feel free to go as big or as small as you want.

## Install
## Installing

Make sure that you have a modern version of `yarn` that supports workspaces (`>= 1.0`), then run:

```bash
yarn
```

You will also need to [install Postgres](https://www.postgresqltutorial.com/install-postgresql-macos/), create a `challenge` database and load the sql file `dump.sql`:
Start a Postgres Docker container, or alternatively run postgres outside docker.

```bash
psql challenge < dump.sql
docker run --name pleo-postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres
```

## Start
Copy the `.env.example` file as `.env` and optionally update it to reflect the proper authentication for your locally running Postgres instance.

```bash
cp .env.example .env
```

Create a `pleo_node_challenge` database in your local instance. The following two steps assume your local postgres instance is running and accessible on 0.0.0.0:5432 as user `postgres` with password `postgres`. Please update below connection string accordingly if that's not the case.

```bash
psql -d "postgresql://postgres:[email protected]" -c 'CREATE DATABASE pleo_node_challenge'
```

Insert some dummy data:

```bash
psql -d "postgresql://postgres:[email protected]/pleo_node_challenge" < insert-dummy-data.sql
```

## Running

To enable logs, use the standard `NODE_DEBUG` flag with the value `DEBUG`

```bash
NODE_DEBUG=DEBUG yarn start
```

## Test
## Testing

Make sure that you have a modern version of `yarn` that supports workspaces, then run:

Expand Down
2 changes: 1 addition & 1 deletion config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = {
db: {
host: '0.0.0.0',
port: 5432,
database: 'challenge',
database: 'pleo_node_challenge',
},
debug: {
stackSize: 4,
Expand Down
4 changes: 2 additions & 2 deletions dump.sql → insert-dummy-data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ f3f34c29-274a-414d-988f-711802eeac25 BRUS 5000 DKK 3d16547a-79f6-4f62-9034-d3bfb

COPY public.users (id, first_name, last_name, company_name, ssn) FROM stdin;
da140a29-ae80-4f0e-a62d-6c2d2bc8a474 jeppe rindom pleo 1
e17825a6-ad80-41bb-a76b-c5ee17b2f29d petr janda pleo 2
3d16547a-79f6-4f62-9034-d3bfb31fb37c olov eriksson pleo 3
e17825a6-ad80-41bb-a76b-c5ee17b2f29d nicco perra pleo 2
3d16547a-79f6-4f62-9034-d3bfb31fb37c jane doe pleo 3
\.


Expand Down
4 changes: 2 additions & 2 deletions packages/domains/user/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export function capitalize(word) {
return str[0].toUpperCase() + str.slice(1);
}

export function secureTrim(user: User): string {
return JSON.stringify(user, publicFields);
export function redactSensitiveFields(user: User): Pick<User, 'first_name' | 'last_name' | 'company_name'> {
return JSON.parse(JSON.stringify(user, publicFields));
}

export function format(rawUser): User {
Expand Down
4 changes: 2 additions & 2 deletions packages/domains/user/routes/v1-get-user.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ApiError } from '@nc/utils/errors';
import { getUserDetails } from '../model';
import { redactSensitiveFields } from '../formatter';
import { Router } from 'express';
import { secureTrim } from '../formatter';
import { to } from '@nc/utils/async';

export const router = Router();
Expand All @@ -17,5 +17,5 @@ router.get('/get-user-details', async (req, res, next) => {
return res.json({});
}

return res.json(secureTrim(userDetails));
return res.json(redactSensitiveFields(userDetails));
});
15 changes: 8 additions & 7 deletions packages/domains/user/tests/formatter.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { capitalize, format, secureTrim } from '../formatter';
import { capitalize, format, redactSensitiveFields } from '../formatter';

describe('[Packages | User-domain | Formatter] capitalize', () => {
test('capitalize should make the first character as a capital letter', () => {
Expand All @@ -18,18 +18,19 @@ describe('[Packages | User-domain | Formatter] capitalize', () => {
});
});

describe('[Packages | User-domain | Formatter] secureTrim', () => {
test('secureTrim should remove fields that are not defined in the list of public fields', () => {
return expect(secureTrim({
describe('[Packages | User-domain | Formatter] redactSensitiveFields', () => {
test('redactSensitiveFields should remove fields that are not defined in the list of public fields', () => {
return expect(redactSensitiveFields({
id: '18d60d19-e747-4365-92e8-d8951eb47904',
first_name: 'John',
last_name: 'Smith',
company_name: 'Pleo',
ssn: 1,
})).toEqual(JSON.stringify({
ssn: '1230',
})).toEqual({
first_name: 'John',
last_name: 'Smith',
company_name: 'Pleo',
}));
});
});
});

Expand Down
8 changes: 6 additions & 2 deletions server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { createServer as createHTTPSServer, Server as SecureServer } from 'https

const logger = Logger('server');
const app = express();
const server: Server | SecureServer = (config.https.enabled === true) ? createHTTPSServer(config.https, app as any) : createHTTPServer(app as any);
const server: (Server | SecureServer) & {ready?: boolean} = (config.https.enabled === true) ? createHTTPSServer(config.https, app as any) : createHTTPServer(app as any);
server.ready = false;

gracefulShutdown(server);
Expand All @@ -31,7 +31,11 @@ app.use(security);

app.use('/user', userRoutes);

app.use(function(err, req, res) {
app.use(function(err, req, res, next) {
if (res.headersSent) {
return next(err);
}

res.status(500).json(err);
});

Expand Down
4 changes: 0 additions & 4 deletions test/utils/jest/config-injector.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import config from 'config';

config.auth.jwtSecret = 'some-fake-key';

process.env.TEST_MODE = 'test';

process.on('unhandledRejection', (err: Error) => process.stderr.write(`unhandledRejection: ${err.stack}\n`));

0 comments on commit ef9d5e3

Please sign in to comment.