diff --git a/Passbook.Generator.Tests/GeneratorTests.cs b/Passbook.Generator.Tests/GeneratorTests.cs index 170af1b..3b857b4 100644 --- a/Passbook.Generator.Tests/GeneratorTests.cs +++ b/Passbook.Generator.Tests/GeneratorTests.cs @@ -1,190 +1,210 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Passbook.Generator.Exceptions; using Passbook.Generator.Fields; -using System; -using System.IO; using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; using TimeZoneConverter; using Xunit; -namespace Passbook.Generator.Tests +namespace Passbook.Generator.Tests; + +public class GeneratorTests { - public class GeneratorTests + [Fact] + public void EnsurePassIsGeneratedCorrectly() { - [Fact] - public void EnsurePassIsGeneratedCorrectly() + var request = new PassGeneratorRequest(); + request.ExpirationDate = new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Utc); + request.Nfc = new Nfc("My NFC Message", "SKLSJLKJ"); + + var offset = new DateTime(2018, 01, 05, 12, 00, 0); + var zone = TZConvert.GetTimeZoneInfo("Eastern Standard Time"); + var offsetConverted = new DateTimeOffset(offset, zone.GetUtcOffset(offset)); + + request.RelevantDate = offsetConverted; + + request.AddAuxiliaryField(new StandardField() { - PassGeneratorRequest request = new PassGeneratorRequest(); - request.ExpirationDate = new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Local); - request.Nfc = new Nfc("My NFC Message", "SKLSJLKJ"); + Key = "aux-1", + Value = "Test", + Label = "Label", + Row = 1 + }); + + request.AssociatedStoreIdentifiers.Add(long.MaxValue); + + using var ms = new MemoryStream(); + var opts = new JsonWriterOptions { Indented = true }; + using (var writer = new Utf8JsonWriter(ms, opts)) + + request.Write(writer); + + string jsonString = Encoding.UTF8.GetString(ms.ToArray()); + + dynamic json = JsonSerializer.Deserialize(jsonString)!; + + json.TryGetProperty("expirationDate", out JsonElement expirationDate); + Assert.Equal("2018-01-01T00:00:00+00:00", expirationDate.GetString()); + + json.TryGetProperty("relevantDate", out JsonElement relevantDate); + Assert.Equal("2018-01-05T12:00:00-05:00", relevantDate.GetString()); - DateTime offset = new DateTime(2018, 01, 05, 12, 00, 0); - TimeZoneInfo zone = TZConvert.GetTimeZoneInfo("Eastern Standard Time"); - DateTimeOffset offsetConverted = new DateTimeOffset(offset, zone.GetUtcOffset(offset)); + json.TryGetProperty("nfc", out JsonElement nfcPayload); + nfcPayload.TryGetProperty("message", out JsonElement nfcMessage); + Assert.Equal("My NFC Message", nfcMessage.GetString()); - request.RelevantDate = offsetConverted; + json.TryGetProperty("generic", out JsonElement genericKeys); + genericKeys.TryGetProperty("auxiliaryFields", out JsonElement auxFields); + Assert.Equal(1, auxFields.GetArrayLength()); - request.AddAuxiliaryField(new StandardField() - { - Key = "aux-1", - Value = "Test", - Label = "Label", - Row = 1 - }); + var auxField = auxFields.EnumerateArray().ToArray()[0]; - request.AssociatedStoreIdentifiers.Add(long.MaxValue); + auxField.TryGetProperty("key", out JsonElement key); + Assert.Equal("aux-1", key.GetString()); - using (MemoryStream ms = new MemoryStream()) - { - using (StreamWriter sr = new StreamWriter(ms)) - { - using (JsonWriter writer = new JsonTextWriter(sr)) - { - writer.Formatting = Formatting.Indented; - request.Write(writer); - } + auxField.TryGetProperty("value", out JsonElement value); + Assert.Equal("Test", value.GetString()); - string jsonString = Encoding.UTF8.GetString(ms.ToArray()); + auxField.TryGetProperty("label", out JsonElement label); + Assert.Equal("Label", label.GetString()); - var settings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None }; + auxField.TryGetProperty("row", out JsonElement row); + Assert.Equal(1, row.GetInt32()); - dynamic json = JsonConvert.DeserializeObject(jsonString, settings); + json.TryGetProperty("associatedStoreIdentifiers", out JsonElement associatedAppIdentifiersPayload); + Assert.Equal(1, associatedAppIdentifiersPayload.GetArrayLength()); - Assert.Equal("2018-01-01T00:00:00+00:00", (string)json["expirationDate"]); - Assert.Equal("2018-01-05T12:00:00-05:00", (string)json["relevantDate"]); + var assocId = associatedAppIdentifiersPayload + .EnumerateArray() + .ToArray()[0]; + Assert.Equal(long.MaxValue, assocId.GetInt64()); + } - var nfcPayload = (JToken)json["nfc"]; - var nfcMessage = (string)nfcPayload["message"]; - Assert.Equal("My NFC Message", nfcMessage); + [Fact] + public void EnsureDuplicteKeysThrowAnException() + { + PassGeneratorRequest request = new PassGeneratorRequest(); - var genericKeys = json["generic"]; - Assert.Equal(1, genericKeys["auxiliaryFields"].Count); + request.AddAuxiliaryField(new StandardField() + { + Key = "aux-1", + Value = "Test", + Label = "Label", + }); + + Assert.Throws(() => request.AddHeaderField(new StandardField() + { + Key = "aux-1", + Value = "Test", + Label = "Label", + })); + } - var auxField = genericKeys["auxiliaryFields"][0]; + [Fact] + public void EnsureFieldHasLocalTime() + { + var request = new PassGeneratorRequest + { + ExpirationDate = new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Local), + Nfc = new Nfc("My NFC Message", "SKLSJLKJ") + }; - Assert.Equal("aux-1", (string)auxField["key"]); - Assert.Equal("Test", (string)auxField["value"]); - Assert.Equal("Label", (string)auxField["label"]); - Assert.Equal(1, (int)auxField["row"]); + var offset = new DateTime(2018, 01, 05, 12, 00, 0); + var zone = TZConvert.GetTimeZoneInfo("Eastern Standard Time"); + var offsetConverted = new DateTimeOffset(offset, zone.GetUtcOffset(offset)); - var associatedAppIdentifiersPayload = (JArray)json["associatedStoreIdentifiers"]; - Assert.Single(associatedAppIdentifiersPayload); - Assert.Equal(long.MaxValue, associatedAppIdentifiersPayload[0]); - } - } - } + request.RelevantDate = offsetConverted; - [Fact] - public void EnsureDuplicteKeysThrowAnException() + request.AddAuxiliaryField(new StandardField() { - PassGeneratorRequest request = new PassGeneratorRequest(); - - request.AddAuxiliaryField(new StandardField() - { - Key = "aux-1", - Value = "Test", - Label = "Label", - }); - - Assert.Throws(() => request.AddHeaderField(new StandardField() - { - Key = "aux-1", - Value = "Test", - Label = "Label", - })); - } - - [Fact] - public void EnsureFieldHasLocalTime() + Key = "aux-1", + Value = "Test", + Label = "Label", + Row = 1 + }); + + var local = DateTime.Now; + local = new DateTime(local.Year, local.Month, local.Day, local.Hour, local.Minute, local.Second, local.Kind); + request.AddAuxiliaryField(new DateField() { - PassGeneratorRequest request = new PassGeneratorRequest(); - request.ExpirationDate = new DateTime(2018, 1, 1, 0, 0, 0, DateTimeKind.Local); - request.Nfc = new Nfc("My NFC Message", "SKLSJLKJ"); - - DateTime offset = new DateTime(2018, 01, 05, 12, 00, 0); - TimeZoneInfo zone = TZConvert.GetTimeZoneInfo("Eastern Standard Time"); - DateTimeOffset offsetConverted = new DateTimeOffset(offset, zone.GetUtcOffset(offset)); - - request.RelevantDate = offsetConverted; - - request.AddAuxiliaryField(new StandardField() - { - Key = "aux-1", - Value = "Test", - Label = "Label", - Row = 1 - }); - - var local = DateTime.Now; - local = new DateTime(local.Year, local.Month, local.Day, local.Hour, local.Minute, local.Second, local.Kind); - request.AddAuxiliaryField(new DateField() - { - Key = "datetime-1", - Value = local, - Label = "Label", - }); - - var utc = DateTime.UtcNow; - utc = new DateTime(utc.Year, utc.Month, utc.Day, utc.Hour, utc.Minute, utc.Second, utc.Kind); - request.AddAuxiliaryField(new DateField() - { - Key = "datetime-2", - Value = utc, - Label = "Label", - }); - - using (MemoryStream ms = new MemoryStream()) - { - using (StreamWriter sr = new StreamWriter(ms)) - { - using (JsonWriter writer = new JsonTextWriter(sr)) - { - writer.Formatting = Formatting.Indented; - request.Write(writer); - } - - string jsonString = Encoding.UTF8.GetString(ms.ToArray()); - Console.WriteLine(jsonString); - var settings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None }; - - dynamic json = JsonConvert.DeserializeObject(jsonString, settings); - - Assert.Equal("2018-01-01T00:00:00+00:00", (string)json["expirationDate"]); - Assert.Equal("2018-01-05T12:00:00-05:00", (string)json["relevantDate"]); - - var nfcPayload = (JToken)json["nfc"]; - var nfcMessage = (string)nfcPayload["message"]; - Assert.Equal("My NFC Message", nfcMessage); - - var genericKeys = json["generic"]; - Assert.Equal(3, genericKeys["auxiliaryFields"].Count); - - var auxField = genericKeys["auxiliaryFields"][0]; - - Assert.Equal("aux-1", (string)auxField["key"]); - Assert.Equal("Test", (string)auxField["value"]); - Assert.Equal("Label", (string)auxField["label"]); - Assert.Equal(1, (int)auxField["row"]); - - var datetimeField = genericKeys["auxiliaryFields"][1]; - Assert.Equal("datetime-1", (string)datetimeField["key"]); - string datetime1 = (string)datetimeField["value"]; - string expected1start = string.Format("{0:yyyy-MM-ddTHH:mm}", local); - - Assert.StartsWith(expected1start, datetime1); - Assert.DoesNotContain("Z", datetime1); - Assert.Equal("Label", (string)datetimeField["label"]); - - var utcdatetimeField = genericKeys["auxiliaryFields"][2]; - Assert.Equal("datetime-2", (string)utcdatetimeField["key"]); - string datetime2 = (string)utcdatetimeField["value"]; - string expected2 = string.Format("{0:yyyy-MM-ddTHH:mm:ss}Z", utc); - - Assert.Equal(expected2, datetime2); - Assert.Equal("Label", (string)utcdatetimeField["label"]); - } - } - } + Key = "datetime-1", + Value = local, + Label = "Label", + }); + + var utc = DateTime.UtcNow; + utc = new DateTime(utc.Year, utc.Month, utc.Day, utc.Hour, utc.Minute, utc.Second, utc.Kind); + request.AddAuxiliaryField(new DateField() + { + Key = "datetime-2", + Value = utc, + Label = "Label", + }); + + using var ms = new MemoryStream(); + var opts = new JsonWriterOptions { Indented = true }; + using (var writer = new Utf8JsonWriter(ms, opts)) + + request.Write(writer); + + string jsonString = Encoding.UTF8.GetString(ms.ToArray()); + Console.WriteLine(jsonString); + + dynamic json = JsonSerializer.Deserialize(jsonString)!; + + json.TryGetProperty("expirationDate", out JsonElement expirationDate); + Assert.Equal("2018-01-01T00:00:00+02:00", expirationDate.GetString()); + + json.TryGetProperty("relevantDate", out JsonElement relevantDate); + Assert.Equal("2018-01-05T12:00:00-05:00", relevantDate.GetString()); + + json.TryGetProperty("nfc", out JsonElement nfcPayload); + nfcPayload.TryGetProperty("message", out JsonElement nfcMessage); + Assert.Equal("My NFC Message", nfcMessage.GetString()); + + json.TryGetProperty("generic", out JsonElement genericKeys); + + genericKeys.TryGetProperty("auxiliaryFields", out JsonElement auxFields); + Assert.Equal(3, auxFields.EnumerateArray().Count()); + + var auxField = auxFields.EnumerateArray() + .ToArray()[0]; + + auxField.TryGetProperty("key", out JsonElement key); + Assert.Equal("aux-1", key.GetString()); + auxField.TryGetProperty("value", out JsonElement value); + Assert.Equal("Test", value.GetString()); + auxField.TryGetProperty("label", out JsonElement label); + Assert.Equal("Label", label.GetString()); + auxField.TryGetProperty("row", out JsonElement row); + Assert.Equal(1, row.GetInt32()); + + var dateTimeField = auxFields.EnumerateArray() + .ToArray()[1]; + + dateTimeField.TryGetProperty("key", out JsonElement datetimeKey); + Assert.Equal("datetime-1", datetimeKey.GetString()); + + dateTimeField.TryGetProperty("value", out JsonElement dateTimeValue); + string expected1start = string.Format("{0:yyyy-MM-ddTHH:mm}", local); + + Assert.StartsWith(expected1start, dateTimeValue.GetString()); + Assert.DoesNotContain("Z", dateTimeValue.GetString()); + + dateTimeField.TryGetProperty("label", out JsonElement dateTimeLabel); + Assert.Equal("Label", dateTimeLabel.GetString()); + + var utcDateTimeField = auxFields.EnumerateArray().ToArray()[2]; + + utcDateTimeField.TryGetProperty("key", out JsonElement utcDateTimeFieldKey); + Assert.Equal("datetime-2", utcDateTimeFieldKey.GetString()); + + utcDateTimeField.TryGetProperty("value", out JsonElement utcDateTimeFieldValue); + + string expected2 = string.Format("{0:yyyy-MM-ddTHH:mm:ss}Z", utc); + Assert.Equal(expected2, utcDateTimeFieldValue.GetString()); + + utcDateTimeField.TryGetProperty("label", out JsonElement utcDateTimeFieldLabel); + Assert.Equal("Label", utcDateTimeFieldLabel.GetString()); } } \ No newline at end of file diff --git a/Passbook.Generator.Tests/Passbook.Generator.Tests.csproj b/Passbook.Generator.Tests/Passbook.Generator.Tests.csproj index 068a199..cba27fe 100644 --- a/Passbook.Generator.Tests/Passbook.Generator.Tests.csproj +++ b/Passbook.Generator.Tests/Passbook.Generator.Tests.csproj @@ -1,29 +1,19 @@ - net48;netcoreapp3.1;net5.0;net6.0 - false + net8.0 + enable + true + enable - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + + + - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - \ No newline at end of file diff --git a/Passbook.Generator.Tests/SemanticTagsTests.cs b/Passbook.Generator.Tests/SemanticTagsTests.cs index e3df17e..542d9e8 100644 --- a/Passbook.Generator.Tests/SemanticTagsTests.cs +++ b/Passbook.Generator.Tests/SemanticTagsTests.cs @@ -1,46 +1,51 @@ -using Newtonsoft.Json; -using Passbook.Generator.Tags; +using Passbook.Generator.Tags; using System.IO; using System.Text; +using System.Text.Json; using Xunit; -namespace Passbook.Generator.Tests +namespace Passbook.Generator.Tests; + +public class SemanticTagsTests { - public class SemanticTagsTests + [Fact] + public void EnsureSemanticFieldsIsGeneratedCorrectly() { - [Fact] - public void EnsureSemanticFieldsIsGeneratedCorrectly() - { - PassGeneratorRequest request = new PassGeneratorRequest(); - request.SemanticTags.Add(new AirlineCode("EX")); - request.SemanticTags.Add(new Balance("1000", "GBP")); + PassGeneratorRequest request = new PassGeneratorRequest(); + request.SemanticTags.Add(new AirlineCode("EX")); + request.SemanticTags.Add(new Balance("1000", "GBP")); - using (MemoryStream ms = new MemoryStream()) - { - using (StreamWriter sr = new StreamWriter(ms)) - { - using (JsonWriter writer = new JsonTextWriter(sr)) - { - writer.Formatting = Formatting.Indented; - request.Write(writer); - } + using var ms = new MemoryStream(); + var options = new JsonWriterOptions { Indented = true }; + using (var writer = new Utf8JsonWriter(ms, options)) + + request.Write(writer); - string jsonString = Encoding.UTF8.GetString(ms.ToArray()); + string jsonString = Encoding.UTF8.GetString(ms.ToArray()); - var settings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None }; + using var doc = JsonDocument.Parse(jsonString); + var root = doc.RootElement; - dynamic json = JsonConvert.DeserializeObject(jsonString, settings); + if (!root.TryGetProperty("semantics", out JsonElement semantics)) + { + Assert.Fail("semantics not found"); + } - var semantics = json["semantics"]; + if (!semantics.TryGetProperty("airlineCode", out JsonElement airlineCode)) + { + Assert.Fail("airlineCode not found"); + } + Assert.Equal("EX", airlineCode.GetString()); - var airlineCode = semantics.airlineCode; - Assert.Equal("EX", (string)airlineCode); + if (!semantics.TryGetProperty("balance", out JsonElement balance)) + { + Assert.Fail("balance not found"); + } - var balance = semantics.balance; - Assert.Equal("1000", (string)balance.amount); - Assert.Equal("GBP", (string)balance.currencyCode); - } - } + if (!balance.TryGetProperty("amount", out JsonElement amount)) + { + Assert.Fail("amount not found"); } + Assert.Equal("1000", amount.GetString()); } } diff --git a/Passbook.Generator/Exceptions/DuplicateFieldKeyException.cs b/Passbook.Generator/Exceptions/DuplicateFieldKeyException.cs index 5dcc54c..99793de 100644 --- a/Passbook.Generator/Exceptions/DuplicateFieldKeyException.cs +++ b/Passbook.Generator/Exceptions/DuplicateFieldKeyException.cs @@ -1,11 +1,7 @@ using System; -namespace Passbook.Generator.Exceptions +namespace Passbook.Generator.Exceptions; + +public class DuplicateFieldKeyException(string key) : Exception($"A field with the key `{key}` is already present") { - public class DuplicateFieldKeyException : Exception - { - public DuplicateFieldKeyException(string key) : - base($"A field with the key `{key}` is already present") - { } - } } diff --git a/Passbook.Generator/Exceptions/ManifestSigningException.cs b/Passbook.Generator/Exceptions/ManifestSigningException.cs index d7ec73e..587b3c3 100644 --- a/Passbook.Generator/Exceptions/ManifestSigningException.cs +++ b/Passbook.Generator/Exceptions/ManifestSigningException.cs @@ -1,16 +1,11 @@ using System; -namespace Passbook.Generator.Exceptions +namespace Passbook.Generator.Exceptions; + +[Serializable] +public class ManifestSigningException : Exception { - [Serializable] - public class ManifestSigningException : Exception - { - public ManifestSigningException() { } - public ManifestSigningException(string message) : base(message) { } - public ManifestSigningException(string message, Exception inner) : base(message, inner) { } - protected ManifestSigningException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) - : base(info, context) { } - } + public ManifestSigningException() { } + public ManifestSigningException(string message) : base(message) { } + public ManifestSigningException(string message, Exception inner) : base(message, inner) { } } diff --git a/Passbook.Generator/Exceptions/RequiredFieldValueMissingException.cs b/Passbook.Generator/Exceptions/RequiredFieldValueMissingException.cs index 3233bf4..b5bcd08 100644 --- a/Passbook.Generator/Exceptions/RequiredFieldValueMissingException.cs +++ b/Passbook.Generator/Exceptions/RequiredFieldValueMissingException.cs @@ -1,12 +1,8 @@ using System; -namespace Passbook.Generator.Exceptions +namespace Passbook.Generator.Exceptions; + +[Serializable] +public class RequiredFieldValueMissingException(string fieldName) : Exception("Missing value for field [key: '" + fieldName + "']. Every field must have a value specified in the template or the individual pass.") { - [Serializable] - public class RequiredFieldValueMissingException : Exception - { - public RequiredFieldValueMissingException(string fieldName) : - base("Missing value for field [key: '" + fieldName + "']. Every field must have a value specified in the template or the individual pass.") - { } - } } diff --git a/Passbook.Generator/Extensions/DataDetectorTypeExtensions.cs b/Passbook.Generator/Extensions/DataDetectorTypeExtensions.cs index 03fa66b..b2f437f 100644 --- a/Passbook.Generator/Extensions/DataDetectorTypeExtensions.cs +++ b/Passbook.Generator/Extensions/DataDetectorTypeExtensions.cs @@ -1,26 +1,20 @@ using Passbook.Generator.Fields; -namespace Passbook.Generator +namespace Passbook.Generator; + +public static class DataDetectorTypeExtensions { - public static class DataDetectorTypeExtensions + // Dotfuscated friendly enum name conversion + // http://stackoverflow.com/questions/483794/convert-enum-to-string + public static string ToSafeString(this DataDetectorTypes dataDetectorType) { - // Dotfucated friendly enum name conversion - // http://stackoverflow.com/questions/483794/convert-enum-to-string - public static string ToSafeString(this DataDetectorTypes dataDetectorType) + return dataDetectorType switch { - switch (dataDetectorType) - { - case DataDetectorTypes.PKDataDetectorTypeAddress: - return "PKDataDetectorTypeAddress"; - case DataDetectorTypes.PKDataDetectorTypeCalendarEvent: - return "PKDataDetectorTypeCalendarEvent"; - case DataDetectorTypes.PKDataDetectorTypeLink: - return "PKDataDetectorTypeLink"; - case DataDetectorTypes.PKDataDetectorTypePhoneNumber: - return "PKDataDetectorTypePhoneNumber"; - default: - return ""; - } - } + DataDetectorTypes.PKDataDetectorTypeAddress => "PKDataDetectorTypeAddress", + DataDetectorTypes.PKDataDetectorTypeCalendarEvent => "PKDataDetectorTypeCalendarEvent", + DataDetectorTypes.PKDataDetectorTypeLink => "PKDataDetectorTypeLink", + DataDetectorTypes.PKDataDetectorTypePhoneNumber => "PKDataDetectorTypePhoneNumber", + _ => "", + }; } } diff --git a/Passbook.Generator/Fields/BarCode.cs b/Passbook.Generator/Fields/BarCode.cs index baaf705..a52fd19 100644 --- a/Passbook.Generator/Fields/BarCode.cs +++ b/Passbook.Generator/Fields/BarCode.cs @@ -1,61 +1,60 @@ -using Newtonsoft.Json; +using System.Text.Json; -namespace Passbook.Generator.Fields +namespace Passbook.Generator.Fields; + +public class Barcode { - public class Barcode + public Barcode(BarcodeType type, string message, string encoding) { - public Barcode(BarcodeType type, string message, string encoding) - { - Type = type; - Message = message; - Encoding = encoding; - } + Type = type; + Message = message; + Encoding = encoding; + } - public Barcode(BarcodeType type, string message, string encoding, string alternateText) - { - Type = type; - Message = message; - Encoding = encoding; - AlternateText = alternateText; - } + public Barcode(BarcodeType type, string message, string encoding, string alternateText) + { + Type = type; + Message = message; + Encoding = encoding; + AlternateText = alternateText; + } - /// - /// Required. Barcode format - /// - public BarcodeType Type { get; set; } + /// + /// Required. Barcode format + /// + public BarcodeType Type { get; set; } - /// - /// Required. Message or payload to be displayed as a barcode. - /// - public string Message { get; set; } + /// + /// Required. Message or payload to be displayed as a barcode. + /// + public string Message { get; set; } - /// - /// Required. Text encoding that is used to convert the message from the string representation to a data representation to render the barcode. The value is typically iso-8859-1, but you may use another encoding that is supported by your barcode scanning infrastructure. - /// - public string Encoding { get; set; } + /// + /// Required. Text encoding that is used to convert the message from the string representation to a data representation to render the barcode. The value is typically iso-8859-1, but you may use another encoding that is supported by your barcode scanning infrastructure. + /// + public string Encoding { get; set; } - /// - /// Optional. Text displayed near the barcode. For example, a human-readable version of the barcode data in case the barcode doesn’t scan. - /// - public string AlternateText { get; set; } + /// + /// Optional. Text displayed near the barcode. For example, a human-readable version of the barcode data in case the barcode doesn’t scan. + /// + public string AlternateText { get; set; } - public void Write(JsonWriter writer) + public void Write(Utf8JsonWriter writer) + { + writer.WriteStartObject(); + writer.WritePropertyName("format"); + writer.WriteStringValue(Type.ToString()); + writer.WritePropertyName("message"); + writer.WriteStringValue(Message); + writer.WritePropertyName("messageEncoding"); + writer.WriteStringValue(Encoding); + + if (!string.IsNullOrEmpty(AlternateText)) { - writer.WriteStartObject(); - writer.WritePropertyName("format"); - writer.WriteValue(Type.ToString()); - writer.WritePropertyName("message"); - writer.WriteValue(Message); - writer.WritePropertyName("messageEncoding"); - writer.WriteValue(Encoding); - - if (!string.IsNullOrEmpty(AlternateText)) - { - writer.WritePropertyName("altText"); - writer.WriteValue(AlternateText); - } - - writer.WriteEndObject(); + writer.WritePropertyName("altText"); + writer.WriteStringValue(AlternateText); } + + writer.WriteEndObject(); } } diff --git a/Passbook.Generator/Fields/DateField.cs b/Passbook.Generator/Fields/DateField.cs index e4e4e42..6b4725e 100644 --- a/Passbook.Generator/Fields/DateField.cs +++ b/Passbook.Generator/Fields/DateField.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Text.Json; namespace Passbook.Generator.Fields { @@ -12,16 +13,16 @@ public DateField() public DateField(string key, string label, FieldDateTimeStyle dateStyle, FieldDateTimeStyle timeStyle) : base(key, label) { - this.DateStyle = dateStyle; - this.TimeStyle = timeStyle; + DateStyle = dateStyle; + TimeStyle = timeStyle; } public DateField(string key, string label, FieldDateTimeStyle dateStyle, FieldDateTimeStyle timeStyle, DateTime value) : base(key, label) { - this.Value = value; - this.DateStyle = dateStyle; - this.TimeStyle = timeStyle; + Value = value; + DateStyle = dateStyle; + TimeStyle = timeStyle; } public DateTime Value { get; set; } @@ -46,44 +47,44 @@ public DateField(string key, string label, FieldDateTimeStyle dateStyle, FieldDa /// public bool? IgnoresTimeZone { get; set; } - protected override void WriteKeys(Newtonsoft.Json.JsonWriter writer) + protected override void WriteKeys(Utf8JsonWriter writer) { if (DateStyle != FieldDateTimeStyle.Unspecified) { writer.WritePropertyName("dateStyle"); - writer.WriteValue(DateStyle.ToString()); + writer.WriteStringValue(DateStyle.ToString()); } if (TimeStyle != FieldDateTimeStyle.Unspecified) { writer.WritePropertyName("timeStyle"); - writer.WriteValue(TimeStyle.ToString()); + writer.WriteStringValue(TimeStyle.ToString()); } if (IsRelative.HasValue) { writer.WritePropertyName("isRelative"); - writer.WriteValue(IsRelative.Value); + writer.WriteBooleanValue(IsRelative.Value); } if (IgnoresTimeZone.HasValue) { writer.WritePropertyName("ignoresTimeZone"); - writer.WriteValue(IgnoresTimeZone.Value); + writer.WriteBooleanValue(IgnoresTimeZone.Value); } } - protected override void WriteValue(Newtonsoft.Json.JsonWriter writer) + protected override void WriteValue(Utf8JsonWriter writer) { - if (this.Value.Kind == DateTimeKind.Utc || - this.Value.Kind == DateTimeKind.Unspecified) + if (Value.Kind == DateTimeKind.Utc || + Value.Kind == DateTimeKind.Unspecified) { - writer.WriteValue(Value.ToString("yyyy-MM-ddTHH:mm:ssZ")); + writer.WriteStringValue(Value.ToString("yyyy-MM-ddTHH:mm:ssZ")); } else { - var localDate = new DateTime(this.Value.Year, this.Value.Month, this.Value.Day, this.Value.Hour, this.Value.Minute, this.Value.Second, this.Value.Kind); - var utcDate = new DateTime(this.Value.Year, this.Value.Month, this.Value.Day, this.Value.Hour, this.Value.Minute, this.Value.Second, this.Value.Kind); + var localDate = new DateTime(Value.Year, Value.Month, Value.Day, Value.Hour, Value.Minute, Value.Second, Value.Kind); + var utcDate = new DateTime(Value.Year, Value.Month, Value.Day, Value.Hour, Value.Minute, Value.Second, Value.Kind); var diff = utcDate - localDate.ToUniversalTime(); string outputText = localDate.ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture); @@ -96,13 +97,13 @@ protected override void WriteValue(Newtonsoft.Json.JsonWriter writer) outputText = string.Format("{0}+{1:00}:{2:00}", outputText, Math.Abs(diff.Hours), diff.Minutes); } - writer.WriteValue(outputText); + writer.WriteStringValue(outputText); } } public override void SetValue(object value) { - this.Value = (DateTime)value; + Value = (DateTime)value; } public override bool HasValue diff --git a/Passbook.Generator/Fields/Field.cs b/Passbook.Generator/Fields/Field.cs index 0f865ec..0339ac7 100644 --- a/Passbook.Generator/Fields/Field.cs +++ b/Passbook.Generator/Fields/Field.cs @@ -1,6 +1,6 @@ -using Newtonsoft.Json; -using Passbook.Generator.Exceptions; +using Passbook.Generator.Exceptions; using System; +using System.Text.Json; namespace Passbook.Generator.Fields { @@ -8,21 +8,21 @@ public abstract class Field { public Field() { - this.DataDetectorTypes = DataDetectorTypes.PKDataDetectorAll; + DataDetectorTypes = DataDetectorTypes.PKDataDetectorAll; } public Field(string key, string label) : this() { - this.Key = key; - this.Label = label; + Key = key; + Label = label; } public Field(string key, string label, string changeMessage, FieldTextAlignment textAligment) : this(key, label) { - this.ChangeMessage = changeMessage; - this.TextAlignment = textAligment; + ChangeMessage = changeMessage; + TextAlignment = textAligment; } /// @@ -95,43 +95,43 @@ public Field(string key, string label, string changeMessage, FieldTextAlignment /// public int? Row { get; set; } - public void Write(JsonWriter writer) + public void Write(Utf8JsonWriter writer) { Validate(); writer.WriteStartObject(); writer.WritePropertyName("key"); - writer.WriteValue(Key); + writer.WriteStringValue(Key); if (!string.IsNullOrEmpty(ChangeMessage)) { writer.WritePropertyName("changeMessage"); - writer.WriteValue(ChangeMessage); + writer.WriteStringValue(ChangeMessage); } if (!string.IsNullOrEmpty(Label)) { writer.WritePropertyName("label"); - writer.WriteValue(Label); + writer.WriteStringValue(Label); } if (TextAlignment != FieldTextAlignment.Unspecified) { writer.WritePropertyName("textAlignment"); - writer.WriteValue(TextAlignment.ToString()); + writer.WriteStringValue(TextAlignment.ToString()); } if (!string.IsNullOrEmpty(AttributedValue)) { writer.WritePropertyName("attributedValue"); - writer.WriteValue(this.AttributedValue); + writer.WriteStringValue(AttributedValue); } if (Row.HasValue) { writer.WritePropertyName("row"); - writer.WriteValue(this.Row.Value); + writer.WriteNumberValue(Row.Value); } WriteKeys(writer); @@ -144,7 +144,7 @@ public void Write(JsonWriter writer) writer.WriteEndObject(); } - private void WriteDataDetectorTypes(JsonWriter writer) + private void WriteDataDetectorTypes(Utf8JsonWriter writer) { if (DataDetectorTypes != DataDetectorTypes.PKDataDetectorAll) { @@ -155,7 +155,7 @@ private void WriteDataDetectorTypes(JsonWriter writer) if (value.CompareTo(DataDetectorTypes.PKDataDetectorNone) != 0 && value.CompareTo(DataDetectorTypes.PKDataDetectorAll) != 0 && DataDetectorTypes.HasFlag(value)) - writer.WriteValue(value.ToString()); + writer.WriteStringValue(value.ToString()); writer.WriteEndArray(); } @@ -169,12 +169,12 @@ private void Validate() } } - protected virtual void WriteKeys(JsonWriter writer) + protected virtual void WriteKeys(Utf8JsonWriter writer) { // NO OP } - protected abstract void WriteValue(JsonWriter writer); + protected abstract void WriteValue(Utf8JsonWriter writer); public abstract void SetValue(object value); diff --git a/Passbook.Generator/Fields/NumberField.cs b/Passbook.Generator/Fields/NumberField.cs index 4161e2f..5726224 100644 --- a/Passbook.Generator/Fields/NumberField.cs +++ b/Passbook.Generator/Fields/NumberField.cs @@ -1,4 +1,6 @@ -namespace Passbook.Generator.Fields +using System.Text.Json; + +namespace Passbook.Generator.Fields { public class NumberField : Field { @@ -9,8 +11,8 @@ public NumberField() public NumberField(string key, string label, decimal value, FieldNumberStyle numberStyle) : base(key, label) { - this.Value = value; - this.NumberStyle = numberStyle; + Value = value; + NumberStyle = numberStyle; } public NumberField(string key, string label, int value, FieldNumberStyle numberStyle) @@ -30,29 +32,29 @@ public NumberField(string key, string label, int value, FieldNumberStyle numberS public decimal Value { get; set; } - protected override void WriteKeys(Newtonsoft.Json.JsonWriter writer) + protected override void WriteKeys(Utf8JsonWriter writer) { if (!string.IsNullOrEmpty(CurrencyCode)) { writer.WritePropertyName("currencyCode"); - writer.WriteValue(CurrencyCode); + writer.WriteStringValue(CurrencyCode); } if (NumberStyle != FieldNumberStyle.Unspecified) { writer.WritePropertyName("numberStyle"); - writer.WriteValue(NumberStyle.ToString()); + writer.WriteStringValue(NumberStyle.ToString()); } } - protected override void WriteValue(Newtonsoft.Json.JsonWriter writer) + protected override void WriteValue(Utf8JsonWriter writer) { - writer.WriteValue(Value); + writer.WriteNumberValue(Value); } public override void SetValue(object value) { - this.Value = (decimal)value; + Value = (decimal)value; } public override bool HasValue diff --git a/Passbook.Generator/NFC.cs b/Passbook.Generator/NFC.cs index 54feb1e..22d4e3a 100644 --- a/Passbook.Generator/NFC.cs +++ b/Passbook.Generator/NFC.cs @@ -1,15 +1,8 @@ -namespace Passbook.Generator -{ - public class Nfc - { - public Nfc(string message, string encryptionPublicKey) - { - Message = message; - EncryptionPublicKey = encryptionPublicKey; - } +namespace Passbook.Generator; - public string Message { get; } +public class Nfc(string message, string encryptionPublicKey) +{ + public string Message { get; } = message; - public string EncryptionPublicKey { get; } - } + public string EncryptionPublicKey { get; } = encryptionPublicKey; } diff --git a/Passbook.Generator/Pass.cs b/Passbook.Generator/Pass.cs index dec31cd..96f2eb4 100644 --- a/Passbook.Generator/Pass.cs +++ b/Passbook.Generator/Pass.cs @@ -1,25 +1,19 @@ using System.IO; -namespace Passbook.Generator -{ - public class Pass - { - private string packagePathAndName; +namespace Passbook.Generator; - public Pass(string packagePathAndName) - { - this.packagePathAndName = packagePathAndName; - } +public class Pass(string packagePathAndName) +{ + private string packagePathAndName = packagePathAndName; - public byte[] GetPackage() - { - byte[] contents = File.ReadAllBytes(packagePathAndName); - return contents; - } + public byte[] GetPackage() + { + byte[] contents = File.ReadAllBytes(packagePathAndName); + return contents; + } - public string PackageDirectory - { - get { return Path.GetDirectoryName(this.packagePathAndName); } - } + public string PackageDirectory + { + get { return Path.GetDirectoryName(packagePathAndName); } } } diff --git a/Passbook.Generator/PassGenerator.cs b/Passbook.Generator/PassGenerator.cs index 5da7b1d..a970d05 100644 --- a/Passbook.Generator/PassGenerator.cs +++ b/Passbook.Generator/PassGenerator.cs @@ -1,4 +1,3 @@ -using Newtonsoft.Json; using Passbook.Generator.Exceptions; using System; using System.Collections.Generic; @@ -10,345 +9,324 @@ using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Text.Json; using System.Text.RegularExpressions; -namespace Passbook.Generator +namespace Passbook.Generator; + +public class PassGenerator { - public class PassGenerator + private byte[] passFile = null; + private byte[] signatureFile = null; + private byte[] manifestFile = null; + private Dictionary localizationFiles = null; + private byte[] pkPassFile = null; + private byte[] pkPassBundle = null; + private const string passTypePrefix = "Pass Type ID: "; + + /// + /// Creates a byte array which contains one pkpass file + /// + /// + /// An instance of a PassGeneratorRequest + /// + /// A byte array which contains a zipped pkpass file. + /// + /// + public byte[] Generate(PassGeneratorRequest generatorRequest) { - private byte[] passFile = null; - private byte[] signatureFile = null; - private byte[] manifestFile = null; - private Dictionary localizationFiles = null; - private byte[] pkPassFile = null; - private byte[] pkPassBundle = null; - private const string passTypePrefix = "Pass Type ID: "; - - /// - /// Creates a byte array which contains one pkpass file - /// - /// - /// An instance of a PassGeneratorRequest - /// - /// A byte array which contains a zipped pkpass file. - /// - /// - public byte[] Generate(PassGeneratorRequest generatorRequest) + if (generatorRequest == null) { - if (generatorRequest == null) - { - throw new ArgumentNullException(nameof(generatorRequest), "You must pass an instance of PassGeneratorRequest"); - } + throw new ArgumentNullException(nameof(generatorRequest), "You must pass an instance of PassGeneratorRequest"); + } - CreatePackage(generatorRequest); - ZipPackage(generatorRequest); + CreatePackage(generatorRequest); + ZipPackage(generatorRequest); - return pkPassFile; - } + return pkPassFile; + } - /// - /// Creates a byte array that can contains a .pkpasses file for bundling multiple passes together - /// - /// - /// A list of PassGeneratorRequest objects - /// - /// - /// A byte array which contains a zipped pkpasses file. - /// - /// - /// - public byte[] Generate(IReadOnlyList generatorRequests) + /// + /// Creates a byte array that can contains a .pkpasses file for bundling multiple passes together + /// + /// + /// A list of PassGeneratorRequest objects + /// + /// + /// A byte array which contains a zipped pkpasses file. + /// + /// + /// + public byte[] Generate(IReadOnlyList generatorRequests) + { + if (generatorRequests == null) { - if (generatorRequests == null) - { - throw new ArgumentNullException(nameof(generatorRequests), "You must pass an instance of IReadOnlyList containing at least one PassGeneratorRequest"); - } + throw new ArgumentNullException(nameof(generatorRequests), "You must pass an instance of IReadOnlyList containing at least one PassGeneratorRequest"); + } - if (!generatorRequests.Any()) - { - throw new ArgumentException(nameof(generatorRequests), "The IReadOnlyList must contain at least one PassGeneratorRequest"); - } + if (!generatorRequests.Any()) + { + throw new ArgumentException(nameof(generatorRequests), "The IReadOnlyList must contain at least one PassGeneratorRequest"); + } - ZipBundle(generatorRequests); + ZipBundle(generatorRequests); - return pkPassBundle; - } + return pkPassBundle; + } - private void ZipBundle(IEnumerable generatorRequests) + private void ZipBundle(IEnumerable generatorRequests) + { + using (MemoryStream zipToOpen = new MemoryStream()) { - using (MemoryStream zipToOpen = new MemoryStream()) + using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create, true)) { - using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create, true)) - { - int i = 0; + int i = 0; - foreach (PassGeneratorRequest generatorRequest in generatorRequests) - { - ZipArchiveEntry zipEntry = archive.CreateEntry($"pass{i++}.pkpass"); + foreach (PassGeneratorRequest generatorRequest in generatorRequests) + { + ZipArchiveEntry zipEntry = archive.CreateEntry($"pass{i++}.pkpass"); - CreatePackage(generatorRequest); - ZipPackage(generatorRequest); + CreatePackage(generatorRequest); + ZipPackage(generatorRequest); - using (MemoryStream originalFileStream = new MemoryStream(pkPassFile)) + using (MemoryStream originalFileStream = new MemoryStream(pkPassFile)) + { + using (Stream zipEntryStream = zipEntry.Open()) { - using (Stream zipEntryStream = zipEntry.Open()) - { - originalFileStream.CopyTo(zipEntryStream); - } + originalFileStream.CopyTo(zipEntryStream); } } } + } - pkPassBundle = zipToOpen.ToArray(); + pkPassBundle = zipToOpen.ToArray(); - zipToOpen.Flush(); - } + zipToOpen.Flush(); } + } - private void ZipPackage(PassGeneratorRequest request) + private void ZipPackage(PassGeneratorRequest request) + { + using (MemoryStream zipToOpen = new MemoryStream()) { - using (MemoryStream zipToOpen = new MemoryStream()) + using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update, true)) { - using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update, true)) + foreach (KeyValuePair image in request.Images) { - foreach (KeyValuePair image in request.Images) - { - ZipArchiveEntry imageEntry = archive.CreateEntry(image.Key.ToFilename()); + ZipArchiveEntry imageEntry = archive.CreateEntry(image.Key.ToFilename()); - using (BinaryWriter writer = new BinaryWriter(imageEntry.Open())) - { - writer.Write(image.Value); - writer.Flush(); - } - } - - foreach (KeyValuePair localization in localizationFiles) + using (BinaryWriter writer = new BinaryWriter(imageEntry.Open())) { - ZipArchiveEntry localizationEntry = archive.CreateEntry(string.Format("{0}.lproj/pass.strings", localization.Key.ToLower())); - - using (BinaryWriter writer = new BinaryWriter(localizationEntry.Open())) - { - writer.Write(localization.Value); - writer.Flush(); - } - } - - ZipArchiveEntry PassJSONEntry = archive.CreateEntry(@"pass.json"); - using (BinaryWriter writer = new BinaryWriter(PassJSONEntry.Open())) - { - writer.Write(passFile); + writer.Write(image.Value); writer.Flush(); } + } - ZipArchiveEntry ManifestJSONEntry = archive.CreateEntry(@"manifest.json"); - using (BinaryWriter writer = new BinaryWriter(ManifestJSONEntry.Open())) - { - writer.Write(manifestFile); - writer.Flush(); - } + foreach (KeyValuePair localization in localizationFiles) + { + ZipArchiveEntry localizationEntry = archive.CreateEntry(string.Format("{0}.lproj/pass.strings", localization.Key.ToLower())); - ZipArchiveEntry SignatureEntry = archive.CreateEntry(@"signature"); - using (BinaryWriter writer = new BinaryWriter(SignatureEntry.Open())) + using (BinaryWriter writer = new BinaryWriter(localizationEntry.Open())) { - writer.Write(signatureFile); + writer.Write(localization.Value); writer.Flush(); } } - pkPassFile = zipToOpen.ToArray(); - zipToOpen.Flush(); + ZipArchiveEntry PassJSONEntry = archive.CreateEntry(@"pass.json"); + using (BinaryWriter writer = new BinaryWriter(PassJSONEntry.Open())) + { + writer.Write(passFile); + writer.Flush(); + } + + ZipArchiveEntry ManifestJSONEntry = archive.CreateEntry(@"manifest.json"); + using (BinaryWriter writer = new BinaryWriter(ManifestJSONEntry.Open())) + { + writer.Write(manifestFile); + writer.Flush(); + } + + ZipArchiveEntry SignatureEntry = archive.CreateEntry(@"signature"); + using (BinaryWriter writer = new BinaryWriter(SignatureEntry.Open())) + { + writer.Write(signatureFile); + writer.Flush(); + } } + + pkPassFile = zipToOpen.ToArray(); + zipToOpen.Flush(); } + } - private void CreatePackage(PassGeneratorRequest request) + private void CreatePackage(PassGeneratorRequest request) + { + ValidateCertificates(request); + CreatePassFile(request); + GenerateLocalizationFiles(request); + GenerateManifestFile(request); + } + + private void ValidateCertificates(PassGeneratorRequest request) + { + if (request.PassbookCertificate == null) { - ValidateCertificates(request); - CreatePassFile(request); - GenerateLocalizationFiles(request); - GenerateManifestFile(request); + throw new FileNotFoundException("Certificate could not be found. Please ensure the thumbprint and cert location values are correct."); } - private void ValidateCertificates(PassGeneratorRequest request) + if (request.AppleWWDRCACertificate == null) { - if (request.PassbookCertificate == null) - { - throw new FileNotFoundException("Certificate could not be found. Please ensure the thumbprint and cert location values are correct."); - } + throw new FileNotFoundException("Apple Certificate could not be found. Please download it from http://www.apple.com/certificateauthority/ and install it into your PERSONAL or LOCAL MACHINE certificate store."); + } - if (request.AppleWWDRCACertificate == null) - { - throw new FileNotFoundException("Apple Certificate could not be found. Please download it from http://www.apple.com/certificateauthority/ and install it into your PERSONAL or LOCAL MACHINE certificate store."); - } + string passTypeIdentifier = request.PassbookCertificate.GetNameInfo(X509NameType.SimpleName, false); - string passTypeIdentifier = request.PassbookCertificate.GetNameInfo(X509NameType.SimpleName, false); + if (passTypeIdentifier.StartsWith(passTypePrefix, StringComparison.OrdinalIgnoreCase)) + { + passTypeIdentifier = passTypeIdentifier.Substring(passTypePrefix.Length); - if (passTypeIdentifier.StartsWith(passTypePrefix, StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrEmpty(passTypeIdentifier) && !string.Equals(request.PassTypeIdentifier, passTypeIdentifier, StringComparison.Ordinal)) { - passTypeIdentifier = passTypeIdentifier.Substring(passTypePrefix.Length); - - if (!string.IsNullOrEmpty(passTypeIdentifier) && !string.Equals(request.PassTypeIdentifier, passTypeIdentifier, StringComparison.Ordinal)) + if (!string.IsNullOrEmpty(request.PassTypeIdentifier)) { - if (!string.IsNullOrEmpty(request.PassTypeIdentifier)) - { - Trace.TraceWarning("Configured passTypeIdentifier {0} does not match pass certificate {1}, correcting.", request.PassTypeIdentifier, passTypeIdentifier); - } - - request.PassTypeIdentifier = passTypeIdentifier; + Trace.TraceWarning("Configured passTypeIdentifier {0} does not match pass certificate {1}, correcting.", request.PassTypeIdentifier, passTypeIdentifier); } - } - - Dictionary nameParts = - Regex.Matches(request.PassbookCertificate.SubjectName.Name, @"(?[^=,\s]+)\=*(?("".+""|[^,])+)") - .Cast() - .ToDictionary( - m => m.Groups["key"].Value, - m => m.Groups["value"].Value); - string teamIdentifier; - - if (nameParts.TryGetValue("OU", out teamIdentifier)) - { - if (!string.IsNullOrEmpty(teamIdentifier) && !string.Equals(request.TeamIdentifier, teamIdentifier, StringComparison.Ordinal)) - { - if (!string.IsNullOrEmpty(request.TeamIdentifier)) - { - Trace.TraceWarning("Configured teamidentifier {0} does not match pass certificate {1}, correcting.", request.TeamIdentifier, teamIdentifier); - } - - request.TeamIdentifier = teamIdentifier; - } + request.PassTypeIdentifier = passTypeIdentifier; } } - private void CreatePassFile(PassGeneratorRequest request) - { - using (MemoryStream ms = new MemoryStream()) - { - using (StreamWriter sr = new StreamWriter(ms)) - { - using (JsonWriter writer = new JsonTextWriter(sr)) - { - writer.Formatting = Formatting.Indented; - - Trace.TraceInformation("Writing JSON..."); - request.Write(writer); - } + Dictionary nameParts = + Regex.Matches(request.PassbookCertificate.SubjectName.Name, @"(?[^=,\s]+)\=*(?("".+""|[^,])+)") + .Cast() + .ToDictionary( + m => m.Groups["key"].Value, + m => m.Groups["value"].Value); - passFile = ms.ToArray(); - } - } - } + string teamIdentifier; - private void GenerateLocalizationFiles(PassGeneratorRequest request) + if (nameParts.TryGetValue("OU", out teamIdentifier)) { - localizationFiles = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (KeyValuePair> localization in request.Localizations) + if (!string.IsNullOrEmpty(teamIdentifier) && !string.Equals(request.TeamIdentifier, teamIdentifier, StringComparison.Ordinal)) { - using (MemoryStream ms = new MemoryStream()) + if (!string.IsNullOrEmpty(request.TeamIdentifier)) { - using (StreamWriter sr = new StreamWriter(ms, Encoding.UTF8)) - { - foreach (KeyValuePair value in localization.Value) - { - sr.WriteLine("\"{0}\" = \"{1}\";\n", value.Key, value.Value); - } - - sr.Flush(); - localizationFiles.Add(localization.Key, ms.ToArray()); - } + Trace.TraceWarning("Configured teamidentifier {0} does not match pass certificate {1}, correcting.", request.TeamIdentifier, teamIdentifier); } + + request.TeamIdentifier = teamIdentifier; } } + } + + private void CreatePassFile(PassGeneratorRequest request) + { + using var ms = new MemoryStream(); + var options = new JsonWriterOptions {Indented = true}; + var writer = new Utf8JsonWriter(ms, options); + + Trace.TraceInformation("Writing JSON..."); + request.Write(writer); + + passFile = ms.ToArray(); + } + + private void GenerateLocalizationFiles(PassGeneratorRequest request) + { + localizationFiles = new Dictionary(StringComparer.OrdinalIgnoreCase); - private void GenerateManifestFile(PassGeneratorRequest request) + foreach (KeyValuePair> localization in request.Localizations) { - using (MemoryStream ms = new MemoryStream()) + using var ms = new MemoryStream(); + using var sr = new StreamWriter(ms, Encoding.UTF8); + foreach (KeyValuePair value in localization.Value) { - using (StreamWriter sw = new StreamWriter(ms)) - { - using (JsonWriter jsonWriter = new JsonTextWriter(sw)) - { - jsonWriter.Formatting = Formatting.Indented; - jsonWriter.WriteStartObject(); - - string hash = null; + sr.WriteLine("\"{0}\" = \"{1}\";\n", value.Key, value.Value); + } - hash = GetHashForBytes(passFile); - jsonWriter.WritePropertyName(@"pass.json"); - jsonWriter.WriteValue(hash); + sr.Flush(); + localizationFiles.Add(localization.Key, ms.ToArray()); + } + } - foreach (KeyValuePair image in request.Images) - { - try - { - hash = GetHashForBytes(image.Value); - jsonWriter.WritePropertyName(image.Key.ToFilename()); - jsonWriter.WriteValue(hash); - } - catch (Exception exception) - { - throw new Exception($"Unexpect error writing image on manifest file. Image Key: \"{image.Key}\"", exception); - } - } + private void GenerateManifestFile(PassGeneratorRequest request) + { + using var ms = new MemoryStream(); + var options = new JsonWriterOptions {Indented = true}; + var jsonWriter = new Utf8JsonWriter(ms, options); + jsonWriter.WriteStartObject(); - foreach (KeyValuePair localization in localizationFiles) - { - hash = GetHashForBytes(localization.Value); - jsonWriter.WritePropertyName(string.Format("{0}.lproj/pass.strings", localization.Key.ToLower())); - jsonWriter.WriteValue(hash); - } - } + string hash = null; - manifestFile = ms.ToArray(); - } + hash = GetHashForBytes(passFile); + jsonWriter.WritePropertyName(@"pass.json"); + jsonWriter.WriteStringValue(hash); - SignManifestFile(request); + foreach (KeyValuePair image in request.Images) + { + try + { + hash = GetHashForBytes(image.Value); + jsonWriter.WritePropertyName(image.Key.ToFilename()); + jsonWriter.WriteStringValue(hash); + } + catch (Exception exception) + { + throw new Exception($"Unexpect error writing image on manifest file. Image Key: \"{image.Key}\"", exception); } } - private void SignManifestFile(PassGeneratorRequest request) + foreach (KeyValuePair localization in localizationFiles) { - Trace.TraceInformation("Signing the manifest file..."); + hash = GetHashForBytes(localization.Value); + jsonWriter.WritePropertyName(string.Format("{0}.lproj/pass.strings", localization.Key.ToLower())); + jsonWriter.WriteStringValue(hash); + } + manifestFile = ms.ToArray(); - try - { - ContentInfo contentInfo = new ContentInfo(manifestFile); + SignManifestFile(request); + } - SignedCms signing = new SignedCms(contentInfo, true); + private void SignManifestFile(PassGeneratorRequest request) + { + Trace.TraceInformation("Signing the manifest file..."); - CmsSigner signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, request.PassbookCertificate) - { - IncludeOption = X509IncludeOption.None - }; + try + { + ContentInfo contentInfo = new ContentInfo(manifestFile); - Trace.TraceInformation("Fetching Apple Certificate for signing.."); - Trace.TraceInformation("Constructing the certificate chain.."); - signer.Certificates.Add(request.AppleWWDRCACertificate); - signer.Certificates.Add(request.PassbookCertificate); + SignedCms signing = new SignedCms(contentInfo, true); - signer.SignedAttributes.Add(new Pkcs9SigningTime()); + CmsSigner signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, request.PassbookCertificate) + { + IncludeOption = X509IncludeOption.None + }; - Trace.TraceInformation("Processing the signature.."); - signing.ComputeSignature(signer); + Trace.TraceInformation("Fetching Apple Certificate for signing.."); + Trace.TraceInformation("Constructing the certificate chain.."); + signer.Certificates.Add(request.AppleWWDRCACertificate); + signer.Certificates.Add(request.PassbookCertificate); - signatureFile = signing.Encode(); + signer.SignedAttributes.Add(new Pkcs9SigningTime()); - Trace.TraceInformation("The file has been successfully signed!"); - } - catch (Exception exp) - { - Trace.TraceError("Failed to sign the manifest file: [{0}]", exp.Message); - throw new ManifestSigningException("Failed to sign manifest", exp); - } - } + Trace.TraceInformation("Processing the signature.."); + signing.ComputeSignature(signer); + + signatureFile = signing.Encode(); - private string GetHashForBytes(byte[] bytes) + Trace.TraceInformation("The file has been successfully signed!"); + } + catch (Exception exp) { - using (SHA1CryptoServiceProvider hasher = new SHA1CryptoServiceProvider()) - { - return BitConverter.ToString(hasher.ComputeHash(bytes)).Replace("-", string.Empty).ToLower(); - } + Trace.TraceError("Failed to sign the manifest file: [{0}]", exp.Message); + throw new ManifestSigningException("Failed to sign manifest", exp); } } + + private string GetHashForBytes(byte[] bytes) + { + using SHA1 hasher = SHA1.Create(); + return BitConverter.ToString(hasher.ComputeHash(bytes)).Replace("-", string.Empty).ToLower(); + } } diff --git a/Passbook.Generator/PassGeneratorRequest.cs b/Passbook.Generator/PassGeneratorRequest.cs index 095ebd2..a64346b 100644 --- a/Passbook.Generator/PassGeneratorRequest.cs +++ b/Passbook.Generator/PassGeneratorRequest.cs @@ -1,4 +1,3 @@ -using Newtonsoft.Json; using Passbook.Generator.Exceptions; using Passbook.Generator.Fields; using System; @@ -7,673 +6,675 @@ using System.Globalization; using System.Linq; using System.Security.Cryptography.X509Certificates; +using System.Text.Json; +using System.Text.Json.Serialization; -namespace Passbook.Generator +namespace Passbook.Generator; + +public class PassGeneratorRequest { - public class PassGeneratorRequest + public PassGeneratorRequest() { - public PassGeneratorRequest() - { - SemanticTags = new SemanticTags(); - HeaderFields = new List(); - PrimaryFields = new List(); - SecondaryFields = new List(); - AuxiliaryFields = new List(); - BackFields = new List(); - Images = new Dictionary(); - RelevantLocations = new List(); - RelevantBeacons = new List(); - AssociatedStoreIdentifiers = new List(); - Localizations = new Dictionary>(StringComparer.OrdinalIgnoreCase); - Barcodes = new List(); - UserInfo = new Dictionary(); - } - - #region Standard Keys + SemanticTags = []; + HeaderFields = []; + PrimaryFields = []; + SecondaryFields = []; + AuxiliaryFields = []; + BackFields = []; + Images = []; + RelevantLocations = []; + RelevantBeacons = []; + AssociatedStoreIdentifiers = []; + Localizations = new Dictionary>(StringComparer.OrdinalIgnoreCase); + Barcodes = []; + UserInfo = new Dictionary(); + } - /// - /// Required. Pass type identifier, as issued by Apple. The value must correspond with your signing certificate. - /// - public string PassTypeIdentifier { get; set; } + #region Standard Keys - /// - /// Required. Version of the file format. The value must be 1. - /// - public int FormatVersion { get { return 1; } } + /// + /// Required. Pass type identifier, as issued by Apple. The value must correspond with your signing certificate. + /// + public string PassTypeIdentifier { get; set; } - /// - /// Required. Serial number that uniquely identifies the pass. No two passes with the same pass type identifier may have the same serial number. - /// - public string SerialNumber { get; set; } + /// + /// Required. Version of the file format. The value must be 1. + /// + public int FormatVersion { get { return 1; } } - /// - /// Required. A simple description of the pass - /// - public string Description { get; set; } + /// + /// Required. Serial number that uniquely identifies the pass. No two passes with the same pass type identifier may have the same serial number. + /// + public string SerialNumber { get; set; } - /// - /// Required. Team identifier of the organization that originated and signed the pass, as issued by Apple. - /// - public string TeamIdentifier { get; set; } + /// + /// Required. A simple description of the pass + /// + public string Description { get; set; } - /// - /// Required. Display name of the organization that originated and signed the pass. - /// - public string OrganizationName { get; set; } + /// + /// Required. Team identifier of the organization that originated and signed the pass, as issued by Apple. + /// + public string TeamIdentifier { get; set; } - /// - /// Disables sharing of the pass. - /// - public bool SharingProhibited { get; set; } + /// + /// Required. Display name of the organization that originated and signed the pass. + /// + public string OrganizationName { get; set; } - #endregion + /// + /// Disables sharing of the pass. + /// + public bool SharingProhibited { get; set; } - #region Images Files + #endregion - /// - /// When using in memory, the binary of each image is put here. - /// - public Dictionary Images { get; set; } + #region Images Files - #endregion + /// + /// When using in memory, the binary of each image is put here. + /// + public Dictionary Images { get; set; } - #region Companion App Keys + #endregion - #endregion + #region Companion App Keys - #region Expiration Keys + #endregion - public DateTimeOffset? ExpirationDate { get; set; } + #region Expiration Keys - public Boolean? Voided { get; set; } + public DateTimeOffset? ExpirationDate { get; set; } - #endregion + public bool? Voided { get; set; } - #region Visual Appearance Keys + #endregion - /// - /// Optional. Foreground color of the pass, specified as a CSS-style RGB triple. For example, rgb(100, 10, 110). - /// - public string ForegroundColor { get; set; } + #region Visual Appearance Keys - /// - /// Optional. Background color of the pass, specified as an CSS-style RGB triple. For example, rgb(23, 187, 82). - /// - public string BackgroundColor { get; set; } + /// + /// Optional. Foreground color of the pass, specified as a CSS-style RGB triple. For example, rgb(100, 10, 110). + /// + public string ForegroundColor { get; set; } - /// - /// Optional. Color of the label text, specified as a CSS-style RGB triple. For example, rgb(255, 255, 255). - /// If omitted, the label color is determined automatically. - /// - public string LabelColor { get; set; } + /// + /// Optional. Background color of the pass, specified as an CSS-style RGB triple. For example, rgb(23, 187, 82). + /// + public string BackgroundColor { get; set; } - /// - /// Optional. Text displayed next to the logo on the pass. - /// - public string LogoText { get; set; } + /// + /// Optional. Color of the label text, specified as a CSS-style RGB triple. For example, rgb(255, 255, 255). + /// If omitted, the label color is determined automatically. + /// + public string LabelColor { get; set; } - /// - /// Optional. If true, the strip image is displayed without a shine effect. The default value is false. - /// - public bool? SuppressStripShine { get; set; } + /// + /// Optional. Text displayed next to the logo on the pass. + /// + public string LogoText { get; set; } - /// - /// Optional. The semantic tags to add to the pass. Read more about them here https://developer.apple.com/documentation/walletpasses/semantictags - /// - public SemanticTags SemanticTags { get; } + /// + /// Optional. If true, the strip image is displayed without a shine effect. The default value is false. + /// + public bool? SuppressStripShine { get; set; } - /// - /// Optional. Fields to be displayed prominently on the front of the pass. - /// - public List HeaderFields { get; private set; } + /// + /// Optional. The semantic tags to add to the pass. Read more about them here https://developer.apple.com/documentation/walletpasses/semantictags + /// + public SemanticTags SemanticTags { get; } - /// - /// Optional. Fields to be displayed prominently on the front of the pass. - /// - public List PrimaryFields { get; private set; } + /// + /// Optional. Fields to be displayed prominently on the front of the pass. + /// + public List HeaderFields { get; private set; } - /// - /// Optional. Fields to be displayed on the front of the pass. - /// - public List SecondaryFields { get; private set; } + /// + /// Optional. Fields to be displayed prominently on the front of the pass. + /// + public List PrimaryFields { get; private set; } - /// - /// Optional. Additional fields to be displayed on the front of the pass. - /// - public List AuxiliaryFields { get; private set; } + /// + /// Optional. Fields to be displayed on the front of the pass. + /// + public List SecondaryFields { get; private set; } - /// - /// Optional. Information about fields that are displayed on the back of the pass. - /// - public List BackFields { get; private set; } + /// + /// Optional. Additional fields to be displayed on the front of the pass. + /// + public List AuxiliaryFields { get; private set; } - /// - /// Optional. Information specific to barcodes. - /// - public Barcode Barcode { get; private set; } + /// + /// Optional. Information about fields that are displayed on the back of the pass. + /// + public List BackFields { get; private set; } - /// - /// Required. Pass type. - /// - public PassStyle Style { get; set; } + /// + /// Optional. Information specific to barcodes. + /// + public Barcode Barcode { get; private set; } - /// - /// Required for boarding passes; otherwise not allowed. Type of transit. - /// - public TransitType TransitType { get; set; } + /// + /// Required. Pass type. + /// + public PassStyle Style { get; set; } - /// - /// Optional for event tickets and boarding passes; otherwise not allowed. Identifier used to group related passes - /// - public string GroupingIdentifier { get; set; } + /// + /// Required for boarding passes; otherwise not allowed. Type of transit. + /// + public TransitType TransitType { get; set; } - #endregion + /// + /// Optional for event tickets and boarding passes; otherwise not allowed. Identifier used to group related passes + /// + public string GroupingIdentifier { get; set; } - #region Relevance Keys + #endregion - /// - /// Optional. Date and time when the pass becomes relevant. For example, the start time of a movie. - /// - public DateTimeOffset? RelevantDate { get; set; } + #region Relevance Keys - /// - /// Optional. Locations where the passisrelevant. For example, the location of your store. - /// - public List RelevantLocations { get; private set; } + /// + /// Optional. Date and time when the pass becomes relevant. For example, the start time of a movie. + /// + public DateTimeOffset? RelevantDate { get; set; } - /// - /// Optional. Beacons marking locations where the pass is relevant. - /// - public List RelevantBeacons { get; private set; } + /// + /// Optional. Locations where the passisrelevant. For example, the location of your store. + /// + public List RelevantLocations { get; private set; } - /// - /// Optional. Maximum distance in meters from a relevant latitude and longitude that the pass is relevant - /// - public int? MaxDistance { get; set; } + /// + /// Optional. Beacons marking locations where the pass is relevant. + /// + public List RelevantBeacons { get; private set; } - #endregion + /// + /// Optional. Maximum distance in meters from a relevant latitude and longitude that the pass is relevant + /// + public int? MaxDistance { get; set; } - #region Certificates + #endregion - /// - /// A byte array containing the PassKit certificate - /// - public X509Certificate2 PassbookCertificate { get; set; } + #region Certificates - /// - /// A byte array containing the Apple WWDRCA X509 certificate - /// - public X509Certificate2 AppleWWDRCACertificate { get; set; } + /// + /// A byte array containing the PassKit certificate + /// + public X509Certificate2 PassbookCertificate { get; set; } - #endregion + /// + /// A byte array containing the Apple WWDRCA X509 certificate + /// + public X509Certificate2 AppleWWDRCACertificate { get; set; } - #region Web Service Keys + #endregion - /// - /// The authentication token to use with the web service. - /// - public string AuthenticationToken { get; set; } - /// - /// The URL of a web service that conforms to the API described in Pass Kit Web Service Reference. - /// The web service must use the HTTPS protocol and includes the leading https://. - /// On devices configured for development, there is UI in Settings to allow HTTP web services. - /// - public string WebServiceUrl { get; set; } + #region Web Service Keys - #endregion + /// + /// The authentication token to use with the web service. + /// + public string AuthenticationToken { get; set; } + /// + /// The URL of a web service that conforms to the API described in Pass Kit Web Service Reference. + /// The web service must use the HTTPS protocol and includes the leading https://. + /// On devices configured for development, there is UI in Settings to allow HTTP web services. + /// + public string WebServiceUrl { get; set; } - #region Associated App Keys + #endregion - public List AssociatedStoreIdentifiers { get; set; } + #region Associated App Keys - public string AppLaunchURL { get; set; } + public List AssociatedStoreIdentifiers { get; set; } - #endregion + public string AppLaunchURL { get; set; } - #region Barcodes + #endregion - public List Barcodes { get; private set; } + #region Barcodes - #endregion + public List Barcodes { get; private set; } - #region User Info Keys + #endregion - public IDictionary UserInfo { get; set; } + #region User Info Keys - #endregion + public IDictionary UserInfo { get; set; } - #region Localization - public Dictionary> Localizations { get; set; } - #endregion + #endregion - #region NFC + #region Localization + public Dictionary> Localizations { get; set; } + #endregion - public Nfc Nfc { get; set; } + #region NFC - #endregion + public Nfc Nfc { get; set; } - #region Helpers and Serialization + #endregion - public void AddHeaderField(Field field) - { - EnsureFieldKeyIsUnique(field.Key); - HeaderFields.Add(field); - } + #region Helpers and Serialization - public void AddPrimaryField(Field field) - { - EnsureFieldKeyIsUnique(field.Key); - PrimaryFields.Add(field); - } - - public void AddSecondaryField(Field field) - { - EnsureFieldKeyIsUnique(field.Key); - SecondaryFields.Add(field); - } + public void AddHeaderField(Field field) + { + EnsureFieldKeyIsUnique(field.Key); + HeaderFields.Add(field); + } - public void AddAuxiliaryField(Field field) - { - EnsureFieldKeyIsUnique(field.Key); - AuxiliaryFields.Add(field); - } + public void AddPrimaryField(Field field) + { + EnsureFieldKeyIsUnique(field.Key); + PrimaryFields.Add(field); + } - public void AddBackField(Field field) - { - EnsureFieldKeyIsUnique(field.Key); - BackFields.Add(field); - } + public void AddSecondaryField(Field field) + { + EnsureFieldKeyIsUnique(field.Key); + SecondaryFields.Add(field); + } - private void EnsureFieldKeyIsUnique(string key) - { - if (HeaderFields.Any(x => x.Key == key) || - PrimaryFields.Any(x => x.Key == key) || - SecondaryFields.Any(x => x.Key == key) || - AuxiliaryFields.Any(x => x.Key == key) || - BackFields.Any(x => x.Key == key)) - { - throw new DuplicateFieldKeyException(key); - } - } + public void AddAuxiliaryField(Field field) + { + EnsureFieldKeyIsUnique(field.Key); + AuxiliaryFields.Add(field); + } - public void AddBarcode(BarcodeType type, string message, string encoding, string alternateText) - { - Barcodes.Add(new Barcode(type, message, encoding, alternateText)); - } + public void AddBackField(Field field) + { + EnsureFieldKeyIsUnique(field.Key); + BackFields.Add(field); + } - public void AddBarcode(BarcodeType type, string message, string encoding) + private void EnsureFieldKeyIsUnique(string key) + { + if (HeaderFields.Any(x => x.Key == key) || + PrimaryFields.Any(x => x.Key == key) || + SecondaryFields.Any(x => x.Key == key) || + AuxiliaryFields.Any(x => x.Key == key) || + BackFields.Any(x => x.Key == key)) { - Barcodes.Add(new Barcode(type, message, encoding)); + throw new DuplicateFieldKeyException(key); } + } - public void SetBarcode(BarcodeType type, string message, string encoding, string alternateText = null) - { - Barcode = new Barcode(type, message, encoding, alternateText); - } + public void AddBarcode(BarcodeType type, string message, string encoding, string alternateText) + { + Barcodes.Add(new Barcode(type, message, encoding, alternateText)); + } - public void AddLocation(double latitude, double longitude) - { - AddLocation(latitude, longitude, null); - } + public void AddBarcode(BarcodeType type, string message, string encoding) + { + Barcodes.Add(new Barcode(type, message, encoding)); + } - public void AddLocation(double latitude, double longitude, string relevantText) - { - RelevantLocations.Add(new RelevantLocation() { Latitude = latitude, Longitude = longitude, RelevantText = relevantText }); - } + public void SetBarcode(BarcodeType type, string message, string encoding, string alternateText = null) + { + Barcode = new Barcode(type, message, encoding, alternateText); + } - public void AddBeacon(string proximityUUID, string relevantText) - { - RelevantBeacons.Add(new RelevantBeacon() { ProximityUUID = proximityUUID, RelevantText = relevantText }); - } + public void AddLocation(double latitude, double longitude) + { + AddLocation(latitude, longitude, null); + } - public void AddBeacon(string proximityUUID, string relevantText, int major) - { - RelevantBeacons.Add(new RelevantBeacon() { ProximityUUID = proximityUUID, RelevantText = relevantText, Major = major }); - } + public void AddLocation(double latitude, double longitude, string relevantText) + { + RelevantLocations.Add(new RelevantLocation() { Latitude = latitude, Longitude = longitude, RelevantText = relevantText }); + } - public void AddBeacon(string proximityUUID, string relevantText, int major, int minor) - { - RelevantBeacons.Add(new RelevantBeacon() { ProximityUUID = proximityUUID, RelevantText = relevantText, Major = major, Minor = minor }); - } + public void AddBeacon(string proximityUUID, string relevantText) + { + RelevantBeacons.Add(new RelevantBeacon() { ProximityUUID = proximityUUID, RelevantText = relevantText }); + } - public void AddLocalization(string languageCode, string key, string value) - { - Dictionary values; + public void AddBeacon(string proximityUUID, string relevantText, int major) + { + RelevantBeacons.Add(new RelevantBeacon() { ProximityUUID = proximityUUID, RelevantText = relevantText, Major = major }); + } - if (!Localizations.TryGetValue(languageCode, out values)) - { - values = new Dictionary(StringComparer.OrdinalIgnoreCase); - Localizations.Add(languageCode, values); - } + public void AddBeacon(string proximityUUID, string relevantText, int major, int minor) + { + RelevantBeacons.Add(new RelevantBeacon() { ProximityUUID = proximityUUID, RelevantText = relevantText, Major = major, Minor = minor }); + } - values[key] = value; - } + public void AddLocalization(string languageCode, string key, string value) + { + Dictionary values; - public virtual void PopulateFields() + if (!Localizations.TryGetValue(languageCode, out values)) { - // NO OP. + values = new Dictionary(StringComparer.OrdinalIgnoreCase); + Localizations.Add(languageCode, values); } - public void Write(JsonWriter writer) - { - PopulateFields(); - - writer.WriteStartObject(); - - Trace.TraceInformation("Writing semantics.."); - WriteSemantics(writer); - Trace.TraceInformation("Writing standard keys.."); - WriteStandardKeys(writer); - Trace.TraceInformation("Writing user information.."); - WriteUserInfo(writer); - Trace.TraceInformation("Writing relevance keys.."); - WriteRelevanceKeys(writer); - Trace.TraceInformation("Writing appearance keys.."); - WriteAppearanceKeys(writer); - Trace.TraceInformation("Writing expiration keys.."); - WriteExpirationKeys(writer); - Trace.TraceInformation("Writing barcode keys.."); - WriteBarcodes(writer); - - if (Nfc != null) - { - Trace.TraceInformation("Writing NFC fields"); - WriteNfcKeys(writer); - } + values[key] = value; + } - Trace.TraceInformation("Opening style section.."); - OpenStyleSpecificKey(writer); - - Trace.TraceInformation("Writing header fields"); - WriteSection(writer, "headerFields", this.HeaderFields); - Trace.TraceInformation("Writing primary fields"); - WriteSection(writer, "primaryFields", this.PrimaryFields); - Trace.TraceInformation("Writing secondary fields"); - WriteSection(writer, "secondaryFields", this.SecondaryFields); - Trace.TraceInformation("Writing auxiliary fields"); - WriteSection(writer, "auxiliaryFields", this.AuxiliaryFields); - Trace.TraceInformation("Writing back fields"); - WriteSection(writer, "backFields", this.BackFields); - - if (this.Style == PassStyle.BoardingPass) - { - writer.WritePropertyName("transitType"); - writer.WriteValue(this.TransitType.ToString()); - } + public virtual void PopulateFields() + { + // NO OP. + } - Trace.TraceInformation("Closing style section.."); - CloseStyleSpecificKey(writer); + public void Write(Utf8JsonWriter writer) + { + PopulateFields(); - WriteBarcode(writer); - WriteUrls(writer); + writer.WriteStartObject(); - writer.WriteEndObject(); - } + Trace.TraceInformation("Writing semantics.."); + WriteSemantics(writer); + Trace.TraceInformation("Writing standard keys.."); + WriteStandardKeys(writer); + Trace.TraceInformation("Writing user information.."); + WriteUserInfo(writer); + Trace.TraceInformation("Writing relevance keys.."); + WriteRelevanceKeys(writer); + Trace.TraceInformation("Writing appearance keys.."); + WriteAppearanceKeys(writer); + Trace.TraceInformation("Writing expiration keys.."); + WriteExpirationKeys(writer); + Trace.TraceInformation("Writing barcode keys.."); + WriteBarcodes(writer); - private void WriteRelevanceKeys(JsonWriter writer) + if (Nfc != null) { - if (RelevantDate.HasValue) - { - writer.WritePropertyName("relevantDate"); - writer.WriteValue(RelevantDate.Value.ToString("yyyy-MM-ddTHH:mm:ssK")); - } + Trace.TraceInformation("Writing NFC fields"); + WriteNfcKeys(writer); + } - if (MaxDistance.HasValue) - { - writer.WritePropertyName("maxDistance"); - writer.WriteValue(MaxDistance.Value.ToString()); - } + Trace.TraceInformation("Opening style section.."); + OpenStyleSpecificKey(writer); - if (RelevantLocations.Count > 0) - { - writer.WritePropertyName("locations"); - writer.WriteStartArray(); + Trace.TraceInformation("Writing header fields"); + WriteSection(writer, "headerFields", HeaderFields); + Trace.TraceInformation("Writing primary fields"); + WriteSection(writer, "primaryFields", PrimaryFields); + Trace.TraceInformation("Writing secondary fields"); + WriteSection(writer, "secondaryFields", SecondaryFields); + Trace.TraceInformation("Writing auxiliary fields"); + WriteSection(writer, "auxiliaryFields", AuxiliaryFields); + Trace.TraceInformation("Writing back fields"); + WriteSection(writer, "backFields", BackFields); - foreach (var location in RelevantLocations) - { - location.Write(writer); - } + if (Style == PassStyle.BoardingPass) + { + writer.WritePropertyName("transitType"); + writer.WriteStringValue(TransitType.ToString()); + } - writer.WriteEndArray(); - } + Trace.TraceInformation("Closing style section.."); + CloseStyleSpecificKey(writer); - if (RelevantBeacons.Count > 0) - { - writer.WritePropertyName("beacons"); - writer.WriteStartArray(); + WriteBarcode(writer); + WriteUrls(writer); - foreach (var beacon in RelevantBeacons) - { - beacon.Write(writer); - } + writer.WriteEndObject(); + } - writer.WriteEndArray(); - } + private void WriteRelevanceKeys(Utf8JsonWriter writer) + { + if (RelevantDate.HasValue) + { + writer.WritePropertyName("relevantDate"); + writer.WriteStringValue(RelevantDate.Value.ToString("yyyy-MM-ddTHH:mm:ssK")); } - private void WriteUrls(JsonWriter writer) + if (MaxDistance.HasValue) { - if (!string.IsNullOrEmpty(AuthenticationToken)) - { - writer.WritePropertyName("authenticationToken"); - writer.WriteValue(AuthenticationToken); - writer.WritePropertyName("webServiceURL"); - writer.WriteValue(WebServiceUrl); - } + writer.WritePropertyName("maxDistance"); + writer.WriteStringValue(MaxDistance.Value.ToString()); } - private void WriteBarcode(JsonWriter writer) + if (RelevantLocations.Count > 0) { - if (Barcode != null) + writer.WritePropertyName("locations"); + writer.WriteStartArray(); + + foreach (var location in RelevantLocations) { - writer.WritePropertyName("barcode"); - Barcode.Write(writer); + location.Write(writer); } + + writer.WriteEndArray(); } - private void WriteBarcodes(JsonWriter writer) + if (RelevantBeacons.Count > 0) { - if (Barcodes.Count > 0) + writer.WritePropertyName("beacons"); + writer.WriteStartArray(); + + foreach (var beacon in RelevantBeacons) { - writer.WritePropertyName("barcodes"); - writer.WriteStartArray(); + beacon.Write(writer); + } - foreach (var barcode in Barcodes) - { - barcode.Write(writer); - } + writer.WriteEndArray(); + } + } - writer.WriteEndArray(); - } + private void WriteUrls(Utf8JsonWriter writer) + { + if (!string.IsNullOrEmpty(AuthenticationToken)) + { + writer.WritePropertyName("authenticationToken"); + writer.WriteStringValue(AuthenticationToken); + writer.WritePropertyName("webServiceURL"); + writer.WriteStringValue(WebServiceUrl); } + } - private void WriteSemantics(JsonWriter writer) + private void WriteBarcode(Utf8JsonWriter writer) + { + if (Barcode != null) { - SemanticTags.Write(writer); + writer.WritePropertyName("barcode"); + Barcode.Write(writer); } + } - private void WriteStandardKeys(JsonWriter writer) + private void WriteBarcodes(Utf8JsonWriter writer) + { + if (Barcodes.Count > 0) { - writer.WritePropertyName("passTypeIdentifier"); - writer.WriteValue(PassTypeIdentifier); + writer.WritePropertyName("barcodes"); + writer.WriteStartArray(); - writer.WritePropertyName("formatVersion"); - writer.WriteValue(FormatVersion); + foreach (var barcode in Barcodes) + { + barcode.Write(writer); + } - writer.WritePropertyName("serialNumber"); - writer.WriteValue(SerialNumber); + writer.WriteEndArray(); + } + } - writer.WritePropertyName("description"); - writer.WriteValue(Description); + private void WriteSemantics(Utf8JsonWriter writer) + { + SemanticTags.Write(writer); + } - writer.WritePropertyName("organizationName"); - writer.WriteValue(OrganizationName); + private void WriteStandardKeys(Utf8JsonWriter writer) + { + writer.WritePropertyName("passTypeIdentifier"); + writer.WriteStringValue(PassTypeIdentifier); - writer.WritePropertyName("teamIdentifier"); - writer.WriteValue(TeamIdentifier); + writer.WritePropertyName("formatVersion"); + writer.WriteNumberValue(FormatVersion); - writer.WritePropertyName("sharingProhibited"); - writer.WriteValue(SharingProhibited); + writer.WritePropertyName("serialNumber"); + writer.WriteStringValue(SerialNumber); - if (!String.IsNullOrEmpty(LogoText)) - { - writer.WritePropertyName("logoText"); - writer.WriteValue(LogoText); - } + writer.WritePropertyName("description"); + writer.WriteStringValue(Description); - if (AssociatedStoreIdentifiers.Count > 0) - { - writer.WritePropertyName("associatedStoreIdentifiers"); - writer.WriteStartArray(); + writer.WritePropertyName("organizationName"); + writer.WriteStringValue(OrganizationName); - foreach (var storeIdentifier in AssociatedStoreIdentifiers) - { - writer.WriteValue(storeIdentifier); - } + writer.WritePropertyName("teamIdentifier"); + writer.WriteStringValue(TeamIdentifier); - writer.WriteEndArray(); - } + writer.WritePropertyName("sharingProhibited"); + writer.WriteBooleanValue(SharingProhibited); - if (!string.IsNullOrEmpty(AppLaunchURL)) - { - writer.WritePropertyName("appLaunchURL"); - writer.WriteValue(AppLaunchURL); - } + if (!string.IsNullOrEmpty(LogoText)) + { + writer.WritePropertyName("logoText"); + writer.WriteStringValue(LogoText); } - private void WriteUserInfo(JsonWriter writer) + if (AssociatedStoreIdentifiers.Count > 0) { - if (UserInfo != null) + writer.WritePropertyName("associatedStoreIdentifiers"); + writer.WriteStartArray(); + + foreach (var storeIdentifier in AssociatedStoreIdentifiers) { - writer.WritePropertyName("userInfo"); - writer.WriteRawValue(JsonConvert.SerializeObject(UserInfo)); + writer.WriteNumberValue(storeIdentifier); } + + writer.WriteEndArray(); } - private void WriteAppearanceKeys(JsonWriter writer) + if (!string.IsNullOrEmpty(AppLaunchURL)) { - if (!String.IsNullOrEmpty(ForegroundColor)) - { - writer.WritePropertyName("foregroundColor"); - writer.WriteValue(ConvertColor(ForegroundColor)); - } + writer.WritePropertyName("appLaunchURL"); + writer.WriteStringValue(AppLaunchURL); + } + } - if (!String.IsNullOrEmpty(BackgroundColor)) - { - writer.WritePropertyName("backgroundColor"); - writer.WriteValue(ConvertColor(BackgroundColor)); - } + private void WriteUserInfo(Utf8JsonWriter writer) + { + if (UserInfo != null) + { + writer.WritePropertyName("userInfo"); + string json = JsonSerializer.Serialize(UserInfo); + writer.WriteRawValue(json); + } + } - if (!String.IsNullOrEmpty(LabelColor)) - { - writer.WritePropertyName("labelColor"); - writer.WriteValue(ConvertColor(LabelColor)); - } + private void WriteAppearanceKeys(Utf8JsonWriter writer) + { + if (!string.IsNullOrEmpty(ForegroundColor)) + { + writer.WritePropertyName("foregroundColor"); + writer.WriteStringValue(ConvertColor(ForegroundColor)); + } - if (SuppressStripShine.HasValue) - { - writer.WritePropertyName("suppressStripShine"); - writer.WriteValue(SuppressStripShine.Value); - } + if (!string.IsNullOrEmpty(BackgroundColor)) + { + writer.WritePropertyName("backgroundColor"); + writer.WriteStringValue(ConvertColor(BackgroundColor)); + } - if (!String.IsNullOrEmpty(GroupingIdentifier)) - { - writer.WritePropertyName("groupingIdentifier"); - writer.WriteValue(GroupingIdentifier); - } + if (!string.IsNullOrEmpty(LabelColor)) + { + writer.WritePropertyName("labelColor"); + writer.WriteStringValue(ConvertColor(LabelColor)); } - private void WriteExpirationKeys(JsonWriter writer) + if (SuppressStripShine.HasValue) { - if (ExpirationDate.HasValue) - { - writer.WritePropertyName("expirationDate"); - writer.WriteValue(ExpirationDate.Value.ToString("yyyy-MM-ddTHH:mm:ssK")); - } + writer.WritePropertyName("suppressStripShine"); + writer.WriteBooleanValue(SuppressStripShine.Value); + } - if (Voided.HasValue) - { - writer.WritePropertyName("voided"); - writer.WriteValue(Voided.Value); - } + if (!string.IsNullOrEmpty(GroupingIdentifier)) + { + writer.WritePropertyName("groupingIdentifier"); + writer.WriteStringValue(GroupingIdentifier); } + } - private void OpenStyleSpecificKey(JsonWriter writer) + private void WriteExpirationKeys(Utf8JsonWriter writer) + { + if (ExpirationDate.HasValue) { - string key = Style.ToString(); + writer.WritePropertyName("expirationDate"); + writer.WriteStringValue(ExpirationDate.Value.ToString("yyyy-MM-ddTHH:mm:ssK")); + } - writer.WritePropertyName(char.ToLowerInvariant(key[0]) + key.Substring(1)); - writer.WriteStartObject(); + if (Voided.HasValue) + { + writer.WritePropertyName("voided"); + writer.WriteBooleanValue(Voided.Value); } + } + + private void OpenStyleSpecificKey(Utf8JsonWriter writer) + { + string key = Style.ToString(); + + writer.WritePropertyName(char.ToLowerInvariant(key[0]) + key.Substring(1)); + writer.WriteStartObject(); + } - private static void CloseStyleSpecificKey(JsonWriter writer) + private static void CloseStyleSpecificKey(Utf8JsonWriter writer) + { + writer.WriteEndObject(); + } + + private static void WriteSection(Utf8JsonWriter writer, string sectionName, List fields) + { + writer.WritePropertyName(sectionName); + writer.WriteStartArray(); + + foreach (var field in fields) { - writer.WriteEndObject(); + field.Write(writer); } - private static void WriteSection(JsonWriter writer, string sectionName, List fields) + writer.WriteEndArray(); + } + + private void WriteNfcKeys(Utf8JsonWriter writer) + { + if (!string.IsNullOrEmpty(Nfc.Message)) { - writer.WritePropertyName(sectionName); - writer.WriteStartArray(); + writer.WritePropertyName("nfc"); + writer.WriteStartObject(); + writer.WritePropertyName("message"); + writer.WriteStringValue(Nfc.Message); - foreach (var field in fields) + if (!string.IsNullOrEmpty(Nfc.EncryptionPublicKey)) { - field.Write(writer); + writer.WritePropertyName("encryptionPublicKey"); + writer.WriteStringValue(Nfc.EncryptionPublicKey); } - writer.WriteEndArray(); + writer.WriteEndObject(); } + } - private void WriteNfcKeys(JsonWriter writer) + private static string ConvertColor(string color) + { + if (!string.IsNullOrEmpty(color) && color.Substring(0, 1) == "#") { - if (!string.IsNullOrEmpty(Nfc.Message)) + int r, g, b; + + if (color.Length == 3) { - writer.WritePropertyName("nfc"); - writer.WriteStartObject(); - writer.WritePropertyName("message"); - writer.WriteValue(Nfc.Message); - - if (!string.IsNullOrEmpty(Nfc.EncryptionPublicKey)) - { - writer.WritePropertyName("encryptionPublicKey"); - writer.WriteValue(Nfc.EncryptionPublicKey); - } - - writer.WriteEndObject(); + r = int.Parse(color.Substring(1, 1), NumberStyles.HexNumber); + g = int.Parse(color.Substring(2, 1), NumberStyles.HexNumber); + b = int.Parse(color.Substring(3, 1), NumberStyles.HexNumber); } - } - - private static string ConvertColor(string color) - { - if (!string.IsNullOrEmpty(color) && color.Substring(0, 1) == "#") + else if (color.Length >= 6) { - int r, g, b; - - if (color.Length == 3) - { - r = int.Parse(color.Substring(1, 1), NumberStyles.HexNumber); - g = int.Parse(color.Substring(2, 1), NumberStyles.HexNumber); - b = int.Parse(color.Substring(3, 1), NumberStyles.HexNumber); - } - else if (color.Length >= 6) - { - r = int.Parse(color.Substring(1, 2), NumberStyles.HexNumber); - g = int.Parse(color.Substring(3, 2), NumberStyles.HexNumber); - b = int.Parse(color.Substring(5, 2), NumberStyles.HexNumber); - } - else - { - throw new ArgumentException("use #rgb or #rrggbb for color values", color); - } - - return $"rgb({r},{g},{b})"; + r = int.Parse(color.Substring(1, 2), NumberStyles.HexNumber); + g = int.Parse(color.Substring(3, 2), NumberStyles.HexNumber); + b = int.Parse(color.Substring(5, 2), NumberStyles.HexNumber); } else { - return color; + throw new ArgumentException("use #rgb or #rrggbb for color values", color); } - } - #endregion + return $"rgb({r},{g},{b})"; + } + else + { + return color; + } } + + #endregion } diff --git a/Passbook.Generator/PassStyle.cs b/Passbook.Generator/PassStyle.cs index ec8cd7b..023aa69 100644 --- a/Passbook.Generator/PassStyle.cs +++ b/Passbook.Generator/PassStyle.cs @@ -1,14 +1,13 @@ -namespace Passbook.Generator +namespace Passbook.Generator; + +/// +/// +/// +public enum PassStyle { - /// - /// - /// - public enum PassStyle - { - Generic, - BoardingPass, - Coupon, - EventTicket, - StoreCard - } + Generic, + BoardingPass, + Coupon, + EventTicket, + StoreCard } diff --git a/Passbook.Generator/Passbook.Generator.csproj b/Passbook.Generator/Passbook.Generator.csproj index 6dccf58..e4a6cc1 100644 --- a/Passbook.Generator/Passbook.Generator.csproj +++ b/Passbook.Generator/Passbook.Generator.csproj @@ -1,12 +1,12 @@  - netstandard2.0 3.2.4.0 false dotnet-passbook Tomas McGuinness dotnet-passbook + net8.0 Generate pass files for Apple Wallet. This library allows you to build and sign a pkpass file. Fix issue where some Associated Store Identifier values where not being handled correctly (GitHub issue #179) PassBook Wallet Apple Passkit @@ -27,15 +27,9 @@ - - - - + - - - - + diff --git a/Passbook.Generator/RelevantBeacon.cs b/Passbook.Generator/RelevantBeacon.cs index 3237125..bf986ca 100644 --- a/Passbook.Generator/RelevantBeacon.cs +++ b/Passbook.Generator/RelevantBeacon.cs @@ -1,60 +1,59 @@ -using Newtonsoft.Json; +using System.Text.Json; using Passbook.Generator.Exceptions; -namespace Passbook.Generator -{ - public class RelevantBeacon - { - /// - /// Required. Unique identifier of a Bluetooth Low Energy location beacon. - /// - public string ProximityUUID { get; set; } +namespace Passbook.Generator; - /// - /// Optional. Text displayed on the lock screen when the pass is currently relevant. - /// - public string RelevantText { get; set; } +public class RelevantBeacon +{ + /// + /// Required. Unique identifier of a Bluetooth Low Energy location beacon. + /// + public string ProximityUUID { get; set; } - public int? Major { get; set; } + /// + /// Optional. Text displayed on the lock screen when the pass is currently relevant. + /// + public string RelevantText { get; set; } - public int? Minor { get; set; } + public int? Major { get; set; } - public void Write(JsonWriter writer) - { - Validate(); + public int? Minor { get; set; } - writer.WriteStartObject(); + public void Write(Utf8JsonWriter writer) + { + Validate(); - writer.WritePropertyName("proximityUUID"); - writer.WriteValue(ProximityUUID); + writer.WriteStartObject(); - if (!string.IsNullOrEmpty(RelevantText)) - { - writer.WritePropertyName("relevantText"); - writer.WriteValue(RelevantText); - } + writer.WritePropertyName("proximityUUID"); + writer.WriteStringValue(ProximityUUID); - if (Minor.HasValue) - { - writer.WritePropertyName("minor"); - writer.WriteValue(Minor); - } + if (!string.IsNullOrEmpty(RelevantText)) + { + writer.WritePropertyName("relevantText"); + writer.WriteStringValue(RelevantText); + } - if (Major.HasValue) - { - writer.WritePropertyName("major"); - writer.WriteValue(Major); - } + if (Minor.HasValue) + { + writer.WritePropertyName("minor"); + writer.WriteNumberValue(Minor.Value); + } - writer.WriteEndObject(); + if (Major.HasValue) + { + writer.WritePropertyName("major"); + writer.WriteNumberValue(Major.Value); } - private void Validate() + writer.WriteEndObject(); + } + + private void Validate() + { + if (string.IsNullOrEmpty(ProximityUUID)) { - if (string.IsNullOrEmpty(ProximityUUID)) - { - throw new RequiredFieldValueMissingException("ProximityUUID"); - } + throw new RequiredFieldValueMissingException("ProximityUUID"); } } } diff --git a/Passbook.Generator/RelevantLocation.cs b/Passbook.Generator/RelevantLocation.cs index edd8c6f..5c5ca39 100644 --- a/Passbook.Generator/RelevantLocation.cs +++ b/Passbook.Generator/RelevantLocation.cs @@ -1,68 +1,67 @@ -using Newtonsoft.Json; +using System.Text.Json; using Passbook.Generator.Exceptions; -namespace Passbook.Generator -{ - public class RelevantLocation - { - /// - /// Optional. Altitude, in meters, of the location. - /// - public double? Altitude { get; set; } +namespace Passbook.Generator; - /// - /// Required. Latitude, in degrees, of the location. - /// - public double Latitude { get; set; } +public class RelevantLocation +{ + /// + /// Optional. Altitude, in meters, of the location. + /// + public double? Altitude { get; set; } - /// - /// Required. Longitude, in degrees, of the location. - /// - public double Longitude { get; set; } + /// + /// Required. Latitude, in degrees, of the location. + /// + public double Latitude { get; set; } - /// - /// Optional. Text displayed on the lock screen when the pass is currently relevant. - /// - public string RelevantText { get; set; } + /// + /// Required. Longitude, in degrees, of the location. + /// + public double Longitude { get; set; } - public void Write(JsonWriter writer) - { - Validate(); + /// + /// Optional. Text displayed on the lock screen when the pass is currently relevant. + /// + public string RelevantText { get; set; } - writer.WriteStartObject(); + public void Write(Utf8JsonWriter writer) + { + Validate(); - if (Altitude.HasValue) - { - writer.WritePropertyName("altitude"); - writer.WriteValue(Altitude.Value); - } + writer.WriteStartObject(); - writer.WritePropertyName("latitude"); - writer.WriteValue(Latitude); + if (Altitude.HasValue) + { + writer.WritePropertyName("altitude"); + writer.WriteNumberValue(Altitude.Value); + } - writer.WritePropertyName("longitude"); - writer.WriteValue(Longitude); + writer.WritePropertyName("latitude"); + writer.WriteNumberValue(Latitude); - if (RelevantText != null) - { - writer.WritePropertyName("relevantText"); - writer.WriteValue(RelevantText); - } + writer.WritePropertyName("longitude"); + writer.WriteNumberValue(Longitude); - writer.WriteEndObject(); + if (RelevantText != null) + { + writer.WritePropertyName("relevantText"); + writer.WriteStringValue(RelevantText); } - private void Validate() + writer.WriteEndObject(); + } + + private void Validate() + { + if (Latitude == double.MinValue) { - if (Latitude == double.MinValue) - { - throw new RequiredFieldValueMissingException("latitude"); - } + throw new RequiredFieldValueMissingException("latitude"); + } - if (Longitude == double.MinValue) - { - throw new RequiredFieldValueMissingException("longitude"); - } + if (Longitude == double.MinValue) + { + throw new RequiredFieldValueMissingException("longitude"); } } } diff --git a/Passbook.Generator/SemanticTags.cs b/Passbook.Generator/SemanticTags.cs index 69017ff..93ecbc8 100644 --- a/Passbook.Generator/SemanticTags.cs +++ b/Passbook.Generator/SemanticTags.cs @@ -1,23 +1,21 @@ -using Newtonsoft.Json; -using Passbook.Generator.Tags; +using Passbook.Generator.Tags; using System.Collections.Generic; -using System.Text; +using System.Text.Json; -namespace Passbook.Generator +namespace Passbook.Generator; + +public class SemanticTags : List { - public class SemanticTags : List + public void Write(Utf8JsonWriter writer) { - public void Write(JsonWriter writer) + writer.WritePropertyName("semantics"); + writer.WriteStartObject(); + + foreach (var tag in this) { - writer.WritePropertyName("semantics"); - writer.WriteStartObject(); - - foreach (var tag in this) - { - tag.Write(writer); - } - - writer.WriteEndObject(); + tag.Write(writer); } + + writer.WriteEndObject(); } } diff --git a/Passbook.Generator/StandardField.cs b/Passbook.Generator/StandardField.cs index dcae14d..a2c52b3 100644 --- a/Passbook.Generator/StandardField.cs +++ b/Passbook.Generator/StandardField.cs @@ -1,46 +1,46 @@ -using Passbook.Generator.Exceptions; +using System.Text.Json; +using Passbook.Generator.Exceptions; -namespace Passbook.Generator.Fields +namespace Passbook.Generator.Fields; + +public class StandardField : Field { - public class StandardField : Field - { - public StandardField() - : base() - { } + public StandardField() + : base() + { } - public StandardField(string key, string label, string value) - : base(key, label) - { - this.Value = value; - } + public StandardField(string key, string label, string value) + : base(key, label) + { + Value = value; + } - public StandardField(string key, string label, string value, string attributedValue, DataDetectorTypes dataDetectorTypes) - : this(key, label, value) - { - this.AttributedValue = attributedValue; - this.DataDetectorTypes = dataDetectorTypes; - } + public StandardField(string key, string label, string value, string attributedValue, DataDetectorTypes dataDetectorTypes) + : this(key, label, value) + { + AttributedValue = attributedValue; + DataDetectorTypes = dataDetectorTypes; + } - public string Value { get; set; } + public string Value { get; set; } - protected override void WriteValue(Newtonsoft.Json.JsonWriter writer) + protected override void WriteValue(Utf8JsonWriter writer) + { + if (Value == null) { - if (Value == null) - { - throw new RequiredFieldValueMissingException(Key); - } - - writer.WriteValue(Value); + throw new RequiredFieldValueMissingException(Key); } - public override void SetValue(object value) - { - this.Value = value as string; - } + writer.WriteStringValue(Value); + } - public override bool HasValue - { - get { return !string.IsNullOrEmpty(Value); } - } + public override void SetValue(object value) + { + Value = value as string; + } + + public override bool HasValue + { + get { return !string.IsNullOrEmpty(Value); } } } diff --git a/Passbook.Generator/Tags/AirlineCode.cs b/Passbook.Generator/Tags/AirlineCode.cs index e89217d..98f1177 100644 --- a/Passbook.Generator/Tags/AirlineCode.cs +++ b/Passbook.Generator/Tags/AirlineCode.cs @@ -1,15 +1,8 @@ -using Newtonsoft.Json; +namespace Passbook.Generator.Tags; -namespace Passbook.Generator.Tags +/// +/// The IATA airline code, such as “EX” for flightCode “EX123”. Use this key only for airline boarding passes. +/// +public class AirlineCode(string value) : SemanticTagBaseValue("airlineCode", value) { - /// - /// The IATA airline code, such as “EX” for flightCode “EX123”. Use this key only for airline boarding passes. - /// - public class AirlineCode : SemanticTagBaseValue - { - public AirlineCode(string value) : base("airlineCode", value) - { - // NO Op - } - } } diff --git a/Passbook.Generator/Tags/ArtistIds.cs b/Passbook.Generator/Tags/ArtistIds.cs index ed36dbb..d6377db 100644 --- a/Passbook.Generator/Tags/ArtistIds.cs +++ b/Passbook.Generator/Tags/ArtistIds.cs @@ -1,23 +1,21 @@ -using Newtonsoft.Json; +using System.Text.Json; -namespace Passbook.Generator.Tags -{ - /// - /// An array of the Apple Music persistent ID for each artist performing at the event, in decreasing order of significance. - /// Use this key for any type of event ticket. - /// - public class ArtistIds : SemanticTag - { - private readonly string[] _artistIds; +namespace Passbook.Generator.Tags; - public ArtistIds(params string[] artistIds) : base("artistIds") - { - _artistIds = artistIds; - } +/// +/// An array of the Apple Music persistent ID for each artist performing at the event, in decreasing order of significance. +/// Use this key for any type of event ticket. +/// +public class ArtistIds(params string[] artistIds) : SemanticTag("artistIds") +{ - public override void WriteValue(JsonWriter writer) + public override void WriteValue(Utf8JsonWriter writer) + { + writer.WriteStartArray(); + foreach (var artistId in artistIds) { - writer.WriteValue(_artistIds); + writer.WriteStringValue(artistId); } + writer.WriteEndArray(); } } diff --git a/Passbook.Generator/Tags/AwayTeamAbbreviation.cs b/Passbook.Generator/Tags/AwayTeamAbbreviation.cs index ec9c584..efa7e32 100644 --- a/Passbook.Generator/Tags/AwayTeamAbbreviation.cs +++ b/Passbook.Generator/Tags/AwayTeamAbbreviation.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The unique abbreviation of the away team’s name. Use this key only for a sports event ticket. +/// +public class AwayTeamAbbreviation(string value) : SemanticTagBaseValue("awayTeamAbbreviation", value) { - /// - /// The unique abbreviation of the away team’s name. Use this key only for a sports event ticket. - /// - public class AwayTeamAbbreviation : SemanticTagBaseValue - { - public AwayTeamAbbreviation(string value) : base("awayTeamAbbreviation", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/AwayTeamLocation.cs b/Passbook.Generator/Tags/AwayTeamLocation.cs index 3928ae7..a0f147f 100644 --- a/Passbook.Generator/Tags/AwayTeamLocation.cs +++ b/Passbook.Generator/Tags/AwayTeamLocation.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The home location of the away team. Use this key only for a sports event ticket. +/// +public class AwayTeamLocation(string value) : SemanticTagBaseValue("awayTeamLocation", value) { - /// - /// The home location of the away team. Use this key only for a sports event ticket. - /// - public class AwayTeamLocation : SemanticTagBaseValue - { - public AwayTeamLocation(string value) : base("awayTeamLocation", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/AwayTeamName.cs b/Passbook.Generator/Tags/AwayTeamName.cs index 0cce0a3..e1ec539 100644 --- a/Passbook.Generator/Tags/AwayTeamName.cs +++ b/Passbook.Generator/Tags/AwayTeamName.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The name of the away team. Use this key only for a sports event ticket. +/// +public class AwayTeamName(string value) : SemanticTagBaseValue("awayTeamName", value) { - /// - /// The name of the away team. Use this key only for a sports event ticket. - /// - public class AwayTeamName : SemanticTagBaseValue - { - public AwayTeamName(string value) : base("awayTeamName", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/EventTypes.cs b/Passbook.Generator/Tags/EventTypes.cs index 84b5e1b..579f9fd 100644 --- a/Passbook.Generator/Tags/EventTypes.cs +++ b/Passbook.Generator/Tags/EventTypes.cs @@ -1,14 +1,13 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public enum EventTypes { - public enum EventTypes - { - PKEventTypeGeneric, - PKEventTypeLivePerformance, - PKEventTypeMovie, - PKEventTypeSports, - PKEventTypeConference, - PKEventTypeConvention, - PKEventTypeWorkshop, - PKEventTypeSocialGathering - } + PKEventTypeGeneric, + PKEventTypeLivePerformance, + PKEventTypeMovie, + PKEventTypeSports, + PKEventTypeConference, + PKEventTypeConvention, + PKEventTypeWorkshop, + PKEventTypeSocialGathering } \ No newline at end of file diff --git a/Passbook.Generator/Tags/Seat.cs b/Passbook.Generator/Tags/Seat.cs index 91a7eda..cfe3b6f 100644 --- a/Passbook.Generator/Tags/Seat.cs +++ b/Passbook.Generator/Tags/Seat.cs @@ -1,39 +1,38 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class Seat { - public class Seat - { - /// - /// A description of the seat, such as “A flat bed seat”. - /// - public string SeatDescription { get; set; } + /// + /// A description of the seat, such as “A flat bed seat”. + /// + public string SeatDescription { get; set; } - /// - /// The identifier code for the seat. - /// + /// + /// The identifier code for the seat. + /// - public string SeatIdentifier { get; set; } + public string SeatIdentifier { get; set; } - /// - /// The number of the seat. - /// - public string SeatNumber { get; set; } + /// + /// The number of the seat. + /// + public string SeatNumber { get; set; } - /// - /// The row that contains the seat. - /// - public string SeatRow { get; set; } + /// + /// The row that contains the seat. + /// + public string SeatRow { get; set; } - /// - /// The section that contains the seat. - /// + /// + /// The section that contains the seat. + /// - public string SeatSection { get; set; } + public string SeatSection { get; set; } - /// - /// The type of seat, such as “Reserved seating”. - /// - public string SeatType { get; set; } - } + /// + /// The type of seat, such as “Reserved seating”. + /// + public string SeatType { get; set; } } diff --git a/Passbook.Generator/Tags/SemanticTag.cs b/Passbook.Generator/Tags/SemanticTag.cs index e7c8e35..80047b0 100644 --- a/Passbook.Generator/Tags/SemanticTag.cs +++ b/Passbook.Generator/Tags/SemanticTag.cs @@ -1,22 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json; -namespace Passbook.Generator.Tags -{ - public abstract class SemanticTag - { - public SemanticTag(string tag) - { - Tag = tag; - } - - public string Tag { get; } +namespace Passbook.Generator.Tags; - public void Write(JsonWriter writer) - { - writer.WritePropertyName(Tag); - WriteValue(writer); - } +public abstract class SemanticTag(string tag) +{ + public string Tag { get; } = tag; - public abstract void WriteValue(JsonWriter writer); + public void Write(Utf8JsonWriter writer) + { + writer.WritePropertyName(Tag); + WriteValue(writer); } + + public abstract void WriteValue(Utf8JsonWriter writer); } \ No newline at end of file diff --git a/Passbook.Generator/Tags/SemanticTagBaseValue.cs b/Passbook.Generator/Tags/SemanticTagBaseValue.cs index d0bdd67..a2232e4 100644 --- a/Passbook.Generator/Tags/SemanticTagBaseValue.cs +++ b/Passbook.Generator/Tags/SemanticTagBaseValue.cs @@ -1,29 +1,52 @@ -using Newtonsoft.Json; +using System; +using System.Text.Json; -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public abstract class SemanticTagBaseValue : SemanticTag { - public abstract class SemanticTagBaseValue : SemanticTag - { - private readonly object _value; + private readonly object _value; - public SemanticTagBaseValue(string tag, string value) : base(tag) - { - _value = value; - } + public SemanticTagBaseValue(string tag, string value) : base(tag) + { + _value = value; + } - public SemanticTagBaseValue(string tag, bool value) : base(tag) - { - _value = value; - } + public SemanticTagBaseValue(string tag, bool value) : base(tag) + { + _value = value; + } - public SemanticTagBaseValue(string tag, double value) : base(tag) - { - _value = value; - } + public SemanticTagBaseValue(string tag, double value) : base(tag) + { + _value = value; + } - public override void WriteValue(JsonWriter writer) + public override void WriteValue(Utf8JsonWriter writer) + { + switch (_value) { - writer.WriteValue(_value); + case string s: + writer.WriteStringValue(s); + break; + case bool b: + writer.WriteBooleanValue(b); + break; + case double d: + writer.WriteNumberValue(d); + break; + case float f: + writer.WriteNumberValue(f); + break; + case decimal m: + writer.WriteNumberValue(m); + break; + case int i: + writer.WriteNumberValue(i); + break; + case long l: + writer.WriteNumberValue(l); + break; } } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/balance.cs b/Passbook.Generator/Tags/balance.cs index a560484..3d3704c 100644 --- a/Passbook.Generator/Tags/balance.cs +++ b/Passbook.Generator/Tags/balance.cs @@ -1,25 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json; namespace Passbook.Generator.Tags { - public class Balance : SemanticTag + public class Balance(string amount, string currencyCode) : SemanticTag("balance") { - private readonly string _amount; - private readonly string _currencyCode; - - public Balance(string amount, string currencyCode) : base("balance") - { - _amount = amount; - _currencyCode = currencyCode; - } - - public override void WriteValue(JsonWriter writer) + public override void WriteValue(Utf8JsonWriter writer) { writer.WriteStartObject(); writer.WritePropertyName("amount"); - writer.WriteValue(_amount); + writer.WriteStringValue(amount); writer.WritePropertyName("currencyCode"); - writer.WriteValue(_currencyCode); + writer.WriteStringValue(currencyCode); writer.WriteEndObject(); } } diff --git a/Passbook.Generator/Tags/boardingGroup.cs b/Passbook.Generator/Tags/boardingGroup.cs index 9a01672..fa43a26 100644 --- a/Passbook.Generator/Tags/boardingGroup.cs +++ b/Passbook.Generator/Tags/boardingGroup.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class BoardingGroup(string value) : SemanticTagBaseValue("boardingGroup", value) { - public class BoardingGroup : SemanticTagBaseValue - { - public BoardingGroup(string value) : base("boardingGroup", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/boardingSequenceNumber.cs b/Passbook.Generator/Tags/boardingSequenceNumber.cs index f067960..13f2b01 100644 --- a/Passbook.Generator/Tags/boardingSequenceNumber.cs +++ b/Passbook.Generator/Tags/boardingSequenceNumber.cs @@ -1,9 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class BoardingSequenceNumber(string value) : SemanticTagBaseValue("boardingSequenceNumber", value) { - public class BoardingSequenceNumber : SemanticTagBaseValue - { - public BoardingSequenceNumber(string value) : base("boardingSequenceNumber", value) - { - } - } } diff --git a/Passbook.Generator/Tags/carNumber.cs b/Passbook.Generator/Tags/carNumber.cs index fdf2e2c..ccc4ddc 100644 --- a/Passbook.Generator/Tags/carNumber.cs +++ b/Passbook.Generator/Tags/carNumber.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class CarNumber(string value) : SemanticTagBaseValue("carNumber", value) { - public class CarNumber : SemanticTagBaseValue - { - public CarNumber(string value) : base("carNumber", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/confirmationNumber.cs b/Passbook.Generator/Tags/confirmationNumber.cs index 7464734..7075866 100644 --- a/Passbook.Generator/Tags/confirmationNumber.cs +++ b/Passbook.Generator/Tags/confirmationNumber.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class ConfirmationNumber(string value) : SemanticTagBaseValue("confirmationNumber", value) { - public class ConfirmationNumber : SemanticTagBaseValue - { - public ConfirmationNumber(string value) : base("confirmationNumber", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/currentArrivalDate.cs b/Passbook.Generator/Tags/currentArrivalDate.cs index 2365eb4..bb75011 100644 --- a/Passbook.Generator/Tags/currentArrivalDate.cs +++ b/Passbook.Generator/Tags/currentArrivalDate.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class CurrentArrivalDate(string value) : SemanticTagBaseValue("currentArrivalDate", value) { - public class CurrentArrivalDate : SemanticTagBaseValue - { - public CurrentArrivalDate(string value) : base("currentArrivalDate", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/currentBoardingDate.cs b/Passbook.Generator/Tags/currentBoardingDate.cs index 6d6ff82..1ff6ea6 100644 --- a/Passbook.Generator/Tags/currentBoardingDate.cs +++ b/Passbook.Generator/Tags/currentBoardingDate.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +class CurrentBoardingDate(string value) : SemanticTagBaseValue("currentBoardingDate", value) { - class CurrentBoardingDate : SemanticTagBaseValue - { - public CurrentBoardingDate(string value) : base("currentBoardingDate", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/currentDepartureDate.cs b/Passbook.Generator/Tags/currentDepartureDate.cs index ff137d3..794d06e 100644 --- a/Passbook.Generator/Tags/currentDepartureDate.cs +++ b/Passbook.Generator/Tags/currentDepartureDate.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +class CurrentDepartureDate(string value) : SemanticTagBaseValue("currentDepartureDate", value) { - class CurrentDepartureDate : SemanticTagBaseValue - { - public CurrentDepartureDate(string value) : base("currentDepartureDate", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/departureAirportCode.cs b/Passbook.Generator/Tags/departureAirportCode.cs index e89ec81..55e1835 100644 --- a/Passbook.Generator/Tags/departureAirportCode.cs +++ b/Passbook.Generator/Tags/departureAirportCode.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +class DepartureAirportCode(string value) : SemanticTagBaseValue("departureAirportCode", value) { - class DepartureAirportCode : SemanticTagBaseValue - { - public DepartureAirportCode(string value) : base("departureAirportCode", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/departureAirportName.cs b/Passbook.Generator/Tags/departureAirportName.cs index 967a9bc..f190a6d 100644 --- a/Passbook.Generator/Tags/departureAirportName.cs +++ b/Passbook.Generator/Tags/departureAirportName.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +class DepartureAirportName(string value) : SemanticTagBaseValue("departureAirportName", value) { - class DepartureAirportName : SemanticTagBaseValue - { - public DepartureAirportName(string value) : base("departureAirportName", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/departureGate.cs b/Passbook.Generator/Tags/departureGate.cs index 29c2bc4..22d6a5c 100644 --- a/Passbook.Generator/Tags/departureGate.cs +++ b/Passbook.Generator/Tags/departureGate.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +class DepartureGate(string value) : SemanticTagBaseValue("departureGate", value) { - class DepartureGate : SemanticTagBaseValue - { - public DepartureGate(string value) : base("departureGate", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/departureLocation.cs b/Passbook.Generator/Tags/departureLocation.cs index 790e7f7..db12143 100644 --- a/Passbook.Generator/Tags/departureLocation.cs +++ b/Passbook.Generator/Tags/departureLocation.cs @@ -1,25 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json; namespace Passbook.Generator.Tags { - public class DepartureLocation : SemanticTag + public class DepartureLocation(double latitude, double longitude) : SemanticTag("departureLocation") { - private readonly double _latitude; - private readonly double _longitude; - - public DepartureLocation(double latitude, double longitude) : base("departureLocation") - { - _latitude = latitude; - _longitude = longitude; - } - - public override void WriteValue(JsonWriter writer) + public override void WriteValue(Utf8JsonWriter writer) { writer.WriteStartObject(); writer.WritePropertyName("latitude"); - writer.WriteValue(_latitude); + writer.WriteNumberValue(latitude); writer.WritePropertyName("longitude"); - writer.WriteValue(_longitude); + writer.WriteNumberValue(longitude); writer.WriteEndObject(); } } diff --git a/Passbook.Generator/Tags/departureLocationDescription.cs b/Passbook.Generator/Tags/departureLocationDescription.cs index e206bfd..948cf40 100644 --- a/Passbook.Generator/Tags/departureLocationDescription.cs +++ b/Passbook.Generator/Tags/departureLocationDescription.cs @@ -1,10 +1,6 @@ namespace Passbook.Generator.Tags { - class DepartureLocationDescription : SemanticTagBaseValue + class DepartureLocationDescription(string value) : SemanticTagBaseValue("departureLocationDescription", value) { - public DepartureLocationDescription(string value) : base("departureLocationDescription", value) - { - // NO OP - } } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/departurePlatform.cs b/Passbook.Generator/Tags/departurePlatform.cs index c268523..411cc63 100644 --- a/Passbook.Generator/Tags/departurePlatform.cs +++ b/Passbook.Generator/Tags/departurePlatform.cs @@ -1,10 +1,6 @@ namespace Passbook.Generator.Tags { - public class DeparturePlatform : SemanticTagBaseValue + public class DeparturePlatform(string value) : SemanticTagBaseValue("departurePlatform", value) { - public DeparturePlatform(string value) : base("departurePlatform", value) - { - // NO OP - } } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/departureStationName.cs b/Passbook.Generator/Tags/departureStationName.cs index 2cf065f..f47dd60 100644 --- a/Passbook.Generator/Tags/departureStationName.cs +++ b/Passbook.Generator/Tags/departureStationName.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class DepartureStationName(string value) : SemanticTagBaseValue("departureStationName", value) { - public class DepartureStationName : SemanticTagBaseValue - { - public DepartureStationName(string value) : base("departureStationName", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/departureTerminal.cs b/Passbook.Generator/Tags/departureTerminal.cs index 14b52b1..40f81d7 100644 --- a/Passbook.Generator/Tags/departureTerminal.cs +++ b/Passbook.Generator/Tags/departureTerminal.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class DepartureTerminal(string value) : SemanticTagBaseValue("departureTerminal", value) { - public class DepartureTerminal : SemanticTagBaseValue - { - public DepartureTerminal(string value) : base("departureTerminal", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/destinationAirportCode.cs b/Passbook.Generator/Tags/destinationAirportCode.cs index e1aff2d..c1a0ebe 100644 --- a/Passbook.Generator/Tags/destinationAirportCode.cs +++ b/Passbook.Generator/Tags/destinationAirportCode.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +class DestinationAirportCode(string value) : SemanticTagBaseValue("destinationAirportCode", value) { - class DestinationAirportCode : SemanticTagBaseValue - { - public DestinationAirportCode(string value) : base("destinationAirportCode", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/destinationAirportName.cs b/Passbook.Generator/Tags/destinationAirportName.cs index a5e8412..df0919b 100644 --- a/Passbook.Generator/Tags/destinationAirportName.cs +++ b/Passbook.Generator/Tags/destinationAirportName.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class DestinationAirportName(string value) : SemanticTagBaseValue("destinationAirportName", value) { - public class DestinationAirportName : SemanticTagBaseValue - { - public DestinationAirportName(string value) : base("destinationAirportName", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/destinationGate.cs b/Passbook.Generator/Tags/destinationGate.cs index 2c1b42d..ff4040f 100644 --- a/Passbook.Generator/Tags/destinationGate.cs +++ b/Passbook.Generator/Tags/destinationGate.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class DestinationGate(string value) : SemanticTagBaseValue("destinationGate", value) { - public class DestinationGate : SemanticTagBaseValue - { - public DestinationGate(string value) : base("destinationGate", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/destinationLocation.cs b/Passbook.Generator/Tags/destinationLocation.cs index b903b11..bd015cc 100644 --- a/Passbook.Generator/Tags/destinationLocation.cs +++ b/Passbook.Generator/Tags/destinationLocation.cs @@ -1,26 +1,15 @@ -using Newtonsoft.Json; +using System.Text.Json; -namespace Passbook.Generator.Tags -{ - public class DestinationLocation : SemanticTag - { - private readonly double _latitude; - private readonly double _longitude; - - public DestinationLocation(double latitude, double longitude) : base("destinationLocation ") - { - _latitude = latitude; - _longitude = longitude; - } +namespace Passbook.Generator.Tags; - public override void WriteValue(JsonWriter writer) - { - writer.WriteStartObject(); - writer.WritePropertyName("latitude"); - writer.WriteValue(_latitude); - writer.WritePropertyName("longitude"); - writer.WriteValue(_longitude); - writer.WriteEndObject(); - } +public class DestinationLocation(double latitude, double longitude) : SemanticTag("destinationLocation ") +{ public override void WriteValue(Utf8JsonWriter writer) + { + writer.WriteStartObject(); + writer.WritePropertyName("latitude"); + writer.WriteNumberValue(latitude); + writer.WritePropertyName("longitude"); + writer.WriteNumberValue(longitude); + writer.WriteEndObject(); } } diff --git a/Passbook.Generator/Tags/destinationLocationDescription.cs b/Passbook.Generator/Tags/destinationLocationDescription.cs index 5c9ac72..8073772 100644 --- a/Passbook.Generator/Tags/destinationLocationDescription.cs +++ b/Passbook.Generator/Tags/destinationLocationDescription.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class DestinationLocationDescription(string value) : SemanticTagBaseValue("destinationLocationDescription", value) { - public class DestinationLocationDescription : SemanticTagBaseValue - { - public DestinationLocationDescription(string value) : base("destinationLocationDescription", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/destinationPlatform.cs b/Passbook.Generator/Tags/destinationPlatform.cs index 1f7d517..96dfa64 100644 --- a/Passbook.Generator/Tags/destinationPlatform.cs +++ b/Passbook.Generator/Tags/destinationPlatform.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class DestinationPlatform(string value) : SemanticTagBaseValue("destinationPlatform", value) { - public class DestinationPlatform : SemanticTagBaseValue - { - public DestinationPlatform(string value) : base("destinationPlatform", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/destinationStationName.cs b/Passbook.Generator/Tags/destinationStationName.cs index 9a39e01..240447b 100644 --- a/Passbook.Generator/Tags/destinationStationName.cs +++ b/Passbook.Generator/Tags/destinationStationName.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +class DestinationStationName(string value) : SemanticTagBaseValue("destinationStationName", value) { - class DestinationStationName : SemanticTagBaseValue - { - public DestinationStationName(string value) : base("destinationStationName", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/destinationTerminal.cs b/Passbook.Generator/Tags/destinationTerminal.cs index ad13bb8..c87fe7e 100644 --- a/Passbook.Generator/Tags/destinationTerminal.cs +++ b/Passbook.Generator/Tags/destinationTerminal.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class DestinationTerminal(string value) : SemanticTagBaseValue("destinationTerminal", value) { - public class DestinationTerminal : SemanticTagBaseValue - { - public DestinationTerminal(string value) : base("destinationTerminal", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/duration.cs b/Passbook.Generator/Tags/duration.cs index d0cf37d..b436b5c 100644 --- a/Passbook.Generator/Tags/duration.cs +++ b/Passbook.Generator/Tags/duration.cs @@ -1,12 +1,6 @@ -using Newtonsoft.Json; - -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags { - public class Duration : SemanticTagBaseValue + public class Duration(double value) : SemanticTagBaseValue("duration", value) { - public Duration(double value) : base("duration", value) - { - // NO OP - } } } diff --git a/Passbook.Generator/Tags/eventEndDate.cs b/Passbook.Generator/Tags/eventEndDate.cs index 9d33334..ba15631 100644 --- a/Passbook.Generator/Tags/eventEndDate.cs +++ b/Passbook.Generator/Tags/eventEndDate.cs @@ -1,14 +1,9 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The date and time the event ends. Use this key for any type of event ticket. +/// +/// ISO 8601 date as string +public class EventEndDate(string value) : SemanticTagBaseValue("eventEndDate", value) { - /// - /// The date and time the event ends. Use this key for any type of event ticket. - /// - public class EventEndDate : SemanticTagBaseValue - { - /// ISO 8601 date as string - public EventEndDate(string value) : base("eventEndDate", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/eventName.cs b/Passbook.Generator/Tags/eventName.cs index d74ffcc..ae93244 100644 --- a/Passbook.Generator/Tags/eventName.cs +++ b/Passbook.Generator/Tags/eventName.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The full name of the event, such as the title of a movie. Use this key for any type of event ticket. +/// +public class EventName(string value) : SemanticTagBaseValue("eventName", value) { - /// - /// The full name of the event, such as the title of a movie. Use this key for any type of event ticket. - /// - public class EventName : SemanticTagBaseValue - { - public EventName(string value) : base("eventName", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/eventStartDate.cs b/Passbook.Generator/Tags/eventStartDate.cs index 82f022b..7524005 100644 --- a/Passbook.Generator/Tags/eventStartDate.cs +++ b/Passbook.Generator/Tags/eventStartDate.cs @@ -1,14 +1,9 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The date and time the event starts. Use this key for any type of event ticket. +/// +/// ISO 8601 date as string +public class EventStartDate(string value) : SemanticTagBaseValue("eventStartDate", value) { - /// - /// The date and time the event starts. Use this key for any type of event ticket. - /// - public class EventStartDate : SemanticTagBaseValue - { - /// ISO 8601 date as string - public EventStartDate(string value) : base("eventStartDate", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/eventType.cs b/Passbook.Generator/Tags/eventType.cs index 4f54478..6618d38 100644 --- a/Passbook.Generator/Tags/eventType.cs +++ b/Passbook.Generator/Tags/eventType.cs @@ -1,22 +1,14 @@ -using Newtonsoft.Json; +using System.Text.Json; -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The type of event. Use this key for any type of event ticket. +/// +public class EventType(EventTypes eventType) : SemanticTag("eventType") { - /// - /// The type of event. Use this key for any type of event ticket. - /// - public class EventType : SemanticTag + public override void WriteValue(Utf8JsonWriter writer) { - private readonly EventTypes _eventType; - - public EventType(EventTypes eventType) : base("eventType") - { - _eventType = eventType; - } - - public override void WriteValue(JsonWriter writer) - { - writer.WriteValue(_eventType.ToString()); - } + writer.WriteStringValue(eventType.ToString()); } } diff --git a/Passbook.Generator/Tags/flightCode.cs b/Passbook.Generator/Tags/flightCode.cs index 8ffa652..5a5d451 100644 --- a/Passbook.Generator/Tags/flightCode.cs +++ b/Passbook.Generator/Tags/flightCode.cs @@ -1,14 +1,9 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The IATA flight code, such as “EX123”. Use this key only for airline boarding passes. +/// +/// +public class FlightCode(string value) : SemanticTagBaseValue("flightCode", value) { - public class FlightCode : SemanticTagBaseValue - { - /// - /// The IATA flight code, such as “EX123”. Use this key only for airline boarding passes. - /// - /// - public FlightCode(string value) : base("flightCode", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/flightNumber.cs b/Passbook.Generator/Tags/flightNumber.cs index 9e71b4c..fb9163f 100644 --- a/Passbook.Generator/Tags/flightNumber.cs +++ b/Passbook.Generator/Tags/flightNumber.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The numeric portion of the IATA flight code, such as 123 for flightCode “EX123”. Use this key only for airline boarding passes. +/// +public class FlightNumber(string value) : SemanticTagBaseValue("flightNumber", value) { - /// - /// The numeric portion of the IATA flight code, such as 123 for flightCode “EX123”. Use this key only for airline boarding passes. - /// - public class FlightNumber : SemanticTagBaseValue - { - public FlightNumber(string value) : base("flightNumber", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/genre.cs b/Passbook.Generator/Tags/genre.cs index 8d89688..85131e5 100644 --- a/Passbook.Generator/Tags/genre.cs +++ b/Passbook.Generator/Tags/genre.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The genre of the performance, such as “Classical”. Use this key for any type of event ticket. +/// +public class Genre(string value) : SemanticTagBaseValue("genre", value) { - /// - /// The genre of the performance, such as “Classical”. Use this key for any type of event ticket. - /// - public class Genre : SemanticTagBaseValue - { - public Genre(string value) : base("genre", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/homeTeamAbbreviation.cs b/Passbook.Generator/Tags/homeTeamAbbreviation.cs index df12d71..23012a9 100644 --- a/Passbook.Generator/Tags/homeTeamAbbreviation.cs +++ b/Passbook.Generator/Tags/homeTeamAbbreviation.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The unique abbreviation of the homee team’s name. Use this key only for a sports event ticket. +/// +public class HomeTeamAbbreviation(string value) : SemanticTagBaseValue("homeTeamAbbreviation", value) { - /// - /// The unique abbreviation of the homee team’s name. Use this key only for a sports event ticket. - /// - public class HomeTeamAbbreviation : SemanticTagBaseValue - { - public HomeTeamAbbreviation(string value) : base("homeTeamAbbreviation", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/homeTeamLocation.cs b/Passbook.Generator/Tags/homeTeamLocation.cs index 4e64c65..3990af8 100644 --- a/Passbook.Generator/Tags/homeTeamLocation.cs +++ b/Passbook.Generator/Tags/homeTeamLocation.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The home location of the home team. Use this key only for a sports event ticket. +/// +public class HomeTeamLocation(string value) : SemanticTagBaseValue("homeTeamLocation", value) { - /// - /// The home location of the home team. Use this key only for a sports event ticket. - /// - public class HomeTeamLocation : SemanticTagBaseValue - { - public HomeTeamLocation(string value) : base("homeTeamLocation", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/homeTeamName.cs b/Passbook.Generator/Tags/homeTeamName.cs index ba60af7..a4a545e 100644 --- a/Passbook.Generator/Tags/homeTeamName.cs +++ b/Passbook.Generator/Tags/homeTeamName.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The name of the home team. Use this key only for a sports event ticket. +/// +public class HomeTeamName(string value) : SemanticTagBaseValue("homeTeamName", value) { - /// - /// The name of the home team. Use this key only for a sports event ticket. - /// - public class HomeTeamName : SemanticTagBaseValue - { - public HomeTeamName(string value) : base("homeTeamName", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/leagueAbbreviation.cs b/Passbook.Generator/Tags/leagueAbbreviation.cs index 8b84df6..7a0350d 100644 --- a/Passbook.Generator/Tags/leagueAbbreviation.cs +++ b/Passbook.Generator/Tags/leagueAbbreviation.cs @@ -1,12 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The abbreviated league name for a sports event. Use this key only for a sports event ticket. +/// +public class LeagueAbbreviation(string value) : SemanticTagBaseValue("leagueAbbreviation", value) { - /// - /// The abbreviated league name for a sports event. Use this key only for a sports event ticket. - /// - public class LeagueAbbreviation : SemanticTagBaseValue - { - public LeagueAbbreviation(string value) : base("leagueAbbreviation", value) - { - } - } } diff --git a/Passbook.Generator/Tags/leagueName.cs b/Passbook.Generator/Tags/leagueName.cs index 96ea8da..caa2226 100644 --- a/Passbook.Generator/Tags/leagueName.cs +++ b/Passbook.Generator/Tags/leagueName.cs @@ -1,12 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The unabbreviated league name for a sports event. Use this key only for a sports event ticket. +/// +public class LeagueName(string value) : SemanticTagBaseValue("leagueName", value) { - /// - /// The unabbreviated league name for a sports event. Use this key only for a sports event ticket. - /// - public class LeagueName : SemanticTagBaseValue - { - public LeagueName(string value) : base("leagueName", value) - { - } - } } diff --git a/Passbook.Generator/Tags/membershipProgramName.cs b/Passbook.Generator/Tags/membershipProgramName.cs index d4cd312..85d3821 100644 --- a/Passbook.Generator/Tags/membershipProgramName.cs +++ b/Passbook.Generator/Tags/membershipProgramName.cs @@ -1,12 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The name of a frequent flyer or loyalty program. Use this key for any type of boarding pass. +/// +public class MembershipProgramName(string value) : SemanticTagBaseValue("membershipProgramName", value) { - /// - /// The name of a frequent flyer or loyalty program. Use this key for any type of boarding pass. - /// - public class MembershipProgramName : SemanticTagBaseValue - { - public MembershipProgramName(string value) : base("membershipProgramName", value) - { - } - } } diff --git a/Passbook.Generator/Tags/membershipProgramNumber.cs b/Passbook.Generator/Tags/membershipProgramNumber.cs index c0812f0..6a4e47a 100644 --- a/Passbook.Generator/Tags/membershipProgramNumber.cs +++ b/Passbook.Generator/Tags/membershipProgramNumber.cs @@ -1,13 +1,9 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The ticketed passenger’s frequent flyer or loyalty number. Use this key for any type of boarding pass. +/// +public class MembershipProgramNumber(string value) : SemanticTagBaseValue("membershipProgramNumber", value) { - /// - /// The ticketed passenger’s frequent flyer or loyalty number. Use this key for any type of boarding pass. - /// - public class MembershipProgramNumber : SemanticTagBaseValue - { - public MembershipProgramNumber(string value) : base("membershipProgramNumber", value) - { - } - } } diff --git a/Passbook.Generator/Tags/originalArrivalDate.cs b/Passbook.Generator/Tags/originalArrivalDate.cs index 4c85ffd..7cd69c3 100644 --- a/Passbook.Generator/Tags/originalArrivalDate.cs +++ b/Passbook.Generator/Tags/originalArrivalDate.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class OriginalArrivalDate(string value) : SemanticTagBaseValue("originalArrivalDate", value) { - public class OriginalArrivalDate : SemanticTagBaseValue - { - public OriginalArrivalDate(string value) : base("originalArrivalDate", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/originalBoardingDate.cs b/Passbook.Generator/Tags/originalBoardingDate.cs index 469eb44..e2a2a3f 100644 --- a/Passbook.Generator/Tags/originalBoardingDate.cs +++ b/Passbook.Generator/Tags/originalBoardingDate.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class OriginalBoardingDate(string value) : SemanticTagBaseValue("originalBoardingDate", value) { - public class OriginalBoardingDate : SemanticTagBaseValue - { - public OriginalBoardingDate(string value) : base("originalBoardingDate", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/originalDepartureDate.cs b/Passbook.Generator/Tags/originalDepartureDate.cs index ba6d99e..93bb968 100644 --- a/Passbook.Generator/Tags/originalDepartureDate.cs +++ b/Passbook.Generator/Tags/originalDepartureDate.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class OriginalDepartureDate(string value) : SemanticTagBaseValue("originalDepartureDate", value) { - public class OriginalDepartureDate : SemanticTagBaseValue - { - public OriginalDepartureDate(string value) : base("originalDepartureDate", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/passengerName.cs b/Passbook.Generator/Tags/passengerName.cs index ecf50f6..035a18d 100644 --- a/Passbook.Generator/Tags/passengerName.cs +++ b/Passbook.Generator/Tags/passengerName.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// An object that represents the name of the passenger. Use this key for any type of boarding pass. +/// +public class PassengerName(string value) : SemanticTagBaseValue("passengerName", value) { - /// - /// An object that represents the name of the passenger. Use this key for any type of boarding pass. - /// - public class PassengerName : SemanticTagBaseValue - { - public PassengerName(string value) : base("passengerName", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/performerNames.cs b/Passbook.Generator/Tags/performerNames.cs index 291eb19..64b98c0 100644 --- a/Passbook.Generator/Tags/performerNames.cs +++ b/Passbook.Generator/Tags/performerNames.cs @@ -1,22 +1,19 @@ -using Newtonsoft.Json; +using System.Text.Json; -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// An array of the full names of the performers and opening acts at the event, in decreasing order of significance. Use this key for any type of event ticket. +/// +public class PerformerNames(params string[] performerNames) : SemanticTag("performerNames") { - /// - /// An array of the full names of the performers and opening acts at the event, in decreasing order of significance. Use this key for any type of event ticket. - /// - public class PerformerNames : SemanticTag + public override void WriteValue(Utf8JsonWriter writer) { - private readonly string[] _performerNames; - - public PerformerNames(params string[] performerNames) : base("performerNames") - { - _performerNames = performerNames; - } - - public override void WriteValue(JsonWriter writer) + writer.WriteStartArray(); + foreach (var performerName in performerNames) { - writer.WriteValue(_performerNames); + writer.WriteStringValue(performerName); } + writer.WriteEndArray(); } } diff --git a/Passbook.Generator/Tags/priorityStatus.cs b/Passbook.Generator/Tags/priorityStatus.cs index d9c4075..11115bc 100644 --- a/Passbook.Generator/Tags/priorityStatus.cs +++ b/Passbook.Generator/Tags/priorityStatus.cs @@ -1,13 +1,8 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +/// +/// The priority status the ticketed passenger holds, such as “Gold” or “Silver”. Use this key for any type of boarding pass. +/// +public class PriorityStatus(string value) : SemanticTagBaseValue("priorityStatus", value) { - /// - /// The priority status the ticketed passenger holds, such as “Gold” or “Silver”. Use this key for any type of boarding pass. - /// - public class PriorityStatus : SemanticTagBaseValue - { - public PriorityStatus(string value) : base("priorityStatus", value) - { - // NO OP - } - } } diff --git a/Passbook.Generator/Tags/seats.cs b/Passbook.Generator/Tags/seats.cs index c2ced89..0bfd5e8 100644 --- a/Passbook.Generator/Tags/seats.cs +++ b/Passbook.Generator/Tags/seats.cs @@ -1,28 +1,20 @@ -using Newtonsoft.Json; +using System.Text.Json; -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class Seats(params Seat[] seats) : SemanticTag("seats") { - public class Seats : SemanticTag + public override void WriteValue(Utf8JsonWriter writer) { - private readonly Seat[] _seats; - - public Seats(params Seat[] seats) : base("seats") + writer.WriteStartArray(); + + foreach(var seat in seats) { - _seats = seats; - } + writer.WriteStartObject(); - public override void WriteValue(JsonWriter writer) - { - writer.WriteStartArray(); - - foreach(var seat in _seats) - { - writer.WriteStartObject(); - - writer.WriteEndObject(); - } - - writer.WriteEndArray(); + writer.WriteEndObject(); } + + writer.WriteEndArray(); } } diff --git a/Passbook.Generator/Tags/securityScreening.cs b/Passbook.Generator/Tags/securityScreening.cs index 62eaf87..a8d44d8 100644 --- a/Passbook.Generator/Tags/securityScreening.cs +++ b/Passbook.Generator/Tags/securityScreening.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class SecurityScreening(string value) : SemanticTagBaseValue("securityScreening", value) { - public class SecurityScreening : SemanticTagBaseValue - { - public SecurityScreening(string value) : base("securityScreening", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/silenceRequested.cs b/Passbook.Generator/Tags/silenceRequested.cs index 4c3894d..c85f5fc 100644 --- a/Passbook.Generator/Tags/silenceRequested.cs +++ b/Passbook.Generator/Tags/silenceRequested.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class SilenceRequested(bool value) : SemanticTagBaseValue("silenceRequested", value) { - public class SilenceRequested : SemanticTagBaseValue - { - public SilenceRequested(bool value) : base("silenceRequested", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/sportName.cs b/Passbook.Generator/Tags/sportName.cs index 43f1315..8a415f2 100644 --- a/Passbook.Generator/Tags/sportName.cs +++ b/Passbook.Generator/Tags/sportName.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class SportName(string value) : SemanticTagBaseValue("sportName", value) { - public class SportName : SemanticTagBaseValue - { - public SportName(string value) : base("sportName", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/totalPrice.cs b/Passbook.Generator/Tags/totalPrice.cs index 67cff5a..d9310c4 100644 --- a/Passbook.Generator/Tags/totalPrice.cs +++ b/Passbook.Generator/Tags/totalPrice.cs @@ -1,25 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json; namespace Passbook.Generator.Tags { - public class TotalPrice : SemanticTag + public class TotalPrice(string amount, string currencyCode) : SemanticTag("totalPrice") { - private readonly string _amount; - private readonly string _currencyCode; - - public TotalPrice(string amount, string currencyCode) : base("totalPrice") - { - _amount = amount; - _currencyCode = currencyCode; - } - - public override void WriteValue(JsonWriter writer) + public override void WriteValue(Utf8JsonWriter writer) { writer.WriteStartObject(); writer.WritePropertyName("amount"); - writer.WriteValue(_amount); + writer.WriteStringValue(amount); writer.WritePropertyName("currencyCode"); - writer.WriteValue(_currencyCode); + writer.WriteStringValue(currencyCode); writer.WriteEndObject(); } } diff --git a/Passbook.Generator/Tags/transitProvider.cs b/Passbook.Generator/Tags/transitProvider.cs index 527cf2e..b14f8a8 100644 --- a/Passbook.Generator/Tags/transitProvider.cs +++ b/Passbook.Generator/Tags/transitProvider.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class TransitProvider(string value) : SemanticTagBaseValue("transitProvider", value) { - public class TransitProvider : SemanticTagBaseValue - { - public TransitProvider(string value) : base("transitProvider", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/transitStatus.cs b/Passbook.Generator/Tags/transitStatus.cs index 8e36b4b..7cae61e 100644 --- a/Passbook.Generator/Tags/transitStatus.cs +++ b/Passbook.Generator/Tags/transitStatus.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class TransitStatus(string value) : SemanticTagBaseValue("transitStatus", value) { - public class TransitStatus : SemanticTagBaseValue - { - public TransitStatus(string value) : base("transitStatus", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/transitStatusReason.cs b/Passbook.Generator/Tags/transitStatusReason.cs index 1c2b240..c59075d 100644 --- a/Passbook.Generator/Tags/transitStatusReason.cs +++ b/Passbook.Generator/Tags/transitStatusReason.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class TransitStatusReason(string value) : SemanticTagBaseValue("transitStatusReason", value) { - public class TransitStatusReason : SemanticTagBaseValue - { - public TransitStatusReason(string value) : base("transitStatusReason", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/vehicleName.cs b/Passbook.Generator/Tags/vehicleName.cs index ebeacff..bd7fcb0 100644 --- a/Passbook.Generator/Tags/vehicleName.cs +++ b/Passbook.Generator/Tags/vehicleName.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class VehicleName(string value) : SemanticTagBaseValue("vehicleName", value) { - public class VehicleName : SemanticTagBaseValue - { - public VehicleName(string value) : base("vehicleName", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/vehicleNumber.cs b/Passbook.Generator/Tags/vehicleNumber.cs index 3f525ca..26574e9 100644 --- a/Passbook.Generator/Tags/vehicleNumber.cs +++ b/Passbook.Generator/Tags/vehicleNumber.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class VehicleNumber(string value) : SemanticTagBaseValue("vehicleNumber", value) { - public class VehicleNumber : SemanticTagBaseValue - { - public VehicleNumber(string value) : base("vehicleNumber", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/vehicleType.cs b/Passbook.Generator/Tags/vehicleType.cs index 8e803ca..11962b6 100644 --- a/Passbook.Generator/Tags/vehicleType.cs +++ b/Passbook.Generator/Tags/vehicleType.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class VehicleType(string value) : SemanticTagBaseValue("vehicleType", value) { - public class VehicleType : SemanticTagBaseValue - { - public VehicleType(string value) : base("vehicleType", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/venueEntrance.cs b/Passbook.Generator/Tags/venueEntrance.cs index ddd9615..65f39c0 100644 --- a/Passbook.Generator/Tags/venueEntrance.cs +++ b/Passbook.Generator/Tags/venueEntrance.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class VenueEntrance(string value) : SemanticTagBaseValue("venueEntrance", value) { - public class VenueEntrance : SemanticTagBaseValue - { - public VenueEntrance(string value) : base("venueEntrance", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/venueLocation.cs b/Passbook.Generator/Tags/venueLocation.cs index 99326b5..ff0b553 100644 --- a/Passbook.Generator/Tags/venueLocation.cs +++ b/Passbook.Generator/Tags/venueLocation.cs @@ -1,26 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json; -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class VenueLocation(double latitude, double longitude) : SemanticTag("venueLocation") { - public class VenueLocation : SemanticTag + public override void WriteValue(Utf8JsonWriter writer) { - private readonly double _latitude; - private readonly double _longitude; - - public VenueLocation(double latitude, double longitude) : base("venueLocation") - { - _latitude = latitude; - _longitude = longitude; - } - - public override void WriteValue(JsonWriter writer) - { - writer.WriteStartObject(); - writer.WritePropertyName("latitude"); - writer.WriteValue(_latitude); - writer.WritePropertyName("longitude"); - writer.WriteValue(_longitude); - writer.WriteEndObject(); - } + writer.WriteStartObject(); + writer.WritePropertyName("latitude"); + writer.WriteNumberValue(latitude); + writer.WritePropertyName("longitude"); + writer.WriteNumberValue(longitude); + writer.WriteEndObject(); } } diff --git a/Passbook.Generator/Tags/venueName.cs b/Passbook.Generator/Tags/venueName.cs index db3a924..3016246 100644 --- a/Passbook.Generator/Tags/venueName.cs +++ b/Passbook.Generator/Tags/venueName.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class VenueName(string value) : SemanticTagBaseValue("venueName", value) { - public class VenueName : SemanticTagBaseValue - { - public VenueName(string value) : base("venueName", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/venuePhoneNumber.cs b/Passbook.Generator/Tags/venuePhoneNumber.cs index ba51e54..67731a4 100644 --- a/Passbook.Generator/Tags/venuePhoneNumber.cs +++ b/Passbook.Generator/Tags/venuePhoneNumber.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class VenuePhoneNumber(string value) : SemanticTagBaseValue("venuePhoneNumber", value) { - public class VenuePhoneNumber : SemanticTagBaseValue - { - public VenuePhoneNumber(string value) : base("venuePhoneNumber", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/venueRoom.cs b/Passbook.Generator/Tags/venueRoom.cs index fcce77e..8683497 100644 --- a/Passbook.Generator/Tags/venueRoom.cs +++ b/Passbook.Generator/Tags/venueRoom.cs @@ -1,10 +1,5 @@ -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class VenueRoom(string value) : SemanticTagBaseValue("venueRoom", value) { - public class VenueRoom : SemanticTagBaseValue - { - public VenueRoom(string value) : base("venueRoom", value) - { - // NO OP - } - } } \ No newline at end of file diff --git a/Passbook.Generator/Tags/wifiAccess.cs b/Passbook.Generator/Tags/wifiAccess.cs index ca48e1d..8478464 100644 --- a/Passbook.Generator/Tags/wifiAccess.cs +++ b/Passbook.Generator/Tags/wifiAccess.cs @@ -1,26 +1,16 @@ -using Newtonsoft.Json; +using System.Text.Json; -namespace Passbook.Generator.Tags +namespace Passbook.Generator.Tags; + +public class WifiAccess(string ssid, string password) : SemanticTag("wifiAccess") { - public class WifiAccess : SemanticTag + public override void WriteValue(Utf8JsonWriter writer) { - private readonly string _ssid; - private readonly string _password; - - public WifiAccess(string ssid, string password) : base("wifiAccess") - { - _ssid = ssid; - _password = password; - } - - public override void WriteValue(JsonWriter writer) - { - writer.WriteStartObject(); - writer.WritePropertyName("password"); - writer.WriteValue(_ssid); - writer.WritePropertyName("ssid"); - writer.WriteValue(_password); - writer.WriteEndObject(); - } + writer.WriteStartObject(); + writer.WritePropertyName("ssid"); + writer.WriteStringValue(ssid); + writer.WritePropertyName("password"); + writer.WriteStringValue(password); + writer.WriteEndObject(); } } diff --git a/Passbook.Generator/TransitType.cs b/Passbook.Generator/TransitType.cs index 6bea6e9..bbd7a76 100644 --- a/Passbook.Generator/TransitType.cs +++ b/Passbook.Generator/TransitType.cs @@ -1,11 +1,10 @@ -namespace Passbook.Generator +namespace Passbook.Generator; + +public enum TransitType { - public enum TransitType - { - PKTransitTypeAir, - PKTransitTypeBoat, - PKTransitTypeBus, - PKTransitTypeGeneric, - PKTransitTypeTrain - } + PKTransitTypeAir, + PKTransitTypeBoat, + PKTransitTypeBus, + PKTransitTypeGeneric, + PKTransitTypeTrain }