How to send a get Request in AL - dynamics-business-central

I currently have 2 problems. I am trying to send a GetRequest to my web service. This is done with the SendNotify (phonenumber: text; template: text) method. When I call the method via an action, I get the following error message: Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.
When I debug, the program stops at the following line: ContentHeaders.Add('Authorization', 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2dsadaXdrZUZTTWpNcnlBc2s1IiwiZXhwIjoxNTk1NDA3NDgzLCJpYXQiOjE1OTQzNjgyNTR9.1tAsf-x2FEvhDMyB4dsvgVKfZMLwAHcr_OLRA8RBeiY');
The token is currently hard coded but should be removed from the service setup list.
Can anyone tell me what I am doing wrong?
codeunit 2020803 "Notify SMS Interface" implements SendNotifyInterface
{
procedure CheckInputData(NotifyEntry: Record "Notify Entry")
begin
NotifyEntry.Get();
end;
procedure SendNotify(phonenumber: text; template: text)
var
client: HttpClient;
RequestMessage: HttpRequestMessage;
RequestHeaders: HttpHeaders;
ResponseMessage: HttpResponseMessage;
NotifyServiceSetup: Record "Notify Service Setup";
JsonText: Text;
IsSuccessful: Boolean;
SendSMSURL: text;
begin
NotifyServiceSetup.Get();
SendSMSURL := NotifyServiceSetup."Service URL" + '/contacts/contacts/sms/' + 'sagos/' +
phonenumber + '/' + template;
JsonText := BuildJsonText();
InitHttpRequestContent(RequestMessage, JsonText);
InitHttpRequestMessage(RequestMessage, SendSMSURL, 'GET');
IsSuccessful := client.Send(RequestMessage, ResponseMessage);
if not IsSuccessful then
Error('Authentication failed!');
if not ResponseMessage.IsSuccessStatusCode then begin
Error('request was not successfully');
exit;
end;
end;
local procedure InitHttpRequestContent(var RequestMessage: HttpRequestMessage; JsonText: Text)
var
ContentHeaders: HttpHeaders;
NotifyServiceSetup: Record "Notify Service Setup WMR";
bearerToken: Text[250];
token: Text[250];
begin
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
bearerToken := 'Bearer ' + token;
NotifyServiceSetup.Get();
RequestMessage.Content().Clear();
RequestMessage.Content().WriteFrom(JsonText);
RequestMessage.Content().GetHeaders(ContentHeaders);
ContentHeaders.Clear();
ContentHeaders.Add('Content-Type', 'application/json');
ContentHeaders.Add('Authorization', 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2dsadaXdrZUZTTWpNcnlBc2s1IiwiZXhwIjoxNTk1NDA3NDgzLCJpYXQiOjE1OTQzNjgyNTR9.1tAsf-x2FEvhDMyB4dsvgVKfZMLwAHcr_OLRA8RBeiY');
end;
local procedure InitHttpRequestMessage(var RequestMessage: HttpRequestMessage; ServiceURL: Text; Method: Text)
var
RequestHeaders: HttpHeaders;
NotifyServiceSetup: Record "Notify Service Setup WMR";
token: Text[250];
bearerToken: Text[250];
begin
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
bearerToken := 'Bearer ' + token;
RequestMessage.GetHeaders(RequestHeaders);
RequestHeaders.Clear();
RequestHeaders.Add('Accept', 'application/json');
RequestHeaders.Add('Authorization', 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2dXdrZUZTTWpNcnlBc2s1IiwiZXhwIjoxNTk1NDA3NDgzLCJpYXQiOjE1OTQzNjgyNTR9.1tAsf-x2FEvhDMyB4dsvgVKfZMLwAHcr_OLRA8RBeiY');
RequestMessage.Method(Method);
RequestMessage.SetRequestUri(ServiceURL);
end;
local procedure BuildJsonText() ContentText: Text
var
ContentJson: JsonObject;
begin
ContentJson.WriteTo(ContentText);
end;
}
The second problem I have is checking the data in the CheckInputData (NotifyEntry: Record "Notify Entry") method. There is a field in the Notify Entry called Contact No. that has all the information about the customer. I want to ask in the method to have the phone number and the salutation available. Unfortunately I do not know how I got out of Contact No. Can request data. Would someone have a tip?
UPDATE 1
codeunit 2020808 Test
{
procedure sendNotify(phonenumber: text; template: text)
var
NotifyServiceSetup: Record "Notify Service Setup WMR";
IsSuccessful: Boolean;
client: HttpClient;
content: HttpContent;
contentHeaders: HttpHeaders;
request: HttpRequestMessage;
response: HttpResponseMessage;
txtResponse: InStream;
Url: Text;
token: Text[250];
begin
NotifyServiceSetup.Get();
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
content.GetHeaders(contentHeaders);
contentHeaders.Clear();
contentHeaders.Add('Content-Type', 'application/json');
request.GetHeaders(contentHeaders);
contentHeaders.Add('Authorization', StrSubstNo('Bearer %1', token));
request.Content := content;
Url := NotifyServiceSetup."Service URL" + '/contacts/contacts/sms/' + 'Tegos/' + phonenumber + '/' + template;
request.SetRequestUri(Url);
request.Method := 'GET';
client.Send(request, response);
response.Content().ReadAs(txtResponse);
end;[![enter image description here][1]][1]

If the problem seems to be in the contentHeader.Add() This happened to me too.
I leave you this code for you to take as a reference.
procedure CheckCodeWebService(_accessToken: Text; _salesHeader: record "Sales Header")
var
jsonRequest: Text;
txtResponse: InStream;
Url: Text;
client: HttpClient;
request: HttpRequestMessage;
response: HttpResponseMessage;
contentHeaders: HttpHeaders;
content: HttpContent;
begin
jsonRequest := '{' +
'"GetPurchaseOrder": {' +
'"value": {' +
'"DataArea": {' +
'"PurchaseOrder": [' +
'{' +
'"PurchaseOrderHeader": {' +
'"ID": {' +
'"value": ""' +
'},' +
'"DocumentReference": [' +
'{' +
'"ID": {' +
'"value": " ' + _salesHeader.DealID + ' "' +
'}' +
'}' +
'],' +
'"SalesOrderReference": [' +
'{' +
'"ID": {' +
'"value": " ' + _salesHeader.SalesOrderNroCisco + ' "' +
'}' +
'}' +
'],' +
'"Description": [' +
'{' +
'"value": "yes",' +
'"typeCode": "details"' +
'}' +
']' +
'}' +
'}' +
']' +
'},' +
'"ApplicationArea": {' +
'"CreationDateTime": "datetime",' +
'"BODID": {' +
'"value": "BoDID-test",' +
'"schemeVersionID": "V1"' +
'}' +
'}' +
'}' +
'}' +
'}';
content.WriteFrom(jsonRequest);
content.GetHeaders(contentHeaders);
contentHeaders.Clear();
contentHeaders.Add('Content-Type', 'application/json');
request.GetHeaders(contentHeaders);
contentHeaders.Add('Authorization', StrSubstNo('Bearer %1', _accessToken));
contentHeaders.Add('Accept', 'application/xml');
request.Content := content;
Url := 'https://api.xxxx.com/xxxxx/ORDER/v2/sync/xxxxxxxx';
request.SetRequestUri(Url);
request.Method := 'POST';
client.Send(request, response);
response.Content().ReadAs(txtResponse);

Okay problem solved. Instead of the content type I have now entered RequestHeaders.Add ('Accept', 'application / json'). Now the GetRequest works.
codeunit 2020808 Test
{
procedure sendNotify(phonenumber: text; template: text)
var
NotifyServiceSetup: Record "Notify Service Setup WMR";
IsSuccessful: Boolean;
client: HttpClient;
content: HttpContent;
contentHeaders: HttpHeaders;
request: HttpRequestMessage;
response: HttpResponseMessage;
txtResponse: InStream;
Url: Text;
token: Text[250];
begin
NotifyServiceSetup.Get();
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
content.GetHeaders(contentHeaders);
contentHeaders.Clear();
//contentHeaders.Add('Content-Type', 'application/json');
request.GetHeaders(contentHeaders);
contentHeaders.Add('Authorization', StrSubstNo('Bearer %1', token));
contentHeaders.Add('Accept', 'application/json');
//request.Content := content;
Url := NotifyServiceSetup."Service URL" + '/contacts/contacts/sms/' + 'Tegos/' + phonenumber + '/' + template;
request.SetRequestUri(Url);
request.Method := 'GET';
client.Send(request, response);
response.Content().ReadAs(txtResponse);
end;
}

Related

Next Auth with Zitadel cloud: expected 200 OK, got: 301 Moved Permanently

Using next.js, next-auth with zitadel
import ZitadelProvider from "next-auth/providers/zitadel";
...
providers: [
ZitadelProvider({
issuer: process.env.ZITADEL_ISSUER,
clientId: process.env.ZITADEL_CLIENT_ID,
clientSecret: process.env.ZITADEL_CLIENT_SECRET,
})
]
...
And .env
NEXTAUTH_SECRET=random
NEXTAUTH_URL=http://localhost:3000
# Next Auth ZITADEL Provider
ZITADEL_CLIENT_ID=xyz#myproject
ZITADEL_CLIENT_SECRET=random
ZITADEL_ISSUER=https://myinstance-qz4usg.zitadel.cloud/
I get the following error when I try to sign in with zitadel
[next-auth][error][SIGNIN_OAUTH_ERROR]
https://next-auth.js.org/errors#signin_oauth_error expected 200 OK, got: 301 Moved Permanently {
error: {
message: 'expected 200 OK, got: 301 Moved Permanently',
stack: 'OPError: expected 200 OK, got: 301 Moved Permanently\n' +
' at processResponse (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/openid-client/lib/helpers/process_response.js:41:11)\n' +
' at Function.discover (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/openid-client/lib/issuer.js:152:20)\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (node:internal/process/task_queues:96:5)\n' +
' at async openidClient (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/core/lib/oauth/client.js:16:14)\n' +
' at async getAuthorizationUrl (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/core/lib/oauth/authorization-url.js:67:18)\n' +
' at async Object.signin (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/core/routes/signin.js:38:24)\n' +
' at async AuthHandler (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/core/index.js:253:26)\n' +
' at async NextAuthHandler (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/next/index.js:23:19)\n' +
' at async /Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/next/index.js:59:32\n' +
' at async Object.apiResolver (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/api-utils/node.js:363:9)\n' +
' at async DevServer.runApi (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/next-server.js:487:9)\n' +
' at async Object.fn (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/next-server.js:749:37)\n' +
' at async Router.execute (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/router.js:253:36)\n' +
' at async DevServer.run (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/base-server.js:384:29)\n' +
' at async DevServer.run (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/dev/next-dev-server.js:741:20)\n' +
' at async DevServer.handleRequest (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/base-server.js:322:20)',
name: 'OPError'
},
providerId: 'zitadel',
message: 'expected 200 OK, got: 301 Moved Permanently'
}
Copying the issuer url from the .well-known/openid-configuration endpoint put a trailing '/' at the end of my issuer (as can be seen in my .env above).
Removing the '/' fixed it.
i.e. ZITADEL_ISSUER=https://myinstance-qz4usg.zitadel.cloud

response of react native get request gets status text undefined

I'm new to React Native and I'm calling an API with params. It looks like this.
async onSendClick() {
AsyncStorage.getItem('#Token:key').then((token) => {
console.log("console is " + token)
let subject = "Feedback Form"
let senderEmail = 'test#test.com'
let fromEmail = 'us#test.com'
let replyTo = 'customer#test.com'
let url = BASE_URL + '/email/send?'
let params = "subject=" + subject + "&email=" +senderEmail + "&fromEmail=" + fromEmail + "&replyTo=" + replyTo + "&content=" + feedBackMessage
return fetch(url + params , {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
}).then((responseOne) => {
console.log(responseOne)
if (responseOne.status == 200) {
console.log("success")
} else{
console.log("error")
}
}).catch((error) => console.error("ERROR" + error));
})
}
In the response section , I'm getting 404 error with statusText: undefined. Please help me to fix this issue.
You must encode the URI. Otherwise it will not work.
Follow this link for more info about URL encoding in javascript.

Trying To Include Email Address (or User's Name) In Notification Email

I have a Page Fragment that allows users to create an entry. When they click the send button it runs the following:
newSOEmailMessage(widget);
widget.datasource.createItem();
app.closeDialog();
This activates a Client Script that sends an email to the user which includes the values from the widget fields:
function newSOEmailMessage(sendButton) {
var pageWidgets = sendButton.root.descendants;
var currentuser = Session.getActiveUser().getEmail();
var htmlbody = currentuser + 'has created new system order for: <h1><span style="color:#2196F3">' + pageWidgets.ShowName.value + ' - ' + pageWidgets.UsersPosition.value + '</h1>' +
'<p>R2 Order #: <b>' + pageWidgets.R2OrderNumber.value + '</b>' +
'<p>Delivery Date: <b>' + pageWidgets.DeliveryDate.value.toDateString() + '</b>' +
'<p>Start of Billing: <b>' + pageWidgets.SOB.value.toDateString() + '</b>' +
'<p>Sales Person: <b>' + pageWidgets.SalesPerson.value + '</b>' +
'<p> </p>' +
'<p>Company: <b>' + pageWidgets.Company.value + '</b>' +
'<p> </p>' +
'<p>Notes: <b>' + pageWidgets.Notes.value + '</b>';
google.script.run
.withSuccessHandler(function() {
})
.withFailureHandler(function(err) {
console.error(JSON.stringify(err));
})
.sendEmailCreate(
'user#email.com',
'New order for: ' + pageWidgets.ShowName.value + ' - ' + pageWidgets.UsersPosition.value,
htmlbody);
}
All of this works fine except the "currentuser" option (after var htmlbody =). With the code above I get the following error:
Session is not defined
at newSOEmailMessage (Notifications_ClientScripts:7:45)
at SystemOrders_Add.SubmitButton.onClick:1:1
I would like "currentuser" to equal the email address (or preferably the user's actual name).
ex: "John Doe has created a new system order for..."
What am I missing?
Thank you!
Note: I already have a Directory Model setup to show user's names in a comments section for a different Model. That Model is running the following (I'm assuming I could add that to my SystemOrders model?)
// onCreate
var email = Session.getActiveUser().getEmail();
var directoryQuery = app.models.Directory.newQuery();
directoryQuery.filters.PrimaryEmail._equals = email;
var reporter = directoryQuery.run()[0];
Looks like you are mixing server and client side APIs
// It is server side API
var email = Session.getActiveUser().getEmail();
// It is client side API
var email = app.user.email;
If you want to utilize user Full Name from the directory, then you need to load it advance, for instance in app startup script:
// App startup script
// CurrentUser - assuming that it is Directory model's datasource
// configured to load record for current user.
loader.suspendLoad();
app.datasources.CurrentUser.load({
success: function() {
loader.resumeLoad();
},
failure: function(error) {
// TODO: Handle error
}
});
So, you can refer to this datasource item later in your code:
var fullName = app.datasources.CurrentUser.item.FullName;
Also, I would recommend send emails only when record is actually created:
// Sends async request to server to create record
widget.datasource.createItem(function() {
// Record was successfully created
newSOEmailMessage(widget);
});

how to make http get request using TclientSocket?

I tried the following HTTP GET request
function CreateHTTPRequest(Site: String): String;
var
Request: String;
begin
Randomize;
Request := 'GET ' + Site + ' HTTP/1.1' + #13#10;
Request := Request + 'Host: ' + Site + #13#10;
Request := Request + 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' + #13#10;
Request := Request + 'Accept-Language: en-us,en' + #13#10;
Request := Request + 'User-Agent: ' + UserAgent + #13#10;
Request := Request + 'Referer: ' + Referer + #13#10;
Request := Request + 'Connection: close' + #13#10#13#10;
Result := Request;
end;
var
httpSocket: TClientSocket;
Site: String;
Target : string;
begin
httpSocket := TClientSocket.Create(nil);
httpSocket.Host := 'www.google.com';
httpSocket.Port := 80;
httpSocket.ClientType := ctBlocking;
httpSocket.Active := True;
if httpSocket.Socket.Connected=True then
begin
memo1.Lines.Add('requested');
Site := 'http://' + 'google.com';
httpSocket.Socket.SendText(CreateHTTPRequest(Site));
memo1.Lines.Add(httpSocket.Socket.ReceiveText);
httpSocket.Active := False;
end;
httpSocket.Free;
end;
I don't get any response from this. What did I do wrong? I cannot do any more HTTPS requests with TclientSocket. Is it dead already?

Can't get the token of the Google account

I follow the instruction to send the id token of the Google account to the back end server to be authenticated but it seems like the token does not exist.
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
var id_token = googleUser.getAuthResponse().id_token;
console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
console.log('Name: ' + profile.getName());
console.log('Image URL: ' + profile.getImageUrl());
console.log('Email: ' + profile.getEmail());
console.log('Token: ' + id_token);
}
The line Token: is not printed in the console. Anybody could tell me what's going on? Much appreciated

Resources