Can I Update Subscription Properties via REST API using PATCH method? - office365api

I know that when you want to renew your subscription I need to call subscriptions endpoint with payload which tells new expiration date or nothing, to get maximum 3 days.
// endpoint
me/subscriptions($subscriptionId)
// payload
{
"#odata.type": "#Microsoft.OutlookServices.PushSubscription"
}
What I want to do now, is to update NotificationURL property of that subscription.
I figured it should work like this using PATCH method:
// endpoint
me/subscriptions($subscriptionId)
// payload
{
"#odata.type": "#Microsoft.OutlookServices.PushSubscription",
"NotificationURL": "https://app.domain.com/notifications"
}
But when I try to do this I only get following errors:
code: ErrorInvalidParameter
message: Notification URL 'https://oldapp.domain.com/notifications?validationtoken=[someHashCode]' verification failed 'System.Net.WebException: The remote server returned an error: (404) Not Found.
Well, of course it fails and gives 404, because it's trying to connect old NotificationURL. It looks like, it's just trying to renew subcription instead of only updating NotificationURL property of that subscription.
I know I can handle this manually in few ways for example by creating new subscriptions, but I want to make this to work automatically everytime my server boots. And it feels like a good idea to just update the NotificationURL instead of unsubscribing from all notificaitons and creating new ones.
Any help would be appreciated!

Related

Microsoft teams messaging extension inconsistently sending a valid conversation ID to use in a graph call

I am developing a MSTeams application, and inside I use a messaging extension. Upon opening the extension, a request is fired over to my message handler, which I use an azure function to handle. Alongside the request is a payload, with details about the context (in this case the conversation or chat) of where the messaging extension was opened from.
Now, I've built up a graph URL with the conversation ID from the payload:
const id = context.req.body.conversation.id
const graphEndpoint = encodeURIComponent(`https://graph.microsoft.com/beta/me/chats/${id}/members`)
I authenticate a user by calling microsoftTeams.authentication.authenticate({...}) before I make the call, and use the token in the request.
Sometimes, this call will succeed, and return the information I want. However, the other times it will fail with a 400, telling me I had a bad request, despite it being a GET request with no body.
I notice in bad requests, that the conversation ID doesn't trail with #thread.v2 or #unq.gbl.spaces etc. I have no clue why this is so inconsistent, or if it's my fault. Any help would be appreciated.
EDIT: I have also seen that the issue only occurs when the id starts with a:, and succeeds when it starts with 19:. However, the context in which I open the messaging extension is the same each time: In a 1:1 / User:User chat.
I have previously implemented installing the bot in the conversation to get this information, but this method is very undesirable. Perhaps a side point - it seems that the conversations where I have previously installed the bot seem to return the 19: id, and everything else a:.
Here's an example of the 400 response:
{
"error": {
"code": "BadRequest",
"message": "Bad Request",
"innerError": {
"date": "2021-01-25T09:43:26",
"request-id": "3bb55aa2-e694-4c80-952c-88842f482dc1",
"client-request-id": "3bb55aa2-e694-4c80-952c-88842f482dc1"
}
}
}
The conversation id you received in the turn-context is not the chat-id. The conversation id is different from conversation id. Conversation id the id between bot and the user and chat id the id of the chat. Both are different. You cannot use conversation id to call the graph API. Please use the chat id to call graph API. You can get the chat id using list chats API.

Graph Lifecycle Notifications Not registering correct endpoint

I am trying to us the Lifecycle events within the Graph Beta API using code like this:
var subscription = new Subscription
{
Resource = $"users/{userObjectId}/mailFolders('{resource}')/messages",
ChangeType = "created,updated",
NotificationUrl = notificationWebHookUrl,
LifecycleNotificationUrl = lifecycleNotificationWebHookUrl,
ClientState = clientState,
ExpirationDateTime = DateTime.UtcNow + new TimeSpan(0, 0, 4200, 0),
};
However, even though I have supplied a different LifecycleNotificationUrl to the NotificationUrl, the initial requests to perform the validate request only go to the NotificationUrl endpoint not the LifecycleNotificationUrl endpoint. I have checked and I am definitely supplying different endpoint urls.
I am using 2 separate Azure Functions with Http triggers as the endpoints.
Also to note is that I am using ngrok for exposing my localhost Azure functions.
I understand that if you do not supply a LifecycleNotificationUrl that this is the behaviour that you should expect, but I am.
We currently have an open issue where the validation code is sending two validation requests to the notificationUrl and none to the lifecycleNotificationUrl. This is something we're trying to address, hopefully shortly. I suggest you follow this issue to get notified of any update on the matter.
Besides that, once the validation is passed, lifecycle notifications will get delivered to your lifecycleNotificationUrl and not your notificationUrl.

Calendar ID in create response differs from what Graph stores

We are experiencing inconsistencies with calendar ID's.
When sending a POST to https://graph.mircrosoft.com/v1.0/me/calendars with the following payload
{ name: 'Calendar' }
We receive this reponse from which we store the id
{
:"#odata.context"=>"https://graph.microsoft.com/v1.0/$metadata#users('user%40outlook.com')/calendars/$entity",
:id=>"AQMkADAwATMwMAItMjE5ZC01YjYyLTAwAi0wMAoARgAAA1D6u4KwtRdMm1rAZoOEKvAHAMf0BP7S_89KmnrxCgze9tcAAAIBBgAAAMf0BP7S_89KmnrxCgze9tcAAAEBKdoAAAA=",
:name=>"Calendar",
:color=>"auto",
:changeKey=>"x/QE/tL7z0qaevEKDN721wAAAAAOFQ==",
:canShare=>true,
:canViewPrivateItems=>true,
:canEdit=>true,
:owner=>{:name=>"User", :address=>"user#outlook.com"}
}
When we attempt to create events into this calendar errors are being thrown as that ID does not exist. Looking into it further and making a GET request to https://graph.mircrosoft.com/v1.0/me/calendars we receive this payload (truncated for brevity)
{
:id=>"AQMkADAwATMwMAItMjE5ZC01YjYyLTAwAi0wMAoARgAAA1D6u4KwtRdMm1rAZoOEKvAHAMf0BP7S_89KmnrxCgze9tcAAAIBBgAAAMf0BP7S_89KmnrxCgze9tcAAAIjxAAAAA==",
:name=>"Calendar",
:color=>"auto",
:changeKey=>"I8E7t/aNjEqDHtJJL1UC6AAADFI=",
:canShare=>true,
:canViewPrivateItems=>true,
:canEdit=>true,
:owner=>{:name=>"User", :address=>"user#outlook.com"}}]
}
After diffing both ID's, we notice they differ. The interesting part of this is that this only happens with a handful of users and isn't an issue with most accounts. Is there a better way to keep track of specific calendars that we can continue to sync into? I'd hate to have to ping for calendars every time we'd like to fire off a CRUD action.

Update Intune Managed Device Category with Microsoft Graph were Failed

I'd failed to update the managed device category in Intune with Microsoft Graph. With the same code, I'd succeeded to update device owner. Parameter below:
URL: https://graph.microsoft.com/beta/deviceManagement/managedDevices('XXXXXXXXXX')
Failed request body:
{ "deviceCategoryDisplayName": "General Purpose" }
Succeeded request body:
{ "Owner": "Personal" }
"General Purpose" is a custom value. When failed, the server returns an error code and activity id.
How can I fix it?
I've got the answer finally.
We should use odata.id to update the property. Like these,
URL: https://graph.microsoft.com/beta/deviceManagement/managedDevices('XXXXX-YOUR-INTUNE-DEVICE-GUID-XXXXX')
Method: PUT
Payload: {#odata.id: "https://graph.microsoft.com/beta/deviceManagement/deviceCategories/XXXXX-YOUR-DEVICE-CATEGROY-GUID-XXXX"}
Response code: 204
You will receive response code 204 when success to update. And, you cannot update other properties with it. It occurs error.
In the API documentation, it can update with string, but it is not correct. Maybe, it is not string property but refers to other objects. I think other objects referring property are the same, but not tested.
https://techcommunity.microsoft.com/t5/Microsoft-Intune/Update-Intune-Managed-Device-Category-with-Microsoft-Graph-were/m-p/366263/highlight/true#M1683

How to authenticate user with token (stay authenticated in iPhone)

I have two related questions and I hope someone help me because I've been stuck for 2 days
First: mobile phone failed to authenticate
Here is what I have done:
1- user signs up
2- token released
3- token saved in user's device
but then when the same user try to do API requests I get
Rooute to sign up :
$api = app('Dingo\Api\Routing\Router');
$api->version('v1', function ($api) {
$api->post('auth/signup', 'App\Api\V1\Controllers\AuthController#signup');
then I get a token , so I guess everything looks great!
then now when the same device sends a post request to laravel I get this message
"message": "Failed to authenticate because of bad credentials or an invalid authorization header."
this is the route to the post request
$api->group(['middleware'=>'api.auth'],
function ($api) {
$api->post('auth/ios', 'App\Api\V1\Controllers\AuthController#create');
Second: is my method right to save data made by a mobile phone?
Since I couldn't test this method I'd like to know if this is at least one of the right ways to receive data and save it. The reason to save it is because I will show it in a control panel.
public function create(Request $request)
{
$user = new User();
$id = Auth::id();
$user->phone = $request->input('phone');
$user->city = $request->input('city');
$user->street = $request->input('street');
$user->save();
return 'Employee record successfully created with id ' . $user->id;
}
I understand that you are authenticate users based on api token.
Here is what you could do :
set up a column called api_token in users table by adding the following migration
$table->string('api_token', 60)->unique();.This generates a random api token for every user.
send the api_token back to the user's device and save it there
Send it back with every request. Preferalbly set it up globally and send it in the request Authentication request header
Get the authenticated user like so$user= Auth::guard('api')->user();
Laravel takes care of all the authentication stuff behind the scenes.
Learn More about this here

Resources