public async Task persists_successfully() { SubscriptionLogRepo repo = new(CreateTemporaryDatabase()); Instant timestamp = Instant.FromUnixTimeSeconds(123); const string userId = "123"; const int monthsStreak = 101; const int monthsNumPrev = 103; const int monthsNumNew = 105; const int monthsDifference = 2; const int loyaltyLeaguePrev = 20; const int loyaltyLeagueNew = 21; const int loyaltyCompletions = 1; const int rewardTokens = 10; const string subMessage = "message text"; const SubscriptionTier subPlan = SubscriptionTier.Tier2; const string subPlanName = "plan name"; // persist to db SubscriptionLog written = await repo.LogSubscription(userId, timestamp, monthsStreak, monthsNumPrev, monthsNumNew, monthsDifference, loyaltyLeaguePrev, loyaltyLeagueNew, loyaltyCompletions, rewardTokens, subMessage, subPlan, subPlanName); Assert.That(written.Timestamp, Is.EqualTo(timestamp)); Assert.That(written.UserId, Is.EqualTo(userId)); Assert.That(written.MonthsStreak, Is.EqualTo(monthsStreak)); Assert.That(written.MonthsNumPrev, Is.EqualTo(monthsNumPrev)); Assert.That(written.MonthsNumNew, Is.EqualTo(monthsNumNew)); Assert.That(written.MonthsDifference, Is.EqualTo(monthsDifference)); Assert.That(written.LoyaltyLeaguePrev, Is.EqualTo(loyaltyLeaguePrev)); Assert.That(written.LoyaltyLeagueNew, Is.EqualTo(loyaltyLeagueNew)); Assert.That(written.LoyaltyCompletions, Is.EqualTo(loyaltyCompletions)); Assert.That(written.RewardTokens, Is.EqualTo(rewardTokens)); Assert.That(written.SubMessage, Is.EqualTo(subMessage)); Assert.That(written.SubPlan, Is.EqualTo(subPlan)); Assert.That(written.SubPlanName, Is.EqualTo(subPlanName)); Assert.NotNull(written.Id); // read from db List <SubscriptionLog> allItems = await repo.Collection.Find(FilterDefinition <SubscriptionLog> .Empty).ToListAsync(); Assert.That(allItems.Count, Is.EqualTo(1)); SubscriptionLog read = allItems[0]; Assert.That(read, Is.EqualTo(written)); Assert.That(read.Timestamp, Is.EqualTo(timestamp)); Assert.That(read.UserId, Is.EqualTo(userId)); Assert.That(read.MonthsStreak, Is.EqualTo(monthsStreak)); Assert.That(read.MonthsNumPrev, Is.EqualTo(monthsNumPrev)); Assert.That(read.MonthsNumNew, Is.EqualTo(monthsNumNew)); Assert.That(read.MonthsDifference, Is.EqualTo(monthsDifference)); Assert.That(read.LoyaltyLeaguePrev, Is.EqualTo(loyaltyLeaguePrev)); Assert.That(read.LoyaltyLeagueNew, Is.EqualTo(loyaltyLeagueNew)); Assert.That(read.LoyaltyCompletions, Is.EqualTo(loyaltyCompletions)); Assert.That(read.RewardTokens, Is.EqualTo(rewardTokens)); Assert.That(read.SubMessage, Is.EqualTo(subMessage)); Assert.That(read.SubPlan, Is.EqualTo(subPlan)); Assert.That(read.SubPlanName, Is.EqualTo(subPlanName)); }
public async Task <SubscriptionLog> LogSubscription( string userId, Instant timestamp, int monthsStreak, int monthsNumPrev, int monthsNumNew, int monthsDifference, int loyaltyLeaguePrev, int loyaltyLeagueNew, int loyaltyCompletions, int rewardTokens, string?subMessage, SubscriptionTier subPlan, string subPlanName) { var item = new SubscriptionLog( string.Empty, userId, timestamp, monthsStreak, monthsNumPrev, monthsNumNew, monthsDifference, loyaltyLeaguePrev, loyaltyLeagueNew, loyaltyCompletions, rewardTokens, subMessage, subPlan, subPlanName); await Collection.InsertOneAsync(item); Debug.Assert(item.Id.Length > 0, "The MongoDB driver injected a generated ID"); return(item); }
/// <summary> /// Disabled Instantly Subscription after sent /// </summary> /// <param name="model"></param> /// <returns></returns> public ResponseModel DisabledSubscriptionDirectly(SubscriptionLog model) { model.IsDirectlySent = true; return(Update(model)); }
/// <summary> /// Deactive Subscription Log /// </summary> /// <param name="model"></param> /// <returns></returns> public ResponseModel DeactiveSubscriptionLog(SubscriptionLog model) { model.Active = false; return(Update(model)); }
internal ResponseModel Delete(SubscriptionLog subscriptionLog) { return(_subscriptionLogRepository.Delete(subscriptionLog)); }
internal ResponseModel Insert(SubscriptionLog subscriptionLog) { return(_subscriptionLogRepository.Insert(subscriptionLog)); }
public SubscriptionLogItem(SubscriptionLog log) : this() { ChangeLog = log.ChangeLog; ChangeDate = log.Created; }
public async Task <ISubscriptionProcessor.SubResult> ProcessSubscription(SubscriptionInfo subscriptionInfo) { User user = subscriptionInfo.Subscriber; if (user.MonthsSubscribed > 0 && user.SubscriptionTier == null) { _logger.LogWarning("Subscriber {User} has no subscription tier recorded. Assuming Tier 1", user); user = await _userRepo.SetSubscriptionInfo( user, user.MonthsSubscribed, SubscriptionTier.Tier1, user.LoyaltyLeague, user.SubscriptionUpdatedAt); } if (user.MonthsSubscribed == subscriptionInfo.NumMonths && user.SubscriptionTier?.ToRank() >= subscriptionInfo.Tier.ToRank()) { // If twitch reports the new months as being the same as the old months, such as due to repeated message // or other error, ignore the sub but send a warning to the user in case of issues. return(new ISubscriptionProcessor.SubResult.SameMonth(subscriptionInfo.NumMonths)); } bool subCountCorrected = false; if (user.MonthsSubscribed > subscriptionInfo.NumMonths) { // Repair the user data and re-read it for further processing. // Set to current months - 1 to process as a 1-month subscription further down. user = await _userRepo.SetSubscriptionInfo( user, subscriptionInfo.NumMonths - 1, subscriptionInfo.Tier, user.LoyaltyLeague, user.SubscriptionUpdatedAt); subCountCorrected = true; } // If our internal months subscribed count is less than what Twitch says it is, // we update our count and give the subscriber "back pay" tokens. // This can occur when users (re)subscribe while the tpp bot is down. Debug.Assert(subscriptionInfo.NumMonths > user.MonthsSubscribed || (subscriptionInfo.NumMonths == user.MonthsSubscribed && subscriptionInfo.Tier.ToRank() > user.SubscriptionTier !.Value.ToRank())); // Difference between previous recorded subscribed months and new amount. int monthsDifference = subscriptionInfo.NumMonths - user.MonthsSubscribed; int loyaltyCompletions; if (monthsDifference > 0) { // Additional benefits for expensive plans are given only for the current months to prevent users from // tricking us into giving them extra "back pay", e.g. by purposefully not announcing lower grade // subscriptions from previous months. loyaltyCompletions = monthsDifference - 1 + subscriptionInfo.Tier.ToRank(); } else { Debug.Assert(user.SubscriptionTier.HasValue, "no months difference must mean it's a tier upgrade, so the user has subscribed before"); // Same month, but an upgrade in subscription tier. Pay the difference in monetary rank. loyaltyCompletions = subscriptionInfo.Tier.ToRank() - user.SubscriptionTier.Value.ToRank(); } const int maxLeague = 15; const int tokensPerLeague = 2; const int baseTokens = 10; int newLoyaltyLeague = Math.Min(user.LoyaltyLeague + loyaltyCompletions, maxLeague); int tokens = Enumerable .Range(user.LoyaltyLeague, loyaltyCompletions) .Select(league => baseTokens + Math.Min(league, maxLeague) * tokensPerLeague) .Sum(); int oldLoyaltyLeague = user.LoyaltyLeague; SubscriptionLog subscriptionLog = await _subscriptionLogRepo.LogSubscription( user.Id, subscriptionInfo.SubscriptionAt, subscriptionInfo.StreakMonths, user.MonthsSubscribed, subscriptionInfo.NumMonths, monthsDifference, oldLoyaltyLeague, newLoyaltyLeague, loyaltyCompletions, tokens, subscriptionInfo.Message, subscriptionInfo.Tier, subscriptionInfo.PlanName); TransactionLog transactionLog = await _tokenBank.PerformTransaction(new Transaction <User>( user, tokens, TransactionType.Subscription, new Dictionary <string, object?> { ["previous_months_subscribed"] = user.MonthsSubscribed, ["new_months_subscribed"] = subscriptionInfo.NumMonths, ["months_difference"] = monthsDifference, ["previous_loyalty_tier"] = oldLoyaltyLeague, ["new_loyalty_tier"] = newLoyaltyLeague, ["loyalty_completions"] = loyaltyCompletions })); user = await _userRepo.SetIsSubscribed(user, true); user = await _userRepo.SetSubscriptionInfo( user, subscriptionInfo.NumMonths, subscriptionInfo.Tier, newLoyaltyLeague, subscriptionInfo.SubscriptionAt); return(new ISubscriptionProcessor.SubResult.Ok( DeltaTokens: tokens, OldLoyaltyLeague: oldLoyaltyLeague, NewLoyaltyLeague: newLoyaltyLeague, CumulativeMonths: subscriptionInfo.NumMonths, SubCountCorrected: subCountCorrected)); }