Skip to content

Commit

Permalink
Merge pull request #86 from dyatlov-a/appraiser-rounds-and-links
Browse files Browse the repository at this point in the history
appraiser-rounds-and-links
  • Loading branch information
dyatlov-a authored Dec 4, 2024
2 parents 3528d57 + 7fa82ab commit 918da2c
Show file tree
Hide file tree
Showing 24 changed files with 228 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public async Task<CommandResult> 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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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<AddStoryCommand>
{
public AddStoryCommandValidator()
private readonly IMessageBuilder _messageBuilder;
public AddStoryCommandValidator(IMessageBuilder messageBuilder)
{
_messageBuilder = messageBuilder ?? throw new ArgumentNullException(nameof(messageBuilder));

RuleFor(e => e.TeamId)
.NotEmpty();

Expand All @@ -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<string> links,
ValidationContext<AddStoryCommand> 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);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +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.AcceptedValue.DisplayValue,
story.RoundsCount,
story.Url);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ public static SummaryByStory ConvertTo(Story story)
story.ExternalId,
story.Title,
story.StoryType.ToString(),
story.Links.ToArray(),
story.EstimateEnded,
story.CalculateMean().DisplayValue,
story.CalculateMedian().DisplayValue,
story.AcceptedValue.DisplayValue,
storyForEstimates,
assessments,
story.Accepted,
assessmentsToAccept);
assessmentsToAccept,
story.RoundsCount,
story.Url);
}
}
3 changes: 3 additions & 0 deletions src/Inc.TeamAssistant.Appraiser.Application/Messages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ 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));
public static readonly MessageId Appraiser_MultipleLinkError = new(nameof(Appraiser_MultipleLinkError));
public static readonly MessageId Appraiser_LinkLengthError = new(nameof(Appraiser_LinkLengthError));
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public async Task<NotificationMessage> 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),
Expand Down Expand Up @@ -68,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)
Expand Down Expand Up @@ -161,4 +164,14 @@ 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();
var roundsInfo = await _messageBuilder.Build(Messages.Appraiser_NumberOfRounds, summary.LanguageId);
builder.AppendLine($"{roundsInfo} {summary.RoundsCount}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ public static async Task<IReadOnlyCollection<Story>> 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.total_value AS totalvalue,
s.rounds_count AS roundscount,
s.url AS url
FROM appraiser.stories AS s
WHERE s.id = ANY(@story_ids);
Expand Down
5 changes: 3 additions & 2 deletions src/Inc.TeamAssistant.Appraiser.DataAccess/StoryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ public async Task<IReadOnlyCollection<Story>> 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.total_value AS totalvalue,
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
Expand Down
14 changes: 8 additions & 6 deletions src/Inc.TeamAssistant.Appraiser.DataAccess/StoryRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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, 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)
@external_id, @total_value, @rounds_count, @url)
ON CONFLICT (id) DO UPDATE SET
bot_id = EXCLUDED.bot_id,
story_type = EXCLUDED.story_type,
Expand All @@ -61,8 +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;",
total_value = EXCLUDED.total_value,
rounds_count = EXCLUDED.rounds_count,
url = EXCLUDED.url;",
new
{
id = story.Id,
Expand All @@ -75,8 +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
total_value = story.TotalValue,
rounds_count = story.RoundsCount,
url = story.Url
},
flags: CommandFlags.None,
cancellationToken: token);
Expand Down
14 changes: 8 additions & 6 deletions src/Inc.TeamAssistant.Appraiser.Domain/Story.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,17 @@ 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; }
public string? Url { get; private set; }

private readonly List<StoryForEstimate> _storyForEstimates;
public IReadOnlyCollection<StoryForEstimate> StoryForEstimates => _storyForEstimates;

public ICollection<string> Links { get; private set; }

private IEstimationStrategy EstimationStrategy => EstimationStrategyFactory.Create(StoryType);

private Story()
{
_storyForEstimates = new();
Links = new List<string>();
}

public Story(
Expand All @@ -53,7 +52,8 @@ public Story(
LanguageId = languageId ?? throw new ArgumentNullException(nameof(languageId));
TeamId = teamId;
Title = title;
}
RoundsCount = 1;
}

public void SetExternalId(int storyExternalId) => ExternalId = storyExternalId;

Expand All @@ -77,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)
Expand All @@ -91,6 +91,8 @@ public void Reset(long participantId, bool hasManagerAccess)

foreach (var storyForEstimate in _storyForEstimates)
storyForEstimate.Reset();

RoundsCount++;
}

public void Finish(long participantId, bool hasManagerAccess)
Expand Down
5 changes: 3 additions & 2 deletions src/Inc.TeamAssistant.Appraiser.Model/Common/StoryDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ namespace Inc.TeamAssistant.Appraiser.Model.Common;
public sealed record StoryDto(
Guid Id,
string Title,
IReadOnlyCollection<string> Links,
IReadOnlyCollection<StoryForEstimateDto> StoryForEstimates,
bool EstimateEnded,
string Mean,
string Median,
string AcceptedValue);
string AcceptedValue,
int RoundsCount,
string? Url);
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ public sealed record SummaryByStory(
int? StoryExternalId,
string StoryTitle,
string StoryType,
IReadOnlyCollection<string> StoryLinks,
bool EstimateEnded,
string Mean,
string Median,
string AcceptedValue,
IReadOnlyCollection<EstimateItemDetails> Items,
IReadOnlyCollection<EstimateDto> Assessments,
bool Accepted,
IReadOnlyCollection<EstimateDto> AssessmentsToAccept);
IReadOnlyCollection<EstimateDto> AssessmentsToAccept,
int RoundsCount,
string? Url);
3 changes: 3 additions & 0 deletions src/Inc.TeamAssistant.Gateway/wwwroot/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
"Appraiser_PowerOfTwo_16SP": "16",
"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",
Expand Down
3 changes: 3 additions & 0 deletions src/Inc.TeamAssistant.Gateway/wwwroot/langs/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
"Appraiser_PowerOfTwo_16SP": "16",
"Appraiser_PowerOfTwo_32SP": "32",
"Appraiser_PowerOfTwo_64SP": "64",
"Appraiser_NumberOfRounds": "Количество раундов оценки",
"Appraiser_MultipleLinkError": "Описание должно содержать одну ссылку",
"Appraiser_LinkLengthError": "Длина ссылки не должна превышать 2000 символов",

"CheckIn_GetStarted": "Добавьте бота в чат для начала работы",
"CheckIn_ConnectLinkText": "Перейдите по ссылке {0} чтобы увидеть наши локации",
Expand Down
27 changes: 27 additions & 0 deletions src/Inc.TeamAssistant.Migrations/2024_11_07_0_AddRoundsCount.cs
Original file line number Diff line number Diff line change
@@ -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");
}
}
Loading

0 comments on commit 918da2c

Please sign in to comment.