diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/Condition.cs b/src/LEGO.AsyncAPI.Bindings/Sns/Condition.cs new file mode 100644 index 00000000..38b21da9 --- /dev/null +++ b/src/LEGO.AsyncAPI.Bindings/Sns/Condition.cs @@ -0,0 +1,67 @@ +// Copyright (c) The LEGO Group. All rights reserved. + +namespace LEGO.AsyncAPI.Bindings.Sns; + +using System; +using System.Collections.Generic; +using System.Linq; +using LEGO.AsyncAPI.Models.Interfaces; +using LEGO.AsyncAPI.Readers.ParseNodes; +using LEGO.AsyncAPI.Writers; + +public class Condition : IAsyncApiElement +{ + public Dictionary> Value { get; private set; } + + public Condition(Dictionary> value) + { + this.Value = value; + } + + public void Serialize(IAsyncApiWriter writer) + { + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteStartObject(); + foreach (var conditionValue in this.Value) + { + writer.WriteRequiredMap(conditionValue.Key, conditionValue.Value, (w, t) => t.Value.Write(w)); + } + + writer.WriteEndObject(); + } + + public static Condition Parse(ParseNode node) + { + switch (node) + { + case MapNode mapNode: + { + var conditionValues = new Dictionary>(); + foreach (var conditionNode in mapNode) + { + switch (conditionNode.Value) + { + case MapNode conditionValueNode: + conditionValues.Add(conditionNode.Name, new Dictionary(conditionValueNode.Select(x => + new KeyValuePair(x.Name, StringOrStringList.Parse(x.Value))) + .ToDictionary(x => x.Key, x => x.Value))); + break; + default: + throw new ArgumentException($"An error occured while parsing a {nameof(Condition)} node. " + + $"AWS condition values should be one or more key value pairs."); + } + } + + return new Condition(conditionValues); + } + + default: + throw new ArgumentException($"An error occured while parsing a {nameof(Condition)} node. " + + $"Node should contain a collection of condition types."); + } + } +} \ No newline at end of file diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/SnsChannelBinding.cs b/src/LEGO.AsyncAPI.Bindings/Sns/SnsChannelBinding.cs index 4d8668c9..4394cdd1 100644 --- a/src/LEGO.AsyncAPI.Bindings/Sns/SnsChannelBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/Sns/SnsChannelBinding.cs @@ -60,7 +60,7 @@ public class SnsChannelBinding : ChannelBinding { "principal", (a, n) => { a.Principal = Principal.Parse(n); } }, { "action", (a, n) => { a.Action = StringOrStringList.Parse(n); } }, { "resource", (a, n) => { a.Resource = StringOrStringList.Parse(n); } }, - { "condition", (a, n) => { a.Condition = n.CreateAny(); } }, + { "condition", (a, n) => { a.Condition = Condition.Parse(n); } }, }; /// diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/Statement.cs b/src/LEGO.AsyncAPI.Bindings/Sns/Statement.cs index 170fe371..95b5e3df 100644 --- a/src/LEGO.AsyncAPI.Bindings/Sns/Statement.cs +++ b/src/LEGO.AsyncAPI.Bindings/Sns/Statement.cs @@ -33,7 +33,7 @@ public class Statement : IAsyncApiExtensible /// /// Specific circumstances under which the policy grants permission. /// - public AsyncApiAny? Condition { get; set; } + public Condition? Condition { get; set; } public IDictionary Extensions { get; set; } = new Dictionary(); @@ -49,7 +49,7 @@ public void Serialize(IAsyncApiWriter writer) writer.WriteRequiredObject("principal", this.Principal, (w, t) => t.Serialize(w)); writer.WriteRequiredObject("action", this.Action, (w, t) => t.Value.Write(w)); writer.WriteOptionalObject("resource", this.Resource, (w, t) => t?.Value.Write(w)); - writer.WriteOptionalObject("condition", this.Condition, (w, t) => t?.Write(w)); + writer.WriteOptionalObject("condition", this.Condition, (w, t) => t?.Serialize(w)); writer.WriteExtensions(this.Extensions); writer.WriteEndObject(); } diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/Condition.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/Condition.cs new file mode 100644 index 00000000..93bdf733 --- /dev/null +++ b/src/LEGO.AsyncAPI.Bindings/Sqs/Condition.cs @@ -0,0 +1,67 @@ +// Copyright (c) The LEGO Group. All rights reserved. + +namespace LEGO.AsyncAPI.Bindings.Sqs; + +using System; +using System.Collections.Generic; +using System.Linq; +using LEGO.AsyncAPI.Models.Interfaces; +using LEGO.AsyncAPI.Readers.ParseNodes; +using LEGO.AsyncAPI.Writers; + +public class Condition : IAsyncApiElement +{ + public Dictionary> Value { get; private set; } + + public Condition(Dictionary> value) + { + this.Value = value; + } + + public void Serialize(IAsyncApiWriter writer) + { + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteStartObject(); + foreach (var conditionValue in this.Value) + { + writer.WriteRequiredMap(conditionValue.Key, conditionValue.Value, (w, t) => t.Value.Write(w)); + } + + writer.WriteEndObject(); + } + + public static Condition Parse(ParseNode node) + { + switch (node) + { + case MapNode mapNode: + { + var conditionValues = new Dictionary>(); + foreach (var conditionNode in mapNode) + { + switch (conditionNode.Value) + { + case MapNode conditionValueNode: + conditionValues.Add(conditionNode.Name, new Dictionary(conditionValueNode.Select(x => + new KeyValuePair(x.Name, StringOrStringList.Parse(x.Value))) + .ToDictionary(x => x.Key, x => x.Value))); + break; + default: + throw new ArgumentException($"An error occured while parsing a {nameof(Condition)} node. " + + $"AWS condition values should be one or more key value pairs."); + } + } + + return new Condition(conditionValues); + } + + default: + throw new ArgumentException($"An error occured while parsing a {nameof(Condition)} node. " + + $"Node should contain a collection of AWS condition types."); + } + } +} \ No newline at end of file diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/SqsChannelBinding.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/SqsChannelBinding.cs index f0b24be7..bd806071 100644 --- a/src/LEGO.AsyncAPI.Bindings/Sqs/SqsChannelBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/Sqs/SqsChannelBinding.cs @@ -67,7 +67,7 @@ public class SqsChannelBinding : ChannelBinding { "principal", (a, n) => { a.Principal = Principal.Parse(n); } }, { "action", (a, n) => { a.Action = StringOrStringList.Parse(n); } }, { "resource", (a, n) => { a.Resource = StringOrStringList.Parse(n); } }, - { "condition", (a, n) => { a.Condition = n.CreateAny(); } }, + { "condition", (a, n) => { a.Condition = Condition.Parse(n); } }, }; public override void SerializeProperties(IAsyncApiWriter writer) diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/SqsOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/SqsOperationBinding.cs index ed278013..0beb89b8 100644 --- a/src/LEGO.AsyncAPI.Bindings/Sqs/SqsOperationBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/Sqs/SqsOperationBinding.cs @@ -59,7 +59,7 @@ public class SqsOperationBinding : OperationBinding { "principal", (a, n) => { a.Principal = Principal.Parse(n); } }, { "action", (a, n) => { a.Action = StringOrStringList.Parse(n); } }, { "resource", (a, n) => { a.Resource = StringOrStringList.Parse(n); } }, - { "condition", (a, n) => { a.Condition = n.CreateAny(); } }, + { "condition", (a, n) => { a.Condition = Condition.Parse(n); } }, }; public override void SerializeProperties(IAsyncApiWriter writer) diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/Statement.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/Statement.cs index 4abc05a6..0ab25e89 100644 --- a/src/LEGO.AsyncAPI.Bindings/Sqs/Statement.cs +++ b/src/LEGO.AsyncAPI.Bindings/Sqs/Statement.cs @@ -34,7 +34,7 @@ public class Statement : IAsyncApiExtensible /// /// Specific circumstances under which the policy grants permission. /// - public AsyncApiAny? Condition { get; set; } + public Condition? Condition { get; set; } public IDictionary Extensions { get; set; } = new Dictionary(); @@ -50,7 +50,7 @@ public void Serialize(IAsyncApiWriter writer) writer.WriteRequiredObject("principal", this.Principal, (w, t) => t.Serialize(w)); writer.WriteRequiredObject("action", this.Action, (w, t) => t.Value.Write(w)); writer.WriteOptionalObject("resource", this.Resource, (w, t) => t?.Value.Write(w)); - writer.WriteOptionalObject("condition", this.Condition, (w, t) => t?.Write(w)); + writer.WriteOptionalObject("condition", this.Condition, (w, t) => t?.Serialize(w)); writer.WriteExtensions(this.Extensions); writer.WriteEndObject(); } diff --git a/test/LEGO.AsyncAPI.Tests/Bindings/Sns/SnsBindings_Should.cs b/test/LEGO.AsyncAPI.Tests/Bindings/Sns/SnsBindings_Should.cs index fbb3622e..daed9e88 100644 --- a/test/LEGO.AsyncAPI.Tests/Bindings/Sns/SnsBindings_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Bindings/Sns/SnsBindings_Should.cs @@ -92,12 +92,14 @@ public void SnsChannelBinding_WithFilledObject_SerializesAndDeserializes() "sns:Publish", "sns:Delete", })), - Condition = new AsyncApiAny(new Dictionary() + Condition = new Condition(new Dictionary> { { - "StringEquals", new Dictionary>() + "StringEquals", new Dictionary { - { "aws:username", new List() { "johndoe", "mrsmith" } }, + { + "aws:username", new StringOrStringList(new AsyncApiAny(new List() { "johndoe", "mrsmith" })) + }, } }, }), @@ -109,12 +111,14 @@ public void SnsChannelBinding_WithFilledObject_SerializesAndDeserializes() "AWS", new StringOrStringList(new AsyncApiAny(new List { "arn:aws:iam::123456789012:user/alex.wichmann", "arn:aws:iam::123456789012:user/dec.kolakowski" })))), Action = new StringOrStringList(new AsyncApiAny("sns:Create")), - Condition = new AsyncApiAny(new Dictionary() + Condition = new Condition(new Dictionary> { { - "NumericLessThanEquals", new Dictionary() + "NumericLessThanEquals", new Dictionary { - { "aws:MultiFactorAuthAge", "3600" }, + { + "aws:MultiFactorAuthAge", new StringOrStringList(new AsyncApiAny("3600")) + }, } }, }), diff --git a/test/LEGO.AsyncAPI.Tests/Bindings/Sqs/SqsBindings_should.cs b/test/LEGO.AsyncAPI.Tests/Bindings/Sqs/SqsBindings_should.cs index 3a0337a3..c3f7ff9d 100644 --- a/test/LEGO.AsyncAPI.Tests/Bindings/Sqs/SqsBindings_should.cs +++ b/test/LEGO.AsyncAPI.Tests/Bindings/Sqs/SqsBindings_should.cs @@ -143,12 +143,14 @@ public void SqsChannelBinding_WithFilledObject_SerializesAndDeserializes() "sqs:SendMessage", "sqs:ReceiveMessage", })), - Condition = new AsyncApiAny(new Dictionary() + Condition = new Condition(new Dictionary> { { - "StringEquals", new Dictionary>() + "StringEquals", new Dictionary { - { "aws:username", new List() { "johndoe", "mrsmith" } }, + { + "aws:username", new StringOrStringList(new AsyncApiAny(new List { "johndoe", "mrsmith" })) + }, } }, }), @@ -170,12 +172,14 @@ public void SqsChannelBinding_WithFilledObject_SerializesAndDeserializes() "AWS", new StringOrStringList(new AsyncApiAny(new List { "arn:aws:iam::123456789012:user/alex.wichmann", "arn:aws:iam::123456789012:user/dec.kolakowski" })))), Action = new StringOrStringList(new AsyncApiAny("sqs:CreateQueue")), - Condition = new AsyncApiAny(new Dictionary() + Condition = new Condition(new Dictionary> { { - "NumericLessThanEquals", new Dictionary() + "NumericLessThanEquals", new Dictionary { - { "aws:MultiFactorAuthAge", "3600" }, + { + "aws:MultiFactorAuthAge", new StringOrStringList(new AsyncApiAny("3600")) + }, } }, }),