Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contributors Page that auto-fills using GitHub API #26

Merged
merged 7 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 70 additions & 67 deletions ReplayBrowser/Helpers/GitHubApiHelper.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
using System.Net.Http;
using System.Net.Mime;
using System.Text.Json; // Add this for JSON deserialization
using System.Text.Json;
using Microsoft.Extensions.Caching.Memory;
using Serilog;

namespace ReplayBrowser.Helpers;

public class GitHubApiHelper
{
public List<GitHubAccount> Contributors;
private readonly IMemoryCache _memoryCache;
private readonly string? _apiToken;

public GitHubApiHelper(IConfiguration configuration)
public GitHubApiHelper(IConfiguration configuration, IMemoryCache memoryCache)
{
Contributors = new List<GitHubAccount>();
_memoryCache = memoryCache;

try
{
_apiToken = configuration["GitHubAPIToken"];
Expand All @@ -26,88 +26,91 @@ public GitHubApiHelper(IConfiguration configuration)

public async Task<List<GitHubAccount>> GetContributors()
{
try
if (!_memoryCache.TryGetValue("GitHubContributors", out List<GitHubAccount> contributors))
{
using (var httpClient = new HttpClient())
try
{
using (var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/Simyon264/ReplayBrowser/contributors"))
using (var httpClient = new HttpClient())
{
// lesson learned: don't forget the user agent
request.Headers.TryAddWithoutValidation("Accept", "application/vnd.github+json");
request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {_apiToken}");
request.Headers.TryAddWithoutValidation("X-GitHub-Api-Version", "2022-11-28");
request.Headers.TryAddWithoutValidation("User-Agent", "YourAppNameHere");

var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
using (var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/Simyon264/ReplayBrowser/contributors"))
{
request.Headers.TryAddWithoutValidation("Accept", "application/vnd.github+json");
request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {_apiToken}");
request.Headers.TryAddWithoutValidation("X-GitHub-Api-Version", "2022-11-28");
request.Headers.TryAddWithoutValidation("User-Agent", "YourAppNameHere");

var responseBody = await response.Content.ReadAsStringAsync();

// Deserialize JSON into GitHubAccount list
var responseJson = JsonSerializer.Deserialize<List<JsonElement>>(responseBody);
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();

foreach (var obj in responseJson)
{
var responseBody = await response.Content.ReadAsStringAsync();

// Initialize variables with default values
// Doing this to 100% make sure that respinse errors / null responses don't crash anything
string accountName = null;
string accountImageURL = null;
string accountLink = null;
var responseJson = JsonSerializer.Deserialize<List<JsonElement>>(responseBody);
contributors = new List<GitHubAccount>();

// Safely retrieve properties
if (obj.TryGetProperty("login", out var loginProperty))
foreach (var obj in responseJson)
{
accountName = loginProperty.GetString();
}
string accountName = null;
string accountImageURL = null;
string accountLink = null;

if (obj.TryGetProperty("avatar_url", out var avatarUrlProperty))
{
accountImageURL = avatarUrlProperty.GetString();
}
if (obj.TryGetProperty("login", out var loginProperty))
{
accountName = loginProperty.GetString();
}

if (obj.TryGetProperty("html_url", out var htmlUrlProperty))
{
accountLink = htmlUrlProperty.GetString();
}
if (obj.TryGetProperty("avatar_url", out var avatarUrlProperty))
{
accountImageURL = avatarUrlProperty.GetString();
}

// Check for nulls before adding to the list
if (accountName != null && accountImageURL != null && accountLink != null)
{
var account = new GitHubAccount
if (obj.TryGetProperty("html_url", out var htmlUrlProperty))
{
AccountName = accountName,
AccountImageURL = accountImageURL,
AccountLink = accountLink
};
accountLink = htmlUrlProperty.GetString();
}

Contributors.Add(account);
}
else
{
Log.Warning("A required property was missing in the JSON response while attempting to fetch project contributors.");
if (accountName != null && accountImageURL != null && accountLink != null)
{
var account = new GitHubAccount
{
AccountName = accountName,
AccountImageUrl = accountImageURL,
AccountLink = accountLink
};

contributors.Add(account);
}
else
{
Log.Warning("A required property was missing in the JSON response while attempting to fetch project contributors.");
}
}
}

Log.Information("Successfully fetched project contributor list.");
return Contributors;
Log.Information("Successfully fetched project contributor list.");

// Set cache options and cache the contributors list
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(30)); // Adjust expiration as needed

_memoryCache.Set("GitHubContributors", contributors, cacheEntryOptions);
}
}
}
catch (Exception e)
{
Log.Error($"Exception when querying GitHub: {e.Message} - {e.StackTrace}");

// return empty list
return new List<GitHubAccount>();
}
}
catch (Exception e)
{
Log.Error($"Exception when querying GitHub: {e.Message} - {e.StackTrace.ToString()}");

// return empty list
// TODO - Proper handling
return new List<GitHubAccount>();
}

return contributors;
}
}

public struct GitHubAccount
{
public string AccountName { get; set; }
public string AccountImageURL { get; set; }
public string AccountLink { get; set; }
public string AccountName { get; init; }
public string AccountImageUrl { get; init; }
public string AccountLink { get; init; }
}
6 changes: 3 additions & 3 deletions ReplayBrowser/Pages/Contributors.razor
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@
<div style="display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; align-items: center; padding: 20px;">
@if (_contributors.Count == 0)
{
<h4>Error fetching contributors from the GitHub API</h4>
<h4 style="color: red">Error fetching contributors from the GitHub API</h4>
}
else
{
@foreach (var contrib in _contributors)
{
<ContributorCard ContributorName="@contrib.AccountName" ContributorImage="@contrib.AccountImageURL" ContributorLink="@contrib.AccountLink" />
<ContributorCard ContributorName="@contrib.AccountName" ContributorImage="@contrib.AccountImageUrl" ContributorLink="@contrib.AccountLink" />
}
}
</div>

@code {
private List<GitHubAccount>? _contributors = new List<GitHubAccount>();
private List<GitHubAccount> _contributors = new List<GitHubAccount>();

protected async override Task OnInitializedAsync()
{
Expand Down
3 changes: 0 additions & 3 deletions ReplayBrowser/Pages/Shared/ContributorCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,4 @@
[Parameter] public required string ContributorName { get; set; }
[Parameter] public required string ContributorImage { get; set; }
[Parameter] public required string ContributorLink { get; set; }



}
2 changes: 2 additions & 0 deletions ReplayBrowser/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ public void ConfigureServices(IServiceCollection services)
services.AddSingleton<AnalyticsService>();
services.AddSingleton<NoticeHelper>();
services.AddSingleton<GitHubApiHelper>();

services.AddMemoryCache();
bhenrich marked this conversation as resolved.
Show resolved Hide resolved

services.AddHostedService<BackgroundServiceStarter<ReplayParserService>>();
services.AddHostedService<BackgroundServiceStarter<AccountService>>();
Expand Down
Loading