I have a group on azure, I have been able to get the members of the group using MS Graph API.
I have the details of the users in this format:
{
'#odata.type': '#microsoft.graph.user',
id: 'xxx-xxxxx-xxxxx',
businessPhones: [],
displayName: 'USER__FULL_NAME',
givenName: 'USER_FIRST_NAME',
jobTitle: null,
mail: 'USER_EMAIL',
mobilePhone: null,
officeLocation: null,
preferredLanguage: 'en-US',
surname: 'USER_LAST_NAME',
userPrincipalName: 'USER_EMAIL'
}
I want to send a message to the members of the group using BotFramework Node.js SDK.
I have checked Microsoft Bot Service Documentation, I can't find anything related
there are two approaches :
Using pro-active messages via the bot's Teams Channel.
https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/send-proactive-messages?tabs=dotnet
if you do not need/want a bot that there are options to 'just' start a new 1:1 or group-chat with a Graph call.
https://learn.microsoft.com/en-us/graph/api/chat-post?view=graph-rest-beta&tabs=http
Related
My application for Microsoft Teams works as a tab and needs to get the list of the chat members or channel members, depending on where it is installed.
/chats/{chat-id}/members
/teams/{team-id}/channels/{channel-id}/members
To use the APIs, I get the Context object from the client SDK library to get the identifiers required for the APIs. It works fine for chats–both group and one on one (using Context.chatId), and public team channels (using Context.groupId and Context.channelId).
However, nothing I try seems to work for private team channels.
The context object returned for private team channels contains teamId and channelId, but they are equal, and using one value for both ids naturally doesn't work. Here is an example of what is returned for a private team channel by the SDK library 1.11.0 (the latest):
{
"locale": "en-us",
"theme": "default",
"subEntityId": "",
"isFullScreen": false,
"sessionId": "5194fd2b-5c9a-16a7-7411-94ddabffffff",
"chatId": "",
"meetingId": "",
"parentMessageId": "",
"hostClientType": "desktop",
"tenantSKU": "unknown",
"jsonTabUrl": "microsoft-teams-json-tab.azurewebsites.net",
"userLicenseType": "Unknown",
"appSessionId": "7503c11c-d524-409c-b58b-004810ffffff",
"appLaunchId": "c736c663-cc0b-47c3-8824-ba56b7ffffff",
"isMultiWindow": false,
"appIconPosition": 79,
"userClickTime": 1637007245298,
"sourceOrigin": null,
"userFileOpenPreference": "inline",
"osLocaleInfo": {
"platform": "macos",
"regionalFormat": "en-gb",
"longDate": "d MMMM y",
"shortDate": "dd/MM/y",
"longTime": "HH:mm:ss z",
"shortTime": "HH:mm"
},
"frameContext": "settings",
"isTeamArchived": false,
"teamType": 0,
"userTeamRole": 0,
"channelRelativeUrl": "/sites/ffffff/Shared Documents/Devel",
"channelId": "19:0bc109b412d9448bb6b1b3d4d485700b#thread.tacv2",
"channelName": "Devel",
"channelType": "Private",
"defaultOneNoteSectionId": "",
"teamId": "19:0bc109b412d9448bb6b1b3d4d485700b#thread.tacv2",
"teamName": "Devel",
"teamSiteUrl": "https://ffffff.sharepoint.com/sites/worldrtech-Devel",
"teamSiteDomain": "ffffff.sharepoint.com",
"teamSitePath": "/sites/ffffff",
"teamTemplateId": "",
"teamSiteId": "",
"ringId": "general",
"tid": "d158bb9f-f90c-422d-9d0d-0040efffffff",
"loginHint": "ffffff#ffffff.uk",
"upn": "nox#worldr.co.uk",
"userPrincipalName": "ffffff#ffffff.uk",
"userObjectId": "fc5a4a6d-60e2-4370-83bd-aab1baffffff"
}
You can see above that the two are equal:
"channelId": "19:0bc109b412d9448bb6b1b3d4d485700b#thread.tacv2"
"teamId": "19:0bc109b412d9448bb6b1b3d4d485700b#thread.tacv2"
I wonder, whether this is an expected behaviour, or something is broken there... 🤔 As per comment by #Prasad-MSFT, this is normal behaviour for private channels.
There is an answer suggesting that one should first list all the teams the user joined. However, I don't see how I would connect this information to the context data shown above.
Is there a way to list the members of a private team channel? What am I missing?
UPDATE1 16.11:
I did an experiment, but the results got me puzzled. I followed the idea of getting all the teams of the user first. This got me ids of all the teams the user is a member of. I then requested members of for the current private channel for every team: I expected to get errors for all teams but one–that team the channel really belongs to. However, I got members for every request! That's very confusing.
/me/joinedTeams
/teams/{id}/channels/{channel_id}/members for each team received in 1. and channelId received from context.
Each call returned some members, which I did not expect...
UPDATE2 16.11:
This long-winded way gets me channel members in the end:
/me/joinedTeams
/teams/{id}/channels for each team received in 1.
Find the channel with id matching the channelId from my context among those received in 2.
/teams/{id}/channels/{channel_id}/members for the channel found in 3.
Looks like a lot of effort for such a simple thing. 🙄
Update: see the new answer from Nov 1 2022.
Update 2: it's still not fully functional, use both. 🤷♂️
This long-winded way gets me channel members list in the end. Only applies to private team channels because we don't have group id/team id in the Context there. As per #Prasad-MSFT's comment to the original post, there is no other way at the time of writing.
Get /me/joinedTeams
Get /teams/{id}/channels for each team received in #1.
Find the channel with id matching the channelId from the Context among those received in #2.
Get /teams/{id}/channels/{channel_id}/members for the channel found in #3.
Here is a caveat: if you create a private team channel and immediately add your tab to it, there is a chance that your new channel will not be returned by the API. If #3 in the above list of procedures fails, I ask the user to retry in a couple of minutes.
A year later there seem to be some improvements! (Yeah, but not really, see below.)
There is a new property called hostTeamGroupId which appears to contain the correct team id for private channels. The documentation, however, doesn't mention private channels specifically and only tells us about shared channels. Nevertheless, it seems to be working for the purposes of this question.
In #microsoft/teams-js v2 we can use Context.channel.ownerGroupId.
hostTeamGroupId
The property is newly added and describes the host
team’s Azure AD group ID, useful for making Microsoft Graph API calls
to retrieve shared channel membership.
However
This still doesn't work on mobile platforms at the time of writing 08.11.2022. The fields mentioned above are not populated.
So, for mobile platforms, we still need my other answer.
I'm trying to Share Files on a SharePoint Document Library that I have as a part of an Office 365 Developer Program instance.
My AD has a variety of users, some "native" users created in the AD manually and the rest are "guests" from different domains that my team and I work for.
I'm executing the following API request on the graph via code using NestJs (as per snippet). I've all the required Delegated Permissions in the Application Registration to do everything too.
REST View:
POST /drives/{drive-id}/items/{item-id}/invite
{
"requireSignIn": true,
"sendInvitation": false,
"roles": [
"sp.full control"
],
"recipients": [
{
"email": "xxx.xxx#xxx.com"
}
]
}
Code View:
//build list of all to add: PL, PLB, Main, Current User and whatever is added in DTO
const participantsToAdd = [project.projectLead]
.concat(project.projectLeadBackup)
.concat(project.participants.filter(p => newRoles.includes(p.participantRole.name)).map(p => p.user))
.map(u => ({
oid: u.microsoftId,
mail: u.mail,
}));
const permission = {
recipients: participantsToAdd.map(p => ({ email: p.mail })),
requireSignIn: true,
sendInvitation: false,
roles: ['sp.full control'],
};
// add the right permissions to the file
const result = await client.api(`/drives/${this.libraryId}/items/${fileId}/invite`).post(permission);
The above code is building up a list of "User" objects which contain an "oid" which I use later, and a "mail" object. I give these users "sp.full control" role on a file. Some are granted direct access and others are given links (grantedToIndentities) with write permissions.
This only seems to be happening when Guests on the active directory make the request; though it's only occurring for some guests. Two guest users in particular that I grant access to are fine, they get "Direct Access". Others go into the "link sharing" category. I don't see any differences in the users in AD anywhere.
I've tried looking through all admin sites (SharePoint, M365) and tweaked External Sharing permissions but the problem still persists.
When I invoke the action from a "native" user on AD to the Graph using the same request, it all works fine. All users (native and guests) are added with "direct access".
Can anyone share any thoughts? Hope I've given enough info.
Snippet from Graph response:
Image
I'm using a consumer facebook developer account. I need to get user media information from the following endpoint. Particularly need to get user full name, email and profile picture url
Request:
https://graph.instagram.com/{user-id}?fields=id,username,account_type,media_count&access_token=xxxxxxxxxxxxxxxxxxxxxxx
Response:
{
id: "3454354543543345",
username: "test",
account_type: "PERSONAL",
media_count: 22
}
Referred from the doc: getting-profile-info user-fields
Request URL:https://graph.microsoft.com/v1.0/me/messages
Some times when I try to get messages with this query (top > 10) /v1.0/me/messages?$top=20, it fails and responds 503-UnknownError. But with this one $top=10, it always works.
Another confusing part is that this problem only occurred with a specific personal-outlook(not organizational) email address!!!
There is another similar problem too:
Sometimes, When I try to initiate the graph-client I get this error:
AADSTS70012: A transient error has occurred. Please try again
The other problem:
It's possible to create a new outlook account with valid Gmail-address, then you can log in to your outlook account with a username equal to a valid Gmail-address.
This is what I got from M-Graph-Console:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"displayName": "FirstName LastName",
"surname": "LastName",
"givenName": "FirstName",
"id": "286526a26a78f1a8",
"userPrincipalName": "any-valid-gmail-username#gmail.com",
"businessPhones": [],
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null
}
Check the mail property: it's null !!
You can not fetch randomly-genrated-username#outlook.com from graph-APIs!!
As I know the only way to find the real outlook email address is to fetch sent messages and parse both of from and sender properties.
Now you can send an email to any other valid Gmail address from your outlook dashboard, but it's not possible to reply it or send email to your new outlook account address (any-valid-gmail-username#gmail.com).
I'm not sure this is a bug or feature but it does not seem to be a good idea!
503 is a server side issue. Possibly a bug on the Graph API side. If you are able to reproduce it you should open a support ticket.
You should not be able to add a user (in Office365 Business) for an unverified domain. Obviously you won't be able to verify gmail.com as your domain. Therefore, if you have managed to find a scenario where you are able to create an #gmail.com account in Office365, I suggest you report it to Microsoft as a bug (possibly "security" severity).
Next to retrieving calendar views of a user's calendar (on behalf of the user), we are trying hard to also get the calendar view of rooms via the Graph API using
https://graph.microsoft.com/beta/users/room1#ourdomain.com/calendarView. It's a painful process since we've been running into many problems and are currently stuck with the following 404 response:
https://graph.microsoft.com:443/v1.0/users/room1#ourdomain.com/calendarView?startDateTime=2018-12-04T23:00:00.000Z&endDateTime=2019-02-10T22:59:59.999Z
{
"error": {
"code": "ErrorItemNotFound",
"message": "The specified object was not found in the store.",
"innerError": {
"request-id": "358a003a-57a4-4f0e-91da-edc17c1fa2d8",
"date": "2018-12-12T07:38:33"
}
}
}
The email address of the room has been double checked and the resource exists, since we can create appointments with it and it is even being returned in the response when we retrieve the calendar of the user who has an appointment in that location.
App permissions and OAuth2 scopes are set to: openid email profile offline_access https://graph.microsoft.com/Calendars.Read https://graph.microsoft.com/Calendars.Read.Shared https://graph.microsoft.com/User.Read
https://graph.microsoft.com/User.ReadBasic.All https://graph.microsoft.com/User.Read.All, so that should not be an issue, judging by the documentation.
Does anyone know how to solve this?
I've tried all possible ways, but there is no way to get access.
This is what I've tried out the following in the Graph explorer:
https://graph.microsoft.com/v1.0/users/meetingroom1#domain.com/events -> DelegatedCalendarAccessDenied
https://graph.microsoft.com/v1.0/users/meetingroom1#domain.com/calendarView?startDateTime=2019-01-14&endDateTime=2019-01-18 -> ErrorItemNotFound
https://graph.microsoft.com/v1.0/users/meetingroom1#domain.com/calendar/calendarView?startDateTime=2019-01-14&endDateTime=2019-01-18 -> ErrorItemNotFound
All three on both the v1.0 and the beta.
It isn't an issue with rights, because for my testing I granted the Graph Explorer the Directory.ReadWrite.All scope. Resulting in the following scp claim.
The first requests seems the most promising (because of the different error), I also made myself a delegate with full control of the rooms-mailbox. That still didn't help.
A request to https://graph.microsoft.com/v1.0/users/meetingroom1#domain.com gives a result, as in a result describing the meetingroom.
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": [],
"displayName": "Meeting room 1",
"givenName": null,
"jobTitle": null,
"mail": "meetingroom1#domain.com",
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "meetingroom1#domain.com",
"id": "3e0a7b7e-xxxx-xxxx-xxxx-xxxxcxxxx120"
}
After doing all these tests, I can only conclude that you cannot access the events in a rooms mailbox. This is either intended (as in only use the scheduling assistant) or a bug.
Maybe some of the Microsoft guys around here could clarify this?
FINALLY! After going through this with countless Microsoft support people, each of whom said this was not their territory and did not know where to forward the question, I got in touch with somebody from the Exchange team. He suggested the one thing that worked for us: the user on behalf of which you are retrieving the room resource calendar needs to be a delegate of that room resource!
In addition, to retrieve the list of room resources which the user can select from, we needed to use the findRooms endpoint but this only works on the beta API. The only drawback of this is that you cannot seem to filter for rooms of which the user is a delegate. So the user will get a list of rooms for which he might or might not be able to retrieve the calendar.
A final drawback of the room resource calendarView response is that the response does not contain the names of the meetings planned in the rooms. The description of each event only contains the name of the meeting organizer.