I want to send a post request with loopback "invokeStaticMethod".
Please help me how to do it.
I want to send a POST API request to below url:
localhost:3000/api/user/id/unblock With parameter {"userId", "blockId"}
Please let me know how can I send a POST request with Loopback
You could create a remote method like this:
User.unblock = function(id, userId, blockId, callback) {
var result;
// TODO
callback(null, result);
};
Then, the remote method definition in the json file could look like this:
"unblock": {
"accepts": [
{
"arg": "id",
"type": "string",
"required": true,
"description": "",
"http": {
"source": "path"
}
},
{
"arg": "userId",
"type": "string",
"required": false,
"description": "",
"http": {
"source": "form"
}
},
{
"arg": "blockId",
"type": "string",
"required": false,
"description": "",
"http": {
"source": "form"
}
}
],
"returns": [
{
"arg": "result",
"type": "object",
"root": false,
"description": ""
}
],
"description": "",
"http": [
{
"path": "/:id/unblock",
"verb": "post"
}
]
}
Then your remote method would look like this:
You could play around with function arguments and use one body argument instead of 2 form arguments and read the data from there, although I believe that if there are only 2 additional parameters it's better to put them separately. But it depends on your approach.
I believe this is what you are looking for...
https://loopback.io/doc/en/lb3/Adding-remote-methods-to-built-in-models.html
In your case, it should look something like this...
module.exports = function(app) {
const User = app.models.User;
User.unblock = function(userId, blockId, cb) {
... <Your logic goes here> ...
cb(null, result);
};
User.remoteMethod('unblock', {
accepts: [{arg: 'userId', type: 'string'}, {arg: 'blockId', type: 'string'}],
returns: {arg: 'result', type: 'string'}
});
Related
I have a Teams application where I need to use local storage (IndexedDB).
All works fine with the most common browsers: Chrome, Firefox but when I try to use the application with the Android app for Teams, something goes wrong: "It is necessary for the correct functioning of the app to allow access to IndexedDB".
Android Version: 10 - WebView Version: 81.0.4044.138
From my point of view is something relative to the permissions for local storage with WebView
This is my code:
if (window.indexedDB) {
var request = indexedDB.open('__mydb', 2);
request.onerror = function (event) {
alert('It is necessary for the correct functioning of the app to allow access to IndexedDB.');
};
request.onsuccess = function (event) {
mydb = event.target.result;
try {
console.log('Database opened, checking existence of table');
var objectStore = mydb.transaction([tableName], 'readwrite')
.objectStore(tableName);
console.log('Table exists. Proceeding to save data');
saveTokenDataIndexedDB(objectStore);
console.log('All done, going to app');
goToApp();
} catch (e) {
console.log(e);
}
};
}
This is the manifest file of my Teams application:
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.2/MicrosoftTeams.schema.json",
"manifestVersion": "1.0",
"packageName": "XXXXXX",
"id": "29bcd6f4-XXXXXX-4111-820b-XXXXXXXXXXX",
"version": "0.1",
"developer": {
"name": "XXXXXXXXXXXXX",
"websiteUrl": "https://products.office.com/en-us/sharepoint/collaboration",
"privacyUrl": "https://privacy.microsoft.com/en-us/privacystatement",
"termsOfUseUrl": "https://www.microsoft.com/en-us/servicesagreement"
},
"name": {
"short": "XXXXXXXXXXXX"
},
"description": {
"short": "XXXXXXXXXXXXX",
"full": "XXXXXXXXXXXXXXXX"
},
"icons": {
"outline": "XXXXXXXXXXXX_outline.png",
"color": "XXXXXXXXXXXXX_color.png"
},
"accentColor": "#004578",
"configurableTabs": [
{
"configurationUrl": "https://{teamSiteDomain}{teamSitePath}/_layouts/15/TeamsLogon.aspx?SPFX=true&dest={teamSitePath}/_layouts/15/teamshostedapp.aspx%3FopenPropertyPane=true%26teams%26componentId=XXXXX-eadc-4020-XXXX-edea2c24753b%26forceLocale={locale}",
"canUpdateConfiguration": true,
"scopes": [
"team"
]
}
],
"staticTabs": [
{
"entityId": "XXXXX",
"name": "XXXXXXXXX",
"contentUrl": "https://{teamSiteDomain}/_layouts/15/TeamsLogon.aspx?SPFX=true&dest=/_layouts/15/teamshostedapp.aspx%3Fteams%26personal%26componentId=XXXXXXXXX-eadc-4020-b4e2-XXXXXXXb%26forceLocale={locale}",
"scopes": [
"personal"
]
}
],
"validDomains": [
"*.login.microsoftonline.com",
"*.sharepoint.com",
"*.sharepoint-df.com",
"spoppe-a.akamaihd.net",
"spoprod-a.akamaihd.net",
"resourceseng.blob.core.windows.net",
"msft.spoppe.com"
],
"webApplicationInfo": {
"resource": "https://{teamSiteDomain}",
"id": "XXXXXXXX-eadc-4020-b4e2-XXXXXXXXXX"
}
}
I'm stuck with this, if somebody can give me a clue I will be grateful.
Regards
I have a class which is part of a school and this class has teachers and students, all of them has name and maybe has phone number , I want to get the full data for the classes
but firstly, could you advice me, what is the best for performance and maintaining from the following Dbs :
1st one
"schools":{
"school1":{
"class1":{
"name":"SC1",
"teachers":[{
"name":"T1"
}, {
"name":"T2"
}],
"students":[
{"name":"S1"},
{"name":"S2"}
]
}
}
.
.
.
.
.
.
.
}
and the 2nd
"school":{
"school1":{
"name":"SC1"
},
"school2":{
"name":"SC2"
}
},
"classes": {
"class1": {
"name": "C1"
},
"class2": {
"name": "C2"
}
},
"students": {
"student1": {
"name": "S1",
"phone":"123456789"
},
"student2": {
"name": "S2",
"phone":"123456789"
},
"student3": {
"name": "S3",
"phone":"123456789"
},
"student4": {
"name": "S4",
"phone":"123456789"
}
},
"teachers": {
"student1": {
"name": "T1",
"phone":"123456789"
},
"student2": {
"name": "T2",
"phone":"123456789"
},
"student3": {
"name": "T3",
"phone":"123456789"
},
"student4": {
"name": "T4",
"phone":"123456789"
}
},
"classes_enrollments": {
"class1": {
"teacher1": true,
"teacher3": true,
"student1": true,
"student2": true
},
"class2": {
"teacher2": true,
"teacher4": true,
"student3": true,
"student4": true
},
"class3": {
"teacher1": true,
"teacher2": true,
"student3": true,
"student4": true,
"student1": true,
"student2": true
}
},
"student_friends": {
"student1": {
"student2": true
},
"students2": {
"student1": true,
"student3": true
},
"students3": {
"student2": true
}
},
"teacher_friends": {
"teacher1": {
"teacher2": true
},
"teacher2": {
"teacher1": true,
"teacher3": true
},
"teacher3": {
"teacher2": true
}
}
and for the 2nd way how to get the full data for the class1: in which school and it's name and count of teachers and students and their names and phones
Thank you
I would mix those two.
For code simplicity and reading performance of individual class details, the 2nd scheme would indeed be messy. The 1st scheme would be better, but with some improvements.
Keep the teachers and students paths at root, just like in the 2nd scheme.
Add teacher_enrollments and student_enrollments path at root, to save the ids of the classes that each teacher/student is associated with.
Don't save class teachers and students as arrays inside classes, but use maps instead, similar to what you're saving in the root teachers and students path.
That way, when you edit a teacher from the root path, you can also get a list of all their associated classes (the ids) from the enrollments path, and do a multi-path update for these classes, to update the teacher/student details in each associated class.
If you have lots of data, you might want to maintain a separate path for class summaries, so that you can easily show a list of classes, without having to download the data for all included teachers and students (which would be present multiple times in all these classes).
When you delete a class, you would also want to do a multi-path update to delete all associated enrollments. If the total number of students and teachers is not too big, you can just delete the enrollments for ALL teacheres/students. If you have lots of teachers/students, you could keep your classes_enrollments path (but with intermediate teachers and students before the ids), so that you can make an update with only the required teacher/student ids. (it's actually a lot simpler. You already have the teacher/student IDs in the class info)
// How to delete a class in JavaScript.
// For Java, use updateChildren() instead of update(),
// and supply it with a HashMap instead of a plain object.
const classToDelete = { id: 'class1', teachers: ..., students: ..., school: ... };
const updateObject = {
['classes/'+classToDelete.id]: null },
['schools/'+classToDelete.school.id+'/classes/'+classToDelete.id]: null },
};
Object.keys(classToDelete.teachers).forEach(teacherId => {
updateObject['teachers/'+teacherId +'/classes/'+classToDelete.id] = null;
});
Object.keys(classToDelete.students).forEach(studentId=> {
updateObject['students/'+studentId+'/classes/'+classToDelete.id] = null;
});
dbRef.update(updateObject);
Example database structure (slightly different than instructed, but using the same concepts):
"schools": {
"school1": {
"id": "school1",
"name": "The best school",
"classes": {
"class1": {
"id": "class1",
"name": "The best class"
}
}
}
},
"classes": {
"class1": {
"id": "class1",
"name": "The best class",
"teachers": {
"teacher1": {
"id": "teacher1",
"name": "The best teacher",
"phone": "123"
}
},
"students": {
"student1": {
"id": "student1",
"name": "The best student",
"phone": "456"
}
},
"school": {
"id": "school1",
"name": "The best school"
}
}
},
"teachers": {
"teacher1": {
"id": "teacher1",
"name": "The best teacher",
"phone": "123",
"classes": {
"class1": {
"name": "The best class",
"school": {
"id": "school1",
"name": "The best school"
}
}
}
}
},
"students": {
"student1": {
"id": "student1",
"name": "The best student",
"phone": "456",
"classes": {
"class1": {
"name": "The best class",
"school": {
"id": "school1",
"name": "The best school"
}
}
}
}
}
Good luck!
My previous server is lost, I am developing an Android app with backend on a ubuntu server on AWS, what I am trying to do now is I need to recover the backend loopback based on the json files of the models. For example I am having this,
{
"name": "BikeStop",
"plural": "bikeStops",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"geo": {
"type": "geopoint",
"required": true
},
"description": {
"type": "string",
"required": false
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
is it possible that I can just import this to a new lb folder, or do i have to call lb model and manually type in and set up? If there is a way to do it, how??
Copy your model in a JSON file as
bikestop.json
{
"name": "BikeStop",
"plural": "bikeStops",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"geo": {
"type": "geopoint",
"required": true
},
"description": {
"type": "string",
"required": false
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
Now create a javascript file for this model as
bikestop.js
'use strict';
module.exports = function(Bikestop) {
};
PS : Model name should has only the first letter uppercase.
Finally define this model in model-config.json
"BikeStop": {
"dataSource": "YourDataSourceName",
"public": true
}
I am used loopback's framework to generate my APIs. Now, I am trying to write a custom "RemoteMethod" that will require a long number (timestamp in unix format such as 1466598625506) and return an array of Sync Objects (I am using retrofit to comunicate with the endpoints). In my android app when I call the end point "getRecodsAfterTimestamp" it should return the records with equal or bigger timeStamp value than the provided one in the request. What It returns is all of the records (3 at this time).
This is how my model (sync.json) called Sync looks like:
{
"name": "Sync",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"uuid": {
"type": "string"
},
"table": {
"type": "string"
},
"action": {
"type": "string"
},
"timeChanged": {
"type": "number"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
And this is my sync.js with the remote method looks like:
module.exports = function(Sync) {
Sync.getRecodsAfterTimestamp = function(timestamp, cb){
// var response;
Sync.find({where:{ or: [
{timeChanged:timestamp},
{timeChanged: {gt:timestamp } }
] }}, function(err, sync) {
cb(null,sync);
// response.push(sync);
});
// cb(null, response);
}
Sync.remoteMethod (
'getRecodsAfterTimestamp',
{
http: {path: '/getRecodsAfterTimestamp', verb: 'get'},
accepts: {arg: 'timeChanged', type: 'number', http: { source: 'query' } },
returns: {
arg: 'data',
type: 'array',
root: true
}
}
);
};
I dont know if it matters but this is my retrofit method declaration:
#GET("Syncs")
Call<List<Sync>> getAllSyncsAfterThisTimeStamp(#Query(("getRecodsAfterTimestamp?timeChanged=")) long timeChanged);
And here I am calling it like that:
Long timeStamp = 1466598625506L;
Log.e(TAG, "Job Service task is running...");
getAllSyncsCall = espcService.getAllSyncsAfterThisTimeStamp(timeStamp);
getAllSyncsCall.enqueue(EspcJobSheculerService.this);
This code returns
This is not the result I want. It should have returned all of the records after 1466598625506 which is two records only.
Your query is correct.
Check in find callback you get right output or not
I have a loopback model customer and I wanted to access the related model order, from a customer model instance in android. But, I couldn't find any documentation regarding this. Can somebody help me with this?
Thanks in advance!
{
"name": "customer",
"plural": "customers",
"base": "User",
"properties": {
"phoneVerified": {
"type": "boolean",
"default": "false"
}
},
"validations": [],
"relations": {
"roles": {
"type": "hasMany",
"model": "Role",
"through": "RoleMapping",
"foreignKey": "principalId"
},
"baggedProducts": {
"type": "hasMany",
"model": "product",
"through": "baggedProduct",
"foreignKey": "customerId"
},
"orders": {
"type": "hasMany",
"model": "order",
"foreignKey": "orderId"
}
},
"acls": [],
"methods": []
}
As per the given relation, model customer has many model order. Therefore, to access orders from a given customer use:
customer.order.find({}, function(err, results) {
if(err) throw err;
console.log(results);
});
Now if you are using URL to fetch results: you need to find the url for this method which will be like this:
{your server}/customer/{id}/orders
Else if you are using Android SDK, follow this: Android SDK guide for LoopBack.