diff --git a/build.sbt b/build.sbt index caf745b7..b0bee304 100644 --- a/build.sbt +++ b/build.sbt @@ -26,8 +26,6 @@ val snapshotReleaseSuffix = "-SNAPSHOT" lazy val artifactProductionSettings = Seq( scalaVersion := "2.13.12", - // This old attempt to downgrade scrooge reserved word clashes is now insufficient... https://github.com/twitter/scrooge/issues/259#issuecomment-1900743695 - Compile / scroogeDisableStrict := true, // scrooge 21.3.0: Builds are now only supported for Scala 2.12+ // https://twitter.github.io/scrooge/changelog.html#id11 crossScalaVersions := Seq("2.12.18", scalaVersion.value), diff --git a/json/src/main/scala/com/gu/contentapi/json/CirceDecoders.scala b/json/src/main/scala/com/gu/contentapi/json/CirceDecoders.scala index 60fabb2e..e616b78f 100644 --- a/json/src/main/scala/com/gu/contentapi/json/CirceDecoders.scala +++ b/json/src/main/scala/com/gu/contentapi/json/CirceDecoders.scala @@ -95,6 +95,15 @@ object CirceDecoders { } } + def renameField(oldName: String, newName: String): JsonObject => JsonObject = + o => o(oldName).fold(o)(v => o.remove(oldName).add(newName, v)) + + def renameStartAndEndFields(c: ACursor): ACursor = { + c.withFocus { + _.mapObject (renameField("end", "endDate").andThen(renameField("start", "startDate"))) + } + } + implicit val contentFieldsDecoder: Decoder[ContentFields] = deriveDecoder implicit val editionDecoder: Decoder[Edition] = deriveDecoder implicit val sponsorshipDecoder: Decoder[Sponsorship] = deriveDecoder @@ -104,7 +113,7 @@ object CirceDecoders { implicit val podcastDecoder: Decoder[Podcast] = deriveDecoder implicit val podcastCategoryDecoder: Decoder[PodcastCategory] = deriveDecoder implicit val assetDecoder: Decoder[Asset] = deriveDecoder - implicit val assetFieldsDecoder: Decoder[AssetFields] = deriveDecoder + implicit val assetFieldsDecoder: Decoder[AssetFields] = deriveDecoder[AssetFields].prepare(renameStartAndEndFields) implicit val cartoonVariantDecoder: Decoder[CartoonVariant] = deriveDecoder implicit val cartoonImageDecoder: Decoder[CartoonImage] = deriveDecoder implicit val elementDecoder: Decoder[Element] = deriveDecoder @@ -120,7 +129,7 @@ object CirceDecoders { implicit val standardElementFieldsDecoder: Decoder[StandardElementFields] = deriveDecoder implicit val witnessElementFieldsDecoder: Decoder[WitnessElementFields] = deriveDecoder implicit val richLinkElementFieldsDecoder: Decoder[RichLinkElementFields] = deriveDecoder - implicit val membershipElementFieldsDecoder: Decoder[MembershipElementFields] = deriveDecoder + implicit val membershipElementFieldsDecoder: Decoder[MembershipElementFields] = deriveDecoder[MembershipElementFields].prepare(renameStartAndEndFields) implicit val embedElementFieldsDecoder: Decoder[EmbedElementFields] = deriveDecoder implicit val instagramElementFieldsDecoder: Decoder[InstagramElementFields] = deriveDecoder implicit val commentElementFieldsDecoder: Decoder[CommentElementFields] = deriveDecoder diff --git a/json/src/main/scala/com/gu/contentapi/json/CirceEncoders.scala b/json/src/main/scala/com/gu/contentapi/json/CirceEncoders.scala index d713773b..22c1b142 100644 --- a/json/src/main/scala/com/gu/contentapi/json/CirceEncoders.scala +++ b/json/src/main/scala/com/gu/contentapi/json/CirceEncoders.scala @@ -45,6 +45,13 @@ object CirceEncoders { ) } + def renameField(oldName: String, newName: String): JsonObject => JsonObject = + o => o(oldName).fold(o)(v => o.remove(oldName).add(newName, v)) + + def renameStartAndEndFields: Json => Json = { + _.mapObject(renameField("endDate", "end").andThen(renameField("startDate", "start"))) + } + implicit val contentFieldsEncoder: Encoder[ContentFields] = deriveEncoder implicit val editionEncoder: Encoder[Edition] = deriveEncoder implicit val sponsorshipEncoder: Encoder[Sponsorship] = deriveEncoder @@ -54,7 +61,7 @@ object CirceEncoders { implicit val podcastEncoder: Encoder[Podcast] = deriveEncoder implicit val podcastCategoryEncoder: Encoder[PodcastCategory] = deriveEncoder implicit val assetEncoder: Encoder[Asset] = deriveEncoder - implicit val assetFieldsEncoder: Encoder[AssetFields] = deriveEncoder + implicit val assetFieldsEncoder: Encoder[AssetFields] = deriveEncoder[AssetFields].mapJson(renameStartAndEndFields(_)) implicit val cartoonVariantEncoder: Encoder[CartoonVariant] = deriveEncoder implicit val cartoonImageEncoder: Encoder[CartoonImage] = deriveEncoder implicit val elementEncoder: Encoder[Element] = deriveEncoder @@ -70,7 +77,7 @@ object CirceEncoders { implicit val standardElementFieldsEncoder: Encoder[StandardElementFields] = deriveEncoder implicit val witnessElementFieldsEncoder: Encoder[WitnessElementFields] = deriveEncoder implicit val richLinkElementFieldsEncoder: Encoder[RichLinkElementFields] = deriveEncoder - implicit val membershipElementFieldsEncoder: Encoder[MembershipElementFields] = deriveEncoder + implicit val membershipElementFieldsEncoder: Encoder[MembershipElementFields] = deriveEncoder[MembershipElementFields].mapJson(renameStartAndEndFields(_)) implicit val embedElementFieldsEncoder: Encoder[EmbedElementFields] = deriveEncoder implicit val instagramElementFieldsEncoder: Encoder[InstagramElementFields] = deriveEncoder implicit val commentElementFieldsEncoder: Encoder[CommentElementFields] = deriveEncoder diff --git a/json/src/test/resources/templates/membership-element-no-start-date.json b/json/src/test/resources/templates/membership-element-no-start-date.json new file mode 100644 index 00000000..e33dd213 --- /dev/null +++ b/json/src/test/resources/templates/membership-element-no-start-date.json @@ -0,0 +1,14 @@ +{ + "response": { + "venue": "The Scott room", + "identifier": "guardian-live", + "image": "https://media.guim.co.uk/e50e166a08e4279c352d83fa2f3210186999bd13/0_586_2064_1239/500.jpg", + "price": "£10", + "linkText": "Guardian Live | Guardian Newsroom: Should the UK bomb Syria?", + "location": "The Guardian, Kings Place, 90 York Way, London, N1 9GU", + "end": "2015-09-30T19:30:00Z", + "originalUrl": "https://membership.theguardian.com/event/guardian-live-guardian-newsroom-should-the-uk-bomb-syria-18761779989", + "title": "Guardian Live | Guardian Newsroom: Should the UK bomb Syria?", + "linkPrefix": "Membership Event: " + } +} diff --git a/json/src/test/resources/templates/membership-element.json b/json/src/test/resources/templates/membership-element.json new file mode 100644 index 00000000..c548bb3c --- /dev/null +++ b/json/src/test/resources/templates/membership-element.json @@ -0,0 +1,15 @@ +{ + "response": { + "venue": "The Scott room", + "identifier": "guardian-live", + "image": "https://media.guim.co.uk/e50e166a08e4279c352d83fa2f3210186999bd13/0_586_2064_1239/500.jpg", + "price": "£10", + "start": "2015-09-30T18:00:00Z", + "linkText": "Guardian Live | Guardian Newsroom: Should the UK bomb Syria?", + "location": "The Guardian, Kings Place, 90 York Way, London, N1 9GU", + "end": "2015-09-30T19:30:00Z", + "originalUrl": "https://membership.theguardian.com/event/guardian-live-guardian-newsroom-should-the-uk-bomb-syria-18761779989", + "title": "Guardian Live | Guardian Newsroom: Should the UK bomb Syria?", + "linkPrefix": "Membership Event: " + } +} diff --git a/json/src/test/scala/com/gu/contentapi/json/CirceRoundTripSpec.scala b/json/src/test/scala/com/gu/contentapi/json/CirceRoundTripSpec.scala index 0026c657..184d3da0 100644 --- a/json/src/test/scala/com/gu/contentapi/json/CirceRoundTripSpec.scala +++ b/json/src/test/scala/com/gu/contentapi/json/CirceRoundTripSpec.scala @@ -167,6 +167,11 @@ class CirceRoundTripSpec extends FlatSpec with Matchers { checkRoundTrip[EntitiesResponse]("entities.json") } + it should "serialise and deserialise the renamed fields “startDate” and “endDate” as “start” and “end” respectively" in { + checkRoundTrip[MembershipElementFields]("membership-element.json") + checkRoundTrip[MembershipElementFields]("membership-element-no-start-date.json") + } + def checkRoundTrip[T : Decoder : Encoder]( jsonFileName: String, transformBeforeDecode: Json => Json = identity, diff --git a/models/src/main/thrift/content/v1.thrift b/models/src/main/thrift/content/v1.thrift index 1ef481c9..867a5582 100644 --- a/models/src/main/thrift/content/v1.thrift +++ b/models/src/main/thrift/content/v1.thrift @@ -394,10 +394,9 @@ struct AssetFields { 65: optional string price - 66: optional CapiDateTime start + 66: optional CapiDateTime startDate - /* `end` is a reserved word in scrooge, so use Compile / scroogeDisableStrict := true in build.sbt */ - 67: optional CapiDateTime end + 67: optional CapiDateTime endDate 68: optional bool safeEmbedCode @@ -724,9 +723,8 @@ struct MembershipElementFields { 7: optional string identifier 8: optional string image 9: optional string price - 10: optional CapiDateTime start - /* `end` is a reserved word in scrooge, so use Compile / scroogeDisableStrict := true in build.sbt */ - 11: optional CapiDateTime end + 10: optional CapiDateTime startDate + 11: optional CapiDateTime endDate 12: optional string role }