How can i pass input argument when writing loopback-testing - node.js

I am writing a test driven development for my strongloop API code with the help of loopback-testing .
Here they do not have any detailed document on this, so i am stuck with case of argument passing with the API call
Example i have a below case,
Method : PUT
URL : /api/admin/vineyard/<vineyard_id>
i need to pass the below arguments with this URL
1. 'vineyard_id' is a id of vine, it should be an integer .
2. in header = 'token'
3. in body = '{'name':'tastyWine','price':200}'
How can i pass these three arguments with this API ?
I can easily handle ,if there is only two types of arguments
Example :
Method : POST
`/api/user/members/<test_username>/auth'`
arguments : test_username and password
I can handle this like this ,
lt.describe.whenCalledRemotely('POST',
'/api/user/members/'+test_username+'/auth', {
'password': test_passwords
},
But how can i handle the above case , Many thanks for your answers for this example.

I'm not entirely sure what your specific problem is, but I will attempt to walk through everything you should need.
I am assuming you are using the predefined prototype.updateAttributes() method for your model as described here.
Next assumption is that you want to use the built-in authentication and authorization to allow the user to call this method. Given that assumption, you need something like this in your test code:
var vineyard_id = 123; //the id of the test item you want to change
var testUser = {email: 'test#test.com',password: 'test'};
lt.describe.whenCalledByUser(testUser, 'PUT', '/api/admin/vineyard/'+vineyard_id,
{
'name':'tastyWine',
'price':200
},
function () {
it('should update the record and return ok', function() {
assert.equal(this.res.statusCode, 200);
});
}
);
If you are using the out-of-the-box user model, you should be fine, but if you extended the model as is commonly done, you may need something like this early on in your test file:
lt.beforeEach.withUserModel('user');
Also, be aware of a few (currently incomplete) updates to will allow for better handling of built-in model extensions: Suggestions #56, Add support for non-default models #57, and givenLoggedInUser() function throws error #59.

Related

Lighthouse GraphQL - How to return current_user in mutation resolver?

I have a situation where I'm writing a custom mutation resolver, and currently have to pass the current_user's ID from my frontend to be able to then perform a ::find on the User model. What would be ideal however, is to be able to use an instance of current_user so that I don't have to rely on passing over an ID to my GraphQL server.
I'm still fairly new to the world of Laravel and GraphQL in general, however I've been reading up on the Lighthouse docs that mention the #auth directive, and other StackOverflow answers that mention using auth('api')->user(), however that returns NULL for me. I should also mention that I'm using the lighthouse-graphql-passport-auth library for dealing with user authentication, if that makes any difference. Does anybody know how to access current_user?
public function __invoke($_, array $args)
{
// $user = \App\Models\User::find($args['id']); <--- not ideal
$user = auth('api')->user(); <--- returns NULL
var_dump($user);
foreach ($user->notifications as $notification) {
$notification->viewed = true;
$notification->save();
}
$notifications = $user->notifications->toArray();
return [
'status' => 'Success',
'notifications' => $notifications
];
}
I found an interesting part in the lighthouse-graphql-passport-auth docs that discuss setting a [global middleware][3] to insert the logged in user into the $context. This was exactly like what I needed, and after adding the line into the middleware section of lighthouse.php config as mentioned in the docs, I was able to use $context->user() to return the currently logged in user.

How to chain express-validator based on query values?

I am trying to find a solution to chain conditions based on the query values passed to the route.
Task1:
// if value for query A = noIdNeeeded, then i do not need to search for a second queryB
/endpoint?queryA=noIdNeeded
Task2:
// if value for query A = idNeeded, then i need to ensure second queryB exists
/endpoint?queryA=idNeeded&queryB=SomeId
I am having trouble with the writing parameter for Task 2.
For task 1 i have use this logic and works fine [query('page').exists().notEmpty().isIn(seoPageTypes),]
So far I have seen there is an if clause that we can use probably (link) however implementing this has been a challenge due to lack of examples and no prior experience.
If anyone can guide on how to do this correctly or any hint is much appreciated.
Make sure you have a new version of express-validator installed.
The following should do your job.
query('queryA').exists().notEmpty().isIn(seoPageTypes),
query('queryB')
.if(query('queryA').equals('idNeeded'))
.exists().notEmpty().withMessage('queryB must exist'),
Another approach is to use a custom validator
query('queryA').exists().notEmpty().isIn(seoPageTypes)
.custom((value, {req}) => {
if (value === "idNeeded" && !req.query.queryB) {
throw new Error('queryB must exist');
}
return true;
}),
Use what suits you more :)

How to update user permission discord js

So, I want to update a permission for some users.
First, I tried to create a text channel and overwrite a user Permission. Then I do a for loop to update the permission, but I dont know how.
Things I've tried to update the permission :
channel.overwritePermissions({
permissionOverwrites: [
{
id: guild.id,
deny: ['VIEW_CHANNEL'],
},
{
id: playerData[i],
allow: ['VIEW_CHANNEL'],
},
],
});
//it said channel not defined?
message.guild.channels.cache.find('🐺werewolves').overwritePermissions({
permissionOverwrites: [
{
id: playerData[i],
allow:['VIEW_CHANNEL'],
}
]
})
//it said : fn is not a function
I've I have seen this solution and read the documentation, but the instruction isn't clear.
PS : The permission update must be a loop because the number of users who get the permission always changing.
Regarding first codeblock
channel is not defined, because it's not defined. You cannot use variables without defining them, that's how JavaScript works. To solve it, you would have to define it using for example const channel = ..., or access it from other variables you have, just like you are trying to use find in your second codeblock - you access it from message, as you're most likely in the message event.
Regarding second codeblock
This is not a proper way to use find, neither in old - removed in your version - way, nor the new way. The old way was to do find(property, value), to which you wouldn't provide a value ('🐺werewolves' would be treated as property you're trying to search by). New way you have to use, allows way more flexibility by requiring to pass it a function, just like in the example for the method. Since what you passed was a string and not a function, internal code throws an error fn is not a function.
For your example above, correct way to use that find would be
message.guild.channels.cache.find(channel => channel.name === '🐺werewolves');
Additionally, note that ideally you shouldn't try to call any methods on that directly, as in case when no channel with that name would be found, your code will throw an error. Snippet below should avoid that possibility.
const channel = message.guild.channels.cache.find(channel => channel.name === '🐺werewolves');
if (channel) channel.overwritePermissions(...)

Docuemt postopen event not operating on profile document

I need to save serial number of the document in a profile document and here is a code of action Execute Script:
if (document1.isNewNote()){
var pdoc:NotesDocument=database.getProfileDocument("LastNumber","")
var lnm=pdoc.getItemValue("lastNumber")[0];
var inputText6:com.ibm.xsp.component.xp.XspInputText = getComponent("inputText6");
inputText6.setValue(lnm);
pdoc.replaceItemValue("lastNumber",lnm);
pdoc.save();
}
This code is not opening profile document at all. Any thing wrong in the code?
"LastNumber" is the name of the form used to create Profile Document ?
this profile document already exist ?
there are no reader fields in this profile document ?
you have an error on this line : var pdoc:NotesDocument=database.getProfileDocument("LastNumber","") ?
or you have debug it and see that pdoc is null ?
instead of pdoc.getItemValue("lastNumber")[0] you can use pdoc.getItemValueInteger("lastNumber") to get a typed result
I supposed that this field contains a number and you want to increment it
instead of using inputText field you can set value directly with document1.setValue("NumberField", lnm);
I second the caution Per is suggesting. Profile documents can be a beast. You should abstract access to the "next number" into a SSJS function call. Btw. in your code snippet you don't actually increment the last number. Also: if your input text control is bound, go after the data source, not the UI.
A crude way (I would use a managed application bean for better isolation) for a better function could be this:
if(document1.isNewNote() {
document1.setValue("DocumentNumber",applicationTools.getNextNumber());
}
Then in a SSJS library you would have:
var applicationTools = {
"getNextNumber" : function() {
synchronized(applicationScope){
var pdoc:NotesDocument=database.getProfileDocument("LastNumber","");
if (!applicationScope.lastNumber) {
applicationScope.lastNumber = pdoc.getItemValueInteger("lastNumber");
}
applicationScope.lastNumber++;
pdoc.replaceItemValue("lastNumber",applicationScope.lastNumber);
pdoc.save(); //Make sure pdoc is writeable by ALL!!!!
pdoc.recycle();
return applicationScope.lastNumber;
}
},
"someOtherUtility" : function(nameToLookup, departments) {
// more stuff here
}
}
Which, in some way has been asked before, but not for a profile field. Someone still could simply go after the applicationScope.lastNumber variable, which is one of the reasons why I rather use a bean. The other: you could do the saving asynchronously, so it would be faster.
Note: in any case the number generation only works when you have a non-replicating database. But abstracting the function opens the possibility to replace fetching the number from the profile with a call to a central number generator ... or any other mechanism ... without changing your form again.

Subclass QueryReadStore or ItemFileWriteStore to include write api and server side paging and sorting.

I am using Struts 2 and want to include an editable server side paging and sorting grid.
I need to sublclass the QueryReadStore to implement the write and notification APIs. I do not want to inlcude server side REST services so i do not want to use JsonRest store. Any idea how this can be done.? What methods do i have to override and exactly how. I have gone through many examples but i am not getting how this can be done exactly.
Also is it possible to just extend the ItemFileWriteStore and just override its methods to include server side pagination? If so then which methods do i need to override. Can i get an example about how this can be done?
Answer is ofc yes :)
But do you really need to subclass ItemFileWriteStore, does it not fit your needs? A short explaination of the .save() follows.
Clientside does modify / new / delete in the store and in turn those items are marked as dirty. While having dirty items, the store will keep references to those in a has, like so:
store._pending = { _deletedItems: [], _modifiedItems: [], _newItems: [] };
On call save() each of these should be looped, sending requests to server BUT, this does not happen if neither _saveEverything or _saveCustom is defined. WriteStore simply resets its client-side revert feature and saves in client-memory.
See source search "save: function"
Here is my implementation of a simple writeAPI, must be modified to use without its inbuilt validation:
OoCmS._storeAPI
In short, follow this boiler, given that you would have a CRUD pattern on server:
new ItemFileWriteStore( {
url: 'path/to/c**R**ud',
_saveCustom: function() {
for(var i in this._pending._newItems) if(this._pending._deletedItems.hasOwnProperty(i)) {
item = this._getItemByIdentity(i);
dxhr.post({ url: 'path/to/**C**rud', contents: { id:i }});
}
for(i in this._pending._modifiedItems) if(this._pending._deletedItems.hasOwnProperty(i)) {
item = this._getItemByIdentity(i);
dxhr.post({ url: 'path/to/cr**U**d', contents: { id:i }});
}
for(i in this._pending._deletedItems) if(this._pending._deletedItems.hasOwnProperty(i)) {
item = this._getItemByIdentity(i);
dxhr.post({ url: 'path/to/cru**D**', contents: { id:i }});
}
});
Now; as for paging, ItemFileWriteStore has the pagination in it from its superclass mixins.. You just need to call it with two setups, one being directly on store meaning server should only return a subset - or on a model with query capeabilities where server returns a full set.
var pageSize = 5, // lets say 5 items pr request
currentPage = 2; // note, starting on second page (with *one* being offset)
store.fetch({
onComplete: function(itemsReceived) { },
query: { foo: 'bar*' }, // optional filtering, server gets json urlencoded
count: pageSize, // server gets &count=pageSize
start: currentPage*pageSize-pageSize // server gets &start=offsetCalculation
});
quod erat demonstrandum

Resources