Accessing url parameters in sails action - javascript

I have a sails app, and I am agttempting to load a page with some data from a database, based on the id of the recipe model.
I have the route 'GET /recipes/single-recipe/:id': { action: 'recipes/view-single-recipe' } set up, and am accessing the url http://localhost:1337/recipes/single-recipe/5b8c169936f1df3439fa39c7
In my view-single-recipe action I'm attempting to load the recipe with the id of the URL parameter by accessing req.param('id') but req is showing undefined.
//view-single-recipe.js
module.exports = {
friendlyName: 'View single recipe',
description: 'Display "Single recipe" page.',
exits: {
success: {
viewTemplatePath: 'pages/recipes/single-recipe'
}
},
fn: async function(inputs, exits) {
const recipe = await Recipe.find({
id: req.param('id') //req undefiend
});
// Respond with view.
return exits.success({
recipe: recipe
});
}
};
Getting error: error: Sending 500 ("Server Error") response:
ReferenceError: req is not defined
How can I load the correct recipe using the url param?

If you have the route /recipes/single-recipe/:id', then the "id" from the URL path will be available as req.params.id. Otherwise, it defaults to {} For more info
UPDATE:
But when it comes to Actions and Controllers, Sails.js uses the machine-as-action module to automatically create route-handling functions out of machines like the example shows. See the machine-as-action docs for more information.
Note that machine-as-action provides actions with access to the request object as this.req instead of just req, otherwise, there'll be a server error of req is not defined. So, for future references don't forget the this keyword.

Related

One drive api secure url

Short:
I am unable to find any setting in documentation one drive api to get a file url that could not be accessed without access token
Details:
I tried different things with queryParameters: "select=id,name,size,file" but could not change the result
Using javascript API, when files chosen from one it gives an array named values in which each object contains properties like (some fake but sample values)
#microsoft.graph.downloadUrl: "https://public.sn.files.1drv.com/m7ZHglUdfkMkwg-qqnNj8"
#odata.context: "https://graph.microsoft.com/v1.0/$metadata#drives('D2CFA54CB9FFC341')/items/$entity"
id: "FA4454CB9FFC341!172"
name: "sada.pdf"
size: 4344
My code to get above results is
var odOptions = {
clientId: "df45ae45-68bd-4568-a473-4159a1b16fc1",
action: "download",
multiSelect: true,
// openInNewWindow: true,
// advanced: {
// queryParameters: "/drive/root/children?select=id,name,size,file",
// },
success: function (response) {
console.log(555, response);
},
cancel: function (response) { console.log(response); },
error: function (e) { console.log(e); }
};
OneDrive.open(odOptions);
the problen is https://public.sn.files.. public url (any one can access file without login using this url) unlike google drive which gives a secure url
The downloadUrl is a short lived URL that is preauthenticated so that authorization is not required. Access control checks are instead performed on the request that returns the URL. A flow that's closer to what Google Drive utilizes would be to hit the /content endpoint for a specific file - this request requires an OAuth token to be provided and will return the binary content.

Pass a NodeJS express object to AngularJS 1.6

I have a working NodeJS API using Express. I am confused how to properly pass in a parameter from NodeJS to AngularJS in order to retrieve the data for the page.
Note: My question is an extension (not a repeat) of this question:
How do I pass node.js server variables into my angular/html view?
I have set up two routes, one to render the page and one to return the JSON object based on the Book ID (the unique ID of the entity). When the page loads, Angular uses $http to send a GET request to get the data from a JSON endpoint.
This is working, but I have hard-coded an example Book ID in Angular.
Question: How can I pass the Book ID to the Angular controller?
/*EXPRESS ROUTES*/
//Render page
router
.route('/detail/:book_id')
.get(ctrlRequest.detailPage);
//Return JSON data
router
.route('/detail/json/:book_id')
.get(ctrlRequest.detailJSON);
/*NODEJS CONTROLLERS*/
//Render page
module.exports.detailPage = function(req, res) {
res.render('transfer_request_detail.pug', {
title: 'Transfer Request Detail'
});
};
//Return JSON data
module.exports.detailJSON = function(req, res) {
getModel().read(req.params.book_id, (err, entity) => {
if (err) {
console.log('Request Detail JSON unable to return data results. Error message: ', err);
return;
} else {
res.json(entity);
}
});
};
/*ANGULAR WITH HARD-CODED BOOK ID*/
//QUESTION: HOW TO PASS THE BOOK ID IN DYNAMICALLY?
function DetailPageController($http) {
var vm = this;
$http({
url: '/detail/json/5761233819297931', //HARD-CODED ID HOW TO PASS IN DYNAMICALLY?
method: 'GET'
}).then(function (response){
vm.book = response.data;
console.log('API worked', response);
},function (error){
console.log('API error: ', error);
});
}
UPDATE:
"This probably depends on how your application is used. For example, the app might display a list of Books fetched from Express, and the user clicks one to see the detail page. In that case, the frontend fetches the complete list of Book ID's from Express. Can you please outline the behavior of your application?"
Use Case 1:
After the user submits a the New Book form, the Node app will redirect to the URL that renders the detail page. '/detail/:book_id'. I want to use Angular to build a datatable to display the details of the book that was created.
Use Case 2:
Another use case in the future will be to display all books that were created by the logged-in user. In this case, I want to use Angular to display all the books in a datatable. The route will be something like '/mybooks/:username'. Also, the user should also be able to click on a link that brings them to the details page (use case 1) for single book.
UPDATE 2:
I tried using routeParams to extract the ID out of the URL. It appears to be exactly what I need however it isn't working. Note that the routes were created on the server side with Express, not Angular.
$routeParams //Object
$routeParams.book_id //undefined
https://docs.angularjs.org/api/ngRoute/service/$routeParams
UPDATE 3:
I was able to solve this with a bit of a hacky workaround. I'm not super satisfied with this solution since it is quite hacky but at least it works for the time being.
I used this code in the Angular controller to extract the ID from the URL.
var relpath = $location.path().split('/');
var book_id = relpath[3];
UPDATE 4:
So it looks like I am back to square one. This solution broke the express routing. I am now having the same issue as described in this thread because locationProvider HTML mode is enabled to get this solution to work. Pages aren't loading when clicking on menu links, they are only loading when typed in directly.
Angular routing doesn't work when URL is directly visited in browser but works when clicked to?
You can use template literals: in your url string.
function DetailPageController($http, id = 5761233819297931) {
var vm = this;
$http({
url: `/detail/json/${id}`, //HARD-CODED ID HOW TO PASS IN DYNAMICALLY?
method: 'GET'
}).then(function (response){
vm.book = response.data;
console.log('API worked', response);
},function (error){
console.log('API error: ', error);
});
}

How to get currently logged in user details from Promise object in jhipster based application

I am trying to create 'Order' object in the front end and pushing it into the database using REST services. POJO of 'Order' looks like below
#NotNull
#Field("total")
private BigDecimal total;
#Field("status")
private String status;
#Embedded
public User user;
Now I have a 'Principal' service which is providing information of the currently logged in user.I have tried 'console.log(Principal.identity())' which is returning result as shown below. Here 'User' data is present inside the '$$state' Object.
I am not able to find out how to take 'user' data from promise object and add to the 'Order' object. I have dirty method to get user data by digging inside the Promise object as shown below but I am skeptical about this method.
What is the correct way to get data from Promise in this scenario?
EDIT:
This is jhipster based application. Below is the "Principle" service code
'identity: function (force) {
var deferred = $q.defer();
if (force === true) {
_identity = undefined;
}
// check and see if we have retrieved the identity data from the server.
// if we have, reuse it by immediately resolving
if (angular.isDefined(_identity)) {
deferred.resolve(_identity);
return deferred.promise;
}
// retrieve the identity data from the server, update the identity object, and then resolve.
Account.get().$promise
.then(function (account) {
_identity = account.data;
_authenticated = true;
deferred.resolve(_identity);
Tracker.connect();
})
.catch(function() {
_identity = null;
_authenticated = false;
deferred.resolve(_identity);
});
return deferred.promise;
}'
Here is the jhipster generated method to receive resource from server using ngResource.
'angular.module('hotSpiceApp')
.factory('Order', function ($resource, DateUtils) {
return $resource('api/orders/:id', {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
data = angular.fromJson(data);
return data;
}
},
'update': { method:'PUT' }
});
});'
The Principal.identity() function returns a Promise. First read what is promise.
Then do something like:
Principal.identity().then(function (user) {
var data = {
// other fields
user: user
};
// do something with data only inside this inner function
});
Doing Principal.identity().$$state.value is bad not only because it related on internal implementation of angular's promises but it also won't work in all cases. Promises by nature is asynchronous and this work only because Jhipster caches result of http request which returns current user. But if there are no info about current user at time of your new requst, then Principal.identity().$$state.value will be undefined because first it need to send http request to the server and only after that this promise will be "resolved" (internally it will set the value variable and call function defined in then method).
Also I should note, that you should not pass current user from JS code to the server. You should take current user on server side (from session or something) after request arrived and set it to your model if needed. Never trust user code (code which runs in user's browser). It can inject any value to this request and send it to the server.
Can you explain the way you are retrieving the principal service? If it is returning a promise you need to set the data you want to a local variable in the "then" method.
Now to see what "Principal" service has , you can use the below code in chrome console
angular.element(document.querySelector('html')).injector().get(Principal);

Node.js: POST request sent twice by system

I send JSON POST data via a form in a MEAN environment to my server. On the server side, I process the data inside of a waterfall function, using the async library, including various operations such as:
[...]
- create a database entry for a new author
- create a database entry for a new book
- associate the new book to an author (reference to book ID)
[...]
This is the method called by my route, which handles the associated POST-request:
exports.createAuthor = function(req, res) {
console.log(req.url+' !!!POST REQUEST INCOMING!!! '+req.body);
async.waterfall([
function(callback){
//create Author db entry
},
function(parameter, callback){
//add author to additional directory (db action)
},
function(parameter, callback){
//create book db entry
},
function(parameter, callback){
//associate book to author (db action)
}
], function (err, result) {
console.log('DONE!!!');
res.send('200');
});
}
This is the client-side AngularJS controller code:
searchApp = angular.module("searchApp",[]);
searchApp.controller('authorCreator', function ($scope,$http) {
$scope.tags = [];
$scope.sendAuthor = function(){
alert('I was called!');
$http({
method: 'POST',
url: '/newauthor/',
data: { 'authorname' : $scope.authorName,
'authordescription' : $scope.authorDescr,
'bookname' : $scope.bookName,
'tags' : $scope.tags }
})
.success(function(data){
//no actions yet
})
.error(function(){
//no actions yet
});
};
});
This is the AngularJS form:
<div ng-controller="authorCreator">
<form>
<p>Author name: <input ng-model="authorName"></p>
<p>Author description: <input ng-model="authorDescr"></p>
<p>Book name: <input ng-model="bookName"></p>
<p>Tags:<input ng-model="tags"></p>
<p><button ng-click="sendAuthor()">Send</button></p>
</form>
</div>
I noticed that, if the waterfall-process is "stuck" somewhere, meaning the client does not get an answer to it's request whatsoever, the POST request seems to be sent a second time automatically (as soon as the browser is giving a timeout according to firebug). According to firebug, a second POST request does not seem to be sent by the browser, so the call must be initiated from somewhere else.
I found out by checking the database (multiple documents with identical values, except the ObjectID of course) and monitoring the node.js console window where I output incoming POST data. Again: as soon as the entire waterfall-process completes, hence the client browser does not abort the post request after a while, and res.send('200') executes, the error does not occur (= no multiple db entries).
Can anyone please tell me, who does initiate this second POST request and how may I deactivate it?
Cheers
Igor
Try adding this:
exports.createAuthor = function(req, res) {
if(req.method == 'POST' && req.url = 'REQUESTEDURL'){
console.log('POST REQUEST INCOMING!!! '+req.body);
async.waterfall([
//TODO...
]);
}
Maybe the problem is that the favicon or some other resource is doing a request to
After spending some time on that issue I found out, that this error seems to be based on missing answers to the client (be it via res.json, res.sendfile, ...). Therefore the client seems to re-send the request after some time, thus executing server-side code a second time. Responding to the client in reasonable time solves this issue. Sorry for the confusion.
i "fixed" this by adding
.get('/favicon.ico:1', (req, res) =>{
//do nothing because i dont care
})

AngularJS: Cancel overwriting values $resource object after calling save ();

var User = $resource(
'http://test/index.php'
);
var user = User.get({id:'1'});
// GET: http://test/index.php?id=1
// server returns: { "login":"foo", "name":"bar", "mail":"baz" }
user.name = "qux";
user.$save();
// POST: http://test/index.php?id=1
// server returns: { "login":"foo", "name":"bar", "mail":"qux"}
In this case, when you call the save() user object, properties will be replaced by those that came from the server.
But if the server responds like this:
{
"errors":{
"login":"too short",
"name":"is already using that name.",
"mail":"invalid email."
}
}
User object properties are overwritten and instead, property errors containing these mistakes will come up.
Is there a way to change the behavior of $resource? I would like to check the status of the response and, based on that, decide whether to update the properties of an object or report an error to the user.
Angular's $resource is meant to interact with RESTful web services.
In RESTful web services, if there's an error while saving a resource, you should return an appropriate HTTP status (for example, 400).
Then, you can optionally use the error callback:
user.$save(function (response) {
console.log("success!");
}, function (response) {
console.log("error");
});
For a full list of error HTTP statuses:
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error

Categories