Accessing other models' methods from custom method in Loopback - node.js

I'm trying to create a custom method for a User based model in Loopback.
The method calls login and then retrieves user's role and adds it into response so the login request holds token and role info at once.
My problem is that once I have the token information I don't know how to call Role & RoleMapping methods from the one I'm creating...
How can I add those models to the current scope?
How can I access rootScope from this method?
This is how I've made it:
module.exports = function(TiUser) {
TiUser.auth = function(credentials, include, fn) {
var self = this;
self.login(credentials, include, function(err, token) {
var role = // Here I would retrieve Role related info
authInfo = {
token: token,
role: role
};
fn(err, authInfo);
});
};
TiUser.remoteMethod(
'auth',
{
description: 'Login method with Role data information embedded in return',
accepts: [
{arg: 'credentials', type: 'object', required: true, http: {source: 'body'}},
{arg: 'include', type: ['string'], http: {source: 'query' },
description: 'Related objects to include in the response. ' +
'See the description of return value for more details.'}
],
returns: {
arg: 'accessToken', type: 'object', root: true,
description: 'User Model'
},
http: {verb: 'post'}
}
);
};

You can get back to app from your models like so TiUser.app
So the way that I call other Model methods is:
TiUser.app.models.Roles.find etc.

Related

Create LinkedIn UGC Post with Document Asset

The LinkedIn API documentation for UGC Posts seems to imply you can share a post with a document by setting shareMediaCategory: "NATIVE_DOCUMENT", but there is no additional information about how to make this work. The documentation seems limited to images/videos.
This is what I have tried so far.
const registerUpload = () => {
// Doesn't seem to be documented, but the API responses on the LinkedIn site
// returns 'urn:li:digitalmediaRecipe:feedshare-document', so it seemed like a decent guess
const type = 'document'; // 'image' or 'video' works fine
return axios({
method: 'post',
url: 'https://api.linkedin.com/v2/assets?action=registerUpload',
data: {
registerUploadRequest: {
owner,
recipes: [
`urn:li:digitalmediaRecipe:feedshare-${type}`,
],
serviceRelationships: [
{
identifier: 'urn:li:userGeneratedContent',
relationshipType: 'OWNER',
},
],
...(synchronous ? {
supportedUploadMechanism: [
'SYNCHRONOUS_UPLOAD',
],
} : {}),
},
},
headers: {
Authorization: `Bearer ${tokenInfo.token}`,
'X-Restli-Protocol-Version': '2.0.0',
},
});
}
which returns the following
{
serviceErrorCode: 100,
message: 'Field Value validation failed in REQUEST_BODY: Data Processing Exception while processing fields [/registerUploadRequest/recipes/relationshipType]',
status: 403
}
This doesn't make sense to me since registerUploadRequest/recipes/relationshipType doesn't match the documented schema. Is there another way to register document assets for UGC posts?

Error: Failed to load Stripe.js at HTMLScriptElement.<anonymous>

I am using #stripe/stripe-js module in my javascript to run Stripe in my frontend alongside node and express in backend. I tried using the stripe cdn src='https://js.stripe.com/v3/' in my pug template and that didn't work form me, so I used the npm module.
Now every time I send request to my endpoints from frontend, I get an error:
Refused to load the script 'https://js.stripe.com/v3' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback
Failed to load Stripe.js
at HTMLScriptElement. (bundle.js:6999:16)
but when I console the data from fetch method, I get the success result as
{message: 'success', session: {…}}
message: "success"
session:
after_expiration: null
allow_promotion_codes: null
amount_subtotal: 70000
amount_total: 70000
automatic_tax: {enabled: false, status: null}
billing_address_collection: null
cancel_url: "http://127.0.0.1:3000/accessTours/poon-hill-hot-spring-trekking"
client_reference_id: "5c88fa8cf4afda39709c2921"
consent: null
consent_collection: null
currency: "usd"
customer: null
customer_creation: "always"
customer_details: {email: 'abc#gmail.com', phone: null, tax_exempt: 'none', tax_ids: null}
customer_email: "abc#gmail.com"
expires_at: 1643568461
id: "cs_test_a1spczl6c2aTyF1K3DZ1nNmPWugoxgPqeREy4f85pHphxHx8IFUXi88UiU"
livemode: false
locale: null
metadata: {}
mode: "payment"
object: "checkout.session"
payment_intent: "pi_3KNLxZF1gqmNMMdG1Ow9eJFc"
payment_link: null
payment_method_options: {}
payment_method_types: ['card']
payment_status: "unpaid"
phone_number_collection: {enabled: false}
recovered_from: null
setup_intent: null
shipping: null
shipping_address_collection: null
shipping_options: []
shipping_rate: null
status: "open"
submit_type: null
subscription: null
success_url: "http://127.0.0.1:3000/"
total_details: {amount_discount: 0, amount_shipping: 0, amount_tax: 0}
url: "https://checkout.stripe.com/pay/cs_test_a1spczl6c2aTyF1K3DZ1nNmPWugoxgPqeREy4f85pHphxHx8IFUXi88UiU#fidkdWxOYHwnPyd1blpxYHZxWjA0TktEMElDNGJ0aEtISGFCb3JQYGM9T0F9UHFMPXAzamkxMDB3PXJKX31IUVcyQHRkTHA9cFE8ckx1SDRnY3xkU3M8PXZuSHBIcldUSmFrVzdjZGdJd3E8NTVnSEhfYnBvUScpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXdwYHgl"
[[Prototype]]: Object
[[Prototype]]: Object
Also when I check the stripe dash board there I can see incomplete payments.
Below is my code, can anyone help me with this?
import { loadStripe } from '#stripe/stripe-js';
export const session = async (tourID) => {
console.log('session');
// 1. GET CLIENT CHECKOUT SESSION FROM OUR API ENDPOINT
const url = `http://localhost:3000/api/vr1/accessBooking/client-checkout-session/${tourID}`;
// const url = `http://127.0.0.1:3000/api/vr1/accessBooking/client-checkout-session/${tourID}`;
try {
const response = await fetch(url, {
method: 'GET',
mode: 'same-origin',
});
const data = await response.json();
console.log(data);
// 2. CHARGE THE CARD WITHIN FORM
const stripe = await loadStripe(
'pk_test_51KNA5LF1gqmNMMdGjwUef8JD**MY_API_KEY**'
);
stripe.redirectToCheckout({
sessionId: data.session.id,
});
} catch (err) {
console.log(err);
}
};
But somehow I can not reach to the checkout page.
Stripe has a document about required CSP policies if you have CSP enabled in your app. Generally you would need
connect-src, https://api.stripe.com
frame-src, https://js.stripe.com, https://hooks.stripe.com
script-src, https://js.stripe.com

How to query an account to get only single object in quickbooks?

I am calling this function to get the accounts details with particular Name
const getAccount = async ({ realmId, auth }) => {
const postBody = {
url: `https://sandbox-quickbooks.api.intuit.com/v3/company/${realmId}/query?query=select * from Account where Name='Sales of Product Income'`,
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded",
Authorization: "Bearer " + auth
}
};
const data = await rp.get(postBody);
return JSON.parse(data);
};
However it is giving me data in an array
{
Account: [
{
Name: 'Sales of Product Income',
SubAccount: false,
FullyQualifiedName: 'Sales of Product Income',
Active: true,
Classification: 'Revenue',
AccountType: 'Income',
AccountSubType: 'SalesOfProductIncome',
CurrentBalance: 0,
CurrentBalanceWithSubAccounts: 0,
CurrencyRef: [Object],
domain: 'QBO',
sparse: false,
Id: '79',
SyncToken: '0',
MetaData: [Object]
}
],
startPosition: 1,
maxResults: 1
}
So I need to know is there any api to get single object instead of array in quickbooks or can I pass some parameter to get object?
This question is quite specific for quickbooks api. I never use this API before, but following the document, they provide filter data query like SQL
So, I think you can use a same api and change query. Something like SELECT * FROM your_table WHERE id = your_book_id

customize CRUD operation in loopback js

i am new to loopback js trying to create remote method Create,Read,update and delete operation.
i have created a model name class and now i want to write the crud operation in my project file
models/class.js file.
'use strict';
module.exports = function(Class) {
};
I have no idea how to do it , read docs but does not clearify things if anyone can give example to write CRUD operation would be better understanding. (Using loopback 3 for practice.)
To create a custom method for a model, you need to do two things:
1/ Create the method within your model like this:
module.exports = function (Mymodel) {
Mymodel.myCustomMethod = function (req, res, cb) {
// method body
}
}
2/ To declare the remote to your model, so it can be exposed
module.exports = function (Mymodel) {
/* custom methods, hooks, ... */
Mymodel.remoteMethod(
'myCustomMethod', {
http: {
path: '/myCustomMethod',
verb: 'post' // it could also be 'post', 'put', 'delete'
},
accepts: {
arg: 'data',
type: 'object', // accepting an object in the body
'http': {
source: 'body' // Reading the body of the request. It could also be 'req' to read the req url for parameters.
}
},
returns: {
type: 'object', // Returns an object to the front
root: true
}
}
)
}
This is an example for a 'post' remote method. A 'put' remote method will look exactly the same, except for the keyword 'put' instead of 'post'.
For a 'get' or 'delete' requests, only the request url will be read, so the remote method should contain:
http: { path: '/myCustomMethod/:projectId', verb: 'get' },
accepts: { arg: 'projectId', type: 'number' },
With projectId the name of a property given in the URL, and number being the type of projectId.

Loopback OAuth2 Authentification

I've got an issue when trying to protect my loopback endpoints with the oauth2 component.
I use a custom user model and a custom application model.
Here's are my oauth2 options
var options = {
dataSource: app.dataSources.db, // Data source for oAuth2 metadata persistence
userModel: 'LAccount',
applicationModel: 'LOAuthClientApp',
resourceServer: true,
authorizationServer: true,
//useAccessTokenModel: true,
authorizePath: '/oauth/authorize',
tokenPath: '/oauth/token',
supportedGrantTypes: [
'clientCredentials',
'refreshToken',
'resourceOwnerPasswordCredentials'
]
};
var oauth2 = require('loopback-component-oauth2').oAuth2Provider(
app, // The app instance
options // The options
);
I'm trying to protect some of my api endpoints
app.use([ '/api/mymodel/whoami', '/coordinator_noscope'], oauth2.authenticate({session: false}));
router.get('/coordinator_noscope', function(req, res) {
console.log(req.accessToken);
res.json({ 'result': 'done' });
});
Here my "MyModel" route
MyModel.remoteMethod('whoami', {
accepts: {arg: "options", type: "object", http: "optionsFromRequest"},
returns: { arg: 'object', type: 'object', root: true },
http: {path: '/whoami', verb: 'get'}
});
MyModel.whoami = function(options, callback) {
console.log(options.accessToken);
callback(null, new Success('done'));
};
When I'm getting an access token with a client (with the /oauth/authorize), the /coordinator_noscope route works, but the /api/mymodel/whoami get me a 401 (AUTHORIZATION_REQUIRED) error ..
I don't have any acls configured on "MyModel" model.
I don't understand what is the auth difference between the router.get route and the loopback api routes

Resources