public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Admin, "post", Route = "clearschedule")] ClearScheduleModel clearScheduleModel, [DurableClient] IDurableOrchestrationClient starter, ILogger log) { if (!clearScheduleModel.IsValid()) { return(new BadRequestResult()); } // ensure that the team's orchestrators will not execute by disabling them await _scheduleConnectorService.UpdateEnabledAsync(clearScheduleModel.TeamId, false).ConfigureAwait(false); // get the connection model as we need the time zone information for the team var connectionModel = await _scheduleConnectorService.GetConnectionAsync(clearScheduleModel.TeamId).ConfigureAwait(false); try { SetStartAndEndDates(clearScheduleModel, connectionModel.TimeZoneInfoId); } catch (ArgumentException ex) { return(new BadRequestObjectResult(ex.Message)); } if (await starter.TryStartSingletonAsync(nameof(ClearScheduleOrchestrator), ClearScheduleOrchestrator.InstanceId(clearScheduleModel.TeamId), clearScheduleModel).ConfigureAwait(false)) { return(new OkResult()); } else { return(new ConflictResult()); } }
public async Task <ResultModel> Run([ActivityTrigger] ClearScheduleModel clearScheduleModel, ILogger log) { var resultModel = new ResultModel(); try { var batchSize = clearScheduleModel.QueryEndDate.HasValue ? _options.ClearScheduleMaxBatchSize : _options.ClearScheduleBatchSize; var shifts = await _scheduleDestinationService.ListShiftsAsync(clearScheduleModel.TeamId, clearScheduleModel.StartDate, clearScheduleModel.QueryEndDate ?? clearScheduleModel.EndDate, batchSize); // restrict the shifts to delete to those that actually started between the start and end dates shifts = shifts.Where(s => s.StartDate < clearScheduleModel.EndDate).ToList(); if (shifts.Count > 0) { var tasks = shifts .Select(shift => TryDeleteShiftAsync(clearScheduleModel, shift, log)) .ToArray(); var result = await Task.WhenAll(tasks); resultModel.DeletedCount = result.Count(r => r == true); } resultModel.Finished = shifts.Count == 0; } catch (Exception ex) { log.LogShiftError(ex, clearScheduleModel, nameof(_scheduleDestinationService.ListShiftsAsync)); } return(resultModel); }
/// <summary> /// The purpose of this method is to set the StartDate and EndDate values on the /// ClearScheduleModel thus defining the full range of the dates in complete weeks that will /// be cleared. /// </summary> /// <param name="clearScheduleModel">The model sent by the caller.</param> /// <remarks> /// Users can supply these dates in which case we need to ensure that whatever they entered, /// the start date is the first day of that week and the end date is the last day of that /// week. If the dates are not supplied by the user but they did supply values for the /// PastWeeks and FutureWeeks then we will compute the start and end dates on the basis of /// those. Finally if the user supplied neither start and end dates nor past and future /// weeks then we will use the past and future weeks configured for the syncs to compute the /// dates. In addition to the start and end dates, this method also sets the utc start and /// end times of the date range because we have to use utc dates when calling the graph api /// to get the list of items to be deleted. /// </remarks> private void SetStartAndEndDates(ClearScheduleModel clearScheduleModel, string timeZoneInfoId) { var pastWeeks = clearScheduleModel.PastWeeks ?? _options.PastWeeks; var futureWeeks = clearScheduleModel.FutureWeeks ?? _options.FutureWeeks; if (clearScheduleModel.StartDate == default) { // if the start and end dates have not been explicitly supplied then we must compute // them from the past and future weeks values relative to today clearScheduleModel.StartDate = _timeService.UtcNow .StartOfWeek(_options.StartDayOfWeek) .AddWeeks(-pastWeeks) .Date; clearScheduleModel.EndDate = _timeService.UtcNow .StartOfWeek(_options.StartDayOfWeek) .AddWeeks(futureWeeks + 1) .AddDays(-1) .Date; } else { // ensure that the start date is the start of the week of the start date because we // cannot handle periods of less than 1 full week because of the clearcacheactivity // which deletes the cache for the whole week clearScheduleModel.StartDate = clearScheduleModel.StartDate.StartOfWeek(_options.StartDayOfWeek); // because a start date has been specified, we need to ensure that an end date has // also been supplied or if not use the start date to default it to the end date of // the same week if (clearScheduleModel.EndDate == default) { // e.g. startdate = 23/08/2020 then end date = 29/08/2020 clearScheduleModel.EndDate = clearScheduleModel.StartDate.AddDays(6); } else { // make sure the end date is the end date for the week it appears within clearScheduleModel.EndDate = clearScheduleModel.EndDate.StartOfWeek(_options.StartDayOfWeek).AddDays(6); } } // validate the start date is < end date if (clearScheduleModel.StartDate > clearScheduleModel.EndDate) { throw new ArgumentException("End date must be after start date.", nameof(clearScheduleModel)); } // ensure that the end date is the end of the day i.e. 23:59:59 and not the start i.e. 00:00:00 clearScheduleModel.EndDate = clearScheduleModel.EndDate.AddDays(1).AddSeconds(-1); clearScheduleModel.UtcStartDate = clearScheduleModel.StartDate.ConvertFromLocalTime(timeZoneInfoId, _timeService); clearScheduleModel.UtcEndDate = clearScheduleModel.EndDate.ConvertFromLocalTime(timeZoneInfoId, _timeService); }
public async Task Run([ActivityTrigger] ClearScheduleModel clearScheduleModel, ILogger log) { var pastWeeks = clearScheduleModel.PastWeeks ?? _options.PastWeeks; var futureWeeks = clearScheduleModel.FutureWeeks ?? _options.FutureWeeks; var weeksRange = DateTime.Today .Range(pastWeeks, futureWeeks, _options.StartDayOfWeek); foreach (var week in weeksRange) { await _scheduleCacheService.DeleteScheduleAsync(clearScheduleModel.TeamId, week); } }
private async Task <bool> TryDeleteOpenShiftAsync(ClearScheduleModel clearScheduleModel, ShiftModel shift, ILogger log) { try { await _teamsService.DeleteOpenShiftAsync(clearScheduleModel.TeamId, shift, true).ConfigureAwait(false); return(true); } catch (Exception ex) { log.LogShiftError(ex, clearScheduleModel, nameof(_teamsService.DeleteOpenShiftAsync), shift, "OpenShift"); return(false); } }
private async Task <bool> TryDeleteTimeOffAsync(ClearScheduleModel clearScheduleModel, TimeOffModel timeOff, ILogger log) { try { await _teamsService.DeleteTimeOffAsync(clearScheduleModel.TeamId, timeOff, true).ConfigureAwait(false); return(true); } catch (Exception ex) { log.LogTimeOffError(ex, clearScheduleModel, nameof(_teamsService.DeleteTimeOffAsync), timeOff); return(false); } }
private async Task <bool> TryDeleteShiftAsync(ClearScheduleModel clearScheduleModel, ShiftModel shift, ILogger log) { try { await _scheduleDestinationService.DeleteShiftAsync(clearScheduleModel.TeamId, shift); return(true); } catch (Exception ex) { log.LogShiftError(ex, clearScheduleModel, nameof(_scheduleDestinationService.DeleteShiftAsync), shift); return(false); } }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Admin, "post", Route = "clearschedule")] ClearScheduleModel clearScheduleModel, [OrchestrationClient] DurableOrchestrationClient starter, ILogger log) { if (!clearScheduleModel.IsValid()) { return(new BadRequestResult()); } if (await starter.TryStartSingletonAsync(nameof(ClearScheduleOrchestrator), clearScheduleModel.InstanceId, clearScheduleModel)) { return(new OkResult()); } else { return(new ConflictResult()); } }
public async Task Run([ActivityTrigger] ClearScheduleModel clearScheduleModel, ILogger log) { try { var shifts = await _teamsService.ListOpenShiftsAsync(clearScheduleModel.TeamId, clearScheduleModel.UtcStartDate, clearScheduleModel.QueryEndDate ?? clearScheduleModel.UtcEndDate, _options.ClearScheduleBatchSize).ConfigureAwait(false); // restrict the shifts to delete to those that actually started between the start // and end dates shifts = shifts.Where(s => s.StartDate < clearScheduleModel.UtcEndDate).ToList(); if (shifts.Count > 0) { var tasks = shifts .Select(shift => TryDeleteOpenShiftAsync(clearScheduleModel, shift, log)) .ToArray(); await Task.WhenAll(tasks).ConfigureAwait(false); } } catch (Exception ex) { log.LogShiftError(ex, clearScheduleModel, nameof(_teamsService.ListOpenShiftsAsync), "OpenShift"); } }
public async Task Run([ActivityTrigger] ClearScheduleModel clearScheduleModel, ILogger log) { var weeksRange = clearScheduleModel.StartDate .Range(clearScheduleModel.EndDate, _options.StartDayOfWeek); foreach (var week in weeksRange) { if (clearScheduleModel.ClearShifts) { await _scheduleCacheService.DeleteScheduleAsync(clearScheduleModel.TeamId, week).ConfigureAwait(false); } if (_featureOptions.EnableOpenShiftSync && clearScheduleModel.ClearOpenShifts) { await _scheduleCacheService.DeleteScheduleAsync(clearScheduleModel.TeamId + ApplicationConstants.OpenShiftsSuffix, week).ConfigureAwait(false); } if (_featureOptions.EnableTimeOffSync && clearScheduleModel.ClearTimeOff) { await _timeOffCacheService.DeleteTimeOffAsync(clearScheduleModel.TeamId, week).ConfigureAwait(false); } } }
public async Task Run([ActivityTrigger] ClearScheduleModel clearScheduleModel, ILogger log) { try { var timeOffRecs = await _teamsService.ListTimeOffAsync(clearScheduleModel.TeamId, clearScheduleModel.UtcStartDate, clearScheduleModel.QueryEndDate ?? clearScheduleModel.UtcEndDate, _options.ClearScheduleBatchSize).ConfigureAwait(false); // restrict the time off to delete those that actually started between the start and // end dates timeOffRecs = timeOffRecs.Where(s => s.StartDate < clearScheduleModel.UtcEndDate).ToList(); if (timeOffRecs.Count > 0) { var tasks = timeOffRecs .Select(timeOff => TryDeleteTimeOffAsync(clearScheduleModel, timeOff, log)) .ToArray(); await Task.WhenAll(tasks).ConfigureAwait(false); } } catch (Exception ex) { log.LogTimeOffError(ex, clearScheduleModel, nameof(_teamsService.ListTimeOffAsync)); } }
public static void LogShiftError(this ILogger log, Exception ex, ClearScheduleModel clear, string operationName) { log.LogError(new EventId(9, "Shift"), ex, "Shift: Status={status}, OperationName={operationName}, TeamId={teamId}, DayDate={dayDate}", Status.Failed, operationName, clear.TeamId, clear.StartDate.AsDateString()); }
public static void LogShiftError(this ILogger log, Exception ex, ClearScheduleModel clear, string operationName, ShiftModel shift) { log.LogError(new EventId(9, "Shift"), ex, "Shift: Status={status}, OperationName={operationName}, SourceId={sourceId}, DestinationId={destinationId}, EmployeeId={employeeId}, TeamId={teamId}, DayDate={dayDate}", Status.Failed, operationName, shift.JdaShiftId, shift.TeamsShiftId, shift.JdaEmployeeId, clear.TeamId, clear.StartDate.AsDateString()); }
public static void LogClearEnd(this ILogger log, ClearScheduleModel clear, ResultModel resultModel) { log.Log(resultModel.LogLevel, new EventId(12, "Clear"), "Clear: Stage={stage}, TeamId={teamId}, StartDate={startDate}, DeletedCount={deletedCount}, IterationCount={iterationCount}, IsFinished={isFinished}", Stage.End, clear.TeamId, clear.StartDate.AsDateString(), resultModel.DeletedCount, resultModel.IterationCount, resultModel.Finished); }
public static void LogClearStart(this ILogger log, ClearScheduleModel clear) { log.LogInformation(new EventId(12, "Clear"), "Clear: Stage={stage}, TeamId={teamId}, StartDate={startDate}, EndDate={endDate}", Stage.Start, clear.TeamId, clear.StartDate.AsDateString(), clear.EndDate.AsDateString()); }
public static void LogClearStart(this ILogger log, ClearScheduleModel clear, string clearType) { log.LogInformation(EventIds.ClearSchedule, "Clear{clearType}: Stage={stage}, TeamId={teamId}, StartDate={startDate}, EndDate={endDate}, UtcStartDate={utcStartDate}, UtcEndDate={utcEndDate}, ClearOpenShifts={clearOpenShifts}, ClearSchedulingGroups={clearSchedulingGroups}, ClearShifts={clearShifts}, ClearTimeOff={clearTimeOff}", clearType, Stage.Start, clear.TeamId, clear.StartDate.AsDateString(), clear.EndDate.AsDateString(), clear.UtcStartDate.AsDateString(), clear.UtcEndDate.AsDateString(), clear.ClearOpenShifts, clear.ClearSchedulingGroups, clear.ClearShifts, clear.ClearTimeOff); }
public static void LogTimeOffError(this ILogger log, Exception ex, ClearScheduleModel clearModel, string operationName, TimeOffModel timeOff) { log.LogError(EventIds.TimeOff, ex, "TimeOff: Status={status}, OperationName={operationName}, DestinationId={destinationId}, EmployeeId={employeeId}, TeamId={teamId}, StartDate={startDate}, EndDate={endDate}", Status.Failed, operationName, timeOff.TeamsTimeOffId, timeOff.TeamsEmployeeId, clearModel.TeamId, clearModel.StartDate.AsDateString(), clearModel.EndDate.AsDateString()); }
public static void LogClearEnd(this ILogger log, ClearScheduleModel clear, string clearType, ResultModel resultModel) { log.Log(resultModel.LogLevel, EventIds.ClearSchedule, "Clear{clearType}: Stage={stage}, TeamId={teamId}, StartDate={startDate}, EndDate={endDate}, UtcStartDate={utcStartDate}, UtcEndDate={utcEndDate}, DeletedCount={deletedCount}", clearType, Stage.End, clear.TeamId, clear.StartDate.AsDateString(), clear.EndDate.AsDateString(), clear.UtcStartDate.AsDateString(), clear.UtcEndDate.AsDateString(), resultModel.DeletedCount); }
public static void LogTimeOffError(this ILogger log, Exception ex, ClearScheduleModel clear, string operationName) { log.LogError(EventIds.ClearSchedule, ex, "TimeOff: Status={status}, OperationName={operationName}, TeamId={teamId}, StartDate={startDate}, EndDate={endDate}, UtcStartDate={utcStartDate}, UtcEndDate={utcEndDate}", Status.Failed, operationName, clear.TeamId, clear.StartDate.AsDateString(), clear.EndDate.AsDateString(), clear.UtcStartDate.AsDateString(), clear.UtcEndDate.AsDateString()); }