diff --git a/src/PostIt.Tests/BearerScopeTests.cs b/src/PostIt.Tests/BearerScopeTests.cs index 1f47a176..fbccb606 100644 --- a/src/PostIt.Tests/BearerScopeTests.cs +++ b/src/PostIt.Tests/BearerScopeTests.cs @@ -97,7 +97,7 @@ public class BearerScopeTests // CapturingHttpHandler is the assertion point. It // records the first request's Authorization header and // returns 200 with an empty array (BlogApiClient - // deserialises to List). + // deserialises to List). var captured = new CapturingHttpHandler(); var client = new YavscApiClient( settings, diff --git a/src/PostIt.Tests/BlogApiTestFakes.cs b/src/PostIt.Tests/BlogApiTestFakes.cs index 3f8b98b0..4b541e42 100644 --- a/src/PostIt.Tests/BlogApiTestFakes.cs +++ b/src/PostIt.Tests/BlogApiTestFakes.cs @@ -18,7 +18,7 @@ internal sealed class CallRecorder /// Test fake that records every CallAsync invocation /// and answers them with a canned sequence: the first call gets -/// a server-issued BlogPost (Id=42), the second call gets a +/// a server-issued BlogPostDto (Id=42), the second call gets a /// single-element list containing that post. Used by the ViewModel /// tests and the headless UI test to capture exactly what the /// Save button posts to the server. @@ -44,20 +44,20 @@ internal sealed class RecordingYavscApiClient : YavscApiClient public override Task CallAsync(HttpMethod method, string path, object? body = null, CancellationToken ct = default) { _recorder.Calls.Add((method, path, body)); - // BlogPost? boxes to BlogPost at runtime, so we test the - // non-nullable type — typeof(BlogPost?) is a C# error + // BlogPostDto? boxes to BlogPostDto at runtime, so we test the + // non-nullable type — typeof(BlogPostDto?) is a C# error // (CS8639: "typeof cannot be used on a nullable reference // type"). - if (typeof(T) == typeof(BlogPost)) - return Task.FromResult((T)(object)new BlogPost + if (typeof(T) == typeof(BlogPostDto)) + return Task.FromResult((T)(object)new BlogPostDto { Id = 42, Title = "Mon premier billet", AuthorId = "tester", Article = "Contenu du billet de test.", }); - if (typeof(T) == typeof(List)) - return Task.FromResult((T)(object)new List + if (typeof(T) == typeof(List)) + return Task.FromResult((T)(object)new List { new() { Id = 42, Title = "Mon premier billet" } }); diff --git a/src/PostIt.Tests/MainPageSaveTests.cs b/src/PostIt.Tests/MainPageSaveTests.cs index 350a71f1..b6bf963a 100644 --- a/src/PostIt.Tests/MainPageSaveTests.cs +++ b/src/PostIt.Tests/MainPageSaveTests.cs @@ -25,7 +25,7 @@ namespace PostIt.Tests; /// in which a brand-new post can be created), the binding has /// no target and the user's keystrokes are silently dropped. /// Clicking "Save" then routes to the VM branch -/// if (SelectedPost is null) { new BlogPost { Title = string.Empty, ... } } +/// if (SelectedPost is null) { new BlogPostDto { Title = string.Empty, ... } } /// which the controller rejects with 400 "The Title field is /// required." This test fails on that branch today and will /// pass once the VM owns a dedicated Title/Article @@ -77,14 +77,14 @@ public class MainPageSaveTests // we inspect the recorder. await Task.Delay(200); - // Assert: the first POST to "blog" carried a BlogPost + // Assert: the first POST to "blog" carried a BlogPostDto // whose Title is exactly what the user typed. The bug // fails this assertion with Title == string.Empty. Assert.NotEmpty(recorder.Calls); var (method, path, body) = recorder.FirstCall; Assert.Equal(HttpMethod.Post, method); Assert.Equal("blog", path); - var sent = Assert.IsType(body); + var sent = Assert.IsType(body); Assert.Equal(typed, sent.Title); } } diff --git a/src/PostIt.Tests/PostItViewModelTests.cs b/src/PostIt.Tests/PostItViewModelTests.cs index b964a18e..2dee4604 100644 --- a/src/PostIt.Tests/PostItViewModelTests.cs +++ b/src/PostIt.Tests/PostItViewModelTests.cs @@ -18,9 +18,9 @@ public class PostItViewModelTests var blog = new BlogApiClient(fakeApi, "http://localhost/"); var viewModel = new MainPageViewModel(blog); - viewModel.Posts.Add(new BlogPost { Id = 1, Title = "First post", Article = "Hello world", AuthorId = "alice" }); - viewModel.Posts.Add(new BlogPost { Id = 2, Title = "Second post", Article = "Nothing here", AuthorId = "bob" }); - viewModel.Posts.Add(new BlogPost { Id = 3, Title = "Third post", Article = "Search me", AuthorId = "carol" }); + viewModel.Posts.Add(new BlogPostDto { Id = 1, Title = "First post", Article = "Hello world", AuthorId = "alice" }); + viewModel.Posts.Add(new BlogPostDto { Id = 2, Title = "Second post", Article = "Nothing here", AuthorId = "bob" }); + viewModel.Posts.Add(new BlogPostDto { Id = 3, Title = "Third post", Article = "Search me", AuthorId = "carol" }); viewModel.SearchText = "search"; viewModel.SearchCommand.Execute(null); @@ -41,7 +41,7 @@ public class PostItViewModelTests // The new BlogApiClient delegates transport to YavscApiClient. // We feed it a fake YavscApiClient that returns the expected // list straight from CallAsync. - var expected = new List + var expected = new List { new() { Id = 1, Title = "Hello" }, new() { Id = 2, Title = "World" } @@ -77,8 +77,8 @@ public class PostItViewModelTests /// Test fake that hands back a canned list of posts from any CallAsync. private sealed class StubYavscApiClient : YavscApiClient { - private readonly List _posts; - public StubYavscApiClient(List posts) + private readonly List _posts; + public StubYavscApiClient(List posts) : base( new Settings { @@ -98,7 +98,7 @@ public class PostItViewModelTests { // The canned fake only knows about a list of posts; the // BlogApiClient test asserts on that list directly. - if (typeof(T) == typeof(List)) + if (typeof(T) == typeof(List)) return Task.FromResult((T)(object)_posts); return Task.FromResult(default(T)!); } diff --git a/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs b/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs index ddf6a732..d907606f 100644 --- a/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs @@ -25,7 +25,7 @@ public partial class MainPageViewModel : ViewModelBase /// previous "{Binding SelectedPost.Title}" binding, the user's /// keystrokes were silently dropped whenever /// SelectedPost was null, which made the editor a trap - /// and caused Save to POST a BlogPost with an empty + /// and caused Save to POST a BlogPostDto with an empty /// title — hence the 400 "The Title field is required". [ObservableProperty] public partial string DraftTitle { get; set; } @@ -47,13 +47,13 @@ public partial class MainPageViewModel : ViewModelBase public partial string SearchText { get; set; } [ObservableProperty] - public partial ObservableCollection Posts { get; set; } + public partial ObservableCollection Posts { get; set; } [ObservableProperty] - public partial ObservableCollection FilteredPosts { get; set; } + public partial ObservableCollection FilteredPosts { get; set; } [ObservableProperty] - public partial BlogPost? SelectedPost { get; set; } + public partial BlogPostDto? SelectedPost { get; set; } [ObservableProperty] public partial bool IsBusy { get; set; } @@ -83,8 +83,8 @@ public partial class MainPageViewModel : ViewModelBase private void Init(Settings? settings) { SearchText = string.Empty; - Posts = new ObservableCollection(); - FilteredPosts = new ObservableCollection(); + Posts = new ObservableCollection(); + FilteredPosts = new ObservableCollection(); SelectedPost = null; IsBusy = false; StatusMessage = "Ready"; @@ -120,7 +120,7 @@ public partial class MainPageViewModel : ViewModelBase partial void OnSearchTextChanged(string value) => ApplyFilter(); - partial void OnSelectedPostChanged(BlogPost? value) + partial void OnSelectedPostChanged(BlogPostDto? value) { // Mirror the selection into the editor buffer so the // XAML-bound TextBox/TextEditor show the right content @@ -177,7 +177,7 @@ public partial class MainPageViewModel : ViewModelBase await ExecuteAsync(async () => { - // Build a fresh BlogPost from the editor buffer on + // Build a fresh BlogPostDto from the editor buffer on // every Save — we no longer mutate SelectedPost in // place. The previous behaviour copied the buffer // (which was a no-op when SelectedPost was null) @@ -189,7 +189,7 @@ public partial class MainPageViewModel : ViewModelBase // the update path. if (SelectedPost is null || SelectedPost.Id == 0) { - var draft = new BlogPost + var draft = new BlogPostDto { Title = DraftTitle, Article = DraftArticle ?? string.Empty, @@ -205,7 +205,7 @@ public partial class MainPageViewModel : ViewModelBase } else { - var update = new BlogPost + var update = new BlogPostDto { Id = SelectedPost.Id, AuthorId = SelectedPost.AuthorId, @@ -327,7 +327,7 @@ public partial class MainPageViewModel : ViewModelBase /// because the navigation surface (NavigationPage) lives /// in the View layer. /// - public event EventHandler? ManageAclRequested; + public event EventHandler? ManageAclRequested; [RelayCommand(CanExecute = nameof(CanManageAcl))] public void ManageAcl() diff --git a/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs b/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs index 476a6b9a..68b96b7c 100644 --- a/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs @@ -34,7 +34,7 @@ public partial class PostAclDialogViewModel : ViewModelBase /// The post whose ACL is being edited. Set by the /// caller (MainPage) when opening the dialog. - public BlogPost Post { get; } + public BlogPostDto Post { get; } [ObservableProperty] public partial ObservableCollection MyCircles { get; set; } = new(); @@ -52,7 +52,7 @@ public partial class PostAclDialogViewModel : ViewModelBase public partial string StatusMessage { get; set; } = string.Empty; public PostAclDialogViewModel( - BlogPost post, + BlogPostDto post, BlogAclApiClient aclClient, CircleApiClient circleClient) { diff --git a/src/PostIt/PostIt/Views/MainPage.axaml b/src/PostIt/PostIt/Views/MainPage.axaml index 1686feef..c6e7fb10 100644 --- a/src/PostIt/PostIt/Views/MainPage.axaml +++ b/src/PostIt/PostIt/Views/MainPage.axaml @@ -53,7 +53,7 @@ - + diff --git a/src/PostIt/PostIt/Views/MainPage.axaml.cs b/src/PostIt/PostIt/Views/MainPage.axaml.cs index c39bf2ff..bec3e86c 100644 --- a/src/PostIt/PostIt/Views/MainPage.axaml.cs +++ b/src/PostIt/PostIt/Views/MainPage.axaml.cs @@ -37,7 +37,7 @@ public partial class MainPage : ContentPage } } - void OnManageAclRequested(object? sender, BlogPost post) + void OnManageAclRequested(object? sender, BlogPostDto post) { var app = Application.Current as App; var services = app?.ServiceProvider; diff --git a/src/PostIt/PostIt/Views/PostAclDialog.axaml.cs b/src/PostIt/PostIt/Views/PostAclDialog.axaml.cs index c632378a..c52b6f63 100644 --- a/src/PostIt/PostIt/Views/PostAclDialog.axaml.cs +++ b/src/PostIt/PostIt/Views/PostAclDialog.axaml.cs @@ -22,7 +22,7 @@ public partial class PostAclDialog : ContentPage InitializeComponent(); } - public PostAclDialog(BlogPost post, BlogAclApiClient aclClient, CircleApiClient circleClient) + public PostAclDialog(BlogPostDto post, BlogAclApiClient aclClient, CircleApiClient circleClient) { InitializeComponent(); DataContext = new PostAclDialogViewModel(post, aclClient, circleClient); diff --git a/src/Yavsc.Abstract/Blogspot/BlogPost.cs b/src/Yavsc.Abstract/Blogspot/BlogPost.cs index 854aa29f..5e397245 100644 --- a/src/Yavsc.Abstract/Blogspot/BlogPost.cs +++ b/src/Yavsc.Abstract/Blogspot/BlogPost.cs @@ -4,7 +4,7 @@ using Yavsc.Abstract.Identity.Security; namespace Yavsc.Blogspot; -public class BlogPost : IBlogPost +public class BlogPostDto : IBlogPost { public string AuthorId { get; set; } diff --git a/src/Yavsc.Api.Client/BlogAclApiClient.cs b/src/Yavsc.Api.Client/BlogAclApiClient.cs index 71263ca4..4cb19f9a 100644 --- a/src/Yavsc.Api.Client/BlogAclApiClient.cs +++ b/src/Yavsc.Api.Client/BlogAclApiClient.cs @@ -11,7 +11,7 @@ namespace Yavsc.Api.Client; /// HTTP client for /api/blogacl on the Yavsc Blogs server. /// /// Each grants a single -/// Circle access to a single BlogPost. The server +/// Circle access to a single BlogPostDto. The server /// scopes every endpoint to the caller's uid: only the author of /// the underlying blog post can list, create, modify, or delete /// its ACL entries. diff --git a/src/Yavsc.Api.Client/BlogApiClient.cs b/src/Yavsc.Api.Client/BlogApiClient.cs index 537124a7..611c892f 100644 --- a/src/Yavsc.Api.Client/BlogApiClient.cs +++ b/src/Yavsc.Api.Client/BlogApiClient.cs @@ -53,19 +53,19 @@ public sealed class BlogApiClient _pathPrefix = pathPrefix?.TrimStart('/') ?? DefaultPathPrefix; } - public Task> GetPostsAsync(int start = 0, int take = 25, CancellationToken ct = default) - => _api.CallAsync>( + public Task> GetPostsAsync(int start = 0, int take = 25, CancellationToken ct = default) + => _api.CallAsync>( HttpMethod.Get, $"{_pathPrefix}?start={start}&take={take}", ct: ct); - public Task GetPostAsync(long id, CancellationToken ct = default) - => _api.CallAsync(HttpMethod.Get, $"{_pathPrefix}/{id}", ct: ct); + public Task GetPostAsync(long id, CancellationToken ct = default) + => _api.CallAsync(HttpMethod.Get, $"{_pathPrefix}/{id}", ct: ct); - public Task CreatePostAsync(BlogPost post, CancellationToken ct = default) - => _api.CallAsync(HttpMethod.Post, _pathPrefix, body: post, ct: ct); + public Task CreatePostAsync(BlogPostDto post, CancellationToken ct = default) + => _api.CallAsync(HttpMethod.Post, _pathPrefix, body: post, ct: ct); - public Task UpdatePostAsync(long id, BlogPost post, CancellationToken ct = default) + public Task UpdatePostAsync(long id, BlogPostDto post, CancellationToken ct = default) => _api.CallAsync(HttpMethod.Put, $"{_pathPrefix}/{id}", body: post, ct: ct); public Task DeletePostAsync(long id, CancellationToken ct = default)