예제 #1
0
        public async Task <DomainValidationResult <Clan> > CreateClanAsync(UserId userId, string name)
        {
            var result = new DomainValidationResult <Clan>();

            if (await _clanRepository.IsMemberAsync(userId))
            {
                result.AddFailedPreconditionError("User already in a clan.");
            }

            if (await _clanRepository.ExistsAsync(name))
            {
                result.AddFailedPreconditionError("Clan with the same name already exist");
            }

            if (result.IsValid)
            {
                var clan = new Clan(name, userId);

                _clanRepository.Create(clan);

                await _clanRepository.UnitOfWork.CommitAsync();

                return(clan);
            }

            return(result);
        }
예제 #2
0
        public async Task <DomainValidationResult <Candidature> > SendCandidatureAsync(UserId userId, ClanId clanId)
        {
            var result = new DomainValidationResult <Candidature>();

            if (await _clanRepository.IsMemberAsync(userId))
            {
                result.AddFailedPreconditionError("User already in a clan.");
            }

            if (await _candidatureRepository.ExistsAsync(userId, clanId))
            {
                result.AddFailedPreconditionError("The candidature of this member for that clan already exist.");
            }

            if (result.IsValid)
            {
                var candidature = new Candidature(userId, clanId);

                _candidatureRepository.Create(candidature);

                await _candidatureRepository.UnitOfWork.CommitAsync();

                return(candidature);
            }

            return(result);
        }
예제 #3
0
        public async Task <DomainValidationResult <Member> > KickMemberFromClanAsync(Clan clan, UserId userId, MemberId memberId)
        {
            var result = new DomainValidationResult <Member>();

            if (!clan.MemberIsOwner(userId))
            {
                result.AddFailedPreconditionError($"The user ({userId}) isn't the clan owner.");
            }

            if (!clan.HasMember(memberId))
            {
                result.AddFailedPreconditionError($"The memberId ({memberId}) isn't a member of the clan '{clan.Name}'.");
            }

            if (result.IsValid)
            {
                var member = clan.FindMember(memberId);

                clan.Kick(member);

                await _clanRepository.UnitOfWork.CommitAsync();

                return(member);
            }

            return(result);
        }
예제 #4
0
        public async Task <DomainValidationResult <Promotion> > CancelPromotionAsync(Promotion promotion, IDateTimeProvider canceledAt)
        {
            var result = new DomainValidationResult <Promotion>();

            if (promotion.IsCanceled())
            {
                result.AddFailedPreconditionError("The promotional code is canceled");
            }

            if (promotion.IsExpired())
            {
                result.AddFailedPreconditionError("The promotional code is expired");
            }

            if (result.IsValid)
            {
                promotion.Cancel(canceledAt);

                await _promotionRepository.CommitAsync();

                return(promotion);
            }

            return(result);
        }
예제 #5
0
        public async Task <DomainValidationResult <Promotion> > RedeemPromotionAsync(Promotion promotion, UserId userId, IDateTimeProvider redeemedAt)
        {
            var result = new DomainValidationResult <Promotion>();

            var user = new User(userId);

            var recipient = new PromotionRecipient(user, redeemedAt);

            if (promotion.IsExpired())
            {
                result.AddFailedPreconditionError("The promotional code is expired");
            }

            if (!promotion.IsActive())
            {
                result.AddFailedPreconditionError("The promotional code is invalid");
            }

            if (promotion.IsRedeemBy(recipient))
            {
                result.AddFailedPreconditionError("The promotional code is already redeemed");
            }

            if (result.IsValid)
            {
                promotion.Redeem(recipient);

                await _promotionRepository.CommitAsync();

                return(promotion);
            }

            return(result);
        }
예제 #6
0
        private async Task <DomainValidationResult <ITransaction> > CreateDepositTransactionAsync(
            ITokenAccount account,
            Token token,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <ITransaction>();

            var transactionBundles = await this.FetchTransactionBundlesAsync(EnumTransactionType.Deposit, EnumCurrencyType.Token);

            if (transactionBundles.All(deposit => deposit.Currency.Amount != token.Amount))
            {
                result.AddFailedPreconditionError(
                    $"The amount of {nameof(Token)} is invalid. These are valid amounts: [{string.Join(", ", transactionBundles.Select(deposit => deposit.Currency.Amount))}].");
            }

            if (!account.IsDepositAvailable())
            {
                result.AddFailedPreconditionError(
                    $"Buying tokens is unavailable until {account.LastDeposit?.Add(TokenAccountDecorator.DepositInterval)}. For security reason we limit the number of financial transaction that can be done in {TokenAccountDecorator.DepositInterval.TotalHours} hours.");
            }

            if (result.IsValid)
            {
                var transaction = account.Deposit(token);

                await _accountRepository.CommitAsync(true, cancellationToken);

                return(transaction.Cast <Transaction>());
            }

            return(result);
        }
예제 #7
0
        public async Task <DomainValidationResult <Division> > CreateDivisionAsync(
            Clan clan,
            UserId userId,
            string name,
            string description
            )
        {
            var result = new DomainValidationResult <Division>();

            if (!clan.MemberIsOwner(userId))
            {
                result.AddFailedPreconditionError($"The user ({userId}) isn't the clan owner.");
            }

            if (result.IsValid)
            {
                var division = new Division(clan.Id, name, description);

                clan.CreateDivision(division);

                await _clanRepository.UnitOfWork.CommitAsync();

                return(division);
            }

            return(result);
        }
예제 #8
0
        public async Task <DomainValidationResult <Clan> > LeaveClanAsync(Clan clan, UserId userId)
        {
            var result = new DomainValidationResult <Clan>();

            if (!clan.HasMember(userId))
            {
                result.AddFailedPreconditionError($"The user ({userId}) isn't a member of the clan '{clan.Name}'.");
            }

            if (result.IsValid)
            {
                var member = clan.FindMember(userId);

                clan.Leave(member);

                await _clanRepository.UnitOfWork.CommitAsync();

                if (clan.Deleted)
                {
                    await this.DeleteClanAsync(clan);
                }

                return(clan);
            }

            return(result);
        }
예제 #9
0
        public async Task <DomainValidationResult <UserProfile> > CreateProfileAsync(
            User user,
            string firstName,
            string lastName,
            Gender gender
            )
        {
            var result = new DomainValidationResult <UserProfile>();

            if (user.Profile != null)
            {
                result.AddFailedPreconditionError("The user's profile has already been created.");
            }

            if (result.IsValid)
            {
                var profile = new UserProfile(firstName, lastName, gender);

                user.Create(profile);

                //await this.UpdateSecurityStampAsync(user);

                await this.UpdateUserAsync(user);

                await _publisher.PublishUserProfileChangedIntegrationEventAsync(UserId.FromGuid(user.Id), profile);

                return(profile);
            }

            return(result);
        }
예제 #10
0
        public async Task <DomainValidationResult <PaymentMethod> > AttachPaymentMethodAsync(
            string paymentMethodId,
            string customerId,
            bool defaultPaymentMethod = false
            )
        {
            var result = new DomainValidationResult <PaymentMethod>();

            var paymentMethodCardLimit = Options.PaymentMethod.Card.Limit;

            if (await this.PaymentMethodCountAsync(customerId) >= paymentMethodCardLimit)
            {
                result.AddFailedPreconditionError(
                    $"You can have a maximum of {paymentMethodCardLimit} card{(paymentMethodCardLimit > 1 ? "s" : string.Empty)} as a payment method");
            }

            if (result.IsValid)
            {
                var options = new PaymentMethodAttachOptions
                {
                    Customer = customerId
                };

                var paymentMethod = await this.AttachAsync(paymentMethodId, options);

                if (defaultPaymentMethod || !await _stripeCustomerService.HasDefaultPaymentMethodAsync(customerId))
                {
                    await _stripeCustomerService.SetDefaultPaymentMethodAsync(customerId, paymentMethodId);
                }

                return(paymentMethod);
            }

            return(result);
        }
예제 #11
0
        public async Task <DomainValidationResult <Participant> > SnapshotChallengeParticipantAsync(
            IChallenge challenge,
            PlayerId gamePlayerId,
            IDateTimeProvider synchronizedAt,
            Func <IScoring, IImmutableSet <Match> > snapshotMatches,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <Participant>();

            if (!challenge.ParticipantExists(gamePlayerId))
            {
                result.AddFailedPreconditionError("Participant doesn't exists.");
            }

            if (result.IsValid)
            {
                var participant = challenge.FindParticipant(gamePlayerId);

                var matches = snapshotMatches(challenge.Scoring);

                participant.Snapshot(matches, synchronizedAt);

                await _challengeRepository.CommitAsync(true, cancellationToken);

                return(participant);
            }

            return(result);
        }
        public override async Task <DomainValidationResult <object> > GenerateAuthenticationAsync(UserId userId, LeagueOfLegendsRequest request)
        {
            try
            {
                var result = new DomainValidationResult <object>();

                var summoner = await _leagueOfLegendsService.Summoner.GetSummonerByNameAsync(Region.Na, request.SummonerName);

                if (await _gameCredentialRepository.CredentialExistsAsync(PlayerId.Parse(summoner.AccountId), Game))
                {
                    result.AddFailedPreconditionError("Summoner's name is already linked by another eDoxa account");
                }

                if (result.IsValid)
                {
                    if (await _gameAuthenticationRepository.AuthenticationExistsAsync(userId, Game))
                    {
                        await _gameAuthenticationRepository.RemoveAuthenticationAsync(userId, Game);
                    }

                    var gameAuthentication = await this.GenerateAuthFactor(summoner);

                    await _gameAuthenticationRepository.AddAuthenticationAsync(userId, Game, gameAuthentication);

                    return(gameAuthentication.Factor);
                }

                return(result);
            }
            catch (RiotSharpException)
            {
                return(DomainValidationResult <object> .Failure("Summoner name is invalid"));
            }
        }
예제 #13
0
        private async Task <DomainValidationResult <ITransaction> > CreateChargeTransactionAsync(
            ITokenAccount account,
            Token token,
            TransactionMetadata?metadata        = null,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <ITransaction>();

            if (!account.HaveSufficientMoney(token))
            {
                result.AddFailedPreconditionError("Insufficient funds.");
            }

            if (result.IsValid)
            {
                var transaction = account.Charge(token, metadata);

                await _accountRepository.CommitAsync(true, cancellationToken);

                return(transaction.Cast <Transaction>());
            }

            return(result);
        }
예제 #14
0
        public async Task <DomainValidationResult <ITransaction> > MarkAccountTransactionAsCanceledAsync(
            IAccount account,
            TransactionMetadata metadata,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <ITransaction>();

            if (!account.TransactionExists(metadata))
            {
                result.AddFailedPreconditionError("Transaction does not exists.");
            }

            if (result.IsValid)
            {
                var transaction = account.FindTransaction(metadata);

                transaction.MarkAsCanceled();

                await _accountRepository.CommitAsync(true, cancellationToken);

                return(transaction.Cast <Transaction>());
            }

            return(result);
        }
예제 #15
0
        public async Task <DomainValidationResult <Invitation> > SendInvitationAsync(ClanId clanId, UserId userId, UserId ownerId)
        {
            var result = new DomainValidationResult <Invitation>();

            if (!await _clanRepository.IsOwnerAsync(clanId, ownerId))
            {
                result.AddDebugError("Permission required.");
            }

            if (await _clanRepository.IsMemberAsync(userId))
            {
                result.AddDebugError("Target already in a clan.");
            }

            if (await _invitationRepository.ExistsAsync(ownerId, clanId))
            {
                result.AddFailedPreconditionError("The invitation from this clan to that member already exist.");
            }

            if (result.IsValid)
            {
                var invitation = new Invitation(userId, clanId);

                _invitationRepository.Create(invitation);

                await _invitationRepository.UnitOfWork.CommitAsync();

                return(invitation);
            }

            return(result);
        }
예제 #16
0
        public async Task <DomainValidationResult <Promotion> > CreatePromotionAsync(
            string promotionalCode,
            Currency currency,
            TimeSpan duration,
            DateTime expiredAt
            )
        {
            var result = new DomainValidationResult <Promotion>();

            if (!await _promotionRepository.IsPromotionalCodeAvailableAsync(promotionalCode))
            {
                result.AddFailedPreconditionError("The promotional code isn't available");
            }

            if (result.IsValid)
            {
                var promotion = new Promotion(
                    promotionalCode,
                    currency,
                    duration,
                    new DateTimeProvider(expiredAt));

                _promotionRepository.Create(promotion);

                await _promotionRepository.CommitAsync();

                return(promotion);
            }

            return(result);
        }
예제 #17
0
        public async Task <DomainValidationResult <ITransaction> > CreateTransactionAsync(
            IAccount account,
            int bundleId,
            TransactionMetadata?metadata        = null,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <ITransaction>();

            if (!await this.TransactionBundleExistsAsync(bundleId))
            {
                result.AddFailedPreconditionError($"Transaction bundle with id of '{bundleId}' wasn't found.");
            }

            if (result.IsValid)
            {
                var transactionBundle = await this.FindTransactionBundleAsync(bundleId);

                return(await this.CreateTransactionAsync(
                           account,
                           transactionBundle.Currency.Amount,
                           transactionBundle.Currency.Type.ToEnumeration <CurrencyType>(),
                           transactionBundle.Type.ToEnumeration <TransactionType>(),
                           metadata,
                           cancellationToken));
            }

            return(result);
        }
예제 #18
0
        public async Task <DomainValidationResult <Credential> > LinkCredentialAsync(UserId userId, Game game)
        {
            var result = new DomainValidationResult <Credential>();

            if (await _gameCredentialRepository.CredentialExistsAsync(userId, game))
            {
                return(result.AddFailedPreconditionError($"{game} credential are already linked."));
            }

            if (!await _gameAuthenticationService.AuthenticationExistsAsync(userId, game))
            {
                return(result.AddFailedPreconditionError($"{game} authentication process not started."));
            }

            var authFactor = await _gameAuthenticationService.FindAuthenticationAsync(userId, game);

            var authResult = await _gameAuthenticationService.ValidateAuthenticationAsync(userId, game, authFactor);

            if (!authResult.IsValid)
            {
                foreach (var error in authResult.Errors)
                {
                    result.AddFailedPreconditionError(error.ErrorMessage);
                }
            }

            if (result.IsValid)
            {
                var credential = new Credential(
                    userId,
                    game,
                    authFactor.PlayerId,
                    new UtcNowDateTimeProvider());

                _gameCredentialRepository.CreateCredential(credential);

                await _gameCredentialRepository.UnitOfWork.CommitAsync();

                return(credential);
            }

            return(result);
        }
예제 #19
0
        public async Task <DomainValidationResult <Participant> > RegisterChallengeParticipantAsync(
            IChallenge challenge,
            UserId userId,
            ParticipantId participantId,
            PlayerId playerId,
            IDateTimeProvider registeredAt,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <Participant>();

            if (challenge.SoldOut)
            {
                result.AddFailedPreconditionError("The challenge was sold out.");
            }

            if (challenge.ParticipantExists(userId))
            {
                result.AddFailedPreconditionError("The user already is registered.");
            }

            if (result.IsValid)
            {
                var participant = new Participant(
                    participantId,
                    userId,
                    playerId,
                    registeredAt);

                challenge.Register(participant);

                if (challenge.SoldOut)
                {
                    challenge.Start(registeredAt);
                }

                await _challengeRepository.CommitAsync(true, cancellationToken);

                return(participant);
            }

            return(result);
        }
예제 #20
0
        private async Task <DomainValidationResult <ITransaction> > CreateWithdrawTransactionAsync(
            IMoneyAccount account,
            Money money,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <ITransaction>();

            var transactionBundles = await this.FetchTransactionBundlesAsync(EnumTransactionType.Withdraw, EnumCurrencyType.Money);

            if (transactionBundles.All(withdraw => withdraw.Currency.Amount != money.Amount))
            {
                result.AddFailedPreconditionError(
                    $"The amount of {nameof(Money)} is invalid. These are valid amounts: [{string.Join(", ", transactionBundles.Select(deposit => deposit.Currency.Amount))}].");
            }

            if (!account.HaveSufficientMoney(money))
            {
                result.AddFailedPreconditionError("Insufficient funds.");
            }

            if (!account.IsWithdrawAvailable())
            {
                result.AddFailedPreconditionError(
                    $"Withdraw is unavailable until {account.LastWithdraw?.Add(MoneyAccountDecorator.WithdrawInterval)}. For security reason we limit the number of financial transaction that can be done in {MoneyAccountDecorator.WithdrawInterval.TotalHours} hours.");
            }

            if (result.IsValid)
            {
                var transaction = account.Withdraw(money);

                await _accountRepository.CommitAsync(true, cancellationToken);

                return(transaction.Cast <Transaction>());
            }

            return(result);
        }
예제 #21
0
        public override async Task <DomainValidationResult <GameAuthentication> > ValidateAuthenticationAsync(UserId userId, LeagueOfLegendsGameAuthentication gameAuthentication)
        {
            var result = new DomainValidationResult <GameAuthentication>();

            await _gameAuthenticationRepository.RemoveAuthenticationAsync(userId, Game);

            var summoner = await _leagueOfLegendsService.Summoner.GetSummonerByAccountIdAsync(Region.Na, gameAuthentication.PlayerId);

            if (summoner.ProfileIconId != gameAuthentication.Factor.ExpectedSummonerProfileIconId)
            {
                result.AddFailedPreconditionError($"{Game} authentication process failed.");
            }

            return(result);
        }
예제 #22
0
        public async Task <DomainValidationResult <IChallenge> > CreateChallengeAsync(
            ChallengeId challengeId,
            ChallengePayoutEntries payoutEntries,
            EntryFee entryFee,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <IChallenge>();

            var strategy = _challengePayoutFactory.CreateInstance();

            if (payoutEntries == 0)
            {
                return(result.AddFailedPreconditionError("Challenge payout entries cannot be zero."));
            }

            var payout = strategy.GetChallengePayout(payoutEntries, entryFee);

            if (payout == null)
            {
                return(result.AddFailedPreconditionError("Invalid payout structure. Payout entries doesn't match the chart."));
            }

            if (result.IsValid)
            {
                var challenge = new Challenge(challengeId, payout !);

                _challengeRepository.Create(challenge);

                await _challengeRepository.CommitAsync(true, cancellationToken);

                return(challenge);
            }

            return(result);
        }
예제 #23
0
        public async Task <DomainValidationResult <IChallenge> > DeleteChallengeAsync(IChallenge challenge, CancellationToken cancellationToken = default)
        {
            var result = new DomainValidationResult <IChallenge>();

            if (!challenge.CanDelete())
            {
                result.AddFailedPreconditionError("Challenge can't be deleted.");
            }

            if (result.IsValid)
            {
                _challengeRepository.Delete(challenge);

                await _challengeRepository.CommitAsync(true, cancellationToken);

                return(challenge.Cast <Challenge>());
            }

            return(result);
        }
예제 #24
0
        public async Task <DomainValidationResult <Division> > DeleteDivisionAsync(Clan clan, UserId userId, DivisionId divisionId)
        {
            var result = new DomainValidationResult <Division>();

            if (!clan.MemberIsOwner(userId))
            {
                result.AddFailedPreconditionError($"The user ({userId}) isn't the clan owner.");
            }

            if (result.IsValid)
            {
                var division = clan.RemoveDivision(divisionId);

                await _clanRepository.UnitOfWork.CommitAsync();

                return(division);
            }

            return(result);
        }
예제 #25
0
        public async Task <DomainValidationResult <Clan> > UpdateClanAsync(Clan clan, UserId userId, string?summary)
        {
            var result = new DomainValidationResult <Clan>();

            if (!clan.MemberIsOwner(userId))
            {
                result.AddFailedPreconditionError($"The user ({userId}) isn't the clan owner.");
            }

            if (result.IsValid)
            {
                clan.Update(summary);

                await _clanRepository.UnitOfWork.CommitAsync();

                return(clan);
            }

            return(result);
        }
예제 #26
0
        public async Task <DomainValidationResult <Address> > AddAddressAsync(
            UserId userId,
            Country country,
            string line1,
            string?line2,
            string city,
            string?state,
            string?postalCode
            )
        {
            var result = new DomainValidationResult <Address>();

            var addressBookLimit = Options.Static.AddressBook.Limit;

            if (await _addressRepository.AddressCountAsync(userId) >= addressBookLimit)
            {
                result.AddFailedPreconditionError($"You can have a maximum of {addressBookLimit} addresses in your address book");
            }

            if (result.IsValid)
            {
                var address = new Address(
                    userId,
                    country,
                    line1,
                    line2,
                    city,
                    state,
                    postalCode);

                _addressRepository.Create(address);

                await _addressRepository.UnitOfWork.CommitAsync();

                await _serviceBusPublisher.PublishUserAddressChangedIntegrationEventAsync(userId, address);

                return(address);
            }

            return(result);
        }
예제 #27
0
        public async Task <DomainValidationResult <IChallenge> > SynchronizeChallengeAsync(
            IChallenge challenge,
            IDateTimeProvider synchronizedAt,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <IChallenge>();

            if (!challenge.CanSynchronize())
            {
                result.AddFailedPreconditionError("Challenge wasn't synchronized due to is current state.");
            }

            if (result.IsValid)
            {
                challenge.Synchronize(synchronizedAt);

                await _challengeRepository.CommitAsync(true, cancellationToken);

                return(challenge.Cast <Challenge>());
            }

            return(result);
        }
예제 #28
0
        public async Task <DomainValidationResult <UserProfile> > UpdateProfileAsync(User user, string firstName)
        {
            var result = new DomainValidationResult <UserProfile>();

            if (user.Profile == null)
            {
                result.AddFailedPreconditionError("The user's personal informations does not exist.");
            }

            if (result.IsValid)
            {
                user.Update(firstName);

                await this.UpdateSecurityStampAsync(user);

                await this.UpdateUserAsync(user);

                await _publisher.PublishUserProfileChangedIntegrationEventAsync(UserId.FromGuid(user.Id), user.Profile !);

                return(user.Profile !);
            }

            return(result);
        }
예제 #29
0
        public async Task <DomainValidationResult <Credential> > UnlinkCredentialAsync(Credential credential)
        {
            var result = new DomainValidationResult <Credential>();

            if (credential.Timestamp > DateTime.UtcNow.AddMonths(-1))
            {
                result.AddFailedPreconditionError($"You will have the right to unlink your {credential.Game.DisplayName} credentials in {(credential.Timestamp - DateTime.UtcNow.AddMonths(-1)).Days} days.");
            }

            if (result.IsValid)
            {
                credential.Delete();

                await _gameCredentialRepository.UnitOfWork.CommitAsync();

                _gameCredentialRepository.DeleteCredential(credential);

                await _gameCredentialRepository.UnitOfWork.CommitAsync();

                return(credential);
            }

            return(result);
        }
예제 #30
0
        public async Task <DomainValidationResult <IChallenge> > CloseChallengeAsync(
            IChallenge challenge,
            IDateTimeProvider provider,
            CancellationToken cancellationToken = default
            )
        {
            var result = new DomainValidationResult <IChallenge>();

            if (!challenge.CanClose())
            {
                result.AddFailedPreconditionError("Challenge can't be closed.");
            }

            if (result.IsValid)
            {
                challenge.Close(provider);

                await _challengeRepository.CommitAsync(true, cancellationToken);

                return(challenge.Cast <Challenge>());
            }

            return(result);
        }