Skip to content
This repository has been archived by the owner on Mar 3, 2024. It is now read-only.

Commit

Permalink
move AssetCatalog to using a local database
Browse files Browse the repository at this point in the history
  • Loading branch information
parzivail committed Aug 4, 2021
1 parent 863d9d2 commit 8a62d33
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 73 deletions.
1 change: 1 addition & 0 deletions AssetCatalog/AssetCatalog.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ItemGroup>
<PackageReference Include="FirebaseAuthentication.net" Version="4.0.0-alpha.2" />
<PackageReference Include="Google.Cloud.Firestore" Version="2.3.0" />
<PackageReference Include="LiteDB" Version="5.0.11" />
<PackageReference Include="ModernWpfUI" Version="0.9.3" />
<PackageReference Include="OpenTK.GLWpfControl" Version="4.1.0" />
</ItemGroup>
Expand Down
58 changes: 29 additions & 29 deletions AssetCatalog/ForgeCatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,7 @@ public class ForgeCatalog : ICatalogApp, INotifyPropertyChanged
private string _status;
private ulong _uidFilter;

private ForgeCatalog()
{
}

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

private bool EntryMatchesFilter(Entry arg)
{
if (_uidFilter != 0 && arg.Uid != _uidFilter)
return false;

var catalogEntry = CatalogDb.Get(arg.Uid);

if (!string.IsNullOrWhiteSpace(_nameFilter) && !catalogEntry.Name.Contains(_nameFilter))
return false;

if (_filteredStatuses.Length != 0 && !_filteredStatuses.Contains(catalogEntry.Status))
return false;

if (_filteredCategories.Length != 0 && !_filteredCategories.Contains(catalogEntry.Category))
return false;

return true;
}
public event PropertyChangedEventHandler PropertyChanged;

public string Status
{
Expand All @@ -60,7 +34,7 @@ public string Status
}
}

public ICatalogDb CatalogDb { get; } = new FirestoreCatalogDb();
public ICatalogDb CatalogDb { get; } = new LocalCatalogDb();

public Forge OpenedForge
{
Expand Down Expand Up @@ -101,6 +75,10 @@ private set
/// <inheritdoc />
public IEnumerable<Entry> FilteredEntries => OpenedForge == null ? Array.Empty<Entry>() : OpenedForge.Entries.Where(EntryMatchesFilter);

private ForgeCatalog()
{
}

public void OpenForge(Stream stream)
{
var forgeStream = new BinaryReader(stream);
Expand All @@ -122,6 +100,28 @@ public void OnCatalogChanged()
OnPropertyChanged(nameof(FilteredEntries));
}

public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

private bool EntryMatchesFilter(Entry arg)
{
if (_uidFilter != 0 && arg.Uid != _uidFilter)
return false;

var catalogEntry = CatalogDb.Get(arg.Uid);

if (!string.IsNullOrWhiteSpace(_nameFilter) && !catalogEntry.Name.Contains(_nameFilter))
return false;

if (_filteredStatuses.Length != 0 && !_filteredStatuses.Contains(catalogEntry.Status))
return false;

if (_filteredCategories.Length != 0 && !_filteredCategories.Contains(catalogEntry.Category))
return false;

return true;
}
}
}
11 changes: 7 additions & 4 deletions AssetCatalog/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,14 @@ public MainWindow()

private async void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
var result = await LoginDialog.ShowAsync();
if (ForgeCatalog.Instance.CatalogDb.NeedsAuth())
{
var result = await LoginDialog.ShowAsync();

if (result != ContentDialogResult.Primary)
// Cancelled login
Environment.Exit(0);
if (result != ContentDialogResult.Primary)
// Cancelled login
Environment.Exit(0);
}

await ForgeCatalog.Instance.CatalogDb.Connect(LoginEmail.Text, LoginPassword.Password);
}
Expand Down
89 changes: 49 additions & 40 deletions AssetCatalog/Model/FirestoreCatalogDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,10 @@ public class FirestoreCatalogDb : ICatalogDb
private QuerySnapshot _catalog;
private FirestoreDb _db;

private static async Task<FirestoreDb> CreateFirestoreDbWithEmailAuthentication(string emailAddress, string password)
/// <inheritdoc />
public bool NeedsAuth()
{
// Create a custom authentication mechanism for Email/Password authentication
// If the authentication is successful, we will get back the current authentication token and the refresh token
// The authentication expires every hour, so we need to use the obtained refresh token to obtain a new authentication token as the previous one expires

// This requires the following ruleset or similar to be applied to the Firestore:
/*
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
*/

var authProvider = new FirebaseAuthClient(new FirebaseAuthConfig
{
ApiKey = "AIzaSyCcV55HIDDdeIp8SP5aki-eX4FfJtpyWB4",
AuthDomain = "parzi-rainbowforge.firebaseapp.com",
Providers = new FirebaseAuthProvider[] {new EmailProvider()}
});
var auth = await authProvider.SignInWithEmailAndPasswordAsync(emailAddress, password);

var callCredentials = CallCredentials.FromInterceptor(async (context, metadata) =>
{
var token = await auth.User.GetIdTokenAsync();
metadata.Clear();
metadata.Add("Authorization", $"Bearer {token}");
});
var credentials = ChannelCredentials.Create(new SslCredentials(), callCredentials);

var client = await new FirestoreClientBuilder
{
ChannelCredentials = credentials
}.BuildAsync();

return await FirestoreDb.CreateAsync("parzi-rainbowforge", client);
return true;
}

/// <inheritdoc />
Expand All @@ -77,6 +40,7 @@ public CatalogEntry Get(ulong uid)
if (_catalog == null)
return new CatalogEntry
{
Uid = uid,
Status = CatalogEntryStatus.Incomplete,
Category = CatalogAssetCategory.Uncategorized
};
Expand All @@ -86,6 +50,7 @@ public CatalogEntry Get(ulong uid)
if (document == null)
return new CatalogEntry
{
Uid = uid,
Status = CatalogEntryStatus.Incomplete,
Category = CatalogAssetCategory.Uncategorized
};
Expand All @@ -100,6 +65,7 @@ public CatalogEntry Get(ulong uid)

return new CatalogEntry
{
Uid = uid,
Name = name,
Category = category,
Status = status,
Expand All @@ -122,5 +88,48 @@ public void Put(ulong uid, CatalogEntry entry)

_db.Collection("catalog").Document(uid.ToString()).SetAsync(doc);
}

private static async Task<FirestoreDb> CreateFirestoreDbWithEmailAuthentication(string emailAddress, string password)
{
// Create a custom authentication mechanism for Email/Password authentication
// If the authentication is successful, we will get back the current authentication token and the refresh token
// The authentication expires every hour, so we need to use the obtained refresh token to obtain a new authentication token as the previous one expires

// This requires the following ruleset or similar to be applied to the Firestore:
/*
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
*/

var authProvider = new FirebaseAuthClient(new FirebaseAuthConfig
{
ApiKey = "AIzaSyCcV55HIDDdeIp8SP5aki-eX4FfJtpyWB4",
AuthDomain = "parzi-rainbowforge.firebaseapp.com",
Providers = new FirebaseAuthProvider[] {new EmailProvider()}
});
var auth = await authProvider.SignInWithEmailAndPasswordAsync(emailAddress, password);

var callCredentials = CallCredentials.FromInterceptor(async (context, metadata) =>
{
var token = await auth.User.GetIdTokenAsync();
metadata.Clear();
metadata.Add("Authorization", $"Bearer {token}");
});
var credentials = ChannelCredentials.Create(new SslCredentials(), callCredentials);

var client = await new FirestoreClientBuilder
{
ChannelCredentials = credentials
}.BuildAsync();

return await FirestoreDb.CreateAsync("parzi-rainbowforge", client);
}
}
}
4 changes: 4 additions & 0 deletions AssetCatalog/Model/ICatalogDb.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System.ComponentModel;
using System.Threading.Tasks;
using AssetCatalog.Converters;
using LiteDB;

namespace AssetCatalog.Model
{
public interface ICatalogDb
{
public bool NeedsAuth();
public Task Connect(string email, string password);

public CatalogEntry Get(ulong uid);
Expand All @@ -14,6 +16,8 @@ public interface ICatalogDb

public class CatalogEntry
{
[BsonId(false)] public ulong Uid { get; set; }

public CatalogEntryStatus Status { get; set; } = CatalogEntryStatus.PartiallyComplete;
public CatalogAssetCategory Category { get; set; } = CatalogAssetCategory.Uncategorized;

Expand Down
50 changes: 50 additions & 0 deletions AssetCatalog/Model/LocalCatalogDb.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Threading.Tasks;
using LiteDB;

namespace AssetCatalog.Model
{
public class LocalCatalogDb : ICatalogDb
{
private LiteDatabase _db;
private ILiteCollection<CatalogEntry> _catalog;

/// <inheritdoc />
public bool NeedsAuth()
{
return false;
}

/// <inheritdoc />
public Task Connect(string email, string password)
{
_db = new LiteDatabase("catalog.db");
_catalog = _db.GetCollection<CatalogEntry>("catalog");
_catalog.EnsureIndex(entry => entry.Uid);

return Task.CompletedTask;
}

/// <inheritdoc />
public CatalogEntry Get(ulong uid)
{
var entry = _catalog.FindById(uid);

if (entry != null)
return entry;

return new CatalogEntry
{
Uid = uid,
Status = CatalogEntryStatus.Incomplete,
Category = CatalogAssetCategory.Uncategorized
};
}

/// <inheritdoc />
public void Put(ulong uid, CatalogEntry entry)
{
_catalog.Upsert(uid, entry);
ForgeCatalog.Instance.OnCatalogChanged();
}
}
}

0 comments on commit 8a62d33

Please sign in to comment.