Loopback remoteMethod with onesignal push notification - loopback

i still learn, and trying to be learn. im looking for trying hard remote method on loopback 3 for push notification to specific user with onesignal.
any wrong in my code ?
because always :
Error: [ 'All included players are not subscribed' ]
My Case :
im using ionic 3 framework
loopback 3 (or latest)
2 User, (Customer & Seller)
Customer buying product from thread's seller.
If success to order, the seller will receive the notification.
and This is My code :
Ajiorder.observe('after save', function (ctx, next) {
console.log('Order', ctx.instance);
let postingModel = app.models.AjiPosting;
let userAuth = app.models.AjiUserAuth;
postingModel.find({
where:
{ id: ctx.instance.id }
}, function (err, success) {
console.log(success, 'SUKSES');
if (ctx.instance) {
let dataFilter = [];
dataFilter.push({
'field': 'tag',
'key': 'id',
'relation': '=',
'value': success[0].id
});
console.log(success[0].idSeller, 'ID TOT')
console.log(dataFilter, 'dataFilter');
let data = {
idSeller: ctx.instance.idSeller
}
console.log(data, 'Data');
userAuth.find({
where:
{ id: ctx.instance.idCustomer }
}, function (err, result) {
console.log(result, 'Data Personal');
let content = result[0].namaLengkap + ' ' + 'Order your product';
console.log(content, 'Nama Order');
console.log(ctx.instance.idSeller, 'My Dream', success[0].id);
if (ctx.instance.id != success[0].id) {
console.log('Spirit');
sendMessage(dataFilter, content, data);
}
})
}
next();
});
});
var sendMessage = function (device, message, data) {
var restKey = 'XXXXXXXXXXXXXXXXXX';
var appID = 'XXXXXXXXXXXXXXXXX';
request(
{
method: 'POST',
uri: 'https://onesignal.com/api/v1/notifications',
headers: {
'authorization': 'Basic ' + restKey,
'content-type': 'application/json'
},
json: true,
body: {
'app_id': appID,
'filters': device,
'data': data,
'contents': { en: message }
}
},
function (error, response, body) {
try {
if (!body.errors) {
console.log(body);
} else {
console.error('Error:', body.errors);
}
} catch (err) {
console.log(err);
}
}
)
}
};
and i got this error :
Error: [ 'All included players are not subscribed' ]
Picture : Picture of Console Log Here
any one can help me ?
sorry for my english too bad.
Greetings

Solved !
I'm Forget to add some code from onesignal. thanks

Related

Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'validateStatus' in

I am getting ** Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'validateStatus' in 5f8425a33a14f026f80133ed** where 5f8425a33a14f026f80133ed is the id passed to the axios url
I want to display the services based on the user id. My url works perfectly in postman but when i access it from the veux store it gives an error.
services.js (store)
import axios from 'axios';
const state = {
services : {},
status: '',
error: null
};
const getters = {
services : state => { return state.services }
};
const actions = {
async fetchServices({commit}, userId) {
let res = await axios.get('http://localhost:5000/api/services/displayUser' , userId)
commit('setProducts', res.data)
return res;
}
};
const mutations = {
setProducts (state, items) {
state.services= items
},
};
export default {
state,
actions,
mutations,
getters
};
This is how I am calling the action :
computed: {
...mapGetters(["services"]),
},
methods: {
...mapActions(["fetchServices"]),
getData(){
this.fetchServices(this.user._id)
},
},
async created() {
await this.getProfile();
await this.getData();
}
The axios route is defined as
router.get('/displayUser', (req,res) => {
const query = user = req.body ;
Services.find(query)
.exec((err, services) => res.json(services))
})
the error screenshot :
Error screenshot
GET request should not have a body. Either use query params, indicate an id in a path, or use POST request.
In case of query params this may look like this:
let res = await axios.get('http://localhost:5000/api/services/displayUser' , { params: { userId })
router.get('/displayUser', (req,res) => {
const query = user = req.query;
Services.find(query)
.exec((err, services) => res.json(services))
})
This worked for me too:
In front end: Vue Js
let res = axios.get("http://localhost:3000/api/v1/role/getRoleByName",
{ params: { roleName: "name of role you want to send as params" },
});
In back end: Node Js
router.get('/getRoleByName', (req,res)=>{
let roleName = req.query.roleName;
roleModule.getRoleByName(roleName).then(data =>{
response.json(res,data)
}
).catch(err=> {
response.badRequest(res, err);
})
});
it's a silly mistake axios.post req.
async addTodo({ commit }, title) {
try {
const res = await axios.post(BASE_URL, { title, complete: false });
commit("newTodo", res.data);
} catch (err) {
console.log(err.message);
}
},

Uploading hundreds of photos (almost a thousand) using ionic

I've been struggling for months to do this but it seems impossible.
I am creating an app using ionic framework which uploads hundreds of photos.
This app is used to generate reports which contains a lot of photos.
The APIs work perfectly on a local server but when I tried using our cloud server much photos are not getting uploaded, the app shows success but when I check the server only few photos are getting uploaded (less than a hundred).
Any ideas about what should I do to make this work?
Thanks.
EDIT:
here's the code for capturing photos cameraservice.js
app.factory('cameraService', function ($rootScope, $q, $http, $location, $timeout, $cordovaCamera,$cordovaFile,$cordovaFileTransfer, apiUrl) {
var settings = {
saveToPhotoAlbum: true,
correctOrientation: true,
quality: 10,
targetWidth: 720,
targetHeight: 720,
};
return {
getPicture: function(){
var d = $q.defer();
let options = {
popoverOptions: CameraPopoverOptions
};
angular.extend(options, settings)
$cordovaCamera.getPicture(options).then(function(imageData) {
let namePath = imageData.substr(0, imageData.lastIndexOf('/') + 1);
let filename = imageData.replace(/^.*[\\\/]/, '');
$cordovaFile.moveFile(namePath, filename, cordova.file.dataDirectory, filename)
.then(function (res) {
d.resolve({ filename: res.name });
}, function (error) {
console.log(error)
});
}, function(err) {
console.log(err)
});
return d.promise;
}
}
})
and here's my uploadservice.js
app.factory('imageUploadService', function ($cordovaFileTransfer) {
var settings = {
fileKey: "file",
chunkedMode: false,
mimeType: "multipart/form-data",
headers : {
Connection:"close"
}
};
return {
upload: function(url, filename, options){
let filePath = cordova.file.dataDirectory + filename;
angular.extend(options, settings);
console.log(url, filePath, options)
return $cordovaFileTransfer.upload(url, filePath, options);
}
}
});
this is how I use the APIs sendservice.js
app.factory('sendService', function ($http, $q, imageUploadService, $timeout, apiUrl) {
return {
photos: function(id, data){
let d = $q.defer();
var url = apiUrl + "/api/senddescription"
var api = apiUrl + "/api/senddetailedphoto";
let q = [];
angular.forEach(data, (item, index)=>{
angular.forEach(item.photos, (i)=>{
let origName = i.image;
var options = {
filename: i.image,
params : {
report_no : id,
label: i.label,
photo_count: index,
photo_label: i.label
},
chunkedMode: false,
headers : {
Connection : "close"
}
};
setTimeout(function(){
q.push(imageUploadService.upload(api, origName, options))
},15000);
})
let data = {
report_no: id,
photo_count: index,
product_description: item.product_description
}
q.push($http.post(url, data));
$q.all(q).then(res=>{
d.resolve(res);
}, err=>{
d.reject(err);
})
})
return d.promise;
}
}
});
These are my APIs
/api/senddescription
public function sendPhotoDescription(Request $request){
$desc = DetailedPhotoDescription::where('report_number',$request->input('report_no'))->where('photo_count',$request->input('photo_count'))->first();
if (!$desc) {
$desc = new DetailedPhotoDescription();
$desc->report_number = $request->input('report_no');
}
$desc->photo_count = $request->input('photo_count');
$desc->product_description = $request->input('product_description');
if ($desc->save()) {
return response()->json([
'message'=>'OK'
],200);
}else{
return response()->json([
'message'=>'Error submitting photo. Please resend the report!'
],500);
}
}
/api/senddetailedphoto
public function sendDetailedPhoto(Request $request){
$file = $request->file('file');
//set a unique file name
$filename = uniqid() . '.' . $file->getClientOriginalExtension();
// //move the files to the correct folder
if ($file->move('images/reports/'. $request->input('report_no').'/detailedPhoto'.'/'.$request->input('photo_count').'/', $filename)) {
$detailed = new DetailedPhoto();
$detailed->report_number = $request->input('report_no');
$detailed->photo_count = $request->input('photo_count');
$detailed->photo_label = $request->input('photo_label');
$detailed->image_data = $filename;
if ($detailed->save()) {
return response()->json([
'message' => 'OK'
],200);
}else{
return response()->json([
'message' => 'Error saving detailed photos. Please resend the report!'
],500);
}
}else{
return response()->json([
'message' => 'Error uploading detailed photos. Please resend the report!'
],500);
}
}

Protractor/Jasmine send REST Call when a test failed

I am using Protractor and Jasmine to test my hybrid mobile app, which works fine. I'd like to create an incident on my Team Foundation Server (TFS), when a test fails. Therefore, I have to send an REST-Call to the Api, which also works fine in my Angular App. But it does not work, when I am inside my test environment.
My Code:
var BrowsePage = require('./browse.page');
var tfsIncident = require('./tfsIncident_service');
var request = require('request');
describe('Testing the browse state', function () {
var browsePage = new BrowsePage();
var specsArray = [];
var reporterCurrentSpec = {
specDone: function (result) {
if (result.status === 'failed') {
var mappedResult = tfsIncident.create(result);
console.log(mappedResult); //This works so far, but then it crashes
var options = {
method: 'PATCH', //THis Method requiered the API
url: 'MY_COOL_API_ENDPOINT',
headers: {
'Authorization': 'Basic ' + btoa('USERNAME' + ':' + 'PASSWORD'),
'Content-Type': 'application/json-patch+json'
},
body: mappedResult
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
console.log(response);
console.log(info);
}
}
request(options, callback);
}
}
};
jasmine.getEnv().addReporter(reporterCurrentSpec);
//This test passes
it('should be able to take display the heading', function () {
expect(browsePage.headline.isPresent()).toBe(true);
});
// Test is supposed to fail
it('should be able to fail', function () {
expect(browsePage.headline).toBe(1);
});
// Test is supposed to fail as well
it('should be able to fail too', function () {
expect(browsePage.headline).toBe(2);
});
});
So the problem is, that my only console output is (after the console.log(mappedResult)): E/launcher - BUG: launcher exited with 1 tasks remaining
So I have no idea, why this does not work.
Any help appreciated.
Edit
Protractor: 5.0.0
Appium Desktop Client: 1.4.16.1
Chromedriver: 2.27
Windows 10 64 Bit
Jasmine: 2.4.1
I finally got my problem solved. The problem was caused by ignoring the promises by jasmine. I had to add a .controllFlow().wait() to my protractor.promise
The following code works fine:
var BrowsePage = require('./browse.page');
describe('Testing the browse state', function () {
var browsePage = new BrowsePage();
var reporterCurrentSpec = {
specDone: function (result) {
if (result.status === 'failed') {
//Mapping of the result
var incident = [
{
op: 'add',
path: '/fields/System.Title',
value: 'Test: ' + result.fullName + ' failed'
},
{
op: 'add',
path: '/fields/System.Description',
value: result.failedExpectations[0].message
},
{
op: 'add',
path: '/fields/Microsoft.VSTS.Common.Priority',
value: '1'
},
{
op: 'add',
path: '/fields/System.AssignedTo',
value: 'Name Lastname <e#mail.com>'
}
];
protractor.promise.controlFlow().wait(create(incident)).then(function (done) { //The magic happens in this line
console.log("test done from specDone:" + done);
});
}
}
};
jasmine.getEnv().addReporter(reporterCurrentSpec); //Add new Jasmine-Reporter
function create(incident) {
var request = require('request');
var defer = protractor.promise.defer(); //new promise
request({
url: 'https://MY_COOL_ENDPOINT.COM',
method: "PATCH",
json: true, // <--Very important!!!
headers: {
'Authorization': 'Basic ' + new Buffer('USERNAME' + ':' + 'PASSWORD').toString('base64'),
'Content-Type': 'application/json-patch+json'
},
body: incident
}, function (error, response, body) {
console.log(error);
console.log(response.statusCode);
console.log(body.id); //Id of created incident on TFS
defer.fulfill({
statusCode: response.statusCode
}); //resolve the promise
});
return defer.promise; //return promise here
}
it('should be able to display the heading', function () {
expect(browsePage.headline.isPresent()).toBe(true);
});
it('should be able to fail', function () {
expect(browsePage.headline.isPresent()).toBe(false);
});
it('should be able to fail 2', function () {
expect(browsePage.headline.isPresent()).toBe(false);
});
});
Attention
When the test suite is done and the last promise is not resolved at this moment, the last incident is not created. I'll try to work around by adding to the last test a browser.sleep(5000); so that the create(incident) function gets more time to finish.
Thanks to this StackOverflow answer for helping me.

How to retrieve `custom_disclaimer_responses` in Facebook lead gen webhook data

I have set up a webhook that gets data submitted from a lead gen ad on Facebook.
In my response I have access to field_data and can see names and email address coming through but can't seem to find where the custom_disclaimer_responses is.
I am using the graph API explorer to send test submissions and getting a successful response
My webhook code is as follows:
exports.webhook = function (req, res, next) {
var lead = req.body.entry[0].changes[0].value;
var leadID = lead.leadgen_id;
var formID = lead.form_id;
var customDisclaimerResponses = lead.custom_disclaimer_responses
fs.readFile(config.token, 'utf8', function(err, data) {
if (err) {
console.log('err', err)
throw err;
}
var content = JSON.parse(data);
if(!content.access_token) {
console.log('Facebook Access Token is invalid.');
res.sendStatus(400);
} else {
FB.options({accessToken: content.access_token});
FB.api('/' + leadID, function (response) {
if(response && response.error) {
console.log('error', response.error);
res.sendStatus(400);
} else {
var fields = response.field_data;
// do stuff here with fields
// Response moved to outside of above function block since Facebook will
// stop sending updates if the webhook starts giving errors repeatedly.
res.sendStatus(200);
}
});
}
});
}
Example of response:
{ created_time: '2016-11-17T09:52:44+0000',
id: '<id>',
field_data:
[ { name: 'email', values: [Object] },
{ name: 'first_name', values: [Object] },
{ name: 'last_name', values: [Object] },
{ name: 'city', values: [Object] },
{ name: 'date_of_birth', values: [Object] }
]
}
I don't use webhooks, but I think this can help you:
You can add the parameter fields=custom_disclaimer_responses to get the data you need.
I re-join collected data (the ones in field_data got without parameter) by user id
This is my PHP code, for example:
$url = "https://graph.facebook.com/v2.9/$leadForm/leads?access_token=".$appToken;
$urlCustom = "https://graph.facebook.com/v2.9/$leadForm/leads?fields=custom_disclaimer_responses&access_token=".$appToken;

Multiple functions in restify function to elasticsearch client

I'm building a REST API using node and restify that communicaties with an elasticsearch database. Now when I delete an object, I want this to do a kind of cascading delete to some other objects. I know this is not really what to use elasticsearch for but bear with me.
So here is my code:
function deleteHostname(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
var endpoints = [];
client.search({
index: 'test',
type: 'something',
body: {
from: 0, size: 100,
query: {
match: {
hostname: 'www.test.com'
}
}
}
}).then(function (error, resp) {
if(error) {
res.send(error);
}
endpoints = resp.hits.hits;
for (index = 0, len = endpoints.length; index < len; ++index) {
client.delete({
index: 'test',
type: 'something',
id: endpoints[index]._id
}, function (error, response) {
if(error) {
res.send(error);
}
});
}
res.send(endpoints);
return next();
});
}
So basically I just want to search for any objects with hostname www.test.com ( I just hard coded this to test it ). Then I want to delete all objects I found. It follows the error path and sends me this:
{
"took":1,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"failed":0
},
"hits":{
"total":1,
"max_score":2.098612,
"hits":[
{
"_index":"test",
"_type":"something",
"_id":"123456",
"_score":2.098612,
"_source":{
"duration":107182,
"date":"2016-05-04 00:54:43",
"isExceptional":true,
"hostname":"www.test.com",
"eta":613,
"hasWarnings":false,
"grade":"A+",
"ipAddress":"ipip",
"progress":100,
"delegation":2,
"statusMessage":"Ready"
}
}
]
}
}
So in my opinion this doesn't look like an error? So why am I getting it back as an error? If I remove:
if(error) {
res.send(error);
}
From my code, I won't get any response.
You need to change your code like this (see the changes denoted by -> to the left):
if(error) {
1-> return res.send(error);
}
endpoints = resp.hits.hits;
for (index = 0, len = endpoints.length; index < len; ++index) {
2-> (function(id){
client.delete({
index: 'test',
type: 'something',
3-> id: id
}, function (error, response) {
if(error) {
4-> next(error);
}
});
5-> })(endpoints[index._id]);
}
6-> //res.send(endpoints);
I'm now explaining each change:
If you don't return you'll send the error and then you'll continue with processing the hits
(3/5) Since client.delete is an asynchronous function, you need to call it in an anonymous function
In case of error you need to call next(error) not res.send
You cannot send the response at this point since your for loop might not be terminated yet. Instead of a for loop, you should use the excellent async library instead (see an example of using asynch.each below)
Async example:
var async = require('async');
...
if(error) {
return res.send(error);
}
endpoints = resp.hits.hits;
async.each(endpoints,
function(endpoint, callback) {
client.delete({
index: 'test',
type: 'something',
id: endpoint._id
}, callback);
},
// this is called when all deletes are done
function(err){
if (err) {
next(err);
} else {
res.send(endpoints);
next();
}
}
);
Another solution for you to achieve exactly what you want is to use the delete by query plugin. That feature allows you to do all the above in a single query.
If you are still on ES 1.x, delete-by-query is still part of the core and you can simply call the deleteByQuery function of the Javascript client.
If you are on ES 2.x, delete-by-query is now a plugin, so yo need to install it and then also require the deleteByQuery extension library for the Javascript client
function deleteHostname(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
client.deleteByQuery({
index: 'test',
type: 'something',
body: {
query: {
match: { hostname: 'www.test.com' }
}
}
}, function (error, response) {
if (error) {
next(error);
} else {
res.send(endpoints);
next();
}
});
}