public async Task OrgHookWithErrorIsSkipped() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org = TestUtil.MakeTestOrg(context); context.OrganizationAccounts.Add(new OrganizationAccount() { UserId = user.Id, OrganizationId = org.Id, }); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = "event1,event2", GitHubId = null, // Empty GitHub Id OrganizationId = org.Id, Secret = Guid.NewGuid(), LastError = DateTimeOffset.UtcNow, }); await context.SaveChangesAsync(); var orgActor = CreateOrgActor(org.Id, org.Login); var changes = await orgActor.AddOrUpdateOrganizationWebhooks(context, null); var beforeError = hook.LastError; await context.Entry(hook).ReloadAsync(); Assert.IsTrue(hook.LastError == beforeError, "Recent LastError should be skipped."); Assert.IsEmpty(changes.Repositories, "skipped hook should not send changes."); } }
public async Task <HttpResponseMessage> Resync(string owner, string repo) { // first, validate that the secret is presented Request.Headers.TryGetValues("X-Admin-Secret", out var presentedSecrets); var presentedSecret = presentedSecrets?.FirstOrDefault(); var secret = _configuration.AdminSecret; if (secret.IsNullOrWhiteSpace() || presentedSecret != secret) { return(new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)); } long?repoId = null; using (var context = new ShipHubContext()) { var repoFullName = $"{owner}/{repo}"; repoId = (await context.Repositories.SingleOrDefaultAsync(r => r.FullName == repoFullName))?.Id; } if (repoId == null) { return(new HttpResponseMessage(System.Net.HttpStatusCode.NotFound)); } var repoActor = await _grainFactory.GetGrain <IRepositoryActor>(repoId.Value); repoActor.ForceResyncRepositoryIssues().LogFailure(); return(new HttpResponseMessage(System.Net.HttpStatusCode.OK)); }
private ShipHubContext _ephemeralContext; // this is for WithContext only. If you're not WithContext, don't use it. private async Task WithContext(Func <ShipHubContext, Task> dbWork) { if (_borrowedContext != null) { // legacy path await dbWork(_borrowedContext); } else if (_ephemeralContext != null) { // re-entrant path await dbWork(_ephemeralContext); } else { try { _ephemeralContext = _contextFactory.CreateInstance(); await dbWork(_ephemeralContext); } finally { if (_ephemeralContext != null) { _ephemeralContext.Dispose(); _ephemeralContext = null; } } } }
private async Task <string> GitHubUserNameFromWebhookPayload(ChargeBeeWebhookPayload payload) { // Most events include the customer portion which gives us the GitHub username. if (payload.Content.Customer?.GitHubUserName != null) { return(payload.Content.Customer.GitHubUserName); } else { // Invoice events (and maybe others, TBD) don't include the Customer portion so // we have to find the customer id in another section. var candidates = new[] { payload.Content.Invoice?.CustomerId, payload.Content.CreditNote?.CustomerId, }; var customerId = candidates.SkipWhile(string.IsNullOrEmpty).FirstOrDefault(); if (customerId != null) { var accountId = ChargeBeeUtilities.AccountIdFromCustomerId(customerId); using (var context = new ShipHubContext()) { var login = await context.Accounts .AsNoTracking() .Where(x => x.Id == accountId) .Select(x => x.Login) .FirstOrDefaultAsync(); return(login); } } else { return(null); } } }
public async Task RepoHookSetLastErrorIfGitHubAddRequestFails() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var repo = TestUtil.MakeTestRepo(context, user.Id); await context.SaveChangesAsync(); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.RepositoryWebhooks(repo.FullName, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>(), Status = HttpStatusCode.OK, }); mock .Setup(x => x.AddRepositoryWebhook(repo.FullName, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ThrowsAsync(new Exception("some exception!")); var repoActor = CreateRepoActor(repo.Id, repo.FullName); var changes = await repoActor.AddOrUpdateWebhooks(mock.Object); Assert.IsEmpty(changes.Repositories, "Failed hook creation should not send notifications."); var hook = context.Hooks.SingleOrDefault(x => x.RepositoryId == repo.Id); Assert.IsNotNull(hook.LastError, "hook should have been marked as errored when we noticed the AddRepoHook failed"); } }
public async Task OrgHookSetLastErrorIfGitHubAddRequestFails() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org = TestUtil.MakeTestOrg(context); context.OrganizationAccounts.Add(new OrganizationAccount() { UserId = user.Id, OrganizationId = org.Id, }); await context.SaveChangesAsync(); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.OrganizationWebhooks(org.Login, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>(), Status = HttpStatusCode.OK, }); mock .Setup(x => x.AddOrganizationWebhook(org.Login, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ThrowsAsync(new Exception("some exception!")); var orgActor = CreateOrgActor(org.Id, org.Login); var changes = await orgActor.AddOrUpdateOrganizationWebhooks(context, mock.Object); Assert.IsEmpty(changes.Repositories, "Failed hook creation should not send notifications."); var hook = context.Hooks.SingleOrDefault(x => x.OrganizationId == org.Id); Assert.IsNotNull(hook.LastError, "hook should have been marked as errored when we noticed the AddRepoHook failed"); } }
public async Task <IHttpActionResult> SaveQuery(string queryId, [FromBody] QueryBody query) { var id = Guid.Parse(queryId); using (var context = new ShipHubContext()) { var updater = new DataUpdater(context, _mapper); await updater.UpdateQuery(id, ShipHubUser.UserId, query.Title, query.Predicate); // If there are no changes, then the author ID didn't match if (updater.Changes.IsEmpty) { return(StatusCode(System.Net.HttpStatusCode.Conflict)); } _queueClient.NotifyChanges(updater.Changes).LogFailure(ShipHubUser.DebugIdentifier); } var ret = new ShortQueryResponse() { Identifier = queryId, Title = query.Title, Predicate = query.Predicate, Author = ShipHubUser.UserId }; return(Ok(ret)); }
private async Task <QueryEntry> LookupQuery(ShipHubContext context, Guid id) { var q = await context.Queries .AsNoTracking() .Include(x => x.Author) .Where(x => x.Id == id) .SingleOrDefaultAsync(); if (q != null) { return(new QueryEntry() { Id = q.Id, Title = q.Title, Predicate = q.Predicate, Author = new AccountEntry() { Identifier = q.Author.Id, Login = q.Author.Login, Name = q.Author.Name } }); } return(null); }
public async Task SendPurchasePersonalMessage(ChargeBeeWebhookPayload payload) { ChargeBeeUtilities.ParseCustomerId(payload.Content.Customer.Id, out var accountType, out var accountId); if (accountType != "user") { // "activated" only happens on transition from trial -> active, and we only do trials // for personal subscriptions. throw new Exception("subscription_activated should only happen on personal/user subscriptions"); } var belongsToOrganization = false; using (var context = new ShipHubContext()) { belongsToOrganization = (await context.OrganizationAccounts.CountAsync(x => x.UserId == accountId)) > 0; } var wasGivenTrialCredit = payload.Content.Invoice.Discounts? .Count(x => x.EntityType == "document_level_coupon" && x.EntityId.StartsWith("trial_days_left")) > 0; var pdf = await PdfInfo(payload); await _mailer.PurchasePersonal( new Mail.Models.PurchasePersonalMailMessage() { GitHubUserName = payload.Content.Customer.GitHubUserName, ToAddress = payload.Content.Customer.Email, CustomerName = payload.Content.Customer.FirstName + " " + payload.Content.Customer.LastName, BelongsToOrganization = belongsToOrganization, WasGivenTrialCredit = wasGivenTrialCredit, InvoicePdfUrl = pdf.SignedUrl, AttachmentName = pdf.FileName, AttachmentUrl = pdf.DirectUrl, }); }
private async Task <bool> RepoShipNeedsWebhookHelpHelper(bool hasHook, bool isAdmin) { using (var context = new ShipHubContext()) { var userAccount = TestUtil.MakeTestUser(context); var orgAccount = new AccountTableType() { Id = 4001, Login = "******", Type = "org", }; var repo = new RepositoryTableType() { Id = 5001, AccountId = 4001, Name = "unicorns", FullName = "pureimaginary/unicorns", Private = true, HasIssues = true, }; await context.BulkUpdateAccounts(DateTimeOffset.UtcNow, new[] { orgAccount }); var user = context.Users.Single(x => x.Id == userAccount.Id); await context.SaveChangesAsync(); await context.BulkUpdateRepositories(DateTimeOffset.UtcNow, new[] { repo }); await context.SetUserOrganizations(user.Id, new[] { orgAccount.Id }); await context.SetAccountLinkedRepositories( userAccount.Id, new[] { (repo.Id, isAdmin) });
public async Task <IHttpActionResult> WatchQuery(Guid queryId) { QueryEntry entry = null; using (var context = new ShipHubContext()) { entry = await LookupQuery(context, queryId); if (entry != null) { var updater = new DataUpdater(context, _mapper); await updater.ToggleWatchQuery(queryId, ShipHubUser.UserId, true); _queueClient.NotifyChanges(updater.Changes).LogFailure(ShipHubUser.DebugIdentifier); } } if (entry != null) { return(Ok(entry)); } else { return(NotFound()); } }
public async Task RepoHookWithErrorIsSkipped() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var repo = TestUtil.MakeTestRepo(context, user.Id); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = "event1,event2", GitHubId = null, // Empty GitHubId RepositoryId = repo.Id, Secret = Guid.NewGuid(), LastError = DateTimeOffset.UtcNow, }); await context.SaveChangesAsync(); var repoActor = CreateRepoActor(repo.Id, repo.FullName); var changes = await repoActor.AddOrUpdateWebhooks(null); var beforeError = hook.LastError; await context.Entry(hook).ReloadAsync(); Assert.IsTrue(hook.LastError == beforeError, "Recent LastError should be skipped."); Assert.IsEmpty(changes.Repositories, "skipped hook should not send changes."); } }
public async Task SendPaymentSucceededOrganizationMessage(ChargeBeeWebhookPayload payload) { var accountId = ChargeBeeUtilities.AccountIdFromCustomerId(payload.Content.Customer.Id); var planLineItem = payload.Content.Invoice.LineItems.Single(x => x.EntityType == "plan"); var newInvoiceStartDate = DateTimeOffset.FromUnixTimeSeconds(planLineItem.DateFrom); var previousMonthStart = DateTimeOffsetFloor(newInvoiceStartDate.AddMonths(-1)); var previousMonthEnd = DateTimeOffsetFloor(newInvoiceStartDate.AddDays(-1)); int activeUsersCount; string[] activeUsersSample; using (var context = new ShipHubContext()) { activeUsersCount = await context.Usage .Where(x => ( x.Date >= previousMonthStart && x.Date <= previousMonthEnd && context.OrganizationAccounts .Where(y => y.OrganizationId == accountId) .Select(y => y.UserId) .Contains(x.AccountId))) .Select(x => x.AccountId) .Distinct() .CountAsync(); activeUsersSample = await context.Usage .Where(x => ( x.Date >= previousMonthStart && x.Date <= previousMonthEnd && context.OrganizationAccounts .Where(y => y.OrganizationId == accountId) .Select(y => y.UserId) .Contains(x.AccountId))) .Select(x => x.Account.Login) .OrderBy(x => x) .Distinct() .Take(20) .ToArrayAsync(); } var pdf = await PdfInfo(payload); await _mailer.PaymentSucceededOrganization( new Mail.Models.PaymentSucceededOrganizationMailMessage() { GitHubUserName = payload.Content.Customer.GitHubUserName, ToAddress = payload.Content.Customer.Email, CustomerName = payload.Content.Customer.FirstName + " " + payload.Content.Customer.LastName, InvoicePdfUrl = pdf.SignedUrl, AttachmentName = pdf.FileName, AttachmentUrl = pdf.DirectUrl, ServiceThroughDate = DateTimeOffset.FromUnixTimeSeconds(planLineItem.DateTo), PreviousMonthActiveUsersCount = activeUsersCount, PreviousMonthActiveUsersSample = activeUsersSample, PreviousMonthStart = previousMonthStart, AmountPaid = payload.Content.Invoice.AmountPaid / 100.0, PaymentMethodSummary = PaymentMethodSummary(payload.Content.Transaction), }); }
private async Task <SyncSpiderProgress> SpiderProgress(ShipHubContext context) { var dsp = context.SyncSpiderProgress(_user.UserId, _selectiveSyncEnabled); using (var reader = await dsp.ExecuteReaderAsync()) { return(ReadSpiderProgress(reader)); } }
public async Task <IHttpActionResult> BuyFinish(string id, string state) { var hostedPage = (await _chargeBee.HostedPage.Retrieve(id).Request()).HostedPage; if (hostedPage.State != cbm.HostedPage.StateEnum.Succeeded) { // We should only get here if the signup was completed. throw new InvalidOperationException("Asked to complete signup for subscription when checkout did not complete."); } var passThruContent = JsonConvert.DeserializeObject <BuyPassThruContent>(hostedPage.PassThruContent); ChargeBeeUtilities.ParseCustomerId(hostedPage.Content.Subscription.CustomerId, out var accountType, out var accountId); ChangeSummary changes; using (var context = new ShipHubContext()) { changes = await context.BulkUpdateSubscriptions(new[] { new SubscriptionTableType() { AccountId = accountId, State = SubscriptionState.Subscribed.ToString(), TrialEndDate = null, Version = hostedPage.Content.Subscription.ResourceVersion.Value, }, }); } if (!changes.IsEmpty) { await _queueClient.NotifyChanges(changes); } if (passThruContent.AnalyticsId != null) { await _mixpanelClient.TrackAsync( "Purchased", passThruContent.AnalyticsId, new { plan = hostedPage.Content.Subscription.PlanId, customer_id = hostedPage.Content.Subscription.CustomerId, // These refer to the account performing the action, which in the case of // an org subscription, is different than the account being purchased. _github_id = passThruContent.ActorId, _github_login = passThruContent.ActorLogin, }); } var hashParams = new ThankYouPageHashParameters() { Value = hostedPage.Content.Subscription.PlanUnitPrice.Value / 100, PlanId = hostedPage.Content.Subscription.PlanId, }; var hashParamBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes( JsonConvert.SerializeObject(hashParams, GitHubSerialization.JsonSerializerSettings))); return(Redirect($"https://{_configuration.WebsiteHostName}/signup-thankyou.html#{WebUtility.UrlEncode(hashParamBase64)}")); }
public async Task <IHttpActionResult> Accounts() { var combined = new List <Account>(); using (var context = new ShipHubContext()) { var user = await context.Users .Include(x => x.Subscription) .Where(x => x.Subscription != null) .SingleOrDefaultAsync(x => x.Id == ShipHubUser.UserId); if (user != null) { combined.Add(user); } var orgs = await context.AccountRepositories .Where(x => ( x.AccountId == ShipHubUser.UserId && x.Repository.Account is Organization && x.Repository.Account.Subscription != null)) .Select(x => x.Repository.Account) .GroupBy(x => x.Id) .Select(x => x.FirstOrDefault()) .Include(x => x.Subscription) .ToArrayAsync(); combined.AddRange(orgs); } var result = combined .Select(x => { var hasSubscription = x.Subscription.State == SubscriptionState.Subscribed; var signature = CreateSignature(ShipHubUser.UserId, x.Id); var apiHostName = _configuration.ApiHostName; var actionUrl = $"https://{apiHostName}/billing/{(hasSubscription ? "manage" : "buy")}/{ShipHubUser.UserId}/{x.Id}/{signature}"; return(new BillingAccountRow() { Account = new BillingAccount() { Identifier = x.Id, Login = x.Login, // TODO: Sync avatars and return real values here. AvatarUrl = "https://avatars.githubusercontent.com/u/335107?v=3", Type = (x is User) ? "user" : "organization", }, Subscribed = hasSubscription, // TODO: Only allow edits for purchaser or admins. CanEdit = hasSubscription, ActionUrl = actionUrl, PricingLines = new[] { "Free" }, }); }).ToList(); return(Ok(result)); }
public async Task <IHttpActionResult> UnwatchQuery(Guid queryId) { using (var context = new ShipHubContext()) { var updater = new DataUpdater(context, _mapper); await updater.ToggleWatchQuery(queryId, ShipHubUser.UserId, false); _queueClient.NotifyChanges(updater.Changes).LogFailure(ShipHubUser.DebugIdentifier); } return(StatusCode(System.Net.HttpStatusCode.OK)); }
public async Task ModeDefaultsToPaid() { using (var context = new ShipHubContext()) { var env = await MakeEnvironment(context); var response = await GetSubscriptionResponse(env.user1); Assert.AreEqual(SubscriptionMode.Paid, response.Mode, "If we haven't been able to fetch the data from ChargeBee yet, act as if paid."); } }
public async Task CanGetAccounts() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org1 = TestUtil.MakeTestOrg(context, 6001, "myorg1"); var org2 = TestUtil.MakeTestOrg(context, 6002, "myorg2"); var org3 = TestUtil.MakeTestOrg(context, 6003, "myorg3"); var org1Repo = TestUtil.MakeTestRepo(context, org1.Id, 2001, "org1repo"); var org2Repo = TestUtil.MakeTestRepo(context, org2.Id, 2002, "org2repo"); var org3Repo = TestUtil.MakeTestRepo(context, org3.Id, 2003, "org3repo"); await context.SetAccountLinkedRepositories(user.Id, new[] {
private async Task RecordUsage() { var utcNow = DateTimeOffset.UtcNow; // We only have to record usage once per calendar day. if (_lastRecordedUsage == null || _lastRecordedUsage?.DayOfYear != utcNow.DayOfYear) { using (var context = new ShipHubContext()) { await context.RecordUsage(_user.UserId, utcNow); } _lastRecordedUsage = utcNow; } }
public async Task SendHelloResponse(Guid purgeIdentifier) { using (var context = new ShipHubContext()) { var spiderProgress = await SpiderProgress(context); await _connection.SendJsonAsync( new HelloResponse() { PurgeIdentifier = purgeIdentifier, SpiderProgress = spiderProgress } ); } }
private static async Task <Environment> MakeEnvironment(ShipHubContext context) { var env = new Environment() { user1 = TestUtil.MakeTestUser(context, 3001, "alok"), user2 = TestUtil.MakeTestUser(context, 3002, "aroon"), org = TestUtil.MakeTestOrg(context, 6001, "pureimaginary") }; await context.SetUserOrganizations(env.user1.Id, new[] { env.org.Id }); await context.SaveChangesAsync(); return(env); }
public async Task OrgHookWithOldErrorIsRetried() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var org = TestUtil.MakeTestOrg(context); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = "event1,event2", GitHubId = null, // Empty GitHub Id OrganizationId = org.Id, Secret = Guid.NewGuid(), LastError = DateTimeOffset.UtcNow.Subtract(OrganizationActor.HookErrorDelay), }); await context.SaveChangesAsync(); await context.SetUserOrganizations(user.Id, new[] { org.Id }); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.OrganizationWebhooks(org.Login, null, It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>() { }, Status = HttpStatusCode.OK, }); mock .Setup(x => x.AddOrganizationWebhook(org.Login, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <Webhook>(null) { Result = new Webhook() { Id = 9999, }, Status = HttpStatusCode.OK, }); var orgActor = CreateOrgActor(org.Id, org.Login); var changes = await orgActor.AddOrUpdateOrganizationWebhooks(context, mock.Object); await context.Entry(hook).ReloadAsync(); Assert.AreEqual(9999, hook.GitHubId); Assert.IsNull(hook.LastError); Assert.IsTrue(changes.Organizations?.First() == org.Id, "New hook should send notifications."); } }
public async Task UsersCanBecomeOrgs() { using (var context = new ShipHubContext()) { var user1 = TestUtil.MakeTestUser(context, 3001, "user1"); var user2 = TestUtil.MakeTestUser(context, 3002, "user2"); var user3 = TestUtil.MakeTestUser(context, 3003, "user3"); var repo1 = TestUtil.MakeTestRepo(context, user1.Id, 2001, "unicorns1"); var repo2 = TestUtil.MakeTestRepo(context, user1.Id, 2002, "unicorns2"); var repo3 = TestUtil.MakeTestRepo(context, user2.Id, 2003, "unicorns3"); var repo4 = TestUtil.MakeTestRepo(context, user3.Id, 2004, "unicorns4"); var org1 = TestUtil.MakeTestOrg(context, 6001, "org1"); var org2 = TestUtil.MakeTestOrg(context, 6002, "org2"); await context.SaveChangesAsync(); await context.SetAccountLinkedRepositories(user1.Id, new[] {
public async Task Run(IAsyncCollector <ChangeMessage> notifyChanges) { using (var context = new ShipHubContext()) { // Get all the tokens var tokens = await context.Tokens .AsNoTracking() .Where(x => x.Version < TokenVersion) .ToArrayAsync(); if (tokens.Any()) { Log.Info($"{tokens.Length} tokens need to be rolled."); foreach (var token in tokens) { var speedLimit = Task.Delay(1000); try { var newToken = await ResetToken(token.Token); if (newToken == null) { // Delete the single token await context.DeleteUserAccessToken(token.UserId, token.Token); Log.Info("Deleted expired token."); } else { // Replace the token await context.RollUserAccessToken(token.UserId, token.Token, newToken, TokenVersion); Log.Info("Updated valid token."); } var cs = new ChangeSummary(); cs.Add(userId: token.UserId); await notifyChanges.AddAsync(new ChangeMessage(cs)); } catch (Exception e) { Log.Exception(e, $"Error rolling token for {token.UserId}:{token.Version}"); } await speedLimit; } Log.Info($"Done processing tokens."); } } }
public async Task <IHttpActionResult> QueryInfo(Guid queryId) { QueryEntry entry = null; using (var context = new ShipHubContext()) { entry = await LookupQuery(context, queryId); } if (entry != null) { return(Ok(entry)); } else { return(NotFound()); } }
public async Task RepoHookWithOldErrorIsRetried() { using (var context = new ShipHubContext()) { var user = TestUtil.MakeTestUser(context); var repo = TestUtil.MakeTestRepo(context, user.Id); var hook = context.Hooks.Add(new Hook() { Id = 1001, Events = "event1,event2", GitHubId = null, // Empty GitHubId RepositoryId = repo.Id, Secret = Guid.NewGuid(), LastError = DateTimeOffset.UtcNow.Subtract(RepositoryActor.HookErrorDelay), }); await context.SaveChangesAsync(); var mock = new Mock <IGitHubActor>(); mock .Setup(x => x.RepositoryWebhooks(repo.FullName, It.IsAny <GitHubCacheDetails>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <IEnumerable <Webhook> >(null) { Result = new List <Webhook>(), Status = HttpStatusCode.OK, }); mock .Setup(x => x.AddRepositoryWebhook(repo.FullName, It.IsAny <Webhook>(), It.IsAny <RequestPriority>())) .ReturnsAsync(new GitHubResponse <Webhook>(null) { Result = new Webhook() { Id = 9999, }, Status = HttpStatusCode.OK, }); var repoActor = CreateRepoActor(repo.Id, repo.FullName); var changes = await repoActor.AddOrUpdateWebhooks(mock.Object); await context.Entry(hook).ReloadAsync(); Assert.AreEqual(9999, hook.GitHubId); Assert.IsNull(hook.LastError); Assert.IsTrue(changes.Repositories.First() == repo.Id, "New hook should send notifications."); } }
public static async Task <ShipHubPrincipal> ValidateToken(string token) { using (var s = new ShipHubContext()) { var user = await s.Tokens .AsNoTracking() .Where(x => x.Token == token) .Select(x => new { Id = x.UserId, Login = x.User.Login }) .SingleOrDefaultAsync() .ConfigureAwait(false); if (user == null) { return(null); } return(new ShipHubPrincipal(user.Id, user.Login)); } }
public async Task ModeIsPaidWithPersonalSubscription() { using (var context = new ShipHubContext()) { var env = await MakeEnvironment(context); context.Subscriptions.Add(new Subscription() { AccountId = env.user1.Id, State = SubscriptionState.Subscribed, }); await context.SaveChangesAsync(); var entry = await GetSubscriptionResponse(env.user1); Assert.AreEqual(SubscriptionMode.Paid, entry.Mode, "Mode is paid with a personal subscription."); } }
public async Task HandlePendingInvoiceCreated(ChargeBeeWebhookPayload payload) { var accountId = ChargeBeeUtilities.AccountIdFromCustomerId(payload.Content.Invoice.CustomerId); var planLineItem = payload.Content.Invoice.LineItems.Single(x => x.EntityType == "plan"); if (planLineItem.EntityId == "organization") { // Calculate the number of active users during the previous month, and then // attach extra charges to this month's invoice. So, for organizations, the // base charge on every invoice is for the coming month, but the metered // component is always for the trailing month. var newInvoiceStartDate = DateTimeOffset.FromUnixTimeSeconds(planLineItem.DateFrom); var previousMonthStart = DateTimeOffsetFloor(newInvoiceStartDate.AddMonths(-1)); var previousMonthEnd = DateTimeOffsetFloor(newInvoiceStartDate.AddDays(-1)); int activeUsers; using (var context = new ShipHubContext()) { activeUsers = await context.Usage .AsNoTracking() .Where(x => ( x.Date >= previousMonthStart && x.Date <= previousMonthEnd && context.OrganizationAccounts .Where(y => y.OrganizationId == accountId) .Select(y => y.UserId) .Contains(x.AccountId))) .Select(x => x.AccountId) .Distinct() .CountAsync(); } if (activeUsers > 1) { await _chargeBee.Invoice.AddAddonCharge(payload.Content.Invoice.Id) .AddonId("additional-seats") .AddonQuantity(Math.Max(activeUsers - 1, 0)) .Request(); } } await _chargeBee.Invoice.Close(payload.Content.Invoice.Id).Request(); }