Ejemplo n.º 1
0
        public async Task UpdateAvailabilityAsync(EmployeeAvailabilityModel availability)
        {
            Guard.ArgumentNotNullOrEmpty(availability.TeamsEmployeeId, nameof(EmployeeAvailabilityModel.TeamsEmployeeId));

            var appClient = _clientFactory.CreateUserClient(_options, availability.TeamsEmployeeId);

            // get the existing shift preference from Teams
            var shiftPreference = await appClient.GetUserShiftPreferenceAsync(availability.TeamsEmployeeId).ConfigureAwait(false);

            shiftPreference.Availability = _availabilityMap.MapAvailability(availability);
            await appClient.UpdateUserShiftPreferenceAsync(shiftPreference, availability.TeamsEmployeeId).ConfigureAwait(false);
        }
Ejemplo n.º 2
0
        public async Task DeleteAvailabilityAsync(EmployeeAvailabilityModel availability)
        {
            Guard.ArgumentNotNullOrEmpty(availability.TeamsEmployeeId, nameof(EmployeeAvailabilityModel.TeamsEmployeeId));

            var appClient = _clientFactory.CreateUserClient(_options, availability.TeamsEmployeeId);

            // Teams does not support deleting of availability, so all we can do is to restore
            // availability to the default of all-day for all days of the week, however, we should
            // check to see if it is already default because if so, we should skip the operation

            // get the existing shift preference from Teams
            var shiftPreference = await appClient.GetUserShiftPreferenceAsync(availability.TeamsEmployeeId).ConfigureAwait(false);

            var defaultWeekAvailability = CreateDefaultAvailabilityForWeek(availability.TimeZoneInfoId);

            if (!AvailabilityMatches(shiftPreference.Availability, defaultWeekAvailability))
            {
                shiftPreference.Availability = defaultWeekAvailability;
                await appClient.UpdateUserShiftPreferenceAsync(shiftPreference, availability.TeamsEmployeeId).ConfigureAwait(false);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Maps Teams availability items to the internal employee availability model representation.
        /// </summary>
        /// <param name="availabilityItems">The list of Teams availability items</param>
        /// <param name="userId">The Teams user ID</param>
        /// <returns>The internal model.</returns>
        public EmployeeAvailabilityModel MapAvailability(IList <AvailabilityItem> availabilityItems, string userId)
        {
            var availabilityModel = new EmployeeAvailabilityModel
            {
                TeamsEmployeeId = userId,
                Availability    = new List <AvailabilityModel>(),
                StartDate       = _timeService.UtcNow.StartOfWeek(_options.StartDayOfWeek),
                // in Teams shift preferences have no end date, they continue indefinitely until changed
                EndDate = null,
                // Teams only has single week availability
                NumberOfWeeks  = 1,
                TimeZoneInfoId = availabilityItems.Count > 0 ? availabilityItems.First().TimeZone : null
            };

            foreach (var availabilityItem in availabilityItems)
            {
                foreach (var dayOfWeek in availabilityItem.Recurrence.Pattern.DaysOfWeek)
                {
                    if (availabilityItem.TimeSlots != null)
                    {
                        foreach (var timeslot in availabilityItem.TimeSlots)
                        {
                            availabilityModel.Availability.Add(new AvailabilityModel
                            {
                                DayOfWeek = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), CultureInfo.CurrentCulture.TextInfo.ToTitleCase(dayOfWeek)),
                                // convert times from whatever time zone Teams sends them to us to UTC
                                StartTime = DateTimeHelper.ConvertFromLocalTime(timeslot.StartTime, availabilityItem.TimeZone, _timeService),
                                EndTime   = DateTimeHelper.ConvertFromLocalTime(timeslot.EndTime, availabilityItem.TimeZone, _timeService),
                                // as Teams only supports a single availability week, default it
                                WeekNumber = 1
                            });
                        }
                    }
                }
            }

            return(availabilityModel);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Maps the internal employee availability model back to Teams availability items.
        /// </summary>
        /// <param name="availabilityModel">The model to map.</param>
        /// <param name="timeZoneInfoId">The time zone id to use to convert utc back to local.</param>
        /// <returns>The list of Teams availability items.</returns>
        public IList <AvailabilityItem> MapAvailability(EmployeeAvailabilityModel availabilityModel)
        {
            // when writing availability to Teams, we need to use IANA time zones rather than
            // Windows, so convert if necessary
            if (!TZConvert.TryWindowsToIana(availabilityModel.TimeZoneInfoId, out string ianaTimeZone))
            {
                ianaTimeZone = availabilityModel.TimeZoneInfoId;
            }

            // Some WFM providers allow for availability to be different for different weeks on an
            // alternating basis, however, Teams only allows a single 'current' availability pattern
            // to be defined per user this means that we need to identify the item in the rotational
            // availability that represents the current week.
            var rotationalWeekNumber = (((int)((_timeService.UtcNow - availabilityModel.CycleBaseDate).TotalDays / 7)) % availabilityModel.NumberOfWeeks) + 1;

            var groupedByDayItems = availabilityModel.Availability
                                    .Where(a => a.WeekNumber == rotationalWeekNumber)
                                    .GroupBy(a => a.DayOfWeek.ToString(), a => new TimeSlotItem {
                StartTime = a.StartTime, EndTime = a.EndTime
            }, (key, g) =>
                                             new
            {
                Day       = key,
                TimeSlots = g.ToList()
            });

            var availabilityItems = new List <AvailabilityItem>();

            foreach (var item in groupedByDayItems)
            {
                var availabilityItem = new AvailabilityItem
                {
                    Recurrence = new RecurrenceItem
                    {
                        Pattern = new PatternItem
                        {
                            DaysOfWeek = new List <string> {
                                item.Day
                            },
                            Interval = 1,
                            Type     = "Weekly"
                        },
                        Range = new RangeItem
                        {
                            Type = "noEnd"
                        }
                    },
                    TimeSlots = new List <TimeSlotItem>(),
                    TimeZone  = ianaTimeZone
                };

                foreach (var timeSlot in item.TimeSlots)
                {
                    availabilityItem.TimeSlots.Add(new TimeSlotItem
                    {
                        StartTime = DateTimeHelper.ConvertToLocalTime(timeSlot.StartTime, availabilityModel.TimeZoneInfoId, _timeService),
                        EndTime   = DateTimeHelper.ConvertToLocalTime(timeSlot.EndTime, availabilityModel.TimeZoneInfoId, _timeService)
                    });
                }

                availabilityItems.Add(availabilityItem);
            }

            if (availabilityItems.Count < 7)
            {
                AddUnavailableDays(availabilityItems, ianaTimeZone);
            }

            return(availabilityItems);
        }
 public static void LogAvailabilitySkipped(this ILogger log, string teamId, string operationName, EmployeeAvailabilityModel availability)
 {
     log.LogTrace(EventIds.Availability, "Availability: Status={status}, OperationName={operationName}, SourceId={sourceId}, EmployeeId={employeeId}, StartDate={startDate}, EndDate={endDate}, TeamId={teamId}", Status.Skipped, operationName, availability.WfmId, availability.WfmEmployeeId, availability.StartDate.AsDateString(), availability.EndDate.AsDateString(), teamId);
 }
 public static void LogAvailabilityError(this ILogger log, MicrosoftGraphException ex, string teamId, string operationName, EmployeeAvailabilityModel availability)
 {
     log.LogError(EventIds.Availability, ex, "Availability: Status={status}, OperationName={operationName}, ErrorCode={errorCode}, ErrorDescription={errorDescription}, ErrorRequestId={errorRequestId}, ErrorDate={errorDate}, SourceId={sourceId}, EmployeeId={employeeId}, StartDate={startDate}, EndDate={endDate}, TeamId={teamId}", Status.Failed, operationName, ex.Error.Code, ex.Error.Message, ex.Error.InnerError?.RequestId, ex.Error.InnerError?.Date, availability.WfmId, availability.WfmEmployeeId, availability.StartDate.AsDateString(), availability.EndDate.AsDateString(), teamId);
 }