From 7363d0c1287a8591e6f2794c6f92024da80da8fe Mon Sep 17 00:00:00 2001 From: Nick Beckley Date: Fri, 19 Jun 2026 14:08:46 +0100 Subject: [PATCH] Scene inspector character attribute fix --- PlotLine/Controllers/ScenesController.cs | 23 +++++++++++++++++++ PlotLine/Data/Repositories.cs | 8 +++++++ PlotLine/Services/CoreServices.cs | 1 + .../069_CharacterAttributeEventsByScene.sql | 19 +++++++++++++++ PlotLine/Views/Scenes/_SceneInspector.cshtml | 5 ++++ 5 files changed, 56 insertions(+) create mode 100644 PlotLine/Sql/069_CharacterAttributeEventsByScene.sql diff --git a/PlotLine/Controllers/ScenesController.cs b/PlotLine/Controllers/ScenesController.cs index c45df15..21cfab9 100644 --- a/PlotLine/Controllers/ScenesController.cs +++ b/PlotLine/Controllers/ScenesController.cs @@ -286,6 +286,29 @@ public sealed class ScenesController( [ValidateAntiForgeryToken] public async Task AddCharacterAttributeEvent(CharacterAttributeEventCreateViewModel model) { + if (model.SceneID <= 0) + { + return BadRequest(); + } + + if (model.CharacterID <= 0) + { + TempData["CharacterAttributeAddError"] = "Choose a character before adding an attribute."; + return RedirectForScene(model.SceneID, model.ReturnProjectID, model.ReturnBookID); + } + + if (model.CharacterAttributeTypeID <= 0) + { + TempData["CharacterAttributeAddError"] = "Choose an attribute type before saving."; + return RedirectForScene(model.SceneID, model.ReturnProjectID, model.ReturnBookID); + } + + if (string.IsNullOrWhiteSpace(model.AttributeValue)) + { + TempData["CharacterAttributeAddError"] = "Enter an attribute value before saving."; + return RedirectForScene(model.SceneID, model.ReturnProjectID, model.ReturnBookID); + } + await characters.AddAttributeEventAsync(model); return RedirectForScene(model.SceneID, model.ReturnProjectID, model.ReturnBookID); } diff --git a/PlotLine/Data/Repositories.cs b/PlotLine/Data/Repositories.cs index 7323c36..6408ebe 100644 --- a/PlotLine/Data/Repositories.cs +++ b/PlotLine/Data/Repositories.cs @@ -174,6 +174,7 @@ public interface ICharacterRepository Task> ListSceneCharactersAsync(int sceneId); Task SaveSceneCharacterAsync(SceneCharacter sceneCharacter); Task DeleteSceneCharacterAsync(int sceneCharacterId); + Task> ListAttributeEventsBySceneAsync(int sceneId); Task> ListAttributeEventsByCharacterAsync(int characterId); Task SaveAttributeEventAsync(CharacterAttributeEvent attributeEvent); Task> ListKnowledgeBySceneAsync(int sceneId); @@ -3254,6 +3255,13 @@ public sealed class CharacterRepository(ISqlConnectionFactory connectionFactory) return rows.ToList(); } + public async Task> ListAttributeEventsBySceneAsync(int sceneId) + { + using var connection = connectionFactory.CreateConnection(); + var rows = await connection.QueryAsync("dbo.CharacterAttributeEvent_ListByScene", new { SceneID = sceneId }, commandType: CommandType.StoredProcedure); + return rows.ToList(); + } + public async Task SaveAttributeEventAsync(CharacterAttributeEvent attributeEvent) { using var connection = connectionFactory.CreateConnection(); diff --git a/PlotLine/Services/CoreServices.cs b/PlotLine/Services/CoreServices.cs index 1b3676b..1445972 100644 --- a/PlotLine/Services/CoreServices.cs +++ b/PlotLine/Services/CoreServices.cs @@ -1540,6 +1540,7 @@ public sealed class SceneService( model.AssetCustodyEvents = model.SceneID == 0 ? [] : await assets.ListCustodyBySceneAsync(model.SceneID); model.SceneAssetLocations = model.SceneID == 0 ? [] : await locations.ListSceneAssetLocationsAsync(model.SceneID); model.SceneCharacters = model.SceneID == 0 ? [] : await characters.ListSceneCharactersAsync(model.SceneID); + model.CharacterAttributeEvents = model.SceneID == 0 ? [] : await characters.ListAttributeEventsBySceneAsync(model.SceneID); model.Warnings = model.SceneID == 0 ? [] : await warnings.ListBySceneAsync(model.SceneID); model.AgeContinuityWarnings = await BuildAgeContinuityWarningsAsync(model); var sceneDependencyRows = model.SceneID == 0 ? [] : await sceneDependencies.ListBySceneAsync(model.SceneID); diff --git a/PlotLine/Sql/069_CharacterAttributeEventsByScene.sql b/PlotLine/Sql/069_CharacterAttributeEventsByScene.sql new file mode 100644 index 0000000..0c29670 --- /dev/null +++ b/PlotLine/Sql/069_CharacterAttributeEventsByScene.sql @@ -0,0 +1,19 @@ +CREATE OR ALTER PROCEDURE dbo.CharacterAttributeEvent_ListByScene + @SceneID int +AS +BEGIN + SET NOCOUNT ON; + + SELECT cae.CharacterAttributeEventID, cae.CharacterID, ch.CharacterName, cae.CharacterAttributeTypeID, + cat.AttributeName, cae.SceneID, s.SceneNumber, s.SceneTitle, c.ChapterNumber, b.BookTitle, b.Subtitle AS BookSubtitle, + cae.AttributeValue, cae.Description, cae.CreatedDate, cae.UpdatedDate + FROM dbo.CharacterAttributeEvents cae + INNER JOIN dbo.Characters ch ON ch.CharacterID = cae.CharacterID + INNER JOIN dbo.CharacterAttributeTypes cat ON cat.CharacterAttributeTypeID = cae.CharacterAttributeTypeID + INNER JOIN dbo.Scenes s ON s.SceneID = cae.SceneID + INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID + INNER JOIN dbo.Books b ON b.BookID = c.BookID + WHERE cae.SceneID = @SceneID + ORDER BY ch.CharacterName, cat.SortOrder, cae.CreatedDate; +END; +GO diff --git a/PlotLine/Views/Scenes/_SceneInspector.cshtml b/PlotLine/Views/Scenes/_SceneInspector.cshtml index c289d41..8474f1d 100644 --- a/PlotLine/Views/Scenes/_SceneInspector.cshtml +++ b/PlotLine/Views/Scenes/_SceneInspector.cshtml @@ -566,6 +566,11 @@ + + @if (TempData["CharacterAttributeAddError"] is string addCharacterAttributeError) + { +

@addCharacterAttributeError

+ }