I am trying to create a component that makes a post request to a custom action in my environment. This action has an input called leadid and an output called data, and when called triggers a custom plugin. However, I am having trouble trying to figure out how to call this action from my component.
I understand that you can make calls using this._context.webAPI.retrieveMultipleRecords(entity, query) but I am not trying to achieve this.
I have tried the following directly in the console (in the browser) and it works perfectly, but I get an error Xrm is not defined when using the same code in my TypeScript file:
fetch(Xrm.Page.context.getClientUrl() + "/api/data/v9.2/dev_GetData", {
"method":"POST",
"headers":{
"Accept": "application/json",
"Content-Type": "application/json; charset=utf-8",
"OData-MaxVersion": "4.0",
"OData-Version": "4.0"
},
"body": JSON.stringify({
"leadid": "7ba18ae0-4d0e-ea11-a813-000d3a1bbd52"
})
}).then((response) => response.json())
.then((data) => {
console.log(data);
})
I find this odd as when I hover over the other parts (page, context, getClientUrl), it gives me the details of what It does.
What might I be doing wrong, or how may I get the client url without using Xrm.page...?
There is Managed solution/Additional Tool for Dataverse which will give you code snippet with actual values for webapi call.
Tool is Dataverse Rest Builder
https://www.xrmtoolbox.com/plugins/GuidoPreite.DRB/
Example code snippet for Lead qualification Action
var execute_QualifyLead_Request = {
// Parameters
entity: { entityType: "lead", id: "524a9e0b-f3e6-e711-80e9-005056936c69" }, // entity
CreateAccount: true, // Edm.Boolean
CreateContact: true, // Edm.Boolean
CreateOpportunity: true, // Edm.Boolean
Status: 1, // Edm.Int32
getMetadata: function () {
return {
boundParameter: "entity",
parameterTypes: {
entity: { typeName: "mscrm.lead", structuralProperty: 5 },
CreateAccount: { typeName: "Edm.Boolean", structuralProperty: 1 },
CreateContact: { typeName: "Edm.Boolean", structuralProperty: 1 },
CreateOpportunity: { typeName: "Edm.Boolean", structuralProperty: 1 },
Status: { typeName: "Edm.Int32", structuralProperty: 1 }
},
operationType: 0, operationName: "QualifyLead"
};
}
};
Xrm.WebApi.online.execute(execute_QualifyLead_Request).then(
function success(response) {
if (response.ok) { return response.json(); }
}
).then(function (responseBody) {
var result = responseBody;
console.log(result);
// Return Type: Collection(mscrm.crmbaseentity)
}).catch(function (error) {
console.log(error.message);
});
[1]: https://github.com/GuidoPreite/DRB
Related
I need to do a new api in order to send an email with sendgrid. I followed the official doc and other examples so I did:
config/plugins
module.exports = ({ env }) => ({
email: {
provider: 'sendgrid',
providerOptions: {
apiKey: env('SENDGRID_API_KEY'),
},
settings: {
defaultFrom: 'juliasedefdjian#strapi.io',
defaultReplyTo: 'juliasedefdjian#strapi.io',
},
},
});
then I did a new folder named email in api folder
api/email/config/routes.json
{
"routes": [
{
"method": "POST",
"path": "/email",
"handler": "email.index",
"config": {
"policies": []
}
}
]
}
finally under api/email/controllers/email.js
const { default: createStrapi } = require('strapi');
module.exports = {
index: async (ctx) => {
//build email with data from ctx.request.body
await createStrapi.plugins['email'].services.email.send({
to: 'email#email.com',
from: 'email#email.com',
replyTo: 'email#email.com',
subject: 'test',
text: 'test',
});
ctx.send('Email sent!');
},
};
The real problem is that /email api returns me a 403 even if I did this from the dashboard:
I have done many APIs with strapi but I have never sent emails with it.
Is there a way to add permissions from the code? I have to say that if I use GET method it works, but I need to do it with a POST method, which doesn't. Did I miss something?
I'm writing a WordPress plugin that creates a block, the block needs to pull data using a custom REST endpoint that returns, in the example below, a simple string. I'd like to include this string in the return from edit() and save() in my registerBlockType config but. I'm using fetch() to call the REST endpoint but this, obviously, is async. Any thoughts on the best way to do this appreciated, thanks:
const { registerBlockType } = wp.blocks
registerBlockType( 'daisy-views/da-test', {
title: 'Daisy Test: Test Block',
icon: 'format-gallery',
category: 'common',
attributes: {
gid: {
default: 2,
type: 'integer'
},
},
edit( props ) {
const restEP = daRestUrl + 'test'
fetch( restEP, {
body: JSON.stringify( {p: 'test param'}), // test parameters
cache: 'no-cache',
method: 'POST',
redirect: 'follow',
referrer: 'no-referrer',
headers : {
'Access-Control-Allow-Origin' : '*',
'X-WP-Nonce' : wpApiSettings.nonce,
}
})
.then( response => {
response.json()
.then( data => {
var returnValue = data.data // REST test, returns a string
console.log( 'Fetch returns: ', returnValue )
})
})
return <div>
test block edit
{/* return value from fetch here */}
</div>
},
save( props ) {
return <div>
Test Block
{/* return value from fetch here */}
</div>
}
} );
My best solution, to date, is to add a code attribute and have the fetch call fill that attribute with HTML. if fetch is called directly in the edit function there needs to be a check to prevent it from being called in an endless loop when it updates the attribute.
There is a nice example how Rollup function could be called via MS CRM WebApi here.
But it covers general access to CRM WebApi. Although in most recent versions new JS namespace Xrm.WebApi was introduced. Which provides more straightforward way to access that endpoint.
Method Xrm.WebApi.execute should be able to execute Rollup request, as it is able to execute WhoAmI. But I'm struggling to figure out correct values of parameters to make this execution happen.
Here is my code:
var RollupRequest = function(entityType, id, query) {
this.Target = { entityType: entityType, id: id };
this.RollupType = "Related";
this.Query = {
Query: query
};
};
RollupRequest.prototype.getMetadata = function() {
return {
boundParameter: null,
parameterTypes: {
Target: {
typeName: "Microsoft.Xrm.Sdk.EntityReference",
structuralProperty: 5
},
RollupType: {
typeName: "Microsoft.Dynamics.CRM.RollupType",
structuralProperty: 3
},
Query: {
typeName: "Microsoft.Xrm.Sdk.Query.FetchExpression",
structuralProperty: 5
}
},
operationType: 1, // This is a function. Use '0' for actions and '2' for CRUD
operationName: "Rollup"
};
};
var request = new RollupRequest(
"contact",
"0473FD41-C744-E911-A822-000D3A2AA2C5",
"<fetch><entity name='activitypointer'></entity></fetch>"
);
Xrm.WebApi.execute(request).then(
function(data) {
console.log("Success: ", data);
},
function(error) {
console.log("Failure: ", error);
}
);
The code generates following URL:
/api/data/v9.0/Rollup(Target=#Target,RollupType=#RollupType,Query=#Query)?#Target={"#odata.id":"contacts(0473FD41-C744-E911-A822-000D3A2AA2C5)"}&#RollupType=&#Query={"Query":"<fetch><entity name='activitypointer'></entity></fetch>"}
and the error: "Expression expected at position 0 in ''."
Which, seems to be, indicates that RollupType was not set correctly, because indeed in URL RollupType is missing.
I assume there are more than one potential error, because I'm using FetchXML as query expression. But meanwhile is it possible indicate what should be changed to generate proper URL at least for RollupType property?
I'm currently trying to write some functionality that requires the response.request.responseURL value to be set when axios handles the response. However, I can't seem to set this value with moxios. Here's what my test looks like:
it('resets list selection if input contents were replaced', (done) => {
component.currently_selected_list_value = 10;
component.last_called_url = 'henkiehoutman';
let input = domElt.querySelector('input');
ReactTestUtils.Simulate.change(input);
moxios.wait(() => {
let request = moxios.requests.mostRecent();
request.respondWith({
status: 200,
response: [{
customer_info_customers: ['', '', '', '', ''],
domain_info_customers: {},
}],
request: {responseURL: 'banaan'}
}).then(() => {
// The contents were replaced, so it's best to forget whatever our selection was.
expect(component.currently_selected_list_value).toEqual(-1);
done();
});
});
});
This is what my actual application looks like:
onChange (event) {
return axios.get(
this.props.ApiUrl + encodeURIComponent(event.target.value)
).then(
(response) => {
let response_url = response.request.responseURL; // This is the value I want to set manually.
if(this.shouldHandleResponse(response_url)){
this.last_called_url = response_url;
let data = response.data;
this.setState({results: data, dropdown: data.length > 0});
if ( this.currently_selected_list_value > max_index) {
this.currently_selected_list_value = max_index;
}
}
}
);
},
However, when I log what this value is, it just says undefined. And this is what the actual response.request value is (put it in a quote so it's a bit more readable):
LOG: Request{resolve: function (a) { ... }, reject: function (a) { ... }, config: Object{adapter: function mockAdapter(config) { ... }, transformRequest: Object{0: ...}, transformResponse: Object{0: ...}, timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, validateStatus: function validateStatus(status) { ... }, headers: Object{Accept: ..., X-CSRFToken: ...}, method: 'get', url: 'my_api_url/', data: undefined}, headers: Object{Accept: 'application/json, text/plain, /', X-CSRFToken: 'my_csrf_token'}, url: 'my_api_url/', timeout: 0, withCredentials: false, responseType: undefined}
This breaks my application, because a responseURL should always be defined. It looks like it's overwriting the request I defined in moxios. This is not necessarily a bad thing, because I assume it needs these things to function properly. However, it would be nice if I could add some values to this request.
So; How do I add a responseURL value to this request in moxios?
Turns out that it's not possible to set the responseURL because of the way I chained it to respondWith(). After checking this function in the moxios source code I saw that the values you pass in here really only have to do with actual data being returned, not an actual response object.
I also saw that the respondWith() function returns a Promise object, which is quite logical. I figured that I should not set anything on the Promise, but on the actual request. So I assigned the returned Promise to a promise variable and unchained the .then() part of the test. I set the request'sresponseURL after that. Then I called promise.then() again to assert that my test has passed.
Here is what I eventually went for:
it('resets list selection if input contents were replaced', (done) => {
component.currently_selected_list_value = 10;
component.last_called_url = 'henkiehoutman';
let input = domElt.querySelector('input');
ReactTestUtils.Simulate.change(input);
moxios.wait(() => {
let request = moxios.requests.mostRecent();
let promise = request.respondWith({
status: 200,
response: [{
customer_info_customers: ['', '', '', '', ''],
domain_info_customers: {},
}],
});
request.responseURL = 'banaan';
promise.then(() => {
// The contents were replaced, so it's best to forget whatever our selection was.
expect(component.currently_selected_list_value).toEqual(-1);
done();
});
});
});
I have a Web API which is returning a response in JSON, in this format:
{
"email": "john#google.com",
"password": null,
"accessLevel": 2
}
I am trying to access the accessLevel field within that response, but I am getting this Angular error:
Error in resource configuration for action `query`. Expected response to contain an array but got an object (Request: GET http://localhost:51608/api/UserRole?email=john#google.com...)
This is my Angular resource code (below), I just added the isArray false to attempt to solve the issue:
function userRoleResource($resource, appSettings) {
return $resource(appSettings.serverPath + "/api/UserRole?email=:email", { email: '#email' },
{
get: {
method: 'GET',
isArray: false
}
});
}
And this is how I am attempting to use the data:
userRoleResource.query({ email: vm.userData.email },
function (data) {
vm.userData.accessLevel = data.AccessLevel;
});
you're specifying that the 'get' function is not an array, but you're using the 'query' function.
try this:
userRoleResource.get({ email: vm.userData.email },
function (data) {
vm.userData.accessLevel = data.AccessLevel;
});