forked from imgbot/Imgbot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MarketplaceSync.cs
128 lines (112 loc) · 5.48 KB
/
MarketplaceSync.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Common;
using Common.TableModels;
using Install;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Newtonsoft.Json;
using Octokit;
namespace MarketplaceSyncFunction
{
public static class MarketplaceSync
{
private static readonly HttpClient HttpClient = new HttpClient();
[Singleton]
[FunctionName("MarketplaceSync")]
public static async Task TimerTrigger(
[TimerTrigger("0 0 * * * *", RunOnStartup = true)]TimerInfo timerInfo,
ILogger logger,
ExecutionContext context)
{
var installationTokenProvider = new InstallationTokenProvider();
var storageAccount = CloudStorageAccount.Parse(KnownEnvironmentVariables.AzureWebJobsStorage);
var marketplaceTable = storageAccount.CreateCloudTableClient().GetTableReference("marketplace");
await RunAsync(marketplaceTable, installationTokenProvider, logger, context);
}
public static async Task RunAsync(
CloudTable marketplaceTable,
IInstallationTokenProvider installationTokenProvider,
ILogger logger,
ExecutionContext context)
{
logger.LogInformation("MarketplaceSync starting");
var jwt = installationTokenProvider.GenerateJWT(
new InstallationTokenParameters
{
AppId = KnownGitHubs.AppId,
},
KnownEnvironmentVariables.APP_PRIVATE_KEY);
var currentPlans = KnownGitHubs.Plans.Keys.Where(k =>
KnownGitHubs.Plans[k] == -1 || KnownGitHubs.Plans[k] >= KnownGitHubs.SmallestLimitPaidPlan);
foreach (var planId in currentPlans)
{
// TODO this will need to be updated to get more than 100 purchases per plan (loop with page) when we get more of the new plans bought
var planRequest = new HttpRequestMessage(HttpMethod.Get, $"https://api.github.com/marketplace_listing/plans/{planId}/accounts?per_page=100");
planRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
planRequest.Headers.Add("User-Agent", "ImgBot");
planRequest.Headers.Add("Accept", "application/vnd.github.machine-man-preview+json");
var planResponse = await HttpClient.SendAsync(planRequest);
var planJson = await planResponse.Content.ReadAsStringAsync();
Account[] accountsInPlan = new Account[0];
try
{
accountsInPlan = JsonConvert.DeserializeObject<Account[]>(planJson);
}
catch (Exception)
{
logger.LogInformation("SerializationError:> " + planJson);
}
logger.LogInformation("MarketplaceSync found {NumPlans} for {PlanId}", accountsInPlan.Length, planId);
// loop through the plans and get all purchases from github in order to sync with our database
// ie. sync all purchases that are on git and not saved on our side
Dictionary<int, bool> gitData = new Dictionary<int, bool>();
foreach (var account in accountsInPlan)
{
var row = new Common.TableModels.Marketplace(account.id, account.login)
{
AccountType = account.type,
PlanId = account.marketplace_purchase.plan.id
};
await marketplaceTable.ExecuteAsync(TableOperation.InsertOrMerge(row));
// create a map to easily check the plans at the next step
gitData.Add(account.id, true);
}
// get all purchases for a plan from our database
// then get all purchases for the plan from the github api
// remove anything that is in our database and not on the github api response
var query = new TableQuery<Common.TableModels.Marketplace>().Where(
"PlanId eq " + planId.ToString()).Take(1000);
TableContinuationToken contToken = null;
var deletedPurchases = new List<string>();
do
{
var rows = await marketplaceTable.ExecuteQuerySegmentedAsync(query, contToken);
contToken = rows.ContinuationToken;
if (!rows.Any())
continue;
bool redundantVariable;
foreach (var purchase in rows)
{
if (gitData.TryGetValue(purchase.AccountId, out redundantVariable))
{
continue;
}
deletedPurchases.Add(purchase.PartitionKey);
await marketplaceTable.DropRow(purchase.PartitionKey, purchase.AccountLogin);
}
}
while (contToken != null);
logger.LogInformation("MarketplaceSync missing git purchases " + JsonConvert.SerializeObject(deletedPurchases));
logger.LogInformation("MarketplaceSync finished");
}
}
}
}