public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { // at the time of creation, we only support the delete of shifts which are sent to the // integration as a put because when deleting a shift, Teams puts the shift into a draft // delete state which becomes final when the changes are shared return(CanHandleChangeRequest(changeRequest, ShiftChangeUriTemplate, out changeItemRequest) && changeRequest.Requests.Length == 1 && changeItemRequest.Method.Equals("put", StringComparison.OrdinalIgnoreCase)); }
public ChangeSuccessResult(ChangeResponse changeResponse, ChangeItemRequest changeItemRequest, string eTag = null) : base(changeResponse) { var changeItemResponse = changeResponse.Responses.First(cir => cir.Id == changeItemRequest.Id); changeItemResponse.Status = (int)HttpStatusCode.OK; changeItemResponse.Body.Etag = eTag ?? GenerateEtag(changeItemResponse.Id); }
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { changeItemRequest = null; if (changeRequest.Requests.Length == 1 && ShiftPreferenceRequestUriTemplate.TryMatch(changeRequest.Requests[0].Url, out _)) { changeItemRequest = changeRequest.Requests[0]; } return(changeItemRequest != null); }
public ChangeSuccessResult(ChangeResponse changeResponse, ChangeItemRequest changeItemRequest, List <string> data) : base(changeResponse) { var changeItemResponse = changeResponse.Responses.First(cir => cir.Id == changeItemRequest.Id); changeItemResponse.Status = (int)HttpStatusCode.OK; changeItemResponse.Body = new ChangeItemDataResponseBody { Data = data }; }
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { changeItemRequest = null; if (CanHandleChangeRequest(changeRequest, OpenShiftRequestUriTemplate, out ChangeItemRequest itemRequest)) { if (itemRequest.Method.Equals("POST", StringComparison.OrdinalIgnoreCase)) { changeItemRequest = itemRequest; } } return(changeItemRequest != null); }
private bool IsDeletedShift(ChangeItemRequest changeItemRequest) { var shift = changeItemRequest.Body.ToObject <ShiftChangeRequest>(); // when the user chooses delete for a shift, the SharedShift details are copied to the // DraftShift and the IsActive flag for the DraftShift is set to false. If the user then // shares the individual delete to commit it, the integration is called again and the // DraftShift is set to null and the IsActive flag of the SharedShift is set to false. // HOWEVER, if the user chooses to share the entire schedule then the drafts are // committed but the integration is not called again, therefore we must perform the work // of the delete in the draft stage but also be able to handle the secondary commit stage return(shift?.DraftShift?.IsActive == false || shift?.SharedShift?.IsActive == false); }
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { changeItemRequest = null; if (base.CanHandleChangeRequest(changeRequest, out ChangeItemRequest itemRequest)) { // a sender swap request is identified by the fact that the method is a POST if (itemRequest.Method.Equals("POST", StringComparison.OrdinalIgnoreCase)) { changeItemRequest = itemRequest; } } return(changeItemRequest != null); }
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { changeItemRequest = null; // in order for this handler to be able to handle this open shift change, it must // contain exactly two requests, one for the open shift being assigned and one for the // shift that is to be created from it if (changeRequest.Requests.Length == 2 && CanHandleChangeRequest(changeRequest, OpenShiftChangeHandler.OpenShiftChangeUriTemplate, out ChangeItemRequest itemRequest) && CanHandleChangeRequest(changeRequest, ShiftChangeHandler.ShiftChangeUriTemplate, out _)) { changeItemRequest = itemRequest; } return(changeItemRequest != null); }
private bool TryValidateChangeItemRequest(ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, out IActionResult validationResponse) { validationResponse = null; if (changeItemRequest.Headers == null || changeItemRequest.Headers.Count == 0) { return(true); } if (changeItemRequest.Headers.Expires.HasValue && DateTime.UtcNow > changeItemRequest.Headers.Expires.Value) { validationResponse = new ChangeErrorResult(changeResponse, changeItemRequest, ErrorCodes.RequestExpired, _stringLocalizer[ErrorCodes.RequestExpired]); return(false); } return(true); }
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { changeItemRequest = null; if (base.CanHandleChangeRequest(changeRequest, out ChangeItemRequest itemRequest)) { if (itemRequest.Method.Equals("PUT", StringComparison.OrdinalIgnoreCase)) { // this is an approval, but is it a recipient approval var swapRequest = itemRequest.Body.ToObject <SwapRequest>(); var state = swapRequest.EvaluateState(itemRequest.Method); if (state == ChangeRequestState.RecipientApproved || state == ChangeRequestState.RecipientDeclined) { changeItemRequest = itemRequest; } } } return(changeItemRequest != null); }
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { changeItemRequest = null; if (CanHandleChangeRequest(changeRequest, OpenShiftRequestUriTemplate, out ChangeItemRequest itemRequest)) { if (itemRequest.Method.Equals("PUT", StringComparison.OrdinalIgnoreCase)) { // this is an approval/decline, but is it a manager approval/decline var openShiftRequest = itemRequest.Body.ToObject <OpenShiftsChangeRequest>(); var state = openShiftRequest.EvaluateState(itemRequest.Method); if (state == ChangeRequestState.ManagerApproved || state == ChangeRequestState.ManagerDeclined) { changeItemRequest = itemRequest; } } } return(changeItemRequest != null); }
public ChangeErrorResult(ChangeResponse changeResponse, ChangeItemRequest changeItemRequest, string errorCode, string errorMessage, bool dataErrorResponse, HttpStatusCode statusCode = HttpStatusCode.BadRequest) : base(changeResponse) { var changeItemResponse = changeResponse.Responses.First(cir => cir.Id == changeItemRequest.Id); changeItemResponse.Status = (int)statusCode; if (dataErrorResponse) { changeItemResponse.Body = new ChangeItemDataResponseBody(); } changeItemResponse.Body.Error = new ChangeErrorResponse { Code = errorCode, Message = errorMessage }; // notwithstanding that this is an error result, the status code must still be 200 OK this.StatusCode = (int)HttpStatusCode.OK; }
private async Task <IActionResult> DeleteShiftAsync(ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { var shift = await ScheduleCacheHelper.FindShiftByTeamsShiftIdAsync(changeItemRequest.Id, teamId, _teamOptions.PastWeeks, _teamOptions.FutureWeeks, _teamOptions.StartDayOfWeek, _scheduleCacheService, _systemTimeService).ConfigureAwait(false); if (shift != null) { var policy = GetConflictRetryPolicy(_teamOptions.RetryMaxAttempts, _teamOptions.RetryIntervalSeconds); try { await policy.ExecuteAsync(() => RemoveShiftFromScheduleAsync(shift, teamId)).ConfigureAwait(false); await ShareDelete(shift, teamId, starter).ConfigureAwait(false); } catch (Exception ex) { log.LogDeleteShiftException(ex, shift, teamId); return(new ChangeErrorResult(changeResponse, ErrorCodes.InternalError, _stringLocalizer[ErrorCodes.InternalError], HttpStatusCode.InternalServerError)); } log.LogDeleteShiftSuccess(shift, teamId); } return(new ChangeSuccessResult(changeResponse)); }
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { changeItemRequest = null; if (CanHandleChangeRequest(changeRequest, OpenShiftRequestUriTemplate, out ChangeItemRequest itemRequest)) { if (itemRequest.Method.Equals("delete", StringComparison.OrdinalIgnoreCase)) { changeItemRequest = itemRequest; } else if (itemRequest.Body != null) { var openShiftRequest = itemRequest.Body.ToObject <OpenShiftsChangeRequest>(); if (openShiftRequest.AssignedTo.Equals(ChangeRequestAssignedTo.System, StringComparison.OrdinalIgnoreCase) && openShiftRequest.State.Equals(ChangeRequestPhase.Declined, StringComparison.OrdinalIgnoreCase)) { changeItemRequest = itemRequest; } } } return(changeItemRequest != null); }
protected async Task <T> ReadRequestObjectAsync <T>(ChangeItemRequest changeItemRequest, string teamId) where T : IHandledRequest { try { if (changeItemRequest.Body != null) { var request = changeItemRequest.Body.ToObject <T>(); var cachedRequest = await _requestCacheService.LoadRequestAsync <T>(teamId, changeItemRequest.Id).ConfigureAwait(false); if (cachedRequest != null) { request.FillTargetIds(cachedRequest); } return(request); } else { return(await _requestCacheService.LoadRequestAsync <T>(teamId, changeItemRequest.Id).ConfigureAwait(false)); } } catch { return(default);
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { // we cannot use the base class method here as we need to handle the invalid url's that // Teams is sending with this request changeItemRequest = null; if (changeRequest.Requests.Length == 1) { // the url as supplied by Teams looks something like the following: //"/shifts/SHFT_bff7961c-1bff-4c39-b2b1-7808eca233de/requestableShifts?requestType=SwapRequest&startTime=5/31/2020 11:00:00 PM +00:00&endTime=6/30/2020 10:59:59 PM +00:00" // because the datetime values are not valid in a url we are having to strip them so that the url parser // does not fail in the TryMatch method var request = changeRequest.Requests[0]; var url = request.Url.Substring(0, request.Url.IndexOf("&")); if (ShiftSwapFilterRequestUriTemplate.TryMatch(url, out var changeItemParams)) { if (changeItemParams.ContainsKey("requestType") && changeItemParams["requestType"].ToString().Equals("SwapRequest", StringComparison.OrdinalIgnoreCase)) { changeItemRequest = request; } } } return(changeItemRequest != null); }
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { var openShiftRequest = await ReadRequestObjectAsync <OpenShiftsChangeRequest>(changeItemRequest, teamId).ConfigureAwait(false); if (openShiftRequest == null) { return(new ChangeErrorResult(changeResponse, ErrorCodes.ChangeRequestNotFound, _stringLocalizer[ErrorCodes.ChangeRequestNotFound])); } if (!await MapOpenShiftRequestIdentitiesAsync(openShiftRequest).ConfigureAwait(false)) { return(new ChangeErrorResult(changeResponse, ErrorCodes.UserCredentialsNotFound, _stringLocalizer[ErrorCodes.UserCredentialsNotFound])); } var openShift = await GetOpenShift(teamId, openShiftRequest.OpenShiftId).ConfigureAwait(false); if (openShift == null) { return(new ChangeErrorResult(changeResponse, ErrorCodes.NoOpenShiftsFound, _stringLocalizer[ErrorCodes.NoOpenShiftsFound])); } var connectionModel = await _scheduleConnectorService.GetConnectionAsync(teamId).ConfigureAwait(false); var wfmOpenShiftRequest = openShiftRequest.AsWfmOpenShiftRequest(); wfmOpenShiftRequest.BuId = connectionModel.WfmBuId; wfmOpenShiftRequest.TimeZoneInfoId = connectionModel.TimeZoneInfoId; wfmOpenShiftRequest.WfmOpenShift = openShift; var wfmResponse = await _wfmActionService.CreateOpenShiftRequestAsync(wfmOpenShiftRequest, log).ConfigureAwait(false); if (wfmResponse.Success) { await _requestCacheService.SaveRequestAsync(teamId, openShiftRequest.Id, openShiftRequest).ConfigureAwait(false); if (_featureOptions.EnableOpenShiftAutoApproval) { await AutoApproveRequestAsync(openShiftRequest, teamId, starter).ConfigureAwait(false); } return(new ChangeSuccessResult(changeResponse)); } return(new ChangeErrorResult(changeResponse, ErrorCodes.ShiftNotAvailableToUser, _stringLocalizer[ErrorCodes.ShiftNotAvailableToUser])); }
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { var swapRequest = await ReadRequestObjectAsync <SwapRequest>(changeItemRequest, teamId).ConfigureAwait(false); if (swapRequest == null) { return(new ChangeErrorResult(changeResponse, ErrorCodes.SwapRequestNotFound, _stringLocalizer[ErrorCodes.SwapRequestNotFound])); } var connectionModel = await _scheduleConnectorService.GetConnectionAsync(teamId).ConfigureAwait(false); var wfmSwapRequest = swapRequest.AsWfmSwapRequest(); wfmSwapRequest.BuId = connectionModel.WfmBuId; var wfmResponse = await _wfmActionService.CancelShiftSwapRequestAsync(wfmSwapRequest, log).ConfigureAwait(false); var actionResult = WfmResponseToActionResult(wfmResponse, changeItemRequest, changeResponse); if (wfmResponse.Success) { await _requestCacheService.SaveRequestAsync(teamId, changeItemRequest.Id, swapRequest).ConfigureAwait(false); } // whether we successfully cancelled the swap request or not, ensure we clear the cache data await DeleteChangeDataAsync(swapRequest).ConfigureAwait(false); return(actionResult); }
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string userId, ILogger log, IDurableOrchestrationClient starter) { var preferenceRequest = changeItemRequest.Body.ToObject <ShiftPreferenceResponse>(); if (preferenceRequest == null) { return(new ChangeErrorResult(changeResponse, ErrorCodes.ChangeRequestNotFound, _stringLocalizer[ErrorCodes.ChangeRequestNotFound])); } var employee = await _cacheService.GetKeyAsync <EmployeeModel>(ApplicationConstants.TableNameEmployees, userId).ConfigureAwait(false); if (employee == null) { return(new ChangeErrorResult(changeResponse, ErrorCodes.UserCredentialsNotFound, _stringLocalizer[ErrorCodes.UserCredentialsNotFound])); } // get the conection object which contains TimeZoneInfoId to populate below availabilityModel. var connection = await _scheduleConnectorService.GetConnectionAsync(employee.TeamIds[0]).ConfigureAwait(false); // map the preference request to an availability model var availabilityModel = _availabilityMap.MapAvailability(preferenceRequest.Availability, userId); availabilityModel.WfmEmployeeId = employee.WfmEmployeeId; availabilityModel.TimeZoneInfoId = connection.TimeZoneInfoId; var wfmResponse = await _wfmActionService.UpdateEmployeeAvailabilityAsync(availabilityModel, log).ConfigureAwait(false); return(WfmResponseToActionResult(wfmResponse, changeItemRequest, changeResponse)); }
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { if (IsDeletedShift(changeItemRequest)) { return(await DeleteShiftAsync(changeItemRequest, changeResponse, teamId, log, starter).ConfigureAwait(false)); } else { // the connector does not currently support this operation return(new ChangeErrorResult(changeResponse, ErrorCodes.UnsupportedOperation, _stringLocalizer[ErrorCodes.UnsupportedOperation], HttpStatusCode.Forbidden)); } }
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { var swapRequest = await ReadRequestObjectAsync <SwapRequest>(changeItemRequest, teamId).ConfigureAwait(false); if (swapRequest == null) { return(new ChangeErrorResult(changeResponse, ErrorCodes.SwapRequestNotFound, _stringLocalizer[ErrorCodes.SwapRequestNotFound])); } // are we already processing a request, if so block premature retries var changeData = await ReadChangeDataAsync(swapRequest).ConfigureAwait(false); if (changeData.RecipientStatus == ChangeData.RequestStatus.InProgress) { changeData = await WaitAndReadChangeDataAsync(swapRequest).ConfigureAwait(false); if (changeData.RecipientStatus == ChangeData.RequestStatus.InProgress) { return(new ChangeErrorResult(changeResponse, ErrorCodes.RequestInProgress, _stringLocalizer[ErrorCodes.RequestInProgress], HttpStatusCode.Processing)); } } if (changeData.RecipientStatus == ChangeData.RequestStatus.Complete) { if (changeData.RecipientResult.StatusCode == (int)HttpStatusCode.OK) { return(new ChangeSuccessResult(changeResponse)); } return(new ChangeErrorResult(changeResponse, changeItemRequest, changeData.RecipientResult.ErrorCode, changeData.RecipientResult.ErrorMessage)); } changeData.RecipientStatus = ChangeData.RequestStatus.InProgress; // clear other statuses to avoid blocking subsequent requests for the same two shifts ResetChangeDataStatuses(changeData); await SaveChangeDataAsync(swapRequest, changeData).ConfigureAwait(false); var connectionModel = await _scheduleConnectorService.GetConnectionAsync(teamId).ConfigureAwait(false); var wfmSwapRequest = swapRequest.AsWfmSwapRequest(); wfmSwapRequest.BuId = connectionModel.WfmBuId; var approve = swapRequest.EvaluateState(changeItemRequest.Method) == ChangeRequestState.RecipientApproved; var wfmResponse = await _wfmActionService.RecipientApproveShiftSwapRequestAsync(wfmSwapRequest, approve, log).ConfigureAwait(false); var actionResult = WfmResponseToActionResult(wfmResponse, changeItemRequest, changeResponse); if (wfmResponse.Success) { await _requestCacheService.SaveRequestAsync(teamId, changeItemRequest.Id, swapRequest).ConfigureAwait(false); await SaveChangeResultAsync(swapRequest).ConfigureAwait(false); } else { await SaveChangeResultAsync(swapRequest, HttpStatusCode.BadRequest, wfmResponse.Error.Code, wfmResponse.Error.Message).ConfigureAwait(false); } await _requestCacheService.SaveRequestAsync(teamId, changeItemRequest.Id, swapRequest).ConfigureAwait(false); // flag that the recipient approval has now finished changeData = await ReadChangeDataAsync(swapRequest).ConfigureAwait(false); changeData.RecipientStatus = ChangeData.RequestStatus.Complete; await SaveChangeDataAsync(swapRequest, changeData).ConfigureAwait(false); // if the auto manager approval feature is enabled, issue it now if (actionResult is ChangeSuccessResult && _featureOptions.EnableShiftSwapAutoApproval) { var deferredActionModel = new DeferredActionModel { ActionType = DeferredActionModel.DeferredActionType.ApproveSwapShiftsRequest, DelaySeconds = _teamOptions.DelayedActionSeconds, RequestId = swapRequest.Id, TeamId = teamId, Message = _stringLocalizer.GetString("ApproveSwapShifts") }; await starter.StartNewAsync(nameof(DeferredActionOrchestrator), deferredActionModel).ConfigureAwait(false); } return(actionResult); }
public abstract bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest);
protected static bool CanHandleChangeRequest(ChangeRequest changeRequest, UriTemplate uriTemplate, out ChangeItemRequest changeItemRequest) { changeItemRequest = null; foreach (var request in changeRequest.Requests) { if (uriTemplate.TryMatch(request.Url, out var changeItemParams)) { changeItemRequest = request; break; } } return(changeItemRequest != null); }
public abstract Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string entityId, ILogger log, IDurableOrchestrationClient starter);
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { log.LogTrace($"{nameof(SenderSwapRequestHandler)}:{nameof(HandleRequest)}:Started"); var swapRequest = await ReadRequestObjectAsync <SwapRequest>(changeItemRequest, teamId).ConfigureAwait(false); if (swapRequest == null) { return(new ChangeErrorResult(changeResponse, ErrorCodes.SwapRequestNotFound, _stringLocalizer[ErrorCodes.SwapRequestNotFound])); } // are we already processing a request, if so block premature retries var changeData = await ReadChangeDataAsync(swapRequest).ConfigureAwait(false); if (changeData.SenderStatus == ChangeData.RequestStatus.InProgress) { changeData = await WaitAndReadChangeDataAsync(swapRequest).ConfigureAwait(false); if (changeData.SenderStatus == ChangeData.RequestStatus.InProgress) { return(new ChangeErrorResult(changeResponse, ErrorCodes.RequestInProgress, _stringLocalizer[ErrorCodes.RequestInProgress], HttpStatusCode.Processing)); } } if (changeData.SenderStatus == ChangeData.RequestStatus.Complete) { // we have already processed this request and it is complete so just return the // result we received the first time // before doing so, however, because Teams creates a new swap request ID each time, // get the previous version of the swap request and update the targetid's of this // new request and save it and delete the old one var oldSwapRequest = await _requestCacheService.LoadRequestAsync <SwapRequest>(teamId, changeData.SwapRequestId).ConfigureAwait(false); swapRequest.FillTargetIds(oldSwapRequest); await _requestCacheService.DeleteRequestAsync(teamId, changeData.SwapRequestId).ConfigureAwait(false); await _requestCacheService.SaveRequestAsync(teamId, changeItemRequest.Id, swapRequest).ConfigureAwait(false); if (changeData.SenderResult.StatusCode == (int)HttpStatusCode.OK) { return(new ChangeSuccessResult(changeResponse)); } return(new ChangeErrorResult(changeResponse, changeItemRequest, changeData.SenderResult.ErrorCode, changeData.SenderResult.ErrorMessage)); } await MapSwapRequestIdentitiesAsync(swapRequest, teamId, log).ConfigureAwait(false); if (string.IsNullOrEmpty(swapRequest.TargetSenderShiftId)) { return(new ChangeErrorResult(changeResponse, ErrorCodes.SenderShiftNotFound, _stringLocalizer[ErrorCodes.SenderShiftNotFound])); } else if (string.IsNullOrEmpty(swapRequest.TargetSenderLoginName)) { return(new ChangeErrorResult(changeResponse, ErrorCodes.UserCredentialsNotFound, _stringLocalizer[ErrorCodes.UserCredentialsNotFound])); } else if (string.IsNullOrEmpty(swapRequest.TargetRecipientShiftId)) { return(new ChangeErrorResult(changeResponse, ErrorCodes.RecipientShiftNotFound, _stringLocalizer[ErrorCodes.RecipientShiftNotFound])); } else if (string.IsNullOrEmpty(swapRequest.TargetRecipientLoginName)) { return(new ChangeErrorResult(changeResponse, ErrorCodes.UserCredentialsNotFound, _stringLocalizer[ErrorCodes.UserCredentialsNotFound])); } // set the request in progress and store the swap request id in cache in case this call // times out and Teams makes a second request changeData.SenderStatus = ChangeData.RequestStatus.InProgress; // clear other statuses to avoid blocking subsequent requests for the same two shifts ResetChangeDataStatuses(changeData); changeData.SwapRequestId = changeItemRequest.Id; await SaveChangeDataAsync(swapRequest, changeData).ConfigureAwait(false); var connectionModel = await _scheduleConnectorService.GetConnectionAsync(teamId).ConfigureAwait(false); var wfmSwapRequest = swapRequest.AsWfmSwapRequest(); wfmSwapRequest.BuId = connectionModel.WfmBuId; var wfmResponse = await _wfmActionService.CreateShiftSwapRequestAsync(wfmSwapRequest, log).ConfigureAwait(false); var actionResult = WfmResponseToActionResult(wfmResponse, changeItemRequest, changeResponse); if (wfmResponse.Success) { swapRequest.TargetSwapRequestId = wfmSwapRequest.SwapRequestId; await _requestCacheService.SaveRequestAsync(teamId, changeItemRequest.Id, swapRequest).ConfigureAwait(false); await SaveChangeResultAsync(swapRequest).ConfigureAwait(false); } else { await SaveChangeResultAsync(swapRequest, HttpStatusCode.BadRequest, wfmResponse.Error.Code, wfmResponse.Error.Message).ConfigureAwait(false); } // flag that the swap request creation has now finished changeData = await ReadChangeDataAsync(swapRequest).ConfigureAwait(false); changeData.SenderStatus = ChangeData.RequestStatus.Complete; await SaveChangeDataAsync(swapRequest, changeData).ConfigureAwait(false); return(actionResult); }
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { // get the open shift from the change item var openShift = changeItemRequest.Body.ToObject <OpenShiftResponse>(); // get the proposed shift to be created from the open shift var proposedShift = changeRequest.Requests .Where(r => r.Method.Equals("POST", StringComparison.OrdinalIgnoreCase)) .Select(r => r.Body.ToObject <ShiftResponse>()) .First(); var connectionModel = await _scheduleConnectorService.GetConnectionAsync(teamId).ConfigureAwait(false); // get the corresponding open shift from cache var localStartDate = openShift.SharedOpenShift.StartDateTime.ApplyTimeZoneOffset(connectionModel.TimeZoneInfoId); var weekStartDate = localStartDate.StartOfWeek(_teamOptions.StartDayOfWeek); var scheduleId = teamId + ApplicationConstants.OpenShiftsSuffix; var cacheModel = await _scheduleCacheService.LoadScheduleAsync(scheduleId, weekStartDate).ConfigureAwait(false); var assignedShift = cacheModel.Tracked.FirstOrDefault(o => o.TeamsShiftId == openShift.Id); if (assignedShift == null) { // we didn't find an open shift with this ID return(new ChangeErrorResult(changeResponse, changeItemRequest, ErrorCodes.NoOpenShiftsFound, _stringLocalizer[ErrorCodes.NoOpenShiftsFound])); } // get the employee object for the manager who initiated the change var manager = await _cacheService.GetKeyAsync <EmployeeModel>(ApplicationConstants.TableNameEmployees, openShift.LastModifiedBy.User.Id).ConfigureAwait(false); if (manager == null) { return(new ChangeErrorResult(changeResponse, changeItemRequest, ErrorCodes.UserCredentialsNotFound, _stringLocalizer[ErrorCodes.UserCredentialsNotFound])); } // get the employee object for the user the open shift is assigned to var employee = await _cacheService.GetKeyAsync <EmployeeModel>(ApplicationConstants.TableNameEmployees, proposedShift.UserId).ConfigureAwait(false); if (employee == null) { return(new ChangeErrorResult(changeResponse, changeItemRequest, ErrorCodes.UserCredentialsNotFound, _stringLocalizer[ErrorCodes.UserCredentialsNotFound])); } var wfmResponse = await _wfmActionService.ManagerAssignOpenShiftAsync(assignedShift, manager, employee, connectionModel.WfmBuId, connectionModel.TimeZoneInfoId, log).ConfigureAwait(false); if (!wfmResponse.Success) { return(new ChangeErrorResult(changeResponse, changeItemRequest, wfmResponse.Error.Code, wfmResponse.Error.Message)); } var policy = GetConflictRetryPolicy(_teamOptions.RetryMaxAttempts, _teamOptions.RetryIntervalSeconds); // as it has been assigned successfully, decrement the quantity assignedShift.Quantity--; // update the open shift in the cache await policy.ExecuteAsync(() => UpdateCachedOpenShiftsAsync(scheduleId, assignedShift, weekStartDate)).ConfigureAwait(false); // convert the open shift to a shift and add it to the week shifts cache assignedShift.Quantity = 1; assignedShift.WfmEmployeeId = employee.WfmEmployeeId; assignedShift.TeamsEmployeeId = employee.TeamsEmployeeId; assignedShift.TeamsShiftId = proposedShift.Id; assignedShift.WfmShiftId = wfmResponse.NewEntityId; await policy.ExecuteAsync(() => UpdateCachedShiftsAsync(teamId, assignedShift, weekStartDate)).ConfigureAwait(false); // finally, set up a deferred action to share the schedule var deferredActionModel = new DeferredActionModel { ActionType = DeferredActionModel.DeferredActionType.ShareTeamSchedule, DelaySeconds = _teamOptions.DelayedActionSeconds, ShareStartDate = openShift.SharedOpenShift.StartDateTime.Date, ShareEndDate = openShift.SharedOpenShift.EndDateTime.Date.AddHours(23).AddMinutes(59), TeamId = teamId }; await starter.StartNewAsync(nameof(DeferredActionOrchestrator), deferredActionModel).ConfigureAwait(false); return(new ChangeSuccessResult(changeResponse)); }
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { return(CanHandleChangeRequest(changeRequest, OpenShiftChangeUriTemplate, out changeItemRequest) && changeRequest.Requests.Length == 1); }
public override bool CanHandleChangeRequest(ChangeRequest changeRequest, out ChangeItemRequest changeItemRequest) { return(CanHandleChangeRequest(changeRequest, SwapRequestUriTemplate, out changeItemRequest)); }
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { var openShiftRequest = await ReadRequestObjectAsync <OpenShiftsChangeRequest>(changeItemRequest, teamId).ConfigureAwait(false); if (openShiftRequest == null) { return(new ChangeErrorResult(changeResponse, ErrorCodes.ChangeRequestNotFound, _stringLocalizer[ErrorCodes.ChangeRequestNotFound])); } var connectionModel = await _scheduleConnectorService.GetConnectionAsync(teamId).ConfigureAwait(false); var wfmOpenShiftRequest = openShiftRequest.AsWfmOpenShiftRequest(); wfmOpenShiftRequest.BuId = connectionModel.WfmBuId; var wfmResponse = await _wfmActionService.CancelOpenShiftRequestAsync(wfmOpenShiftRequest, log).ConfigureAwait(false); if (wfmResponse.Success) { await _requestCacheService.DeleteRequestAsync(teamId, changeItemRequest.Id).ConfigureAwait(false); return(new ChangeSuccessResult(changeResponse)); } return(WfmErrorToActionResult(wfmResponse.Error, changeItemRequest, changeResponse)); }
public override Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { return(Task.FromResult <IActionResult>(new ChangeErrorResult(changeResponse, ErrorCodes.UnsupportedOperation, _stringLocalizer[ErrorCodes.UnsupportedOperation], HttpStatusCode.Forbidden))); }