public async Task JoinAsync(EventJoinDto joinDto, bool addedByColleague = false) { await _semaphoreSlim.WaitAsync(); try { var @event = _eventsDbSet .Include(x => x.EventParticipants) .Include(x => x.EventOptions) .Include(x => x.EventType) .Where(x => x.Id == joinDto.EventId && x.OrganizationId == joinDto.OrganizationId) .Select(MapEventToJoinValidationDto) .FirstOrDefault(); _eventValidationService.CheckIfEventExists(@event); if (addedByColleague) { var hasPermission = await _permissionService.UserHasPermissionAsync(joinDto, AdministrationPermissions.Event); if (@event != null) { _eventValidationService.CheckIfUserHasPermission(joinDto.UserId, @event.ResponsibleUserId, hasPermission); } } // ReSharper disable once PossibleNullReferenceException @event.SelectedOptions = @event.Options .Where(option => joinDto.ChosenOptions.Contains(option.Id)) .ToList(); _eventValidationService.CheckIfRegistrationDeadlineIsExpired(@event.RegistrationDeadline); _eventValidationService.CheckIfProvidedOptionsAreValid(joinDto.ChosenOptions, @event.SelectedOptions); _eventValidationService.CheckIfJoiningNotEnoughChoicesProvided(@event.MaxChoices, joinDto.ChosenOptions.Count()); _eventValidationService.CheckIfJoiningTooManyChoicesProvided(@event.MaxChoices, joinDto.ChosenOptions.Count()); _eventValidationService.CheckIfSingleChoiceSelectedWithRule(@event.SelectedOptions, OptionRules.IgnoreSingleJoin); _eventValidationService.CheckIfEventHasEnoughPlaces(@event.MaxParticipants, @event.Participants.Count + joinDto.ParticipantIds.Count); _eventValidationService.CheckIfAttendOptionIsAllowed(joinDto.AttendStatus, @event); foreach (var userId in joinDto.ParticipantIds) { var userExists = await _usersDbSet.AnyAsync(x => x.Id == userId && x.OrganizationId == joinDto.OrganizationId); _eventValidationService.CheckIfUserExists(userExists); var alreadyParticipates = @event.Participants.Any(p => p == userId); _eventValidationService.CheckIfUserAlreadyJoinedSameEvent(alreadyParticipates); await ValidateSingleJoinAsync(@event, joinDto.OrganizationId, userId); await AddParticipanAsync(userId, @event.Id, @event.SelectedOptions); await JoinOrLeaveEventWallAsync(@event.ResponsibleUserId, userId, @event.WallId, joinDto); } await _uow.SaveChangesAsync(false); _asyncRunner.Run <IEventCalendarService>(async notifier => await notifier.SendInvitationAsync(@event, joinDto.ParticipantIds, joinDto.OrganizationId), _uow.ConnectionName); if (@event.SendEmailToManager) { await NotifyManagersAsync(joinDto, @event); } } finally { _semaphoreSlim.Release(); } }