From 1909e998b57a6d77d34f072b2078044357a3723f Mon Sep 17 00:00:00 2001 From: Space-tourist <114026452+Space-tourist@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:24:10 +0300 Subject: [PATCH 1/3] appraiser story rounds count added --- .../Converters/StoryConverter.cs | 3 ++- .../Converters/SummaryByStoryConverter.cs | 3 ++- .../Messages.cs | 1 + .../Services/SummaryByStoryBuilder.cs | 13 +++++++++ .../Internal/GetStoryQuery.cs | 3 ++- .../StoryReader.cs | 3 ++- .../StoryRepository.cs | 10 ++++--- .../Story.cs | 6 ++++- .../Common/StoryDto.cs | 3 ++- .../Common/SummaryByStory.cs | 3 ++- .../wwwroot/langs/en.json | 1 + .../wwwroot/langs/ru.json | 1 + .../2024_11_07_0_AddRoundsCount.cs | 27 +++++++++++++++++++ .../AssessmentSession.stories.razor | 3 ++- .../AssessmentSessionHistory.stories.razor | 9 ++++--- .../AssessmentSessionResources.Designer.cs | 6 +++++ .../AssessmentSessionResources.resx | 3 +++ .../AssessmentSessionResources.ru.Designer.cs | 6 +++++ .../AssessmentSessionResources.ru.resx | 3 +++ .../AssessmentSession/StoryTotal.razor | 4 +++ 20 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 src/Inc.TeamAssistant.Migrations/2024_11_07_0_AddRoundsCount.cs diff --git a/src/Inc.TeamAssistant.Appraiser.Application/Converters/StoryConverter.cs b/src/Inc.TeamAssistant.Appraiser.Application/Converters/StoryConverter.cs index 88b9fe09..f2e47367 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/Converters/StoryConverter.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/Converters/StoryConverter.cs @@ -33,6 +33,7 @@ public static StoryDto Convert(Story story) story.EstimateEnded, story.CalculateMean().DisplayValue, story.CalculateMedian().DisplayValue, - story.AcceptedValue.DisplayValue); + story.AcceptedValue.DisplayValue, + story.RoundsCount); } } \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.Application/Converters/SummaryByStoryConverter.cs b/src/Inc.TeamAssistant.Appraiser.Application/Converters/SummaryByStoryConverter.cs index 581c7200..00066495 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/Converters/SummaryByStoryConverter.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/Converters/SummaryByStoryConverter.cs @@ -43,6 +43,7 @@ public static SummaryByStory ConvertTo(Story story) storyForEstimates, assessments, story.Accepted, - assessmentsToAccept); + assessmentsToAccept, + story.RoundsCount); } } \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.Application/Messages.cs b/src/Inc.TeamAssistant.Appraiser.Application/Messages.cs index a459f583..b6bd4d29 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/Messages.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/Messages.cs @@ -15,4 +15,5 @@ internal static class Messages public static readonly MessageId Appraiser_Revote = new(nameof(Appraiser_Revote)); public static readonly MessageId Connector_TeamNotFound = new(nameof(Connector_TeamNotFound)); public static readonly MessageId Appraiser_MissingTaskForEvaluate = new(nameof(Appraiser_MissingTaskForEvaluate)); + public static readonly MessageId Appraiser_NumberOfRounds = new(nameof(Appraiser_NumberOfRounds)); } \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.Application/Services/SummaryByStoryBuilder.cs b/src/Inc.TeamAssistant.Appraiser.Application/Services/SummaryByStoryBuilder.cs index fe5650ff..5ef7d7ea 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/Services/SummaryByStoryBuilder.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/Services/SummaryByStoryBuilder.cs @@ -39,6 +39,8 @@ public async Task Build(SummaryByStory summary) if (summary.Accepted) await AddAcceptedValue(builder, summary); + await AddRoundsInfo(builder, summary); + var notification = summary.StoryExternalId.HasValue ? NotificationMessage.Edit( new ChatMessage(summary.ChatId, summary.StoryExternalId.Value), @@ -161,4 +163,15 @@ private string BuildLinkForDashboard(Guid teamId, LanguageId languageId) languageId.Value, teamId.ToString("N")); } + + private async Task AddRoundsInfo(StringBuilder builder, SummaryByStory summary) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentNullException.ThrowIfNull(summary); + + builder.AppendLine(); + builder.Append(await _messageBuilder.Build(Messages.Appraiser_NumberOfRounds, summary.LanguageId)); + builder.Append(' '); + builder.Append(summary.RoundsCount); + } } \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.DataAccess/Internal/GetStoryQuery.cs b/src/Inc.TeamAssistant.Appraiser.DataAccess/Internal/GetStoryQuery.cs index 5470b5be..1f59a82d 100644 --- a/src/Inc.TeamAssistant.Appraiser.DataAccess/Internal/GetStoryQuery.cs +++ b/src/Inc.TeamAssistant.Appraiser.DataAccess/Internal/GetStoryQuery.cs @@ -26,7 +26,8 @@ public static async Task> Get( s.title AS title, s.external_id AS externalid, s.links AS links, - s.total_value AS totalvalue + s.total_value AS totalvalue, + s.rounds_count AS roundscount FROM appraiser.stories AS s WHERE s.id = ANY(@story_ids); diff --git a/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryReader.cs b/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryReader.cs index b0151519..3758bcff 100644 --- a/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryReader.cs +++ b/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryReader.cs @@ -34,7 +34,8 @@ public async Task> GetStories( s.title AS title, s.external_id AS externalid, s.links AS links, - s.total_value AS totalvalue + s.total_value AS totalvalue, + s.rounds_count AS roundscount FROM appraiser.stories AS s WHERE s.team_id = @team_id AND s.created <= @before AND (@from is null OR s.created >= @from);", new diff --git a/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryRepository.cs b/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryRepository.cs index d256b453..d7be9441 100644 --- a/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryRepository.cs +++ b/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryRepository.cs @@ -47,10 +47,10 @@ public async Task Upsert(Story story, CancellationToken token) var upsertStory = new CommandDefinition(@" INSERT INTO appraiser.stories ( id, bot_id, story_type, created, team_id, chat_id, moderator_id, language_id, title, - external_id, links, total_value) + external_id, links, total_value, rounds_count) VALUES ( @id, @bot_id, @story_type, @created, @team_id, @chat_id, @moderator_id, @language_id, @title, - @external_id, @links::jsonb, @total_value) + @external_id, @links::jsonb, @total_value, @rounds_count) ON CONFLICT (id) DO UPDATE SET bot_id = EXCLUDED.bot_id, story_type = EXCLUDED.story_type, @@ -62,7 +62,8 @@ ON CONFLICT (id) DO UPDATE SET title = EXCLUDED.title, external_id = EXCLUDED.external_id, links = EXCLUDED.links, - total_value = EXCLUDED.total_value;", + total_value = EXCLUDED.total_value, + rounds_count = EXCLUDED.rounds_count;", new { id = story.Id, @@ -76,7 +77,8 @@ ON CONFLICT (id) DO UPDATE SET title = story.Title, external_id = story.ExternalId, links = JsonSerializer.Serialize(story.Links), - total_value = story.TotalValue + total_value = story.TotalValue, + rounds_count = story.RoundsCount }, flags: CommandFlags.None, cancellationToken: token); diff --git a/src/Inc.TeamAssistant.Appraiser.Domain/Story.cs b/src/Inc.TeamAssistant.Appraiser.Domain/Story.cs index fabce6ae..15c94130 100644 --- a/src/Inc.TeamAssistant.Appraiser.Domain/Story.cs +++ b/src/Inc.TeamAssistant.Appraiser.Domain/Story.cs @@ -17,6 +17,7 @@ public sealed class Story public int? ExternalId { get; private set; } public bool Accepted => TotalValue.HasValue; public int? TotalValue { get; private set; } + public int RoundsCount { get; private set; } private readonly List _storyForEstimates; public IReadOnlyCollection StoryForEstimates => _storyForEstimates; @@ -53,7 +54,8 @@ public Story( LanguageId = languageId ?? throw new ArgumentNullException(nameof(languageId)); TeamId = teamId; Title = title; - } + RoundsCount = 1; + } public void SetExternalId(int storyExternalId) => ExternalId = storyExternalId; @@ -91,6 +93,8 @@ public void Reset(long participantId, bool hasManagerAccess) foreach (var storyForEstimate in _storyForEstimates) storyForEstimate.Reset(); + + RoundsCount++; } public void Finish(long participantId, bool hasManagerAccess) diff --git a/src/Inc.TeamAssistant.Appraiser.Model/Common/StoryDto.cs b/src/Inc.TeamAssistant.Appraiser.Model/Common/StoryDto.cs index 783dbcc3..06c549ed 100644 --- a/src/Inc.TeamAssistant.Appraiser.Model/Common/StoryDto.cs +++ b/src/Inc.TeamAssistant.Appraiser.Model/Common/StoryDto.cs @@ -8,4 +8,5 @@ public sealed record StoryDto( bool EstimateEnded, string Mean, string Median, - string AcceptedValue); \ No newline at end of file + string AcceptedValue, + int RoundsCount); \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.Model/Common/SummaryByStory.cs b/src/Inc.TeamAssistant.Appraiser.Model/Common/SummaryByStory.cs index 7d6f1caf..87afcb1b 100644 --- a/src/Inc.TeamAssistant.Appraiser.Model/Common/SummaryByStory.cs +++ b/src/Inc.TeamAssistant.Appraiser.Model/Common/SummaryByStory.cs @@ -18,4 +18,5 @@ public sealed record SummaryByStory( IReadOnlyCollection Items, IReadOnlyCollection Assessments, bool Accepted, - IReadOnlyCollection AssessmentsToAccept); \ No newline at end of file + IReadOnlyCollection AssessmentsToAccept, + int RoundsCount); \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Gateway/wwwroot/langs/en.json b/src/Inc.TeamAssistant.Gateway/wwwroot/langs/en.json index 27c79aea..f94a67e9 100644 --- a/src/Inc.TeamAssistant.Gateway/wwwroot/langs/en.json +++ b/src/Inc.TeamAssistant.Gateway/wwwroot/langs/en.json @@ -40,6 +40,7 @@ "Appraiser_PowerOfTwo_16SP": "16", "Appraiser_PowerOfTwo_32SP": "32", "Appraiser_PowerOfTwo_64SP": "64", + "Appraiser_NumberOfRounds": "Number of evaluation rounds", "CheckIn_GetStarted": "To get started, please add the bot to your chat room", "CheckIn_ConnectLinkText": "Use {0} to see our locations", diff --git a/src/Inc.TeamAssistant.Gateway/wwwroot/langs/ru.json b/src/Inc.TeamAssistant.Gateway/wwwroot/langs/ru.json index efd58027..80fd3380 100644 --- a/src/Inc.TeamAssistant.Gateway/wwwroot/langs/ru.json +++ b/src/Inc.TeamAssistant.Gateway/wwwroot/langs/ru.json @@ -40,6 +40,7 @@ "Appraiser_PowerOfTwo_16SP": "16", "Appraiser_PowerOfTwo_32SP": "32", "Appraiser_PowerOfTwo_64SP": "64", + "Appraiser_NumberOfRounds": "Количество раундов оценки", "CheckIn_GetStarted": "Добавьте бота в чат для начала работы", "CheckIn_ConnectLinkText": "Перейдите по ссылке {0} чтобы увидеть наши локации", diff --git a/src/Inc.TeamAssistant.Migrations/2024_11_07_0_AddRoundsCount.cs b/src/Inc.TeamAssistant.Migrations/2024_11_07_0_AddRoundsCount.cs new file mode 100644 index 00000000..7e13dc99 --- /dev/null +++ b/src/Inc.TeamAssistant.Migrations/2024_11_07_0_AddRoundsCount.cs @@ -0,0 +1,27 @@ +using FluentMigrator; + +namespace Inc.TeamAssistant.Migrations; + +[Migration(2024_11_07_0)] + +public sealed class AddRoundsCount : Migration +{ + public override void Up() + { + Create + .Column("rounds_count") + .OnTable("stories") + .InSchema("appraiser") + .AsInt32() + .NotNullable() + .SetExistingRowsTo(1); + } + + public override void Down() + { + Delete + .Column("rounds_count") + .FromTable("stories") + .InSchema("appraiser"); + } +} \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSession.stories.razor b/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSession.stories.razor index 79e7894a..fdb3783e 100644 --- a/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSession.stories.razor +++ b/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSession.stories.razor @@ -103,7 +103,8 @@ EstimateEnded: true, Mean: "9.6", Median: "8", - AcceptedValue: string.Empty)); + AcceptedValue: string.Empty, + RoundsCount: 1)); private void OnViewChanged(AssessmentType view) { diff --git a/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSessionHistory.stories.razor b/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSessionHistory.stories.razor index 06047164..f5bee06c 100644 --- a/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSessionHistory.stories.razor +++ b/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSessionHistory.stories.razor @@ -75,7 +75,8 @@ EstimateEnded: true, Mean: "9.6", Median: "8", - AcceptedValue: "8"), + AcceptedValue: "8", + RoundsCount: 1), new( Id: Guid.NewGuid(), Title: "Create order from user card", @@ -104,7 +105,8 @@ EstimateEnded: true, Mean: "9.6", Median: "8", - AcceptedValue: "8"), + AcceptedValue: "8", + RoundsCount: 1), new( Id: Guid.NewGuid(), Title: "Create order from user card", @@ -133,7 +135,8 @@ EstimateEnded: true, Mean: "9.6", Median: "8", - AcceptedValue: "8") + AcceptedValue: "8", + RoundsCount: 1) ]; private void OnViewChanged(AssessmentType view) diff --git a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.Designer.cs b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.Designer.cs index 04bf17c9..92fe7431 100644 --- a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.Designer.cs +++ b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.Designer.cs @@ -57,6 +57,12 @@ internal static string MedianRating { } } + internal static string RoundsCount { + get { + return ResourceManager.GetString("RoundsCount", resourceCulture); + } + } + internal static string AcceptedValue { get { return ResourceManager.GetString("AcceptedValue", resourceCulture); diff --git a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.resx b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.resx index 5ba2102a..beeed07a 100644 --- a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.resx +++ b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.resx @@ -24,6 +24,9 @@ median + + round + accepted diff --git a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.ru.Designer.cs b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.ru.Designer.cs index f6e39eb9..064d9318 100644 --- a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.ru.Designer.cs +++ b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.ru.Designer.cs @@ -57,6 +57,12 @@ internal static string MedianRating { } } + internal static string RoundsCount { + get { + return ResourceManager.GetString("RoundsCount", resourceCulture); + } + } + internal static string AcceptedValue { get { return ResourceManager.GetString("AcceptedValue", resourceCulture); diff --git a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.ru.resx b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.ru.resx index 332b5f13..bd8f8e43 100644 --- a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.ru.resx +++ b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/AssessmentSessionResources.ru.resx @@ -24,6 +24,9 @@ медиана + + раунд + принята diff --git a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/StoryTotal.razor b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/StoryTotal.razor index 6273602c..807e4e68 100644 --- a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/StoryTotal.razor +++ b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/StoryTotal.razor @@ -17,6 +17,10 @@ @Localizer["AcceptedValue"] } + + @Story.RoundsCount + @Localizer["RoundsCount"] + From 50d356c1bd298c4bce9b9df2eaf95738f922d878 Mon Sep 17 00:00:00 2001 From: Space-tourist <114026452+Space-tourist@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:47:39 +0300 Subject: [PATCH 2/3] Single url added to story --- .../AddStory/AddStoryCommandHandler.cs | 4 +- .../Validators/AddStoryCommandValidator.cs | 37 +++++++++++++-- .../Converters/StoryConverter.cs | 4 +- .../Converters/SummaryByStoryConverter.cs | 4 +- .../Messages.cs | 2 + .../Services/SummaryByStoryBuilder.cs | 12 ++--- .../Internal/GetStoryQuery.cs | 4 +- .../StoryReader.cs | 4 +- .../StoryRepository.cs | 12 ++--- .../Story.cs | 8 ++-- .../Common/StoryDto.cs | 4 +- .../Common/SummaryByStory.cs | 4 +- .../wwwroot/langs/en.json | 2 + .../wwwroot/langs/ru.json | 2 + .../2024_11_25_0_AddUrl.cs | 45 +++++++++++++++++++ .../AssessmentSession.stories.razor | 4 +- .../AssessmentSessionHistory.stories.razor | 12 ++--- .../AssessmentSession/StoryDetails.razor | 18 ++++---- 18 files changed, 130 insertions(+), 52 deletions(-) create mode 100644 src/Inc.TeamAssistant.Migrations/2024_11_25_0_AddUrl.cs diff --git a/src/Inc.TeamAssistant.Appraiser.Application/CommandHandlers/AddStory/AddStoryCommandHandler.cs b/src/Inc.TeamAssistant.Appraiser.Application/CommandHandlers/AddStory/AddStoryCommandHandler.cs index b5f42fb8..485f5906 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/CommandHandlers/AddStory/AddStoryCommandHandler.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/CommandHandlers/AddStory/AddStoryCommandHandler.cs @@ -43,8 +43,8 @@ public async Task Handle(AddStoryCommand command, CancellationTok command.MessageContext.LanguageId, command.Title); - foreach (var link in command.Links) - story.AddLink(link); + if(command.Links.Any()) + story.AddLink(command.Links.Single()); foreach (var teammate in command.Teammates) story.AddStoryForEstimate(new StoryForEstimate( diff --git a/src/Inc.TeamAssistant.Appraiser.Application/CommandHandlers/AddStory/Validators/AddStoryCommandValidator.cs b/src/Inc.TeamAssistant.Appraiser.Application/CommandHandlers/AddStory/Validators/AddStoryCommandValidator.cs index 93de0bd8..aeaf3a6d 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/CommandHandlers/AddStory/Validators/AddStoryCommandValidator.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/CommandHandlers/AddStory/Validators/AddStoryCommandValidator.cs @@ -1,12 +1,16 @@ using FluentValidation; using Inc.TeamAssistant.Appraiser.Model.Commands.AddStory; +using Inc.TeamAssistant.Primitives.Languages; namespace Inc.TeamAssistant.Appraiser.Application.CommandHandlers.AddStory.Validators; internal sealed class AddStoryCommandValidator : AbstractValidator { - public AddStoryCommandValidator() + private readonly IMessageBuilder _messageBuilder; + public AddStoryCommandValidator(IMessageBuilder messageBuilder) { + _messageBuilder = messageBuilder ?? throw new ArgumentNullException(nameof(messageBuilder)); + RuleFor(e => e.TeamId) .NotEmpty(); @@ -18,10 +22,37 @@ public AddStoryCommandValidator() .Must(e => !e.StartsWith("/")) .WithMessage("'{PropertyName}' please enter text value."); - RuleForEach(e => e.Links) - .NotEmpty(); + RuleFor(e => e.Links) + .CustomAsync(CheckLinks); RuleFor(e => e.Teammates) .NotEmpty(); } + + private async Task CheckLinks( + IReadOnlyCollection links, + ValidationContext context, + CancellationToken token) + { + ArgumentNullException.ThrowIfNull(links); + ArgumentNullException.ThrowIfNull(context); + + if (links.Count > 1) + { + var errorMessage = await _messageBuilder.Build(Messages.Appraiser_MultipleLinkError, + context.InstanceToValidate.MessageContext.LanguageId); + context.AddFailure(nameof(AddStoryCommand.Links), errorMessage); + } + else + { + var link = links.FirstOrDefault(); + + if (!string.IsNullOrWhiteSpace(link) && link.Length > 2000) + { + var errorMessage = await _messageBuilder.Build(Messages.Appraiser_LinkLengthError, + context.InstanceToValidate.MessageContext.LanguageId); + context.AddFailure(nameof(AddStoryCommand.Links), errorMessage); + } + } + } } \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.Application/Converters/StoryConverter.cs b/src/Inc.TeamAssistant.Appraiser.Application/Converters/StoryConverter.cs index f2e47367..859307d2 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/Converters/StoryConverter.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/Converters/StoryConverter.cs @@ -28,12 +28,12 @@ public static StoryDto Convert(Story story) return new( story.Id, story.Title, - story.Links.ToArray(), items, story.EstimateEnded, story.CalculateMean().DisplayValue, story.CalculateMedian().DisplayValue, story.AcceptedValue.DisplayValue, - story.RoundsCount); + story.RoundsCount, + story.Url); } } \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.Application/Converters/SummaryByStoryConverter.cs b/src/Inc.TeamAssistant.Appraiser.Application/Converters/SummaryByStoryConverter.cs index 00066495..ccad8aa2 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/Converters/SummaryByStoryConverter.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/Converters/SummaryByStoryConverter.cs @@ -35,7 +35,6 @@ public static SummaryByStory ConvertTo(Story story) story.ExternalId, story.Title, story.StoryType.ToString(), - story.Links.ToArray(), story.EstimateEnded, story.CalculateMean().DisplayValue, story.CalculateMedian().DisplayValue, @@ -44,6 +43,7 @@ public static SummaryByStory ConvertTo(Story story) assessments, story.Accepted, assessmentsToAccept, - story.RoundsCount); + story.RoundsCount, + story.Url); } } \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.Application/Messages.cs b/src/Inc.TeamAssistant.Appraiser.Application/Messages.cs index b6bd4d29..44e79269 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/Messages.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/Messages.cs @@ -16,4 +16,6 @@ internal static class Messages public static readonly MessageId Connector_TeamNotFound = new(nameof(Connector_TeamNotFound)); public static readonly MessageId Appraiser_MissingTaskForEvaluate = new(nameof(Appraiser_MissingTaskForEvaluate)); public static readonly MessageId Appraiser_NumberOfRounds = new(nameof(Appraiser_NumberOfRounds)); + public static readonly MessageId Appraiser_MultipleLinkError = new(nameof(Appraiser_MultipleLinkError)); + public static readonly MessageId Appraiser_LinkLengthError = new(nameof(Appraiser_LinkLengthError)); } \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.Application/Services/SummaryByStoryBuilder.cs b/src/Inc.TeamAssistant.Appraiser.Application/Services/SummaryByStoryBuilder.cs index 5ef7d7ea..0fbce6a4 100644 --- a/src/Inc.TeamAssistant.Appraiser.Application/Services/SummaryByStoryBuilder.cs +++ b/src/Inc.TeamAssistant.Appraiser.Application/Services/SummaryByStoryBuilder.cs @@ -70,10 +70,11 @@ private async Task AddBody(StringBuilder builder, SummaryByStory summary) summary.LanguageId); builder.AppendLine(storyHeader); + builder.AppendLine(summary.StoryTitle); - if (summary.StoryLinks.Any()) - foreach (var link in summary.StoryLinks) - builder.AppendLine(link); + + if (!string.IsNullOrWhiteSpace(summary.Url)) + builder.AppendLine(summary.Url); } private async Task AddEstimateSummary(StringBuilder builder, SummaryByStory summary) @@ -170,8 +171,7 @@ private async Task AddRoundsInfo(StringBuilder builder, SummaryByStory summary) ArgumentNullException.ThrowIfNull(summary); builder.AppendLine(); - builder.Append(await _messageBuilder.Build(Messages.Appraiser_NumberOfRounds, summary.LanguageId)); - builder.Append(' '); - builder.Append(summary.RoundsCount); + var roundsInfo = await _messageBuilder.Build(Messages.Appraiser_NumberOfRounds, summary.LanguageId); + builder.AppendLine($"{roundsInfo} {summary.RoundsCount}"); } } \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.DataAccess/Internal/GetStoryQuery.cs b/src/Inc.TeamAssistant.Appraiser.DataAccess/Internal/GetStoryQuery.cs index 1f59a82d..481de138 100644 --- a/src/Inc.TeamAssistant.Appraiser.DataAccess/Internal/GetStoryQuery.cs +++ b/src/Inc.TeamAssistant.Appraiser.DataAccess/Internal/GetStoryQuery.cs @@ -25,9 +25,9 @@ public static async Task> Get( s.language_id AS languageid, s.title AS title, s.external_id AS externalid, - s.links AS links, s.total_value AS totalvalue, - s.rounds_count AS roundscount + s.rounds_count AS roundscount, + s.url AS url FROM appraiser.stories AS s WHERE s.id = ANY(@story_ids); diff --git a/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryReader.cs b/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryReader.cs index 3758bcff..2b9e6237 100644 --- a/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryReader.cs +++ b/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryReader.cs @@ -33,9 +33,9 @@ public async Task> GetStories( s.language_id AS languageid, s.title AS title, s.external_id AS externalid, - s.links AS links, s.total_value AS totalvalue, - s.rounds_count AS roundscount + s.rounds_count AS roundscount, + s.url AS url FROM appraiser.stories AS s WHERE s.team_id = @team_id AND s.created <= @before AND (@from is null OR s.created >= @from);", new diff --git a/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryRepository.cs b/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryRepository.cs index d7be9441..4bec3bb8 100644 --- a/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryRepository.cs +++ b/src/Inc.TeamAssistant.Appraiser.DataAccess/StoryRepository.cs @@ -47,10 +47,10 @@ public async Task Upsert(Story story, CancellationToken token) var upsertStory = new CommandDefinition(@" INSERT INTO appraiser.stories ( id, bot_id, story_type, created, team_id, chat_id, moderator_id, language_id, title, - external_id, links, total_value, rounds_count) + external_id, total_value, rounds_count, url) VALUES ( @id, @bot_id, @story_type, @created, @team_id, @chat_id, @moderator_id, @language_id, @title, - @external_id, @links::jsonb, @total_value, @rounds_count) + @external_id, @total_value, @rounds_count, @url) ON CONFLICT (id) DO UPDATE SET bot_id = EXCLUDED.bot_id, story_type = EXCLUDED.story_type, @@ -61,9 +61,9 @@ ON CONFLICT (id) DO UPDATE SET language_id = EXCLUDED.language_id, title = EXCLUDED.title, external_id = EXCLUDED.external_id, - links = EXCLUDED.links, total_value = EXCLUDED.total_value, - rounds_count = EXCLUDED.rounds_count;", + rounds_count = EXCLUDED.rounds_count, + url = EXCLUDED.url;", new { id = story.Id, @@ -76,9 +76,9 @@ ON CONFLICT (id) DO UPDATE SET language_id = story.LanguageId.Value, title = story.Title, external_id = story.ExternalId, - links = JsonSerializer.Serialize(story.Links), total_value = story.TotalValue, - rounds_count = story.RoundsCount + rounds_count = story.RoundsCount, + url = story.Url }, flags: CommandFlags.None, cancellationToken: token); diff --git a/src/Inc.TeamAssistant.Appraiser.Domain/Story.cs b/src/Inc.TeamAssistant.Appraiser.Domain/Story.cs index 15c94130..751a3828 100644 --- a/src/Inc.TeamAssistant.Appraiser.Domain/Story.cs +++ b/src/Inc.TeamAssistant.Appraiser.Domain/Story.cs @@ -18,18 +18,16 @@ public sealed class Story public bool Accepted => TotalValue.HasValue; public int? TotalValue { get; private set; } public int RoundsCount { get; private set; } + public string? Url { get; private set; } private readonly List _storyForEstimates; public IReadOnlyCollection StoryForEstimates => _storyForEstimates; - public ICollection Links { get; private set; } - private IEstimationStrategy EstimationStrategy => EstimationStrategyFactory.Create(StoryType); private Story() { _storyForEstimates = new(); - Links = new List(); } public Story( @@ -79,8 +77,8 @@ public void AddStoryForEstimate(StoryForEstimate storyForEstimate) public void AddLink(string link) { ArgumentException.ThrowIfNullOrWhiteSpace(link); - - Links.Add(link); + + Url = link; } public void Reset(long participantId, bool hasManagerAccess) diff --git a/src/Inc.TeamAssistant.Appraiser.Model/Common/StoryDto.cs b/src/Inc.TeamAssistant.Appraiser.Model/Common/StoryDto.cs index 06c549ed..196ae1ca 100644 --- a/src/Inc.TeamAssistant.Appraiser.Model/Common/StoryDto.cs +++ b/src/Inc.TeamAssistant.Appraiser.Model/Common/StoryDto.cs @@ -3,10 +3,10 @@ namespace Inc.TeamAssistant.Appraiser.Model.Common; public sealed record StoryDto( Guid Id, string Title, - IReadOnlyCollection Links, IReadOnlyCollection StoryForEstimates, bool EstimateEnded, string Mean, string Median, string AcceptedValue, - int RoundsCount); \ No newline at end of file + int RoundsCount, + string? Url); \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Appraiser.Model/Common/SummaryByStory.cs b/src/Inc.TeamAssistant.Appraiser.Model/Common/SummaryByStory.cs index 87afcb1b..c020d9f4 100644 --- a/src/Inc.TeamAssistant.Appraiser.Model/Common/SummaryByStory.cs +++ b/src/Inc.TeamAssistant.Appraiser.Model/Common/SummaryByStory.cs @@ -10,7 +10,6 @@ public sealed record SummaryByStory( int? StoryExternalId, string StoryTitle, string StoryType, - IReadOnlyCollection StoryLinks, bool EstimateEnded, string Mean, string Median, @@ -19,4 +18,5 @@ public sealed record SummaryByStory( IReadOnlyCollection Assessments, bool Accepted, IReadOnlyCollection AssessmentsToAccept, - int RoundsCount); \ No newline at end of file + int RoundsCount, + string? Url); \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Gateway/wwwroot/langs/en.json b/src/Inc.TeamAssistant.Gateway/wwwroot/langs/en.json index f94a67e9..2e1d01ce 100644 --- a/src/Inc.TeamAssistant.Gateway/wwwroot/langs/en.json +++ b/src/Inc.TeamAssistant.Gateway/wwwroot/langs/en.json @@ -41,6 +41,8 @@ "Appraiser_PowerOfTwo_32SP": "32", "Appraiser_PowerOfTwo_64SP": "64", "Appraiser_NumberOfRounds": "Number of evaluation rounds", + "Appraiser_MultipleLinkError": "Description must contain one link", + "Appraiser_LinkLengthError": "Link length must be less than 2000 symbols", "CheckIn_GetStarted": "To get started, please add the bot to your chat room", "CheckIn_ConnectLinkText": "Use {0} to see our locations", diff --git a/src/Inc.TeamAssistant.Gateway/wwwroot/langs/ru.json b/src/Inc.TeamAssistant.Gateway/wwwroot/langs/ru.json index 80fd3380..209aad7f 100644 --- a/src/Inc.TeamAssistant.Gateway/wwwroot/langs/ru.json +++ b/src/Inc.TeamAssistant.Gateway/wwwroot/langs/ru.json @@ -41,6 +41,8 @@ "Appraiser_PowerOfTwo_32SP": "32", "Appraiser_PowerOfTwo_64SP": "64", "Appraiser_NumberOfRounds": "Количество раундов оценки", + "Appraiser_MultipleLinkError": "Описание должно содержать одну ссылку", + "Appraiser_LinkLengthError": "Длина ссылки не должна превышать 2000 символов", "CheckIn_GetStarted": "Добавьте бота в чат для начала работы", "CheckIn_ConnectLinkText": "Перейдите по ссылке {0} чтобы увидеть наши локации", diff --git a/src/Inc.TeamAssistant.Migrations/2024_11_25_0_AddUrl.cs b/src/Inc.TeamAssistant.Migrations/2024_11_25_0_AddUrl.cs new file mode 100644 index 00000000..b44a1a84 --- /dev/null +++ b/src/Inc.TeamAssistant.Migrations/2024_11_25_0_AddUrl.cs @@ -0,0 +1,45 @@ +using FluentMigrator; + +namespace Inc.TeamAssistant.Migrations; + +[Migration(2024_11_25_0)] + +public sealed class AddUrl : Migration +{ + public override void Up() + { + Create + .Column("url") + .OnTable("stories") + .InSchema("appraiser") + .AsString(2000) + .Nullable(); + + Execute.Sql( + """ + UPDATE appraiser.stories + SET url = links->>0; + """, + "Add single url to story"); + + Delete + .Column("links") + .FromTable("stories") + .InSchema("appraiser"); + } + + public override void Down() + { + Delete + .Column("url") + .FromTable("stories") + .InSchema("appraiser"); + + Create + .Column("links") + .OnTable("stories") + .InSchema("appraiser") + .AsCustom("jsonb") + .NotNullable(); + } +} \ No newline at end of file diff --git a/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSession.stories.razor b/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSession.stories.razor index fdb3783e..a32660c8 100644 --- a/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSession.stories.razor +++ b/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSession.stories.razor @@ -79,7 +79,6 @@ new StoryDto( Id: Guid.NewGuid(), Title: "Create order from user card", - Links: ["https://amazon.com", "https://ozon.ru"], StoryForEstimates: [ new StoryForEstimateDto( ParticipantId: 0, @@ -104,7 +103,8 @@ Mean: "9.6", Median: "8", AcceptedValue: string.Empty, - RoundsCount: 1)); + RoundsCount: 1, + Url: "https://ozon.ru")); private void OnViewChanged(AssessmentType view) { diff --git a/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSessionHistory.stories.razor b/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSessionHistory.stories.razor index f5bee06c..f0d435a1 100644 --- a/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSessionHistory.stories.razor +++ b/src/Inc.TeamAssistant.Stories/Features/AssessmentSession/AssessmentSessionHistory.stories.razor @@ -50,7 +50,6 @@ new( Id: Guid.NewGuid(), Title: "Create order from user card", - Links: ["https://amazon.com", "https://ozon.ru"], StoryForEstimates: [ new StoryForEstimateDto( @@ -76,11 +75,11 @@ Mean: "9.6", Median: "8", AcceptedValue: "8", - RoundsCount: 1), + RoundsCount: 1, + Url: "https://ozon.ru"), new( Id: Guid.NewGuid(), Title: "Create order from user card", - Links: ["https://amazon.com", "https://ozon.ru"], StoryForEstimates: [ new StoryForEstimateDto( @@ -106,11 +105,11 @@ Mean: "9.6", Median: "8", AcceptedValue: "8", - RoundsCount: 1), + RoundsCount: 1, + Url: "https://ozon.ru"), new( Id: Guid.NewGuid(), Title: "Create order from user card", - Links: ["https://amazon.com", "https://ozon.ru"], StoryForEstimates: [ new StoryForEstimateDto( @@ -136,7 +135,8 @@ Mean: "9.6", Median: "8", AcceptedValue: "8", - RoundsCount: 1) + RoundsCount: 1, + Url: "https://ozon.ru") ]; private void OnViewChanged(AssessmentType view) diff --git a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/StoryDetails.razor b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/StoryDetails.razor index 0bb92f5e..8220e6ca 100644 --- a/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/StoryDetails.razor +++ b/src/Inc.TeamAssistant.WebUI/Features/AssessmentSession/StoryDetails.razor @@ -1,15 +1,13 @@
-

@Story.Title

- @if (Story.Links.Any()) + @if (String.IsNullOrWhiteSpace(Story.Url)) { -
    - @foreach (var link in Story.Links) - { -
  • - @link -
  • - } -
+

@Story.Title

+ } + else + { +

+ @Story.Title +

}
From 7fa82ab8d683ed3665f66a4b9bb170a849d42a72 Mon Sep 17 00:00:00 2001 From: dyatlov-a Date: Wed, 4 Dec 2024 23:42:16 +0300 Subject: [PATCH 3/3] Fix rollback migrations --- .../2024_11_25_0_AddUrl.cs | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Inc.TeamAssistant.Migrations/2024_11_25_0_AddUrl.cs b/src/Inc.TeamAssistant.Migrations/2024_11_25_0_AddUrl.cs index b44a1a84..9f95efc4 100644 --- a/src/Inc.TeamAssistant.Migrations/2024_11_25_0_AddUrl.cs +++ b/src/Inc.TeamAssistant.Migrations/2024_11_25_0_AddUrl.cs @@ -30,16 +30,35 @@ UPDATE appraiser.stories public override void Down() { - Delete - .Column("url") - .FromTable("stories") - .InSchema("appraiser"); - Create + .Column("links") + .OnTable("stories") + .InSchema("appraiser") + .AsCustom("jsonb") + .Nullable(); + + Execute.Sql( + """ + UPDATE appraiser.stories as s + SET links = + CASE + WHEN s.url IS NULL + THEN '[]'::JSONB + ELSE to_jsonb(ARRAY[s.url]) + END; + """, + "Move url to links"); + + Alter .Column("links") .OnTable("stories") .InSchema("appraiser") .AsCustom("jsonb") .NotNullable(); + + Delete + .Column("url") + .FromTable("stories") + .InSchema("appraiser"); } } \ No newline at end of file