public async Task <AuthenticationTicket?> OnSignInAsync(
            ulong userId,
            string username,
            string discriminator,
            string avatarHash,
            Func <CancellationToken, Task <IEnumerable <ulong> > > getGuildIdsDelegate,
            CancellationToken cancellationToken = default)
        {
            AuthenticationLogMessages.UserSigningIn(_logger, userId, username, discriminator);

            // Don't bother tracking or retrieving permissions for users we don't care about.
            var isAdmin = _authorizationConfiguration.AdminUserIds.Contains(userId);

            if (!isAdmin && !(await IsMemberAsync(userId, getGuildIdsDelegate, cancellationToken)))
            {
                AuthenticationLogMessages.UserIgnored(_logger, userId, username, discriminator);
                return(null);
            }

            await _usersService.TrackUserAsync(
                userId,
                username,
                discriminator,
                avatarHash,
                cancellationToken);

            AuthenticationLogMessages.UserTracked(_logger, userId);

            AuthenticationLogMessages.AuthenticationTicketActiveIdFetching(_logger, userId);
            var ticketId = await GetActiveTicketIdAsync(userId, cancellationToken);

            AuthenticationLogMessages.AuthenticationTicketActiveIdFetched(_logger, ticketId);

            AuthenticationLogMessages.GrantedPermissionsFetching(_logger, userId);
            var grantedPermissions = (await _usersService.GetGrantedPermissionsAsync(
                                          userId,
                                          cancellationToken))
                                     .Value
                                     .ToDictionary(x => x.Id, x => x.Name);

            AuthenticationLogMessages.GrantedPermissionsFetched(_logger, grantedPermissions);

            var ticket = new AuthenticationTicket(
                ticketId,
                userId,
                username,
                discriminator,
                avatarHash,
                grantedPermissions);

            AuthenticationLogMessages.UserSignedIn(_logger, ticketId, userId, username, discriminator);
            return(ticket);
        }
        private ValueTask <long> GetActiveTicketIdAsync(
            ulong userId,
            CancellationToken cancellationToken)
        => _memoryCache.OptimisticGetOrCreateAsync(MakeUserActiveTicketIdCacheKey(userId), async entry =>
        {
            entry.Priority = CacheItemPriority.High;

            AuthenticationLogMessages.AuthenticationTicketActiveIdFetching(_logger, userId);
            var result = await _authenticationTicketsRepository.ReadActiveIdAsync(userId, cancellationToken);
            AuthenticationLogMessages.AuthenticationTicketActiveIdFetched(_logger, result.Value);

            return(result.Value);
        });
        private async Task UpdateActiveTicketId(
            ulong userId,
            long actionId,
            CancellationToken cancellationToken)
        {
            AuthenticationLogMessages.AuthenticationTicketInvalidating(_logger, userId, actionId);

            using var transactionScope = _transactionScopeFactory.CreateScope();
            TransactionsLogMessages.TransactionScopeCreated(_logger);

            AuthenticationLogMessages.AuthenticationTicketActiveIdFetching(_logger, userId);
            var activeTicketIdResult = await _authenticationTicketsRepository.ReadActiveIdAsync(userId, cancellationToken);

            if (activeTicketIdResult.IsSuccess)
            {
                AuthenticationLogMessages.AuthenticationTicketActiveIdFetched(_logger, activeTicketIdResult.Value);
                AuthenticationLogMessages.AuthenticationTicketDeleting(_logger, userId, activeTicketIdResult.Value);
                await _authenticationTicketsRepository.DeleteAsync(
                    activeTicketIdResult.Value,
                    actionId,
                    cancellationToken);

                AuthenticationLogMessages.AuthenticationTicketDeleted(_logger, userId, activeTicketIdResult.Value);
            }
            else
            {
                AuthenticationLogMessages.AuthenticationTicketActiveIdFetched(_logger, null);
            }

            AuthenticationLogMessages.AuthenticationTicketCreating(_logger, userId);
            var newTicketId = await _authenticationTicketsRepository.CreateAsync(
                userId,
                actionId,
                cancellationToken);

            AuthenticationLogMessages.AuthenticationTicketCreated(_logger, userId, newTicketId);

            _memoryCache.Set(MakeUserActiveTicketIdCacheKey(userId), newTicketId);

            TransactionsLogMessages.TransactionScopeCommitting(_logger);
            transactionScope.Complete();

            AuthenticationLogMessages.AuthenticationTicketInvalidated(_logger, userId, newTicketId);
        }
        public async Task <AuthenticationTicket> OnAuthenticatedAsync(
            long ticketId,
            ulong userId,
            string username,
            string discriminator,
            string avatarHash,
            IReadOnlyDictionary <int, string> grantedPermissions,
            CancellationToken cancellationToken)
        {
            AuthenticationLogMessages.AuthenticationPerforming(_logger, ticketId, userId, username, discriminator, avatarHash, grantedPermissions);

            AuthenticationLogMessages.AuthenticationTicketActiveIdFetching(_logger, userId);
            var activeTicketId = await GetActiveTicketIdAsync(userId, cancellationToken);

            AuthenticationLogMessages.AuthenticationTicketActiveIdFetched(_logger, activeTicketId);

            if (activeTicketId != ticketId)
            {
                AuthenticationLogMessages.GrantedPermissionsFetching(_logger, userId);
                grantedPermissions = (await _usersService.GetGrantedPermissionsAsync(
                                          userId,
                                          cancellationToken))
                                     .Value
                                     .ToDictionary(x => x.Id, x => x.Name);
                AuthenticationLogMessages.GrantedPermissionsFetched(_logger, grantedPermissions);
            }

            _currentTicket = new AuthenticationTicket(
                activeTicketId,
                userId,
                username,
                discriminator,
                avatarHash,
                grantedPermissions);
            AuthenticationLogMessages.AuthenticationPerformed(_logger, activeTicketId);

            return(_currentTicket);
        }