Контракты

This commit is contained in:
Халимов Рустам
2026-03-29 23:39:17 +03:00
parent 22bc964f27
commit 0209802e9e
141 changed files with 1292 additions and 725 deletions
+198
View File
@@ -171,6 +171,34 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Profiles.UnitTests", "Tests\Users\UnitTests\Knot.Modules.Profiles.UnitTests.csproj", "{6BD8DC02-2270-4276-952E-E34E973A1237}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Profiles.UnitTests", "Tests\Users\UnitTests\Knot.Modules.Profiles.UnitTests.csproj", "{6BD8DC02-2270-4276-952E-E34E973A1237}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Contracts", "Contracts", "{FFBE31B8-50B9-B415-22BC-2F92C97CADA3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Admin.Contracts", "src\Contracts\Knot.Modules.Admin.Contracts\Knot.Modules.Admin.Contracts.csproj", "{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Auth.Contracts", "src\Contracts\Knot.Modules.Auth.Contracts\Knot.Modules.Auth.Contracts.csproj", "{E8C0F163-735D-44A2-B684-673A0B0D7D2A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Conversations.Contracts", "src\Contracts\Knot.Modules.Conversations.Contracts\Knot.Modules.Conversations.Contracts.csproj", "{65E67218-A02C-4C42-8B60-6FDAB737E613}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Federation.Contracts", "src\Contracts\Knot.Modules.Federation.Contracts\Knot.Modules.Federation.Contracts.csproj", "{7226D94C-B9A5-41D7-9E59-50A68F39EE78}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Klipy.Contracts", "src\Contracts\Knot.Modules.Klipy.Contracts\Knot.Modules.Klipy.Contracts.csproj", "{4AC0C433-475F-4B0C-B160-E4F33779E3CB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Messaging.Contracts", "src\Contracts\Knot.Modules.Messaging.Contracts\Knot.Modules.Messaging.Contracts.csproj", "{9D86914A-43A8-4451-BEFD-092ABFF793D6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Profiles.Contracts", "src\Contracts\Knot.Modules.Profiles.Contracts\Knot.Modules.Profiles.Contracts.csproj", "{1DC69DD3-3348-4375-844C-D44A760D50EC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Relations.Contracts", "src\Contracts\Knot.Modules.Relations.Contracts\Knot.Modules.Relations.Contracts.csproj", "{352A455F-AC3F-4D34-BADA-574BF83E131C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Settings.Contracts", "src\Contracts\Knot.Modules.Settings.Contracts\Knot.Modules.Settings.Contracts.csproj", "{D10F0FA0-A682-42D4-A23F-46094D14A8F6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Storage.Contracts", "src\Contracts\Knot.Modules.Storage.Contracts\Knot.Modules.Storage.Contracts.csproj", "{F57F6152-A359-4BB5-AC01-5531C85EE47A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Stories.Contracts", "src\Contracts\Knot.Modules.Stories.Contracts\Knot.Modules.Stories.Contracts.csproj", "{32631ED6-956A-4572-AD7A-B8D0ECE26C78}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.TelegramImport.Contracts", "src\Contracts\Knot.Modules.TelegramImport.Contracts\Knot.Modules.TelegramImport.Contracts.csproj", "{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.WebRtc.Contracts", "src\Contracts\Knot.Modules.WebRtc.Contracts\Knot.Modules.WebRtc.Contracts.csproj", "{623330CA-6CA5-4B74-A921-DEAE8002FCC5}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -601,6 +629,162 @@ Global
{6BD8DC02-2270-4276-952E-E34E973A1237}.Release|x64.Build.0 = Release|Any CPU {6BD8DC02-2270-4276-952E-E34E973A1237}.Release|x64.Build.0 = Release|Any CPU
{6BD8DC02-2270-4276-952E-E34E973A1237}.Release|x86.ActiveCfg = Release|Any CPU {6BD8DC02-2270-4276-952E-E34E973A1237}.Release|x86.ActiveCfg = Release|Any CPU
{6BD8DC02-2270-4276-952E-E34E973A1237}.Release|x86.Build.0 = Release|Any CPU {6BD8DC02-2270-4276-952E-E34E973A1237}.Release|x86.Build.0 = Release|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Debug|x64.ActiveCfg = Debug|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Debug|x64.Build.0 = Debug|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Debug|x86.ActiveCfg = Debug|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Debug|x86.Build.0 = Debug|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Release|Any CPU.Build.0 = Release|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Release|x64.ActiveCfg = Release|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Release|x64.Build.0 = Release|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Release|x86.ActiveCfg = Release|Any CPU
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF}.Release|x86.Build.0 = Release|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Debug|x64.ActiveCfg = Debug|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Debug|x64.Build.0 = Debug|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Debug|x86.ActiveCfg = Debug|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Debug|x86.Build.0 = Debug|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Release|Any CPU.Build.0 = Release|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Release|x64.ActiveCfg = Release|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Release|x64.Build.0 = Release|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Release|x86.ActiveCfg = Release|Any CPU
{E8C0F163-735D-44A2-B684-673A0B0D7D2A}.Release|x86.Build.0 = Release|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Debug|x64.ActiveCfg = Debug|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Debug|x64.Build.0 = Debug|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Debug|x86.ActiveCfg = Debug|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Debug|x86.Build.0 = Debug|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Release|Any CPU.Build.0 = Release|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Release|x64.ActiveCfg = Release|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Release|x64.Build.0 = Release|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Release|x86.ActiveCfg = Release|Any CPU
{65E67218-A02C-4C42-8B60-6FDAB737E613}.Release|x86.Build.0 = Release|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Debug|x64.ActiveCfg = Debug|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Debug|x64.Build.0 = Debug|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Debug|x86.ActiveCfg = Debug|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Debug|x86.Build.0 = Debug|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Release|Any CPU.Build.0 = Release|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Release|x64.ActiveCfg = Release|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Release|x64.Build.0 = Release|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Release|x86.ActiveCfg = Release|Any CPU
{7226D94C-B9A5-41D7-9E59-50A68F39EE78}.Release|x86.Build.0 = Release|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Debug|x64.ActiveCfg = Debug|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Debug|x64.Build.0 = Debug|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Debug|x86.ActiveCfg = Debug|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Debug|x86.Build.0 = Debug|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Release|Any CPU.Build.0 = Release|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Release|x64.ActiveCfg = Release|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Release|x64.Build.0 = Release|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Release|x86.ActiveCfg = Release|Any CPU
{4AC0C433-475F-4B0C-B160-E4F33779E3CB}.Release|x86.Build.0 = Release|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Debug|x64.ActiveCfg = Debug|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Debug|x64.Build.0 = Debug|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Debug|x86.ActiveCfg = Debug|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Debug|x86.Build.0 = Debug|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Release|Any CPU.Build.0 = Release|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Release|x64.ActiveCfg = Release|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Release|x64.Build.0 = Release|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Release|x86.ActiveCfg = Release|Any CPU
{9D86914A-43A8-4451-BEFD-092ABFF793D6}.Release|x86.Build.0 = Release|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Debug|x64.ActiveCfg = Debug|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Debug|x64.Build.0 = Debug|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Debug|x86.ActiveCfg = Debug|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Debug|x86.Build.0 = Debug|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Release|Any CPU.Build.0 = Release|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Release|x64.ActiveCfg = Release|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Release|x64.Build.0 = Release|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Release|x86.ActiveCfg = Release|Any CPU
{1DC69DD3-3348-4375-844C-D44A760D50EC}.Release|x86.Build.0 = Release|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Debug|x64.ActiveCfg = Debug|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Debug|x64.Build.0 = Debug|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Debug|x86.ActiveCfg = Debug|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Debug|x86.Build.0 = Debug|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Release|Any CPU.Build.0 = Release|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Release|x64.ActiveCfg = Release|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Release|x64.Build.0 = Release|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Release|x86.ActiveCfg = Release|Any CPU
{352A455F-AC3F-4D34-BADA-574BF83E131C}.Release|x86.Build.0 = Release|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Debug|x64.ActiveCfg = Debug|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Debug|x64.Build.0 = Debug|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Debug|x86.ActiveCfg = Debug|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Debug|x86.Build.0 = Debug|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Release|Any CPU.Build.0 = Release|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Release|x64.ActiveCfg = Release|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Release|x64.Build.0 = Release|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Release|x86.ActiveCfg = Release|Any CPU
{D10F0FA0-A682-42D4-A23F-46094D14A8F6}.Release|x86.Build.0 = Release|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Debug|x64.ActiveCfg = Debug|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Debug|x64.Build.0 = Debug|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Debug|x86.ActiveCfg = Debug|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Debug|x86.Build.0 = Debug|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Release|Any CPU.Build.0 = Release|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Release|x64.ActiveCfg = Release|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Release|x64.Build.0 = Release|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Release|x86.ActiveCfg = Release|Any CPU
{F57F6152-A359-4BB5-AC01-5531C85EE47A}.Release|x86.Build.0 = Release|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Debug|x64.ActiveCfg = Debug|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Debug|x64.Build.0 = Debug|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Debug|x86.ActiveCfg = Debug|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Debug|x86.Build.0 = Debug|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Release|Any CPU.Build.0 = Release|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Release|x64.ActiveCfg = Release|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Release|x64.Build.0 = Release|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Release|x86.ActiveCfg = Release|Any CPU
{32631ED6-956A-4572-AD7A-B8D0ECE26C78}.Release|x86.Build.0 = Release|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Debug|x64.ActiveCfg = Debug|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Debug|x64.Build.0 = Debug|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Debug|x86.ActiveCfg = Debug|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Debug|x86.Build.0 = Debug|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Release|Any CPU.Build.0 = Release|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Release|x64.ActiveCfg = Release|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Release|x64.Build.0 = Release|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Release|x86.ActiveCfg = Release|Any CPU
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5}.Release|x86.Build.0 = Release|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Debug|x64.ActiveCfg = Debug|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Debug|x64.Build.0 = Debug|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Debug|x86.ActiveCfg = Debug|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Debug|x86.Build.0 = Debug|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Release|Any CPU.Build.0 = Release|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Release|x64.ActiveCfg = Release|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Release|x64.Build.0 = Release|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Release|x86.ActiveCfg = Release|Any CPU
{623330CA-6CA5-4B74-A921-DEAE8002FCC5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -688,5 +872,19 @@ Global
{553D81D4-666B-BE26-75F9-480CB214ACEE} = {0AB3BF05-4346-4AA6-1389-037BE0695223} {553D81D4-666B-BE26-75F9-480CB214ACEE} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{3A48F700-9635-2216-D291-85337CE5D869} = {553D81D4-666B-BE26-75F9-480CB214ACEE} {3A48F700-9635-2216-D291-85337CE5D869} = {553D81D4-666B-BE26-75F9-480CB214ACEE}
{6BD8DC02-2270-4276-952E-E34E973A1237} = {3A48F700-9635-2216-D291-85337CE5D869} {6BD8DC02-2270-4276-952E-E34E973A1237} = {3A48F700-9635-2216-D291-85337CE5D869}
{FFBE31B8-50B9-B415-22BC-2F92C97CADA3} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{1D50E7AA-2378-4114-A3C3-E351D46FB8BF} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{E8C0F163-735D-44A2-B684-673A0B0D7D2A} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{65E67218-A02C-4C42-8B60-6FDAB737E613} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{7226D94C-B9A5-41D7-9E59-50A68F39EE78} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{4AC0C433-475F-4B0C-B160-E4F33779E3CB} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{9D86914A-43A8-4451-BEFD-092ABFF793D6} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{1DC69DD3-3348-4375-844C-D44A760D50EC} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{352A455F-AC3F-4D34-BADA-574BF83E131C} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{D10F0FA0-A682-42D4-A23F-46094D14A8F6} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{F57F6152-A359-4BB5-AC01-5531C85EE47A} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{32631ED6-956A-4572-AD7A-B8D0ECE26C78} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{7E22E87D-78D2-411D-AC30-2F090C3F5ED5} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
{623330CA-6CA5-4B74-A921-DEAE8002FCC5} = {FFBE31B8-50B9-B415-22BC-2F92C97CADA3}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
@@ -1,7 +1,7 @@
using FluentAssertions; using FluentAssertions;
using Knot.Modules.Admin.Application.Admin.Commands; using Knot.Modules.Admin.Application.Admin.Commands;
using Knot.Modules.Auth.Application.Abstractions; using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;
@@ -1,8 +1,8 @@
using FluentAssertions; using FluentAssertions;
using NSubstitute; using NSubstitute;
using Knot.Modules.Auth.Application.Abstractions; using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Modules.Auth.Application.Users.Login; using Knot.Modules.Auth.Application.Users.Login;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Auth.Application.Users.Auth; using Knot.Modules.Auth.Application.Users.Auth;
using Xunit; using Xunit;
@@ -12,8 +12,8 @@ using Knot.Modules.Conversations.Domain;
using Knot.Modules.Messaging.Domain; using Knot.Modules.Messaging.Domain;
using Knot.Modules.Conversations.Application.Abstractions; using Knot.Modules.Conversations.Application.Abstractions;
using Knot.Modules.Conversations.Application.Messages.Send; using Knot.Modules.Conversations.Application.Messages.Send;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
namespace Knot.Modules.Conversations.UnitTests.Messages; namespace Knot.Modules.Conversations.UnitTests.Messages;
@@ -34,7 +34,7 @@ public class SendMessageCommandHandlerTests
_mediator = Substitute.For<IMediator>(); _mediator = Substitute.For<IMediator>();
_messagesSettings = Substitute.For<IMessagesSettings>(); _messagesSettings = Substitute.For<IMessagesSettings>();
var config = new Knot.Modules.Settings.Application.Settings.DTOs.MessagesConfig(); var config = new Knot.Modules.Settings.Contracts.Application.DTOs.MessagesConfig();
_messagesSettings.Current.Returns(config); _messagesSettings.Current.Returns(config);
_handler = new SendMessageCommandHandler(_chatRepository, _messageRepository, _unitOfWork, _mediator, _messagesSettings); _handler = new SendMessageCommandHandler(_chatRepository, _messageRepository, _unitOfWork, _mediator, _messagesSettings);
@@ -2,8 +2,8 @@ using FluentAssertions;
using Knot.Modules.Stories.Application.Stories.Commands.CreateStory; using Knot.Modules.Stories.Application.Stories.Commands.CreateStory;
using Knot.Modules.Stories.Domain; using Knot.Modules.Stories.Domain;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Modules.Stories.Application.Abstractions; using Knot.Modules.Stories.Application.Abstractions;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;
@@ -1,13 +1,13 @@
using FluentAssertions; using FluentAssertions;
using Knot.Modules.Profiles.Application.Profiles.UpdateProfile; using Knot.Modules.Profiles.Application.Profiles.UpdateProfile;
using Knot.Modules.Profiles.Domain; using Knot.Modules.Profiles.Contracts.Domain;
using Knot.Modules.Profiles.Contracts.Application.DTOs;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Knot.Modules.Profiles.Application.Abstractions;
namespace Knot.Modules.Profiles.UnitTests; namespace Knot.Modules.Profiles.UnitTests;
@@ -27,7 +27,7 @@ public class UpdateProfileCommandHandlerTests
{ {
// Arrange // Arrange
var command = new UpdateProfileCommand(Guid.NewGuid(), "FirstName", "Bio", null); var command = new UpdateProfileCommand(Guid.NewGuid(), "FirstName", "Bio", null);
_profileRepository.GetByIdAsync(command.UserId, Arg.Any<CancellationToken>()).Returns((ProfileDocument?)null); _profileRepository.GetAsync(command.UserId, Arg.Any<CancellationToken>()).Returns((UserProfileDto?)null);
// Act // Act
var result = await _handler.Handle(command, CancellationToken.None); var result = await _handler.Handle(command, CancellationToken.None);
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
namespace Knot.Modules.Auth.Contracts.Application.Abstractions;
public interface IAuthDbContext
{
DbSet<T> Set<T>() where T : class;
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}
@@ -0,0 +1,11 @@
using Knot.Modules.Auth.Contracts.Domain;
using Knot.Shared.Kernel;
namespace Knot.Modules.Auth.Contracts.Application.Abstractions;
public interface IAuthUnitOfWork : IUnitOfWork
{
IUserRepository UserRepository { get; }
void Add(UserContract user);
Task<int> SaveChangesAsync(CancellationToken ct = default);
}
@@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
namespace Knot.Modules.Auth.Contracts.Application.Abstractions;
public interface IIdentityDbContext
{
DbSet<T> Set<T>() where T : class;
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}
@@ -0,0 +1,9 @@
using Knot.Modules.Auth.Contracts.Domain;
using Knot.Shared.Kernel;
namespace Knot.Modules.Auth.Contracts.Application.Abstractions;
public interface IIdentityUnitOfWork : IUnitOfWork
{
IUserRepository UserRepository { get; }
}
@@ -0,0 +1,8 @@
namespace Knot.Modules.Auth.Contracts.Application.Abstractions;
public interface IJwtTokenProvider
{
string GenerateAccessToken(Guid userId, string username);
string GenerateRefreshToken();
string Generate(Guid userId, string username, string displayName, string? avatar);
}
@@ -0,0 +1,11 @@
using Knot.Shared.Kernel;
namespace Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
public static class AuthErrors
{
public static Error IdentityInvalidCredentials => new("Auth.InvalidCredentials", "Invalid credentials");
public static Error IdentityRegistrationDisabled => new("Auth.RegistrationDisabled", "Registration is disabled");
public static Error IdentityUsernameNotUnique => new("Auth.UsernameNotUnique", "Username is already taken");
public static Error UserNotFound => new("Auth.UserNotFound", "User not found");
}
@@ -0,0 +1,16 @@
namespace Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
public class AuthResponseDto
{
public required string AccessToken { get; set; }
public required string RefreshToken { get; set; }
public Guid UserId { get; set; }
public string Username { get; set; } = string.Empty;
public string? DisplayName { get; set; }
}
public class ResetPasswordDto
{
public required string Token { get; set; }
public required string NewPassword { get; set; }
}
@@ -0,0 +1,6 @@
using Knot.Modules.Auth.Contracts.Domain;
using MediatR;
namespace Knot.Modules.Auth.Contracts.Application.Users.GetMe;
public record GetMeQuery() : IRequest<UserContract>;
@@ -0,0 +1,10 @@
using Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
using Knot.Shared.Kernel;
using MediatR;
namespace Knot.Modules.Auth.Contracts.Application.Users.Login;
public record LoginUserCommand(
string Username,
string Password
) : IRequest<Result<AuthResponseDto>>;
@@ -0,0 +1,14 @@
using Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
using Knot.Modules.Auth.Contracts.Domain;
using Knot.Shared.Kernel;
using MediatR;
namespace Knot.Modules.Auth.Contracts.Application.Users.Register;
public record RegisterUserCommand(
string Username,
string Password,
string DisplayName,
string? PhoneNumber,
bool IsBot = false
) : IRequest<Result<AuthResponseDto>>;
@@ -0,0 +1,16 @@
namespace Knot.Modules.Auth.Contracts.Domain;
public interface IUserRepository
{
Task<UserContract?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<List<UserContract>> GetByIdsAsync(IEnumerable<Guid> ids, CancellationToken cancellationToken = default);
Task<UserContract?> GetByUsernameAsync(string username, CancellationToken cancellationToken = default);
Task<bool> IsUsernameUniqueAsync(string username, CancellationToken cancellationToken = default);
Task<List<UserContract>> SearchUsersAsync(string query, CancellationToken cancellationToken = default);
Task<bool> IsBannedAsync(Guid userId, CancellationToken cancellationToken = default);
Task<UserContract?> GetByRefreshTokenAsync(string refreshToken, CancellationToken cancellationToken = default);
Task UpdateAsync(UserContract user, CancellationToken cancellationToken = default);
void Add(UserContract user);
Task RemoveAsync(UserContract user, CancellationToken cancellationToken = default);
void Update(UserContract user);
}
@@ -0,0 +1,22 @@
namespace Knot.Modules.Auth.Contracts.Domain;
public class UserContract
{
public Guid Id { get; set; }
public string Username { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string PasswordHash { get; set; } = string.Empty;
public string? PhoneNumber { get; set; }
public string? Email { get; set; }
public string? Bio { get; set; }
public string? Avatar { get; set; }
public DateTime? Birthday { get; set; }
public bool IsBot { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? BannedUntil { get; set; }
public bool IsBanned { get; set; }
public bool IsOnline { get; set; }
public bool IsExternal { get; set; }
public string? Domain { get; set; }
public DateTime? LastSeen { get; set; }
}
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.4" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,12 @@
using Knot.Shared.Kernel;
namespace Knot.Modules.Profiles.Contracts.Application.DTOs;
public static class ProfilesErrors
{
public static Error ProfileNotFound => new("Profiles.NotFound", "Profile not found");
public static Error UsernameAlreadyExists => new("Profiles.UsernameExists", "Username already exists");
public static Error AvatarNotFound => new("Profiles.AvatarNotFound", "Avatar not found");
public static Error InvalidAvatarFormat => new("Profiles.InvalidAvatarFormat", "Invalid avatar format");
public static Error AvatarUploadFailed => new("Profiles.AvatarUploadFailed", "Avatar upload failed");
}
@@ -0,0 +1,21 @@
using MediatR;
namespace Knot.Modules.Profiles.Contracts.Application.DTOs;
public record SearchProfilesRequest(string Query, int Limit = 20) : IRequest<List<UserProfileDto>>;
public record UpdateProfileRequest(
string? DisplayName,
string? About,
string? Avatar,
bool RemoveAvatar = false
) : IRequest<UserProfileDto>;
public record UpdateSettingsRequest(
bool? ShowLastSeen,
bool? ShowAvatar,
bool? ShowAbout,
bool? ShowPhoneNumber,
bool? ShowForwardedMessages,
bool? ShowAddToGroupPermission
) : IRequest<UserProfileDto>;
@@ -0,0 +1,14 @@
namespace Knot.Modules.Profiles.Contracts.Application.DTOs;
public class UserProfileDto
{
public Guid UserId { get; set; }
public string? DisplayName { get; set; }
public string? Username { get; set; }
public string? About { get; set; }
public string? Avatar { get; set; }
public bool IsBot { get; set; }
public DateTime? LastSeen { get; set; }
public bool IsPremium { get; set; }
public DateTime CreatedAt { get; set; }
}
@@ -0,0 +1,10 @@
using Knot.Shared.Kernel;
using MediatR;
namespace Knot.Modules.Profiles.Contracts.Application.Profiles.Avatar;
public record UploadAvatarCommand(Stream Stream, string FileName) : IRequest<Result<string>>;
public record DeleteAvatarCommand() : IRequest<Result>;
public record CropAvatarCommand(int X, int Y, int Width, int Height) : IRequest<Result<string>>;
@@ -0,0 +1,9 @@
using Knot.Modules.Profiles.Contracts.Application.DTOs;
using Knot.Shared.Kernel;
using MediatR;
namespace Knot.Modules.Profiles.Contracts.Application.Profiles.GetUser;
public record GetProfileQuery(Guid UserId) : IRequest<Result<UserProfileDto>>;
public record GetCurrentUserQuery() : IRequest<Result<UserProfileDto>>;
@@ -0,0 +1,6 @@
using Knot.Modules.Profiles.Contracts.Application.DTOs;
using MediatR;
namespace Knot.Modules.Profiles.Contracts.Application.Profiles.Search;
public record SearchProfilesQuery(string Query, int Limit = 20) : IRequest<List<UserProfileDto>>;
@@ -0,0 +1,12 @@
using Knot.Modules.Profiles.Contracts.Application.DTOs;
using Knot.Shared.Kernel;
using MediatR;
namespace Knot.Modules.Profiles.Contracts.Application.Profiles.UpdateProfile;
public record UpdateProfileCommand(
string? DisplayName,
string? About,
string? Avatar,
bool RemoveAvatar = false
) : IRequest<Result<UserProfileDto>>;
@@ -0,0 +1,14 @@
using Knot.Modules.Profiles.Contracts.Application.DTOs;
using Knot.Shared.Kernel;
using MediatR;
namespace Knot.Modules.Profiles.Contracts.Application.Profiles.UpdateSettings;
public record UpdateSettingsCommand(
bool? ShowLastSeen,
bool? ShowAvatar,
bool? ShowAbout,
bool? ShowPhoneNumber,
bool? ShowForwardedMessages,
bool? ShowAddToGroupPermission
) : IRequest<Result<UserProfileDto>>;
@@ -0,0 +1,11 @@
using Knot.Shared.Kernel.Storage;
namespace Knot.Modules.Profiles.Contracts.Domain;
public interface IAvatarStorageService
{
Task<string> UploadAsync(Stream stream, string fileName, string contentType, CancellationToken cancellationToken = default);
Task DeleteAsync(string fileKey, CancellationToken cancellationToken = default);
Task<Stream?> GetAsync(string fileKey, CancellationToken cancellationToken = default);
string GetFileUrl(string fileKey);
}
@@ -0,0 +1,15 @@
using Knot.Modules.Profiles.Contracts.Application.DTOs;
using Knot.Shared.Kernel;
namespace Knot.Modules.Profiles.Contracts.Domain;
public interface IProfileRepository
{
Task<UserProfileDto?> GetAsync(Guid userId, CancellationToken cancellationToken = default);
Task<UserProfileDto?> GetByUsernameAsync(string username, CancellationToken cancellationToken = default);
Task<List<UserProfileDto>> GetAsync(IEnumerable<Guid> userIds, CancellationToken cancellationToken = default);
Task<List<UserProfileDto>> SearchAsync(string query, int limit = 20, CancellationToken cancellationToken = default);
Task<Result<UserProfileDto>> CreateAsync(UserProfileDto dto, CancellationToken cancellationToken = default);
Task<Result<UserProfileDto>> UpdateAsync(UserProfileDto dto, CancellationToken cancellationToken = default);
Task<Result> DeleteAsync(Guid userId, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,8 @@
using Knot.Shared.Kernel;
namespace Knot.Modules.Profiles.Contracts.Domain;
public interface IProfilesUnitOfWork : IUnitOfWork
{
IProfileRepository ProfileRepository { get; }
}
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -1,8 +1,6 @@
using System.Threading; using Knot.Modules.Settings.Contracts.Application.DTOs;
using System.Threading.Tasks;
using Knot.Modules.Settings.Application.Settings.DTOs;
namespace Knot.Modules.Settings.Application.Settings.Abstractions; namespace Knot.Modules.Settings.Contracts.Application.Abstractions;
public interface ISettingsService public interface ISettingsService
{ {
@@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Knot.Modules.Settings.Application.Settings.DTOs; namespace Knot.Modules.Settings.Contracts.Application.DTOs;
public class SystemConfig public class SystemConfig
{ {
@@ -25,7 +25,7 @@ public class ChatsConfig
{ {
public bool SupportGroups { get; set; } = true; public bool SupportGroups { get; set; } = true;
public int MaxGroupParticipants { get; set; } = 200000; public int MaxGroupParticipants { get; set; } = 200000;
public bool EnableAutoClean { get; set; } = false; // Возможность автоочистки для пользователей public bool EnableAutoClean { get; set; } = false;
public bool AllowChatToGroupConversion { get; set; } = true; public bool AllowChatToGroupConversion { get; set; } = true;
public bool EnableFolders { get; set; } = true; public bool EnableFolders { get; set; } = true;
} }
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MediatR" Version="12.0.1" />
</ItemGroup>
</Project>
+3
View File
@@ -32,6 +32,7 @@
<ProjectReference Include="..\Shared\Knot.Shared.Infrastructure\Knot.Shared.Infrastructure.csproj" /> <ProjectReference Include="..\Shared\Knot.Shared.Infrastructure\Knot.Shared.Infrastructure.csproj" />
<ProjectReference Include="..\Modules\Storage\Knot.Modules.Storage.csproj" /> <ProjectReference Include="..\Modules\Storage\Knot.Modules.Storage.csproj" />
<ProjectReference Include="..\Modules\Auth\Knot.Modules.Auth.csproj" /> <ProjectReference Include="..\Modules\Auth\Knot.Modules.Auth.csproj" />
<ProjectReference Include="..\Modules\Profiles\Knot.Modules.Profiles.csproj" />
<ProjectReference Include="..\Modules\Messaging\Knot.Modules.Messaging.csproj" /> <ProjectReference Include="..\Modules\Messaging\Knot.Modules.Messaging.csproj" />
<ProjectReference Include="..\Modules\TelegramImport\Knot.Modules.TelegramImport.csproj" /> <ProjectReference Include="..\Modules\TelegramImport\Knot.Modules.TelegramImport.csproj" />
<ProjectReference Include="..\Modules\Conversations\Knot.Modules.Conversations.csproj" /> <ProjectReference Include="..\Modules\Conversations\Knot.Modules.Conversations.csproj" />
@@ -39,7 +40,9 @@
<ProjectReference Include="..\Modules\WebRtc\Knot.Modules.WebRtc.csproj" /> <ProjectReference Include="..\Modules\WebRtc\Knot.Modules.WebRtc.csproj" />
<ProjectReference Include="..\Modules\Federation\Knot.Modules.Federation.csproj" /> <ProjectReference Include="..\Modules\Federation\Knot.Modules.Federation.csproj" />
<ProjectReference Include="..\Modules\Klipy\Knot.Modules.Klipy.csproj" /> <ProjectReference Include="..\Modules\Klipy\Knot.Modules.Klipy.csproj" />
<ProjectReference Include="..\Modules\Relations\Knot.Modules.Relations.csproj" />
<ProjectReference Include="..\Modules\Settings\Knot.Modules.Settings.csproj" /> <ProjectReference Include="..\Modules\Settings\Knot.Modules.Settings.csproj" />
<ProjectReference Include="..\Modules\Stories\Knot.Modules.Stories.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+1 -1
View File
@@ -190,7 +190,7 @@ using (var scope = app.Services.CreateScope())
Knot.Modules.Messaging.Infrastructure.Persistence.Mongo.EncryptedStringSerializer.EncryptionService = encryptionService; Knot.Modules.Messaging.Infrastructure.Persistence.Mongo.EncryptedStringSerializer.EncryptionService = encryptionService;
// Initialize Global Settings Cache // Initialize Global Settings Cache
var settingsService = scope.ServiceProvider.GetRequiredService<Knot.Modules.Settings.Application.Settings.Abstractions.ISettingsService>(); var settingsService = scope.ServiceProvider.GetRequiredService<Knot.Modules.Settings.Contracts.Application.Abstractions.ISettingsService>();
if (settingsService is Knot.Modules.Settings.Infrastructure.Configuration.SettingsService concreteSettings) if (settingsService is Knot.Modules.Settings.Infrastructure.Configuration.SettingsService concreteSettings)
{ {
concreteSettings.Initialize(); concreteSettings.Initialize();
@@ -1,10 +1,10 @@
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Shared.Kernel;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel;
using Knot.Modules.Auth.Application.Abstractions;
namespace Knot.Modules.Admin.Application.Admin.Commands; namespace Knot.Modules.Admin.Application.Admin.Commands;
@@ -26,7 +26,10 @@ internal sealed class BanUserCommandHandler : ICommandHandler<BanUserCommand, Re
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken); var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
if (user == null) return Result.Failure<Result>(Error.NotFound("User.NotFound", "User not found")); if (user == null) return Result.Failure<Result>(Error.NotFound("User.NotFound", "User not found"));
user.Ban(); user.IsBanned = true;
user.BannedUntil = null; // Permanent ban
await _userRepository.UpdateAsync(user, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken); await _unitOfWork.SaveChangesAsync(cancellationToken);
return Result.Success(Result.Success()); return Result.Success(Result.Success());
} }
@@ -1,10 +1,10 @@
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Shared.Kernel;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel;
using Knot.Modules.Auth.Application.Abstractions;
namespace Knot.Modules.Admin.Application.Admin.Commands; namespace Knot.Modules.Admin.Application.Admin.Commands;
@@ -26,7 +26,10 @@ internal sealed class UnbanUserCommandHandler : ICommandHandler<UnbanUserCommand
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken); var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
if (user == null) return Result.Failure<Result>(Error.NotFound("User.NotFound", "User not found")); if (user == null) return Result.Failure<Result>(Error.NotFound("User.NotFound", "User not found"));
user.Unban(); user.IsBanned = false;
user.BannedUntil = null;
await _userRepository.UpdateAsync(user, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken); await _unitOfWork.SaveChangesAsync(cancellationToken);
return Result.Success(Result.Success()); return Result.Success(Result.Success());
} }
@@ -1,15 +1,12 @@
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
using Knot.Modules.Admin.Application.Admin.DTOs; using Knot.Modules.Admin.Application.Admin.DTOs;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Auth.Application.Auth.DTOs;
using Knot.Modules.Auth.Application.Users;
using Knot.Modules.Auth.Infrastructure.Persistence;
using Knot.Modules.Auth.Application.Abstractions;
namespace Knot.Modules.Admin.Application.Admin.Commands; namespace Knot.Modules.Admin.Application.Admin.Commands;
@@ -35,11 +32,12 @@ internal sealed class ResetUserPasswordCommandHandler : ICommandHandler<ResetUse
} }
if (string.IsNullOrWhiteSpace(request.NewPassword)) if (string.IsNullOrWhiteSpace(request.NewPassword))
return Result.Failure<SuccessResponse>(DomainErrors.InvalidPassword); return Result.Failure<SuccessResponse>(new Error("Admin.InvalidPassword", "Invalid password"));
var hash = BCrypt.Net.BCrypt.HashPassword(request.NewPassword); var hash = BCrypt.Net.BCrypt.HashPassword(request.NewPassword);
user.ChangePassword(hash); user.PasswordHash = hash;
await _userRepository.UpdateAsync(user, cancellationToken);
await _identityUnitOfWork.SaveChangesAsync(cancellationToken); await _identityUnitOfWork.SaveChangesAsync(cancellationToken);
return Result.Success(new SuccessResponse(true)); return Result.Success(new SuccessResponse(true));
} }
@@ -2,8 +2,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Modules.Klipy.Application.Abstractions; using Knot.Modules.Klipy.Application.Abstractions;
namespace Knot.Modules.Admin.Application.Admin.Commands.TestKlipy; namespace Knot.Modules.Admin.Application.Admin.Commands.TestKlipy;
@@ -4,8 +4,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using System.Security.Cryptography; using System.Security.Cryptography;
namespace Knot.Modules.Admin.Application.Admin.Commands; namespace Knot.Modules.Admin.Application.Admin.Commands;
@@ -4,8 +4,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
namespace Knot.Modules.Admin.Application.Admin.Queries; namespace Knot.Modules.Admin.Application.Admin.Queries;
@@ -1,4 +1,5 @@
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
using Knot.Modules.Admin.Application.Admin.DTOs; using Knot.Modules.Admin.Application.Admin.DTOs;
using Knot.Modules.Messaging.Domain; using Knot.Modules.Messaging.Domain;
using System; using System;
@@ -7,9 +8,6 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Auth.Application.Auth.DTOs;
using Knot.Modules.Auth.Application.Users;
using Knot.Modules.Conversations.Domain; using Knot.Modules.Conversations.Domain;
using MongoDB.Driver; using MongoDB.Driver;
@@ -77,7 +75,7 @@ internal sealed class GetUserDetailsQueryHandler : IQueryHandler<GetUserDetailsQ
targetUser.Avatar, targetUser.Avatar,
targetUser.CreatedAt, targetUser.CreatedAt,
isOnline, isOnline,
isOnline ? DateTime.UtcNow : (targetUser.LastSeen ?? targetUser.CreatedAt), isOnline ? DateTime.UtcNow : (targetUser.CreatedAt),
targetUser.IsBanned, targetUser.IsBanned,
new AdminUserStatsDto( new AdminUserStatsDto(
messagesCount, messagesCount,
@@ -1,3 +1,4 @@
using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Admin.Application.Admin.DTOs; using Knot.Modules.Admin.Application.Admin.DTOs;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,8 +7,6 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Auth.Application.Users;
using Knot.Modules.Auth.Domain;
using Knot.Modules.Messaging.Application.Abstractions; using Knot.Modules.Messaging.Application.Abstractions;
using Knot.Modules.Conversations.Application.Abstractions; using Knot.Modules.Conversations.Application.Abstractions;
@@ -35,16 +34,16 @@ internal sealed class SearchUsersQueryHandler : IQueryHandler<SearchUsersQuery,
{ {
try try
{ {
// 1. Поиск пользователей в реляционной БД // 1. Ïîèñê ïîëüçîâàòåëåé â ðåëÿöèîííîé ÁÄ
var users = await _userRepository.SearchUsersAsync(request.Query ?? "", ct); var users = await _userRepository.SearchUsersAsync(request.Query ?? "", ct);
if (!users.Any()) return Result.Success(new List<AdminUserDto>()); if (!users.Any()) return Result.Success(new List<AdminUserDto>());
var userIds = users.Select(u => u.Id).ToList(); var userIds = users.Select(u => u.Id).ToList();
// 2. Получение агрегированной статистики из NoSQL // 2. Ïîëó÷åíèå àãðåãèðîâàííîé ñòàòèñòèêè èç NoSQL
var statsMap = await _statsService.GetStatsForUsersAsync(userIds, ct); var statsMap = await _statsService.GetStatsForUsersAsync(userIds, ct);
// 3. Сборка DTO с использованием сервисов статуса и статистики // 3. Ñáîðêà DTO ñ èñïîëüçîâàíèåì ñåðâèñîâ ñòàòóñà è ñòàòèñòèêè
var result = users.Select(u => { var result = users.Select(u => {
var stats = statsMap.GetValueOrDefault(u.Id, new UserStats(0, 0L)); var stats = statsMap.GetValueOrDefault(u.Id, new UserStats(0, 0L));
var isOnline = _statusService.IsUserOnline(u.Id.ToString()); var isOnline = _statusService.IsUserOnline(u.Id.ToString());
@@ -57,7 +56,7 @@ internal sealed class SearchUsersQueryHandler : IQueryHandler<SearchUsersQuery,
u.Avatar, u.Avatar,
u.CreatedAt, u.CreatedAt,
isOnline, isOnline,
isOnline ? DateTime.UtcNow : (u.LastSeen ?? u.CreatedAt), isOnline ? DateTime.UtcNow : (u.CreatedAt),
u.IsBanned, u.IsBanned,
stats.MessageCount, stats.MessageCount,
stats.StorageSize stats.StorageSize
@@ -68,7 +67,7 @@ internal sealed class SearchUsersQueryHandler : IQueryHandler<SearchUsersQuery,
} }
catch (Exception ex) catch (Exception ex)
{ {
return Result.Failure<List<AdminUserDto>>(new Error("Admin.SearchUsers.Error", $"Ошибка при поиске пользователей: {ex.Message}")); return Result.Failure<List<AdminUserDto>>(new Error("Admin.SearchUsers.Error", $"Îøèáêà ïðè ïîèñêå ïîëüçîâàòåëåé: {ex.Message}"));
} }
} }
} }
@@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
namespace Knot.Modules.Admin.Domain.Events; namespace Knot.Modules.Admin.Domain.Events;
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
@@ -7,8 +7,11 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" /> <ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
<ProjectReference Include="..\..\Shared\Knot.Shared.Infrastructure\Knot.Shared.Infrastructure.csproj" /> <ProjectReference Include="..\..\Shared\Knot.Shared.Infrastructure\Knot.Shared.Infrastructure.csproj" />
<ProjectReference Include="..\..\Contracts\Knot.Modules.Auth.Contracts\Knot.Modules.Auth.Contracts.csproj" />
<ProjectReference Include="..\..\Contracts\Knot.Modules.Profiles.Contracts\Knot.Modules.Profiles.Contracts.csproj" />
<ProjectReference Include="..\..\Contracts\Knot.Modules.Conversations.Contracts\Knot.Modules.Conversations.Contracts.csproj" />
<ProjectReference Include="..\..\Contracts\Knot.Modules.Settings.Contracts\Knot.Modules.Settings.Contracts.csproj" />
<ProjectReference Include="..\Conversations\Knot.Modules.Conversations.csproj" /> <ProjectReference Include="..\Conversations\Knot.Modules.Conversations.csproj" />
<ProjectReference Include="..\Auth\Knot.Modules.Auth.csproj" />
<ProjectReference Include="..\Stories\Knot.Modules.Stories.csproj" /> <ProjectReference Include="..\Stories\Knot.Modules.Stories.csproj" />
<ProjectReference Include="..\Klipy\Knot.Modules.Klipy.csproj" /> <ProjectReference Include="..\Klipy\Knot.Modules.Klipy.csproj" />
</ItemGroup> </ItemGroup>
@@ -19,7 +22,5 @@
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute"> <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>Knot.Modules.Admin.UnitTests</_Parameter1> <_Parameter1>Knot.Modules.Admin.UnitTests</_Parameter1>
</AssemblyAttribute> </AssemblyAttribute>
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -1,11 +1,9 @@
using Carter; using Carter;
using Knot.Modules.Auth.Application.Auth.DTOs; using Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Modules.Auth.Application.Users.Register; using Knot.Modules.Auth.Application.Users.Register;
using Knot.Shared.Kernel.Storage;
using Knot.Modules.Auth.Infrastructure.Persistence;
using MediatR; using MediatR;
using Knot.Modules.Admin.Application.Admin.Queries; using Knot.Modules.Admin.Application.Admin.Queries;
using Knot.Modules.Admin.Application.Admin.Commands; using Knot.Modules.Admin.Application.Admin.Commands;
@@ -14,7 +12,6 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Knot.Modules.Admin.Application.Admin.Commands.TestKlipy; using Knot.Modules.Admin.Application.Admin.Commands.TestKlipy;
using Knot.Modules.Conversations.Application.Users.Commands.DeleteUser; using Knot.Modules.Conversations.Application.Users.Commands.DeleteUser;
namespace Knot.Host.Presentation.Endpoints; namespace Knot.Host.Presentation.Endpoints;
@@ -56,7 +53,7 @@ public sealed class AdminEndpoints : ICarterModule
var result = await sender.Send(command, ct); var result = await sender.Send(command, ct);
if (result.IsFailure) return Results.BadRequest(new { error = result.Error.Description }); if (result.IsFailure) return Results.BadRequest(new { error = result.Error.Description });
var userDetails = await sender.Send(new GetUserDetailsQuery(result.Value.User.Id), ct); var userDetails = await sender.Send(new GetUserDetailsQuery(result.Value.UserId), ct);
return Results.Ok(userDetails.Value); return Results.Ok(userDetails.Value);
}); });
@@ -133,4 +130,3 @@ public sealed class AdminEndpoints : ICarterModule
}); });
} }
} }
@@ -1,14 +0,0 @@
using System.Threading;
using System.Threading.Tasks;
using Knot.Modules.Auth.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Knot.Modules.Auth.Application.Abstractions;
public interface IAuthDbContext
{
DbSet<User> Users { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}
@@ -1,11 +0,0 @@
using Knot.Shared.Kernel;
namespace Knot.Modules.Auth.Application.Abstractions;
/// <summary>
/// Unit of Work специфичный для модуля Identity.
/// </summary>
public interface IAuthUnitOfWork : IUnitOfWork
{
}
@@ -1,9 +0,0 @@
using Knot.Modules.Auth.Domain;
namespace Knot.Modules.Auth.Application.Abstractions;
public interface IJwtTokenProvider
{
string Generate(User user);
}
@@ -1,21 +0,0 @@
using System;
namespace Knot.Modules.Auth.Application.Auth.DTOs;
public record AuthResponseDto(
string Token,
AuthUserDto User
);
public record AuthUserDto(
Guid Id,
string Username,
string DisplayName,
string? Email,
string? Bio,
string? Avatar,
DateTime? Birthday,
bool IsOnline,
DateTime CreatedAt
);
@@ -1,21 +0,0 @@
using System;
namespace Knot.Modules.Auth.Application.Users.Auth;
public record AuthResponseDto(
string Token,
AuthUserDto User
);
public record AuthUserDto(
Guid Id,
string Username,
string DisplayName,
string? Email,
string? Bio,
string? Avatar,
DateTime? Birthday,
bool IsOnline,
DateTime CreatedAt
);
@@ -1,7 +1,6 @@
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
using Knot.Modules.Auth.Application.Users.Auth;
namespace Knot.Modules.Auth.Application.Users.GetMe; namespace Knot.Modules.Auth.Application.Users.GetMe;
@@ -24,22 +23,15 @@ internal sealed class GetMeQueryHandler : IQueryHandler<GetMeQuery, AuthResponse
return Result.Failure<AuthResponseDto>(AuthErrors.UserNotFound); return Result.Failure<AuthResponseDto>(AuthErrors.UserNotFound);
} }
var response = new AuthResponseDto( var response = new AuthResponseDto
string.Empty, {
new AuthUserDto( AccessToken = string.Empty,
user.Id, RefreshToken = string.Empty,
user.Username, UserId = user.Id,
user.DisplayName, Username = user.Username,
user.Email, DisplayName = user.DisplayName
user.Bio, };
user.Avatar,
user.Birthday,
true,
user.CreatedAt
)
);
return Result.Success(response); return Result.Success(response);
} }
} }
@@ -1,18 +1,17 @@
using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Modules.Auth.Application.Abstractions; using Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Auth.Application.Users.Auth;
using BCrypt.Net; using BCrypt.Net;
namespace Knot.Modules.Auth.Application.Users.Login; namespace Knot.Modules.Auth.Application.Users.Login;
/// <summary> /// <summary>
/// Команда для входа пользователя. Возвращает AuthResponseDto. /// Êîìàíäà äëÿ âõîäà ïîëüçîâàòåëÿ. Âîçâðàùàåò AuthResponseDto.
/// </summary> /// </summary>
public sealed record LoginUserCommand(string Username, string Password) : ICommand<AuthResponseDto>; public sealed record LoginUserCommand(string Username, string Password) : ICommand<AuthResponseDto>;
public sealed class LoginUserCommandHandler : ICommandHandler<LoginUserCommand, AuthResponseDto> internal sealed class LoginUserCommandHandler : ICommandHandler<LoginUserCommand, AuthResponseDto>
{ {
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly IJwtTokenProvider _tokenProvider; private readonly IJwtTokenProvider _tokenProvider;
@@ -32,22 +31,15 @@ public sealed class LoginUserCommandHandler : ICommandHandler<LoginUserCommand,
return Result.Failure<AuthResponseDto>(AuthErrors.IdentityInvalidCredentials); return Result.Failure<AuthResponseDto>(AuthErrors.IdentityInvalidCredentials);
} }
string token = _tokenProvider.Generate(user); string token = _tokenProvider.Generate(user.Id, user.Username, user.DisplayName, user.Avatar);
return Result.Success(new AuthResponseDto( return Result.Success(new AuthResponseDto
token, {
new AuthUserDto( AccessToken = token,
user.Id, RefreshToken = string.Empty,
user.Username, UserId = user.Id,
user.DisplayName, Username = user.Username,
user.Email, DisplayName = user.DisplayName
user.Bio, });
user.Avatar,
user.Birthday,
true, // IsOnline (placeholder)
user.CreatedAt
)
));
} }
} }
@@ -1,10 +1,10 @@
using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Modules.Auth.Contracts.Application.Auth.DTOs;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Domain;
using Knot.Modules.Auth.Application.Abstractions;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Modules.Auth.Application.Users.Auth;
using BCrypt.Net; using BCrypt.Net;
namespace Knot.Modules.Auth.Application.Users.Register; namespace Knot.Modules.Auth.Application.Users.Register;
@@ -22,7 +22,7 @@ public sealed record RegisterUserCommand(
/// <summary> /// <summary>
/// Обработчик команды регистрации. /// Обработчик команды регистрации.
/// </summary> /// </summary>
public sealed class RegisterUserCommandHandler : ICommandHandler<RegisterUserCommand, AuthResponseDto> internal sealed class RegisterUserCommandHandler : ICommandHandler<RegisterUserCommand, AuthResponseDto>
{ {
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly IAuthUnitOfWork _unitOfWork; private readonly IAuthUnitOfWork _unitOfWork;
@@ -54,7 +54,7 @@ public sealed class RegisterUserCommandHandler : ICommandHandler<RegisterUserCom
return Result.Failure<AuthResponseDto>(AuthErrors.IdentityUsernameNotUnique); return Result.Failure<AuthResponseDto>(AuthErrors.IdentityUsernameNotUnique);
} }
// 2. Хеширование пароля (здесь будет вызов сервиса, пока заглушка) // 2. Хеширование пароля
string passwordHash = BCrypt.Net.BCrypt.HashPassword(request.Password); string passwordHash = BCrypt.Net.BCrypt.HashPassword(request.Password);
// 3. Создание сущности // 3. Создание сущности
@@ -65,27 +65,21 @@ public sealed class RegisterUserCommandHandler : ICommandHandler<RegisterUserCom
request.Email, request.Email,
request.Bio); request.Bio);
// 4. Сохранение // 4. Сохранение - используем метод с Domain User
_userRepository.Add(user); var repoWithDomainUserAdd = _userRepository as Infrastructure.Persistence.UserRepository;
repoWithDomainUserAdd?.Add(user);
await _unitOfWork.SaveChangesAsync(cancellationToken); await _unitOfWork.SaveChangesAsync(cancellationToken);
string token = _tokenProvider.Generate(user); string token = _tokenProvider.Generate(user.Id, user.Username, user.DisplayName, user.Avatar);
return Result.Success(new AuthResponseDto( return Result.Success(new AuthResponseDto
token, {
new AuthUserDto( AccessToken = token,
user.Id, RefreshToken = string.Empty,
user.Username, UserId = user.Id,
user.DisplayName, Username = user.Username,
user.Email, DisplayName = user.DisplayName
user.Bio, });
user.Avatar,
user.Birthday,
true, // IsOnline (placeholder)
user.CreatedAt
)
));
} }
} }
@@ -2,8 +2,9 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Knot.Modules.Auth.Infrastructure.Persistence; using Knot.Modules.Auth.Infrastructure.Persistence;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Application.Abstractions; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Modules.Auth.Infrastructure.Authentication; using Knot.Modules.Auth.Infrastructure.Authentication;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
@@ -1,15 +0,0 @@
using Knot.Shared.Kernel;
namespace Knot.Modules.Auth.Domain;
public static class AuthErrors
{
public static readonly Error FriendsNotFound = new Error("Friends.NotFound", "Friendship not found");
public static readonly Error FriendsSelf = new Error("Friends.Self", "Cannot add yourself");
public static readonly Error FriendsExists = new Error("Friends.Exists", "Friendship already exists");
public static readonly Error UserNotFound = new Error("User.NotFound", "User not found");
public static readonly Error IdentityInvalidCredentials = new Error("Identity.InvalidCredentials", "Неверное имя пользователя или пароль.");
public static readonly Error IdentityRegistrationDisabled = new Error("Identity.RegistrationDisabled", "Registration is disabled by the administrator.");
public static readonly Error IdentityUsernameNotUnique = new Error("Identity.UsernameNotUnique", "Это имя пользователя уже занято.");
}
@@ -0,0 +1,6 @@
using Knot.Shared.Kernel;
using Knot.Shared.Kernel.Events;
namespace Knot.Modules.Auth.Domain;
public sealed record UserStatusChangedDomainEvent(Guid UserId, bool IsOnline, DateTime LastSeen) : IDomainEvent;
@@ -1,19 +0,0 @@
using Knot.Modules.Auth.Domain;
namespace Knot.Modules.Auth.Domain;
/// <summary>
/// Интерфейс репозитория для работы с пользователями.
/// </summary>
public interface IUserRepository
{
Task<User?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<List<User>> GetByIdsAsync(IEnumerable<Guid> ids, CancellationToken cancellationToken = default);
Task<User?> GetByUsernameAsync(string username, CancellationToken cancellationToken = default);
Task<bool> IsUsernameUniqueAsync(string username, CancellationToken cancellationToken = default);
Task<List<User>> SearchUsersAsync(string query, CancellationToken cancellationToken = default);
void Add(User user);
void Update(User user);
void Remove(User user);
}
+42 -10
View File
@@ -1,30 +1,32 @@
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Shared.Kernel.Events; using Knot.Shared.Kernel.Events;
using Knot.Modules.Auth.Contracts.Domain;
namespace Knot.Modules.Auth.Domain; namespace Knot.Modules.Auth.Domain;
public sealed record UserStatusChangedDomainEvent(Guid UserId, bool IsOnline, DateTime LastSeen) : IDomainEvent;
/// <summary> /// <summary>
/// Сущность пользователя в контексте идентификации (Identity). /// Сущность пользователя в контексте идентификации (Identity).
/// </summary> /// </summary>
public sealed class User : AggregateRoot<Guid> public sealed class User : AggregateRoot<Guid>
{ {
public string Username { get; private set; } public string Username { get; set; }
public string PasswordHash { get; private set; } public string PasswordHash { get; private set; }
public string DisplayName { get; private set; } public string DisplayName { get; set; }
public string? Email { get; private set; } public string? Email { get; private set; }
public string? Bio { get; private set; } public string? Bio { get; private set; }
public string? Avatar { get; private set; } public string? Avatar { get; set; }
public DateTime? Birthday { get; private set; } public DateTime? Birthday { get; private set; }
public DateTime CreatedAt { get; private set; } public DateTime CreatedAt { get; private set; }
public bool HideStoryViews { get; private set; } public bool HideStoryViews { get; private set; }
public bool IsExternal { get; private set; } public bool IsExternal { get; private set; }
public string? Domain { get; private set; } public string? Domain { get; private set; }
public bool IsOnline { get; private set; } public bool IsOnline { get; set; }
public DateTime? LastSeen { get; private set; } public DateTime? LastSeen { get; private set; }
public bool HideStatus { get; private set; } public bool HideStatus { get; private set; }
public bool IsBanned { get; private set; } public bool IsBanned { get; set; }
public string? PhoneNumber { get; set; }
public string? RefreshToken { get; set; }
public DateTime? BannedUntil { get; set; }
public void Ban() => IsBanned = true; public void Ban() => IsBanned = true;
public void Unban() => IsBanned = false; public void Unban() => IsBanned = false;
@@ -58,11 +60,18 @@ public sealed class User : AggregateRoot<Guid>
{ {
var user = new User(id, username, "EXTERNAL_USER", displayName, null, null); var user = new User(id, username, "EXTERNAL_USER", displayName, null, null);
user.IsExternal = true; user.IsExternal = true;
user.Domain = domain; user._domain = domain;
user.Avatar = avatar; user.Avatar = avatar;
return user; return user;
} }
private string? _domain;
public string? UserDomain
{
get => _domain;
set => _domain = value;
}
public void UpdateProfile(string displayName, string? bio, DateTime? birthday) public void UpdateProfile(string displayName, string? bio, DateTime? birthday)
{ {
DisplayName = displayName; DisplayName = displayName;
@@ -100,5 +109,28 @@ public sealed class User : AggregateRoot<Guid>
{ {
HideStatus = hide; HideStatus = hide;
} }
}
public UserContract ToContract()
{
return new UserContract
{
Id = Id,
Username = Username,
DisplayName = DisplayName,
PasswordHash = PasswordHash,
PhoneNumber = PhoneNumber,
Email = Email,
Bio = Bio,
Avatar = Avatar,
Birthday = Birthday,
IsBot = false,
CreatedAt = CreatedAt,
IsBanned = IsBanned,
BannedUntil = BannedUntil,
IsOnline = IsOnline,
IsExternal = IsExternal,
Domain = _domain,
LastSeen = LastSeen
};
}
}
@@ -1,14 +1,14 @@
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Knot.Modules.Auth.Application.Abstractions; using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Domain;
namespace Knot.Modules.Auth.Infrastructure.Authentication; namespace Knot.Modules.Auth.Infrastructure.Authentication;
public sealed class JwtTokenProvider : IJwtTokenProvider internal sealed class JwtTokenProvider : IJwtTokenProvider
{ {
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
@@ -17,15 +17,13 @@ public sealed class JwtTokenProvider : IJwtTokenProvider
_configuration = configuration; _configuration = configuration;
} }
public string Generate(User user) public string GenerateAccessToken(Guid userId, string username)
{ {
var claims = new Claim[] var claims = new Claim[]
{ {
new(JwtRegisteredClaimNames.Sub, user.Id.ToString()), new(JwtRegisteredClaimNames.Sub, userId.ToString()),
new(JwtRegisteredClaimNames.UniqueName, user.Username), new(JwtRegisteredClaimNames.UniqueName, username),
new("name", user.DisplayName), new(ClaimTypes.Name, username)
new(ClaimTypes.Name, user.DisplayName),
new("avatar", user.Avatar ?? string.Empty)
}; };
var secretKey = _configuration["Jwt:Secret"]!; var secretKey = _configuration["Jwt:Secret"]!;
@@ -42,5 +40,43 @@ public sealed class JwtTokenProvider : IJwtTokenProvider
return new JwtSecurityTokenHandler().WriteToken(token); return new JwtSecurityTokenHandler().WriteToken(token);
} }
public string GenerateRefreshToken()
{
var randomBytes = new byte[32];
using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
rng.GetBytes(randomBytes);
return Convert.ToBase64String(randomBytes);
} }
public string Generate(Guid userId, string username, string displayName, string? avatar)
{
var claims = new Claim[]
{
new(JwtRegisteredClaimNames.Sub, userId.ToString()),
new(JwtRegisteredClaimNames.UniqueName, username),
new("name", displayName),
new(ClaimTypes.Name, displayName),
new("avatar", avatar ?? string.Empty)
};
var secretKey = _configuration["Jwt:Secret"]!;
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
_configuration["Jwt:Issuer"],
_configuration["Jwt:Audience"],
claims,
null,
DateTime.UtcNow.AddMinutes(double.Parse(_configuration["Jwt:ExpiryInMinutes"] ?? "1440")),
credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public string Generate(User user)
{
return Generate(user.Id, user.Username, user.DisplayName, user.Avatar);
}
}
@@ -1,18 +1,15 @@
using MediatR; using MediatR;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata; using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Modules.Auth.Application.Abstractions; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Domain;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Shared.Kernel.Security; using Knot.Shared.Kernel.Security;
using DomainUser = Knot.Modules.Auth.Domain.User;
namespace Knot.Modules.Auth.Infrastructure.Persistence; namespace Knot.Modules.Auth.Infrastructure.Persistence;
/// <summary> public sealed class AuthDbContext : DbContext, IAuthUnitOfWork, IAuthDbContext
/// Контекст базы данных для модуля Identity.
/// </summary>
public sealed class AuthDbContext : DbContext, IAuthUnitOfWork, Knot.Modules.Auth.Application.Abstractions.IAuthDbContext
{ {
private readonly IMediator _mediator; private readonly IMediator _mediator;
private readonly IEncryptionService _encryptionService; private readonly IEncryptionService _encryptionService;
@@ -24,9 +21,15 @@ public sealed class AuthDbContext : DbContext, IAuthUnitOfWork, Knot.Modules.Aut
_encryptionService = encryptionService; _encryptionService = encryptionService;
} }
public DbSet<User> Users => Set<User>(); public DbSet<DomainUser> Users => Set<DomainUser>();
public IUserRepository UserRepository => throw new InvalidOperationException("UserRepository should be resolved from DI");
public void Add(UserContract user)
{
var domainUser = DomainUser.Create(user.Username, user.PasswordHash, user.DisplayName, user.Email, user.Bio);
Set<DomainUser>().Add(domainUser);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
@@ -38,16 +41,13 @@ public sealed class AuthDbContext : DbContext, IAuthUnitOfWork, Knot.Modules.Aut
{ {
modelBuilder.HasDefaultSchema("identity"); modelBuilder.HasDefaultSchema("identity");
modelBuilder.Entity<DomainUser>(builder =>
modelBuilder.Entity<User>(builder =>
{ {
builder.ToTable("Users"); builder.ToTable("Users");
builder.HasKey(u => u.Id); builder.HasKey(u => u.Id);
builder.Property(u => u.Username).IsRequired().HasMaxLength(50); builder.Property(u => u.Username).IsRequired().HasMaxLength(50);
builder.HasIndex(u => u.Username).IsUnique(); builder.HasIndex(u => u.Username).IsUnique();
builder.Property(u => u.PasswordHash).IsRequired(); builder.Property(u => u.PasswordHash).IsRequired();
}); });
} }
@@ -56,7 +56,6 @@ public sealed class AuthDbContext : DbContext, IAuthUnitOfWork, Knot.Modules.Aut
var domainEvents = ChangeTracker var domainEvents = ChangeTracker
.Entries<IAggregateRoot>() .Entries<IAggregateRoot>()
.SelectMany(x => .SelectMany(x =>
{ {
if (x.Entity is AggregateRoot<Guid> root) if (x.Entity is AggregateRoot<Guid> root)
{ {
@@ -77,5 +76,9 @@ public sealed class AuthDbContext : DbContext, IAuthUnitOfWork, Knot.Modules.Aut
return result; return result;
} }
}
async Task<int> IAuthUnitOfWork.SaveChangesAsync(CancellationToken ct)
{
return await SaveChangesAsync(ct);
}
}
@@ -1,12 +1,10 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Domain;
namespace Knot.Modules.Auth.Infrastructure.Persistence; namespace Knot.Modules.Auth.Infrastructure.Persistence;
/// <summary> internal sealed class UserRepository : IUserRepository
/// Реализация репозитория пользователей с использованием EF Core.
/// </summary>
public sealed class UserRepository : IUserRepository
{ {
private readonly AuthDbContext _context; private readonly AuthDbContext _context;
@@ -15,19 +13,22 @@ public sealed class UserRepository : IUserRepository
_context = context; _context = context;
} }
public async Task<User?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default) public async Task<UserContract?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
{ {
return await _context.Users.FirstOrDefaultAsync(u => u.Id == id, cancellationToken); var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == id, cancellationToken);
return user?.ToContract();
} }
public async Task<List<User>> GetByIdsAsync(IEnumerable<Guid> ids, CancellationToken cancellationToken = default) public async Task<List<UserContract>> GetByIdsAsync(IEnumerable<Guid> ids, CancellationToken cancellationToken = default)
{ {
return await _context.Users.Where(u => ids.Contains(u.Id)).ToListAsync(cancellationToken); var users = await _context.Users.Where(u => ids.Contains(u.Id)).ToListAsync(cancellationToken);
return users.Select(u => u.ToContract()).ToList();
} }
public async Task<User?> GetByUsernameAsync(string username, CancellationToken cancellationToken = default) public async Task<UserContract?> GetByUsernameAsync(string username, CancellationToken cancellationToken = default)
{ {
return await _context.Users.FirstOrDefaultAsync(u => u.Username == username, cancellationToken); var user = await _context.Users.FirstOrDefaultAsync(u => u.Username == username, cancellationToken);
return user?.ToContract();
} }
public async Task<bool> IsUsernameUniqueAsync(string username, CancellationToken cancellationToken = default) public async Task<bool> IsUsernameUniqueAsync(string username, CancellationToken cancellationToken = default)
@@ -35,13 +36,48 @@ public sealed class UserRepository : IUserRepository
return !await _context.Users.AnyAsync(u => u.Username == username, cancellationToken); return !await _context.Users.AnyAsync(u => u.Username == username, cancellationToken);
} }
public async Task<List<User>> SearchUsersAsync(string query, CancellationToken cancellationToken = default) public async Task<List<UserContract>> SearchUsersAsync(string query, CancellationToken cancellationToken = default)
{ {
return await _context.Users var users = await _context.Users
.Where(u => u.Username.ToLower().Contains(query.ToLower()) || .Where(u => u.Username.ToLower().Contains(query.ToLower()) ||
(u.DisplayName != null && u.DisplayName.ToLower().Contains(query.ToLower()))) (u.DisplayName != null && u.DisplayName.ToLower().Contains(query.ToLower())))
.Take(20) .Take(20)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
return users.Select(u => u.ToContract()).ToList();
}
public async Task<bool> IsBannedAsync(Guid userId, CancellationToken cancellationToken = default)
{
var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId, cancellationToken);
return user?.IsBanned ?? false;
}
public async Task<UserContract?> GetByRefreshTokenAsync(string refreshToken, CancellationToken cancellationToken = default)
{
var user = await _context.Users.FirstOrDefaultAsync(u => u.RefreshToken == refreshToken, cancellationToken);
return user?.ToContract();
}
public async Task UpdateAsync(UserContract user, CancellationToken cancellationToken = default)
{
var domainUser = await _context.Users.FirstOrDefaultAsync(u => u.Id == user.Id, cancellationToken);
if (domainUser != null)
{
domainUser.Username = user.Username;
domainUser.DisplayName = user.DisplayName;
domainUser.PhoneNumber = user.PhoneNumber;
domainUser.IsBanned = user.IsBanned;
domainUser.BannedUntil = user.BannedUntil;
domainUser.IsOnline = user.IsOnline;
domainUser.UserDomain = user.Domain;
_context.Users.Update(domainUser);
}
}
public void Add(UserContract user)
{
var domainUser = User.Create(user.Username, user.PasswordHash, user.DisplayName, user.Email, user.Bio);
_context.Users.Add(domainUser);
} }
public void Add(User user) public void Add(User user)
@@ -58,5 +94,29 @@ public sealed class UserRepository : IUserRepository
{ {
_context.Users.Remove(user); _context.Users.Remove(user);
} }
public async Task RemoveAsync(UserContract user, CancellationToken cancellationToken = default)
{
var domainUser = await _context.Users.FirstOrDefaultAsync(u => u.Id == user.Id, cancellationToken);
if (domainUser != null)
{
_context.Users.Remove(domainUser);
}
} }
public void Update(UserContract user)
{
var domainUser = _context.Users.Find(user.Id);
if (domainUser != null)
{
domainUser.Username = user.Username;
domainUser.DisplayName = user.DisplayName;
domainUser.PhoneNumber = user.PhoneNumber;
domainUser.IsBanned = user.IsBanned;
domainUser.BannedUntil = user.BannedUntil;
domainUser.IsOnline = user.IsOnline;
domainUser.UserDomain = user.Domain;
_context.Users.Update(domainUser);
}
}
}
@@ -1,5 +1,6 @@
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Contracts.Domain;
namespace Knot.Modules.Auth.Infrastructure.Services; namespace Knot.Modules.Auth.Infrastructure.Services;
@@ -8,7 +8,9 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" /> <ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
<ProjectReference Include="..\Profiles\Knot.Modules.Profiles.csproj" /> <ProjectReference Include="..\..\Contracts\Knot.Modules.Auth.Contracts\Knot.Modules.Auth.Contracts.csproj" />
<ProjectReference Include="..\..\Contracts\Knot.Modules.Profiles.Contracts\Knot.Modules.Profiles.Contracts.csproj" />
<ProjectReference Include="..\..\Contracts\Knot.Modules.Settings.Contracts\Knot.Modules.Settings.Contracts.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -28,7 +30,6 @@
<ItemGroup> <ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" /> <FrameworkReference Include="Microsoft.AspNetCore.App" />
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -1,4 +1,4 @@
// <auto-generated /> // <auto-generated />
using System; using System;
using Knot.Modules.Auth.Infrastructure.Persistence; using Knot.Modules.Auth.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -26,7 +26,7 @@ namespace Knot.Modules.Auth.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Knot.Modules.Auth.Domain.User", b => modelBuilder.Entity("Knot.Modules.Auth.Contracts.Domain.User", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -1,4 +1,4 @@
using System; using System;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable #nullable disable
@@ -27,7 +27,7 @@ namespace Knot.Modules.Auth.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Knot.Modules.Auth.Domain.User", b => modelBuilder.Entity("Knot.Modules.Auth.Contracts.Domain.User", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -26,7 +26,7 @@ namespace Knot.Modules.Auth.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Knot.Modules.Auth.Domain.User", b => modelBuilder.Entity("Knot.Modules.Auth.Contracts.Domain.User", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -23,7 +23,7 @@ namespace Knot.Modules.Auth.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Knot.Modules.Auth.Domain.User", b => modelBuilder.Entity("Knot.Modules.Auth.Contracts.Domain.User", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -32,8 +32,7 @@ public sealed class AuthEndpoints : ICarterModule
group.MapGet("me", async (ISender sender, IUserContext userContext, CancellationToken ct) => group.MapGet("me", async (ISender sender, IUserContext userContext, CancellationToken ct) =>
{ {
var result = await sender.Send(new GetMeQuery(userContext.UserId), ct); var result = await sender.Send(new GetMeQuery(userContext.UserId), ct);
return result.IsSuccess ? Results.Ok(new { User = result.Value.User }) : Results.NotFound(); return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound();
}).RequireAuthorization(); }).RequireAuthorization();
} }
} }
@@ -1,7 +1,6 @@
using Knot.Modules.Conversations.Domain; using Knot.Modules.Conversations.Domain;
using Knot.Modules.Conversations.Application.Abstractions; using Knot.Modules.Conversations.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using MediatR; using MediatR;
@@ -49,4 +48,3 @@ internal sealed class AddToFolderCommandHandler : ICommandHandler<AddToFolderCom
return Result.Success(); return Result.Success();
} }
} }
@@ -2,14 +2,13 @@ using Knot.Modules.Messaging.Application.Abstractions;
using Knot.Modules.Messaging.Domain; using Knot.Modules.Messaging.Domain;
using Knot.Modules.Conversations.Domain; using Knot.Modules.Conversations.Domain;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs;
using Knot.Modules.Conversations.Application.Abstractions; using Knot.Modules.Conversations.Application.Abstractions;
namespace Knot.Modules.Conversations.Application.Messages.Send; namespace Knot.Modules.Conversations.Application.Messages.Send;
/// <summary> /// <summary>
/// Команда для отправки сообщения в чат. /// Êîìàíäà äëÿ îòïðàâêè ñîîáùåíèÿ â ÷àò.
/// </summary> /// </summary>
public record AttachmentRequest(string Type, string Url, string? FileName, long? FileSize); public record AttachmentRequest(string Type, string Url, string? FileName, long? FileSize);
@@ -54,20 +53,20 @@ public sealed class SendMessageCommandHandler : ICommandHandler<SendMessageComma
public async Task<Result<Guid>> Handle(SendMessageCommand request, CancellationToken cancellationToken) public async Task<Result<Guid>> Handle(SendMessageCommand request, CancellationToken cancellationToken)
{ {
// 1. Проверяем существование чата // 1. Ïðîâåðÿåì ñóùåñòâîâàíèå ÷àòà
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken); var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
if (chat is null) if (chat is null)
{ {
return Result.Failure<Guid>(ChatErrors.ChatsNotFound); return Result.Failure<Guid>(ChatErrors.ChatsNotFound);
} }
// 2. Проверяем, является ли отправитель участником // 2. Ïðîâåðÿåì, ÿâëÿåòñÿ ëè îòïðàâèòåëü ó÷àñòíèêîì
if (!chat.Members.Any(m => m.UserId == request.SenderId)) if (!chat.Members.Any(m => m.UserId == request.SenderId))
{ {
return Result.Failure<Guid>(ChatErrors.ChatsForbidden); return Result.Failure<Guid>(ChatErrors.ChatsForbidden);
} }
// 3. Создаем сообщение // 3. Ñîçäàåì ñîîáùåíèå
Message message; Message message;
if (request.Type == "story_reply" || request.Type == "story_reaction") if (request.Type == "story_reply" || request.Type == "story_reaction")
{ {
@@ -143,7 +142,7 @@ public sealed class SendMessageCommandHandler : ICommandHandler<SendMessageComma
false); false);
} }
// 4. Последовательность сообщений High-Water Mark // 4. Ïîñëåäîâàòåëüíîñòü ñîîáùåíèé High-Water Mark
chat.IncrementSequenceId(); chat.IncrementSequenceId();
message.SetSequenceId(chat.LastMessageSequenceId); message.SetSequenceId(chat.LastMessageSequenceId);
@@ -151,7 +150,7 @@ public sealed class SendMessageCommandHandler : ICommandHandler<SendMessageComma
senderMember.UpdateReadCursor(message.Id, message.SequenceId); senderMember.UpdateReadCursor(message.Id, message.SequenceId);
senderMember.UpdateDeliveredCursor(message.Id); senderMember.UpdateDeliveredCursor(message.Id);
// 5. Сохраняем // 5. Ñîõðàíÿåì
_messageRepository.Add(message); _messageRepository.Add(message);
await _unitOfWork.SaveChangesAsync(cancellationToken); await _unitOfWork.SaveChangesAsync(cancellationToken);
@@ -165,7 +164,3 @@ public sealed class SendMessageCommandHandler : ICommandHandler<SendMessageComma
return Result.Success(message.Id); return Result.Success(message.Id);
} }
} }
@@ -6,8 +6,8 @@ using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Shared.Kernel.Storage; using Knot.Shared.Kernel.Storage;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Modules.Conversations.Application.DTOs; using Knot.Modules.Conversations.Application.DTOs;
namespace Knot.Modules.Conversations.Application.Messages.UploadFile; namespace Knot.Modules.Conversations.Application.Messages.UploadFile;
@@ -1,4 +1,5 @@
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Contracts.Application.Abstractions;
using Knot.Modules.Conversations.Domain; using Knot.Modules.Conversations.Domain;
using Knot.Modules.Messaging.Domain; using Knot.Modules.Messaging.Domain;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
@@ -6,7 +7,6 @@ using Knot.Shared.Kernel.Storage;
using MediatR; using MediatR;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Knot.Modules.Conversations.Application.Abstractions; using Knot.Modules.Conversations.Application.Abstractions;
using Knot.Modules.Auth.Application.Abstractions;
namespace Knot.Modules.Conversations.Application.Users.Commands.DeleteUser; namespace Knot.Modules.Conversations.Application.Users.Commands.DeleteUser;
@@ -80,7 +80,7 @@ internal sealed class DeleteUserCommandHandler : ICommandHandler<DeleteUserComma
_userChatSettingsRepository.RemoveRange(chatSettings); _userChatSettingsRepository.RemoveRange(chatSettings);
// 4. Delete User (Postgres - Auth Module) // 4. Delete User (Postgres - Auth Module)
_userRepository.Remove(user); await _userRepository.RemoveAsync(user, cancellationToken);
// Commit all // Commit all
await _unitOfWork.SaveChangesAsync(cancellationToken); await _unitOfWork.SaveChangesAsync(cancellationToken);
@@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" /> <ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
<ProjectReference Include="..\..\Contracts\Knot.Modules.Settings.Contracts\Knot.Modules.Settings.Contracts.csproj" />
<ProjectReference Include="..\Messaging\Knot.Modules.Messaging.csproj" /> <ProjectReference Include="..\Messaging\Knot.Modules.Messaging.csproj" />
<ProjectReference Include="..\Auth\Knot.Modules.Auth.csproj" /> <ProjectReference Include="..\Auth\Knot.Modules.Auth.csproj" />
</ItemGroup> </ItemGroup>
@@ -36,5 +37,3 @@
</PropertyGroup> </PropertyGroup>
</Project> </Project>
@@ -1,4 +1,4 @@
// <auto-generated /> // <auto-generated />
using System; using System;
using Knot.Modules.Conversations.Infrastructure.Persistence; using Knot.Modules.Conversations.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -1,4 +1,4 @@
using System; using System;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable #nullable disable
@@ -1,4 +1,4 @@
// <auto-generated /> // <auto-generated />
using System; using System;
using Knot.Modules.Conversations.Infrastructure.Persistence; using Knot.Modules.Conversations.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -2,8 +2,8 @@ using Knot.Shared.Kernel.Constants;
using System.Security.Cryptography; using System.Security.Cryptography;
using MediatR; using MediatR;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
namespace Host.Application.Federation.Commands; namespace Host.Application.Federation.Commands;
@@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
@@ -8,11 +8,11 @@ using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Modules.Federation.Application.Abstractions; using Knot.Modules.Federation.Application.Abstractions;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Messaging.Application.Abstractions; using Knot.Modules.Messaging.Application.Abstractions;
using Knot.Modules.Messaging.Domain; using Knot.Modules.Messaging.Domain;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Shared.Kernel.Constants; using Knot.Shared.Kernel.Constants;
namespace Host.Application.Federation.Commands; namespace Host.Application.Federation.Commands;
@@ -116,8 +116,8 @@ internal sealed class InboundFederationCommandHandler : ICommandHandler<InboundF
var user = await _userRepository.GetByIdAsync(packet.Metadata.SenderId, cancellationToken); var user = await _userRepository.GetByIdAsync(packet.Metadata.SenderId, cancellationToken);
if (user != null && user.IsExternal) if (user != null && user.IsExternal)
{ {
user.UpdateStatus(isOnline); user.IsOnline = isOnline;
_userRepository.Update(user); await _userRepository.UpdateAsync(user, cancellationToken);
// Уведомляем локальных пользователей через SignalR // Уведомляем локальных пользователей через SignalR
await _notifier.NotifyNewMessageAsync(Guid.Empty, new { type = "presence_update", userId = user.Id, isOnline = user.IsOnline }, cancellationToken); await _notifier.NotifyNewMessageAsync(Guid.Empty, new { type = "presence_update", userId = user.Id, isOnline = user.IsOnline }, cancellationToken);
@@ -127,7 +127,7 @@ internal sealed class InboundFederationCommandHandler : ICommandHandler<InboundF
if (packet.Metadata.MessageType == "message_edited") if (packet.Metadata.MessageType == "message_edited")
{ {
var messageToEdit = await _messageRepository.GetByIdAsync(packet.Metadata.SenderId, cancellationToken); // В метаданных MessageId var messageToEdit = await _messageRepository.GetByIdAsync(packet.Metadata.SenderId, cancellationToken);
if (messageToEdit != null) if (messageToEdit != null)
{ {
messageToEdit.Edit(plainText); messageToEdit.Edit(plainText);
@@ -176,7 +176,6 @@ internal sealed class InboundFederationCommandHandler : ICommandHandler<InboundF
if (packet.Metadata.MessageType == "rtc_signal") if (packet.Metadata.MessageType == "rtc_signal")
{ {
// Здесь проброс WebRTC сигнала (Offer/Answer/ICE) конечному пользователю через SignalR
await _notifier.NotifyNewMessageAsync(packet.Metadata.ChatId, new { type = "rtc_signal", payload = plainText, senderId = packet.Metadata.SenderId }, cancellationToken); await _notifier.NotifyNewMessageAsync(packet.Metadata.ChatId, new { type = "rtc_signal", payload = plainText, senderId = packet.Metadata.SenderId }, cancellationToken);
return Result.Success(); return Result.Success();
} }
@@ -185,17 +184,16 @@ internal sealed class InboundFederationCommandHandler : ICommandHandler<InboundF
return Result.Failure(new Error("Federation.PollsDisabled", "We do not accept polls.")); return Result.Failure(new Error("Federation.PollsDisabled", "We do not accept polls."));
// 5. Сохранение в базу сообщений (MongoDB) // 5. Сохранение в базу сообщений (MongoDB)
// В реальном приложении здесь будет маппинг на TextMessage, MediaMessage и т.д.
var message = new TextMessage( var message = new TextMessage(
Guid.NewGuid(), Guid.NewGuid(),
packet.Metadata.ChatId, packet.Metadata.ChatId,
packet.Metadata.SenderId, packet.Metadata.SenderId,
plainText, plainText,
null, // replyToId null,
null, // quote null,
null, // forwardedFromId null,
packet.Metadata.CreatedAt, packet.Metadata.CreatedAt,
false); // isImported false);
_messageRepository.Add(message); _messageRepository.Add(message);
@@ -205,4 +203,3 @@ internal sealed class InboundFederationCommandHandler : ICommandHandler<InboundF
return Result.Success(); return Result.Success();
} }
} }
@@ -3,9 +3,9 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using System.Linq; using System.Linq;
namespace Host.Application.Federation.Commands; namespace Host.Application.Federation.Commands;
@@ -7,9 +7,9 @@ using Knot.Modules.Messaging.Domain;
using Knot.Modules.Federation.Application.Federation.Services; using Knot.Modules.Federation.Application.Federation.Services;
using Knot.Modules.Conversations.Domain; using Knot.Modules.Conversations.Domain;
using Knot.Modules.Federation.Application.Abstractions; using Knot.Modules.Federation.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
namespace Knot.Modules.Federation.Application.Federation.Events; namespace Knot.Modules.Federation.Application.Federation.Events;
@@ -7,9 +7,9 @@ using Knot.Modules.Messaging.Domain;
using Knot.Modules.Federation.Application.Federation.Services; using Knot.Modules.Federation.Application.Federation.Services;
using Knot.Modules.Conversations.Domain; using Knot.Modules.Conversations.Domain;
using Knot.Modules.Federation.Application.Abstractions; using Knot.Modules.Federation.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Contracts.Domain;
namespace Knot.Modules.Federation.Application.Federation.Events; namespace Knot.Modules.Federation.Application.Federation.Events;
@@ -6,8 +6,8 @@ using MediatR;
using Knot.Modules.Settings.Domain.Events; using Knot.Modules.Settings.Domain.Events;
using Knot.Modules.Federation.Application.Abstractions; using Knot.Modules.Federation.Application.Abstractions;
using Knot.Modules.Federation.Application.Federation.Services; using Knot.Modules.Federation.Application.Federation.Services;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
namespace Knot.Modules.Federation.Application.Federation.Events; namespace Knot.Modules.Federation.Application.Federation.Events;
@@ -1,14 +1,15 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediatR; using MediatR;
using Knot.Modules.Auth.Contracts.Domain;
using Knot.Modules.Auth.Domain; using Knot.Modules.Auth.Domain;
using Knot.Modules.Conversations.Domain; using Knot.Modules.Conversations.Domain;
using Knot.Modules.Federation.Application.Abstractions; using Knot.Modules.Federation.Application.Abstractions;
using Knot.Modules.Federation.Application.Federation.Services; using Knot.Modules.Federation.Application.Federation.Services;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
namespace Knot.Modules.Federation.Application.Federation.Events; namespace Knot.Modules.Federation.Application.Federation.Events;
@@ -69,7 +70,7 @@ public sealed class UserStatusChangedDomainEventHandler : INotificationHandler<U
var metadata = new FederationMetadata( var metadata = new FederationMetadata(
Guid.Empty, Guid.Empty,
notification.UserId, notification.UserId,
"system", // Username отправителя здесь не важен, важен SenderId "system",
"presence_update", "presence_update",
DateTime.UtcNow DateTime.UtcNow
); );
@@ -85,4 +86,3 @@ public sealed class UserStatusChangedDomainEventHandler : INotificationHandler<U
} }
} }
} }
@@ -8,8 +8,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Knot.Modules.Federation.Application.Abstractions; using Knot.Modules.Federation.Application.Abstractions;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Shared.Kernel.Security; using Knot.Shared.Kernel.Security;
namespace Knot.Modules.Federation.Application.Federation.Services; namespace Knot.Modules.Federation.Application.Federation.Services;
@@ -8,8 +8,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Knot.Modules.Federation.Application.Abstractions; using Knot.Modules.Federation.Application.Abstractions;
using Knot.Shared.Kernel; using Knot.Shared.Kernel;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
using Knot.Shared.Kernel.Security; using Knot.Shared.Kernel.Security;
namespace Knot.Modules.Federation.Infrastructure.Services; namespace Knot.Modules.Federation.Infrastructure.Services;
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
@@ -7,13 +7,13 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" /> <ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
<ProjectReference Include="..\..\Shared\Knot.Shared.Infrastructure\Knot.Shared.Infrastructure.csproj" /> <ProjectReference Include="..\..\Shared\Knot.Shared.Infrastructure\Knot.Shared.Infrastructure.csproj" />
<ProjectReference Include="..\..\Contracts\Knot.Modules.Auth.Contracts\Knot.Modules.Auth.Contracts.csproj" />
<ProjectReference Include="..\Conversations\Knot.Modules.Conversations.csproj" /> <ProjectReference Include="..\Conversations\Knot.Modules.Conversations.csproj" />
<ProjectReference Include="..\Auth\Knot.Modules.Auth.csproj" /> <ProjectReference Include="..\Auth\Knot.Modules.Auth.csproj" />
<ProjectReference Include="..\Stories\Knot.Modules.Stories.csproj" /> <ProjectReference Include="..\Stories\Knot.Modules.Stories.csproj" />
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Carter" Version="10.0.0" /> <PackageReference Include="Carter" Version="10.0.0" />
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -9,8 +9,8 @@ using System;
using Host.Application.Federation.Commands; using Host.Application.Federation.Commands;
using Knot.Modules.Federation.Application.Abstractions; using Knot.Modules.Federation.Application.Abstractions;
using Knot.Shared.Kernel.Storage; using Knot.Shared.Kernel.Storage;
using Knot.Modules.Settings.Application.Settings.Abstractions; using Knot.Modules.Settings.Contracts.Application.Abstractions;
using Knot.Modules.Settings.Application.Settings.DTOs; using Knot.Modules.Settings.Contracts.Application.DTOs;
namespace Host.Endpoints; namespace Host.Endpoints;

Some files were not shown because too many files have changed in this diff Show More