There seems to be sadly scant documentation out there on working with Meeting Workspaces through the SharePoint API. Especially when it comes to recurring meetings, some (seemingly) basic pieces of meeting information can be very tricky to retrieve. Here're a few that I've dealt with on a recent project:
For tips on working with list items in recurring Meeting Workspaces, check out my
List Items in SharePoint Recurring Meeting Workspaces post.
What meeting instance is the user currently browsing?
You can get this by creating a
SPMeeting object from
SPContext.Current:
if (SPContext.Current != null)
&& SPContext.Current.Web != null
&& SPMeeting.IsMeetingWorkspaceWeb(SPContext.Current.Web))
{
SPMeeting meeting = SPMeeting.GetMeetingInformation(SPContext.Current.Web);
return meeting.InstanceId;
}
Is the current meeting workspace for a recurring meeting?
You can get this by creating a
SPMeeting object from
SPContext.Current and seeing if MeetingCount is -1:
if (SPContext.Current != null
&& SPContext.Current.Web != null
&& SPMeeting.IsMeetingWorkspaceWeb(SPContext.Current.Web))
{
SPMeeting meeting = SPMeeting.GetMeetingInformation(SPContext.Current.Web);
bool isRecurring = (meeting.MeetingCount == -1);
return isRecurring;
}
What is the next meeting recurrence? Or the recurrences for the next 6 months?
This one is quite tricky. My initial thought was to query the hidden Meeting Series list, which keeps track of all the meeting instances in a workspace.
Unfortunately, an instance is only added to the Meeting Series list when a user browses to that instance for the first time. If you create a new meeting workspace with 10 recurrences, Meeting Series will initially contain a single row, representing the entire meeting series. When someone browses to say, the 3rd recurrence, that will then be added to Meeting Series. And so forth. This actually makes sense, because recurring meetings can be indefinite and the list can't be populated with infinite recurrences!
Poking around the OOB webparts and dlls, I found that SharePoint itself uses this obscure piece of CAML to retrieve future instances, ordered by start date:
<Where>
<DateRangesOverlap>
<FieldRef Name="EventDate" />
<FieldRef Name="EndDate" />
<FieldRef Name="RecurrenceID" />
<Value Type="DateTime">
<Month />
</Value>
</DateRangesOverlap>
</Where>
<OrderBy>
<FieldRef Name="EventDate" />
</OrderBy>
This, combined with a couple key
SPQuery properties will return all meeting instances within a specified month, regardless of whether they've been visited or not. More often than not this query will return more items than the ItemCount for Meeting Series!
SPList list = SPContext.Current.Web.Lists["Meeting Series"];
SPQuery query = new SPQuery();
query.CalendarDate = new DateTime(2014, 04, 16);
query.Query = ""; // CAML query above
query.ExpandRecurrence = true;
query.MeetingInstanceId = (int)SPMeeting.SpecialInstance.AllButSeries;
query.RowLimit = 50;
SPListItemCollection results = list.GetItems(query);
The code above returns all meeting instances in the month specified by
CalendarDate (April 2014). The particular day doesn't matter. The results may include the last week of March and first week of May.
ExpandRecurrence must be set to TRUE to include unvisited meeting instances.
Aside from
<Month /> under
<DateRangesOverlap>, the CAML query can also specify:
<Now />,
<Today />,
<Week />, and
<Year />. Unfortunately,
<Year /> seems to return completely non-sensical results. I've tried it on multiple workspaces, and it never returns instances within the specified year like you'd expect.
So. Back to the original questions. Since
<Year /> doesn't work, to find all instances within the next 6 months, I query one month at a time, incrementing Calendar date with each iteration. Similarly, to find the next recurrence, I search forward one month at a time until an instance is found, like so:
public static int GetNextMeetingInstanceId(int currentInstanceId)
{
int nextInstanceId = currentInstanceId;
SPList list = SPContext.Current.Web.Lists["Meeting Series"];
// Convert instanceID to DateTime
DateTime searchDate = DateTime.ParseExact(currentInstanceId.ToString(),
"yyyyMMdd", CultureInfo.InvariantCulture);
// Search up to the next 12 months for the next instance
for (int i = 0; i <= 12; i++)
{
DateTime monthToSearch= searchDate.AddMonths(i);
// Retrieve instances for the month we're currently searching through,
// ordered by start date
SPQuery query = new SPQuery();
query.CalendarDate = monthToSearch;
query.Query = ""; // CAML query above
query.ExpandRecurrence = true;
query.MeetingInstanceId = (int)SPMeeting.SpecialInstance.AllButSeries;
query.RowLimit = 50;
SPListItemCollection results = list.GetItems(query);
foreach (SPListItem instance in results)
{
int instanceId = (int)instance["InstanceID"];
if (instanceId > currentInstanceId)
{
nextInstanceId = instanceId;
return nextInstanceId;
}
}
}
return nextInstanceId;
}