You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+8-6Lines changed: 8 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -82,13 +82,13 @@ Add a user via the graphql playground or a frontend. See example mutations and q
82
82
83
83
Update that user's Document to have the string `admin` in the permissions array. Only an admin can add another admin, so the first user must be done manually. MongoDB Compass is a great tool to modify fields. That user can now add the admin permission or remove the admin permission to or from other users.
84
84
85
-
The UsersService `update` method will update any fields which are valid and not duplicates, even if other fields are invalid or duplicates.
85
+
The `UsersService``update` method will update any fields which are valid and not duplicates, even if other fields are invalid or duplicates.
86
86
87
87
Users can change their `username`, `password`, `email`, or `enabled` status via a mutation. Changing their username will make their token unusable (it won't authenticate when the user presenting the token's username is checked against the token's username). This may or may not be the desired behavior. If using on a front end, make it obvious that you can change your username and it'll log the user out (front end must get a new token via logging in).
88
88
89
89
If a user sets `enabled` to `false` on their account, they cannot log back in (because it is disabled), only an admin can change it back.
90
90
91
-
Because both unique properties username and email can be changed, \_id should be used for many-to-many relationships.
91
+
Because both unique properties `username` and `email` can be changed, `_id` should be used as keys for relationships.
92
92
93
93
See `test/users.e2e-spec.ts` for expected results to mutations and queries.
94
94
@@ -106,7 +106,7 @@ If a user's account property `enabled` is set to false, their token will no long
106
106
107
107
Admin must be set manually as a string in permissions for the first user (add `admin` to the permissions array). That person can then add admin to other users via a mutation. Permissions is an array of strings so that other permissions can be added to allow custom guards.
108
108
109
-
Users can modify or view their own data. Admins can do anything except refresh another user's token, which would allow the admin to impersonate that user.
109
+
Users can modify or view their own data. Admins can do anything except refresh another user's token or change their password, which would allow the admin to impersonate that user.
110
110
111
111
The `UsernameEmailGuard` compares the user's email or username with the same field in a query. If any query or mutation in the resolver has `doAnythingWithUser(username: string)` or `doAnythingWithUser(email: string)` and that email / username matches the user which is requesting the action, it will be approved. Username and email are unique, and the user has already been verified via JWT. **If there is not a username or email in the request, it will pass.** This is because the resolvers will set the action on the user making the request. For example, on `updateUser` if no username is specified, the modification is on the user making the request.
112
112
@@ -138,7 +138,7 @@ The User's Document is accessable in the resolver via `@Context('req')` should i
138
138
139
139
## Relationships
140
140
141
-
To add a relationship with the NestJS Schema first approach and Mongoose there are a few caveats. Take for example a one to many relationship where a Purchase can be made by one user, but a user can have many purchases. Likely, the Purchase GraphQL schema will look like this:
141
+
To add a relationship with the NestJS Schema first approach and Mongoose there are a few caveats. Take for example a one-to-many relationship where a Purchase can be made by one user, but a user can have many purchases. Likely, the Purchase GraphQL schema will look like this:
142
142
143
143
```graphql
144
144
typePurchase {
@@ -148,7 +148,7 @@ type Purchase {
148
148
}
149
149
```
150
150
151
-
Thisallowsausertomakeaquerythatcontainsboththepurchaseanditscustomer'ssubfields (see below for security concerns). TheSchemafirstapproachwillcreateafilethatcontainsthe `Purchase` classwiththe `customer` propertyoftype `User`. ButintheMongoDBdatabaseauserisactuallyjustaMongoID. Itwouldbenicetohavethe `customer` propertybeaunionofa `MongoId` and `User`. ThiswouldallowMongoose's `populate` methodtobeusedtoreplacetheIDwithanactualUser. However, apropertycannotbemademoregenericwhenextendingaclass. FortheMongoDBSchemaandDocument, adifferentfieldfortheforeignkeymustbecreated. Forexample:
151
+
Thisallowsausertomakeaquerythatcontainsboththepurchaseanditscustomer'ssubfields (see below for security concerns). TheSchemafirstapproachwillcreateafilethatcontainsthe `Purchase` class, asdefinedbytheschema above, with the `customer` property of type `User`. For the MongoDB Schema and Document, a different field for the foreign key must be created. For example:
The `customerId` property of the `PurchaseDocument` interface can reference the `ObjectId` and the `customer` property of the `Purchase` class can reference the `User` class. Purchase has only a `customer` property, while the `PurchaseDocument` has both the `customer` and `customerId` properties. This makes sense because a user should never care about how the relationship is built. Below is an example of how the customer's information, including ID, can be queried.
169
+
The `customerId` property of the `PurchaseDocument` interface can reference the `ObjectId` and the `customer` property of the `Purchase` class can reference the `User` class. The `Purchase` class as defined by the schema only has a `customer` property, while the `PurchaseDocument` has both the `customer` and `customerId` properties. This makes sense because a user should never care about how the relationship is built. Below is an example of how the customer's information, including ID, can be queried.
170
170
171
171
```Typescript
172
172
@ResolveProperty()
@@ -189,6 +189,8 @@ query purchase {
189
189
190
190
Keep in mind, the above example would create a security issue as every field of a `User` would be accessable to anyone querying a Location. To fix this, add a new type to the GraphQL schema such as `SanitizedUser` which contains only public fields. Then, the `Purchase.customer` property would be changed from `User` to `SanitizedUser`.
191
191
192
+
It would be nice to have the `customer` property be a union of a `MongoId` and `User`. This would allow Mongoose's `populate` method to be used to replace the `MongoId` with a `User`. However, a property cannot be made more generic when extending a class.
193
+
192
194
## Testing
193
195
194
196
To test, ensure that the environment is different than the `development` environment. When the end to end tests run, they will delete all users in the database specified in the environment file on start. Currently running `npm run test:e2e` will set `NODE_ENV` to `test` based on `package.json` scripts. This will default to the `test.env` file.
0 commit comments