Skip to content

feat: add gamereplays tab with active/upcoming tournament tracking#246

Open
undead2146 wants to merge 4 commits into
community-outpost:developmentfrom
undead2146:feat/gamereplays
Open

feat: add gamereplays tab with active/upcoming tournament tracking#246
undead2146 wants to merge 4 commits into
community-outpost:developmentfrom
undead2146:feat/gamereplays

Conversation

@undead2146

@undead2146 undead2146 commented Jan 6, 2026

Copy link
Copy Markdown
Member

This PR adds a GameReplays tab to the tabs section which checks the tournaments post and displays the active and upcoming tournaments on GameReplays

Greptile Overview

Greptile Summary

This PR adds a GameReplays tab that displays active and upcoming tournaments from the GameReplays.org forum. The implementation includes HTML parsing to extract tournament data, OAuth 2.0 authentication scaffolding, and a modern UI with filtering capabilities.

Key Changes:

  • Added comprehensive tournament tracking system with HTML scraping using HtmlAgilityPack
  • Implemented OAuth 2.0 authentication service (incomplete - browser launch not implemented)
  • Created modern Avalonia UI with glass panel styling and filter tabs
  • Added 5-minute in-memory caching for tournament data
  • Integrated new tab into main navigation system

Critical Issues:

  • OAuth flow incomplete: browser launch and clipboard operations are stubbed out with TODOs
  • HttpClient registered as transient instead of using IHttpClientFactory, risking socket exhaustion
  • Hardcoded placeholder OAuth credentials (genhub_client/genhub_secret) in constants file
  • In-memory token storage means users must re-authenticate on every app restart
  • Thread-safety issues with in-memory cache in GameReplaysService
  • Unused Initialize method in GameReplaysHttpClient means timeout/user-agent won't be configured

Test Artifact:

  • 834-line index.html test fixture committed to repository root should be moved to test directory

Confidence Score: 2/5

  • Not safe to merge - contains incomplete authentication flow and architectural issues that will cause runtime problems
  • Multiple critical issues prevent this from being production-ready: (1) OAuth authentication is incomplete and won't work without browser launch implementation, (2) HttpClient registration pattern will cause socket exhaustion under load, (3) hardcoded placeholder credentials are a security concern, (4) thread-safety issues in caching could cause data corruption, (5) several user-facing features (copy URL, open tournament) are stubbed out and non-functional
  • Pay close attention to GameReplaysModule.cs (DI registration), GameReplaysHttpClient.cs (unused Initialize method), GameReplaysViewModel.cs (incomplete OAuth), GameReplaysConstants.cs (placeholder credentials), and GameReplaysService.cs (thread-safety)

Important Files Changed

Filename Overview
GenHub/GenHub.Core/Services/GameReplays/GameReplaysAuthService.cs OAuth 2.0 authentication service managing login flow, token lifecycle, and state validation with in-memory storage
GenHub/GenHub.Core/Services/GameReplays/GameReplaysHttpClient.cs HTTP client wrapper for GameReplays API with cookie management and JSON serialization, has unused Initialize method
GenHub/GenHub.Core/Constants/GameReplaysConstants.cs Constants file with hardcoded placeholder OAuth credentials that need replacement before production
GenHub/GenHub/Features/GameReplays/ViewModels/GameReplaysViewModel.cs Main view model managing tournament display, filtering, and user interactions with incomplete OAuth browser launch and clipboard functionality
GenHub/GenHub.Core/Infrastructure/DependencyInjection/GameReplaysModule.cs DI registration module with transient HttpClient registration that may cause socket exhaustion issues
index.html Large 834-line HTML test fixture file committed to repository root instead of test directory

Sequence Diagram

sequenceDiagram
    participant User
    participant GameReplaysView
    participant GameReplaysViewModel
    participant GameReplaysService
    participant GameReplaysAuthService
    participant GameReplaysHttpClient
    participant GameReplaysParser
    participant GameReplaysAPI

    Note over User,GameReplaysAPI: Tab Initialization Flow
    User->>GameReplaysView: Navigate to GameReplays tab
    GameReplaysView->>GameReplaysViewModel: InitializeAsync()
    GameReplaysViewModel->>GameReplaysService: GetTournamentsAsync()
    GameReplaysService->>GameReplaysHttpClient: GetHtmlAsync(tournament board URL)
    GameReplaysHttpClient->>GameReplaysAPI: HTTP GET /community/index.php?showtopic=1066376
    GameReplaysAPI-->>GameReplaysHttpClient: HTML response
    GameReplaysHttpClient-->>GameReplaysService: HTML content
    GameReplaysService->>GameReplaysParser: ParseTournamentBoard(html)
    GameReplaysParser-->>GameReplaysService: GameReplaysTournaments
    GameReplaysService-->>GameReplaysViewModel: Tournaments data
    GameReplaysViewModel->>GameReplaysViewModel: UpdateFilteredTournaments()
    GameReplaysViewModel-->>GameReplaysView: Display tournaments

    Note over User,GameReplaysAPI: OAuth Login Flow (Incomplete)
    User->>GameReplaysView: Click Login
    GameReplaysView->>GameReplaysViewModel: LoginCommand
    GameReplaysViewModel->>GameReplaysService: InitiateLoginAsync()
    GameReplaysService->>GameReplaysAuthService: GetAuthorizationUrl()
    GameReplaysAuthService->>GameReplaysAuthService: GenerateState()
    GameReplaysAuthService-->>GameReplaysService: Authorization URL
    GameReplaysService-->>GameReplaysViewModel: Auth URL
    Note over GameReplaysViewModel: TODO: Browser launch not implemented
    GameReplaysViewModel-->>User: Log message only

    Note over User,GameReplaysAPI: OAuth Callback Flow (If implemented)
    GameReplaysAPI->>GameReplaysService: HandleCallbackAsync(code, state)
    GameReplaysService->>GameReplaysAuthService: ValidateState(state)
    GameReplaysAuthService-->>GameReplaysService: Valid
    GameReplaysService->>GameReplaysAuthService: ExchangeCodeForTokenAsync(code)
    GameReplaysAuthService->>GameReplaysHttpClient: PostJsonAsync(token endpoint)
    GameReplaysHttpClient->>GameReplaysAPI: POST /oauth/token
    GameReplaysAPI-->>GameReplaysHttpClient: Token response
    GameReplaysHttpClient-->>GameReplaysAuthService: OAuthTokenResponse
    GameReplaysAuthService->>GameReplaysAuthService: SaveTokenAsync()
    GameReplaysAuthService->>GameReplaysHttpClient: SetAuthCookie()
    GameReplaysAuthService->>GameReplaysHttpClient: GetJsonAsync(user info endpoint)
    GameReplaysHttpClient->>GameReplaysAPI: GET /oauth/resource
    GameReplaysAPI-->>GameReplaysHttpClient: User info
    GameReplaysHttpClient-->>GameReplaysAuthService: OAuthUserInfo
    GameReplaysAuthService-->>GameReplaysService: Success

    Note over User,GameReplaysAPI: Tournament Filtering
    User->>GameReplaysView: Select filter (Active/Upcoming)
    GameReplaysView->>GameReplaysViewModel: SelectFilterCommand
    GameReplaysViewModel->>GameReplaysViewModel: UpdateFilteredTournaments()
    GameReplaysViewModel-->>GameReplaysView: Update UI
Loading

Context used:

  • Context from dashboard - Use dedicated constants classes instead of hardcoding constants string, integers or variables in ser... (source)

greptile-apps[bot]

This comment was marked as resolved.

Comment thread GenHub/GenHub.Core/Constants/GameReplaysConstants.cs
/// <param name="comment">The comment content.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Result indicating success or failure.</returns>
Task<OperationResult<bool>> PostCommentAsync(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference between IGameReplaysService.PostCommentAsync() and IGameReplaysCommentService.PostCommentAsync()? They look identical, but the comment is slightly different (only difference being "tournament". What makes it clear that one targets a tournament and one does not? I don't think this is clear enough.

Same goes for GetCommentsAsync() in both files.

Comment thread GenHub/GenHub.Core/Models/GameReplays/GameReplaysTournaments.cs Outdated
/// <summary>
/// Gets or sets the redirect URI.
/// </summary>
public string RedirectUri { get; set; } = string.Empty;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the benefit of setting all these to string.Empty? Is it so bad if this were string? RedirectUri? I guess it won't matter when doing string.IsNullOrEmpty(), but I was just curious why you're so explicit in setting this to string.Empty.

Comment thread GenHub/GenHub.Core/Models/GameReplays/OAuthTokenResponse.cs
Comment thread GenHub/GenHub.Core/Services/GameReplays/GameReplaysService.cs
Comment thread GenHub/GenHub.Core/Services/GameReplays/GameReplaysService.cs Outdated
Comment thread GenHub/GenHub/Infrastructure/DependencyInjection/AppServices.cs Outdated
greptile-apps[bot]

This comment was marked as resolved.

Resolved merge conflicts by combining both GameReplays and Info features:
- NavigationTab.cs: Keep both GameReplays and Info enum values
- MainViewModel.cs: Merge both GameReplaysViewModel and InfoViewModel
- MainView.axaml: Include both DataTemplates and tab buttons
- AppServices.cs: Register all services (GameReplays, UploadThing, ReplayManager, MapManager)
- SharedViewModelModule.cs: Register both GameReplaysViewModel and InfoViewModel
- MainViewModelTests.cs: Update tests to cover both features

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 files reviewed, 9 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +225 to +230
private static bool Initialize(HttpClient client)
{
client.DefaultRequestHeaders.UserAgent.ParseAdd(ApiConstants.DefaultUserAgent);
client.Timeout = TimeSpan.FromSeconds(GameReplaysConstants.DefaultRequestTimeoutSeconds);
return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static method never called - HttpClient timeout and user agent won't be configured

Prompt To Fix With AI
This is a comment left during a code review.
Path: GenHub/GenHub.Core/Services/GameReplays/GameReplaysHttpClient.cs
Line: 225:230

Comment:
static method never called - `HttpClient` timeout and user agent won't be configured

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +19 to +20
// Register HTTP client as transient (creates new instance each time)
services.AddTransient<IGameReplaysHttpClient, GameReplaysHttpClient>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transient HttpClient registration creates new instances on each request, leading to socket exhaustion under load

Suggested change
// Register HTTP client as transient (creates new instance each time)
services.AddTransient<IGameReplaysHttpClient, GameReplaysHttpClient>();
// Use IHttpClientFactory to manage HttpClient lifecycle properly
services.AddHttpClient<IGameReplaysHttpClient, GameReplaysHttpClient>();
Prompt To Fix With AI
This is a comment left during a code review.
Path: GenHub/GenHub.Core/Infrastructure/DependencyInjection/GameReplaysModule.cs
Line: 19:20

Comment:
transient `HttpClient` registration creates new instances on each request, leading to socket exhaustion under load

```suggestion
        // Use IHttpClientFactory to manage HttpClient lifecycle properly
        services.AddHttpClient<IGameReplaysHttpClient, GameReplaysHttpClient>();
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +237 to +238
// TODO: Open authorization URL in browser
_logger.LogInformation("Initiated OAuth login flow");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

browser launch not implemented - OAuth flow won't work without opening the authorization URL in a browser

Prompt To Fix With AI
This is a comment left during a code review.
Path: GenHub/GenHub/Features/GameReplays/ViewModels/GameReplaysViewModel.cs
Line: 237:238

Comment:
browser launch not implemented - OAuth flow won't work without opening the authorization URL in a browser

How can I resolve this? If you propose a fix, please make it concise.

_logger.LogInformation("Copying tournament URL to clipboard: {Url}", tournament.TournamentUrl);

// This is a placeholder for actual clipboard logic
await Task.CompletedTask;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clipboard functionality not implemented - copy URL feature won't work

Prompt To Fix With AI
This is a comment left during a code review.
Path: GenHub/GenHub/Features/GameReplays/ViewModels/GameReplaysViewModel.cs
Line: 323:323

Comment:
clipboard functionality not implemented - copy URL feature won't work

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +154 to +155
// Placeholder for URL opening
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL opening not implemented - view details button won't work

Prompt To Fix With AI
This is a comment left during a code review.
Path: GenHub/GenHub/Features/GameReplays/ViewModels/TournamentItemViewModel.cs
Line: 154:155

Comment:
URL opening not implemented - view details button won't work

How can I resolve this? If you propose a fix, please make it concise.

if (!string.IsNullOrEmpty(TournamentUrl))
{
// Placeholder for clipboard copy
await Task.CompletedTask;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clipboard functionality not implemented - copy link feature won't work

Prompt To Fix With AI
This is a comment left during a code review.
Path: GenHub/GenHub/Features/GameReplays/ViewModels/TournamentItemViewModel.cs
Line: 168:168

Comment:
clipboard functionality not implemented - copy link feature won't work

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +25 to +26
private GameReplaysTournaments? _cachedTournaments;
private System.DateTime _cacheExpiry;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in-memory cache not thread-safe - concurrent requests could corrupt cached data or cause race conditions

Prompt To Fix With AI
This is a comment left during a code review.
Path: GenHub/GenHub.Core/Services/GameReplays/GameReplaysService.cs
Line: 25:26

Comment:
in-memory cache not thread-safe - concurrent requests could corrupt cached data or cause race conditions

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +27 to +28
private OAuthTokenResponse? _currentToken;
private OAuthUserInfo? _currentUser;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in-memory token storage means tokens are lost on app restart - users must re-authenticate every time the app launches

Prompt To Fix With AI
This is a comment left during a code review.
Path: GenHub/GenHub.Core/Services/GameReplays/GameReplaysAuthService.cs
Line: 27:28

Comment:
in-memory token storage means tokens are lost on app restart - users must re-authenticate every time the app launches

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +193 to +196
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(stateBytes);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RandomNumberGenerator.Create() is obsolete - use RandomNumberGenerator.Create() static methods directly

Suggested change
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(stateBytes);
}
var stateBytes = new byte[32];
RandomNumberGenerator.Fill(stateBytes);
Prompt To Fix With AI
This is a comment left during a code review.
Path: GenHub/GenHub.Core/Services/GameReplays/GameReplaysAuthService.cs
Line: 193:196

Comment:
`RandomNumberGenerator.Create()` is obsolete - use `RandomNumberGenerator.Create()` static methods directly

```suggestion
        var stateBytes = new byte[32];
        RandomNumberGenerator.Fill(stateBytes);
```

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants