Skip to content

Commit

Permalink
Add account system. TODO: Finish "friends"
Browse files Browse the repository at this point in the history
I am 100000% sure that this is bugged in multiple ways. But all surface bugs should be fixed.

Resolves #5.
  • Loading branch information
Simyon264 committed May 11, 2024
1 parent 37b86b2 commit 4ffe224
Show file tree
Hide file tree
Showing 28 changed files with 1,361 additions and 33 deletions.
4 changes: 4 additions & 0 deletions Client/Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@
<ProjectReference Include="..\Shared\Shared.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.4" />
</ItemGroup>

</Project>
43 changes: 42 additions & 1 deletion Client/Components/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -1,10 +1,51 @@
@inherits LayoutComponentBase
@using Microsoft.AspNetCore.Components.Authorization
@inherits LayoutComponentBase
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject SecureHttpClient SecureHttpClient

@code
{
private System.Security.Claims.ClaimsPrincipal User;

protected override async Task OnInitializedAsync()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
User = authState.User;
if (User.Identity.IsAuthenticated)
{
var client = SecureHttpClient.GetClient(authState);
var response = await client.PutAsync("api/Account/ensure-account-exists", null);
if (!response.IsSuccessStatusCode)
{
throw new Exception("Failed to ensure account exists");
}
}
}
}

<div id="modal-root">

</div>

<div class="page">
<main class="container my-5">
@if (User.Identity.IsAuthenticated)
{
<p>Hello <strong>@User.Claims.Single(c => c.Type == "name").Value!</strong></p>

<a href="/account/logout" class="btn btn-primary">Logout</a>
<a href="/account/manage" class="btn btn-primary" style="margin-left: 10px">Manage</a>
}
else
{
<a href="/account/login" class="btn btn-primary">Login</a>
}

<br/>
<a href="/leaderboard" class="btn btn-primary" style="margin-top: 10px">Leaderboard</a>
<a href="/" class="btn btn-primary" style="margin-left: 10px; margin-top: 10px">Main page</a>

<hr/>
@Body
</main>
</div>
Expand Down
103 changes: 103 additions & 0 deletions Client/Components/Pages/Account/Manage.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
@page "/account/manage"
@using System.Text.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Shared.Models.Account
@attribute [Authorize]
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject SecureHttpClient SecureHttpClient
@inject NavigationManager NavigationManager

<h3>Manage Account</h3>

@if(ErrorMessage != null)
{
<div class="alert alert-danger" role="alert">
Failed to save changes:
@ErrorMessage
</div>
}
else if (account != null)
{
@if(ChangeSaved)
{
<div class="alert alert-success" role="alert">
Changes saved
</div>
}

<p>Username: @account.Username</p>
<p>Guid: @account.Guid</p>

<h4>Settings</h4>

// Toggle for redacting account
<em>Redacting an account will mean, that only you will be able to see and search for you in replays.</em>
<p>Redact Account: <input type="checkbox" id="redact" @bind="account.Settings.RedactInformation" /></p>

<button class="btn btn-primary" id="save">Save</button>
}
else
{
<p>Account not found (how did you get here?)</p>
}

<script>
$(document).ready(function() {
$("#save").click(function() {
var redact = $("#redact").is(":checked");
var uri = new URL(window.location.href);
uri.searchParams.set("redact", redact);
window.location.href = uri;
});
});
</script>

@code {
private Account account;
private bool ChangeSaved = false;
private string? ErrorMessage;

protected override async Task OnInitializedAsync()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var httpClient = SecureHttpClient.GetClient(authState);
account = await httpClient.GetFromJsonAsync<Account>("api/Account/get-account");

var uri = new Uri(NavigationManager.Uri);
var query = uri.Query;
var queryDictionary = System.Web.HttpUtility.ParseQueryString(query);

// Basically, clicking on "save" will redirect to the same page with the current account settings put into the query string
// these will then be compared to the current account settings and if they are different, the account will be updated
if (queryDictionary.Count > 0)
{
var redact = queryDictionary["redact"];
var changes = 0;
if (redact != null)
{
var valueRedact = bool.Parse(redact);
if (account.Settings.RedactInformation != valueRedact)
{
account.Settings.RedactInformation = valueRedact;
changes++;
}
}

if (changes > 0)
{
var serializedAccount = JsonSerializer.Serialize(account.Settings);
var responseMessage = await httpClient.PostAsync("api/Account/set-account-settings", new StringContent(serializedAccount));
try
{
responseMessage.EnsureSuccessStatusCode();
ChangeSaved = true;
}
catch (HttpRequestException e)
{
ErrorMessage = e.Message + "\n " + await responseMessage.Content.ReadAsStringAsync();
}
}
}
}
}
13 changes: 8 additions & 5 deletions Client/Components/Pages/Home.razor
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@page "/"
@using Microsoft.AspNetCore.Components.Authorization
@using Replay = Shared.Models.Replay
@inject HttpClient Http
@inject NavigationManager NavigationManager
@inject IJSRuntime JSRuntime
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject SecureHttpClient SecureHttpClient
@attribute [StreamRendering]

<PageTitle>Replay viewer</PageTitle>
Expand Down Expand Up @@ -37,8 +37,11 @@

protected override async Task OnInitializedAsync()
{
Replays = await Http.GetFromJsonAsync<List<Replay>>("replays/most-recent");
Count = await Http.GetFromJsonAsync<List<int>>("replays").ContinueWith(x => x.Result.Count);
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var httpClient = SecureHttpClient.GetClient(authState);

Replays = await httpClient.GetFromJsonAsync<List<Replay>>("replays/most-recent");
Count = await httpClient.GetFromJsonAsync<List<int>>("replays").ContinueWith(x => x.Result.Count);
IsLoading = false;
}
}
36 changes: 32 additions & 4 deletions Client/Components/Pages/Leaderboard.razor
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
@page "/leaderboard"
@using System.Net
@using Microsoft.AspNetCore.Components.Authorization
@using Shared
@inject HttpClient Http
@inject SecureHttpClient SecureHttpClient
@inject NavigationManager NavigationManager
@inject AuthenticationStateProvider AuthenticationStateProvider
@attribute [StreamRendering]
@inject IConfiguration Configuration

<PageTitle>Leaderboard</PageTitle>
<h4>Leaderboards</h4>
@if(LeaderboardData == null)
@if(RequestedPrivate)
{
<div class="alert alert-danger" role="alert">
The requested information is private. Please ask the player to make their profile public in order to view this information.
</div>
}
else if(LeaderboardData == null)
{
<p><em>Loading leaderboard data... Please wait...</em></p>
}
Expand Down Expand Up @@ -141,6 +150,7 @@ else
@code{
private bool IsLoading { get; set; } = true;
private LeaderboardData? LeaderboardData { get; set; } = null;
private bool RequestedPrivate { get; set; } = false;

protected override async Task OnInitializedAsync()
{
Expand All @@ -156,14 +166,32 @@ else
timeRange = int.Parse(queryDictionary["timeRange"]);
}
}

var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var http = SecureHttpClient.GetClient(authState);

if (queryDictionary.AllKeys.Contains("username"))
{
LeaderboardData = await Http.GetFromJsonAsync<LeaderboardData>("api/Data/leaderboard?rangeOption=" + timeRange + "&username=" + queryDictionary["username"]);
var response = await http.GetAsync("api/Data/leaderboard?rangeOption=" + timeRange + "&username=" + queryDictionary["username"]);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
RequestedPrivate = true;
IsLoading = false;
return;
}
LeaderboardData = await response.Content.ReadFromJsonAsync<LeaderboardData>();
}
else
{
LeaderboardData = await Http.GetFromJsonAsync<LeaderboardData>("api/Data/leaderboard?rangeOption=" + timeRange);
var response = await http.GetAsync("api/Data/leaderboard?rangeOption=" + timeRange);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
RequestedPrivate = true;
IsLoading = false;
return;
}

LeaderboardData = await response.Content.ReadFromJsonAsync<LeaderboardData>();
}
IsLoading = false;
}
Expand Down
28 changes: 23 additions & 5 deletions Client/Components/Pages/Player.razor
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
@page "/player/{guid}"
@using System.ComponentModel
@using System.Net
@using Humanizer
@using Microsoft.AspNetCore.Components.Authorization
@using Shared
@inject HttpClient Http
@inject NavigationManager NavigationManager
@inject SecureHttpClient SecureHttpClient
@inject AuthenticationStateProvider AuthenticationStateProvider
@attribute [StreamRendering]

<PageTitle>Player info</PageTitle>
Expand All @@ -12,6 +13,10 @@
{
<p>Loading...</p>
}
else if (IsPrivate)
{
<p>This player's data is private. Either log as this player or ask them to make their data public.</p>
}
else if (FailedToLoad)
{
<p>Failed to load player data. Exception: @Exception.Message</p>
Expand Down Expand Up @@ -89,18 +94,31 @@ else

private CollectedPlayerData? playerData;
private bool FailedToLoad { get; set; } = false;
public Exception? Exception { get; set; }
private Exception? Exception { get; set; }
private bool IsPrivate { get; set; } = false;

protected override async Task OnInitializedAsync()
{
HttpResponseMessage response = null;
var httpClient = SecureHttpClient.GetClient(await AuthenticationStateProvider.GetAuthenticationStateAsync());
try
{
playerData = await Http.GetFromJsonAsync<CollectedPlayerData>($"api/Data/player-data?guid={Guid}");
response = await httpClient.GetAsync($"api/Data/player-data?guid={Guid}");
response.EnsureSuccessStatusCode();
playerData = await response.Content.ReadFromJsonAsync<CollectedPlayerData>();
playerData.Characters = playerData.Characters.OrderByDescending(x => x.RoundsPlayed).ToList();
playerData.JobCount = playerData.JobCount.OrderByDescending(x => x.RoundsPlayed).ToList();
}
catch (Exception e)
{
if (response?.StatusCode == HttpStatusCode.Unauthorized)
{
FailedToLoad = true;
IsPrivate = true;
playerData = new();
return;
}

FailedToLoad = true;
Exception = e;
playerData = new();
Expand Down
10 changes: 6 additions & 4 deletions Client/Components/Pages/Search.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
@using Replay = Shared.Models.Replay
@using System.Net
@using System.Diagnostics
@using Microsoft.AspNetCore.Components.Authorization
@using Shared
@inject HttpClient Http
@inject SecureHttpClient SecureHttpClient
@inject NavigationManager NavigationManager
@inject AuthenticationStateProvider AuthenticationStateProvider

<PageTitle>Replay viewer</PageTitle>
<h1>Replay browser for Space Station 14</h1>
<p>Search for replays by using the search bar below</p>
<a href="/" class="btn btn-primary">Back to main page</a>
<hr/>
<SearchBar></SearchBar>
<hr/>
Expand Down Expand Up @@ -114,8 +115,9 @@
// Get mode and query from query string
var uri = new Uri(NavigationManager.Uri);
var query = uri.Query;
var httpClient = SecureHttpClient.GetClient(await AuthenticationStateProvider.GetAuthenticationStateAsync());

var response = await Http.GetAsync("/search" + query);
var response = await httpClient.GetAsync("/search" + query);

if (response.StatusCode == HttpStatusCode.BadRequest)
{
Expand Down Expand Up @@ -145,7 +147,7 @@

if (loadedReplays.SearchMode is SearchMode.PlayerOocName)
{
var playerGuid = await Http.GetAsync("/api/Data/has-profile?username=" + loadedReplays.Query);
var playerGuid = await httpClient.GetAsync("/api/Data/has-profile?username=" + loadedReplays.Query);
ProfileFound = await playerGuid.Content.ReadFromJsonAsync<PlayerData>();
if (ProfileFound.PlayerGuid == Guid.Empty) ProfileFound = null;
}
Expand Down
7 changes: 5 additions & 2 deletions Client/Components/Pages/ViewReplay.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@page "/replay/{id}"
@using Microsoft.AspNetCore.Components.Authorization
@attribute [StreamRendering]
@inject HttpClient Http
@inject SecureHttpClient SecureHttpClient
@inject AuthenticationStateProvider AuthenticationStateProvider

<PageTitle>Replay viewer</PageTitle>
@if (Replay == null && !IsLoading)
Expand All @@ -23,7 +25,8 @@ else

protected override async Task OnInitializedAsync()
{
var response = await Http.GetAsync($"replay/{Id}");
var httpClient = SecureHttpClient.GetClient(await AuthenticationStateProvider.GetAuthenticationStateAsync());
var response = await httpClient.GetAsync($"replay/{Id}");
if (response.IsSuccessStatusCode)
{
Replay = await response.Content.ReadFromJsonAsync<Shared.Models.Replay>();
Expand Down
Loading

0 comments on commit 4ffe224

Please sign in to comment.