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

feat: implement basic user component #5

Merged
merged 2 commits into from
Aug 17, 2018
Merged

feat: implement basic user component #5

merged 2 commits into from
Aug 17, 2018

Conversation

virkt25
Copy link
Contributor

@virkt25 virkt25 commented Aug 16, 2018

implements the remainder of loopbackio/loopback-next#1480

@virkt25 virkt25 self-assigned this Aug 16, 2018
@virkt25 virkt25 requested review from raymondfeng and a team August 16, 2018 21:18
package.json Outdated
"@loopback/repository": "^0.14.2",
"@loopback/rest": "^0.19.2",
"@loopback/openapi-v3": "^0.12.2"
"@types/bcrypt": "^2.0.0",
"bcrypt": "^3.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for using that modules over the one I'm using?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bcrypt is a binary add-on and it requires compilation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we don't want that? CI was failing before because I was running install with --ignore-scripts. The JS version is about 30% slower according to their own docs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plain JS module is much more desirable for an example app. It will remove a lot of support issues in the future.

Copy link

@shimks shimks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fire

package.json Outdated
"@loopback/repository": "^0.14.2",
"@loopback/rest": "^0.19.2",
"@loopback/openapi-v3": "^0.12.2"
"@types/bcrypt": "^2.0.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reinstall as dev dependency?

}

// Validate Password Length
if (obj.password.length < 8) {
Copy link

@shimks shimks Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a temporary solution to the fact that we are not supporting authentication atm? I would have assumed that the password at the framework level would have been hashed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a default User model like we did in LB3 which is where these checks / hashing would've been implemented. So for now people would have the flexibility to implement User how they want.

@@ -5,7 +5,7 @@

import {createClientForHandler, supertest} from '@loopback/testlab';
import {RestServer} from '@loopback/rest';
import {ShoppingApplication} from '../';
import {ShoppingApplication} from '../..';
Copy link

@shimks shimks Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably a good reminder for us to change the template generated by our app generator so that this file lives in the acceptance folder

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shimks @virkt25 could you please create a follow up issue or open a pull request to fix the template? Otherwise we are most likely going to forget about this.

.send(user)
.expect(200)
// tslint:disable-next-line:no-any
.expect(function(res: any) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not all that important, but we can use the supertest's promise support here:

const response = await client.post('/users').send(user).expect(200);
// assertions

@@ -0,0 +1,14 @@
import {inject} from '@loopback/core';

This comment was marked as resolved.


if [ $TASK = "test" ]; then
echo "TASK => MONGODB STARTUP DELAY"
sleep 10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a check for mongodb service / process here instead of using sleep?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would have to check and sleep / something if the service isn't up and ready yet anyways. This is the fix recommended by Travis themselves, documented here: https://docs.travis-ci.com/user/database-setup/#mongodb-does-not-immediately-accept-connections

bin/setup.sh Outdated
@@ -0,0 +1,3 @@
docker rm -f mongodb_c
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a variable to represent the name of the container? Feel free to ignore as this can be done later if need be.

) {}

@post('/users')
async create(@requestBody() obj: User): Promise<User> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: I suggest we rename obj to userObj or user or something along those lines

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the default we generate using the lb4 controller command but a good call. Will update.

@get('/users/{id}')
async findById(@param.path.string('id') id: string): Promise<User> {
const user = await this.userRepository.findById(id);
delete user.password;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if juggler can take care of this for us using some sort of flag.

Copy link

@shimks shimks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this PR, do we want to have a separate datasource and docker configured for just testing? I'd imagine we don't want to run any tests on potentially existing data

.expect(415);
});

it('returns a user with given id when POST /user/{id} is invoked', async () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

POST -> GET

});

it('returns a user with given id when POST /user/{id} is invoked', async () => {
const userWithId = Object.assign({}, user, {id: userId});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of setting userId in a separate test, I think it's better for the user to be created in the test (through the repository), set the userId, and then call the endpoint. This allows tests to not be dependent upon each other.

Also, the created user instances need to be deleted after each tests

@virkt25 virkt25 merged commit 0eeb580 into master Aug 17, 2018
@virkt25 virkt25 deleted the user branch August 17, 2018 23:24

// Save & Return Result
const savedUser = await this.userRepository.create(user);
delete savedUser.password;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is good enough for the initial implementation, it is also very brittle. We should find a more robust way how to allow models to hide certain properties from toJSON output.

In the past, I had very good experience with moving the password to a different model (table/collection) and use hasMany relation. As a nice side effect, by keeping a hash of all previous passwords, we can easily implement a password policy like "cannot reuse the same password".

@get('/users/{id}')
async findById(@param.path.string('id') id: string): Promise<User> {
const user = await this.userRepository.findById(id, {
fields: {password: false},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here.

@@ -5,7 +5,7 @@

import {createClientForHandler, supertest} from '@loopback/testlab';
import {RestServer} from '@loopback/rest';
import {ShoppingApplication} from '../';
import {ShoppingApplication} from '../..';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shimks @virkt25 could you please create a follow up issue or open a pull request to fix the template? Otherwise we are most likely going to forget about this.

let client: supertest.SuperTest<supertest.Test>;
const userRepo = new UserRepository(new UserDataSource());

const user = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer us to follow our own best practices, see Use data builders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants