Skip to content

Commit 64f8804

Browse files
authored
Merge pull request #14 from GGrouppFoundation/feature/add-channel-to-timesheet
Add channel for timesheet entity
2 parents c27ec3d + e032369 commit 64f8804

File tree

10 files changed

+121
-81
lines changed

10 files changed

+121
-81
lines changed

src/Application/Application.csproj

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,23 @@
88
<InvariantGlobalization>false</InvariantGlobalization>
99
<RootNamespace>GGroupp.Internal.Timesheet</RootNamespace>
1010
<AssemblyName>GGroupp.Internal.Timesheet.Bot.Application</AssemblyName>
11-
<Version>1.1.6</Version>
11+
<Version>1.2.0</Version>
1212
</PropertyGroup>
1313

1414
<PropertyGroup Condition=" '$(RunConfiguration)' == 'Application' " />
1515

1616
<ItemGroup>
17-
<PackageReference Include="GGroupp.Infra.Bot.Builder.Authorization.Dataverse" Version="1.0.0" />
18-
<PackageReference Include="GGroupp.Infra.Bot.Builder.Command.Info" Version="1.0.0" />
19-
<PackageReference Include="GGroupp.Infra.Bot.Builder.Command.Stop" Version="1.0.0" />
20-
<PackageReference Include="GGroupp.Infra.Bot.Builder.Integration.AspNet.Core" Version="1.3.1" />
17+
<PackageReference Include="GGroupp.Infra.Bot.Builder.Authorization.Dataverse" Version="1.1.1" />
18+
<PackageReference Include="GGroupp.Infra.Bot.Builder.Command.Info" Version="1.1.1" />
19+
<PackageReference Include="GGroupp.Infra.Bot.Builder.Command.Stop" Version="1.1.1" />
20+
<PackageReference Include="GGroupp.Infra.Bot.Builder.Integration.AspNet.Core" Version="1.4.0" />
2121
<PackageReference Include="GGroupp.Infra.Bot.Builder.Integration.CosmosDb" Version="1.0.0" />
22-
<PackageReference Include="GGroupp.Infra.Dataverse.Api" Version="2.5.0" />
22+
<PackageReference Include="GGroupp.Infra.Dataverse.Api" Version="2.6.0" />
2323
<PackageReference Include="GGroupp.Infra.Http.SocketsHandlerProvider" Version="2.2.0" />
24-
<PackageReference Include="GGroupp.Internal.Timesheet.ProjectSet.Search.Api" Version="1.3.2" />
25-
<PackageReference Include="GGroupp.Internal.Timesheet.Timesheet.Create.Api" Version="1.3.0" />
26-
<PackageReference Include="GGroupp.Platform.Azure.AzureUser.Get.Api" Version="1.1.0" />
27-
<PackageReference Include="GGroupp.Platform.Dataverse.DataverseUser.Get.Api" Version="1.0.0" />
24+
<PackageReference Include="GGroupp.Internal.Timesheet.ProjectSet.Search.Api" Version="1.4.0" />
25+
<PackageReference Include="GGroupp.Internal.Timesheet.Timesheet.Create.Api" Version="1.4.0" />
26+
<PackageReference Include="GGroupp.Platform.Azure.AzureUser.Get.Api" Version="1.2.0" />
27+
<PackageReference Include="GGroupp.Platform.Dataverse.DataverseUser.Get.Api" Version="1.1.0" />
2828
</ItemGroup>
2929

3030
<ItemGroup>
Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Globalization;
4-
using System.Threading;
53
using GGroupp.Infra.Bot.Builder;
64
using Microsoft.Extensions.Configuration;
75
using Microsoft.Extensions.DependencyInjection;
@@ -14,10 +12,6 @@ internal static IBotBuilder UseGTimesheetBotInfo(this IBotBuilder botBuilder, st
1412
=>
1513
botBuilder.UseBotInfo(commandName, GetBotInfoData);
1614

17-
private static readonly Lazy<TimeZoneInfo> lazyRussianStandardTimeZone
18-
=
19-
new(GetRussianStandardTimeZone, LazyThreadSafetyMode.ExecutionAndPublication);
20-
2115
private static BotInfoData GetBotInfoData(IBotContext botContext)
2216
=>
2317
new(botContext.ServiceProvider.GetRequiredService<IConfiguration>().GetBotInfoData());
@@ -31,19 +25,4 @@ private static BotInfoData GetBotInfoData(IBotContext botContext)
3125
new("Версия сборки", configuration.GetValue<string>("BotBuildVersion")),
3226
new("Время сборки", configuration.GetValue<DateTimeOffset?>("BotBuildDateTime").ToRussianStandardTimeZoneString())
3327
};
34-
35-
private static string? ToRussianStandardTimeZoneString(this DateTimeOffset? dateTime)
36-
{
37-
if (dateTime is null)
38-
{
39-
return default;
40-
}
41-
42-
var russianStandardTime = TimeZoneInfo.ConvertTime(dateTime.Value, lazyRussianStandardTimeZone.Value);
43-
return russianStandardTime.ToString("dd.MM.yyyy HH:mm:ss ('GMT'z)", CultureInfo.InvariantCulture);
44-
}
45-
46-
private static TimeZoneInfo GetRussianStandardTimeZone()
47-
=>
48-
TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
4928
}

src/Application/BotBuilder/Command.TimesheetCreate.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using System;
2+
using System.Collections.Generic;
23
using GGroupp.Infra.Bot.Builder;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.DependencyInjection;
36

47
namespace GGroupp.Internal.Timesheet;
58

@@ -25,6 +28,18 @@ private static ITimesheetCreateFunc GetTimesheetCreateApi(IBotContext botContext
2528
CreateStandardHttpHandlerDependency("TimesheetCreateApi")
2629
.UseDataverseImpersonation(botContext)
2730
.CreateDataverseApiClient()
28-
.UseTimesheetCreateApi()
31+
.UseTimesheetCreateApi(
32+
sp => sp.GetRequiredService<IConfiguration>().GetTimesheetCreateApiConfiguration())
2933
.Resolve(botContext.ServiceProvider);
34+
35+
private static TimesheetCreateApiConfiguration GetTimesheetCreateApiConfiguration(this IConfiguration configuration)
36+
=>
37+
new(
38+
channelCodes: new Dictionary<TimesheetChannel, int?>
39+
{
40+
[TimesheetChannel.Telegram] = configuration.GetValue<int?>("DataverseChannelCodes:Telegram"),
41+
[TimesheetChannel.Teams] = configuration.GetValue<int?>("DataverseChannelCodes:Teams"),
42+
[TimesheetChannel.WebChat] = configuration.GetValue<int?>("DataverseChannelCodes:WebChat"),
43+
[TimesheetChannel.Emulator] = configuration.GetValue<int?>("DataverseChannelCodes:Emulator")
44+
});
3045
}

src/Application/appsettings.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,11 @@
1616
"DataverseApiServiceUrl": "",
1717
"DataverseApiAuthTenantId": "",
1818
"DataverseApiAuthClientId": "",
19-
"DataverseApiAuthClientSecret": ""
19+
"DataverseApiAuthClientSecret": "",
20+
"DataverseChannelCodes": {
21+
"Telegram": 140120000,
22+
"Teams": 140120001,
23+
"WebChat": 140120002,
24+
"Emulator": 140120003
25+
}
2026
}

src/Timesheet.Create/Flow/Flow.CreateTimesheet.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ internal static ChatFlow<Unit> CreateTimesheet(
2323
.ConfirmCreation()
2424
.CreateTimesheet(
2525
timesheetCreateFunc);
26-
}
26+
}

src/Timesheet.Create/Flow/Flow.Recognize.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ partial class TimesheetCreateChatFlow
1010
internal static async ValueTask<Result<ChatFlow, Unit>> InternalRecoginzeOrFailureAsync(
1111
this IBotContext context, string commandName, CancellationToken cancellationToken)
1212
{
13-
var activity = context.TurnContext.Activity;
14-
if (activity.IsNotMessageType())
13+
var turnContext = context.TurnContext;
14+
if (turnContext.IsNotMessageType())
1515
{
1616
return default;
1717
}
@@ -22,6 +22,6 @@ internal static async ValueTask<Result<ChatFlow, Unit>> InternalRecoginzeOrFailu
2222
return chatFlow;
2323
}
2424

25-
return activity.RecognizeCommandOrAbsent(commandName).ToResult().MapSuccess(_ => chatFlow);
25+
return turnContext.RecognizeCommandOrAbsent(commandName).Fold(_ => chatFlow, Result.Absent<ChatFlow>);
2626
}
2727
}

src/Timesheet.Create/Step.Project.Find/ProjectFindFlowStep.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,15 @@ private static TimesheetProjectType ParseProjectType(this LookupValue lookupValu
6969

7070
private static BotFlowFailure MapToFlowFailure(Failure<ProjectSetSearchFailureCode> failure)
7171
=>
72-
new(
73-
userMessage: "При поиске проектов произошла непредвиденная ошибка. Обратитесь к администратору или повторите попытку позднее",
74-
logMessage: failure.FailureMessage);
72+
(failure.FailureCode switch
73+
{
74+
ProjectSetSearchFailureCode.NotAllowed
75+
=> "При поиске проектов произошла ошибка. У вашей учетной записи не достаточно разрешений. Обратитесь к администратору приложения",
76+
ProjectSetSearchFailureCode.TooManyRequests
77+
=> "Слишком много обращений к сервису. Попробуйте повторить попытку через несколько секунд",
78+
_
79+
=> "При поиске проектов произошла непредвиденная ошибка. Обратитесь к администратору или повторите попытку позднее"
80+
})
81+
.Pipe(
82+
message => BotFlowFailure.From(message, failure.FailureMessage));
7583
}

src/Timesheet.Create/Step.Timesheet.Confirm/TimesheetConfirmActivity.cs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Text;
44
using GGroupp.Infra.Bot.Builder;
55
using Microsoft.Bot.Builder;
6-
using Microsoft.Bot.Connector;
76
using Microsoft.Bot.Schema;
87

98
namespace GGroupp.Internal.Timesheet;
@@ -31,7 +30,7 @@ static TimesheetConfirmActivity()
3130

3231
internal static ChatFlowJump<TimesheetCreateFlowStateJson> GetConfirmationResult(this IChatFlowContext<TimesheetCreateFlowStateJson> context)
3332
=>
34-
context.Activity.GetCardActionValueOrAbsent().Fold(
33+
context.GetCardActionValueOrAbsent().Fold(
3534
actionId => actionId switch
3635
{
3736
_ when actionId == ActionCreateId => ChatFlowJump.Next(context.FlowState),
@@ -42,80 +41,82 @@ internal static ChatFlowJump<TimesheetCreateFlowStateJson> GetConfirmationResult
4241

4342
internal static IActivity CreateActivity(IChatFlowContext<TimesheetCreateFlowStateJson> context)
4443
=>
45-
context.Activity.IsCardSupported()
46-
? context.CreateCardSupportedConfirmationActivity()
47-
: context.CreateSimpleConfirmationActivity();
44+
context.IsCardSupported() switch
45+
{
46+
true => context.CreateCardSupportedConfirmationActivity(),
47+
_ => context.CreateSimpleConfirmationActivity()
48+
};
4849

4950
private static IActivity CreateSimpleConfirmationActivity(this IChatFlowContext<TimesheetCreateFlowStateJson> context)
5051
{
51-
var activity = context.Activity;
5252
var flowState = context.FlowState;
5353

54-
var summaryBuilder = activity.CreateSummaryTextBuilder(flowState);
54+
var summaryBuilder = context.CreateSummaryTextBuilder(flowState);
5555
if (string.IsNullOrEmpty(flowState.Description) is false)
5656
{
57-
summaryBuilder = summaryBuilder.AppendLine(activity).AppendRow(activity, "Описание", flowState.Description);
57+
var description = context.EncodeText(flowState.Description);
58+
summaryBuilder = summaryBuilder.AppendLine(context).AppendRow(context, "Описание", description);
5859
}
5960

6061
var card = new HeroCard
6162
{
6263
Title = QuestionText,
63-
Buttons = activity.CreateCardActions()
64+
Buttons = context.CreateCardActions()
6465
};
6566

66-
return MessageFactory.Attachment(card.ToAttachment(), summaryBuilder.ToString().ToEncodedActivityText());
67+
return MessageFactory.Attachment(card.ToAttachment(), summaryBuilder.ToString());
6768
}
6869

6970
private static IActivity CreateCardSupportedConfirmationActivity(this IChatFlowContext<TimesheetCreateFlowStateJson> context)
7071
=>
7172
new HeroCard
7273
{
7374
Title = QuestionText,
74-
Subtitle = context.Activity.CreateSummaryTextBuilder(context.FlowState).ToString(),
75+
Subtitle = context.CreateSummaryTextBuilder(context.FlowState).ToString(),
7576
Text = context.FlowState.Description,
76-
Buttons = context.Activity.CreateCardActions()
77+
Buttons = context.CreateCardActions()
7778
}
7879
.ToAttachment()
7980
.ToActivity();
8081

81-
private static CardAction[] CreateCardActions(this Activity activity)
82+
private static CardAction[] CreateCardActions(this ITurnContext turnContext)
8283
=>
8384
new CardAction[]
8485
{
8586
new(ActionTypes.PostBack)
8687
{
8788
Title = ActionCreateText,
8889
Text = ActionCreateText,
89-
Value = activity.BuildCardActionValue(ActionCreateId)
90+
Value = turnContext.BuildCardActionValue(ActionCreateId)
9091
},
9192
new(ActionTypes.PostBack)
9293
{
9394
Title = ActionCancelText,
9495
Text = ActionCancelText,
95-
Value = activity.BuildCardActionValue(ActionCancelId)
96+
Value = turnContext.BuildCardActionValue(ActionCancelId)
9697
}
9798
};
9899

99-
private static StringBuilder CreateSummaryTextBuilder(this Activity activity, TimesheetCreateFlowStateJson flowStateJson)
100+
private static StringBuilder CreateSummaryTextBuilder(this ITurnContext turnContext, TimesheetCreateFlowStateJson flowStateJson)
100101
=>
101102
Pipeline.Pipe(
102103
new StringBuilder())
103104
.AppendRow(
104-
activity, "Проект", flowStateJson.ProjectName)
105+
turnContext, "Проект", turnContext.EncodeText(flowStateJson.ProjectName))
105106
.AppendLine(
106-
activity)
107+
turnContext)
107108
.AppendRow(
108-
activity, "Дата", flowStateJson.Date.ToString("dd MMMM yyyy", RussianCultureInfo))
109+
turnContext, "Дата", flowStateJson.Date.ToString("dd MMMM yyyy", RussianCultureInfo))
109110
.AppendLine(
110-
activity)
111+
turnContext)
111112
.AppendRow(
112-
activity, "Время", flowStateJson.ValueHours.ToString("G", RussianCultureInfo));
113+
turnContext, "Время", flowStateJson.ValueHours.ToString("G", RussianCultureInfo));
113114

114-
private static StringBuilder AppendRow(this StringBuilder builder, Activity activity, string fieldName, string? fieldValue)
115+
private static StringBuilder AppendRow(this StringBuilder builder, ITurnContext turnContext, string fieldName, string? fieldValue)
115116
{
116117
if (string.IsNullOrEmpty(fieldName) is false)
117118
{
118-
if (activity.ChannelId is Channels.Telegram)
119+
if (turnContext.IsTelegramChannel())
119120
{
120121
_ = builder.Append("**").Append(fieldName).Append(':').Append("**");
121122
}
@@ -133,8 +134,8 @@ private static StringBuilder AppendRow(this StringBuilder builder, Activity acti
133134
return builder;
134135
}
135136

136-
private static StringBuilder AppendLine(this StringBuilder builder, Activity activity)
137+
private static StringBuilder AppendLine(this StringBuilder builder, ITurnContext turnContext)
137138
=>
138139
builder.Append(
139-
activity.ChannelId is Channels.Msteams ? "<br>" : "\n\r\n\r");
140+
turnContext.IsMsteamsChannel() ? "<br>" : "\n\r\n\r");
140141
}

src/Timesheet.Create/Step.Timesheet.Create/TimesheetCreateFlowStep.cs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Threading;
33
using System.Threading.Tasks;
44
using GGroupp.Infra.Bot.Builder;
5+
using Microsoft.Bot.Builder;
56

67
namespace GGroupp.Internal.Timesheet;
78

@@ -16,7 +17,7 @@ internal static ChatFlow<Unit> CreateTimesheet(
1617
chatFlow.ForwardValue(
1718
(context, token) => context.CreateTimesheetAsync(timesheetCreateFunc, token))
1819
.SendText(
19-
_ => "Списание времени создано успешно");
20+
static _ => "Списание времени создано успешно");
2021

2122
private static ValueTask<ChatFlowJump<Unit>> CreateTimesheetAsync(
2223
this IChatFlowContext<TimesheetCreateFlowStateJson> context,
@@ -31,21 +32,51 @@ private static ValueTask<ChatFlowJump<Unit>> CreateTimesheetAsync(
3132
projectId: flowState.ProjectId,
3233
projectType: flowState.ProjectType,
3334
duration: flowState.ValueHours,
34-
description: flowState.Description))
35+
description: flowState.Description,
36+
channel: context.GetChannel()))
3537
.PipeValue(
3638
timesheetCreateFunc.InvokeAsync)
3739
.Map(
3840
Unit.From,
39-
ToUnexpectedBreakState)
41+
ToBreakState)
4042
.Fold(
4143
ChatFlowJump.Next,
4244
ChatFlowJump.Break<Unit>);
4345

44-
private static ChatFlowBreakState ToUnexpectedBreakState<TFailureCode>(
45-
Failure<TFailureCode> failure)
46-
where TFailureCode : struct
46+
private static TimesheetChannel GetChannel(this ITurnContext turnContext)
47+
{
48+
if (turnContext.IsTelegramChannel())
49+
{
50+
return TimesheetChannel.Telegram;
51+
}
52+
53+
if (turnContext.IsMsteamsChannel())
54+
{
55+
return TimesheetChannel.Teams;
56+
}
57+
58+
if (turnContext.IsEmulatorChannel())
59+
{
60+
return TimesheetChannel.Emulator;
61+
}
62+
63+
if (turnContext.IsWebchatChannel())
64+
{
65+
return TimesheetChannel.WebChat;
66+
}
67+
68+
return default;
69+
}
70+
71+
private static ChatFlowBreakState ToBreakState(Failure<TimesheetCreateFailureCode> failure)
4772
=>
48-
ChatFlowBreakState.From(
49-
userMessage: "При создании списания времени произошла непредвиденная ошибка. Обратитесь к администратору или повторите попытку позднее",
50-
logMessage: failure.FailureMessage);
73+
(failure.FailureCode switch
74+
{
75+
TimesheetCreateFailureCode.NotAllowed
76+
=> "Не удалось создать списание времени. Данная операция не разрешена для вашей учетной записи. Обратитесь к администратору",
77+
_
78+
=> "При создании списания времени произошла непредвиденная ошибка. Обратитесь к администратору или повторите попытку позднее"
79+
})
80+
.Pipe(
81+
message => ChatFlowBreakState.From(message, failure.FailureMessage));
5182
}

src/Timesheet.Create/Timesheet.Create.csproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
</PropertyGroup>
1212

1313
<ItemGroup>
14-
<PackageReference Include="EarlyFuncPack.Core.AsyncPipeline" Version="0.0.1" />
15-
<PackageReference Include="GGroupp.Infra.Bot.Builder.ChatFlow.Step.Date" Version="1.1.2" />
16-
<PackageReference Include="GGroupp.Infra.Bot.Builder.ChatFlow.Step.Lookup" Version="1.2.2" />
17-
<PackageReference Include="GGroupp.Infra.Bot.Builder.ChatFlow.Step.Value" Version="1.2.1" />
18-
<PackageReference Include="GGroupp.Internal.Timesheet.ProjectSet.Search.InOut" Version="1.2.0" />
19-
<PackageReference Include="GGroupp.Internal.Timesheet.Timesheet.Create.InOut" Version="1.3.0" />
20-
<PackageReference Include="PrimeFuncPack.Core" Version="1.1.1" />
14+
<PackageReference Include="EarlyFuncPack.Core.AsyncPipeline" Version="0.1.0" />
15+
<PackageReference Include="GGroupp.Infra.Bot.Builder.ChatFlow.Step.Date" Version="1.2.1" />
16+
<PackageReference Include="GGroupp.Infra.Bot.Builder.ChatFlow.Step.Lookup" Version="1.3.1" />
17+
<PackageReference Include="GGroupp.Infra.Bot.Builder.ChatFlow.Step.Value" Version="1.3.1" />
18+
<PackageReference Include="GGroupp.Internal.Timesheet.ProjectSet.Search.InOut" Version="1.3.0" />
19+
<PackageReference Include="GGroupp.Internal.Timesheet.Timesheet.Create.InOut" Version="1.4.0" />
20+
<PackageReference Include="PrimeFuncPack.Core.Failure" Version="2.0.0" />
2121
</ItemGroup>
2222

2323
</Project>

0 commit comments

Comments
 (0)