diff --git a/Common/KnownGitHubs.cs b/Common/KnownGitHubs.cs index 5d5d73133..6970b548c 100644 --- a/Common/KnownGitHubs.cs +++ b/Common/KnownGitHubs.cs @@ -22,7 +22,7 @@ public static class KnownGitHubs // public const string AccessTokensUrlFormat = "https://api.github.com/app/installations/{0}/access_tokens"; - public const int SmallestLimitPaidPlan = 5; + public const int SmallestLimitPaidPlan = 1; // -1 for existing plans that include unlimited private // -2 for old plans which also have unlimited private, that do not need marketplacesync @@ -44,6 +44,11 @@ public static readonly ReadOnlyDictionary Plans { 6921, 50 }, { 6922, 100 }, { 6923, 200 }, + { 7386, 1 }, + { 7387, 3 }, + { 7388, 10 }, + { 7389, 25 }, + { 7390, 100 }, }); } } diff --git a/Common/Messages/BackupMessage.cs b/Common/Messages/BackupMessage.cs new file mode 100644 index 000000000..884b1ddbe --- /dev/null +++ b/Common/Messages/BackupMessage.cs @@ -0,0 +1,11 @@ +namespace Common.Messages +{ + public class BackupMessage + { + public int PlanId { get; set; } + + public string SaleType { get; set; } + + public int Price { get; set; } + } +} \ No newline at end of file diff --git a/Common/TableModels/Marketplace.cs b/Common/TableModels/Marketplace.cs index ee316e82a..1e9617c12 100644 --- a/Common/TableModels/Marketplace.cs +++ b/Common/TableModels/Marketplace.cs @@ -38,5 +38,7 @@ public Marketplace(int accountId, string accountLogin) public int? AllowedPrivate { get; set; } public int? UsedPrivate { get; set; } + + public bool? FreeTrial { get; set; } } } diff --git a/CompressImagesFunction/host.json b/CompressImagesFunction/host.json index b1331224d..233722d2b 100644 --- a/CompressImagesFunction/host.json +++ b/CompressImagesFunction/host.json @@ -1,12 +1,12 @@ { "version": "2.0", - "functionTimeout": "01:00:00", + "functionTimeout": "02:00:00", "logging": { "fileLoggingMode": "never" }, "extensions": { "queues": { - "batchSize": 4 + "batchSize": 2 } } } diff --git a/Test/WebHookTests.cs b/Test/WebHookTests.cs index 1682a103a..c15608760 100644 --- a/Test/WebHookTests.cs +++ b/Test/WebHookTests.cs @@ -32,7 +32,8 @@ public async Task GivenCommitToOtherBranch_ShouldReturnOkDoNothing() out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -65,7 +66,8 @@ public async Task GivenCommitToDefaultBranchNoImages_ShouldReturnOkDoNothing() out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -98,7 +100,8 @@ public async Task GivenCommitToImgBotBranchByImgbot_ShouldReturnOkQueueToOpenPr( out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -134,7 +137,8 @@ public async Task GivenCommitToImgBotBranchByOthers_ShouldReturnOkDoNothing() out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -167,7 +171,8 @@ public async Task GivenCommitToDefaultBranchWithImages_ShouldReturnOkQueueToRout out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -224,6 +229,7 @@ void ExtraSetup( out var installationsTable, out var marketplaceTable, out var settingsTable, + out var backupMessages, ExtraSetup); // Assert OKObjectResult and Value @@ -261,7 +267,8 @@ public async Task GivenCommitToDefaultBranchWithConfig_ShouldReturnOkQueueToRout out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -298,7 +305,8 @@ public async Task GivenCommitToDefaultBranchWithImagesUppercaseExtensions_Should out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -335,7 +343,8 @@ public async Task GivenNewInstallationAdded_ShouldReturnOkQueueRouter() out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -372,7 +381,8 @@ public async Task GivenNewInstallationCreated_ShouldReturnOkQueueRouter() out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -428,6 +438,7 @@ void ExtraSetup( out var installationsTable, out var marketplaceTable, out var settingsTable, + out var backupMessages, ExtraSetup); // Assert OKObjectResult and Value @@ -483,6 +494,7 @@ void ExtraSetup( out var installationsTable, out var marketplaceTable, out var settingsTable, + out var backupMessages, ExtraSetup); // Assert OKObjectResult and Value @@ -516,7 +528,8 @@ public async Task GivenMarketplacePurchase_ShouldReturnOkWriteRow() out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -569,6 +582,7 @@ void ExtraSetup( out var installationsTable, out var marketplaceTable, out var settingsTable, + out var backupMessages, ExtraSetup); // Assert OKObjectResult and Value @@ -603,7 +617,8 @@ public async Task GivenMergedImgBotToDefaultBranch_ShouldReturnOkQueueToDeleteBr out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -660,6 +675,7 @@ void ExtraSetup( out var installationsTable, out var marketplaceTable, out var settingsTable, + out var backupMessages, ExtraSetup); // Assert OKObjectResult and Value @@ -697,7 +713,8 @@ public async Task GivenMergedImgBotToOtherBranch_ShouldReturnOkDoNothing() out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -730,7 +747,8 @@ public async Task GivenSquashMergedImgBotToDefaultBranch_ShouldReturnOkQueueToDe out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -767,7 +785,8 @@ public async Task GivenRebaseMergedImgBotToDefaultBranch_ShouldReturnOkQueueToDe out var deleteBranchMessages, out var installationsTable, out var marketplaceTable, - out var settingsTable); + out var settingsTable, + out var backupMessages); // Assert OKObjectResult and Value var response = (HookResponse)((OkObjectResult)result).Value; @@ -802,6 +821,7 @@ private Task ExecuteHookAsync( out CloudTable installationsTable, out CloudTable marketplaceTable, out CloudTable settingsTable, + out CloudQueue backupMessages, Action extraSetup = null) { var request = Substitute.For(); @@ -811,6 +831,8 @@ private Task ExecuteHookAsync( installationsTable = Substitute.For(new Uri("https://myaccount.table.core.windows.net/Tables/installation")); marketplaceTable = Substitute.For(new Uri("https://myaccount.table.core.windows.net/Tables/marketplace")); settingsTable = Substitute.For(new Uri("https://myaccount.table.core.windows.net/Tables/settings")); + backupMessages = Substitute.For(new Uri("https://myaccount.queue.core.windows.net/Queue/backup")); + var logger = Substitute.For(); request.Headers.Add("X-GitHub-Event", new[] { githubEvent }); @@ -819,7 +841,7 @@ private Task ExecuteHookAsync( extraSetup?.Invoke(routerMessages, openPrMessages, installationsTable, marketplaceTable, settingsTable); return WebHook.WebHookFunction.Run( - request, routerMessages, openPrMessages, deleteBranchMessages, installationsTable, marketplaceTable, settingsTable, logger); + request, routerMessages, openPrMessages, deleteBranchMessages, installationsTable, marketplaceTable, settingsTable, backupMessages, logger); } } } diff --git a/Web/src/app/vue/App.vue b/Web/src/app/vue/App.vue index e20cfab85..bb879a72b 100644 --- a/Web/src/app/vue/App.vue +++ b/Web/src/app/vue/App.vue @@ -139,7 +139,7 @@

- Imgbot © 2017-2020 + Imgbot © 2017-2022

diff --git a/Web/src/app/vue/components/Installation.vue b/Web/src/app/vue/components/Installation.vue index 7ebf6c142..f61163bfd 100644 --- a/Web/src/app/vue/components/Installation.vue +++ b/Web/src/app/vue/components/Installation.vue @@ -77,14 +77,19 @@ export default { case 6894: return 'Starter' case 6919: + case 7386: return 'Team' case 6920: + case 7387: return 'Agency' case 6921: + case 7388: return 'Enterprise' case 6922: + case 7389: return 'Gold' case 6923: + case 7390: return 'Platinium' } @@ -98,11 +103,16 @@ export default { case 6921: case 6922: case 6927: + case 7386: + case 7387: + case 7388: + case 7389: return 'Upgrade plan' case 1750: case 2840: case 2841: case 6923: + case 7390: return 'Downgrade plan' } }, @@ -110,23 +120,33 @@ export default { switch (this.installation.planId) { case 1749: case 6927: - return `https://github.com/marketplace/imgbot/upgrade/6/${this.installation.accountid}` + return `https://github.com/marketplace/imgbot/upgrade/13/${this.installation.accountid}` case 1750: case 2840: case 2841: return `https://github.com/marketplace/imgbot/upgrade/12/${this.installation.accountid}` case 6894: - return `https://github.com/marketplace/imgbot/upgrade/7/${this.installation.accountid}` + return `https://github.com/marketplace/imgbot/upgrade/13/${this.installation.accountid}` case 6919: - return `https://github.com/marketplace/imgbot/upgrade/8/${this.installation.accountid}` + return `https://github.com/marketplace/imgbot/upgrade/14/${this.installation.accountid}` case 6920: - return `https://github.com/marketplace/imgbot/upgrade/9/${this.installation.accountid}` + return `https://github.com/marketplace/imgbot/upgrade/15/${this.installation.accountid}` case 6921: - return `https://github.com/marketplace/imgbot/upgrade/10/${this.installation.accountid}` + return `https://github.com/marketplace/imgbot/upgrade/16/${this.installation.accountid}` case 6922: - return `https://github.com/marketplace/imgbot/upgrade/11/${this.installation.accountid}` + return `https://github.com/marketplace/imgbot/upgrade/17/${this.installation.accountid}` case 6923: - return `https://github.com/marketplace/imgbot/upgrade/10/${this.installation.accountid}` + return `https://github.com/marketplace/imgbot/upgrade/16/${this.installation.accountid}` + case 7386: + return `https://github.com/marketplace/imgbot/upgrade/14/${this.installation.accountid}` + case 7387: + return `https://github.com/marketplace/imgbot/upgrade/15/${this.installation.accountid}` + case 7388: + return `https://github.com/marketplace/imgbot/upgrade/16/${this.installation.accountid}` + case 7389: + return `https://github.com/marketplace/imgbot/upgrade/17/${this.installation.accountid}` + case 7390: + return `https://github.com/marketplace/imgbot/upgrade/16/${this.installation.accountid}` } }, filteredRepositories: function() { diff --git a/Web/src/app/vue/components/Repository.vue b/Web/src/app/vue/components/Repository.vue index ed36bfd39..ffcc36703 100644 --- a/Web/src/app/vue/components/Repository.vue +++ b/Web/src/app/vue/components/Repository.vue @@ -127,7 +127,7 @@ export default { return 'undefined'; }, addedPlan: function() { - return [ 6894, 6919, 6920, 6921, 6922,6923 ].includes(this.planId); + return [ 6894, 6919, 6920, 6921, 6922,6923,7386,7387,7388,7389,7390 ].includes(this.planId); } }, methods: { diff --git a/Web/src/github-students/index.html b/Web/src/github-students/index.html index 4441686c8..928d3af39 100644 --- a/Web/src/github-students/index.html +++ b/Web/src/github-students/index.html @@ -188,7 +188,7 @@

Policies

- Imgbot © 2017-2019 + Imgbot © 2017-2022

diff --git a/Web/src/index.html b/Web/src/index.html index fc090e4cd..0e2457ac7 100644 --- a/Web/src/index.html +++ b/Web/src/index.html @@ -235,7 +235,7 @@

Policies

- Imgbot © 2017-2019 + Imgbot © 2017-2022

diff --git a/Web/src/info/index.html b/Web/src/info/index.html index 6e9d74d33..ca6c04895 100644 --- a/Web/src/info/index.html +++ b/Web/src/info/index.html @@ -121,7 +121,7 @@

Policies

- Imgbot © 2017-2019 + Imgbot © 2017-2022

diff --git a/Web/src/winning/index.html b/Web/src/winning/index.html index 26bfe88a5..c07355ef6 100644 --- a/Web/src/winning/index.html +++ b/Web/src/winning/index.html @@ -178,7 +178,7 @@

Policies

- Imgbot © 2017-2019 + Imgbot © 2017-2022

diff --git a/WebHook/Model/Hook.cs b/WebHook/Model/Hook.cs index ff969b042..29ccf18fb 100644 --- a/WebHook/Model/Hook.cs +++ b/WebHook/Model/Hook.cs @@ -336,11 +336,13 @@ public class MarketplacePurchase public Account account { get; set; } public Plan plan { get; set; } + public bool? on_free_trial { get; set; } } public class Plan { public int id { get; set; } + public int monthly_price_in_cents { get; set; } } } } diff --git a/WebHook/WebHookFunction.cs b/WebHook/WebHookFunction.cs index 1560b3fdd..a75d4e38c 100644 --- a/WebHook/WebHookFunction.cs +++ b/WebHook/WebHookFunction.cs @@ -31,6 +31,7 @@ public static Task Hook( var installationTable = storageAccount.CreateCloudTableClient().GetTableReference("installation"); var marketplaceTable = storageAccount.CreateCloudTableClient().GetTableReference("marketplace"); var settingsTable = storageAccount.CreateCloudTableClient().GetTableReference("settings"); + var backupQueue = storageAccount.CreateCloudQueueClient().GetQueueReference("backup"); return Run( req, @@ -40,6 +41,7 @@ public static Task Hook( installationTable, marketplaceTable, settingsTable, + backupQueue, logger); } @@ -51,6 +53,7 @@ public static async Task Run( CloudTable installationTable, CloudTable marketplaceTable, CloudTable settingsTable, + CloudQueue backupMessages, ILogger logger) { var hookEvent = req.Headers.GetValues("X-GitHub-Event").First(); @@ -67,7 +70,7 @@ public static async Task Run( .ConfigureAwait(false); break; case "marketplace_purchase": - result = await ProcessMarketplacePurchaseAsync(hook, marketplaceTable, logger).ConfigureAwait(false); + result = await ProcessMarketplacePurchaseAsync(hook, marketplaceTable, backupMessages, logger).ConfigureAwait(false); break; } @@ -314,7 +317,7 @@ await routerMessages.AddMessageAsync(new CloudQueueMessage(JsonConvert.Serialize return "truth"; } - private static async Task ProcessMarketplacePurchaseAsync(Hook hook, CloudTable marketplaceTable, ILogger logger) + private static async Task ProcessMarketplacePurchaseAsync(Hook hook, CloudTable marketplaceTable, CloudQueue backupMessages, ILogger logger) { switch (hook.action) { @@ -327,6 +330,45 @@ private static async Task ProcessMarketplacePurchaseAsync(Hook hook, Clo allowedPrivate = KnownGitHubs.Plans[hook.marketplace_purchase.plan.id]; } + if (hook.marketplace_purchase.on_free_trial != true && KnownGitHubs.Plans.ContainsKey(hook.marketplace_purchase.plan.id) && KnownGitHubs.Plans[hook.marketplace_purchase.plan.id] != 0) + { + var mktplc = await marketplaceTable.ExecuteAsync( + TableOperation.Retrieve(hook.marketplace_purchase.account.id.ToString(), hook.marketplace_purchase.account.login)); + + var recurrentSale = "new"; + + if (mktplc?.Result != null) + { + if ((mktplc.Result as Marketplace)?.FreeTrial == true) + { + recurrentSale = "trial_upgrade"; + } + else + { + var previousPlan = (mktplc.Result as Marketplace)?.PlanId ?? 0; + + if (previousPlan != 0 && KnownGitHubs.Plans.ContainsKey(previousPlan) && + KnownGitHubs.Plans[previousPlan] != 0) + { + recurrentSale = "recurrent"; + if (KnownGitHubs.Plans[previousPlan] < + KnownGitHubs.Plans[hook.marketplace_purchase.plan.id]) + { + recurrentSale = "upgrade_" + previousPlan.ToString(); + } + } + } + } + + await backupMessages.AddMessageAsync(new CloudQueueMessage(JsonConvert.SerializeObject( + new BackupMessage + { + PlanId = hook.marketplace_purchase.plan.id, + Price = hook.marketplace_purchase.plan.monthly_price_in_cents / 100, + SaleType = recurrentSale + }))); + } + await marketplaceTable.ExecuteAsync(TableOperation.InsertOrMerge(new Marketplace(hook.marketplace_purchase.account.id, hook.marketplace_purchase.account.login) { AccountType = hook.marketplace_purchase.account.type, @@ -337,6 +379,7 @@ await marketplaceTable.ExecuteAsync(TableOperation.InsertOrMerge(new Marketplace SenderLogin = hook.sender.login, AllowedPrivate = allowedPrivate, UsedPrivate = 0, + FreeTrial = hook.marketplace_purchase.on_free_trial, })); logger.LogInformation("ProcessMarketplacePurchaseAsync/purchased {PlanId} for {Owner}", hook.marketplace_purchase.plan.id, hook.marketplace_purchase.account.login);