Pass user object to model life cycle event in Sails.js - node.js

I'm interested if anyone had managed to pass current logged in user to lifecycle events
I would like to pass the user to the lifecycle events function to keep track of the user making the changes.

I don't think there is a clean way to do this. Even if you don't mind digging into (and modifying) the framework code, I think you'd have to make a few modifications in a few places:
1 - You'd have to override Model.create to accept a req parameter (or something else you can use to get the logged in user).
2 - You'd have to make sure that all uses in the code (yours AND the sails library's) of Model.create pass in the required parameter. In particular...
3 - You'd have to modify the default action caught by POST /create/[modelname] so that it passed in the appropriate parameters to Model.create
Given that that is a lot of steps (and I likely missed some), I'd recommend another approach:
1 - Disable the REST create route from your /config/blueprints.js file.
2 - Funnel all model creation through a custom method. (Could be a directly exposed controller method, or something in /api/services, or in the model itself). Make sure the method gets access to the logged in user, attach it as data to the model, THEN call the default Model.create from within your custom method.

Related

Catel using IEditableObject

I am testing Catel MVVM and I would like to use the implemented IEditableObject. I have got some questions, but the documentation I've found, isn't very detailed in this point.
Did someone have a helpful link, how I have to set this up or how it works, or something like this? Or should I really have a look to the source code, to get these points and get a feeling, how catel do the work.
The questions, that I have got, are these:
What exactly does the method SaveViewModelAsync()?
Where does it save the data, or where can I configurate it?
How can I use it with Orc.EntityFramework6, or do I have this manually?
What's the different between SaveViewModelAsync() and SaveAsync()?
What's the different between CancelViewModelAsync() and CancelAsync()?
I can only cancel the editing one time. If I edit the same ViewModel again, the cancel has no effect anymore.
I think there is only an BeginEdit() missing after the first cancel, like this documentation suggests. Here some informations to this point:
I edit the ViewModel and the Model set the new value
I execute CancelViewModelAsync(), the setter in the Model is not touched
I edit the ViewModel and the Model set the new value. The current value is the original value
I execute CancelViewModelAsync(), nothing happened
I edit the ViewModel and the Model set the new value. The current value is the edited value from step 3, like the View shows
Thanks for help
Lots of questions in a single question, but will try to answer them:
Q1) What exactly does the method SaveViewModelAsync()
It calls IEditableObject.EndEdit on all models that support it (and are decorated with the ModelAttribute
Q2) Where does it save the data, or where can I configurate it?
It just approves the changes to the model, it doesn't "save" anything. So for example, if you are using Catel models, it will commit the changes made by the VM. If you would cancel, it would revert the model back to the state it was when you initialized the VM.
Q3) How can I use it with Orc.EntityFramework6, or do I have this manually?
You have to do this manually. The VM's in Catel work with models, it's up to you when / where you persist them to (e.g. a database, disk, web service, etc)
Q4) What's the different between SaveViewModelAsync() and SaveAsync()?
SaveViewModelAsync is the public method being called and takes care of the plumbing for you. SaveAsync is a method you can override to add additional save logic (e.g. storing in database, update services, etc).
Q5) What's the different between CancelViewModelAsync() and CancelAsync()?
See Q4

Mongoose middleware disable(/unhook/delete/remove) created hooks

In an express/mongoose server application, I want to receive a request, then change state to one which can receive another type of request, and when the second request completes successfully I want to respond to the first one.
The way I've implemented this is to use a placeholder document in MongoDB, and set a mongoose post save hook upon receiving the first request. This async middleware is a closure which holds a reference to the response from the first request.
The second request modifies this placeholder document with new information from another remote client. Upon saving this, the post save hook gets run, which determines if this is the correct document, and validates the change w.r.t the first request. If that passes, the first response is sent. Otherwise, the hook continues waiting for the correct change, checking all the saves that happen to that schema.
My problem is that even after the correct and accepted changes happen and the response is returned to the first client, the (shell) post-save hook still remains. Now, this does return instantly upon seeing that the response has been sent successfully, but it bothers me that it still exists and gets called for all saves.
This is an application that's meant to run with an anticipated 1k-10k such requests over its lifetime. So unless the application is periodically restarted, we might see a significant slowdown from all the post-save hooks getting called.
Now, onto the questions:
Is there a better/easier/straightforward architecture to solve this problem?
If not, should I be worried about all the shell post-save hooks for this use case?
If so, how do I delete a freaking hook?
This is a far more infuriating issue than usual with this sort of thing because of the existence of 'remove' hooks. All the search engines fail to actually point me to disabling/deleting/unhooking/removing middleware functions. Nothing in the docs either.
The best I can come up with is to use a single-argument middleware function, and then overwrite that function with {} or undefined (or another closure function if we encounter another request-type-1). Is this the only solution? With this, I lose the ability to make and retain responses of multiple request-type-1s.
Found two methods of doing this, one from this answer to delete specific entries in the call queue of the schema.
EDIT: The following doesn't work with Mongoose as of 5.1.5 - removePost isn't defined.
The other (better) one was found when perusing the codebase used to implement hooks.
You can remove a post by using
Document.post('set', someFn); // Setting it
Document.removePost('set', someFn); // Removing it

Designing an express API with user-created custom paths conflicting with other api end points

In my express app, a user can create a profile, and in doing so can choose a 'CustomUrl' that will be used to generate the url for their profile (example: http://www.myapp.com/profile/customUrl). A profile can also be reviewed, the end points for which might look like:
router.get('/reviews', ...) and router.post('/reviews/new',...)
The API endpoint for fetching a profile is below:
router.get('/:customUrl',...)
While I don't think a user would pick a customUrl like 'reviews', it is possible, and as such, my API endpoint to fetch their profile would be intercepted by the route to get '/reviews'.
I have a few ideas, but I'm generally new to Express, and wasn't sure if one way was better than another. Here are some of them:
1) I can put any end-point with a customUrl path above other end points. This doesn't sound acceptable as then the customUrl path would intercept any requests that are meant for '/reviews' etc.
2) I can validate a customUrl that it is not only unique, but is not an existing end point. This does not seem satisfactory as it does not scale well (would have to update the blacklist every time I add a new end point). It would also be problematic if a user has selected a customUrl that I later want to use for another end point.
3) Separate review out of profile and into its own route. This is probably the best solution, although it would present a lot of work that I'm hoping to avoid (there are other sub-routes name-spaced under '/profiles').
4) Put router.get('/reviews'...) above customUrl, but call next() if there is no req.query ('?sortBy=dateCreate' etc).
5) I didn't mention this earlier because it feels like I'd only be hiding the problem instead of fixing it, but my client-side is in React on a separate port, and so I could configure the router to display the url as .com/profile/:customUrl, but change the API end point to be something like: router.get('/',...) with a queryString of '?customUrl=...' or something like that. The url would then be 'www.myApp.com/profile/:customUrl' but the get request would be to 'api.myApp.com/profile/?customUrl=:customUrl', and the get request for reviews would be 'api.myApp.com/profile/reviews' (or something like that).
Anyway, I have a feeling that I'm missing something pretty fundamental. Any help would be great!
You probably just need to be RESTful with your route naming, for example:
GETing profile:
router.get('/profile/:customUrl', ...)
GETting reviews for a profile
router.get('/profile/:customUrl/reviews', ...)
POSTing a new review (note you don't need a route that says "new" as this can be determined by it being a POST request)
router.post('/profile/:customUrl/reviews',...)
You should use the following verbs for the reasons listed if you are being truly RESTful:
GET - Fetching records
POST - Adding records
PUT - Editing records
PATCH - Performing partial edits (e.g. not sending the whole document)
DELETE - Removing records

How to prevent use of conflicting keywords in REST api calls in Express

If I am creating a REST api with express for an application, as far as I'm aware, the order of the route definitions matter. For example, if I wrote my routes in the following order:
app.get('/users/:username', user.get);
app.get('/users/list', user.listAll);
then user.listAll could never be reached and the server would assign 'list' to the username parameter when a request was made to '/users/list'. So it's obvious that you want to reverse the order of the declaration of these routes. But here, we'll run into the same problem if a user creates an account with the username 'list', right?
So how do you prevent users from creating names with 'keywords' where keywords are defined here as strings that would conflict with the api routes.
I can think of two ways, but neither of them seem satisfying. First, you could keep a blacklist of strings that you compare against each username creation. But maintaining that would be a nightmare. And two, just pre-create those users in the database (as long as usernames are unique). That kind of seems a bit hacky but I can't think of many arguments against it.
Is there a simple solution to this problem?
Good question. I've faced this a while ago. You must be coming from a web background like me, because you are trying to use the 'slug' method to make user readable calls to the API. Using readable slugs is great and actually preferred in websites! There is actually not 1 way to do it in API's I've seen many ways that work, but I only know 1 way of making it scalable and descriptive in a way that works for almost every usecase.
Always use ID's
One user: /users/:id
List: /users/
Friends: /users/:id/friends
1 friend of 1 user: /users/:id/friends/:id
Above is extendable and still descriptive! In addition I use versioning. (ex: /v1/users). This allows me to upgrade the API to a v2 while still supporting older clients :)
Now how do I lookup a specific user? Use filters!.. How?
/v1/users?username=:username
The above will always return a list of users. If username is unique this will still be a list, but only 1 record or just an empty list.
Use HTTP methods POST PUT GET DELETE
POST on /users (201 created user)
PUT/DELETE on /users (400 method not allowed) (optionally remove all??? Not recommended)
PUT / DELETE on /users/:id (200 success)
POST on /users/:id (400 user already exists)
Hope this will solve your case :)

Unobvious model change

In a angularjs/express/postgres app, i want to load big list of json object from the db to the client.
Each json object is it's self pretty big. Each on is stored in a separate row.
So i want to display each json object as soon as they are read from db.
I've found the EventSource api, to progressivly send the json object from server to client.
Which works fine.
Then i want to display them on my view as soon as possible.
Working with event source include working with event listeners.
As explain here https://groups.google.com/forum/?fromgroups=#!topic/angular/xMkm81VkR9w
the angular won't notice the change of the model since the scope modification occurs outside the angular world, inside a event listener.
There is a way to trigger to dirty cheking by calling $scope.$apply().
But since my list as more than 200 element, this error is triggered:
Error: 10 $digest() iterations reached. Aborting!
So i'm wondering if there is another way to trigger the dirty checking ? Maybe another way to approch my issue.
EDIT:
The title was changed after reflection on the real problem
In fact the issue come from the partial, where i add filter expression in a ng-show directive
My bad

Resources