Сборка бэк
This commit is contained in:
550
backend/Knot.sln
550
backend/Knot.sln
@@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Shared.Infrastructure"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Profiles", "Profiles", "{CA5186C2-289A-9324-4152-9805A73A9773}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Profiles", "src\Modules\Profiles\Knot.Modules.Profiles.csproj", "{CD14770B-8BCD-4D93-AD2C-581ED030E209}"
|
||||
@@ -35,8 +33,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Auth", "Auth", "{E9D55F35-C
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Auth", "src\Modules\Auth\Knot.Modules.Auth.csproj", "{CF08AE9C-B337-47BA-B273-4B8E5610D7BD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Auth.UnitTests", "tests\Knot.Modules.Auth.UnitTests\Knot.Modules.Auth.UnitTests.csproj", "{BA37DF67-98D3-4399-BD68-9679396C1547}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Messaging", "Messaging", "{AE120A0E-5815-2D46-946C-DA544028AD88}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Messaging", "src\Modules\Messaging\Knot.Modules.Messaging.csproj", "{C0B5496E-F083-413E-90AE-31282A0ACCA5}"
|
||||
@@ -49,44 +45,132 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Conversations", "Conversati
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Conversations", "src\Modules\Conversations\Knot.Modules.Conversations.csproj", "{F3EFD119-44F7-46BF-A03C-060F30A1A1E0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Admin.UnitTests", "Tests\Knot.Modules.Admin.UnitTests\Knot.Modules.Admin.UnitTests.csproj", "{489D5878-3945-4F8E-AD13-E5499A18DFCC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Admin", "Admin", "{E9E1155A-A339-766C-C185-6698FF423EBC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Admin", "src\Modules\Admin\Knot.Modules.Admin.csproj", "{FFC12440-F128-48F5-9BE5-E5263930F876}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Federation.UnitTests", "Tests\Knot.Modules.Federation.UnitTests\Knot.Modules.Federation.UnitTests.csproj", "{7A402C99-2E66-4EBE-A257-0D7923A96DFD}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Federation", "Federation", "{837D2CF4-7AEA-BF76-6362-47ECD7058EEC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Federation", "src\Modules\Federation\Knot.Modules.Federation.csproj", "{716E089D-0661-4D39-813B-063DF9A4C0E4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Klipy.UnitTests", "Tests\Knot.Modules.Klipy.UnitTests\Knot.Modules.Klipy.UnitTests.csproj", "{43E6E19C-39EC-49C8-91EE-49586A4B9D03}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Klipy", "Klipy", "{4BC86D3F-8D7B-ACB9-EA51-9374BC9D421A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Klipy", "src\Modules\Klipy\Knot.Modules.Klipy.csproj", "{2498C58C-53B0-4DF2-B4EA-BA69B35A7488}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Stories.UnitTests", "Tests\Knot.Modules.Stories.UnitTests\Knot.Modules.Stories.UnitTests.csproj", "{4394178B-1ADD-478E-BF73-574B31C11292}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Relations.UnitTests", "Tests\Knot.Modules.Relations.UnitTests\Knot.Modules.Relations.UnitTests.csproj", "{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Settings.UnitTests", "Tests\Knot.Modules.Settings.UnitTests\Knot.Modules.Settings.UnitTests.csproj", "{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Settings", "Settings", "{0587C5BB-3015-204D-19B6-EB01E03E48B6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Settings", "src\Modules\Settings\Knot.Modules.Settings.csproj", "{AEFD93B4-59B8-4B02-A694-CA15E4EC1C08}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Storage.UnitTests", "Tests\Knot.Modules.Storage.UnitTests\Knot.Modules.Storage.UnitTests.csproj", "{C11BFE93-017D-4538-A61F-A8D98F8D2D75}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.TelegramImport.UnitTests", "Tests\Knot.Modules.TelegramImport.UnitTests\Knot.Modules.TelegramImport.UnitTests.csproj", "{38276FFF-05D8-4005-8863-018CEE833D66}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.WebRtc.UnitTests", "Tests\Knot.Modules.WebRtc.UnitTests\Knot.Modules.WebRtc.UnitTests.csproj", "{32AC7906-B197-4628-9C47-9337BB5A53E2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebRtc", "WebRtc", "{DD6FAF9E-10A0-95E7-0C06-698A6F70AFEE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.WebRtc", "src\Modules\WebRtc\Knot.Modules.WebRtc.csproj", "{03BE4EB1-FD38-445A-9A4B-7B481560E9A2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{D0D6B8B0-AC35-B3FA-0B96-A9B0E4A3253E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegrationTests.Shared", "IntegrationTests.Shared", "{21C6533F-5B99-F63D-D6A0-0D1E74554637}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.IntegrationTests.Shared", "Tests\Shared\IntegrationTests.Shared\Knot.IntegrationTests.Shared.csproj", "{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Host", "src\Host\Host.csproj", "{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Stories", "Stories", "{407BCCB7-2AB0-5429-FB5F-A9376121CF06}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{E7E14295-D412-4B43-44D5-0AAD5D27712E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Stories.UnitTests", "Tests\Stories\UnitTests\Knot.Modules.Stories.UnitTests.csproj", "{8865807E-C577-4476-BE33-0EBB4E07CD8B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegrationTests", "IntegrationTests", "{8CFDC985-5E1F-E566-CA4D-28D1B5AD1B06}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Stories.IntegrationTests", "Tests\Stories\IntegrationTests\Knot.Modules.Stories.IntegrationTests.csproj", "{028AF0DA-6D64-435F-B1CA-C14829892C4F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Admin", "Admin", "{EDEF9ADB-D556-6B20-2E4B-8F977F5C545A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{AA22B6BC-789B-946B-F9BD-06D6D86B3211}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Admin.UnitTests", "Tests\Admin\UnitTests\Knot.Modules.Admin.UnitTests.csproj", "{9DB38617-9738-45C3-A101-8B04869CB07F}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegrationTests", "IntegrationTests", "{1A80A494-6197-707A-BB12-E5CAFEB6DBC3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Admin.IntegrationTests", "Tests\Admin\IntegrationTests\Knot.Modules.Admin.IntegrationTests.csproj", "{ABC9A8FF-0332-4987-A2E8-63108394DA26}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Auth", "Auth", "{EDFE54F1-08A0-5241-003B-94DECB51237C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{50896B77-11EA-ADED-5FA2-195E6FABE81B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Auth.UnitTests", "Tests\Auth\UnitTests\Knot.Modules.Auth.UnitTests.csproj", "{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegrationTests", "IntegrationTests", "{0BF9C624-18C3-4CFE-0DEF-3D1D0C280507}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Auth.IntegrationTests", "Tests\Auth\IntegrationTests\Knot.Modules.Auth.IntegrationTests.csproj", "{776C6198-A229-4C2C-B19E-3F2744BD5279}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Federation", "Federation", "{036B8169-510F-3971-AD3F-66559BF086AA}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{92885E6D-C52A-2FB4-A33D-9A8FE23A87BF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Federation.UnitTests", "Tests\Federation\UnitTests\Knot.Modules.Federation.UnitTests.csproj", "{EA780C77-735F-4FA7-8AE9-78413C928BA6}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegrationTests", "IntegrationTests", "{3794ADC3-BA35-663C-885F-C144081FBEA1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Federation.IntegrationTests", "Tests\Federation\IntegrationTests\Knot.Modules.Federation.IntegrationTests.csproj", "{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Messaging", "Messaging", "{3AB41C38-05DB-BFCC-9BA0-9BC97041A508}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{43109C86-4551-F94F-E9C3-994B9C735653}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Messaging.UnitTests", "Tests\Messaging\UnitTests\Knot.Modules.Messaging.UnitTests.csproj", "{635D6C93-D9E2-46C2-9294-5C0713CBA245}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegrationTests", "IntegrationTests", "{FE27F79D-3631-2D96-056A-69F8E94CD8E3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Messaging.IntegrationTests", "Tests\Messaging\IntegrationTests\Knot.Modules.Messaging.IntegrationTests.csproj", "{0C37AA6D-37DB-439B-97D5-9E799DDDC831}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Relations", "Relations", "{F29503A5-E7F1-B611-4026-76E83B89B0AB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{8D009ABD-C820-B7D4-2412-0990C1960013}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Relations.UnitTests", "Tests\Relations\UnitTests\Knot.Modules.Relations.UnitTests.csproj", "{89593AC0-B761-400D-8213-F6E728980F59}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegrationTests", "IntegrationTests", "{7C677DC5-D0E9-6A09-3DB0-042075A9E677}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Relations.IntegrationTests", "Tests\Relations\IntegrationTests\Knot.Modules.Relations.IntegrationTests.csproj", "{312F4C56-7865-47FD-8170-E6555DBC4884}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Conversations", "Conversations", "{382D38B3-4D74-95AB-947E-DC7B53CBCF32}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{489DA9C1-7DF6-4B43-A5A6-01AD261B3AC8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Conversations.UnitTests", "Tests\Conversations\UnitTests\Knot.Modules.Conversations.UnitTests.csproj", "{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TelegramImport", "TelegramImport", "{A3D04C92-6F74-537C-D0F4-BD2C8CD7687D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{2BF544BD-4498-3DD9-D97E-96A22189C7D8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.TelegramImport.UnitTests", "Tests\TelegramImport\UnitTests\Knot.Modules.TelegramImport.UnitTests.csproj", "{568561C3-C4D9-4783-8103-B68C94E2F8D1}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebRtc", "WebRtc", "{CCF0649B-70C0-BDF5-F1BD-87A1DBED8C5D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{4FFF0ACB-E93F-597A-5968-6C89F4BB5AC7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.WebRtc.UnitTests", "Tests\WebRtc\UnitTests\Knot.Modules.WebRtc.UnitTests.csproj", "{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Klipy", "Klipy", "{46A5ACB5-176C-983D-5434-922CD2C33C4A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{43930E3C-6ABA-C329-E65B-CFA08664DBAF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Klipy.UnitTests", "Tests\Klipy\UnitTests\Knot.Modules.Klipy.UnitTests.csproj", "{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Storage", "Storage", "{B6FD6E61-6054-1C88-3299-57EC8B98D824}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{93CD11E9-EE4D-82DD-DD63-4D36831D0976}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Storage.UnitTests", "Tests\Storage\UnitTests\Knot.Modules.Storage.UnitTests.csproj", "{418BE048-D472-40C0-917F-060A9E781B82}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Users", "Users", "{553D81D4-666B-BE26-75F9-480CB214ACEE}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{3A48F700-9635-2216-D291-85337CE5D869}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Knot.Modules.Profiles.UnitTests", "Tests\Users\UnitTests\Knot.Modules.Profiles.UnitTests.csproj", "{6BD8DC02-2270-4276-952E-E34E973A1237}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -181,18 +265,6 @@ Global
|
||||
{CF08AE9C-B337-47BA-B273-4B8E5610D7BD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CF08AE9C-B337-47BA-B273-4B8E5610D7BD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CF08AE9C-B337-47BA-B273-4B8E5610D7BD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Release|x64.Build.0 = Release|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C0B5496E-F083-413E-90AE-31282A0ACCA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C0B5496E-F083-413E-90AE-31282A0ACCA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C0B5496E-F083-413E-90AE-31282A0ACCA5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -229,18 +301,6 @@ Global
|
||||
{F3EFD119-44F7-46BF-A03C-060F30A1A1E0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F3EFD119-44F7-46BF-A03C-060F30A1A1E0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F3EFD119-44F7-46BF-A03C-060F30A1A1E0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FFC12440-F128-48F5-9BE5-E5263930F876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FFC12440-F128-48F5-9BE5-E5263930F876}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FFC12440-F128-48F5-9BE5-E5263930F876}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -253,18 +313,6 @@ Global
|
||||
{FFC12440-F128-48F5-9BE5-E5263930F876}.Release|x64.Build.0 = Release|Any CPU
|
||||
{FFC12440-F128-48F5-9BE5-E5263930F876}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FFC12440-F128-48F5-9BE5-E5263930F876}.Release|x86.Build.0 = Release|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{716E089D-0661-4D39-813B-063DF9A4C0E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{716E089D-0661-4D39-813B-063DF9A4C0E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{716E089D-0661-4D39-813B-063DF9A4C0E4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -277,18 +325,6 @@ Global
|
||||
{716E089D-0661-4D39-813B-063DF9A4C0E4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{716E089D-0661-4D39-813B-063DF9A4C0E4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{716E089D-0661-4D39-813B-063DF9A4C0E4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Release|x64.Build.0 = Release|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2498C58C-53B0-4DF2-B4EA-BA69B35A7488}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2498C58C-53B0-4DF2-B4EA-BA69B35A7488}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2498C58C-53B0-4DF2-B4EA-BA69B35A7488}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -301,42 +337,6 @@ Global
|
||||
{2498C58C-53B0-4DF2-B4EA-BA69B35A7488}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2498C58C-53B0-4DF2-B4EA-BA69B35A7488}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2498C58C-53B0-4DF2-B4EA-BA69B35A7488}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8}.Release|x86.Build.0 = Release|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{AEFD93B4-59B8-4B02-A694-CA15E4EC1C08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AEFD93B4-59B8-4B02-A694-CA15E4EC1C08}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AEFD93B4-59B8-4B02-A694-CA15E4EC1C08}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -349,42 +349,6 @@ Global
|
||||
{AEFD93B4-59B8-4B02-A694-CA15E4EC1C08}.Release|x64.Build.0 = Release|Any CPU
|
||||
{AEFD93B4-59B8-4B02-A694-CA15E4EC1C08}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AEFD93B4-59B8-4B02-A694-CA15E4EC1C08}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75}.Release|x86.Build.0 = Release|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Release|x64.Build.0 = Release|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66}.Release|x86.Build.0 = Release|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{03BE4EB1-FD38-445A-9A4B-7B481560E9A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{03BE4EB1-FD38-445A-9A4B-7B481560E9A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{03BE4EB1-FD38-445A-9A4B-7B481560E9A2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -397,6 +361,246 @@ Global
|
||||
{03BE4EB1-FD38-445A-9A4B-7B481560E9A2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{03BE4EB1-FD38-445A-9A4B-7B481560E9A2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{03BE4EB1-FD38-445A-9A4B-7B481560E9A2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Release|x64.Build.0 = Release|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Release|x64.Build.0 = Release|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279}.Release|x86.Build.0 = Release|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6}.Release|x86.Build.0 = Release|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Release|x64.Build.0 = Release|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31}.Release|x86.Build.0 = Release|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Release|x64.Build.0 = Release|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831}.Release|x86.Build.0 = Release|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Release|x64.Build.0 = Release|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{89593AC0-B761-400D-8213-F6E728980F59}.Release|x86.Build.0 = Release|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Release|x64.Build.0 = Release|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8}.Release|x86.Build.0 = Release|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Release|x64.Build.0 = Release|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74}.Release|x86.Build.0 = Release|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Release|x64.Build.0 = Release|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408}.Release|x86.Build.0 = Release|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Release|x64.Build.0 = Release|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{418BE048-D472-40C0-917F-060A9E781B82}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237}.Release|x64.ActiveCfg = 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.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -416,31 +620,73 @@ Global
|
||||
{D052C05A-CDCD-48DF-8F4F-0B10E3719819} = {AF61C489-0B09-54BC-BD16-4353135E9C4A}
|
||||
{E9D55F35-C373-3DD8-6914-3213F2F582A2} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||
{CF08AE9C-B337-47BA-B273-4B8E5610D7BD} = {E9D55F35-C373-3DD8-6914-3213F2F582A2}
|
||||
{BA37DF67-98D3-4399-BD68-9679396C1547} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{AE120A0E-5815-2D46-946C-DA544028AD88} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||
{C0B5496E-F083-413E-90AE-31282A0ACCA5} = {AE120A0E-5815-2D46-946C-DA544028AD88}
|
||||
{4D5D7319-366D-1BD8-49C5-A840B487E852} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||
{C905C120-DE44-4CBC-8F98-5BE148115487} = {4D5D7319-366D-1BD8-49C5-A840B487E852}
|
||||
{138B168B-2473-B06D-4BD5-1B010DA319A1} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||
{F3EFD119-44F7-46BF-A03C-060F30A1A1E0} = {138B168B-2473-B06D-4BD5-1B010DA319A1}
|
||||
{489D5878-3945-4F8E-AD13-E5499A18DFCC} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{E9E1155A-A339-766C-C185-6698FF423EBC} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||
{FFC12440-F128-48F5-9BE5-E5263930F876} = {E9E1155A-A339-766C-C185-6698FF423EBC}
|
||||
{7A402C99-2E66-4EBE-A257-0D7923A96DFD} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{837D2CF4-7AEA-BF76-6362-47ECD7058EEC} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||
{716E089D-0661-4D39-813B-063DF9A4C0E4} = {837D2CF4-7AEA-BF76-6362-47ECD7058EEC}
|
||||
{43E6E19C-39EC-49C8-91EE-49586A4B9D03} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{4BC86D3F-8D7B-ACB9-EA51-9374BC9D421A} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||
{2498C58C-53B0-4DF2-B4EA-BA69B35A7488} = {4BC86D3F-8D7B-ACB9-EA51-9374BC9D421A}
|
||||
{4394178B-1ADD-478E-BF73-574B31C11292} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{2F2C7E01-5791-4A6D-9A80-C71CAD846FA8} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{76706BA9-11E0-463A-AF8E-18DFBD9E95A2} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{0587C5BB-3015-204D-19B6-EB01E03E48B6} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||
{AEFD93B4-59B8-4B02-A694-CA15E4EC1C08} = {0587C5BB-3015-204D-19B6-EB01E03E48B6}
|
||||
{C11BFE93-017D-4538-A61F-A8D98F8D2D75} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{38276FFF-05D8-4005-8863-018CEE833D66} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{32AC7906-B197-4628-9C47-9337BB5A53E2} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{DD6FAF9E-10A0-95E7-0C06-698A6F70AFEE} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||
{03BE4EB1-FD38-445A-9A4B-7B481560E9A2} = {DD6FAF9E-10A0-95E7-0C06-698A6F70AFEE}
|
||||
{D0D6B8B0-AC35-B3FA-0B96-A9B0E4A3253E} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{21C6533F-5B99-F63D-D6A0-0D1E74554637} = {D0D6B8B0-AC35-B3FA-0B96-A9B0E4A3253E}
|
||||
{2BDD861B-44BC-463B-88C4-E8E2B516A7EE} = {21C6533F-5B99-F63D-D6A0-0D1E74554637}
|
||||
{98ABB710-9106-4E5C-AA04-D19D5E92EDC1} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
||||
{407BCCB7-2AB0-5429-FB5F-A9376121CF06} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{E7E14295-D412-4B43-44D5-0AAD5D27712E} = {407BCCB7-2AB0-5429-FB5F-A9376121CF06}
|
||||
{8865807E-C577-4476-BE33-0EBB4E07CD8B} = {E7E14295-D412-4B43-44D5-0AAD5D27712E}
|
||||
{8CFDC985-5E1F-E566-CA4D-28D1B5AD1B06} = {407BCCB7-2AB0-5429-FB5F-A9376121CF06}
|
||||
{028AF0DA-6D64-435F-B1CA-C14829892C4F} = {8CFDC985-5E1F-E566-CA4D-28D1B5AD1B06}
|
||||
{EDEF9ADB-D556-6B20-2E4B-8F977F5C545A} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{AA22B6BC-789B-946B-F9BD-06D6D86B3211} = {EDEF9ADB-D556-6B20-2E4B-8F977F5C545A}
|
||||
{9DB38617-9738-45C3-A101-8B04869CB07F} = {AA22B6BC-789B-946B-F9BD-06D6D86B3211}
|
||||
{1A80A494-6197-707A-BB12-E5CAFEB6DBC3} = {EDEF9ADB-D556-6B20-2E4B-8F977F5C545A}
|
||||
{ABC9A8FF-0332-4987-A2E8-63108394DA26} = {1A80A494-6197-707A-BB12-E5CAFEB6DBC3}
|
||||
{EDFE54F1-08A0-5241-003B-94DECB51237C} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{50896B77-11EA-ADED-5FA2-195E6FABE81B} = {EDFE54F1-08A0-5241-003B-94DECB51237C}
|
||||
{DD4F5E02-4366-4CA3-8CF1-941C21C27B6E} = {50896B77-11EA-ADED-5FA2-195E6FABE81B}
|
||||
{0BF9C624-18C3-4CFE-0DEF-3D1D0C280507} = {EDFE54F1-08A0-5241-003B-94DECB51237C}
|
||||
{776C6198-A229-4C2C-B19E-3F2744BD5279} = {0BF9C624-18C3-4CFE-0DEF-3D1D0C280507}
|
||||
{036B8169-510F-3971-AD3F-66559BF086AA} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{92885E6D-C52A-2FB4-A33D-9A8FE23A87BF} = {036B8169-510F-3971-AD3F-66559BF086AA}
|
||||
{EA780C77-735F-4FA7-8AE9-78413C928BA6} = {92885E6D-C52A-2FB4-A33D-9A8FE23A87BF}
|
||||
{3794ADC3-BA35-663C-885F-C144081FBEA1} = {036B8169-510F-3971-AD3F-66559BF086AA}
|
||||
{60326D0F-D9C7-4B8D-B664-BC8DE239AD31} = {3794ADC3-BA35-663C-885F-C144081FBEA1}
|
||||
{3AB41C38-05DB-BFCC-9BA0-9BC97041A508} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{43109C86-4551-F94F-E9C3-994B9C735653} = {3AB41C38-05DB-BFCC-9BA0-9BC97041A508}
|
||||
{635D6C93-D9E2-46C2-9294-5C0713CBA245} = {43109C86-4551-F94F-E9C3-994B9C735653}
|
||||
{FE27F79D-3631-2D96-056A-69F8E94CD8E3} = {3AB41C38-05DB-BFCC-9BA0-9BC97041A508}
|
||||
{0C37AA6D-37DB-439B-97D5-9E799DDDC831} = {FE27F79D-3631-2D96-056A-69F8E94CD8E3}
|
||||
{F29503A5-E7F1-B611-4026-76E83B89B0AB} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{8D009ABD-C820-B7D4-2412-0990C1960013} = {F29503A5-E7F1-B611-4026-76E83B89B0AB}
|
||||
{89593AC0-B761-400D-8213-F6E728980F59} = {8D009ABD-C820-B7D4-2412-0990C1960013}
|
||||
{7C677DC5-D0E9-6A09-3DB0-042075A9E677} = {F29503A5-E7F1-B611-4026-76E83B89B0AB}
|
||||
{312F4C56-7865-47FD-8170-E6555DBC4884} = {7C677DC5-D0E9-6A09-3DB0-042075A9E677}
|
||||
{382D38B3-4D74-95AB-947E-DC7B53CBCF32} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{489DA9C1-7DF6-4B43-A5A6-01AD261B3AC8} = {382D38B3-4D74-95AB-947E-DC7B53CBCF32}
|
||||
{5B428B36-6857-47BA-8DE1-A8207A2DF1E8} = {489DA9C1-7DF6-4B43-A5A6-01AD261B3AC8}
|
||||
{A3D04C92-6F74-537C-D0F4-BD2C8CD7687D} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{2BF544BD-4498-3DD9-D97E-96A22189C7D8} = {A3D04C92-6F74-537C-D0F4-BD2C8CD7687D}
|
||||
{568561C3-C4D9-4783-8103-B68C94E2F8D1} = {2BF544BD-4498-3DD9-D97E-96A22189C7D8}
|
||||
{CCF0649B-70C0-BDF5-F1BD-87A1DBED8C5D} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{4FFF0ACB-E93F-597A-5968-6C89F4BB5AC7} = {CCF0649B-70C0-BDF5-F1BD-87A1DBED8C5D}
|
||||
{65A65ABB-1F74-471C-84C5-E9CBA6F27B74} = {4FFF0ACB-E93F-597A-5968-6C89F4BB5AC7}
|
||||
{46A5ACB5-176C-983D-5434-922CD2C33C4A} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{43930E3C-6ABA-C329-E65B-CFA08664DBAF} = {46A5ACB5-176C-983D-5434-922CD2C33C4A}
|
||||
{71B7CB00-B0B9-4FEB-9E9F-E8B47FAD5408} = {43930E3C-6ABA-C329-E65B-CFA08664DBAF}
|
||||
{B6FD6E61-6054-1C88-3299-57EC8B98D824} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{93CD11E9-EE4D-82DD-DD63-4D36831D0976} = {B6FD6E61-6054-1C88-3299-57EC8B98D824}
|
||||
{418BE048-D472-40C0-917F-060A9E781B82} = {93CD11E9-EE4D-82DD-DD63-4D36831D0976}
|
||||
{553D81D4-666B-BE26-75F9-480CB214ACEE} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
||||
{3A48F700-9635-2216-D291-85337CE5D869} = {553D81D4-666B-BE26-75F9-480CB214ACEE}
|
||||
{6BD8DC02-2270-4276-952E-E34E973A1237} = {3A48F700-9635-2216-D291-85337CE5D869}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Shared\IntegrationTests.Shared\Knot.IntegrationTests.Shared.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Admin\Knot.Modules.Admin.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -21,8 +21,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\Admin\Knot.Modules.Admin.csproj" />
|
||||
<ProjectReference Include="..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Admin\Knot.Modules.Admin.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -21,8 +21,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
<ProjectReference Include="..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,5 +1,5 @@
|
||||
using FluentAssertions;
|
||||
using Host.Application.Admin.Commands;
|
||||
using Knot.Modules.Admin.Application.Admin.Commands;
|
||||
using Knot.Modules.Auth.Application.Abstractions;
|
||||
using Knot.Modules.Auth.Domain;
|
||||
using Knot.Shared.Kernel;
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -10,13 +10,14 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\Identity\Knot.Modules.Auth.csproj" />
|
||||
<ProjectReference Include="..\..\src\Modules\Auth\Knot.Modules.Auth.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Auth\Knot.Modules.Auth.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
|
||||
@@ -23,9 +23,11 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\Chats\Knot.Modules.Conversations.csproj" />
|
||||
<ProjectReference Include="..\..\src\Modules\Messaging\Knot.Modules.Messaging.csproj" />
|
||||
<ProjectReference Include="..\..\src\Modules\Conversations\Knot.Modules.Conversations.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Chats\Knot.Modules.Conversations.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Messaging\Knot.Modules.Messaging.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Conversations\Knot.Modules.Conversations.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -12,6 +12,8 @@ using Knot.Modules.Conversations.Domain;
|
||||
using Knot.Modules.Messaging.Domain;
|
||||
using Knot.Modules.Conversations.Application.Abstractions;
|
||||
using Knot.Modules.Conversations.Application.Messages.Send;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
namespace Knot.Modules.Conversations.UnitTests.Messages;
|
||||
|
||||
@@ -21,6 +23,7 @@ public class SendMessageCommandHandlerTests
|
||||
private readonly IMessageRepository _messageRepository;
|
||||
private readonly IChatsUnitOfWork _unitOfWork;
|
||||
private readonly IMediator _mediator;
|
||||
private readonly IMessagesSettings _messagesSettings;
|
||||
private readonly SendMessageCommandHandler _handler;
|
||||
|
||||
public SendMessageCommandHandlerTests()
|
||||
@@ -29,8 +32,12 @@ public class SendMessageCommandHandlerTests
|
||||
_messageRepository = Substitute.For<IMessageRepository>();
|
||||
_unitOfWork = Substitute.For<IChatsUnitOfWork>();
|
||||
_mediator = Substitute.For<IMediator>();
|
||||
_messagesSettings = Substitute.For<IMessagesSettings>();
|
||||
|
||||
var config = new Knot.Modules.Settings.Application.Settings.DTOs.MessagesConfig();
|
||||
_messagesSettings.Current.Returns(config);
|
||||
|
||||
_handler = new SendMessageCommandHandler(_chatRepository, _messageRepository, _unitOfWork, _mediator);
|
||||
_handler = new SendMessageCommandHandler(_chatRepository, _messageRepository, _unitOfWork, _mediator, _messagesSettings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -21,8 +21,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\Federation\Knot.Modules.Federation.csproj" />
|
||||
<ProjectReference Include="..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Federation\Knot.Modules.Federation.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -21,8 +21,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\Klipy\Knot.Modules.Klipy.csproj" />
|
||||
<ProjectReference Include="..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Klipy\Knot.Modules.Klipy.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Knot.Modules.Conversations.Application.Chats.Commands.CreatePersonalChat;
|
||||
using Knot.Modules.Conversations.Domain;
|
||||
using Knot.Modules.Conversations.Application.Abstractions;
|
||||
using Knot.Shared.Kernel;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Conversations.UnitTests;
|
||||
|
||||
public class CreatePersonalChatCommandHandlerTests
|
||||
{
|
||||
private readonly IChatRepository _chatRepository;
|
||||
private readonly IChatsUnitOfWork _unitOfWork;
|
||||
private readonly CreatePersonalChatCommandHandler _handler;
|
||||
|
||||
public CreatePersonalChatCommandHandlerTests()
|
||||
{
|
||||
_chatRepository = Substitute.For<IChatRepository>();
|
||||
_unitOfWork = Substitute.For<IChatsUnitOfWork>();
|
||||
_handler = new CreatePersonalChatCommandHandler(_chatRepository, _unitOfWork);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ShouldReturnError_WhenChatAlreadyExists()
|
||||
{
|
||||
// Arrange
|
||||
var command = new CreatePersonalChatCommand(Guid.NewGuid(), Guid.NewGuid());
|
||||
_chatRepository.GetPersonalChatAsync(command.InitiatorId, command.TargetUserId, Arg.Any<CancellationToken>())
|
||||
.Returns(PersonalChat.Create(command.InitiatorId, command.TargetUserId));
|
||||
|
||||
// Act
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Should().Be(ChatErrors.PersonalChatAlreadyExists);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -21,8 +21,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\Relations\Knot.Modules.Relations.csproj" />
|
||||
<ProjectReference Include="..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Relations\Knot.Modules.Relations.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Net.Http;
|
||||
using Testcontainers.PostgreSql;
|
||||
using Testcontainers.MongoDb;
|
||||
using Xunit;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using Knot.Shared.Kernel;
|
||||
using NSubstitute;
|
||||
|
||||
namespace Knot.IntegrationTests;
|
||||
|
||||
public abstract class BaseIntegrationTest : IAsyncLifetime
|
||||
{
|
||||
protected readonly PostgreSqlContainer _postgresContainer = new PostgreSqlBuilder()
|
||||
.WithImage("postgres:15-alpine")
|
||||
.Build();
|
||||
|
||||
protected readonly MongoDbContainer _mongoContainer = new MongoDbBuilder()
|
||||
.WithImage("mongo:6.0")
|
||||
.Build();
|
||||
|
||||
protected HttpClient _client;
|
||||
protected WebApplicationFactory<Program> _factory;
|
||||
protected readonly Guid _userId = Guid.NewGuid();
|
||||
protected readonly IUserContext _userContextMock = Substitute.For<IUserContext>();
|
||||
|
||||
public virtual async Task InitializeAsync()
|
||||
{
|
||||
await _postgresContainer.StartAsync();
|
||||
await _mongoContainer.StartAsync();
|
||||
|
||||
_userContextMock.UserId.Returns(_userId);
|
||||
_userContextMock.IsAuthenticated.Returns(true);
|
||||
|
||||
_factory = new IntegrationTestWebApplicationFactory(
|
||||
_postgresContainer.GetConnectionString(),
|
||||
_mongoContainer.GetConnectionString(),
|
||||
_userContextMock);
|
||||
|
||||
_client = _factory.CreateClient();
|
||||
}
|
||||
|
||||
public virtual async Task DisposeAsync()
|
||||
{
|
||||
await _postgresContainer.StopAsync();
|
||||
await _mongoContainer.StopAsync();
|
||||
_factory?.Dispose();
|
||||
_client?.Dispose();
|
||||
}
|
||||
|
||||
private class IntegrationTestWebApplicationFactory : WebApplicationFactory<Program>
|
||||
{
|
||||
private readonly string _pgConnectionString;
|
||||
private readonly string _mongoConnectionString;
|
||||
private readonly IUserContext _userContext;
|
||||
|
||||
public IntegrationTestWebApplicationFactory(string pg, string mongo, IUserContext userContext)
|
||||
{
|
||||
_pgConnectionString = pg;
|
||||
_mongoConnectionString = mongo;
|
||||
_userContext = userContext;
|
||||
}
|
||||
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
builder.ConfigureAppConfiguration((context, config) =>
|
||||
{
|
||||
config.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
["ConnectionStrings:DefaultConnection"] = _pgConnectionString,
|
||||
["ConnectionStrings:MongoConnection"] = _mongoConnectionString,
|
||||
["DATABASE_URL"] = _pgConnectionString,
|
||||
["MONGO_CONNECTION"] = _mongoConnectionString,
|
||||
["KNOT_MASTER_ENCRYPTION_KEY"] = "TestEncryptionKey_32CharactersLong!"
|
||||
});
|
||||
});
|
||||
|
||||
builder.ConfigureTestServices(services => {
|
||||
services.AddScoped(_ => _userContext);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="FluentAssertions" Version="8.9.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
||||
<PackageReference Include="Respawn" Version="7.0.0" />
|
||||
<PackageReference Include="Testcontainers.MongoDb" Version="4.11.0" />
|
||||
<PackageReference Include="Testcontainers.PostgreSql" Version="4.11.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Host\Host.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Infrastructure\Knot.Shared.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -21,8 +21,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\Storage\Knot.Modules.Storage.csproj" />
|
||||
<ProjectReference Include="..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Storage\Knot.Modules.Storage.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Shared\IntegrationTests.Shared\Knot.IntegrationTests.Shared.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Stories\Knot.Modules.Stories.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
34
backend/Tests/Stories/IntegrationTests/StoriesTests.cs
Normal file
34
backend/Tests/Stories/IntegrationTests/StoriesTests.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Knot.IntegrationTests;
|
||||
using FluentAssertions;
|
||||
using Knot.Modules.Stories.Application.Stories.Commands.CreateStory;
|
||||
using Knot.Shared.Kernel;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NSubstitute;
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.IntegrationTests.Stories;
|
||||
|
||||
public class StoriesTests : BaseIntegrationTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task CreateStory_ShouldReturnOk_WhenValidRequest()
|
||||
{
|
||||
// Arrange
|
||||
var request = new CreateStoryRequest("Text", null, "Hello Integration Test", null);
|
||||
|
||||
// Act
|
||||
var response = await _client.PostAsJsonAsync("api/stories", request);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var content = await response.Content.ReadFromJsonAsync<dynamic>();
|
||||
}
|
||||
}
|
||||
|
||||
public record CreateStoryRequest(string Type, string? MediaUrl, string? Content, string? BgColor);
|
||||
@@ -0,0 +1,76 @@
|
||||
using FluentAssertions;
|
||||
using Knot.Modules.Stories.Application.Stories.Commands.CreateStory;
|
||||
using Knot.Modules.Stories.Domain;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Modules.Stories.Application.Abstractions;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Stories.UnitTests;
|
||||
|
||||
public class CreateStoryCommandHandlerTests
|
||||
{
|
||||
private readonly IStoryRepository _storyRepository;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly CreateStoryCommandHandler _handler;
|
||||
|
||||
public CreateStoryCommandHandlerTests()
|
||||
{
|
||||
_storyRepository = Substitute.For<IStoryRepository>();
|
||||
_settingsService = Substitute.For<ISettingsService>();
|
||||
_handler = new CreateStoryCommandHandler(_storyRepository, _settingsService);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ShouldSucceed_WhenValidRequest()
|
||||
{
|
||||
// Arrange
|
||||
var command = new CreateStoryCommand(Guid.NewGuid(), "Text", null, "Hello Story", null);
|
||||
|
||||
// Act
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
await _storyRepository.Received(1).AddAsync(Arg.Any<Story>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ShouldFail_WhenKlipyDisabledAndKlipyType()
|
||||
{
|
||||
// Arrange
|
||||
var command = new CreateStoryCommand(Guid.NewGuid(), "Klipy", "http://klipy.com/gif", null, null);
|
||||
var settings = new SystemSettingsDto { Klipy = new KlipyConfig { Enabled = false } };
|
||||
_settingsService.GetSettingsAsync(Arg.Any<CancellationToken>()).Returns(settings);
|
||||
|
||||
// Act
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Code.Should().Be("Stories.KlipyDisabled");
|
||||
await _storyRepository.DidNotReceive().AddAsync(Arg.Any<Story>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ShouldSucceed_WhenKlipyEnabledAndKlipyType()
|
||||
{
|
||||
// Arrange
|
||||
var command = new CreateStoryCommand(Guid.NewGuid(), "Klipy", "http://klipy.com/gif", null, null);
|
||||
var settings = new SystemSettingsDto { Klipy = new KlipyConfig { Enabled = true } };
|
||||
_settingsService.GetSettingsAsync(Arg.Any<CancellationToken>()).Returns(settings);
|
||||
|
||||
// Act
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
await _storyRepository.Received(1).AddAsync(Arg.Any<Story>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
using FluentAssertions;
|
||||
using Knot.Modules.Stories.Application.Stories.Commands.DeleteStory;
|
||||
using Knot.Modules.Stories.Domain;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Stories.Application.Abstractions;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Stories.UnitTests;
|
||||
|
||||
public class DeleteStoryCommandHandlerTests
|
||||
{
|
||||
private readonly IStoryRepository _storyRepository;
|
||||
private readonly DeleteStoryCommandHandler _handler;
|
||||
|
||||
public DeleteStoryCommandHandlerTests()
|
||||
{
|
||||
_storyRepository = Substitute.For<IStoryRepository>();
|
||||
_handler = new DeleteStoryCommandHandler(_storyRepository);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ShouldReturnError_WhenStoryNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var command = new DeleteStoryCommand(Guid.NewGuid(), Guid.NewGuid());
|
||||
_storyRepository.GetByIdAsync(command.StoryId, Arg.Any<CancellationToken>()).Returns((Story?)null);
|
||||
|
||||
// Act
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Should().Be(StoryErrors.StoryNotFound);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ShouldReturnError_WhenUserIsNotOwner()
|
||||
{
|
||||
// Arrange
|
||||
var ownerId = Guid.NewGuid();
|
||||
var viewerId = Guid.NewGuid();
|
||||
var story = Story.Create(ownerId, StoryType.Text, null, "Content", null);
|
||||
var command = new DeleteStoryCommand(viewerId, story.Id);
|
||||
|
||||
_storyRepository.GetByIdAsync(command.StoryId, Arg.Any<CancellationToken>()).Returns(story);
|
||||
|
||||
// Act
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Should().Be(StoryErrors.Unauthorized);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ShouldSucceed_WhenOwnerDeletes()
|
||||
{
|
||||
// Arrange
|
||||
var ownerId = Guid.NewGuid();
|
||||
var story = Story.Create(ownerId, StoryType.Text, null, "Content", null);
|
||||
var command = new DeleteStoryCommand(ownerId, story.Id);
|
||||
|
||||
_storyRepository.GetByIdAsync(command.StoryId, Arg.Any<CancellationToken>()).Returns(story);
|
||||
|
||||
// Act
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.Should().BeTrue();
|
||||
await _storyRepository.Received(1).DeleteAsync(story, Arg.Any<CancellationToken>());
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -21,8 +21,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\Stories\Knot.Modules.Stories.csproj" />
|
||||
<ProjectReference Include="..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Stories\Knot.Modules.Stories.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -21,8 +21,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\TelegramImport\Knot.Modules.TelegramImport.csproj" />
|
||||
<ProjectReference Include="..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\TelegramImport\Knot.Modules.TelegramImport.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
<PackageReference Include="FluentAssertions" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Modules\Profiles\Knot.Modules.Profiles.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,41 +1,38 @@
|
||||
using FluentAssertions;
|
||||
using Knot.Modules.Profiles.Application.Profiles.Commands.UpdateProfile;
|
||||
using Knot.Modules.Profiles.Application.Profiles.UpdateProfile;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Shared.Kernel;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
|
||||
namespace Knot.Modules.Profiles.UnitTests;
|
||||
|
||||
public class UpdateProfileCommandHandlerTests
|
||||
{
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
private readonly IProfilesUnitOfWork _unitOfWork;
|
||||
private readonly UpdateProfileCommandHandler _handler;
|
||||
|
||||
public UpdateProfileCommandHandlerTests()
|
||||
{
|
||||
_profileRepository = Substitute.For<IProfileRepository>();
|
||||
_unitOfWork = Substitute.For<IProfilesUnitOfWork>();
|
||||
_handler = new UpdateProfileCommandHandler(_profileRepository, _unitOfWork);
|
||||
_handler = new UpdateProfileCommandHandler(_profileRepository);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ShouldReturnError_WhenProfileNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var command = new UpdateProfileCommand(Guid.NewGuid(), "FirstName", "LastName", "Bio");
|
||||
_profileRepository.GetByIdAsync(command.UserId, Arg.Any<CancellationToken>()).Returns((UserProfile?)null);
|
||||
var command = new UpdateProfileCommand(Guid.NewGuid(), "FirstName", "Bio", null);
|
||||
_profileRepository.GetByIdAsync(command.UserId, Arg.Any<CancellationToken>()).Returns((ProfileDocument?)null);
|
||||
|
||||
// Act
|
||||
var result = await _handler.Handle(command, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.IsFailure.Should().BeTrue();
|
||||
result.Error.Should().Be(ProfileErrors.NotFound);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
@@ -21,8 +21,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Modules\WebRtc\Knot.Modules.WebRtc.csproj" />
|
||||
<ProjectReference Include="..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\WebRtc\Knot.Modules.WebRtc.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Modules\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
105
backend/src/Docs/profiles_module_documentation.md
Normal file
105
backend/src/Docs/profiles_module_documentation.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Документация модуля Profiles (Профили пользователей)
|
||||
|
||||
## Введение
|
||||
|
||||
Модуль `Knot.Modules.Profiles` отвечает за управление публичными данными пользователей, их аватарами и настройками отображения в мессенджере Knot Messager.
|
||||
|
||||
### Разделение ответственности (Auth vs Profiles)
|
||||
В соответствии с принципами **DDD (Domain-Driven Design)** и **Чистой Архитектуры**, модуль Profiles отделен от модуля Auth:
|
||||
* **Auth (Postgres):** Занимается идентификацией (логин, пароль, токены, email).
|
||||
* **Profiles (MongoDB + S3):** Занимается представлением пользователя (имя, био, аватар, настройки видимости).
|
||||
|
||||
Это разделение позволяет изменять структуру профиля (добавлять новые социальные ссылки, поля "О себе") без выполнения миграций в основной реляционной БД.
|
||||
|
||||
---
|
||||
|
||||
## Архитектура хранения данных (Гибридный подход)
|
||||
|
||||
Модуль использует **гибридную схему хранения**, оптимизированную для производительности и гибкости:
|
||||
|
||||
1. **Metadata (MongoDB):** Документ `ProfileDocument` содержит все текстовые данные профиля. Использование NoSQL позволяет легко расширять схему данных.
|
||||
2. **Media (S3/MinIO):** Файлы аватаров хранятся во внешнем объектном хранилище. В MongoDB хранится только `AvatarUrl` (ссылка на файл).
|
||||
3. **Identity Link (UserId):** Поле `Id` в MongoDB-документе совпадает с `UserId` из PostgreSQL. Это единственный ключ для связи модулей.
|
||||
|
||||
---
|
||||
|
||||
## Доменная модель
|
||||
|
||||
### ProfileDocument (Aggregate Root)
|
||||
Основная сущность в модуле. Находится в слое `Domain`.
|
||||
* **Username:** Уникальный хендл пользователя.
|
||||
* **DisplayName:** Публичное имя (может меняться).
|
||||
* **Bio:** Короткая биографическая справка.
|
||||
* **AvatarUrl:** Путь к файлу в формате `/api/files/{fileId}`.
|
||||
* **HideStoryViews:** Флаг приватности (скрывать просмотр сторис от других).
|
||||
|
||||
### Доменные события
|
||||
Модуль генерирует и слушает события для обеспечения согласованности:
|
||||
* `UserRegisteredDomainEvent`: Слушается модулем Profiles (от Auth). При получении создается начальный документ профиля в MongoDB.
|
||||
* `ProfileAvatarChangedDomainEvent`: Генерируется при смене аватара (для потенциальной очистки кэша).
|
||||
|
||||
---
|
||||
|
||||
## Ключевые возможности
|
||||
|
||||
### 1. Управление аватарами
|
||||
Модуль предоставляет эндпоинты для загрузки и удаления аватаров:
|
||||
* **Автоматическое кадрирование:** При вызове `/avatar/crop` используется библиотека `ImageSharp` для вырезания области изображения и ресайза до `400x400` пикселей в формате JPEG.
|
||||
* **Авто-очистка:** При загрузке нового аватара модуль автоматически удаляет старый файл из S3, предотвращая появление "файлов-сирот".
|
||||
|
||||
### 2. Поиск пользователей
|
||||
Реализован через `ProfileRepository` с использованием регулярных выражений MongoDB (case-insensitive) по полям `Username` и `DisplayName`.
|
||||
|
||||
### 3. Настройки приватности
|
||||
Пользователь может управлять отображением своей активности (например, `HideStoryViews`), что сохраняется непосредственно в документе профиля.
|
||||
|
||||
---
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```text
|
||||
Knot.Modules.Profiles/
|
||||
├── Application/
|
||||
│ ├── Abstractions/ # Интерфейсы IProfileRepository, IAvatarStorageService
|
||||
│ ├── Profiles/ # Case-обработчики (Handlers)
|
||||
│ │ ├── Avatar/ # Загрузка, обрезка, удаление аватара
|
||||
│ │ ├── GetUser/ # Получение данных профиля
|
||||
│ │ ├── Search/ # Поиск по базе профилей
|
||||
│ │ └── UpdateProfile/ # Обновление текстовых данных
|
||||
│ └── Integration/ # Обработчики событий от других модулей
|
||||
├── Domain/
|
||||
│ ├── ProfileDocument.cs # Корень агрегата (Mongo Document)
|
||||
│ └── Events/ # Доменные события
|
||||
├── Infrastructure/
|
||||
│ └── Database/ # Реализация репозиториев для MongoDB и S3
|
||||
├── Presentation/
|
||||
│ └── Endpoints/ # Carter-модули (API эндпоинты)
|
||||
└── DependencyInjection.cs # Регистрация сервисов и MongoDB клиента
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Технические детали реализации
|
||||
|
||||
### Интеграция с S3 (MinIO)
|
||||
В модуле реализован адаптер `AvatarStorageService`, который инкапсулирует работу с `IFileStorageService`. Он отвечает за:
|
||||
1. Генерацию уникальных ключей файлов.
|
||||
2. Шифрование контента (через Shared Infrastructure).
|
||||
3. Очистку путей (преобразование URL в ID файла для удаления).
|
||||
|
||||
### Настройка MongoDB
|
||||
Репозиторий `ProfileRepository` использует типизированную коллекцию `IMongoCollection<ProfileDocument>`. Первичный ключ `Id` мапится как строка (BsonType.String) для совместимости с `Guid` из .NET.
|
||||
|
||||
---
|
||||
|
||||
## API Эндпоинты (Примеры)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| :--- | :--- | :--- |
|
||||
| `GET` | `/api/profiles/{id}` | Получить данные профиля пользователя. |
|
||||
| `GET` | `/api/profiles/search?q=text` | Найти пользователей по имени или никнейму. |
|
||||
| `PUT` | `/api/profiles/profile` | Обновить DisplayName, Bio, Birthday. |
|
||||
| `POST` | `/api/profiles/avatar` | Простая загрузка аватара (FormFile). |
|
||||
| `POST` | `/api/profiles/avatar/crop` | Загрузка с указанием координат обрезки (x, y, w, h). |
|
||||
| `DELETE` | `/api/profiles/avatar` | Удаление текущего аватара и файла из S3. |
|
||||
| `PUT` | `/api/profiles/settings` | Обновить настройки приватности профиля. |
|
||||
129
backend/src/Docs/settings_module_documentation.md
Normal file
129
backend/src/Docs/settings_module_documentation.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Документация модуля Settings (Настройки)
|
||||
|
||||
## Введение
|
||||
|
||||
Модуль `Knot.Modules.Settings` является централизованным компонентом для управления глобальными конфигурациями и параметрами системы в архитектуре модульного монолита (Modular Monolith) Knot Messager. Он обеспечивает единый источник истины (Single Source of Truth) для настроек всех других модулей (WebRTC, Federation, Messages, Chats, Admin и др.).
|
||||
|
||||
## Основные принципы (DDD и Clean Architecture)
|
||||
|
||||
- **Независимость и Инкапсуляция:** Модуль выступает как самостоятельная единица и не зависит от реализаций других модулей. Другие модули ссылаются на `Settings` только через абстракции или контракты.
|
||||
- **Единственный Источник Истины:** Любое изменение системной конфигурации (включение/отключение фич, лимиты, домены) происходит через этот модуль.
|
||||
- **Событийная Модель (Domain Events):** При изменении настроек инфраструктура Settings генерирует доменное событие `SystemSettingsUpdatedDomainEvent`, позволяя другим модулям (например, `Federation` для отправки новых Capabilities) реагировать на изменения асинхронно, не создавая жестких связей.
|
||||
|
||||
## Структура модуля
|
||||
|
||||
Модуль спроектирован по принципам Чистой Архитектуры и разделен на слои:
|
||||
|
||||
```text
|
||||
Knot.Modules.Settings/
|
||||
├── Application/ # Слой Приложения (Application Layer)
|
||||
│ ├── Settings/
|
||||
│ │ ├── Abstractions/ # Определение интерфейсов доступа к каждому разделу настроек
|
||||
│ │ │ ├── ISettingsService.cs
|
||||
│ │ │ ├── IMessagesSettings.cs
|
||||
│ │ │ ├── IWebRtcSettings.cs
|
||||
│ │ │ └── ...
|
||||
│ │ ├── DTOs/ # Структуры данных конфигураций
|
||||
│ │ ├── SystemSettingsDto.cs
|
||||
│ │ ├── PublicConfigDto.cs
|
||||
│ │ ├── KlipyConfig.cs
|
||||
│ │ └── ...
|
||||
├── Domain/ # Доменный Слой (Domain Layer)
|
||||
│ ├── Events/
|
||||
│ │ └── SystemSettingsUpdatedDomainEvent.cs # Событие об изменении настроек
|
||||
├── Infrastructure/ # Слой Инфраструктуры (Infrastructure Layer)
|
||||
│ ├── Configuration/
|
||||
│ │ └── SettingsService.cs # Реализация логики кэширования и обновления
|
||||
├── DependencyInjection.cs # Регистрация модуля в DI (AddSettingsModule)
|
||||
```
|
||||
|
||||
## Как это работает?
|
||||
|
||||
### 1. Интерфейсы сегрегации (Interface Segregation Principle - ISP)
|
||||
|
||||
Чтобы модули не зависели от огромного объекта настройки всей системы `SystemSettingsDto`, в слое `Application/Settings/Abstractions/ISettingsService.cs` мы разделили конфигурации на интерфейсы по специализациям:
|
||||
|
||||
- `ISystemSettings` — Системные и общие параметры.
|
||||
- `IWebRtcSettings` — Настройки аудио/видео вызовов (WebRTC, TURN).
|
||||
- `IMessagesSettings` — Настройки сообщений (файлы, ограничения).
|
||||
- `IFederationSettings` — Настройки ActivityPub/Федерации.
|
||||
- `IKlipySettings` — Настройки интеграции внешней библиотеки гифок (Klipy).
|
||||
|
||||
### 2. Доступ к настройкам из других модулей
|
||||
|
||||
Если, например, модулю бесед (Conversations) требуется проверить, включены ли интеграции Klipy, он инжектит специфичный интерфейс `IKlipySettings`, не получая доступа к настройкам админки или WebRTC:
|
||||
|
||||
```csharp
|
||||
public class CreateStoryCommandHandler
|
||||
{
|
||||
private readonly IKlipySettings _klipySettings;
|
||||
|
||||
public CreateStoryCommandHandler(IKlipySettings klipySettings)
|
||||
{
|
||||
_klipySettings = klipySettings;
|
||||
}
|
||||
|
||||
public async Task Handle(...)
|
||||
{
|
||||
if (!_klipySettings.Current.Enabled) {
|
||||
// Отбросить логику
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Хранение и шифрование данных
|
||||
|
||||
Реализация `SettingsService` хранит данные централизованно (в таблице `SystemSettings` БД через `SystemDbContext` в `Knot.Shared.Infrastructure`) в формате JSON.
|
||||
Для безопасности вся JSON-строка **зашифрована** с использованием `IEncryptionService`.
|
||||
|
||||
Особенности хранения:
|
||||
- **Кэширование**: `SettingsService` зарегистрирован как `Singleton`. При запуске сервера конфигурация загружается один раз из базы данных (или кеша/файла) и сохраняется в памяти.
|
||||
- **Обновление**: Метод `UpdateSettingsAsync` сохраняет новый стейт в БД и обновляет объект в памяти (`_current`), предотвращая лишние запросы к базе данных при обычной работе мессенджера.
|
||||
|
||||
## Жизненный цикл обновления настроек (Управление)
|
||||
|
||||
Администратор изменяет настройки через UI (или API), после чего происходит следующий процесс:
|
||||
|
||||
1. Вызывается эндпоинт в модуле **Admin**: `PUT /api/admin/settings`.
|
||||
2. Команда `UpdateSettingsCommand` валидирует входные данные.
|
||||
3. Команда обращается к `ISettingsService.UpdateSettingsAsync(newSettings)`.
|
||||
4. `SettingsService` шифрует новые настройки, обновляет запись в БД, и заменяет кэш в оперативной памяти.
|
||||
5. После успешного сохранения, диспетчер MediatR (в `Admin` модуле) публикует `SystemSettingsUpdatedDomainEvent`.
|
||||
6. Событие отлавливается через `INotificationHandler<SystemSettingsUpdatedDomainEvent>` независимыми слушателями, например:
|
||||
- Модулем `Federation` для рассылки всем "соседним" инстансам новых возможностей `Capabilities`.
|
||||
|
||||
## Регистрация модуля
|
||||
|
||||
При старте приложения в `Host/Program.cs` модуль инициализируется:
|
||||
|
||||
```csharp
|
||||
// Регистрация сервисов модуля настроек
|
||||
builder.Services.AddSettingsModule(builder.Configuration);
|
||||
|
||||
// Дополнительно можно вызывать Initialize(...) чтобы загрузить кэш из БД при старте
|
||||
```
|
||||
|
||||
Под капотом `DependencyInjection.cs`:
|
||||
```csharp
|
||||
public static IServiceCollection AddSettingsModule(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddSingleton<SettingsService>();
|
||||
|
||||
// Привязываем конкретные абстракции к одному Singleton инстансу
|
||||
services.AddSingleton<ISettingsService>(sp => sp.GetRequiredService<SettingsService>());
|
||||
services.AddSingleton<IMessagesSettings>(sp => sp.GetRequiredService<SettingsService>());
|
||||
// ... и остальные
|
||||
}
|
||||
```
|
||||
|
||||
## Публичная конфигурация клиента (PublicConfig)
|
||||
|
||||
Для клиентской части (Frontend) предусмотрен специальный DTO объект `PublicConfigDto`.
|
||||
Это subset (урезанная часть) от `SystemSettingsDto`, которая не содержит чувствительной информации о сервере и ключах:
|
||||
|
||||
- Доступные лимиты медиа файлов.
|
||||
- Включены ли аудио/видео звонки.
|
||||
- Включена ли федерация для поиска глобальных пользователей.
|
||||
|
||||
Таким образом, клиент может запросить `GET /api/app/config`, а бэкенд отдаст безопасный набор доступных разрешений через маппинг `SettingsService.Current`.
|
||||
@@ -43,3 +43,5 @@
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ using Knot.Modules.Messaging;
|
||||
using Carter;
|
||||
using Knot.Shared.Infrastructure;
|
||||
using Knot.Modules.Auth;
|
||||
using Knot.Modules.Settings;
|
||||
using Knot.Modules.Admin;
|
||||
using Knot.Modules.Conversations;
|
||||
using Knot.Modules.Conversations.Infrastructure.SignalR;
|
||||
using Knot.Modules.Auth.Infrastructure.Persistence;
|
||||
@@ -50,11 +52,16 @@ builder.Configuration.AddInMemoryCollection(
|
||||
.ToDictionary(kv => kv.Key, kv => kv.Value));
|
||||
|
||||
builder.Services.AddAuthModule(builder.Configuration);
|
||||
builder.Services.AddSettingsModule(builder.Configuration);
|
||||
builder.Services.AddConversationsModule(builder.Configuration);
|
||||
builder.Services.AddSharedInfrastructure(builder.Configuration);
|
||||
|
||||
// CQRS / MediatR для команд в Host (например, AdminController)
|
||||
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
|
||||
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(
|
||||
typeof(Knot.Modules.Settings.DependencyInjection).Assembly,
|
||||
typeof(Knot.Modules.Admin.DependencyInjection).Assembly
|
||||
));
|
||||
|
||||
// Carter для вызова Minimal APIs (Endpoints)
|
||||
builder.Services.AddCarter();
|
||||
@@ -99,8 +106,6 @@ builder.Services.AddRouting(options =>
|
||||
builder.Services.AddMemoryCache();
|
||||
builder.Services.AddHttpClient();
|
||||
|
||||
|
||||
|
||||
builder.Services.AddSignalR()
|
||||
.AddJsonProtocol(options =>
|
||||
{
|
||||
@@ -162,8 +167,8 @@ using (var scope = app.Services.CreateScope())
|
||||
Knot.Modules.Messaging.Infrastructure.Persistence.Mongo.EncryptedStringSerializer.EncryptionService = encryptionService;
|
||||
|
||||
// Initialize Global Settings Cache
|
||||
var settingsService = scope.ServiceProvider.GetRequiredService<Knot.Shared.Kernel.Configuration.ISettingsService>();
|
||||
if (settingsService is Knot.Shared.Infrastructure.Configuration.SettingsService concreteSettings)
|
||||
var settingsService = scope.ServiceProvider.GetRequiredService<Knot.Modules.Settings.Application.Settings.Abstractions.ISettingsService>();
|
||||
if (settingsService is Knot.Modules.Settings.Infrastructure.Configuration.SettingsService concreteSettings)
|
||||
{
|
||||
concreteSettings.Initialize();
|
||||
}
|
||||
@@ -203,3 +208,4 @@ public class CustomUserIdProvider : IUserIdProvider
|
||||
return connection.User?.FindFirstValue("sub") ?? connection.User?.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ using Knot.Modules.Conversations.Domain;
|
||||
using MongoDB.Driver;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Host.Application.Admin.Commands;
|
||||
namespace Knot.Modules.Admin.Application.Admin.Commands;
|
||||
|
||||
public record CleanRunCommand(IFileStorageService FileStorage, AuthDbContext IdentityDb) : ICommand<MessageResponse>;
|
||||
|
||||
@@ -99,4 +99,4 @@ internal sealed class CleanRunCommandHandler : ICommandHandler<CleanRunCommand,
|
||||
|
||||
return Result.Success(new MessageResponse("Cleanup completed successfully"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ using Knot.Modules.Auth.Domain;
|
||||
using Knot.Modules.Auth.Infrastructure.Persistence;
|
||||
using Knot.Modules.Auth.Application.Abstractions;
|
||||
|
||||
namespace Host.Application.Admin.Commands;
|
||||
namespace Knot.Modules.Admin.Application.Admin.Commands;
|
||||
|
||||
public record ResetUserPasswordCommand(Guid UserId, string NewPassword) : ICommand<SuccessResponse>;
|
||||
|
||||
@@ -44,4 +44,4 @@ internal sealed class ResetUserPasswordCommandHandler : ICommandHandler<ResetUse
|
||||
await _identityUnitOfWork.SaveChangesAsync(cancellationToken);
|
||||
return Result.Success(new SuccessResponse(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Modules.Stories.Application.Abstractions;
|
||||
|
||||
namespace Host.Application.Admin.Commands.TestKlipy;
|
||||
namespace Knot.Modules.Admin.Application.Admin.Commands.TestKlipy;
|
||||
|
||||
public record TestKlipyConnectionCommand() : ICommand<bool>;
|
||||
|
||||
@@ -37,3 +38,5 @@ internal sealed class TestKlipyConnectionCommandHandler : ICommandHandler<TestKl
|
||||
return Result.Success(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,10 +4,11 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Host.Application.Admin.Commands;
|
||||
namespace Knot.Modules.Admin.Application.Admin.Commands;
|
||||
|
||||
public record UpdateSettingsCommand(SystemSettingsDto Settings) : ICommand<SystemSettingsDto>;
|
||||
|
||||
@@ -43,4 +44,6 @@ internal sealed class UpdateSettingsCommandHandler : ICommandHandler<UpdateSetti
|
||||
|
||||
return Result.Success(request.Settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ using Knot.Modules.Auth.Application.Auth.DTOs;
|
||||
|
||||
using Knot.Modules.Auth.Application.Users;
|
||||
|
||||
namespace Host.Application.Admin.Queries;
|
||||
namespace Knot.Modules.Admin.Application.Admin.Queries;
|
||||
|
||||
public record CleanDryRunQuery(IFileStorageService FileStorage, AuthDbContext IdentityDb) : IQuery<CleanupDryRunResultDto>;
|
||||
|
||||
@@ -102,4 +102,4 @@ internal sealed class CleanDryRunQueryHandler : IQueryHandler<CleanDryRunQuery,
|
||||
OrphanedMediaBytes = safeBytes
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using MediatR;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Services;
|
||||
|
||||
namespace Host.Application.Admin.Queries;
|
||||
namespace Knot.Modules.Admin.Application.Admin.Queries;
|
||||
|
||||
public record GetDashboardStatsQuery() : IQuery<DashboardStatsDto>;
|
||||
|
||||
@@ -23,4 +23,4 @@ internal sealed class GetDashboardStatsQueryHandler : IQueryHandler<GetDashboard
|
||||
var stats = await _statisticsService.GetDashboardStatsAsync(cancellationToken);
|
||||
return Result.Success(stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
namespace Host.Application.Admin.Queries;
|
||||
namespace Knot.Modules.Admin.Application.Admin.Queries;
|
||||
|
||||
public record GetSettingsQuery() : IQuery<SystemSettingsDto>;
|
||||
|
||||
@@ -24,4 +25,5 @@ internal sealed class GetSettingsQueryHandler : IQueryHandler<GetSettingsQuery,
|
||||
var settings = await _settingsService.GetSettingsAsync(cancellationToken);
|
||||
return Result.Success(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ using Knot.Modules.Auth.Domain;
|
||||
using Knot.Modules.Conversations.Domain;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Host.Application.Admin.Queries;
|
||||
namespace Knot.Modules.Admin.Application.Admin.Queries;
|
||||
|
||||
public record GetUserDetailsQuery(Guid UserId) : IQuery<AdminUserDetailsDto>;
|
||||
|
||||
@@ -74,4 +74,4 @@ internal sealed class GetUserDetailsQueryHandler : IQueryHandler<GetUserDetailsQ
|
||||
|
||||
return Result.Success(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ using Knot.Modules.Auth.Application.Auth.DTOs;
|
||||
using Knot.Modules.Auth.Application.Users;
|
||||
using Knot.Modules.Auth.Domain;
|
||||
|
||||
namespace Host.Application.Admin.Queries;
|
||||
namespace Knot.Modules.Admin.Application.Admin.Queries;
|
||||
|
||||
public record SearchUsersQuery(string Query) : IQuery<List<AdminUserDto>>;
|
||||
|
||||
@@ -43,4 +43,4 @@ internal sealed class SearchUsersQueryHandler : IQueryHandler<SearchUsersQuery,
|
||||
|
||||
return Result.Success(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
namespace Knot.Modules.Admin.Domain.Events;
|
||||
|
||||
@@ -8,3 +9,4 @@ namespace Knot.Modules.Admin.Domain.Events;
|
||||
/// Доменное событие: глобальные настройки системы обновлены.
|
||||
/// </summary>
|
||||
public sealed record SystemSettingsUpdatedDomainEvent(SystemSettingsDto Settings) : IDomainEvent;
|
||||
|
||||
|
||||
@@ -18,5 +18,7 @@
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
|
||||
<_Parameter1>Knot.Modules.Admin.UnitTests</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
using Carter;
|
||||
using Knot.Modules.Auth.Application.Auth.DTOs;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Modules.Auth.Application.Users.Register;
|
||||
using Knot.Shared.Kernel.Storage;
|
||||
using Knot.Modules.Auth.Infrastructure.Persistence;
|
||||
using MediatR;
|
||||
using Host.Application.Admin.Queries;
|
||||
using Host.Application.Admin.Commands;
|
||||
using Knot.Modules.Admin.Application.Admin.Queries;
|
||||
using Knot.Modules.Admin.Application.Admin.Commands;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Host.Application.Admin.Commands.TestKlipy;
|
||||
using Knot.Modules.Admin.Application.Admin.Commands.TestKlipy;
|
||||
|
||||
namespace Knot.Host.Presentation.Endpoints;
|
||||
|
||||
@@ -90,4 +91,5 @@ public sealed class AdminEndpoints : ICarterModule
|
||||
return Results.Ok(result.Value);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
using Knot.Modules.Auth.Domain;
|
||||
using Knot.Modules.Auth.Application.Abstractions;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Modules.Auth.Application.Users.Auth;
|
||||
using BCrypt.Net;
|
||||
|
||||
@@ -87,3 +88,4 @@ public sealed class RegisterUserCommandHandler : ICommandHandler<RegisterUserCom
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Events;
|
||||
|
||||
namespace Knot.Modules.Auth.Domain;
|
||||
|
||||
@@ -40,7 +41,9 @@ public sealed class User : AggregateRoot<Guid>
|
||||
/// </summary>
|
||||
public static User Create(string username, string passwordHash, string displayName, string? email = null, string? bio = null)
|
||||
{
|
||||
return new User(Guid.NewGuid(), username, passwordHash, displayName, email, bio);
|
||||
var user = new User(Guid.NewGuid(), username, passwordHash, displayName, email, bio);
|
||||
user.RaiseDomainEvent(new UserRegisteredDomainEvent(user.Id, user.Username, user.DisplayName, user.Bio));
|
||||
return user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -21,13 +21,17 @@
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.4" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.16.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.16.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Knot.Modules.Conversations.Domain;
|
||||
using Knot.Modules.Conversations.Application.Abstractions;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Shared.Kernel;
|
||||
using MediatR;
|
||||
|
||||
@@ -48,3 +49,4 @@ internal sealed class AddToFolderCommandHandler : ICommandHandler<AddToFolderCom
|
||||
return Result.Success();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ using Knot.Modules.Messaging.Application.Abstractions;
|
||||
using Knot.Modules.Messaging.Domain;
|
||||
using Knot.Modules.Conversations.Domain;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Modules.Conversations.Application.Abstractions;
|
||||
|
||||
namespace Knot.Modules.Conversations.Application.Messages.Send;
|
||||
@@ -167,3 +168,4 @@ public sealed class SendMessageCommandHandler : ICommandHandler<SendMessageComma
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Storage;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Modules.Conversations.Application.DTOs;
|
||||
|
||||
namespace Knot.Modules.Conversations.Application.Messages.UploadFile;
|
||||
@@ -45,3 +46,4 @@ internal sealed class UploadFileCommandHandler : ICommandHandler<UploadFileComma
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.4" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="3.7.1" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="3.2.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="Knot.Modules.Chats.UnitTests" />
|
||||
<InternalsVisibleTo Include="Knot.Modules.Conversations.UnitTests" />
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -36,3 +36,5 @@
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ using Knot.Shared.Kernel.Constants;
|
||||
using System.Security.Cryptography;
|
||||
using MediatR;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
namespace Host.Application.Federation.Commands;
|
||||
|
||||
@@ -63,4 +64,4 @@ internal sealed class HandshakeFederationCommandHandler : ICommandHandler<Handsh
|
||||
|
||||
return Result.Success(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Auth.Domain;
|
||||
using Knot.Modules.Messaging.Application.Abstractions;
|
||||
using Knot.Modules.Messaging.Domain;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Shared.Kernel.Constants;
|
||||
|
||||
namespace Host.Application.Federation.Commands;
|
||||
@@ -204,3 +205,4 @@ internal sealed class InboundFederationCommandHandler : ICommandHandler<InboundF
|
||||
return Result.Success();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Auth.Domain;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using System.Linq;
|
||||
|
||||
namespace Host.Application.Federation.Commands;
|
||||
@@ -38,3 +39,4 @@ internal sealed class ResolveUserCommandHandler : ICommandHandler<ResolveUserCom
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ using Knot.Modules.Messaging.Domain;
|
||||
using Knot.Modules.Federation.Application.Federation.Services;
|
||||
using Knot.Modules.Conversations.Domain;
|
||||
using Knot.Modules.Federation.Application.Abstractions;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Modules.Auth.Domain;
|
||||
|
||||
namespace Knot.Modules.Federation.Application.Federation.Events;
|
||||
@@ -95,3 +96,4 @@ public sealed class FederatedMessageActionsHandler :
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ using Knot.Modules.Messaging.Domain;
|
||||
using Knot.Modules.Federation.Application.Federation.Services;
|
||||
using Knot.Modules.Conversations.Domain;
|
||||
using Knot.Modules.Federation.Application.Abstractions;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Modules.Auth.Domain;
|
||||
|
||||
namespace Knot.Modules.Federation.Application.Federation.Events;
|
||||
@@ -88,3 +89,4 @@ public sealed class MessageSentDomainEventHandler : INotificationHandler<Message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediatR;
|
||||
using Knot.Modules.Admin.Domain.Events;
|
||||
using Knot.Modules.Settings.Domain.Events;
|
||||
using Knot.Modules.Federation.Application.Abstractions;
|
||||
using Knot.Modules.Federation.Application.Federation.Services;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
namespace Knot.Modules.Federation.Application.Federation.Events;
|
||||
|
||||
@@ -69,3 +70,5 @@ public sealed class SystemSettingsUpdatedDomainEventHandler : INotificationHandl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ using Knot.Modules.Auth.Domain;
|
||||
using Knot.Modules.Conversations.Domain;
|
||||
using Knot.Modules.Federation.Application.Abstractions;
|
||||
using Knot.Modules.Federation.Application.Federation.Services;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
namespace Knot.Modules.Federation.Application.Federation.Events;
|
||||
|
||||
@@ -84,3 +85,4 @@ public sealed class UserStatusChangedDomainEventHandler : INotificationHandler<U
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Knot.Modules.Federation.Application.Abstractions;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Shared.Kernel.Security;
|
||||
|
||||
namespace Knot.Modules.Federation.Application.Federation.Services;
|
||||
@@ -105,3 +106,4 @@ public sealed class FederationPacketService
|
||||
return Result.Success(packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Knot.Modules.Federation.Application.Abstractions;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Shared.Kernel.Security;
|
||||
|
||||
namespace Knot.Modules.Federation.Infrastructure.Services;
|
||||
@@ -56,3 +57,4 @@ public sealed class FederationGateway : IFederationGateway
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,5 +13,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Carter" Version="10.0.0" />
|
||||
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ using System;
|
||||
using Host.Application.Federation.Commands;
|
||||
using Knot.Modules.Federation.Application.Abstractions;
|
||||
using Knot.Shared.Kernel.Storage;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
namespace Host.Endpoints;
|
||||
|
||||
@@ -63,4 +64,4 @@ public sealed class FederationEndpoints : ICarterModule
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Shared.Kernel.Constants;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
@@ -61,3 +62,4 @@ internal sealed class GetTrendingGifsQueryHandler : IQueryHandler<GetTrendingGif
|
||||
return Result.Success<JsonElement?>(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
using Knot.Shared.Kernel.Constants;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
@@ -65,3 +66,4 @@ internal sealed class SearchGifsQueryHandler : IQueryHandler<SearchGifsQuery, Js
|
||||
return Result.Success<JsonElement?>(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,5 +13,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Carter" Version="10.0.0" />
|
||||
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
@@ -7,7 +7,8 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.4" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="3.0.0" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="3.2.0" />
|
||||
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
@@ -17,3 +18,5 @@
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Application.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс для хранения аватаров в S3 (MinIO).
|
||||
/// Отдельный от IFileStorageService модуля Storage,
|
||||
/// чтобы не создавать прямой зависимости на Storage модуль.
|
||||
/// </summary>
|
||||
public interface IAvatarStorageService
|
||||
{
|
||||
/// <summary>
|
||||
/// Загружает файл в S3-бакет аватаров и возвращает fileId (ключ объекта).
|
||||
/// </summary>
|
||||
Task<string> UploadAsync(System.IO.Stream stream, string fileName, string contentType, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Удаляет файл аватара из S3 по fileId.
|
||||
/// </summary>
|
||||
Task DeleteAsync(string fileId, CancellationToken ct = default);
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
namespace Knot.Modules.Profiles.Application.Abstractions;
|
||||
|
||||
public interface IProfileRepository
|
||||
{
|
||||
Task<Profile?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task AddAsync(Profile profile, CancellationToken cancellationToken = default);
|
||||
void Update(Profile profile);
|
||||
Task<System.Collections.Generic.List<Profile>> SearchProfilesAsync(string query, System.Threading.CancellationToken ct = default);
|
||||
Task<ProfileDocument?> GetByIdAsync(Guid userId, CancellationToken ct = default);
|
||||
Task AddAsync(ProfileDocument profile, CancellationToken ct = default);
|
||||
Task UpdateAsync(ProfileDocument profile, CancellationToken ct = default);
|
||||
Task<List<ProfileDocument>> SearchAsync(string query, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
namespace Knot.Modules.Profiles.Application.Abstractions;
|
||||
|
||||
public interface IProfilesUnitOfWork
|
||||
{
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
|
||||
Task SaveChangesAsync(CancellationToken ct = default);
|
||||
}
|
||||
|
||||
@@ -1,69 +1,71 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
|
||||
using Knot.Shared.Kernel.Storage;
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.Avatar;
|
||||
|
||||
public sealed record CropAvatarCommand(Guid ProfileId, Stream FileStream, string FileName, string ContentType, int X, int Y, int Width, int Height) : ICommand<ProfileProfileDto>;
|
||||
public sealed record CropAvatarCommand(
|
||||
Guid UserId,
|
||||
Stream FileStream,
|
||||
string FileName,
|
||||
string ContentType,
|
||||
int X, int Y, int Width, int Height) : ICommand<UserProfileDto>;
|
||||
|
||||
internal sealed class CropAvatarCommandHandler : ICommandHandler<CropAvatarCommand, ProfileProfileDto>
|
||||
internal sealed class CropAvatarCommandHandler : ICommandHandler<CropAvatarCommand, UserProfileDto>
|
||||
{
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
private readonly IProfilesUnitOfWork _unitOfWork;
|
||||
private readonly IFileStorageService _fileStorage;
|
||||
private readonly IProfileRepository _repository;
|
||||
private readonly IAvatarStorageService _avatarStorage;
|
||||
|
||||
public CropAvatarCommandHandler(IProfileRepository profileRepository, IProfilesUnitOfWork unitOfWork, IFileStorageService fileStorage)
|
||||
public CropAvatarCommandHandler(IProfileRepository repository, IAvatarStorageService avatarStorage)
|
||||
{
|
||||
_profileRepository = profileRepository;
|
||||
_unitOfWork = unitOfWork;
|
||||
_fileStorage = fileStorage;
|
||||
_repository = repository;
|
||||
_avatarStorage = avatarStorage;
|
||||
}
|
||||
|
||||
public async Task<Result<ProfileProfileDto>> Handle(CropAvatarCommand request, CancellationToken cancellationToken)
|
||||
public async Task<Result<UserProfileDto>> Handle(CropAvatarCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await _profileRepository.GetByIdAsync(request.ProfileId, cancellationToken);
|
||||
if (profile == null)
|
||||
{
|
||||
return Result.Failure<ProfileProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
}
|
||||
var profile = await _repository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (profile is null)
|
||||
return Result.Failure<UserProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
|
||||
string avatarUrl;
|
||||
// Обрезать и ресайзнуть изображение до 400×400
|
||||
using var ms = await CropAndResizeAsync(request, cancellationToken);
|
||||
|
||||
using (var image = await SixLabors.ImageSharp.Image.LoadAsync(request.FileStream, cancellationToken))
|
||||
{
|
||||
int startX = Math.Max(0, Math.Min(request.X, image.Width - 1));
|
||||
int startY = Math.Max(0, Math.Min(request.Y, image.Height - 1));
|
||||
int rectWidth = Math.Max(1, Math.Min(request.Width, image.Width - startX));
|
||||
int rectHeight = Math.Max(1, Math.Min(request.Height, image.Height - startY));
|
||||
// Удалить старый аватар из S3
|
||||
if (!string.IsNullOrEmpty(profile.AvatarUrl))
|
||||
await _avatarStorage.DeleteAsync(profile.AvatarUrl, cancellationToken);
|
||||
|
||||
image.Mutate(ctx => ctx.Crop(new SixLabors.ImageSharp.Rectangle(startX, startY, rectWidth, rectHeight)));
|
||||
image.Mutate(ctx => ctx.Resize(400, 400));
|
||||
|
||||
using var outStream = new MemoryStream();
|
||||
await image.SaveAsJpegAsync(outStream, cancellationToken);
|
||||
outStream.Position = 0;
|
||||
|
||||
var id = await _fileStorage.UploadFileAsync(outStream, request.FileName, "image/jpeg");
|
||||
avatarUrl = $"/api/files/{id}";
|
||||
}
|
||||
var fileId = await _avatarStorage.UploadAsync(ms, "avatar.jpg", "image/jpeg", cancellationToken);
|
||||
var avatarUrl = $"/api/files/{fileId}";
|
||||
|
||||
profile.UpdateAvatar(avatarUrl);
|
||||
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
await _repository.UpdateAsync(profile, cancellationToken);
|
||||
|
||||
var dto = new ProfileProfileDto(
|
||||
profile.Id,
|
||||
profile.Profilename,
|
||||
profile.DisplayName,
|
||||
profile.Avatar,
|
||||
profile.Bio,
|
||||
profile.Birthday,
|
||||
profile.CreatedAt
|
||||
);
|
||||
return Result.Success(UserProfileDto.FromDocument(profile));
|
||||
}
|
||||
|
||||
return Result.Success(dto);
|
||||
private static async Task<MemoryStream> CropAndResizeAsync(CropAvatarCommand request, CancellationToken ct)
|
||||
{
|
||||
using var image = await Image.LoadAsync(request.FileStream, ct);
|
||||
|
||||
var startX = Math.Clamp(request.X, 0, image.Width - 1);
|
||||
var startY = Math.Clamp(request.Y, 0, image.Height - 1);
|
||||
var width = Math.Clamp(request.Width, 1, image.Width - startX);
|
||||
var height = Math.Clamp(request.Height, 1, image.Height - startY);
|
||||
|
||||
image.Mutate(ctx => ctx
|
||||
.Crop(new Rectangle(startX, startY, width, height))
|
||||
.Resize(400, 400));
|
||||
|
||||
var output = new MemoryStream();
|
||||
await image.SaveAsJpegAsync(output, ct);
|
||||
output.Position = 0;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.Avatar;
|
||||
|
||||
public sealed record DeleteAvatarCommand(Guid ProfileId) : ICommand<ProfileProfileDto>;
|
||||
|
||||
internal sealed class DeleteAvatarCommandHandler : ICommandHandler<DeleteAvatarCommand, ProfileProfileDto>
|
||||
{
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
private readonly IProfilesUnitOfWork _unitOfWork;
|
||||
|
||||
public DeleteAvatarCommandHandler(IProfileRepository profileRepository, IProfilesUnitOfWork unitOfWork)
|
||||
{
|
||||
_profileRepository = profileRepository;
|
||||
_unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public async Task<Result<ProfileProfileDto>> Handle(DeleteAvatarCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await _profileRepository.GetByIdAsync(request.ProfileId, cancellationToken);
|
||||
if (profile == null)
|
||||
{
|
||||
return Result.Failure<ProfileProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
}
|
||||
|
||||
profile.UpdateAvatar(null);
|
||||
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var dto = new ProfileProfileDto(
|
||||
profile.Id,
|
||||
profile.Profilename,
|
||||
profile.DisplayName,
|
||||
profile.Avatar,
|
||||
profile.Bio,
|
||||
profile.Birthday,
|
||||
profile.CreatedAt
|
||||
);
|
||||
|
||||
return Result.Success(dto);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,79 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
|
||||
using Knot.Shared.Kernel.Storage;
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.Avatar;
|
||||
|
||||
public sealed record UploadAvatarCommand(Guid ProfileId, Stream FileStream, string FileName, string ContentType) : ICommand<ProfileProfileDto>;
|
||||
// ─── Upload ────────────────────────────────────────────────────────────────
|
||||
|
||||
internal sealed class UploadAvatarCommandHandler : ICommandHandler<UploadAvatarCommand, ProfileProfileDto>
|
||||
public sealed record UploadAvatarCommand(
|
||||
Guid UserId,
|
||||
Stream FileStream,
|
||||
string FileName,
|
||||
string ContentType) : ICommand<UserProfileDto>;
|
||||
|
||||
internal sealed class UploadAvatarCommandHandler : ICommandHandler<UploadAvatarCommand, UserProfileDto>
|
||||
{
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
private readonly IProfilesUnitOfWork _unitOfWork;
|
||||
private readonly IFileStorageService _fileStorage;
|
||||
private readonly IProfileRepository _repository;
|
||||
private readonly IAvatarStorageService _avatarStorage;
|
||||
|
||||
public UploadAvatarCommandHandler(IProfileRepository profileRepository, IProfilesUnitOfWork unitOfWork, IFileStorageService fileStorage)
|
||||
public UploadAvatarCommandHandler(IProfileRepository repository, IAvatarStorageService avatarStorage)
|
||||
{
|
||||
_profileRepository = profileRepository;
|
||||
_unitOfWork = unitOfWork;
|
||||
_fileStorage = fileStorage;
|
||||
_repository = repository;
|
||||
_avatarStorage = avatarStorage;
|
||||
}
|
||||
|
||||
public async Task<Result<ProfileProfileDto>> Handle(UploadAvatarCommand request, CancellationToken cancellationToken)
|
||||
public async Task<Result<UserProfileDto>> Handle(UploadAvatarCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await _profileRepository.GetByIdAsync(request.ProfileId, cancellationToken);
|
||||
if (profile == null)
|
||||
{
|
||||
return Result.Failure<ProfileProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
}
|
||||
var profile = await _repository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (profile is null)
|
||||
return Result.Failure<UserProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
|
||||
var fileId = await _fileStorage.UploadFileAsync(request.FileStream, request.FileName, request.ContentType);
|
||||
// Удалить старый аватар из S3, если был
|
||||
if (!string.IsNullOrEmpty(profile.AvatarUrl))
|
||||
await _avatarStorage.DeleteAsync(profile.AvatarUrl, cancellationToken);
|
||||
|
||||
var fileId = await _avatarStorage.UploadAsync(request.FileStream, request.FileName, request.ContentType, cancellationToken);
|
||||
var avatarUrl = $"/api/files/{fileId}";
|
||||
|
||||
profile.UpdateAvatar(avatarUrl);
|
||||
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
await _repository.UpdateAsync(profile, cancellationToken);
|
||||
|
||||
var dto = new ProfileProfileDto(
|
||||
profile.Id,
|
||||
profile.Profilename,
|
||||
profile.DisplayName,
|
||||
profile.Avatar,
|
||||
profile.Bio,
|
||||
profile.Birthday,
|
||||
profile.CreatedAt
|
||||
);
|
||||
|
||||
return Result.Success(dto);
|
||||
return Result.Success(UserProfileDto.FromDocument(profile));
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Delete ────────────────────────────────────────────────────────────────
|
||||
|
||||
public sealed record DeleteAvatarCommand(Guid UserId) : ICommand<UserProfileDto>;
|
||||
|
||||
internal sealed class DeleteAvatarCommandHandler : ICommandHandler<DeleteAvatarCommand, UserProfileDto>
|
||||
{
|
||||
private readonly IProfileRepository _repository;
|
||||
private readonly IAvatarStorageService _avatarStorage;
|
||||
|
||||
public DeleteAvatarCommandHandler(IProfileRepository repository, IAvatarStorageService avatarStorage)
|
||||
{
|
||||
_repository = repository;
|
||||
_avatarStorage = avatarStorage;
|
||||
}
|
||||
|
||||
public async Task<Result<UserProfileDto>> Handle(DeleteAvatarCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await _repository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (profile is null)
|
||||
return Result.Failure<UserProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
|
||||
if (!string.IsNullOrEmpty(profile.AvatarUrl))
|
||||
await _avatarStorage.DeleteAsync(profile.AvatarUrl, cancellationToken);
|
||||
|
||||
profile.RemoveAvatar();
|
||||
await _repository.UpdateAsync(profile, cancellationToken);
|
||||
|
||||
return Result.Success(UserProfileDto.FromDocument(profile));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
|
||||
public record UpdateProfileRequest(string? DisplayName, string? Bio, DateTime? Birthday);
|
||||
public record UpdateSettingsRequest(bool? HideStoryViews);
|
||||
@@ -1,7 +0,0 @@
|
||||
using System;
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
|
||||
public sealed record UpdateProfileRequest(string? DisplayName, string? Bio, DateTime? Birthday);
|
||||
@@ -1,5 +0,0 @@
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
|
||||
public sealed record UpdateSettingsRequest(bool? HideStoryViews);
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
|
||||
public record ProfileDto(
|
||||
Guid Id,
|
||||
string Profilename,
|
||||
string DisplayName,
|
||||
string? Avatar,
|
||||
bool IsOnline,
|
||||
DateTime LastSeen
|
||||
);
|
||||
@@ -1,18 +1,29 @@
|
||||
using System;
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
|
||||
public record ProfileProfileDto(
|
||||
public record UserProfileDto(
|
||||
Guid Id,
|
||||
string Profilename,
|
||||
string UserName,
|
||||
string DisplayName,
|
||||
string? Avatar,
|
||||
string? AvatarUrl,
|
||||
string? Bio,
|
||||
DateTime? Birthday,
|
||||
DateTime CreatedAt,
|
||||
bool? HideStoryViews = null,
|
||||
bool HideStoryViews = false,
|
||||
bool IsOnline = false,
|
||||
DateTime? LastSeen = null
|
||||
);
|
||||
DateTime? LastSeen = null)
|
||||
{
|
||||
public static UserProfileDto FromDocument(ProfileDocument doc) =>
|
||||
new(
|
||||
doc.Id,
|
||||
doc.Username,
|
||||
doc.DisplayName,
|
||||
doc.AvatarUrl,
|
||||
doc.Bio,
|
||||
doc.Birthday,
|
||||
doc.CreatedAt,
|
||||
doc.HideStoryViews
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,36 +1,29 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.GetProfile;
|
||||
|
||||
public sealed record GetProfileQuery(Guid Id) : IQuery<ProfileProfileDto>;
|
||||
public sealed record GetProfileQuery(Guid UserId) : IQuery<UserProfileDto>;
|
||||
|
||||
internal sealed class GetProfileQueryHandler : IQueryHandler<GetProfileQuery, ProfileProfileDto>
|
||||
internal sealed class GetProfileQueryHandler : IQueryHandler<GetProfileQuery, UserProfileDto>
|
||||
{
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
private readonly IProfileRepository _repository;
|
||||
|
||||
public GetProfileQueryHandler(IProfileRepository profileRepository)
|
||||
public GetProfileQueryHandler(IProfileRepository repository)
|
||||
{
|
||||
_profileRepository = profileRepository;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public async Task<Result<ProfileProfileDto>> Handle(GetProfileQuery request, CancellationToken cancellationToken)
|
||||
public async Task<Result<UserProfileDto>> Handle(GetProfileQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await _profileRepository.GetByIdAsync(request.Id, cancellationToken);
|
||||
if (profile == null)
|
||||
{
|
||||
return Result.Failure<ProfileProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
}
|
||||
var profile = await _repository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (profile is null)
|
||||
return Result.Failure<UserProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
|
||||
var dto = new ProfileProfileDto(
|
||||
profile.Id,
|
||||
profile.Profilename,
|
||||
profile.Name,
|
||||
profile.AvatarUrl
|
||||
);
|
||||
|
||||
return Result.Success(dto);
|
||||
return Result.Success(UserProfileDto.FromDocument(profile));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
using Knot.Shared.Kernel.Events;
|
||||
using MediatR;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.Integration;
|
||||
|
||||
/// <summary>
|
||||
/// Реакция модуля Profiles на создание пользователя в модуле Auth.
|
||||
/// Создает соответствующий документ в MongoDB.
|
||||
/// </summary>
|
||||
internal sealed class UserRegisteredDomainEventHandler : INotificationHandler<UserRegisteredDomainEvent>
|
||||
{
|
||||
private readonly IProfileRepository _repository;
|
||||
|
||||
public UserRegisteredDomainEventHandler(IProfileRepository repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public async Task Handle(UserRegisteredDomainEvent notification, CancellationToken cancellationToken)
|
||||
{
|
||||
// Проверяем, существует ли уже профиль (защита от дублей)
|
||||
var existing = await _repository.GetByIdAsync(notification.UserId, cancellationToken);
|
||||
if (existing is not null) return;
|
||||
|
||||
var profile = ProfileDocument.Create(
|
||||
notification.UserId,
|
||||
notification.Username,
|
||||
notification.DisplayName,
|
||||
notification.Bio
|
||||
);
|
||||
|
||||
await _repository.AddAsync(profile, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,28 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.Search;
|
||||
|
||||
public sealed record SearchProfilesQuery(string Query) : IQuery<List<ProfileDto>>;
|
||||
public sealed record SearchProfilesQuery(string Query) : IQuery<List<UserProfileDto>>;
|
||||
|
||||
internal sealed class SearchProfilesQueryHandler : IQueryHandler<SearchProfilesQuery, List<ProfileDto>>
|
||||
internal sealed class SearchProfilesQueryHandler : IQueryHandler<SearchProfilesQuery, List<UserProfileDto>>
|
||||
{
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
private readonly IProfileRepository _repository;
|
||||
|
||||
public SearchProfilesQueryHandler(IProfileRepository profileRepository)
|
||||
public SearchProfilesQueryHandler(IProfileRepository repository)
|
||||
{
|
||||
_profileRepository = profileRepository;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public async Task<Result<List<ProfileDto>>> Handle(SearchProfilesQuery request, CancellationToken cancellationToken)
|
||||
public async Task<Result<List<UserProfileDto>>> Handle(SearchProfilesQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profiles = await _profileRepository.SearchProfilesAsync(request.Query, cancellationToken);
|
||||
|
||||
var result = profiles.Select(profile => new ProfileDto(
|
||||
profile.Id,
|
||||
profile.Profilename,
|
||||
profile.DisplayName,
|
||||
profile.Avatar,
|
||||
false,
|
||||
DateTime.UtcNow
|
||||
)).ToList();
|
||||
|
||||
return Result.Success(result);
|
||||
var profiles = await _repository.SearchAsync(request.Query, cancellationToken);
|
||||
var dtos = profiles.Select(UserProfileDto.FromDocument).ToList();
|
||||
return Result.Success(dtos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,40 @@
|
||||
using Knot.Shared.Kernel;
|
||||
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.UpdateProfile;
|
||||
|
||||
public sealed record UpdateProfileCommand(Guid UserId, string? DisplayName, string? Bio, DateTime? Birthday) : ICommand<UserProfileDto>;
|
||||
public sealed record UpdateProfileCommand(
|
||||
Guid UserId,
|
||||
string? DisplayName,
|
||||
string? Bio,
|
||||
DateTime? Birthday) : ICommand<UserProfileDto>;
|
||||
|
||||
internal sealed class UpdateProfileCommandHandler : ICommandHandler<UpdateProfileCommand, UserProfileDto>
|
||||
{
|
||||
private readonly IProfileRepository _userRepository;
|
||||
private readonly IProfilesUnitOfWork _unitOfWork;
|
||||
private readonly IProfileRepository _repository;
|
||||
|
||||
public UpdateProfileCommandHandler(IProfileRepository userRepository, IProfilesUnitOfWork unitOfWork)
|
||||
public UpdateProfileCommandHandler(IProfileRepository repository)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
_unitOfWork = unitOfWork;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public async Task<Result<UserProfileDto>> Handle(UpdateProfileCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<UserProfileDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
var profile = await _repository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (profile is null)
|
||||
return Result.Failure<UserProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
|
||||
user.UpdateProfile(request.DisplayName ?? user.DisplayName, request.Bio, request.Birthday);
|
||||
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
profile.UpdateProfile(
|
||||
request.DisplayName ?? profile.DisplayName,
|
||||
request.Bio,
|
||||
request.Birthday);
|
||||
|
||||
var dto = new UserProfileDto(
|
||||
user.Id,
|
||||
user.Username,
|
||||
user.DisplayName,
|
||||
user.Avatar,
|
||||
user.Bio,
|
||||
user.Birthday,
|
||||
user.CreatedAt
|
||||
);
|
||||
await _repository.UpdateAsync(profile, cancellationToken);
|
||||
|
||||
return Result.Success(dto);
|
||||
return Result.Success(UserProfileDto.FromDocument(profile));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +1,32 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Application.Profiles.DTOs;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Application.Profiles.UpdateSettings;
|
||||
|
||||
public sealed record UpdateSettingsCommand(Guid ProfileId, bool? HideStoryViews) : ICommand<ProfileProfileDto>;
|
||||
public sealed record UpdateSettingsCommand(Guid UserId, bool? HideStoryViews) : ICommand<UserProfileDto>;
|
||||
|
||||
internal sealed class UpdateSettingsCommandHandler : ICommandHandler<UpdateSettingsCommand, ProfileProfileDto>
|
||||
internal sealed class UpdateSettingsCommandHandler : ICommandHandler<UpdateSettingsCommand, UserProfileDto>
|
||||
{
|
||||
private readonly IProfileRepository _profileRepository;
|
||||
private readonly IProfilesUnitOfWork _unitOfWork;
|
||||
private readonly IProfileRepository _repository;
|
||||
|
||||
public UpdateSettingsCommandHandler(IProfileRepository profileRepository, IProfilesUnitOfWork unitOfWork)
|
||||
public UpdateSettingsCommandHandler(IProfileRepository repository)
|
||||
{
|
||||
_profileRepository = profileRepository;
|
||||
_unitOfWork = unitOfWork;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public async Task<Result<ProfileProfileDto>> Handle(UpdateSettingsCommand request, CancellationToken cancellationToken)
|
||||
public async Task<Result<UserProfileDto>> Handle(UpdateSettingsCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var profile = await _profileRepository.GetByIdAsync(request.ProfileId, cancellationToken);
|
||||
if (profile == null)
|
||||
{
|
||||
return Result.Failure<ProfileProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
}
|
||||
var profile = await _repository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (profile is null)
|
||||
return Result.Failure<UserProfileDto>(ProfilesErrors.ProfileNotFound);
|
||||
|
||||
profile.UpdateSettings(request.HideStoryViews ?? profile.HideStoryViews);
|
||||
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
await _repository.UpdateAsync(profile, cancellationToken);
|
||||
|
||||
var dto = new ProfileProfileDto(
|
||||
profile.Id,
|
||||
profile.Profilename,
|
||||
profile.Name,
|
||||
profile.AvatarUrl
|
||||
);
|
||||
|
||||
return Result.Success(dto);
|
||||
return Result.Success(UserProfileDto.FromDocument(profile));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
namespace Knot.Modules.Profiles.Application.Profiles;
|
||||
|
||||
public record ProfileDto(
|
||||
Guid Id,
|
||||
string Profilename,
|
||||
string DisplayName,
|
||||
string? Avatar,
|
||||
bool IsOnline,
|
||||
DateTime LastSeen
|
||||
);
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace Knot.Modules.Profiles.Application.Profiles;
|
||||
using System;
|
||||
public record UserProfileDto(Guid Id, string UserName, string Name, string AvatarUrl)
|
||||
{
|
||||
public UserProfileDto(Guid a, string b, string c, string d, string e, bool f, int g, int h, int i, string j = "") : this(a,b,c,e) {}
|
||||
public UserProfileDto(Guid a, string b, string c, string d, string e, DateTime? f, DateTime g, string h="", string i="", string j="") : this(a,b,c,e) {}
|
||||
}
|
||||
public record ProfileProfileDto(Guid Id, string UserName, string Name, string AvatarUrl)
|
||||
{
|
||||
public ProfileProfileDto(Guid a, string b, string c, string d, string e, bool f, int g, int h, int i, string j = "") : this(a,b,c,e) {}
|
||||
public ProfileProfileDto(Guid a, string b, string c, string d, string e, DateTime? f, DateTime g, string h="", string i="", string j="") : this(a,b,c,e) {}
|
||||
}
|
||||
31
backend/src/Modules/Profiles/DependencyInjection.cs
Normal file
31
backend/src/Modules/Profiles/DependencyInjection.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Infrastructure.Database;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Knot.Modules.Profiles;
|
||||
|
||||
public static class DependencyInjection
|
||||
{
|
||||
public static IServiceCollection AddProfilesModule(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddScoped<IProfileRepository, ProfileRepository>();
|
||||
services.AddScoped<IProfilesUnitOfWork, ProfilesUnitOfWork>();
|
||||
services.AddScoped<IAvatarStorageService, AvatarStorageService>();
|
||||
|
||||
// MongoDB Registration
|
||||
var mongoConnection = configuration.GetConnectionString("MongoConnection")
|
||||
?? configuration["MONGO_URL"]
|
||||
?? "mongodb://localhost:27017";
|
||||
|
||||
var mongoClient = new MongoClient(mongoConnection);
|
||||
var database = mongoClient.GetDatabase("knot_messager");
|
||||
services.AddSingleton<IMongoDatabase>(database);
|
||||
|
||||
services.AddMediatR(config =>
|
||||
config.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly));
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Knot.Shared.Kernel;
|
||||
using System;
|
||||
|
||||
namespace Knot.Modules.Profiles.Domain.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Доменное событие: профиль пользователя создан при регистрации.
|
||||
/// </summary>
|
||||
public sealed record ProfileCreatedDomainEvent(Guid UserId, string Username) : IDomainEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Доменное событие: аватар профиля был изменён (для возможной инвалидации CDN-кэша).
|
||||
/// </summary>
|
||||
public sealed record ProfileAvatarChangedDomainEvent(Guid UserId, string? OldAvatarFileId, string? NewAvatarFileId) : IDomainEvent;
|
||||
69
backend/src/Modules/Profiles/Domain/ProfileDocument.cs
Normal file
69
backend/src/Modules/Profiles/Domain/ProfileDocument.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using System;
|
||||
|
||||
namespace Knot.Modules.Profiles.Domain;
|
||||
|
||||
/// <summary>
|
||||
/// MongoDB-документ профиля пользователя.
|
||||
/// Id совпадает с UserId из модуля Auth (Postgres).
|
||||
/// Аватар хранится в S3 — здесь лежит только ссылка.
|
||||
/// </summary>
|
||||
public sealed class ProfileDocument
|
||||
{
|
||||
[BsonId]
|
||||
[BsonRepresentation(BsonType.String)]
|
||||
public Guid Id { get; private set; }
|
||||
|
||||
public string Username { get; private set; }
|
||||
|
||||
public string DisplayName { get; private set; }
|
||||
|
||||
public string? Bio { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// URL или ключ объекта в S3-хранилище (MinIO).
|
||||
/// Пример: "/api/files/{fileId}"
|
||||
/// </summary>
|
||||
public string? AvatarUrl { get; private set; }
|
||||
|
||||
public DateTime? Birthday { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Скрывать ли просмотры сторис от других пользователей.
|
||||
/// </summary>
|
||||
public bool HideStoryViews { get; private set; }
|
||||
|
||||
public DateTime CreatedAt { get; private set; }
|
||||
|
||||
// Для MongoDB — protected-конструктор через BSON-десериализацию
|
||||
protected ProfileDocument() { }
|
||||
|
||||
private ProfileDocument(Guid id, string username, string displayName, string? bio)
|
||||
{
|
||||
Id = id;
|
||||
Username = username;
|
||||
DisplayName = displayName;
|
||||
Bio = bio;
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public static ProfileDocument Create(Guid userId, string username, string displayName, string? bio = null)
|
||||
=> new(userId, username, displayName, bio);
|
||||
|
||||
public void UpdateProfile(string displayName, string? bio, DateTime? birthday)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
Bio = bio;
|
||||
Birthday = birthday;
|
||||
}
|
||||
|
||||
public void UpdateAvatar(string? avatarUrl)
|
||||
=> AvatarUrl = avatarUrl;
|
||||
|
||||
public void RemoveAvatar()
|
||||
=> AvatarUrl = null;
|
||||
|
||||
public void UpdateSettings(bool hideStoryViews)
|
||||
=> HideStoryViews = hideStoryViews;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Shared.Kernel.Storage;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Infrastructure.Database;
|
||||
|
||||
/// <summary>
|
||||
/// Адаптер к S3-хранилищу для аватаров.
|
||||
/// Инжектирует общий IFileStorageService и передает ему управление.
|
||||
/// </summary>
|
||||
internal sealed class AvatarStorageService : IAvatarStorageService
|
||||
{
|
||||
private readonly IFileStorageService _storage;
|
||||
|
||||
public AvatarStorageService(IFileStorageService storage)
|
||||
{
|
||||
_storage = storage;
|
||||
}
|
||||
|
||||
public async Task<string> UploadAsync(Stream stream, string fileName, string contentType, CancellationToken ct = default)
|
||||
{
|
||||
return await _storage.UploadFileAsync(stream, fileName, contentType);
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(string fileId, CancellationToken ct = default)
|
||||
{
|
||||
// Если fileId содержит "/api/files/", обрезаем его до чистого ID
|
||||
var cleanId = fileId.Replace("/api/files/", "");
|
||||
await _storage.DeleteFileAsync(cleanId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using Knot.Modules.Profiles.Domain;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Infrastructure.Database;
|
||||
|
||||
internal sealed class ProfileRepository : IProfileRepository
|
||||
{
|
||||
private readonly IMongoCollection<ProfileDocument> _profiles;
|
||||
|
||||
public ProfileRepository(IMongoDatabase database)
|
||||
{
|
||||
_profiles = database.GetCollection<ProfileDocument>("profiles");
|
||||
}
|
||||
|
||||
public async Task<ProfileDocument?> GetByIdAsync(Guid userId, CancellationToken ct = default)
|
||||
{
|
||||
return await _profiles.Find(p => p.Id == userId).FirstOrDefaultAsync(ct);
|
||||
}
|
||||
|
||||
public async Task AddAsync(ProfileDocument profile, CancellationToken ct = default)
|
||||
{
|
||||
await _profiles.InsertOneAsync(profile, null, ct);
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(ProfileDocument profile, CancellationToken ct = default)
|
||||
{
|
||||
await _profiles.ReplaceOneAsync(p => p.Id == profile.Id, profile, new ReplaceOptions { IsUpsert = false }, ct);
|
||||
}
|
||||
|
||||
public async Task<List<ProfileDocument>> SearchAsync(string query, CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
return new List<ProfileDocument>();
|
||||
|
||||
// Простой регистронезависимый поиск по Regex (в реальной системе лучше использовать Text Index)
|
||||
var filter = Builders<ProfileDocument>.Filter.Or(
|
||||
Builders<ProfileDocument>.Filter.Regex(p => p.Username, new MongoDB.Bson.BsonRegularExpression(query, "i")),
|
||||
Builders<ProfileDocument>.Filter.Regex(p => p.DisplayName, new MongoDB.Bson.BsonRegularExpression(query, "i"))
|
||||
);
|
||||
|
||||
return await _profiles.Find(filter).Limit(20).ToListAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Knot.Modules.Profiles.Application.Abstractions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Infrastructure.Database;
|
||||
|
||||
internal sealed class ProfilesUnitOfWork : IProfilesUnitOfWork
|
||||
{
|
||||
// MongoDB updates are atomic per document by default in the driver,
|
||||
// so for simple ProfileDocument updates, we don't need distributed transactions.
|
||||
public Task SaveChangesAsync(CancellationToken ct = default) => Task.CompletedTask;
|
||||
}
|
||||
@@ -15,12 +15,22 @@
|
||||
<PackageReference Include="MediatR" Version="12.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.4" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="3.2.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<ProjectReference Include="..\..\Shared\Knot.Shared.Kernel\Knot.Shared.Kernel.csproj" />
|
||||
<ProjectReference Include="..\..\Shared\Knot.Shared.Infrastructure\Knot.Shared.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Settings\Knot.Modules.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="Knot.Modules.Profiles.UnitTests" />
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Knot.Modules.Relations.Application.Abstractions;
|
||||
namespace Knot.Modules.Relations.Application.Abstractions;
|
||||
|
||||
public interface IContactsDbContext
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace Knot.Modules.Relations.Application.Contacts;
|
||||
|
||||
public class ContactDto
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public string Username { get; init; } = string.Empty;
|
||||
public string DisplayName { get; init; } = string.Empty;
|
||||
public string Avatar { get; init; } = string.Empty;
|
||||
public bool IsOnline { get; init; }
|
||||
public DateTime? LastSeen { get; init; }
|
||||
public Guid RelationId { get; init; }
|
||||
public bool IsBlocked { get; init; }
|
||||
public bool IsExternal { get; init; }
|
||||
public string? Domain { get; init; }
|
||||
|
||||
public ContactDto(
|
||||
Guid id,
|
||||
string username,
|
||||
string displayName,
|
||||
string avatar,
|
||||
bool isOnline,
|
||||
DateTime? lastSeen,
|
||||
Guid relationId,
|
||||
bool isBlocked = false,
|
||||
bool isExternal = false,
|
||||
string? domain = null)
|
||||
{
|
||||
Id = id;
|
||||
Username = username;
|
||||
DisplayName = displayName;
|
||||
Avatar = avatar;
|
||||
IsOnline = isOnline;
|
||||
LastSeen = lastSeen;
|
||||
RelationId = relationId;
|
||||
IsBlocked = isBlocked;
|
||||
IsExternal = isExternal;
|
||||
Domain = domain;
|
||||
}
|
||||
}
|
||||
@@ -10,18 +10,6 @@ using Knot.Modules.Relations.Application.Abstractions;
|
||||
|
||||
namespace Knot.Modules.Relations.Application.Contacts;
|
||||
|
||||
public record ContactDto(
|
||||
Guid Id,
|
||||
string Username,
|
||||
string DisplayName,
|
||||
string Avatar,
|
||||
bool IsOnline,
|
||||
DateTime? LastSeen,
|
||||
Guid RelationId,
|
||||
bool IsBlocked = false,
|
||||
bool IsExternal = false,
|
||||
string? Domain = null);
|
||||
|
||||
public record GetContactsQuery(Guid UserId) : IQuery<List<ContactDto>>;
|
||||
|
||||
internal sealed class GetContactsQueryHandler : IQueryHandler<GetContactsQuery, List<ContactDto>>
|
||||
@@ -56,7 +44,7 @@ internal sealed class GetContactsQueryHandler : IQueryHandler<GetContactsQuery,
|
||||
replica.Username,
|
||||
replica.DisplayName,
|
||||
replica.Avatar,
|
||||
false, // Presence handled by another service or real-time
|
||||
false,
|
||||
null,
|
||||
rel.Id,
|
||||
rel.Status == ContactStatus.Blocked,
|
||||
|
||||
@@ -14,9 +14,6 @@ internal sealed class RemoveContactCommandHandler : ICommandHandler<RemoveContac
|
||||
{
|
||||
private readonly IContactsDbContext _context;
|
||||
|
||||
public ContactRelationNotFound() : base("Contacts.NotFound", "Contact relation not found.") { }
|
||||
public ContactRelationUnauthorized() : base("Contacts.Unauthorized", "You are not authorized to remove this contact.") { }
|
||||
|
||||
public RemoveContactCommandHandler(IContactsDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user