I'm using Graph API SDK in a C# Console Application and I'd like to list all the shift data from Microsoft Teams. But I'm unable to retrieve such information. Here is what I have done so far.
According to the documentation to list all shift, you have to provide the team ID in order to retrieve the shift, however, in my case, I have to retrieve all the shift from all the teams. So, I have to retrieve the list of the team first. The documentation says that to retrieve all team you have to retrieve the list of groups first. I've followed the same approach and the following is the code that I've used.
var groups = await graphClient
.Groups.Request()
.Filter("resourceProvisioningOptions/Any(x:x eq 'Team')")
.GetAsync();
foreach (var group in groups)
{
Console.WriteLine(group.DisplayName);
var shifts = await graphClient
.Teams[group.Id]
.Schedule
.Shifts
.Request()
.GetAsync();
}
I'm able to retrieve the Group list, however, I'm not able to retrieve the Shift list. When it tries to retrieve the Shift list the following error occurs:
Code: NotFound
Message: {
"error":{
"code":"NotFound",
"message":"Sorry, the team was not found, or you may not have access to it.",
"details":[],
"innererror":{"code":"TeamNotFound"}
}
}
Inner error:
AdditionalData:
request-id: c5ab5f5c-ec3d-463b-9b1f-0798734e94ce
date: 11/11/2019 7:50:42 AM
ClientRequestId: c5ab5f5c-ec3d-463b-9b1f-0798734e94ce
Would appreciate any help that can help me to list all the shift list from Microsoft Teams. Thank you.
This error most likely occurs since schedule object is not provisioned. The point is List shifts endpoint expects schedule object to be provisioned. From Get schedule documentation:
During schedule provisioning, clients can use the GET method to get
the schedule and look at the provisionStatus property for the current
state of the provisioning. If the provisioning failed, clients can get
additional information from the provisionStatusCode property.
In msgraph-sdk-dotnet whether schedule provisioned could be determined like this:
var schedule = await graphClient.Teams[group.Id].Schedule.Request().GetAsync();
if (schedule.ProvisionStatus == OperationStatus.Completed)
{
//...
}
Here is an updated example (which demonstrates how to retrieve shifts for provisioned schedule):
var groups = await graphClient.Groups.Request()
.Filter("resourceProvisioningOptions/Any(x:x eq 'Team')")
.GetAsync();
foreach (var group in groups)
{
var schedule = await graphClient.Teams[group.Id].Schedule.Request().GetAsync();
if (schedule.ProvisionStatus == OperationStatus.Completed)
{
var shifts = await graphClient.Teams[group.Id].Schedule.Shifts.Request().GetAsync();
//...
}
}
Related
In Client Libraries you can apply LINQ filtering on calendar event request:
var events = await (from i in Client.Me.Events where i.Subject == "Desired Event Name" select i)
.Take(50)
.ExecuteAsync();
Or one can use Where method, however for Start and End fields when we want events from specific time period filtering cannot be used as the DateTimes are stored as strings. Invocation of DateTime.Parse method causes an exception.
This is definitely supposed to be achievable, I even think it was possible at some point and can be done with REST. The begin/finish property is indexed according to documentation. Of course the results can be filtered once received but in that case I started getting events four years old. It really takes a lot of time to get through all the pages in the IPagedCollection in this approach. Fortunately though the events appear to be ordered by date, so you can stop the acquisition of new pages once events begin after your period of time.
Which version of Office 365 REST API you were initializing the OutLookServicesClient? I can filter the events use the v1.0 API. You can refer the code below to use the LINQ to filter the with start and end property:
OutlookServicesClient client = new OutlookServicesClient(new Uri("https://outlook.office.com/api/v1.0/"), () =>
{
return Task.Delay(10).ContinueWith(t => accessToken);
});
var events = await (from i in client.Me.Events where (i.Start > DateTimeOffset.Parse("2016-07-18") && i.End< DateTimeOffset.Parse("2016-07-25")) select i)
.Take(50)
.ExecuteAsync();
foreach (var appointment in events.CurrentPage)
{
Console.WriteLine($"{appointment.Subject}:\t{appointment.Start}~{appointment.End}");
}
Update(V2.0)
Install the V2.0 manage assembly Install-Package Microsoft.Office365.OutlookServices-V2.0
Code:
OutlookServicesClient client = new OutlookServicesClient(new Uri("https://outlook.office.com/api/v2.0/"), () =>
{
return Task.Delay(10).ContinueWith(t => accessToken);
});
var events = await (from i in client.Me.Events where (i.Start.DateTime.CompareTo("2016-07-18")>0 && i.End.DateTime.CompareTo("2016-07-25")<0) select i)
.Take(50)
.ExecuteAsync();
foreach (var appointment in events.CurrentPage)
{
Console.WriteLine($"{appointment.Subject}:\t{appointment.Start}~{appointment.End}");
}
Me. I still did not find solution to querying events with LINQ. To view a specified interval one can use
Client.Me.CalendarView(from as DateTimeOffset, to as DateTimeOffset) or Client.Me.Calendars["<valid calendar id>"].CalendarView(from, to). Filtering by function is probably exclusive to client-side code.
I am developing one application in ASP.NET with office365 REST API. I need to schedule a team event in office365 but before scheduling that event i need to check the available time of all team members. If a slot is free then only i need to setup a event for the team.
Lets assume i have 3 members team like , user1#someone.com , user2#someone.com, user3#clientone.com . I need to check the available times of all members on team and needs to show only compatable times. Lets assume user1 have a schedule meeting at 9:00am - 9:30 am then i need to hide that time why because user1 is not having free time.
How can i do this? Any idea?
Find Meeting Times (=Exchange FreeBusy) is in preview https://msdn.microsoft.com/en-us/office/office365/api/calendar-rest-operations#Findmeetingtimespreview but you should be able to use it via https://outlook.office.com/api/beta
Cheers
Glen
Finally i tried to use the free/busy code . My code as follows... I am following this procedure but i don't know either it is correct or not. I have office365 account and by passing credentials silently i am creating exchange server service. After that i am passing different domain attendee information as ORGANIZER and REQUIRED as follows. But it is returning all values not skipping any scheduled meetings for those users.
Lets assume user1#domain.com is ORGANIZER and user2#anotherdomain.com is REQUIRED for meeting . User1 have meeting scheduled at 7:00-7:30pm on daily basis but when i executed the following script it shows me 7:00-7:30pm as available for meeting. It supposed to block that time. Can you suggest somechanges to code and am i proceeding in correct way??
private static void GetSuggestedMeetingTimes(ExchangeService service)
{
List<AttendeeInfo> attendees = new List<AttendeeInfo>();
attendees.Add(new AttendeeInfo()
{
SmtpAddress = "user1#mydomain.com",
AttendeeType = MeetingAttendeeType.Organizer
});
attendees.Add(new AttendeeInfo()
{
SmtpAddress = "user2#anotherdomain.com",
AttendeeType = MeetingAttendeeType.Required
});
// Specify options to request free/busy information and suggested meeting times.
AvailabilityOptions availabilityOptions = new AvailabilityOptions();
availabilityOptions.GoodSuggestionThreshold = 49;
availabilityOptions.MaximumNonWorkHoursSuggestionsPerDay = 0;
availabilityOptions.MaximumSuggestionsPerDay = 40;
// Note that 60 minutes is the default value for MeetingDuration, but setting it explicitly for demonstration purposes.
availabilityOptions.MeetingDuration = 30;
availabilityOptions.MinimumSuggestionQuality = SuggestionQuality.Good;
availabilityOptions.DetailedSuggestionsWindow = new TimeWindow(DateTime.Now.AddDays(1), DateTime.Now.AddDays(2));
availabilityOptions.RequestedFreeBusyView = FreeBusyViewType.FreeBusy;
// Return free/busy information and a set of suggested meeting times.
// This method results in a GetUserAvailabilityRequest call to EWS.
GetUserAvailabilityResults results = service.GetUserAvailability(attendees,
availabilityOptions.DetailedSuggestionsWindow,
AvailabilityData.FreeBusyAndSuggestions,
availabilityOptions);
// Display suggested meeting times.
Console.WriteLine("Availability for {0} and {1}", attendees[0].SmtpAddress, attendees[1].SmtpAddress);
Console.WriteLine();
foreach (Suggestion suggestion in results.Suggestions)
{
Console.WriteLine("Suggested date: {0}\n", suggestion.Date.ToShortDateString());
Console.WriteLine("Suggested meeting times:\n");
foreach (TimeSuggestion timeSuggestion in suggestion.TimeSuggestions)
{
Console.WriteLine("\t{0} - {1}\n",
timeSuggestion.MeetingTime.ToShortTimeString(),
timeSuggestion.MeetingTime.Add(TimeSpan.FromMinutes(availabilityOptions.MeetingDuration)).ToShortTimeString());
}
}
int i = 0;
// Display free/busy times.
foreach (AttendeeAvailability availability in results.AttendeesAvailability)
{
Console.WriteLine("Availability information for {0}:\n", attendees[i].SmtpAddress);
foreach (CalendarEvent calEvent in availability.CalendarEvents)
{
Console.WriteLine("\tBusy from {0} to {1} \n", calEvent.StartTime.ToString(), calEvent.EndTime.ToString());
}
i++;
}
I am using the ActiveDirectory GraphClient library by Microsoft to access an Azure AD.
In my IActiveDirectoryClient object I can access all users by using the collection in Users property.
By using the ExecuteAsync() method I can load all users, rooms and recources.
void async Task<List<IUser>> GetRooms(IActiveDirectoryClient client)
{
var rooms = new List<IUser>();
var pagedUsers = await client.Users.ExecuteAsync();
while (pagedUsers != null &&
pagedUsers.CurrentPage != null)
{
// enumerate IUser objects
foreach (IUser u in pagedUsers.CurrentPage)
{
//TODO: HOW-TO CHECK IF ROOM
}
/* load next page */
}
return rooms;
}
My problem is:
I'd like to get to know from an IUser object if it is a room or resource but I do not know where to look.
There is no such object in the Azure AD. But you can extend the Azure AD User object to create custom properties :
Extend Azure Active Directory Schema using Graph API
Room mailbox is an object related to Exchange and Exchange online.
I am using the MVC Office 365 API libraries and I would like to archieve the following thing: Logging into User-Accounts where I know the username / password and then get there calendar entries.
What I have so far is code that makes this redirect and ask the user to enter credentials. But how can I log in for them wihtout asking? The idea is to get the calendar entries for every user (lets say 20 of them) automatically every few minutes.
public static async Task<IEvent[]> GetCalendarEvents()
{
var client = await EnsureClientCreated();
// Obtain calendar event data
var eventsResults = await (from i in client.Me.Events
where i.End >= DateTimeOffset.UtcNow
select i).Take(10).ExecuteAsync();
var events = eventsResults.CurrentPage.OrderBy(e => e.Start).ToArray();
return events;
}
public static async Task<ExchangeClient> EnsureClientCreated()
{
var _discoveryContext = await CacheHelper.GetDiscoveryContext();
var dcr = await _discoveryContext.DiscoverResourceAsync(ServiceResourceId);
return new ExchangeClient(ServiceEndpointUri, async () =>
{
return (await _discoveryContext.AuthenticationContext.AcquireTokenByRefreshTokenAsync(new SessionCache().Read("RefreshToken"),
new Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential(_discoveryContext.AppIdentity.ClientId, _discoveryContext.AppIdentity.ClientSecret),
ServiceResourceId))
.AccessToken;
});
}
Late answer I know. But if your still looking for this, or anyone else, this blog may be what your looking for.
http://blogs.msdn.com/b/exchangedev/archive/2015/01/22/building-demon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow.aspx
A daemon/service app will get calendar events on behalf of a user, proving the user and the app are registered under the same tennat/organisation.
I am trying to get a list of all users in our instance of Desire2Learn using a looping structure through the bookmarks however for some reason it continuously loops and doesn't return. When I debug it it is showing massive amounts of users (far more than we have in the system as shown by the User Management Tool. A portion of my code is here:
public async Task<List<UserData>> GetAllUsers(int pages = 0)
{
//List<UserData> users = new List<UserData>();
HashSet<UserData> users = new HashSet<UserData>();
int pageCount = 0;
bool getMorePages = true;
var response = await Get<PagedResultSet<UserData>>("/d2l/api/lp/1.4/users/");
var qParams = new Dictionary<string, string>();
do
{
qParams["bookmark"] = response.PagingInfo.Bookmark;
//users = users.Concat(response.Items).ToList<UserData>();
users.UnionWith(response.Items);
response = await Get<PagedResultSet<UserData>>("/d2l/api/lp/1.4/users/", qParams);
if (pages != 0)
{
pageCount++;
if (pageCount >= pages)
{
getMorePages = false;
}
}
}
while (response.PagingInfo.HasMoreItems && getMorePages);
return users.ToList();
}
I originally was using the List container that is commented out but just switched to the HashSet to see if I could notice if duplicates where being added.
It's fairly simple, but for whatever reason it's not working. The Get<PagedResultSet<UserData>>() method simply wraps the HTTP request logic. We set the bookmark each time and send it on.
The User Management Tool indicates there are 39,695 users in the system. After running for just a couple of minutes and breaking on the UnionWith in the loop I'm showing that my set has 211,800 users.
What am I missing?
It appears that you’ve encountered a defect in this API. The next course of action is for you to have your institution’s Approved Support Contact open an Incident through the Desire2Learn Helpdesk. Please make mention in the Incident report that Sarah-Beth Bianchi is aware of the issue, and I will work with our Support team to direct this issue appropriately.