public async Task <IActionResult> CreateScheduledShift(ScheduledShiftUpdateDto dto) { var now = _clock.UtcNow.UtcDateTime; if (User.RoleInPatrol(dto.PatrolId).CanMaintainSchedule() && ( (dto.Day.HasValue && dto.Day.Value > now) || (dto.StartsAt.HasValue && dto.StartsAt.Value > now) )) { var shift = await _scheduleService.ScheduleShift(dto); return(Ok(shift)); } else { return(Forbid()); } }
public async Task <ScheduledShift> ScheduleShift(ScheduledShiftUpdateDto dto) { var patrol = await _patrolRepository.GetPatrol(dto.PatrolId); Group group = null; IList <User> groupMembers = null; if (dto.GroupId.HasValue) { group = await _groupRepository.GetGroup(dto.GroupId.Value); groupMembers = (await _groupRepository.GetUsersInGroup(dto.GroupId.Value)).ToList(); } Shift shift = null; if (dto.StartsAt.HasValue && dto.EndsAt.HasValue && !dto.ShiftId.HasValue) { var localizedStart = dto.StartsAt.Value.UtcToPatrolLocal(patrol); var localizedEnd = dto.EndsAt.Value.UtcToPatrolLocal(patrol); var shifts = await _shiftRepository.GetShifts(dto.PatrolId, localizedStart.Hour, localizedStart.Minute, localizedEnd.Hour, localizedEnd.Minute); if (shifts.Any()) { shift = shifts.First(); dto.ShiftId = shift.Id; } } else if (dto.ShiftId.HasValue && dto.Day.HasValue) { shift = await _shiftRepository.GetShift(dto.ShiftId.Value); if (!dto.StartsAt.HasValue) { var start = new DateTime(dto.Day.Value.Year, dto.Day.Value.Month, dto.Day.Value.Day, shift.StartHour, shift.StartMinute, 0, 0, DateTimeKind.Unspecified); dto.StartsAt = start.UtcFromPatrolLocal(patrol); } if (!dto.EndsAt.HasValue) { var end = new DateTime(dto.Day.Value.Year, dto.Day.Value.Month, dto.Day.Value.Day, shift.EndHour, shift.EndMinute, 0, 0, DateTimeKind.Unspecified); dto.EndsAt = end.UtcFromPatrolLocal(patrol); } } else { throw new InvalidOperationException("Scheduled shift must provide either start+end or day+shift"); } //by this point we should have filled in the dto as best we can and can now persist ScheduledShift scheduledShift = null; List <ScheduledShiftAssignment> assignments = null; List <ScheduledShiftAssignment> newAssignments = new List <ScheduledShiftAssignment>(); if (dto.Id != default(int)) { scheduledShift = await _shiftRepository.GetScheduledShift(dto.Id); scheduledShift.StartsAt = dto.StartsAt.Value; scheduledShift.EndsAt = dto.EndsAt.Value; scheduledShift.GroupId = group != null ? (int?)group.Id : null; scheduledShift.ShiftId = shift != null ? (int?)shift.Id : null; scheduledShift.DurationSeconds = (int)(scheduledShift.EndsAt - scheduledShift.StartsAt).TotalSeconds; await _shiftRepository.UpdateScheduledShift(scheduledShift); assignments = (await _shiftRepository.GetScheduledShiftAssignmentsForScheduledShift(dto.Id)).ToList(); } else { //make sure there's not an existing shift with the same start/end var existing = await _shiftRepository.GetScheduledShifts(dto.PatrolId, dto.StartsAt.Value, dto.EndsAt.Value); if (existing.Any()) { scheduledShift = existing.First(); dto.Id = scheduledShift.Id; bool updated = false; if (!scheduledShift.GroupId.HasValue && group != null) { scheduledShift.GroupId = group.Id; updated = true; } if (!scheduledShift.ShiftId.HasValue && shift != null) { scheduledShift.ShiftId = shift.Id; updated = true; } if (updated) { scheduledShift.DurationSeconds = (int)(scheduledShift.EndsAt - scheduledShift.StartsAt).TotalSeconds; await _shiftRepository.UpdateScheduledShift(scheduledShift); } assignments = (await _shiftRepository.GetScheduledShiftAssignmentsForScheduledShift(dto.Id)).ToList(); } else { scheduledShift = new ScheduledShift() { PatrolId = dto.PatrolId, GroupId = group != null ? (int?)group.Id : null, ShiftId = shift != null ? (int?)shift.Id : null, StartsAt = dto.StartsAt.Value, EndsAt = dto.EndsAt.Value }; scheduledShift.DurationSeconds = (int)(scheduledShift.EndsAt - scheduledShift.StartsAt).TotalSeconds; await _shiftRepository.InsertScheduledShift(scheduledShift); assignments = new List <ScheduledShiftAssignment>(); //populate with work items if necassary await _shiftWorkItemService.AddWorkItemsToNewShiftOccurence(scheduledShift); } } if (group != null) { foreach (var groupMember in groupMembers) { var existing = assignments.FirstOrDefault(x => x.OriginalAssignedUserId == groupMember.Id || x.AssignedUserId == groupMember.Id || x.ClaimedByUserId == groupMember.Id); if (existing == null) { var ssa = new ScheduledShiftAssignment() { Status = ShiftStatus.Assigned, AssignedUserId = groupMember.Id, OriginalAssignedUserId = groupMember.Id, ScheduledShiftId = scheduledShift.Id }; assignments.Add(ssa); await _shiftRepository.InsertScheduledShiftAssignment(ssa); newAssignments.Add(ssa); } else if (existing.Status == ShiftStatus.Claimed && existing.ClaimedByUserId == groupMember.Id) { existing.AssignedUserId = existing.ClaimedByUserId.Value; existing.Status = ShiftStatus.Assigned; await _shiftRepository.UpdateScheduledShiftAssignment(existing); } } } if (dto.AssignUserIds != null) { foreach (var id in dto.AssignUserIds) { var existing = assignments.FirstOrDefault(x => x.OriginalAssignedUserId == id || x.AssignedUserId == id || x.ClaimedByUserId == id); if (existing == null || !id.HasValue) { var ssa = new ScheduledShiftAssignment() { Status = id.HasValue ? ShiftStatus.Assigned : ShiftStatus.Released, AssignedUserId = id, OriginalAssignedUserId = id, ScheduledShiftId = scheduledShift.Id }; assignments.Add(ssa); await _shiftRepository.InsertScheduledShiftAssignment(ssa); newAssignments.Add(ssa); } else if (existing.Status == ShiftStatus.Claimed && existing.ClaimedByUserId == id) { existing.AssignedUserId = existing.ClaimedByUserId.Value; existing.Status = ShiftStatus.Assigned; await _shiftRepository.UpdateScheduledShiftAssignment(existing); } } } var assigneeUserIds = newAssignments.Where(x => x.AssignedUserId.HasValue).Select(x => x.AssignedUserId.Value).Distinct().ToList(); if (assigneeUserIds.Count > 0) { var newAssignees = await _userRepository.GetUsers(assigneeUserIds); await _emailService.SendShiftAdded(newAssignees.ToList(), patrol, scheduledShift); } //todo: delete things that aren't there? seems risky if we found the shift by time not id etc return(await _shiftRepository.GetScheduledShift(scheduledShift.Id)); }