code reorg
This commit is contained in:
parent
93426986f6
commit
d8c0678462
11 changed files with 154 additions and 22 deletions
|
|
@ -148,7 +148,7 @@ private void ConfigureRootView(MainView rootView)
|
|||
public static async Task PushBlogsPageAsync()
|
||||
{
|
||||
var app = (App)Current!;
|
||||
var mainVm = app.ServiceProvider!.GetRequiredService<MainViewModel>();
|
||||
var mainVm = app.ServiceProvider!.GetRequiredService<BlogsViewModel>();
|
||||
await mainVm.InitializeAsync();
|
||||
await app.PushPageAsync(mainVm);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
using PostIt.Services;
|
||||
using PostIt.ViewModels;
|
||||
using PostIt.Views;
|
||||
using PostIt.Views.Blogs;
|
||||
using PostIt.Views.Commands;
|
||||
using Yavsc.Api.Client;
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ public static class ServiceCollectionHelpers
|
|||
|
||||
// Vues
|
||||
services.AddSingleton<MainView>();
|
||||
services.AddSingleton<MainPage>();
|
||||
services.AddSingleton<BlogsPage>();
|
||||
services.AddSingleton<MainWindow>();
|
||||
|
||||
// SettingsPage is a singleton: there must be one and only one
|
||||
|
|
@ -89,7 +90,7 @@ public static class ServiceCollectionHelpers
|
|||
sessionStatus.Refresh();
|
||||
services.AddSingleton(sessionStatus);
|
||||
services.AddSingleton<SessionStatusBanner>();
|
||||
services.AddSingleton<MainViewModel>();
|
||||
services.AddSingleton<BlogsViewModel>();
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
using PostIt.ViewModels;
|
||||
using PostIt.ViewModels.Commands;
|
||||
using PostIt.Views;
|
||||
using PostIt.Views.Blogs;
|
||||
using PostIt.Views.Commands;
|
||||
|
||||
namespace PostIt;
|
||||
|
|
@ -38,7 +39,7 @@ public class ViewLocator : IDataTemplate
|
|||
var services = app!.ServiceProvider!;
|
||||
return data switch
|
||||
{
|
||||
MainViewModel => services.GetRequiredService<MainPage>(),
|
||||
BlogsViewModel => services.GetRequiredService<BlogsPage>(),
|
||||
Settings => services.GetRequiredService<SettingsPage>(),
|
||||
HomePageViewModel => services.GetRequiredService<HomePage>(),
|
||||
ActivitiesPageViewModel => services.GetRequiredService<ActivitiesPage>(),
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ using PostIt.Helpers;
|
|||
|
||||
namespace PostIt.ViewModels;
|
||||
|
||||
public partial class MainViewModel : ViewModelBase, IActionStatusViewModel
|
||||
public partial class BlogsViewModel : ViewModelBase, IActionStatusViewModel
|
||||
{
|
||||
/// <summary>Window/tab title. Cosmetic — bound by
|
||||
/// <c>MainPage.axaml</c> if at all. Not the post title.</summary>
|
||||
|
|
@ -336,7 +336,7 @@ public partial class MainViewModel : ViewModelBase, IActionStatusViewModel
|
|||
}
|
||||
|
||||
|
||||
public MainViewModel()
|
||||
public BlogsViewModel()
|
||||
{
|
||||
SettingsModel = new Settings();
|
||||
Init(SettingsModel);
|
||||
|
|
@ -396,7 +396,7 @@ public partial class MainViewModel : ViewModelBase, IActionStatusViewModel
|
|||
/// <see cref="BlogApiClient"/>. Production code uses the
|
||||
/// (Settings, BlogApiClient) overload below.
|
||||
/// </summary>
|
||||
public MainViewModel(BlogApiClient blogClient, Settings? settings = null, IServiceProvider? services = null)
|
||||
public BlogsViewModel(BlogApiClient blogClient, Settings? settings = null, IServiceProvider? services = null)
|
||||
{
|
||||
SettingsModel = new Settings();
|
||||
BlogClient = blogClient ?? throw new ArgumentNullException(nameof(blogClient)); ;
|
||||
|
|
@ -5,15 +5,15 @@
|
|||
xmlns:vm="using:PostIt.ViewModels"
|
||||
xmlns:postitControls="using:PostIt.Controls"
|
||||
xmlns:models="using:Yavsc.Blogspot"
|
||||
xmlns:views="using:PostIt.Views"
|
||||
xmlns:views="using:PostIt.Views.Blogs"
|
||||
xmlns:AvaloniaEdit="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
|
||||
mc:Ignorable="d"
|
||||
x:Class="PostIt.Views.MainPage"
|
||||
x:DataType="vm:MainViewModel"
|
||||
x:Class="PostIt.Views.Blogs.BlogsPage"
|
||||
x:DataType="vm:BlogsViewModel"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Design.DataContext>
|
||||
<vm:MainViewModel />
|
||||
<vm:BlogsViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid Margin="12" RowSpacing="12"
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ using System;
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
|
||||
namespace PostIt.Views;
|
||||
namespace PostIt.Views.Blogs;
|
||||
|
||||
public partial class MainPage : ContentPage
|
||||
public partial class BlogsPage : ContentPage
|
||||
{
|
||||
public MainPage()
|
||||
public BlogsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ public partial class MainPage : ContentPage
|
|||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
if (DataContext is ViewModels.MainViewModel vm)
|
||||
if (DataContext is ViewModels.BlogsViewModel vm)
|
||||
{
|
||||
if (!vm.IsLoaded)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
xmlns:views="using:PostIt.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="PostIt.Views.MainView"
|
||||
x:DataType="vm:MainViewModel">
|
||||
x:DataType="vm:HomePageViewModel">
|
||||
<Design.DataContext>
|
||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
||||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
|
||||
<vm:MainViewModel />
|
||||
<vm:HomePageViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<DockPanel LastChildFill="True">
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public partial class MainView : UserControl
|
|||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnDataContextChanged(e);
|
||||
if (DataContext is ViewModels.MainViewModel vm)
|
||||
if (DataContext is ViewModels.BlogsViewModel vm)
|
||||
{
|
||||
if (!vm.IsLoaded)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
<!-- Yavsc.Org.Tests-specific versions -->
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.11" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.11" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.11" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
129
src/Yavsc.Org.Tests/Services/FileSystemAuthManagerTests.cs
Normal file
129
src/Yavsc.Org.Tests/Services/FileSystemAuthManagerTests.cs
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Access;
|
||||
using Yavsc.Models.Relationship;
|
||||
using Yavsc.Services;
|
||||
|
||||
namespace Yavsc.Org.Tests.Services;
|
||||
|
||||
public class FileSystemAuthManagerTests
|
||||
{
|
||||
[Fact]
|
||||
public void SetAccess_creates_acl_row_with_owner_path_and_flags()
|
||||
{
|
||||
using var scope = CreateScope();
|
||||
scope.Service.SetAccess(scope.Circle.Id, "alice/documents/report.txt", FileAccessRight.Read | FileAccessRight.Write);
|
||||
|
||||
var row = scope.Db.CircleAuthorizationToFile.Single();
|
||||
|
||||
Assert.Equal(scope.Circle.Id, row.CircleId);
|
||||
Assert.Equal("alice/documents/report.txt", row.Path);
|
||||
Assert.Equal("alice", row.OwnerId);
|
||||
Assert.Equal(FileAccessRight.Read | FileAccessRight.Write, row.Access);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetAccess_updates_existing_acl_row_without_duplicates()
|
||||
{
|
||||
using var scope = CreateScope();
|
||||
|
||||
scope.Service.SetAccess(scope.Circle.Id, "alice/documents/report.txt", FileAccessRight.Read);
|
||||
scope.Service.SetAccess(scope.Circle.Id, "alice/documents/report.txt", FileAccessRight.Write);
|
||||
|
||||
var rows = scope.Db.CircleAuthorizationToFile.ToList();
|
||||
|
||||
Assert.Single(rows);
|
||||
Assert.Equal(FileAccessRight.Write, rows[0].Access);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetAccess_none_removes_existing_acl_row()
|
||||
{
|
||||
using var scope = CreateScope();
|
||||
|
||||
scope.Service.SetAccess(scope.Circle.Id, "alice/documents/report.txt", FileAccessRight.Read);
|
||||
scope.Service.SetAccess(scope.Circle.Id, "alice/documents/report.txt", FileAccessRight.None);
|
||||
|
||||
Assert.Empty(scope.Db.CircleAuthorizationToFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetAccess_ignores_unknown_owner_prefix()
|
||||
{
|
||||
using var scope = CreateScope();
|
||||
|
||||
scope.Service.SetAccess(scope.Circle.Id, "unknown/documents/report.txt", FileAccessRight.Read);
|
||||
|
||||
Assert.Empty(scope.Db.CircleAuthorizationToFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deleting_circle_cascades_file_acl_rows()
|
||||
{
|
||||
using var scope = CreateScope();
|
||||
|
||||
scope.Service.SetAccess(scope.Circle.Id, "alice/documents/report.txt", FileAccessRight.Read);
|
||||
scope.Db.Circle.Remove(scope.Circle);
|
||||
scope.Db.SaveChanges();
|
||||
|
||||
Assert.Empty(scope.Db.CircleAuthorizationToFile);
|
||||
}
|
||||
|
||||
private static TestScope CreateScope()
|
||||
{
|
||||
var connection = new SqliteConnection("Data Source=:memory:");
|
||||
connection.Open();
|
||||
|
||||
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
||||
.UseSqlite(connection)
|
||||
.Options;
|
||||
|
||||
var db = new ApplicationDbContext(options);
|
||||
db.Database.EnsureCreated();
|
||||
|
||||
db.Users.Add(new ApplicationUser
|
||||
{
|
||||
Id = "alice",
|
||||
UserName = "alice",
|
||||
Email = "alice@example.test"
|
||||
});
|
||||
db.SaveChanges();
|
||||
|
||||
var circle = new Circle
|
||||
{
|
||||
OwnerId = "alice",
|
||||
Name = "shared",
|
||||
Public = false
|
||||
};
|
||||
|
||||
db.Circle.Add(circle);
|
||||
db.SaveChanges();
|
||||
|
||||
var service = new FileSystemAuthManager(db, Options.Create(new SiteSettings()));
|
||||
return new TestScope(connection, db, service, circle);
|
||||
}
|
||||
|
||||
private sealed class TestScope : IDisposable
|
||||
{
|
||||
public TestScope(SqliteConnection connection, ApplicationDbContext db, FileSystemAuthManager service, Circle circle)
|
||||
{
|
||||
Connection = connection;
|
||||
Db = db;
|
||||
Service = service;
|
||||
Circle = circle;
|
||||
}
|
||||
|
||||
public SqliteConnection Connection { get; }
|
||||
public ApplicationDbContext Db { get; }
|
||||
public FileSystemAuthManager Service { get; }
|
||||
public Circle Circle { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Db.Dispose();
|
||||
Connection.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +53,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||
</ItemGroup>
|
||||
<!--
|
||||
MapStaticAssets() in the production pipeline resolves
|
||||
|
|
@ -86,4 +87,4 @@
|
|||
</ItemGroup>
|
||||
<Copy SourceFiles="@(_YavscOrgStaticAssetsFiles)" DestinationFolder="$(OutDir)" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue