Skip to content

Commit

Permalink
Standartized external database access
Browse files Browse the repository at this point in the history
Added GOG autht support
Fixed back to X buttons
  • Loading branch information
Aragas committed May 12, 2023
1 parent f78c6f0 commit 024f19d
Show file tree
Hide file tree
Showing 45 changed files with 1,573 additions and 290 deletions.
3 changes: 2 additions & 1 deletion src/BUTR.Site.NexusMods.Client/Models/DemoUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ namespace BUTR.Site.NexusMods.Client.Models;

public static class DemoUser
{
private static readonly ProfileModel _profile = new(31179975, "Pickysaurus", "demo@demo.com", "https://forums.nexusmods.com/uploads/profile/photo-31179975.png", true, true, ApplicationRoles.User, null, null, true);
private static readonly ProfileModel _profile =
new(31179975, "Pickysaurus", "demo@demo.com", "https://forums.nexusmods.com/uploads/profile/photo-31179975.png", true, true, ApplicationRoles.User, null, null, null, true);
private static readonly List<ModModel> _mods = new()
{
new("Demo Mod 1", 1, ImmutableArray<int>.Empty, ImmutableArray<int>.Empty, ImmutableArray<string>.Empty, ImmutableArray<string>.Empty),
Expand Down
16 changes: 16 additions & 0 deletions src/BUTR.Site.NexusMods.Client/Models/GOGUserInfo2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using BUTR.Site.NexusMods.ServerClient;

namespace BUTR.Site.NexusMods.Client.Models
{
public sealed record GOGUserInfo2
{
public string Url { get; init; }
public string Name { get; init; }

public GOGUserInfo2(GOGUserInfo userInfo)
{
Url = $"https://www.gog.com/u/{userInfo.Username}";
Name = userInfo.Username;
}
};
}
24 changes: 24 additions & 0 deletions src/BUTR.Site.NexusMods.Client/Pages/Basic/Profile.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@inject IUserClient _userClient
@inject IDiscordClient _discordClient
@inject ISteamClient _steamClient
@inject IGOGClient _gogClient

@if (_user is null)
{
Expand Down Expand Up @@ -121,6 +122,26 @@ else
</Column>
</Row>
<Divider/>
<Row>
<Column ColumnSize="@ColumnSize.Is3" TextWeight="@TextWeight.Bold">GOG</Column>
<Column ColumnSize="@ColumnSize.Is9" TextColor="@TextColor.Secondary">
<Anchor Style="text-decoration: none" To="@(_gogUser?.Url ?? "gog-linked-role")" Target="@Target.Blank">
@if (_user.GogUserId is not null && _gogUser?.Name is not null)
{
@(_gogUser.Name)
}
else if (_user.GogUserId is not null && _gogUser?.Name is null)
{
@("Needs Relinking")
}
else
{
@("Not Linked")
}
</Anchor>
</Column>
</Row>
<Divider/>
<Row>
<Column ColumnSize="@ColumnSize.Is3" TextWeight="@TextWeight.Bold">Has Bannerlord</Column>
<Column ColumnSize="@ColumnSize.Is9" TextColor="@TextColor.Secondary">@user.HasBannerlord</Column>
Expand All @@ -131,6 +152,7 @@ else
private ProfileModel? _user;
private DiscordUserInfo2? _discordUser;
private SteamUserInfo2? _steamUser;
private GOGUserInfo2? _gogUser;
private Row? _gutterRow;

protected override async Task OnInitializedAsync()
Expand All @@ -140,6 +162,8 @@ else
_discordUser = discordUserInfo is { Data: { } dataDiscord } ? new DiscordUserInfo2(dataDiscord) : null;
var steamUserInfo = _user?.SteamUserId is not null ? await _steamClient.GetUserInfoAsync() : null;
_steamUser = steamUserInfo is { Data: { } dataSteam } ? new SteamUserInfo2(dataSteam) : null;
var gogUserInfo = _user?.GogUserId is not null ? await _gogClient.GetUserInfoAsync() : null;
_gogUser = gogUserInfo is { Data: { } dataGog } ? new GOGUserInfo2(dataGog) : null;
if (_gutterRow is not null)
_gutterRow.Gutter = (5,5);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@
Padding="@Padding.Is2"
TextWeight="@TextWeight.Bold"
Color="@Color.Primary"
Type="ButtonType.Link"
To="discord://-/"
rel="noreferrer"
rel="noreferrer"
Target="@Target.Blank">
<Figure Margin="@Margin.Is0" Size="@FigureSize.Is32x32">
<FigureImage Margin="Margin.Is0" AlternateText="Discord app icon." Source="images/discord.svg"/>
Expand Down
59 changes: 59 additions & 0 deletions src/BUTR.Site.NexusMods.Client/Pages/GOG/LinkedRole.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@attribute [Authorize]
@page "/gog-linked-role"

@inject IGOGClient _gogClient;
@inject NavigationManager _navigationManager;

<Container>
@if (!string.IsNullOrEmpty(Url))
{
<br/>
<Card>
<CardBody>
<Text>GOG auth is partially supported.</Text>
<br/>
<Text>Please login to GOG by clicking the Login button and paste the url after redirect to here</Text>
<br/>
<Button TextWeight="@TextWeight.Bold"
Color="@Color.Primary"
Type="@ButtonType.Link"
To="@Url"
Target="@Target.Blank">
Login
</Button>
<Divider/>
<Field>
<FieldLabel>Callback Url</FieldLabel>
<TextEdit @bind-Text="@CallbackUrl" Placeholder="https://embed.gog.com/on_login_success?..."></TextEdit>
</Field>
<Button TextWeight="@TextWeight.Bold"
Color="@Color.Primary"
Clicked="Callback">
Confirm
</Button>
</CardBody>
</Card>
}
</Container>

@code {

private string Url = string.Empty;
private string CallbackUrl = string.Empty;

protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();

var response = await _gogClient.GetOAuthUrlAsync();

Url = response.Data.Url;
}

private void Callback()
{
var url = new Uri(CallbackUrl);
_navigationManager.NavigateTo($"/gog-oauth-callback{url.Query}");
}

}
83 changes: 83 additions & 0 deletions src/BUTR.Site.NexusMods.Client/Pages/GOG/OAuthCallback.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
@attribute [Authorize]
@page "/gog-oauth-callback"

@inject IGOGClient _gogClient;
@inject AuthenticationProvider _authenticationProvider;
@inject ILocalStorageService _localStorage;
@inject NavigationManager _navigationManager;

<Container>
<Row Flex="@Flex.JustifyContent.Center">
<Column ColumnSize="@ColumnSize.Is7.OnWidescreen.IsAuto.OnDesktop">
<Card Margin="@Margin.Is5.OnDesktop.Is4.OnTablet.Is3.OnMobile" Border="@Border.Is0.Rounded" Shadow="@Shadow.Small">
<CardBody>
<Heading Padding="@Padding.Is3" Size="@HeadingSize.Is5" TextAlignment="@TextAlignment.Center" TextTransform="@TextTransform.Uppercase" TextWeight="@TextWeight.Bold">@_status</Heading>
<Divider/>
@if (_userInfo is not null)
{
<Row Margin="@Margin.Is2">
<Span><Anchor Style="text-decoration: none" To="@_userInfo.Url" Target="Target.Blank">@_userInfo.Name</Anchor> was successfully linked with the BUTR Site!</Span>
</Row>
}
else
{
<Row Margin="@Margin.Is2">
<Spinner/>
</Row>
}

@if (!string.IsNullOrEmpty(_message))
{
<Row Margin="@Margin.Is2">
<Span>@_message</Span>
</Row>
}

@if (!string.IsNullOrEmpty(_image))
{
<Row Margin="@Margin.Is2">
<FigureImage Margin="Margin.Is0" Source="@_image" AlternateText="A meme image displaying success or failure. Success is Brent Rambo giving a thumbs up. Failure is a horse failing to play with a gymnastics by kinda lying onto it ball and falling."></FigureImage>
</Row>
}
</CardBody>
</Card>
</Column>
</Row>
</Container>

@code {

private const string Success = "images/success.gif";
private const string Failure = "images/failure.gif";

private string _status = string.Empty;
private string _message = string.Empty;
private string _image = string.Empty;
private GOGUserInfo2? _userInfo;

protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();

var queries = _navigationManager.QueryString();
var queryCode = queries["code"];

try
{
await _gogClient.LinkAsync(queryCode);
_ = await _authenticationProvider.ValidateAsync();

var userInfo = await _gogClient.GetUserInfoAsync();
_userInfo = new GOGUserInfo2(userInfo.Data);
_status = "SUCCESS";
_image = Success;
}
catch (ApiException)
{
_status = "FAILURE";
_message = "Failed to link!";
_image = Failure;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@
Padding="@Padding.Is2"
TextWeight="@TextWeight.Bold"
Color="@Color.Primary"
Type="ButtonType.Link"
To="steam://open/main"
rel="noreferrer"
rel="noreferrer"
Target="@Target.Blank">
<Figure Margin="@Margin.Is0" Size="@FigureSize.Is32x32">
<FigureImage Margin="Margin.Is0" AlternateText="Steam app icon." Source="images/steam.svg"/>
Expand Down
1 change: 1 addition & 0 deletions src/BUTR.Site.NexusMods.Client/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public static WebAssemblyHostBuilder CreateHostBuilder(string[] args) => WebAsse
services.AddTransient<IExposedModsClient, ExposedModsClient>(sp => ConfigureClient(sp, (http, opt) => new ExposedModsClient(http, opt)));
services.AddTransient<IDiscordClient, DiscordClient>(sp => ConfigureClient(sp, (http, opt) => new DiscordClient(http, opt)));
services.AddTransient<ISteamClient, SteamClient>(sp => ConfigureClient(sp, (http, opt) => new SteamClient(http, opt)));
services.AddTransient<IGOGClient, GOGClient>(sp => ConfigureClient(sp, (http, opt) => new GOGClient(http, opt)));
services.AddTransient<IStatisticsClient, StatisticsClient>(sp => ConfigureClient(sp, (http, opt) => new StatisticsClient(http, opt)));
services.AddTransient<IQuartzClient, QuartzClient>(sp => ConfigureClient(sp, (http, opt) => new QuartzClient(http, opt)));
services.AddTransient<IRecreateStacktraceClient, RecreateStacktraceClient>(sp => ConfigureClient(sp, (http, opt) => new RecreateStacktraceClient(http, opt)));
Expand Down
2 changes: 2 additions & 0 deletions src/BUTR.Site.NexusMods.Server/Contexts/AppDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.ApplyConfiguration(new CrashScoreInvolvedEntityConfiguration());
modelBuilder.ApplyConfiguration(new NexusModsUserToDiscordEntityConfiguration());
modelBuilder.ApplyConfiguration(new NexusModsUserToSteamEntityConfiguration());
modelBuilder.ApplyConfiguration(new NexusModsUserToGOGEntityConfiguration());
modelBuilder.ApplyConfiguration(new DiscordLinkedRoleTokensEntityConfiguration());
modelBuilder.ApplyConfiguration(new SteamLinkedRoleTokensEntityConfiguration());
modelBuilder.ApplyConfiguration(new GOGLinkedRoleTokensEntityConfiguration());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using BUTR.Site.NexusMods.Server.Models.Database;

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace BUTR.Site.NexusMods.Server.Contexts.Config;

public class GOGLinkedRoleTokensEntityConfiguration : BaseEntityConfiguration<GOGLinkedRoleTokensEntity>
{
protected override void ConfigureModel(EntityTypeBuilder<GOGLinkedRoleTokensEntity> builder)
{
builder.ToTable("gog_linked_role_tokens").HasKey(p => p.UserId).HasName("gog_linked_role_tokens_pkey");
builder.Property(p => p.UserId).HasColumnName("user_id").ValueGeneratedNever().IsRequired();
builder.Property(p => p.RefreshToken).HasColumnName("refresh_token").IsRequired();
builder.Property(p => p.AccessToken).HasColumnName("access_token").IsRequired();
builder.Property(p => p.AccessTokenExpiresAt).HasColumnName("access_token_expires_at").IsRequired();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ protected override void ConfigureModel(EntityTypeBuilder<NexusModsUserToDiscordE
{
builder.ToTable("nexusmods_to_discord").HasKey(p => p.NexusModsUserId).HasName("nexusmods_to_discord_pkey");
builder.Property(p => p.NexusModsUserId).HasColumnName("nexusmods_user_id").ValueGeneratedNever().IsRequired();
builder.Property(p => p.DiscordId).HasColumnName("discord_user_id").IsRequired();
builder.Property(p => p.UserId).HasColumnName("discord_user_id").IsRequired();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using BUTR.Site.NexusMods.Server.Models.Database;

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace BUTR.Site.NexusMods.Server.Contexts.Config
{
public class NexusModsUserToGOGEntityConfiguration : BaseEntityConfiguration<NexusModsUserToGOGEntity>
{
protected override void ConfigureModel(EntityTypeBuilder<NexusModsUserToGOGEntity> builder)
{
builder.ToTable("nexusmods_to_gog").HasKey(p => p.NexusModsUserId).HasName("nexusmods_to_gog_pkey");
builder.Property(p => p.NexusModsUserId).HasColumnName("nexusmods_user_id").ValueGeneratedNever().IsRequired();
builder.Property(p => p.UserId).HasColumnName("gog_user_id").IsRequired();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ protected override void ConfigureModel(EntityTypeBuilder<NexusModsUserToSteamEnt
{
builder.ToTable("nexusmods_to_steam").HasKey(p => p.NexusModsUserId).HasName("nexusmods_to_steam_pkey");
builder.Property(p => p.NexusModsUserId).HasColumnName("nexusmods_user_id").ValueGeneratedNever().IsRequired();
builder.Property(p => p.SteamId).HasColumnName("steam_user_id").IsRequired();
builder.Property(p => p.UserId).HasColumnName("steam_user_id").IsRequired();
}
}
14 changes: 7 additions & 7 deletions src/BUTR.Site.NexusMods.Server/Controllers/DiscordController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ public DiscordController(DiscordClient discordClient, IDiscordStorage discordSto
var userId = HttpContext.GetUserId();
var tokens = HttpContext.GetDiscordTokens();

if (tokens is null)
if (tokens?.Data is null)
return APIResponseError<string>("Unlinked successful!");

if (!await _discordClient.PushMetadata(userId, tokens.UserId, new DiscordOAuthTokens(tokens.AccessToken, tokens.RefreshToken, tokens.ExpiresAt), new Metadata(0, 0, 0, 0)))
if (!await _discordClient.PushMetadata(userId, tokens.ExternalId, tokens.Data, new Metadata(0, 0, 0, 0)))
return APIResponseError<string>("Failed to unlink!");

if (!_discordStorage.Remove(userId, tokens.UserId))
if (!_discordStorage.Remove(userId, tokens.ExternalId))
return APIResponseError<string>("Failed to unlink!");

return APIResponse("Unlinked successful!");
Expand All @@ -100,10 +100,10 @@ public DiscordController(DiscordClient discordClient, IDiscordStorage discordSto
var userId = HttpContext.GetUserId();
var tokens = HttpContext.GetDiscordTokens();

if (tokens is null)
if (tokens?.Data is null)
return APIResponseError<DiscordUserInfo>("Failed to get the token!");

var result = await _discordClient.GetUserInfo(userId, tokens.UserId, new DiscordOAuthTokens(tokens.AccessToken, tokens.RefreshToken, tokens.ExpiresAt));
var result = await _discordClient.GetUserInfo(userId, tokens.ExternalId, tokens.Data);
return APIResponse(result);
}

Expand All @@ -113,7 +113,7 @@ public DiscordController(DiscordClient discordClient, IDiscordStorage discordSto
var userId = HttpContext.GetUserId();
var tokens = HttpContext.GetDiscordTokens();

if (tokens is null)
if (tokens?.Data is null)
return null;

var linkedModsCount = await _dbContext
Expand All @@ -123,7 +123,7 @@ public DiscordController(DiscordClient discordClient, IDiscordStorage discordSto
.Set<NexusModsUserAllowedModuleIdsEntity>()
.CountAsync(y => y.NexusModsUserId == userId);

return await _discordClient.PushMetadata(userId, tokens.UserId, new DiscordOAuthTokens(tokens.AccessToken, tokens.RefreshToken, tokens.ExpiresAt), new Metadata(
return await _discordClient.PushMetadata(userId, tokens.ExternalId, tokens.Data, new Metadata(
1,
role == ApplicationRoles.Moderator ? 1 : 0,
role == ApplicationRoles.Administrator ? 1 : 0,
Expand Down
Loading

0 comments on commit 024f19d

Please sign in to comment.