From ca41e3924a29f37ef4959ead523f660ec058b92b Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Thu, 21 Sep 2023 13:37:15 +0300 Subject: [PATCH 1/5] add linq add ctor add static --- src/KYC.API.Proxy/LambdaFunction.cs | 34 +++++--------------------- src/KYC.API.Proxy/Models/OutputData.cs | 14 ++++++++++- src/KYC.API.Proxy/Utils/DynamoDb.cs | 20 +++++---------- 3 files changed, 25 insertions(+), 43 deletions(-) diff --git a/src/KYC.API.Proxy/LambdaFunction.cs b/src/KYC.API.Proxy/LambdaFunction.cs index 63172cd..1b60ca5 100644 --- a/src/KYC.API.Proxy/LambdaFunction.cs +++ b/src/KYC.API.Proxy/LambdaFunction.cs @@ -1,7 +1,6 @@ using Amazon.Lambda.Core; using KYC.API.Proxy.Utils; using KYC.API.Proxy.Models; -using KYC.API.Proxy.Models.HttpResponse; [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] @@ -27,41 +26,20 @@ public OutputData Run(InputData request) { if (string.IsNullOrWhiteSpace(request.Address) || request.Address == ZeroAddress) { - return new OutputData - { - RequestStatus = RequestStatus.error - }; + return OutputData.Error; } var response = httpCall.GetBlockPassResponse(request.Address); if (response.Status != RequestStatus.error) { - return BuildOutputData(response); + return new(response); } var wallets = dynamoDb.GetWallets(request.Address); - foreach (var wallet in wallets) - { - response = httpCall.GetBlockPassResponse(wallet); - if (response.Status != RequestStatus.error) - { - return BuildOutputData(response); - } - } + var validResponse = wallets + .Select(wallet => httpCall.GetBlockPassResponse(wallet)) + .FirstOrDefault(response => response.Status != RequestStatus.error); - return new OutputData - { - RequestStatus = RequestStatus.error - }; - } - - private static OutputData BuildOutputData(Response response) - { - return new OutputData - { - RequestStatus = response.Status, - Status = response.Data.Status, - Name = response.Data.Identities.GivenName.Value - }; + return validResponse == null? OutputData.Error : new(validResponse); } } diff --git a/src/KYC.API.Proxy/Models/OutputData.cs b/src/KYC.API.Proxy/Models/OutputData.cs index 6ba0b34..8a3f974 100644 --- a/src/KYC.API.Proxy/Models/OutputData.cs +++ b/src/KYC.API.Proxy/Models/OutputData.cs @@ -1,12 +1,24 @@ -using Newtonsoft.Json; +using KYC.API.Proxy.Models.HttpResponse; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace KYC.API.Proxy.Models; public class OutputData { + public OutputData() { } + public OutputData(Response response) + { + RequestStatus = response.Status; + Status = response.Data.Status; + Name = response.Data.Identities.GivenName.Value; + } [JsonConverter(typeof(StringEnumConverter))] public RequestStatus RequestStatus { get; set; } public string? Status { get; set; } public string? Name { get; set; } + public static OutputData Error => new() + { + RequestStatus = RequestStatus.error + }; } \ No newline at end of file diff --git a/src/KYC.API.Proxy/Utils/DynamoDb.cs b/src/KYC.API.Proxy/Utils/DynamoDb.cs index 384899c..e573b5b 100644 --- a/src/KYC.API.Proxy/Utils/DynamoDb.cs +++ b/src/KYC.API.Proxy/Utils/DynamoDb.cs @@ -24,20 +24,12 @@ public virtual string[] GetWallets(string wallet) var associatedWallets = user["EvmWallets"].L.Select(x => x.S).ToArray(); - var wallets = new List(); - foreach (var associatedWallet in associatedWallets) - { - var associatedUser = GetItem(associatedWallet); - if (associatedUser == null || !associatedUser.ContainsKey("EvmWallets")) - continue; - - if (associatedUser["EvmWallets"].L.Exists(x => x.S == wallet)) - { - wallets.Add(associatedUser["EvmWallet"].S); - } - } - - return wallets.ToArray(); + return associatedWallets + .Select(associatedWallet => GetItem(associatedWallet)) + .Where(associatedUser => associatedUser != null && associatedUser.ContainsKey("EvmWallets")) + .Where(associatedUser => associatedUser!["EvmWallets"].L.Exists(x => x.S == wallet)) + .Select(associatedUser => associatedUser!["EvmWallet"].S) + .ToArray(); } public virtual Dictionary? GetItem(string primaryKey) From ae35b96e86d02afb55dff8cb7039c9276dbb46d3 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Thu, 21 Sep 2023 13:49:57 +0300 Subject: [PATCH 2/5] string[] => IEnumerable --- src/KYC.API.Proxy/Utils/DynamoDb.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/KYC.API.Proxy/Utils/DynamoDb.cs b/src/KYC.API.Proxy/Utils/DynamoDb.cs index e573b5b..e26c314 100644 --- a/src/KYC.API.Proxy/Utils/DynamoDb.cs +++ b/src/KYC.API.Proxy/Utils/DynamoDb.cs @@ -16,7 +16,7 @@ public DynamoDb(IAmazonDynamoDB client) this.client = client; } - public virtual string[] GetWallets(string wallet) + public virtual IEnumerable GetWallets(string wallet) { var user = GetItem(wallet); if (user == null || !user.ContainsKey("EvmWallets")) @@ -28,8 +28,7 @@ public virtual string[] GetWallets(string wallet) .Select(associatedWallet => GetItem(associatedWallet)) .Where(associatedUser => associatedUser != null && associatedUser.ContainsKey("EvmWallets")) .Where(associatedUser => associatedUser!["EvmWallets"].L.Exists(x => x.S == wallet)) - .Select(associatedUser => associatedUser!["EvmWallet"].S) - .ToArray(); + .Select(associatedUser => associatedUser!["EvmWallet"].S); } public virtual Dictionary? GetItem(string primaryKey) From 74e1a0dc55384a107b59788c66e8b1370f5b83d8 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Thu, 21 Sep 2023 13:53:55 +0300 Subject: [PATCH 3/5] ctor internal --- src/KYC.API.Proxy/Models/OutputData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/KYC.API.Proxy/Models/OutputData.cs b/src/KYC.API.Proxy/Models/OutputData.cs index 8a3f974..fab0c28 100644 --- a/src/KYC.API.Proxy/Models/OutputData.cs +++ b/src/KYC.API.Proxy/Models/OutputData.cs @@ -6,7 +6,7 @@ namespace KYC.API.Proxy.Models; public class OutputData { - public OutputData() { } + internal OutputData() { } public OutputData(Response response) { RequestStatus = response.Status; From bc7e3b57d90f3e61d00a8199116fba9df246fa25 Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Thu, 21 Sep 2023 14:00:20 +0300 Subject: [PATCH 4/5] fix name, move valid to inputdata --- src/KYC.API.Proxy/LambdaFunction.cs | 5 ++--- src/KYC.API.Proxy/Models/InputData.cs | 2 ++ tests/KYC.API.Proxy.Tests/LambdaFunctionTests.cs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/KYC.API.Proxy/LambdaFunction.cs b/src/KYC.API.Proxy/LambdaFunction.cs index 1b60ca5..20a4540 100644 --- a/src/KYC.API.Proxy/LambdaFunction.cs +++ b/src/KYC.API.Proxy/LambdaFunction.cs @@ -8,7 +8,6 @@ namespace KYC.API.Proxy; public class LambdaFunction { - public const string ZeroAddress = "0x0000000000000000000000000000000000000000"; private readonly HttpCall httpCall; private readonly DynamoDb dynamoDb; @@ -24,7 +23,7 @@ public LambdaFunction(HttpCall httpCall, DynamoDb dynamoDb) public OutputData Run(InputData request) { - if (string.IsNullOrWhiteSpace(request.Address) || request.Address == ZeroAddress) + if (!request.Valid) { return OutputData.Error; } @@ -38,7 +37,7 @@ public OutputData Run(InputData request) var wallets = dynamoDb.GetWallets(request.Address); var validResponse = wallets .Select(wallet => httpCall.GetBlockPassResponse(wallet)) - .FirstOrDefault(response => response.Status != RequestStatus.error); + .FirstOrDefault(_response => _response.Status != RequestStatus.error); return validResponse == null? OutputData.Error : new(validResponse); } diff --git a/src/KYC.API.Proxy/Models/InputData.cs b/src/KYC.API.Proxy/Models/InputData.cs index 7123c45..d0181e2 100644 --- a/src/KYC.API.Proxy/Models/InputData.cs +++ b/src/KYC.API.Proxy/Models/InputData.cs @@ -2,5 +2,7 @@ public class InputData { + public const string ZeroAddress = "0x0000000000000000000000000000000000000000"; public string Address { get; set; } = null!; + public bool Valid => !string.IsNullOrWhiteSpace(Address) && Address != ZeroAddress; } \ No newline at end of file diff --git a/tests/KYC.API.Proxy.Tests/LambdaFunctionTests.cs b/tests/KYC.API.Proxy.Tests/LambdaFunctionTests.cs index 61b3862..7b6b518 100644 --- a/tests/KYC.API.Proxy.Tests/LambdaFunctionTests.cs +++ b/tests/KYC.API.Proxy.Tests/LambdaFunctionTests.cs @@ -32,7 +32,7 @@ internal void Run_ShouldReturnForbidden_WhenAddressIsInvalid() { var request = new InputData { - Address = LambdaFunction.ZeroAddress + Address = InputData.ZeroAddress }; var lambdaFunction = MockLambdaFunction(); From c233fe6934d24b1c91f02de11543d4dab737b8ac Mon Sep 17 00:00:00 2001 From: Stan Goldin Date: Thu, 21 Sep 2023 15:52:22 +0300 Subject: [PATCH 5/5] refactor --- src/KYC.API.Proxy/LambdaFunction.cs | 81 +++++-------------- src/KYC.API.Proxy/LambdaFunctionScenarios.cs | 46 +++++++++++ src/KYC.API.Proxy/Models/OutputData.cs | 3 +- src/KYC.API.Proxy/Utils/DynamoDb.cs | 2 + .../LambdaFunctionTests.cs | 28 +++---- 5 files changed, 86 insertions(+), 74 deletions(-) create mode 100644 src/KYC.API.Proxy/LambdaFunctionScenarios.cs diff --git a/src/KYC.API.Proxy/LambdaFunction.cs b/src/KYC.API.Proxy/LambdaFunction.cs index 333eb6f..e293781 100644 --- a/src/KYC.API.Proxy/LambdaFunction.cs +++ b/src/KYC.API.Proxy/LambdaFunction.cs @@ -4,75 +4,38 @@ [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] -namespace KYC.API.Proxy; - -public class LambdaFunction +namespace KYC.API.Proxy { - private readonly HttpCall httpCall; - private readonly DynamoDb dynamoDb; - - public LambdaFunction() - : this(new HttpCall(), new DynamoDb()) - { } - - public LambdaFunction(HttpCall httpCall, DynamoDb dynamoDb) + public class LambdaFunction : LambdaFunctionScenarios { - this.httpCall = httpCall; - this.dynamoDb = dynamoDb; - } + public LambdaFunction() + : this(new HttpCall(), new DynamoDb()) + { } - public async Task RunAsync(InputData request) - { - if (!request.Valid) - { - return OutputData.Error; - } - var response = httpCall.GetBlockPassResponse(request.Address); - - if (response.Status != RequestStatus.error) - { - return new(response); - } + public LambdaFunction(HttpCall httpCall, DynamoDb dynamoDb) + : base(httpCall, dynamoDb) + { } - var proxy = dynamoDb.GetProxyAddress(request.Address); - if (proxy != null) + public OutputData Run(InputData request) { - response = httpCall.GetBlockPassResponse(proxy); + if (!request.Valid) + return OutputData.Error; - if (response.Status != RequestStatus.error) + var scenarios = new List> { - return BuildOutputData(response, proxy); - } - } + HandleBlockPassResponse, + HandleProxyAddress, + HandleValidWallet + }; - var wallets = dynamoDb.GetWallets(request.Address); - foreach (var wallet in wallets) - { - response = httpCall.GetBlockPassResponse(wallet); - if (response.Status != RequestStatus.error) + foreach (var scenario in scenarios) { - if (proxy != wallet) - { - await dynamoDb.UpdateItemAsync(request.Address, wallet); - } - return BuildOutputData(response, wallet); + var result = scenario(request); + if (result != null) + return result; } - } - return new OutputData - { - RequestStatus = RequestStatus.error - }; - } - - private static OutputData BuildOutputData(Response response, string? proxy = null) - { - return new OutputData - { - RequestStatus = response.Status, - Status = response.Data.Status, - Name = response.Data.Identities.GivenName.Value, - Proxy = proxy - }; + return OutputData.Error; + } } } diff --git a/src/KYC.API.Proxy/LambdaFunctionScenarios.cs b/src/KYC.API.Proxy/LambdaFunctionScenarios.cs new file mode 100644 index 0000000..5125dd7 --- /dev/null +++ b/src/KYC.API.Proxy/LambdaFunctionScenarios.cs @@ -0,0 +1,46 @@ +using KYC.API.Proxy.Models; +using KYC.API.Proxy.Utils; + +namespace KYC.API.Proxy; + +public class LambdaFunctionScenarios +{ + internal LambdaFunctionScenarios(HttpCall httpCall, DynamoDb dynamoDb) + { + _httpCall = httpCall; + _dynamoDb = dynamoDb; + } + + private readonly HttpCall _httpCall; + private readonly DynamoDb _dynamoDb; + internal OutputData? HandleBlockPassResponse(InputData request) + { + var response = _httpCall.GetBlockPassResponse(request.Address); + return response.Status == RequestStatus.success ? new OutputData(response) : null; + } + + internal OutputData? HandleProxyAddress(InputData request) + { + var proxy = _dynamoDb.GetProxyAddress(request.Address); + if (proxy == null) return null; + + var response = _httpCall.GetBlockPassResponse(proxy); + return response.Status == RequestStatus.success ? new OutputData(response, proxy) : null; + } + + internal OutputData? HandleValidWallet(InputData request) + { + var proxy = _dynamoDb.GetProxyAddress(request.Address); + + var validWallet = _dynamoDb.GetWallets(request.Address) + .Select(wallet => new { Wallet = wallet, Response = _httpCall.GetBlockPassResponse(wallet) }) + .FirstOrDefault(w => w.Response.Status == RequestStatus.success); + + if (validWallet == null) return null; + + if (proxy != validWallet.Wallet) + _dynamoDb.UpdateItem(request.Address, validWallet.Wallet); + + return new OutputData(validWallet.Response, validWallet.Wallet); + } +} \ No newline at end of file diff --git a/src/KYC.API.Proxy/Models/OutputData.cs b/src/KYC.API.Proxy/Models/OutputData.cs index 5f9cf95..cc34f2c 100644 --- a/src/KYC.API.Proxy/Models/OutputData.cs +++ b/src/KYC.API.Proxy/Models/OutputData.cs @@ -7,11 +7,12 @@ namespace KYC.API.Proxy.Models; public class OutputData { internal OutputData() { } - public OutputData(Response response) + public OutputData(Response response, string? proxy = null) { RequestStatus = response.Status; Status = response.Data.Status; Name = response.Data.Identities.GivenName.Value; + Proxy = proxy; } [JsonConverter(typeof(StringEnumConverter))] public RequestStatus RequestStatus { get; set; } diff --git a/src/KYC.API.Proxy/Utils/DynamoDb.cs b/src/KYC.API.Proxy/Utils/DynamoDb.cs index cb1e154..6c5d035 100644 --- a/src/KYC.API.Proxy/Utils/DynamoDb.cs +++ b/src/KYC.API.Proxy/Utils/DynamoDb.cs @@ -42,6 +42,8 @@ public virtual IEnumerable GetWallets(string wallet) return user.TryGetValue("Proxy", out var proxy) ? proxy.S : null; } + public void UpdateItem(string primaryKey, string proxyAddress) => UpdateItemAsync(primaryKey, proxyAddress).GetAwaiter().GetResult(); + public virtual async Task UpdateItemAsync(string primaryKey, string proxyAddress) { var request = new UpdateItemRequest diff --git a/tests/KYC.API.Proxy.Tests/LambdaFunctionTests.cs b/tests/KYC.API.Proxy.Tests/LambdaFunctionTests.cs index 926f19b..68c5b14 100644 --- a/tests/KYC.API.Proxy.Tests/LambdaFunctionTests.cs +++ b/tests/KYC.API.Proxy.Tests/LambdaFunctionTests.cs @@ -25,7 +25,7 @@ internal void Ctor_Default() } [Fact] - internal async Task RunAsync_ShouldReturnForbidden_WhenAddressIsInvalid() + internal void RunAsync_ShouldReturnForbidden_WhenAddressIsInvalid() { var request = new InputData { @@ -33,24 +33,24 @@ internal async Task RunAsync_ShouldReturnForbidden_WhenAddressIsInvalid() }; var lambdaFunction = MockLambdaFunction(); - var result = await lambdaFunction.RunAsync(request); + var result = lambdaFunction.Run(request); Assert.Equal(RequestStatus.error, result.RequestStatus); } [Fact] - internal async Task RunAsync_ShouldReturnForbidden_WhenAddressIsMissing() + internal void RunAsync_ShouldReturnForbidden_WhenAddressIsMissing() { var request = new InputData(); var lambdaFunction = MockLambdaFunction(); - var result = await lambdaFunction.RunAsync(request); + var result = lambdaFunction.Run(request); Assert.Equal(RequestStatus.error, result.RequestStatus); } [Fact] - internal async Task RunAsync_ShouldReturnExpectedResponse_WhenAddressIsValid() + internal void RunAsync_ShouldReturnExpectedResponse_WhenAddressIsValid() { var request = new InputData { @@ -58,13 +58,13 @@ internal async Task RunAsync_ShouldReturnExpectedResponse_WhenAddressIsValid() }; var lambdaFunction = MockLambdaFunction(); - var result = await lambdaFunction.RunAsync(request); + var result = lambdaFunction.Run(request); Assert.Equal(RequestStatus.success, result.RequestStatus); } [Fact] - internal async Task RunAsync_ReceiveAddressFromProxyAddress() + internal void RunAsync_ReceiveAddressFromProxyAddress() { var mockDynamoDb = new Mock(); mockDynamoDb.Setup(x => x.GetProxyAddress(TestAddress)) @@ -85,13 +85,13 @@ internal async Task RunAsync_ReceiveAddressFromProxyAddress() }; var lambdaFunction = MockLambdaFunction(mockHttpCall, mockDynamoDb); - var result = await lambdaFunction.RunAsync(request); + var result = lambdaFunction.Run(request); Assert.Equal(RequestStatus.success, result.RequestStatus); } [Fact] - internal async Task RunAsync_BadResponseInProxyAddress() + internal void RunAsync_BadResponseInProxyAddress() { var mockDynamoDb = new Mock(); mockDynamoDb.Setup(x => x.GetProxyAddress(TestAddress)) @@ -112,13 +112,13 @@ internal async Task RunAsync_BadResponseInProxyAddress() }; var lambdaFunction = MockLambdaFunction(mockHttpCall, mockDynamoDb); - var result = await lambdaFunction.RunAsync(request); + var result = lambdaFunction.Run(request); Assert.Equal(RequestStatus.error, result.RequestStatus); } [Fact] - internal async Task RunAsync_ReceiveAddressFromAssociatedWallets() + internal void RunAsync_ReceiveAddressFromAssociatedWallets() { var mockDynamoDb = new Mock(); mockDynamoDb.Setup(x => x.GetWallets(TestAddress)) @@ -139,13 +139,13 @@ internal async Task RunAsync_ReceiveAddressFromAssociatedWallets() }; var lambdaFunction = MockLambdaFunction(mockHttpCall, mockDynamoDb); - var result = await lambdaFunction.RunAsync(request); + var result = lambdaFunction.Run(request); Assert.Equal(RequestStatus.success, result.RequestStatus); } [Fact] - internal async Task RunAsync_ReceiveErrorResponse() + internal void RunAsync_ReceiveErrorResponse() { var mockDynamoDb = new Mock(); mockDynamoDb.Setup(x => x.GetWallets(TestAddress)) @@ -164,7 +164,7 @@ internal async Task RunAsync_ReceiveErrorResponse() var lambdaFunction = MockLambdaFunction(mockHttpCall, mockDynamoDb); - var result = await lambdaFunction.RunAsync(request); + var result = lambdaFunction.Run(request); Assert.Equal(RequestStatus.error, result.RequestStatus); }