public override void DeleteAppointments(ExchangeUser user, List<Appointment> appointments) { foreach (Appointment a in appointments) { _deletedAppt.Add(a); } }
public override void WriteAppointments(ExchangeUser user, List<Appointment> appointments) { foreach (Appointment a in appointments) { _writtenAppt.Add(a); } }
private ExchangeUser createFauxUser(string name, string email) { ExchangeUser result = new ExchangeUser(); result.Email = email; result.MailNickname = name; result.LegacyExchangeDN = "/o=Microsoft/ou=APPS-ABC/cn=RECIPIENTS/cn=ASAMPLE"; return result; }
public List<Appointment> getResult(ExchangeUser user) { // This method runs from the main thread if (ConfigCache.EnableAppointmentLookup) { waitForCompletion(); return result[user]; } else { return new List<Appointment>(); } }
public List <Appointment> getResult(ExchangeUser user) { // This method runs from the main thread if (ConfigCache.EnableAppointmentLookup) { waitForCompletion(); return(result[user]); } else { return(new List <Appointment>()); } }
private void GenerateResponseForTimeBlock( ExchangeUser user, FreeBusyTimeBlock timeBlock, BusyStatus busyStatus, bool firstAppointment, StringBuilder result) { if (timeBlock.Appointments == null || timeBlock.Appointments.Count == 0) { if (!firstAppointment) { result.Append(","); } AppendPrivateFreeBusyEntry(timeBlock.StartDate, timeBlock.EndDate, user.CommonName, busyStatus, result); return; } foreach (Appointment appt in timeBlock.Appointments) { if (!firstAppointment) { result.Append(","); } if (!appt.IsPrivate) { AppendFreeBusyEntry(appt.StartDate, appt.EndDate, appt.Subject, appt.Location, appt.Organizer, appt.BusyStatus, result); } else { AppendPrivateFreeBusyEntry(appt.StartDate, appt.EndDate, user.CommonName, appt.BusyStatus, result); } firstAppointment = false; } }
public void TestConvertEventsToFreeBusy() { ExchangeUser user = new ExchangeUser(); EventEntry googleAppsEvent = new EventEntry("title", "description", "location"); DateTimeRange coveredRange = new DateTimeRange(DateTime.MaxValue, DateTime.MinValue); List <DateTimeRange> busyTimes = new List <DateTimeRange>(); List <DateTimeRange> tentativeTimes = new List <DateTimeRange>(); DateTime startDate = new DateTime(2007, 07, 1, 10, 0, 0, DateTimeKind.Utc); DateTime endDate = new DateTime(2007, 07, 1, 11, 0, 0, DateTimeKind.Utc); When when = new When(startDate, endDate); Uri uri = new Uri("https://www.google.com/calendar/feeds/[email protected]/private/full"); EventFeed googleAppsFeed = new EventFeed(uri, null); AtomEntryCollection entries = new AtomEntryCollection(googleAppsFeed); }
public void TestConvertEventsToFreeBusy() { ExchangeUser user = new ExchangeUser(); EventEntry googleAppsEvent = new EventEntry("title", "description", "location"); DateTimeRange coveredRange = new DateTimeRange(DateTime.MaxValue, DateTime.MinValue); List<DateTimeRange> busyTimes = new List<DateTimeRange>(); List<DateTimeRange> tentativeTimes = new List<DateTimeRange>(); DateTime startDate = new DateTime(2007, 07, 1, 10, 0, 0, DateTimeKind.Utc); DateTime endDate = new DateTime(2007, 07, 1, 11, 0, 0, DateTimeKind.Utc); When when = new When(startDate, endDate); Uri uri = new Uri("https://www.google.com/calendar/feeds/[email protected]/private/full"); EventFeed googleAppsFeed = new EventFeed(uri, null); AtomEntryCollection entries = new AtomEntryCollection(googleAppsFeed); }
/// <summary> /// Delete appointments from an exchange user mailbox /// </summary> /// <param name="user">The user mailbox to remove events from</param> /// <param name="appointments">The events to remove</param> public virtual void DeleteAppointments(ExchangeUser user, List <Appointment> appointments) { try { foreach (Appointment appt in appointments) { webDavQuery.Delete(appt.HRef); } } catch (Exception ex) { throw new GCalExchangeException( GCalExchangeErrorCode.ExchangeUnreachable, "Error deleting appointment", ex); } }
/// <summary> /// Sync a users free busy information between Google Calendar and the /// SchedulePlus Public Folder store /// </summary> /// <param name="user">The user to synchronize</param> /// <param name="googleAppsFeed">The Google Calendar events for the user</param> /// <param name="exchangeGateway">The Exchange Gateway to use</param> /// <param name="window">The DateTimeRange to synchronize for</param> public void SyncUser( ExchangeUser user, EventFeed googleAppsFeed, ExchangeService exchangeGateway, DateTimeRange window) { if (_log.IsInfoEnabled) { _log.InfoFormat("Creating F/B message. [User={0}]", user.Email); _log.DebugFormat("The feed time zone is {0}", googleAppsFeed.TimeZone.Value); } string userFreeBusyUrl = FreeBusyUrl.GenerateUrlFromDN(_exchangeServerUrl, user.LegacyExchangeDN); List <string> busyMonthValues = new List <string>(); List <string> busyBase64Data = new List <string>(); List <string> tentativeMonthValues = new List <string>(); List <string> tentativeBase64Data = new List <string>(); ConvertEventsToFreeBusy(user, googleAppsFeed.Entries, window, busyMonthValues, busyBase64Data, tentativeMonthValues, tentativeBase64Data); string startDate = FreeBusyConverter.ConvertToSysTime(window.Start).ToString(); string endDate = FreeBusyConverter.ConvertToSysTime(window.End).ToString(); exchangeGateway.FreeBusy.CreateFreeBusyMessage(userFreeBusyUrl, user.FreeBusyCommonName, busyMonthValues, busyBase64Data, tentativeMonthValues, tentativeBase64Data, startDate, endDate); if (_log.IsInfoEnabled) { _log.Info("Free/Busy message with the right properties created successfully."); } }
/// <summary> /// Sync a users free busy information between Google Calendar and the /// SchedulePlus Public Folder store /// </summary> /// <param name="user">The user to synchronize</param> /// <param name="googleAppsFeed">The Google Calendar events for the user</param> /// <param name="exchangeGateway">The Exchange Gateway to use</param> /// <param name="window">The DateTimeRange to synchronize for</param> public void SyncUser( ExchangeUser user, EventFeed googleAppsFeed, ExchangeService exchangeGateway, DateTimeRange window) { if (_log.IsInfoEnabled) { _log.InfoFormat("Creating F/B message. [User={0}]", user.Email); _log.DebugFormat("The feed time zone is {0}", googleAppsFeed.TimeZone.Value); } string userFreeBusyUrl = FreeBusyUrl.GenerateUrlFromDN(_exchangeServerUrl, user.LegacyExchangeDN); List<string> busyMonthValues = new List<string>(); List<string> busyBase64Data = new List<string>(); List<string> tentativeMonthValues = new List<string>(); List<string> tentativeBase64Data = new List<string>(); ConvertEventsToFreeBusy(user, googleAppsFeed.Entries, window, busyMonthValues, busyBase64Data, tentativeMonthValues, tentativeBase64Data); string startDate = FreeBusyConverter.ConvertToSysTime(window.Start).ToString(); string endDate = FreeBusyConverter.ConvertToSysTime(window.End).ToString(); exchangeGateway.FreeBusy.CreateFreeBusyMessage(userFreeBusyUrl, user.FreeBusyCommonName, busyMonthValues, busyBase64Data, tentativeMonthValues, tentativeBase64Data, startDate, endDate); if ( _log.IsInfoEnabled ) { _log.Info( "Free/Busy message with the right properties created successfully." ); } }
/// <summary> /// Update appointments in an exchange user mailbox /// </summary> /// <param name="user">The user mailbox to update events in</param> /// <param name="appointments">The appointments to update</param> public virtual void UpdateAppointments(ExchangeUser user, List <Appointment> appointments) { string userMailbox = ExchangeUtil.GetDefaultCalendarUrl(exchangeServerUrl, user.AccountName); try { foreach (Appointment appt in appointments) { webDavQuery.UpdateAppointment(userMailbox, appt); } } catch (Exception ex) { throw new GCalExchangeException( GCalExchangeErrorCode.ExchangeUnreachable, "Error updating appointment", ex); } }
private static void CallConvertEventToFreeBusy( ExchangeUser user, EventEntry googleAppsEvent, DateTimeRange coveredRange, List <DateTimeRange> busyTimes, List <DateTimeRange> tentativeTimes) { object[] parameters = new object[5] { user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes }; BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; Type type = typeof(SchedulePlusFreeBusyWriter); MethodInfo methodInfo = type.GetMethod("ConvertEventToFreeBusy", flags); methodInfo.Invoke(null, parameters); }
/// <summary> /// Returns appointments for the specified exchange user /// </summary> /// <param name="user">The user which appointments will be looked up for</param> /// <param name="window">The event window to return appointments for</param> /// <returns>The event appointments that were looked up</returns> public List <Appointment> Lookup(ExchangeUser user, DateTimeRange window) { /* Create a holder for appointments */ List <Appointment> appointments = new List <Appointment>(); if (!ConfigCache.EnableAppointmentLookup) { if (log.IsDebugEnabled) { log.DebugFormat("Appointment lookup supressed for {0}", user.Email); } return(appointments); } try { /* Attempt to retrieve the Exchanger user's appointments * This may fail if there is a permissions issue for this user's calendar */ string calendarUrl = ExchangeUtil.GetDefaultCalendarUrl(exchangeServerUrl, user); appointments = webDavQuery.LoadAppointments(calendarUrl, window.Start, window.End); user.AccessLevel = GCalAccessLevel.ReadAccess; user.HaveAppointmentDetail = true; log.InfoFormat( "Appointments read succesfully for '{0}', setting access level to ReadAccess.", user.Email); } catch (WebException ex) { log.InfoFormat("Appointment access denied for {0} - {1}", user.Email, ex); } catch (Exception ex) { string errorMessage = string.Format( "Error occured while retrieving appointments for user '{0}'", user.Email); throw new GCalExchangeException( GCalExchangeErrorCode.ExchangeUnreachable, errorMessage, ex); } return(appointments); }
/// <summary> /// Write appointments to an exchange server mailbox /// </summary> /// <param name="user">The user mailbox to write appointments for</param> /// <param name="appointments">The Appointments to write</param> public virtual void WriteAppointments(ExchangeUser user, List <Appointment> appointments) { string calendarUrl = ExchangeUtil.GetDefaultCalendarUrl( exchangeServerUrl, user); try { foreach (Appointment appt in appointments) { webDavQuery.CreateAppointment(calendarUrl, appt); } } catch (Exception ex) { throw new GCalExchangeException( GCalExchangeErrorCode.ExchangeUnreachable, "Error writing appointment", ex); } }
public void TestAdjacentEvent() { DateTime start = DateUtil.ParseDateToUtc("2007-07-30T13:00:00.000Z"); DateTimeRange window = new DateTimeRange(start.AddDays(-7), start.AddDays(7)); // Test overlapping events // - 13:00 - 17:00 in Exchange from GCal // - 17:00 - 18:00 in GCal // Should create an exchange event [17:00-18:00] AddEventExchange(start, start.AddHours(4)); AddEventGCal(start, start.AddHours(4)); AddEventGCal(start.AddHours(4), start.AddHours(5)); EventFeed feed = createEventFeedFromEvents(_gcalEvents); FreeBusyCollection fb = createFreeBusyFromSyncEvents(_exchEvents); ExchangeUser user = createFauxUser("*****@*****.**", "*****@*****.**"); user.BusyTimes = fb; ExchangeGatewayMock gateway = new ExchangeGatewayMock(); this.SyncUser(user, feed, gateway, window); Assert.AreEqual(0, gateway.AppointmentsMock.Deleted.Count); Assert.AreEqual(1, gateway.AppointmentsMock.Written.Count); Assert.AreEqual(0, gateway.AppointmentsMock.Updated.Count); Assert.AreEqual(gateway.AppointmentsMock.Written[0].StartDate, start.AddHours(4)); Assert.AreEqual(gateway.AppointmentsMock.Written[0].EndDate, start.AddHours(5)); AddEventExchange(start.AddHours(4), start.AddHours(5)); feed = createEventFeedFromEvents(_gcalEvents); user.BusyTimes = createFreeBusyFromSyncEvents(_exchEvents); gateway = new ExchangeGatewayMock(); this.SyncUser(user, feed, gateway, window); Assert.AreEqual(0, gateway.AppointmentsMock.Deleted.Count); Assert.AreEqual(0, gateway.AppointmentsMock.Written.Count); Assert.AreEqual(0, gateway.AppointmentsMock.Updated.Count); }
/// <summary> /// Returns appointments for the specified exchange user /// </summary> /// <param name="user">The user which appointments will be looked up for</param> /// <param name="window">The event window to return appointments for</param> /// <returns>The event appointments that were looked up</returns> public List<Appointment> Lookup(ExchangeUser user, DateTimeRange window) { /* Create a holder for appointments */ List<Appointment> appointments = new List<Appointment>(); if (!ConfigCache.EnableAppointmentLookup) { if (log.IsDebugEnabled) log.DebugFormat("Appointment lookup supressed for {0}", user.Email ); return appointments; } try { /* Attempt to retrieve the Exchanger user's appointments * This may fail if there is a permissions issue for this user's calendar */ string calendarUrl = ExchangeUtil.GetDefaultCalendarUrl(exchangeServerUrl, user); appointments = webDavQuery.LoadAppointments(calendarUrl, window.Start, window.End); user.AccessLevel = GCalAccessLevel.ReadAccess; user.HaveAppointmentDetail = true; log.InfoFormat( "Appointments read succesfully for '{0}', setting access level to ReadAccess.", user.Email ); } catch (WebException ex) { log.InfoFormat("Appointment access denied for {0} - {1}", user.Email, ex); } catch (Exception ex) { string errorMessage = string.Format( "Error occured while retrieving appointments for user '{0}'", user.Email ); throw new GCalExchangeException( GCalExchangeErrorCode.ExchangeUnreachable, errorMessage, ex); } return appointments; }
private void GenerateResponseForTimeBlocks( ExchangeUser user, StringBuilder result) { /* If a user has time no blocks associate with him / her */ if (user.BusyTimes == null || user.BusyTimes.Count == 0) { return; } /* Flag for inserting commas */ bool firstAppointment = true; foreach (FreeBusyTimeBlock timeBlock in user.BusyTimes.Values) { GenerateResponseForTimeBlock(user, timeBlock, BusyStatus.Busy, firstAppointment, result); firstAppointment = false; } }
public void TestMissingAppointmentDetail() { DateTime start = DateUtil.ParseDateToUtc("2007-07-30T13:00:00.000Z"); DateTimeRange window = new DateTimeRange(start.AddDays(-7), start.AddDays(7)); AddEventGCal(start, start.AddHours(1)); EventFeed feed = createEventFeedFromEvents(_gcalEvents); FreeBusyCollection fb = createFreeBusyFromExistingEvents(_exchEvents); ExchangeUser user = createFauxUser("*****@*****.**", "*****@*****.**"); user.BusyTimes = fb; user.HaveAppointmentDetail = false; ExchangeGatewayMock gateway = new ExchangeGatewayMock(); this.SyncUser(user, feed, gateway, window); Assert.AreEqual(0, gateway.AppointmentsMock.Deleted.Count); Assert.AreEqual(0, gateway.AppointmentsMock.Written.Count); Assert.AreEqual(0, gateway.AppointmentsMock.Updated.Count); }
private ExchangeUserDict CreateExchangeUserCollection(SearchResultCollection searchResults) { ExchangeUserDict userCollection = new ExchangeUserDict(); if (searchResults != null) { /* For each result set in the result set */ foreach (System.DirectoryServices.SearchResult result in searchResults) { /* Extract the property collection and create a new exchange user with it * Add the new user to the result set and use the account name as the index for * the dictionary collection */ ResultPropertyCollection property = result.Properties; ExchangeUser user = new ExchangeUser(property); if (!user.IsValid) { log.WarnFormat("User '{0}' is invalid and will not be synchronized.", user.CommonName); } else if (userCollection.ContainsKey(user.Email.ToLower())) { log.WarnFormat("User '{0}' was returned multiple times in the LDAP query. " + "Only the first instance was added.", user.Email); } else { userCollection.Add(user.Email.ToLower(), user); log.InfoFormat("Found and added '{0}' as an ExchangeUser.", user.Email); } log.DebugFormat("LDAP object debug info: {0}", user); } } return(userCollection); }
private static void ConvertEventToFreeBusy( ExchangeUser user, EventEntry googleAppsEvent, DateTimeRange coveredRange, List<DateTimeRange> busyTimes, List<DateTimeRange> tentativeTimes) { DateTime startDate = DateTime.MinValue; DateTime endDate = DateTime.MinValue; DateTime utcStartDate = DateTime.MinValue; DateTime utcEndDate = DateTime.MinValue; BusyStatus userStatus = BusyStatus.Free; userStatus = ConversionsUtil.GetUserStatusForEvent(user, googleAppsEvent); // If the user is free, do not put this meeting in the free busy if (userStatus == BusyStatus.Free) { return; } startDate = googleAppsEvent.Times[0].StartTime; utcStartDate = DateTime.SpecifyKind(startDate.ToUniversalTime(), DateTimeKind.Unspecified); endDate = googleAppsEvent.Times[0].EndTime; utcEndDate = DateTime.SpecifyKind(endDate.ToUniversalTime(), DateTimeKind.Unspecified); if (utcStartDate < coveredRange.Start) { coveredRange.Start = utcStartDate; } if (utcEndDate > coveredRange.End) { coveredRange.End = utcEndDate; } if (_log.IsDebugEnabled) { _log.DebugFormat("Read GData FB event {0} - {1}", startDate, endDate); _log.DebugFormat("Write FB event {0} - {1} in UTC", utcStartDate, utcEndDate); _log.DebugFormat("The FB status is {0}", userStatus.ToString()); } if (userStatus == BusyStatus.Tentative) { tentativeTimes.Add(new DateTimeRange(utcStartDate, utcEndDate)); } else { Debug.Assert(userStatus == BusyStatus.Busy); busyTimes.Add(new DateTimeRange(utcStartDate, utcEndDate)); } }
private static void ConvertEventsToFreeBusy( ExchangeUser user, AtomEntryCollection entries, DateTimeRange coveredRange, List<string> busyMonthValues, List<string> busyBase64Data, List<string> tentativeMonthValues, List<string> tentativeBase64Data) { List<DateTimeRange> busyTimes = new List<DateTimeRange>(); List<DateTimeRange> tentativeTimes = new List<DateTimeRange>(); foreach (EventEntry googleAppsEvent in entries) { ConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); } FreeBusyConverter.CondenseFreeBusyTimes(busyTimes); FreeBusyConverter.CondenseFreeBusyTimes(tentativeTimes); FreeBusyConverter.ConvertDateTimeBlocksToBase64String(coveredRange.Start, coveredRange.End, busyTimes, busyMonthValues, busyBase64Data); FreeBusyConverter.ConvertDateTimeBlocksToBase64String(coveredRange.Start, coveredRange.End, tentativeTimes, tentativeMonthValues, tentativeBase64Data); }
public override void GetCalendarInfoForUser(ExchangeUser user, DateTimeRange window) { return; }
/// <summary> /// Merges a users appointment schedule from with appointments generated from a /// GoogleApps feed /// </summary> /// <param name="user">User to update with Google Apps information</param> /// <param name="googleAppsFeed">Source feed to generate appointment information</param> /// <param name="exchangeGateway">Gateway to sync Appointments with</param> /// <param name="window">DateRange to sync for</param> public void SyncUser( ExchangeUser user, EventFeed googleAppsFeed, ExchangeService exchangeGateway, DateTimeRange window) { exchangeGateway.GetCalendarInfoForUser(user, window); if (!user.HaveAppointmentDetail) { // Cannot sync if there is no appointment detail log.InfoFormat("Skipped Sync of {0} due to missing appointment lookup failure", user.Email); return; } List <Appointment> toUpdate = new List <Appointment>(); List <Appointment> toDelete = new List <Appointment>(); List <Appointment> toCreate = new List <Appointment>(); OlsonTimeZone feedTimeZone = OlsonUtil.GetTimeZone(googleAppsFeed.TimeZone.Value); IntervalTree <Appointment> gcalApptTree = CreateAppointments(user, feedTimeZone, googleAppsFeed); /* Iterate through each Free/Busy time block for the user */ foreach (FreeBusyTimeBlock fbtb in user.BusyTimes.Values) { /* Iterate through each appointment for the Free/Busy time block */ foreach (Appointment appt in fbtb.Appointments) { log.Debug(String.Format("Exchange @ '{0} {1}'", appt.Range, ValidateOwnership(appt))); /* Validate that this is a GCalender appoint */ if (ValidateOwnership(appt)) { /* If the GCalender appointments do not contain an * appointment for this period, add it for deletion */ if (gcalApptTree.FindExact(appt.Range) == null) { toDelete.Add(appt); } } } } /* Iterate through each Google Apps appointment */ AppointmentCollection appointments = user.BusyTimes.Appointments; List <Appointment> gcalApptList = gcalApptTree.GetNodeList(); foreach (Appointment newAppt in gcalApptList) { // If the meeting was cancelled log.DebugFormat("Looking @ {0} {1}", newAppt.Range, newAppt.Range.Start.Kind); if (newAppt.MeetingStatus == MeetingStatus.Cancelled) { // Check if there is an existing appointment that matches List <Appointment> matches = appointments.Get(newAppt.Range); foreach (Appointment a in matches) { if (ValidateOwnership(a)) { toDelete.Add(a); } } // Work is done for this appointment, continue to next entry continue; } bool updatedAppointment = false; List <Appointment> apptList = appointments.Get(newAppt.Range); log.DebugFormat("Looking up preexisting event: {0} {1}", newAppt.Range, newAppt.Range.Start.Kind); log.DebugFormat("Found {0} matching items", apptList.Count); // Check that there is a free busy block that correlates with this appointment foreach (Appointment existingAppt in apptList) { if (ValidateOwnership(existingAppt) && !updatedAppointment) { UpdateAppointmentInfo(existingAppt, newAppt); toUpdate.Add(existingAppt); updatedAppointment = true; } } if (!updatedAppointment) { toCreate.Add(newAppt); log.DebugFormat("ADDING '{0}' - Not an update", newAppt.Range); } } if (log.IsInfoEnabled) { log.InfoFormat( "AppointmentWriter for '{0}'. [{1} deleted, {2} updated, {3} new]", user.Email, toDelete.Count, toUpdate.Count, toCreate.Count); } exchangeGateway.Appointments.DeleteAppointments(user, toDelete); // TODO: Updates are not currently published // exchangeGateway.Appointments.UpdateAppointments( user, updateAppointments ); exchangeGateway.Appointments.WriteAppointments(user, toCreate); }
private static void CallConvertEventToFreeBusy( ExchangeUser user, EventEntry googleAppsEvent, DateTimeRange coveredRange, List<DateTimeRange> busyTimes, List<DateTimeRange> tentativeTimes) { object[] parameters = new object[5] { user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes }; BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; Type type = typeof(SchedulePlusFreeBusyWriter); MethodInfo methodInfo = type.GetMethod("ConvertEventToFreeBusy", flags); methodInfo.Invoke(null, parameters); }
private void GenerateResponseForTimeBlocks( ExchangeUser user, StringBuilder result) { /* If a user has time no blocks associate with him / her */ if (user.BusyTimes == null || user.BusyTimes.Count == 0) { return; } /* Flag for inserting commas */ bool firstAppointment = true; foreach (FreeBusyTimeBlock timeBlock in user.BusyTimes.Values) { GenerateResponseForTimeBlock(user, timeBlock, BusyStatus.Busy, firstAppointment, result); firstAppointment = false; } }
public void TestConvertEventToFreeBusy() { ExchangeUser user = new ExchangeUser(); EventEntry googleAppsEvent = new EventEntry("title", "description", "location"); DateTimeRange coveredRange = new DateTimeRange(DateTime.MaxValue, DateTime.MinValue); List <DateTimeRange> busyTimes = new List <DateTimeRange>(); List <DateTimeRange> tentativeTimes = new List <DateTimeRange>(); DateTime startDate = new DateTime(2007, 07, 1, 10, 0, 0, DateTimeKind.Utc); DateTime endDate = new DateTime(2007, 07, 1, 11, 0, 0, DateTimeKind.Utc); When when = new When(startDate, endDate); user.Email = "*****@*****.**"; // Event w/o valid times set should be ignored. CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, DateTime.MaxValue); Assert.AreEqual(coveredRange.End, DateTime.MinValue); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 0); googleAppsEvent.Times.Add(when); // Event w/o explicit status should be treated as busy, since this is how the data // comes from the free busy projection CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 1); Assert.AreEqual(busyTimes[0].Start, startDate); Assert.AreEqual(busyTimes[0].End, endDate); busyTimes.Clear(); // Confirmed event w/o attendees should be treated as busy. googleAppsEvent.Status = EventEntry.EventStatus.CONFIRMED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 1); Assert.AreEqual(busyTimes[0].Start, startDate); Assert.AreEqual(busyTimes[0].End, endDate); busyTimes.Clear(); // Cancelled event should be treated as free. googleAppsEvent.Status = EventEntry.EventStatus.CANCELED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); // Tentative event w/o attendees should be treated as tentative. googleAppsEvent.Status = EventEntry.EventStatus.TENTATIVE; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); Who john = new Who(); googleAppsEvent.Participants.Add(john); john.Attendee_Status = new Who.AttendeeStatus(); john.Email = user.Email; googleAppsEvent.Status = EventEntry.EventStatus.CONFIRMED; // Busy event with attendee tentative should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_TENTATIVE; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Busy event with attendee invited should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_INVITED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Busy event with attendee accepted should be treated as busy. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_ACCEPTED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 1); Assert.AreEqual(busyTimes[0].Start, startDate); Assert.AreEqual(busyTimes[0].End, endDate); busyTimes.Clear(); // Busy event with attendee declined should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_DECLINED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); googleAppsEvent.Status = EventEntry.EventStatus.TENTATIVE; // Tentative event with attendee tentative should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_TENTATIVE; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Tentative event with attendee invited should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_INVITED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Tentative event with attendee accepted should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_ACCEPTED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Tentative event with attendee declined should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_DECLINED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); googleAppsEvent.Status = EventEntry.EventStatus.CANCELED; // Cancelled event with attendee tentative should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_TENTATIVE; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); // Cancelled event with attendee invited should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_INVITED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); // Cancelled event with attendee accepted should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_ACCEPTED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); // Cancelled event with attendee declined should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_DECLINED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); }
public void Init() { _user = createFauxUser("test", "*****@*****.**"); }
/// <summary> /// Assigns free busy times to the exchange users that are passed into the method /// </summary> public virtual void GetCalendarInfoForUser(ExchangeUser user, DateTimeRange window) { ExchangeUserDict users = new ExchangeUserDict(); users.AddExchangeUser(user.Email, user); GetCalendarInfoForUsers(users, window); }
/// <summary> /// Assigns free busy times to the exchange users that are passed into the method /// </summary> public virtual void GetCalendarInfoForUser(ExchangeUser exchangeUser) { GetCalendarInfoForUser(exchangeUser, DateTimeRange.Full); }
public void TestSyncUser() { DateTime start = _base; DateTimeRange window = new DateTimeRange(start, start.AddDays(30)); // Add Event to both AddEventBoth(start, start.AddHours(2)); // Add only to Google Calendar - i.e. Create in exchange start = start.AddDays(2).AddHours(3); AddEventGCal(start, start.AddHours(1)); // Add only to Exchange - i.e. Delete from exchange start = start.AddDays(3).AddHours(3); AddEventExchange(start, start.AddHours(1)); start = start.AddDays(1).AddHours(-5); AddEventExchange(start, start.AddMinutes(20)); // Add to Google Calendar start = start.AddDays(2).AddHours(3); AddEventGCal(start, start.AddHours(1)); // Add Event to both start = start.AddDays(2).AddHours(3); AddEventBoth(start, start.AddHours(2)); // Add only to Exchange start = start.AddDays(2).AddHours(3); AddEventExchange(start, start.AddHours(1)); // Add Event to both start = start.AddDays(2).AddHours(14); AddEventBoth(start, start.AddHours(1)); // Add to Google Calendar start = start.AddDays(2).AddHours(3); AddEventGCal(start, start.AddHours(1)); // Add Event to both start = start.AddDays(5).AddHours(12); AddEventBoth(start, start.AddHours(6)); EventFeed feed = createEventFeedFromEvents(_gcalEvents); FreeBusyCollection fb = createFreeBusyFromSyncEvents(_exchEvents); ExchangeUser user = createFauxUser("*****@*****.**", "*****@*****.**"); user.BusyTimes = fb; ExchangeGatewayMock gateway = new ExchangeGatewayMock(); this.SyncUser(user, feed, gateway, window); Assert.AreEqual(_deleteEvents.Count, gateway.AppointmentsMock.Deleted.Count); Assert.AreEqual(_createEvents.Count, gateway.AppointmentsMock.Written.Count); Assert.AreEqual(0, gateway.AppointmentsMock.Updated.Count); int idx = 0; foreach (DateTimeRange e in _deleteEvents) { Assert.AreEqual(e.Start, gateway.AppointmentsMock.Deleted[idx].StartDate); Assert.AreEqual(e.End, gateway.AppointmentsMock.Deleted[idx].EndDate); idx++; } idx = 0; foreach (DateTimeRange e in _createEvents) { Assert.AreEqual(e.Start, gateway.AppointmentsMock.Written[idx].StartDate); Assert.AreEqual(e.End, gateway.AppointmentsMock.Written[idx].EndDate); idx++; } }
public override void GetCalendarInfoForUser(ExchangeUser user, DateTimeRange window) { return; }
/// <summary> /// Combines the free busy and appointment blocks supplied to the exchange user object /// If no appointments are supplied the user will still have free busy time blocks assigned /// to them, with a null appointment assigned to the free busy time. /// </summary> /// <param name="exchangeUser">Exchange users to apply freeBusy and appointments</param> /// <param name="freeBusy">The collection of FreeBusy blocks to assign to exchangeUser</param> /// <param name="appointments">The collection of appointment blocks to assign to exchangeUser</param> /// <param name="window">Window to merge for</param> protected void MergeFreeBusyWithAppointments( ExchangeUser exchangeUser, FreeBusy freeBusy, List<Appointment> appointments, DateTimeRange window) { using (BlockTimer bt = new BlockTimer("MergeFreeBusyWithAppointments")) { IntervalTree<FreeBusyTimeBlock> busyIntervals = new IntervalTree<FreeBusyTimeBlock>(); FreeBusyCollection busyTimes = new FreeBusyCollection(); int appointmentsCount = 0; List<DateTimeRange> combinedTimes = FreeBusyConverter.MergeFreeBusyLists(freeBusy.All, freeBusy.Tentative); /* Add the date ranges from each collection in the FreeBusy object */ ConvertFreeBusyToBlocks(window, combinedTimes, busyTimes, busyIntervals); if (appointments != null && appointments.Count > 0) { appointmentsCount = appointments.Count; foreach (Appointment appt in appointments) { log.DebugFormat("Appt \"{0}\" {1} {2} response = {3} status = {4} busy = {5}", appt.Subject, appt.Range, appt.StartDate.Kind, appt.ResponseStatus, appt.MeetingStatus, appt.BusyStatus); if (appt.BusyStatus == BusyStatus.Free) { continue; } DateTimeRange range = new DateTimeRange(appt.StartDate, appt.EndDate); List<FreeBusyTimeBlock> result = busyIntervals.FindAll(range, IntervalTreeMatch.Overlap); log.DebugFormat("Found {0} ranges overlap {1}", result.Count, range); foreach (FreeBusyTimeBlock block in result) { log.DebugFormat("Adding \"{0}\" to FB {1} {2}", appt.Subject, block.Range, block.StartDate.Kind); block.Appointments.Add(appt); } busyTimes.Appointments.Add(appt); } } foreach (FreeBusyTimeBlock block in busyTimes.Values) { block.Appointments.Sort(CompareAppointmentsByRanges); } log.InfoFormat("Merge Result of {0} + Appointment {1} -> {2}", combinedTimes.Count, appointmentsCount, busyTimes.Count); /* Assign the data structure to the exchange user */ exchangeUser.BusyTimes = busyTimes; } }
/// <summary> /// Assigns free busy times to the exchange users that are passed into the method /// </summary> public virtual void GetCalendarInfoForUser( ExchangeUser exchangeUser ) { GetCalendarInfoForUser( exchangeUser, DateTimeRange.Full ); }
public void TestConvertEventToFreeBusy() { ExchangeUser user = new ExchangeUser(); EventEntry googleAppsEvent = new EventEntry("title", "description", "location"); DateTimeRange coveredRange = new DateTimeRange(DateTime.MaxValue, DateTime.MinValue); List<DateTimeRange> busyTimes = new List<DateTimeRange>(); List<DateTimeRange> tentativeTimes = new List<DateTimeRange>(); DateTime startDate = new DateTime(2007, 07, 1, 10, 0, 0, DateTimeKind.Utc); DateTime endDate = new DateTime(2007, 07, 1, 11, 0, 0, DateTimeKind.Utc); When when = new When(startDate, endDate); user.Email = "*****@*****.**"; // Event w/o valid times set should be ignored. CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, DateTime.MaxValue); Assert.AreEqual(coveredRange.End, DateTime.MinValue); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 0); googleAppsEvent.Times.Add(when); // Event w/o explicit status should be treated as busy, since this is how the data // comes from the free busy projection CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 1); Assert.AreEqual(busyTimes[0].Start, startDate); Assert.AreEqual(busyTimes[0].End, endDate); busyTimes.Clear(); // Confirmed event w/o attendees should be treated as busy. googleAppsEvent.Status = EventEntry.EventStatus.CONFIRMED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 1); Assert.AreEqual(busyTimes[0].Start, startDate); Assert.AreEqual(busyTimes[0].End, endDate); busyTimes.Clear(); // Cancelled event should be treated as free. googleAppsEvent.Status = EventEntry.EventStatus.CANCELED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); // Tentative event w/o attendees should be treated as tentative. googleAppsEvent.Status = EventEntry.EventStatus.TENTATIVE; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); Who john = new Who(); googleAppsEvent.Participants.Add(john); john.Attendee_Status = new Who.AttendeeStatus(); john.Email = user.Email; googleAppsEvent.Status = EventEntry.EventStatus.CONFIRMED; // Busy event with attendee tentative should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_TENTATIVE; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Busy event with attendee invited should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_INVITED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Busy event with attendee accepted should be treated as busy. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_ACCEPTED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 1); Assert.AreEqual(busyTimes[0].Start, startDate); Assert.AreEqual(busyTimes[0].End, endDate); busyTimes.Clear(); // Busy event with attendee declined should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_DECLINED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); googleAppsEvent.Status = EventEntry.EventStatus.TENTATIVE; // Tentative event with attendee tentative should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_TENTATIVE; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Tentative event with attendee invited should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_INVITED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Tentative event with attendee accepted should be treated as tentative. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_ACCEPTED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(busyTimes.Count, 0); Assert.AreEqual(tentativeTimes.Count, 1); Assert.AreEqual(tentativeTimes[0].Start, startDate); Assert.AreEqual(tentativeTimes[0].End, endDate); tentativeTimes.Clear(); // Tentative event with attendee declined should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_DECLINED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); googleAppsEvent.Status = EventEntry.EventStatus.CANCELED; // Cancelled event with attendee tentative should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_TENTATIVE; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); // Cancelled event with attendee invited should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_INVITED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); // Cancelled event with attendee accepted should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_ACCEPTED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); // Cancelled event with attendee declined should be treated as free. john.Attendee_Status.Value = Who.AttendeeStatus.EVENT_DECLINED; CallConvertEventToFreeBusy(user, googleAppsEvent, coveredRange, busyTimes, tentativeTimes); Assert.AreEqual(coveredRange.Start, startDate); Assert.AreEqual(coveredRange.End, endDate); Assert.AreEqual(tentativeTimes.Count, 0); Assert.AreEqual(busyTimes.Count, 0); }
private ExchangeUserDict CreateExchangeUserCollection( SearchResultCollection searchResults ) { ExchangeUserDict userCollection = new ExchangeUserDict(); if ( searchResults != null ) { /* For each result set in the result set */ foreach ( System.DirectoryServices.SearchResult result in searchResults ) { /* Extract the property collection and create a new exchange user with it * Add the new user to the result set and use the account name as the index for * the dictionary collection */ ResultPropertyCollection property = result.Properties; ExchangeUser user = new ExchangeUser( property ); if ( !user.IsValid ) { log.WarnFormat( "User '{0}' is invalid and will not be synchronized.", user.CommonName ); } else if ( userCollection.ContainsKey( user.Email.ToLower() ) ) { log.WarnFormat( "User '{0}' was returned multiple times in the LDAP query. " + "Only the first instance was added.", user.Email ); } else { userCollection.Add( user.Email.ToLower(), user ); log.InfoFormat("Found and added '{0}' as an ExchangeUser.", user.Email); } log.DebugFormat("LDAP object debug info: {0}", user); } } return userCollection; }
/// <summary> /// Returns the free busy times for the specified exchange users /// </summary> /// <param name="user">The user which free/busy blocks will be looked up for</param> /// <param name="window">The date range to do the lookup</param> /// <returns>FreeBusy data for user in the daterange</returns> public FreeBusy LookupFreeBusyTimes( ExchangeUser user, DateTimeRange window ) { ExchangeUserDict users = new ExchangeUserDict(); users.Add( user.Email, user ); Dictionary<ExchangeUser, FreeBusy> result = LookupFreeBusyTimes ( users, window ); return result[user]; }
/// <summary> /// Update appointments in an exchange user mailbox /// </summary> /// <param name="user">The user mailbox to update events in</param> /// <param name="appointments">The appointments to update</param> public virtual void UpdateAppointments(ExchangeUser user, List<Appointment> appointments) { string userMailbox = ExchangeUtil.GetDefaultCalendarUrl(exchangeServerUrl, user.AccountName); try { foreach (Appointment appt in appointments) { webDavQuery.UpdateAppointment( userMailbox, appt ); } } catch (Exception ex) { throw new GCalExchangeException( GCalExchangeErrorCode.ExchangeUnreachable, "Error updating appointment", ex); } }
/// <summary> /// Returns a set of appointments from a GoogleApps Feed /// </summary> /// <param name="user">The exchange user to get apointments for</param> /// <param name="srcTimeZone">The time zone to use</param> /// <param name="googleAppsFeed">Source feed to create array from</param> /// <returns></returns> private IntervalTree<Appointment> CreateAppointments( ExchangeUser user, OlsonTimeZone srcTimeZone, EventFeed googleAppsFeed) { IntervalTree<Appointment> result = new IntervalTree<Appointment>(); foreach ( EventEntry eventEntry in googleAppsFeed.Entries ) { try { CreateAppointment(result, user, srcTimeZone, eventEntry); } catch ( GCalExchangeException ex ) { if ( ex.ErrorCode == GCalExchangeErrorCode.OlsonTZError ) { log.Error( "Error creating appointment (TimeZone issue)", ex ); } else { throw; } } } return result; }
/// <summary> /// Delete appointments from an exchange user mailbox /// </summary> /// <param name="user">The user mailbox to remove events from</param> /// <param name="appointments">The events to remove</param> public virtual void DeleteAppointments(ExchangeUser user, List<Appointment> appointments) { try { foreach (Appointment appt in appointments) { webDavQuery.Delete(appt.HRef); } } catch (Exception ex) { throw new GCalExchangeException( GCalExchangeErrorCode.ExchangeUnreachable, "Error deleting appointment", ex); } }
private void CreateAppointment( IntervalTree<Appointment> result, ExchangeUser user, OlsonTimeZone srcTimeZone, EventEntry googleAppsEvent) { Appointment appt = new Appointment(); if ( googleAppsEvent.Times != null && googleAppsEvent.Times.Count > 0 ) { When eventTime = googleAppsEvent.Times[0]; appt.StartDate = DateTime.SpecifyKind(eventTime.StartTime.ToUniversalTime(), DateTimeKind.Unspecified); appt.EndDate = DateTime.SpecifyKind(eventTime.EndTime.ToUniversalTime(), DateTimeKind.Unspecified); log.DebugFormat("Create - [{0}] {1}", appt.Range, appt.Range.Start.Kind); appt.AllDayEvent = googleAppsEvent.Times[0].AllDay; } if (ConfigCache.SyncAppointmentDetails && googleAppsEvent.Locations != null && googleAppsEvent.Locations.Count > 0 ) { appt.Location = googleAppsEvent.Locations[0].ValueString ?? string.Empty; } else { appt.Location = String.Empty; } string subject = ConfigCache.PlaceHolderMessage; if (ConfigCache.SyncAppointmentDetails) { subject += ": " + ConversionsUtil.SafeGetText(googleAppsEvent.Title); if (subject.Length > 255) { subject = subject.Remove(255); } } appt.Subject = subject; if (ConfigCache.SyncAppointmentDetails) { appt.Body = ConversionsUtil.SafeGetContent(googleAppsEvent.Content); } appt.MeetingStatus = ConversionsUtil.ConvertGoogleEventStatus(googleAppsEvent.Status); appt.BusyStatus = ConversionsUtil.GetUserStatusForEvent(user, googleAppsEvent); appt.Created = DateUtil.NowUtc; appt.InstanceType = InstanceType.Single; AssignOwnership( appt ); result.Insert(appt.Range, appt); }
private void GenerateResponseForTimeBlock( ExchangeUser user, FreeBusyTimeBlock timeBlock, BusyStatus busyStatus, bool firstAppointment, StringBuilder result) { if (timeBlock.Appointments == null || timeBlock.Appointments.Count == 0) { if (!firstAppointment) { result.Append(","); } AppendPrivateFreeBusyEntry(timeBlock.StartDate, timeBlock.EndDate, user.CommonName, busyStatus, result); return; } foreach (Appointment appt in timeBlock.Appointments) { if (!firstAppointment) { result.Append(","); } if (!appt.IsPrivate) { AppendFreeBusyEntry(appt.StartDate, appt.EndDate, appt.Subject, appt.Location, appt.Organizer, appt.BusyStatus, result); } else { AppendPrivateFreeBusyEntry(appt.StartDate, appt.EndDate, user.CommonName, appt.BusyStatus, result); } firstAppointment = false; } }
/// <summary> /// Merges a users appointment schedule from with appointments generated from a /// GoogleApps feed /// </summary> /// <param name="user">User to update with Google Apps information</param> /// <param name="googleAppsFeed">Source feed to generate appointment information</param> /// <param name="exchangeGateway">Gateway to sync Appointments with</param> /// <param name="window">DateRange to sync for</param> public void SyncUser( ExchangeUser user, EventFeed googleAppsFeed, ExchangeService exchangeGateway, DateTimeRange window) { exchangeGateway.GetCalendarInfoForUser(user, window); if (!user.HaveAppointmentDetail) { // Cannot sync if there is no appointment detail log.InfoFormat("Skipped Sync of {0} due to missing appointment lookup failure", user.Email); return; } List<Appointment> toUpdate = new List<Appointment>(); List<Appointment> toDelete = new List<Appointment>(); List<Appointment> toCreate = new List<Appointment>(); OlsonTimeZone feedTimeZone = OlsonUtil.GetTimeZone(googleAppsFeed.TimeZone.Value); IntervalTree<Appointment> gcalApptTree = CreateAppointments(user, feedTimeZone, googleAppsFeed); /* Iterate through each Free/Busy time block for the user */ foreach (FreeBusyTimeBlock fbtb in user.BusyTimes.Values) { /* Iterate through each appointment for the Free/Busy time block */ foreach (Appointment appt in fbtb.Appointments) { log.Debug(String.Format("Exchange @ '{0} {1}'", appt.Range, ValidateOwnership(appt))); /* Validate that this is a GCalender appoint */ if ( ValidateOwnership( appt ) ) { /* If the GCalender appointments do not contain an * appointment for this period, add it for deletion */ if (gcalApptTree.FindExact(appt.Range) == null) { toDelete.Add( appt ); } } } } /* Iterate through each Google Apps appointment */ AppointmentCollection appointments = user.BusyTimes.Appointments; List<Appointment> gcalApptList = gcalApptTree.GetNodeList(); foreach (Appointment newAppt in gcalApptList) { // If the meeting was cancelled log.DebugFormat("Looking @ {0} {1}", newAppt.Range, newAppt.Range.Start.Kind); if ( newAppt.MeetingStatus == MeetingStatus.Cancelled ) { // Check if there is an existing appointment that matches List<Appointment> matches = appointments.Get(newAppt.Range); foreach (Appointment a in matches) { if (ValidateOwnership(a)) { toDelete.Add(a); } } // Work is done for this appointment, continue to next entry continue; } bool updatedAppointment = false; List<Appointment> apptList = appointments.Get(newAppt.Range); log.DebugFormat("Looking up preexisting event: {0} {1}", newAppt.Range, newAppt.Range.Start.Kind); log.DebugFormat("Found {0} matching items", apptList.Count); // Check that there is a free busy block that correlates with this appointment foreach ( Appointment existingAppt in apptList ) { if (ValidateOwnership(existingAppt) && !updatedAppointment) { UpdateAppointmentInfo(existingAppt, newAppt); toUpdate.Add( existingAppt ); updatedAppointment = true; } } if (!updatedAppointment) { toCreate.Add( newAppt ); log.DebugFormat("ADDING '{0}' - Not an update", newAppt.Range); } } if (log.IsInfoEnabled) { log.InfoFormat( "AppointmentWriter for '{0}'. [{1} deleted, {2} updated, {3} new]", user.Email, toDelete.Count, toUpdate.Count, toCreate.Count); } exchangeGateway.Appointments.DeleteAppointments(user, toDelete); // TODO: Updates are not currently published // exchangeGateway.Appointments.UpdateAppointments( user, updateAppointments ); exchangeGateway.Appointments.WriteAppointments(user, toCreate); }
public void Init() { _user = createFauxUser("test", "*****@*****.**"); }
/// <summary> /// Combines the free busy and appointment blocks supplied to the exchange user object /// If no appointments are supplied the user will still have free busy time blocks assigned /// to them, with a null appointment assigned to the free busy time. /// </summary> /// <param name="exchangeUser">Exchange users to apply freeBusy and appointments</param> /// <param name="freeBusy">The collection of FreeBusy blocks to assign to exchangeUser</param> /// <param name="appointments">The collection of appointment blocks to assign to exchangeUser</param> /// <param name="window">Window to merge for</param> protected void MergeFreeBusyWithAppointments( ExchangeUser exchangeUser, FreeBusy freeBusy, List <Appointment> appointments, DateTimeRange window) { using (BlockTimer bt = new BlockTimer("MergeFreeBusyWithAppointments")) { IntervalTree <FreeBusyTimeBlock> busyIntervals = new IntervalTree <FreeBusyTimeBlock>(); FreeBusyCollection busyTimes = new FreeBusyCollection(); int appointmentsCount = 0; List <DateTimeRange> combinedTimes = FreeBusyConverter.MergeFreeBusyLists(freeBusy.All, freeBusy.Tentative); /* Add the date ranges from each collection in the FreeBusy object */ ConvertFreeBusyToBlocks(window, combinedTimes, busyTimes, busyIntervals); if (appointments != null && appointments.Count > 0) { appointmentsCount = appointments.Count; foreach (Appointment appt in appointments) { log.DebugFormat("Appt \"{0}\" {1} {2} response = {3} status = {4} busy = {5}", appt.Subject, appt.Range, appt.StartDate.Kind, appt.ResponseStatus, appt.MeetingStatus, appt.BusyStatus); if (appt.BusyStatus == BusyStatus.Free) { continue; } DateTimeRange range = new DateTimeRange(appt.StartDate, appt.EndDate); List <FreeBusyTimeBlock> result = busyIntervals.FindAll(range, IntervalTreeMatch.Overlap); log.DebugFormat("Found {0} ranges overlap {1}", result.Count, range); foreach (FreeBusyTimeBlock block in result) { log.DebugFormat("Adding \"{0}\" to FB {1} {2}", appt.Subject, block.Range, block.StartDate.Kind); block.Appointments.Add(appt); } busyTimes.Appointments.Add(appt); } } foreach (FreeBusyTimeBlock block in busyTimes.Values) { block.Appointments.Sort(CompareAppointmentsByRanges); } log.InfoFormat("Merge Result of {0} + Appointment {1} -> {2}", combinedTimes.Count, appointmentsCount, busyTimes.Count); /* Assign the data structure to the exchange user */ exchangeUser.BusyTimes = busyTimes; } }
/// <summary> /// Equality test based on Active Directory CN /// </summary> /// <param name="obj">instance to compare</param> /// <returns>true if the two instances are equal</returns> public override bool Equals(Object obj) { ExchangeUser user = obj as ExchangeUser; return(this.CommonName.Equals(user.CommonName)); }
private FreeBusy createFreeBusy(ExchangeUser user) { FreeBusy result = new FreeBusy(); result.User = user; result.All = _freeBusy.GetRange(0, _freeBusy.Count); result.Busy = _freeBusy.GetRange(0, _freeBusy.Count); return result; }
public void Init() { _requestor = new XmlRequestMock(); _webdav = new WebDavQuery(CredentialCache.DefaultCredentials, _requestor); _user = createFauxUser("test", "*****@*****.**"); }
/// <summary> /// Write appointments to an exchange server mailbox /// </summary> /// <param name="user">The user mailbox to write appointments for</param> /// <param name="appointments">The Appointments to write</param> public virtual void WriteAppointments(ExchangeUser user, List<Appointment> appointments) { string calendarUrl = ExchangeUtil.GetDefaultCalendarUrl( exchangeServerUrl, user ); try { foreach (Appointment appt in appointments) { webDavQuery.CreateAppointment(calendarUrl, appt); } } catch (Exception ex) { throw new GCalExchangeException( GCalExchangeErrorCode.ExchangeUnreachable, "Error writing appointment", ex); } }