I created a web application that is using the outlook rest api V2.0.
I can authenticate the user en get the mail massages en calendar items. Problem is when i want to send a mail i am getting http error 400.
My outlook.php file
<?php
class OutlookService
{
private static $outlookApiUrl = "https://outlook.office.com/api/v2.0";
public static function stuurEmail($access_token, $user_email, $data)
{
$getMessagesUrl = self::$outlookApiUrl."/Me/sendmail?".http_build_query($data);
return self::makeApiCall($access_token, $user_email, "POST", $getMessagesUrl);
}
public static function sendMail ($access_token,$user_email)
{
$sentMessagesParameters = '{"Message":{"Subject":"Meet for lunch?","Body":{"ContentType":"Text","Content":"The new cafeteria is open."},"ToRecipients":[{"EmailAddress":{"Address":"danny.herremans#rkg.vlaanderen"}}]},"SaveToSentItems":"true"}';
$json=json_encode($sentMessagesParameters, true);
$getMessagesUrl = self::$outlookApiUrl."/me/sendmail?".http_build_query($sentMessagesParameters);
return self::makeApiCall($access_token, $user_email, "POST",$getMessageUrl,$json);
}
public static function getPhoto($access_token)
{
$getUserParameters = array (
// Only return the user's display name and email address
"\$select" => "Photo"
);
$getUserUrl = self::$outlookApiUrl."/Me?".http_build_query($getUserParameters);
return self::makeApiCall($access_token, "", "GET", $getUserUrl);
}
public static function getUser($access_token)
{
$getUserParameters = array
(
// Only return the user's display name and email address
"\$select" => "DisplayName,EmailAddress,Alias"
);
$getUserUrl = self::$outlookApiUrl."/Me?".http_build_query($getUserParameters);
return self::makeApiCall($access_token, "", "GET", $getUserUrl);
}
public static function getMessages($access_token, $user_email)
{
$getMessagesParameters = array (
// Only return Subject, ReceivedDateTime, and From fields
"\$select" => "Subject,ReceivedDateTime,From",
// Sort by ReceivedDateTime, newest first
"\$orderby" => "ReceivedDateTime DESC",
// Return at most 10 results
"\$top" => "10"
);
$getMessagesUrl = self::$outlookApiUrl."/Me/MailFolders/Inbox/Messages?".http_build_query($getMessagesParameters);
return self::makeApiCall($access_token, $user_email, "GET", $getMessagesUrl);
}
public static function getEvents($access_token, $user_email)
{
$getEventsParameters = array (
// Only return Subject, Start, and End fields
"\$select" => "Subject,Start,End",
// Sort by Start, oldest first
"\$orderby" => "Start/DateTime",
// Return at most 10 results
"\$top" => "10"
);
$getEventsUrl = self::$outlookApiUrl."/Me/Events?".http_build_query($getEventsParameters);
return self::makeApiCall($access_token, $user_email, "GET", $getEventsUrl);
}
public static function getContacts($access_token, $user_email)
{
$getContactsParameters = array (
// Only return GivenName, Surname, and EmailAddresses fields
"\$select" => "GivenName,Surname,EmailAddresses",
// Sort by GivenName, A-Z
"\$orderby" => "GivenName",
// Return at most 10 results
"\$top" => "10"
);
$getContactsUrl = self::$outlookApiUrl."/Me/Contacts?".http_build_query($getContactsParameters);
return self::makeApiCall($access_token, $user_email, "GET", $getContactsUrl);
}
public static function makeApiCall($access_token, $user_email, $method, $url, $payload = NULL)
{
// Generate the list of headers to always send.
$headers = array(
"User-Agent: php-tutorial/1.0", // Sending a User-Agent header is a best practice.
"Authorization: Bearer ".$access_token, // Always need our auth token!
"Accept: application/json", // Always accept JSON response.
"client-request-id: ".self::makeGuid(), // Stamp each new request with a new GUID.
"return-client-request-id: true", // Tell the server to include our request-id GUID in the response.
"X-AnchorMailbox: ".$user_email // Provider user's email to optimize routing of API call
);
$curl = curl_init($url);
switch(strtoupper($method)) {
case "GET":
// Nothing to do, GET is the default and needs no
// extra headers.
error_log("Doing GET");
break;
case "POST":
error_log("Doing POST");
// Add a Content-Type header (IMPORTANT!)
$headers[] = "Content-Type: application/json";
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
break;
case "PATCH":
error_log("Doing PATCH");
// Add a Content-Type header (IMPORTANT!)
$headers[] = "Content-Type: application/json";
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
break;
case "DELETE":
error_log("Doing DELETE");
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
break;
default:
error_log("INVALID METHOD: ".$method);
exit;
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($curl);
error_log("curl_exec done.");
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
error_log("Request returned status ".$httpCode);
if ($httpCode >= 400) {
return array('errorNumber' => $httpCode,
'error' => 'Request returned HTTP error '.$httpCode);
}
$curl_errno = curl_errno($curl);
$curl_err = curl_error($curl);
if ($curl_errno) {
$msg = $curl_errno.": ".$curl_err;
error_log("CURL returned an error: ".$msg);
curl_close($curl);
return array('errorNumber' => $curl_errno,
'error' => $msg);
}
else {
error_log("Response: ".$response);
curl_close($curl);
return json_decode($response, true);
}
}
// This function generates a random GUID.
public static function makeGuid()
{
if (function_exists('com_create_guid')) {
error_log("Using 'com_create_guid'.");
return strtolower(trim(com_create_guid(), '{}'));
}
else {
error_log("Using custom GUID code.");
$charid = strtolower(md5(uniqid(rand(), true)));
$hyphen = chr(45);
$uuid = substr($charid, 0, 8).$hyphen
.substr($charid, 8, 4).$hyphen
.substr($charid, 12, 4).$hyphen
.substr($charid, 16, 4).$hyphen
.substr($charid, 20, 12);
return $uuid;
}
}
}
?>
So in my home.php file i have the following code for sending the mail
if(isset($_POST['mailing']))
{
#extract($_POST);
$arr = '{
"Message": {
"Subject": "Meet for lunch?",
"Body": {
"ContentType": "Text",
"Content": "The new cafeteria is open."
},
"ToRecipients": [
{
"EmailAddress": {
"Address": "xxxxxxxxx#xxxx.xxx"
}
}
]
},
"SaveToSentItems": "true"
}';
$data=json_encode($arr, true);
$message = OutlookService::stuurEmail(oAuthService::getAccessToken($redirectUri), $_SESSION['user_email'], $data);
print_r($message);
echo"
<div class='alert alert-success'>
<a href='#' title='Sluit deze melding'
class='close' data-dismiss='alert' aria-label='close'>×
</a>
<br>".$_SESSION['access_token']."<br>".$_SESSION['user_email']."<br>$data<br>
</div>
";
}
When i wont to sent a mail i am getting the following error:
Warning: http_build_query(): Parameter 1 expected to be Array or Object. Incorrect value given in /var/www/vhosts/rkgvlaande05001/test/outlook.php on line 14 Array ( [errorNumber] => 400 [error] => Request returned HTTP error 400 )
Any idea what not right in the code or has anyone has a working example for the outlook rest api V2.0?
Thx
I checked you code and the sentMessagesParameters content is correct. However, I found this post mentioned, "you need to 'send mail as a user' permission for O365 Exchange Online in Azure AD if you want to send a mail message with REST API ". Please see the following link:
Outlook Rest Api sending Mail Request returned status 400
Related
I am new to Laravel 9 and usage of Twilio API.
I am trying to create a scenario where a customer_care will call the first participant and after talking with the participant it will call the second participant with whom the first participant will communicate. While calling the second participant, the first participant's call will be kept on hold and after the second participant receives the call both their call will be merged so that they are connected to the same call.
I have written two separate function one for the first call and the other for the second call . The first function is:
public function twiliocall1(Request $request) {
$returnArray = array();
$status = "Error";
$msg = "Call not started";
$validator = Validator::make($request->all(), [
'participants' => 'required|array',
'twilloNo' => 'required',
'contact_id' => 'required'
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 401);
}
$twilloNo = $request->input('twilloNo');
$participants = $request->input('participants');
$sid = "xxxxx";
$token = "yyyy";
$client = new Client($sid, $token);
if (!empty($participants)) {
foreach($participants as $participant) {
$call1 = $client->account->calls->create(
$participant,
$twilloNo,
array("url" => "https://lbwr.operative.dev/multitenant/public/files/conference.php")
);
}
$status = "Success";
$msg = "Call started";
echo($call1->sid);
}
$returnArray['status'] = $status;
$returnArray['msg'] = $msg;
return response()->json($returnArray, 200);
}
The second function is:
public function twiliocall2(Request $request) {
$returnArray = array();
$status = "Error";
$msg = "Call not started";
$validator = Validator::make($request->all(), [
'participants' => 'required|array',
'twilloNo' => 'required',
'contact_id' => 'required',
'sid' => 'required'
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 401);
}
$twilloNo = $request->input('twilloNo');
$participants = $request->input('participants');
$parent_sid = $request->input('sid');
$sid = "xxxx";
$token = "yyyy";
$client = new Client($sid, $token);
foreach($participants as $participant) {
$call = $client->account->calls->get($parent_sid);
$call->update(
$participant,
$twilloNo,
array(
"Url" => "http://demo.twilio.com/docs/voice.xml",
"Method" => "POST"));
}
$status = "Success";
$msg = "Call started";
$returnArray['status'] = $status;
$returnArray['msg'] = $msg;
return response()->json($returnArray, 200);
}
$sid and $token value is same for both the function. I am trying to call the first function using the following json array:
{
"participants":["12345"],
"twilloNo":"68564",
"contact_id":"1234"
}
And on hitting I am getting the sid of this call which I am passing as a json array element to the function twiliocall2() as:
{
"participants":["+7777"],
"twilloNo":"111122",
"contact_id":"1023",
"sid":"fdthgfjkhbklnj"
}
All the values are changed.
The problem arises when I am calling the second function with this Json array as it throws an error:
Twilio\Exceptions\TwilioException: Unknown subresource get in file /opt/lampp/htdocs/multitenant/vendor/twilio/sdk/src/Twilio/Rest/Api/V2010/Account/CallList.php
Kindly suggest if possible where am I going wrong. I am not getting any idea how to implement this scenario any further.
The code in the Controller is as follows which parse an JSON and creates a Conference object where the error is occouring:
public function twilioConferenceCall(Request $request) {
$returnArray = array();
$status = "Error";
$msg = "Call not started";
$validator = Validator::make($request->all(), [
'participants' => 'required|array',
'fromNo' => 'required|numeric',
'twilloNo' => 'required',
'contact_id' => 'required'
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 401);
}
$fromNo = $request->input('fromNo');
$twilloNo = $request->input('twilloNo');
$sid = "someid";
$token = "sometoken";
$client = new Client($sid, $token);
$conference = $client->conferences->create([
'friendlyName' => 'Test Conference Call'
]);
$conference_sid = $conference->sid;
if ($fromNo != "" && !empty($request->participants)) {
foreach($request->participants as $participant) {
$concall = $client->account->calls->create(
$participant,
$twilloNo,
array(
"url" => "http://twimlets.com/conference?Name=Test%20Conference%20Call&ConferenceSid=".$conference_sid."&Moderators%5B0%5D=".$fromNo
)
);
$status = "Success";
$msg = "Started call to " . $participant;
}
}
$returnArray['status'] = $status;
$returnArray['msg'] = $msg;
return response()->json($returnArray, 200);
}
The JSON which am I sending is as follows:
{
"participants":["+1234","+9999"],
"fromNo":"+5678",
"twilloNo":"119988",
"contact_id":"1057"
}
The error which it throws is:
Error: Call to undefined method Twilio\Rest\Api\V2010\Account\ConferenceList::create()
I have included the following headers in my file
use Twilio\autoload;
use Twilio\Rest\Client;
Kindly suggest where am I doing wrong.
I have Twilio starting, pausing, resuming, and stopping the recording of in-progress inbound calls. However, when I use the same approach, same code, to record in-progress outbound calls I get a 20404 error.
I get that I can record outbound calls from the beginning using the <record> verb, but I need to be able to selectively record in-progress outbound calls.
As I say, I have it working for recording in-progress inbound calls, so I'm confused as to why the same approach doesn't work for in-progress outbound calls.
This is my javascript for initiating the recording of a call:
document.getElementById('button-record-start').onclick = function () {
var call_id = $('#call-id').val();
var csrf_token = $('meta[name="csrf-token"]').attr('content');
console.log(call_id);
console.log(csrf_token);
$.ajax({
url: 'https://my-url.ngrok.io/twilio/recording/start',
type: 'POST',
headers: {
'X-CSRF-TOKEN': csrf_token
},
data: {
call_id: call_id
},
dataType: 'JSON',
success: function (data) {
$('#recording-id').val(data.sid);
console.log(data);
},
error: function(xhr, status, error) {
console.log('error:');
console.log(xhr);
}
});
};
The ajax calls to this method in my php (Laravel):
public $twilio_api_base_url = 'https://api.twilio.com/2010-04-01/Accounts/';
public function start(Request $request)
{
$call_id = $request->input('call_id');
$url = $this->twilio_api_base_url . env('TWILIO_ACCOUNT_SID');
$url .= '/Calls/' . $call_id . '/Recordings.json';
$params = [ 'RecordingStatusCallback'=>'https://myapp.com/recording-events',
'RecordingStatusCallbackEvent' => 'in-progress'
];
$this->send_request_to_twilio($url, $params);
}
Method send_request_to_twilio looks like this:
public static function send_request_to_twilio($url, $params)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($ch, CURLOPT_USERPWD, env('TWILIO_ACCOUNT_SID') . ':' . env('TWILIO_AUTH_TOKEN') );
curl_exec($ch);
curl_close($ch);
}
$url is formulating correctly. The only thing I can think of is that maybe as I am on a trial account at the moment Twilio changes the CallSid when it finishes the obligatory recording telling me that I am on a trial account and then initiates the actual call. Is this correct? If so, how would I find out the new id once this has occurred?
Edit:
Adding this to show how I get the call sid:
$.getJSON('twilio/token')
.then(function (data) {
device = new Twilio.Device(data.token);
device.on('ready',function (device) {
console.log('device.on ready')
});
device.on('error', function (error) {
console.log('device.on error');
});
device.on('connect', function (conn) {
console.log('device.on connect');
var twilio_call_sid = conn.parameters.CallSid;
log_call_to_database(twilio_call_sid, 'connect');
});
// other stuff
});
And this is what my twilio/token that the getJSON calls to looks like:
public function new_twilio_token()
{
$twilio_account_sid = env('TWILIO_ACCOUNT_SID');
$twilio_auth_token = env('TWILIO_AUTH_TOKEN');
$twilio_application_sid = env('TWILIO_APPLICATION_SID');
$capability = new ClientToken($twilio_account_sid, $twilio_auth_token);
$capability->allowClientOutgoing($twilio_application_sid);
$identity = 'tom';
$capability->allowClientIncoming($identity);
$token = $capability->generateToken();
return response()->json(['token' => $token, 'identity' => $identity]);
}
Hel-lo! Need to retrieve GWT data (top pages, top queries, internal/external links, etc.). Wrote a php-script (based on this):
//"GetAccessCode.php" file
$OAuth = array(
'oauth_uri' => 'https://accounts.google.com/o/oauth2/auth',
'client_id' => 'here is my client id',
'client_secret' => 'here is my client secret',
'redirect_uri' => 'http://localhost/google/GetAccessCode.php',
'oauth_token_uri' => 'https://accounts.google.com/o/oauth2/token',
);
$token = array(
'access_token' => '',
'token_type' => '',
'expires_in' => '',
'refresh_token' => ''
);
$title = 'No Code';
$AuthCode = 'Null';
// see if error parameter exisits
$error = _get_url_param($_SERVER['REQUEST_URI'], 'error');
if ($error != NULL)
{ // this means the user denied api access to GWMTs
$title = $error;
}
else
{ // does the code parameter exist?
$AuthCode = _get_url_param($_SERVER['REQUEST_URI'], 'code');
if ($AuthCode == NULL)
{ // get authorization code
$OAuth_request = _formatOAuthReq($OAuth, "https://www.google.com/webmasters/tools/feeds/sites/"); //**WHAT URI NEED TO BE HERE?**
header('Location: ' . $OAuth_request);
exit; // the redirect will come back to this page and $code will have a value
}
else
{
$title = 'Got Authorization Code';
// now exchange Authorization code for access token and refresh token
$token_response = _get_auth_token($OAuth, $AuthCode);
$json_obj = json_decode($token_response);
$token['access_token'] = $json_obj->access_token;
$token['token_type'] = $json_obj->token_type;
$token['expires_in'] = $json_obj->expires_in;
$token['refresh_token'] = $json_obj->refresh_token;
$sites = _get_wmt_sites_feed($token);
echo $sites;
}
}
// Return the list of sites registered in your Google Webmaster Tools
function _get_wmt_sites_feed($access_tokens)
{
$post_string = "https://www.google.com/webmasters/tools/feeds/sites/"; //**WHAT URI NEED TO BE HERE?**
$post_string .= '?v=2';
$post_string .= '&oauth_token=' . $access_tokens['access_token'];
$response = file_get_contents($post_string);
return _parse_wmt_sites_response($response);
}
function _parse_wmt_sites_response($response)
{
$xml = simplexml_load_string($response);
$response = '<br />';
foreach ($xml->entry as $entry)
{
foreach ($entry->title as $title)
{
$response .= "<p>$title</p>";
}
}
return $response;
}
function _get_auth_token($params, $code)
{
$url = $params['oauth_token_uri'];
$fields = array(
'code' => $code,
'client_id' => $params['client_id'],
'client_secret' => $params['client_secret'],
'redirect_uri' => $params['redirect_uri'],
'grant_type' => 'authorization_code'
);
$response = _do_post($url, $fields);
return $response;
}
function _do_post($url, $fields)
{
$fields_string = '';
foreach ($fields as $key => $value)
{
$fields_string .= $key . '=' . $value . '&';
}
$fields_string = rtrim($fields_string, '&');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
function _formatOAuthReq($OAuthParams, $scope)
{
$uri = $OAuthParams['oauth_uri'];
$uri .= "?client_id=" . $OAuthParams['client_id'];
$uri .= "&redirect_uri=" . $OAuthParams['redirect_uri'];
$uri .= "&scope=" . $scope;
$uri .= "&response_type=code";
return $uri;
}
function _get_url_param($url, $name)
{
parse_str(parse_url($url, PHP_URL_QUERY), $params);
return isset($params[$name]) ? $params[$name] : null;
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><?= $title; ?></title>
</head>
<body>
<h1>OAuth2 Authorization Code</h1>
<p>Authorization Code: <?= $AuthCode; ?></p>
<p>access token: <?=$token['access_token'];?></p>
<p>expires in: <?=$token['expires_in'];?></p>
<p>refresh token: <?=$token['refresh_token'];?></p>
<p></p>
</body>
</html>
What URI need I to write in the code above instead of https:// www.google.com/webmasters/tools/feeds/sites/ to retrieve the desired data? In this nice code - https://github.com/eyecatchup/php-webmaster-tools-downloads - author uses https:// www.google.com/webmasters/tools/downloads-list?hl=en&siteUrl=http: //site.com/, but also he uses ClientLogin. I try to use this link in my script, but it generates mistakes, because, as I understand, this is not a right scope. So, what is right?
Also found this post here, it mentions about some Basic Authentication. I'm a beginner in Google API, please, tell, what do they mean?
Im using following ruby code to upload files to office 365
uri = URI.parse("#{site_url}/_api/v1.0/me/files/#{folder}/children/#{temp_file.original_filename}/content")
https = Net::HTTP.new(uri.host,uri.port)
https.use_ssl = true
req = Net::HTTP::Put.new(uri.path, initheader = {
'Content-Type' =>'application/octet-stream',
'Authorization' => 'Bearer ' + #current_user.o_auth_token,
'resource' => 'site_url'
})
req.set_form_data(
'file' => temp_file.read,
'Content-Type' => 'application/octet-stream'
)
JSON.parse(https.request(req).body)
The file uploaded to office 365 is corrupt. What's the issue in the code?
The following code in PHP works fine. Please note these are functions within a class and also requires creating a SharepointException class.
public function upload_file($folder_id, $filepath, $filename) {
//remove illegal characters form filename
try {
$filename = $this->clean_filename($filename);
} catch (SharepointException $e) {
throw new SharepointException($e->getMessage());
}
//build uri
if (is_null($folder_id)) {
$uri = $this->base_url . 'files/root/children/'.rawurlencode($filename).'/content?nameConflict=abort';
} else {
$uri = $this->base_url . 'files/'.$folder_id.'/children/'.rawurlencode($filename).'/content?nameConflict=abort';
}
$response = $this->upload($uri, $filepath);
if (array_key_exists('error', $response)) {
throw new SharepointException($response['error']);
}
return $response;
}
private function upload($uri, $filepath) {
$pointer = fopen($filepath, 'r+');
$stat = fstat($pointer);
$pointersize = $stat['size'];
$ch = curl_init($uri);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $pointer);
curl_setopt($ch, CURLOPT_INFILESIZE, (int)$pointersize);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
//Expect:
//HTTP response code 100 workaround
//see http://www.php.net/manual/en/function.curl-setopt.php#82418
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Expect:',
'Content-Type: application/json',
'Authorization: Bearer ' . $this->access_token,
));
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$accepted_codes = array(
'200',
'201',
);
if (!in_array($httpcode, $accepted_codes)) {
//generic error
$error = 'HTTP status code not expected - got '.$httpcode;
//more descriptive error
if ($httpcode == '400') {
$data = json_decode($response, true);
if (isset($data['error']['message'])) {
$error = $data['error']['message'];
}
}
return array('error' => $error);
}
return json_decode($response, true);
}
private function clean_filename($filename) {
$filename = preg_replace('/[*><|}{&#%~:"?\/\\\\]/', '', $filename);
if (strpos('.', $filename) === 0) {
$filename = substr($filename, 1);
}
if (empty($filename)) {
throw new SharepointException('File is empty after removing illegal characters.');
}
return $filename;
}