1 /*
2  *  Make.org Core API
3  *  Copyright (C) 2018 Make.org
4  *
5  * This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU Affero General Public License as
7  *  published by the Free Software Foundation, either version 3 of the
8  *  License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Affero General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Affero General Public License
16  *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  *
18  */
19 
20 package org.make.core
21 
22 import java.net.URI
23 import java.time.{LocalDate, ZonedDateTime}
24 import io.circe._
25 import io.circe.generic.extras.Configuration
26 
27 import java.time.format.DateTimeFormatter
28 import scala.util.{Failure, Success, Try}
29 
30 trait CirceFormatters {
31 
32   implicit val circeConfig: Configuration = Configuration.default
33 
34   implicit lazy val zonedDateTimeEncoder: Encoder[ZonedDateTime] =
35     (a: ZonedDateTime) => Json.fromString(DateFormatters.default.format(a))
36   implicit lazy val zonedDateTimeDecoder: Decoder[ZonedDateTime] =
37     Decoder.decodeString.emap { date =>
38       Try(ZonedDateTime.from(DateFormatters.default.parse(date)))
39         .orElse(Try(ZonedDateTime.parse(date, DateTimeFormatter.ISO_ZONED_DATE_TIME)).map(_.withFixedOffsetZone())) match {
40         case Success(parsed) => Right(parsed)
41         case Failure(_)      => Left(s"$date is not a valid date, it should match yyyy-MM-ddThh:mm:ss.SSSZ")
42       }
43     }
44 
45   implicit lazy val localDateEncoder: Encoder[LocalDate] = (a: LocalDate) => Json.fromString(a.toString)
46   implicit lazy val localDateDecoder: Decoder[LocalDate] =
47     Decoder.decodeString.emap { date =>
48       Try(LocalDate.parse(date)) match {
49         case Success(parsed) => Right(parsed)
50         case Failure(_)      => Left(s"$date is not a valid date, it should match yyyy-MM-dd")
51       }
52     }
53 
54   implicit def h[A, B](implicit a: Decoder[A], b: Decoder[B]): Decoder[Either[A, B]] = {
55     val l: Decoder[Either[A, B]] = a.map(Left.apply)
56     val r: Decoder[Either[A, B]] = b.map(Right.apply)
57     l.or(r)
58   }
59 
60   implicit def stringValueEncoder[A <: StringValue]: Encoder[A] = a => Json.fromString(a.value)
61 
62   implicit val urlEncoder: Encoder[URI] = Encoder[String].contramap(_.toString)
63   implicit val urlDecoder: Decoder[URI] = Decoder[String].emap { url =>
64     Try(new URI(url)) match {
65       case Success(parsed) => Right(parsed)
66       case Failure(_)      => Left(s"Not a valid URL: $url")
67     }
68   }
69 
70   implicit val durationEncoder: Encoder[scala.concurrent.duration.Duration] =
71     (a: scala.concurrent.duration.Duration) => Json.fromString(a.toString)
72   implicit val durationDecoder: Decoder[scala.concurrent.duration.Duration] =
73     Decoder.decodeString.emap { duration =>
74       Try(scala.concurrent.duration.Duration(duration)).toEither.left.map(_ => s"$duration is not a valid duration")
75     }
76 
77   @SuppressWarnings(Array("org.wartremover.warts.Recursion"))
78   implicit def circe2spray(t: Json): spray.json.JsValue =
79     t.fold(
80       spray.json.JsNull,
81       spray.json.JsBoolean(_),
82       x => spray.json.JsNumber(x.toDouble),
83       spray.json.JsString(_),
84       xs => spray.json.JsArray(xs.map(circe2spray)),
85       x  => spray.json.JsObject(x.keys.zip(x.values.map(circe2spray)).toMap)
86     )
87 
88   @SuppressWarnings(Array("org.wartremover.warts.Recursion"))
89   implicit def spray2circe(t: spray.json.JsValue): Json =
90     t match {
91       case spray.json.JsArray(elements) => Json.fromValues(elements.map(spray2circe))
92       case spray.json.JsObject(fields)  => Json.fromFields(fields.keys.zip(fields.values.map(spray2circe)))
93       case spray.json.JsFalse           => Json.False
94       case spray.json.JsTrue            => Json.True
95       case spray.json.JsNumber(value)   => Json.fromBigDecimal(value)
96       case spray.json.JsString(value)   => Json.fromString(value)
97       case spray.json.JsNull            => Json.Null
98     }
99 
100   @SuppressWarnings(Array("org.wartremover.warts.Throw"))
101   def circeCodec2sprayFormatter[A](implicit encoder: Encoder[A], decoder: Decoder[A]): spray.json.RootJsonFormat[A] =
102     new spray.json.RootJsonFormat[A] {
103       override def read(json: spray.json.JsValue): A =
104         decoder(HCursor.fromJson(json)) match {
105           case Left(error)  => throw error
106           case Right(value) => value
107         }
108       override def write(obj: A): spray.json.JsValue = encoder(obj)
109     }
110 }
Line Stmt Id Pos Tree Symbol Tests Code
32 2832 1050 - 1071 Select io.circe.generic.extras.Configuration.default org.make.core.operation.operationofquestiontest,org.make.api.avro.avrocompatibilitytest,org.make.api.idea.ideasearchenginetest,org.make.api.technical.webflow.desertest,org.make.api.technical.streamutilstest,org.make.api.sequence.sequencecacheactortest,org.make.api.technical.retryablefuturetest,org.make.api.user.persistentuserservicecomponenttest,org.make.api.technical.directives.clientdirectivestest,org.make.api.crmtemplates.crmtemplatesservicetest,org.make.api.sessionhistory.sessionhistorycoordinatortest,org.make.api.makeunittest io.circe.generic.extras.Configuration.default
55 5148 2208 - 2225 Apply io.circe.Decoder.map org.make.api.avro.avrocompatibilitytest,org.make.api.technical.crm.mailjeteventtest a.map[Either[A,B]](((value: A) => scala.`package`.Left.apply[A, Nothing](value)))
55 1032 2214 - 2224 Apply scala.util.Left.apply org.make.api.technical.crm.mailjeteventtest scala.`package`.Left.apply[A, Nothing](value)
56 1108 2261 - 2279 Apply io.circe.Decoder.map org.make.api.avro.avrocompatibilitytest,org.make.api.technical.crm.mailjeteventtest b.map[Either[A,B]](((value: B) => scala.`package`.Right.apply[Nothing, B](value)))
56 3102 2267 - 2278 Apply scala.util.Right.apply org.make.api.technical.crm.mailjeteventtest scala.`package`.Right.apply[Nothing, B](value)
57 4662 2284 - 2291 Apply io.circe.Decoder.or org.make.api.avro.avrocompatibilitytest,org.make.api.technical.crm.mailjeteventtest l.or[Either[A,B]](r)
60 1518 2368 - 2392 Apply io.circe.Json.fromString io.circe.Json.fromString(a.value)
60 3620 2384 - 2391 Select org.make.core.StringValue.value a.value
62 4736 2443 - 2443 Select io.circe.Encoder.encodeString org.make.api.avro.avrocompatibilitytest,org.make.api.technical.webflow.desertest,org.make.api.idea.ideasearchenginetest,org.make.core.operation.operationofquestiontest,org.make.api.sequence.sequencecacheactortest,org.make.api.technical.streamutilstest,org.make.api.technical.retryablefuturetest,org.make.api.user.persistentuserservicecomponenttest,org.make.api.technical.directives.clientdirectivestest,org.make.api.crmtemplates.crmtemplatesservicetest,org.make.api.sessionhistory.sessionhistorycoordinatortest,org.make.api.makeunittest circe.this.Encoder.encodeString
62 2761 2462 - 2472 Apply java.net.URI.toString x$2.toString()
62 1044 2436 - 2473 Apply io.circe.Encoder.contramap org.make.core.operation.operationofquestiontest,org.make.api.technical.webflow.desertest,org.make.api.avro.avrocompatibilitytest,org.make.api.idea.ideasearchenginetest,org.make.api.technical.streamutilstest,org.make.api.sequence.sequencecacheactortest,org.make.api.technical.retryablefuturetest,org.make.api.user.persistentuserservicecomponenttest,org.make.api.technical.directives.clientdirectivestest,org.make.api.crmtemplates.crmtemplatesservicetest,org.make.api.sessionhistory.sessionhistorycoordinatortest,org.make.api.makeunittest io.circe.Encoder.apply[String](circe.this.Encoder.encodeString).contramap[java.net.URI](((x$2: java.net.URI) => x$2.toString()))
63 1560 2516 - 2690 Apply io.circe.Decoder.emap org.make.api.avro.avrocompatibilitytest,org.make.api.idea.ideasearchenginetest,org.make.api.technical.webflow.desertest,org.make.core.operation.operationofquestiontest,org.make.api.sequence.sequencecacheactortest,org.make.api.technical.streamutilstest,org.make.api.technical.retryablefuturetest,org.make.api.user.persistentuserservicecomponenttest,org.make.api.technical.directives.clientdirectivestest,org.make.api.crmtemplates.crmtemplatesservicetest,org.make.api.sessionhistory.sessionhistorycoordinatortest,org.make.api.makeunittest io.circe.Decoder.apply[String](circe.this.Decoder.decodeString).emap[java.net.URI](((url: String) => scala.util.Try.apply[java.net.URI](new java.net.URI(url)) match { case (value: java.net.URI): scala.util.Success[java.net.URI]((parsed @ _)) => scala.`package`.Right.apply[Nothing, java.net.URI](parsed) case (exception: Throwable): scala.util.Failure[java.net.URI](_) => scala.`package`.Left.apply[String, Nothing](("Not a valid URL: ".+(url): String)) }))
63 5003 2523 - 2523 Select io.circe.Decoder.decodeString org.make.api.avro.avrocompatibilitytest,org.make.core.operation.operationofquestiontest,org.make.api.technical.webflow.desertest,org.make.api.idea.ideasearchenginetest,org.make.api.technical.streamutilstest,org.make.api.sequence.sequencecacheactortest,org.make.api.technical.retryablefuturetest,org.make.api.user.persistentuserservicecomponenttest,org.make.api.technical.directives.clientdirectivestest,org.make.api.crmtemplates.crmtemplatesservicetest,org.make.api.sessionhistory.sessionhistorycoordinatortest,org.make.api.makeunittest circe.this.Decoder.decodeString
64 1119 2550 - 2567 Apply scala.util.Try.apply scala.util.Try.apply[java.net.URI](new java.net.URI(url))
64 3050 2554 - 2566 Apply java.net.URI.<init> new java.net.URI(url)
65 4606 2606 - 2619 Apply scala.util.Right.apply scala.`package`.Right.apply[Nothing, java.net.URI](parsed)
66 2691 2650 - 2680 Apply scala.util.Left.apply scala.`package`.Left.apply[String, Nothing](("Not a valid URL: ".+(url): String))
71 2983 2817 - 2844 Apply io.circe.Json.fromString io.circe.Json.fromString(a.toString())
71 4687 2833 - 2843 Apply java.lang.Object.toString a.toString()
73 3208 2927 - 3089 Apply io.circe.Decoder.emap org.make.api.avro.avrocompatibilitytest,org.make.api.idea.ideasearchenginetest,org.make.api.technical.webflow.desertest,org.make.core.operation.operationofquestiontest,org.make.api.sequence.sequencecacheactortest,org.make.api.technical.streamutilstest,org.make.api.technical.retryablefuturetest,org.make.api.user.persistentuserservicecomponenttest,org.make.api.technical.directives.clientdirectivestest,org.make.api.crmtemplates.crmtemplatesservicetest,org.make.api.sessionhistory.sessionhistorycoordinatortest,org.make.api.makeunittest io.circe.Decoder.decodeString.emap[scala.concurrent.duration.Duration](((duration: String) => scala.util.Try.apply[scala.concurrent.duration.Duration](scala.concurrent.duration.Duration.apply(duration)).toEither.left.map[String](((x$3: Throwable) => ("".+(duration).+(" is not a valid duration"): String)))))
74 5254 2973 - 3083 Apply scala.util.Either.LeftProjection.map scala.util.Try.apply[scala.concurrent.duration.Duration](scala.concurrent.duration.Duration.apply(duration)).toEither.left.map[String](((x$3: Throwable) => ("".+(duration).+(" is not a valid duration"): String)))
74 978 2977 - 3021 Apply scala.concurrent.duration.Duration.apply scala.concurrent.duration.Duration.apply(duration)
79 4795 3215 - 3488 Apply io.circe.Json.fold t.fold[spray.json.JsValue](spray.json.JsNull, ((x$4: Boolean) => spray.json.JsBoolean.apply(x$4)), ((x: io.circe.JsonNumber) => spray.json.JsNumber.apply(x.toDouble)), ((x$5: String) => spray.json.JsString.apply(x$5)), ((xs: Vector[io.circe.Json]) => spray.json.JsArray.apply(xs.map[spray.json.JsValue](((t: io.circe.Json) => CirceFormatters.this.circe2spray(t))))), ((x: io.circe.JsonObject) => spray.json.JsObject.apply(x.keys.zip[spray.json.JsValue](x.values.map[spray.json.JsValue](((t: io.circe.Json) => CirceFormatters.this.circe2spray(t)))).toMap[String, spray.json.JsValue](scala.this.<:<.refl[(String, spray.json.JsValue)]))))
80 1063 3229 - 3246 Select spray.json.JsNull spray.json.JsNull
81 4613 3254 - 3277 Apply spray.json.JsBoolean.apply spray.json.JsBoolean.apply(x$4)
82 2368 3310 - 3320 Select io.circe.JsonNumber.toDouble org.make.api.proposal.proposalstatetest x.toDouble
82 1507 3290 - 3321 Apply spray.json.JsNumber.apply org.make.api.proposal.proposalstatetest spray.json.JsNumber.apply(x.toDouble)
83 4861 3329 - 3351 Apply spray.json.JsString.apply spray.json.JsString.apply(x$5)
84 990 3384 - 3403 Apply scala.collection.StrictOptimizedIterableOps.map xs.map[spray.json.JsValue](((t: io.circe.Json) => CirceFormatters.this.circe2spray(t)))
84 5144 3365 - 3404 Apply spray.json.JsArray.apply spray.json.JsArray.apply(xs.map[spray.json.JsValue](((t: io.circe.Json) => CirceFormatters.this.circe2spray(t))))
84 2922 3391 - 3402 Apply org.make.core.CirceFormatters.circe2spray CirceFormatters.this.circe2spray(t)
85 4560 3476 - 3476 TypeApply scala.<:<.refl org.make.api.proposal.proposalstatetest scala.this.<:<.refl[(String, spray.json.JsValue)]
85 3151 3462 - 3473 Apply org.make.core.CirceFormatters.circe2spray org.make.api.proposal.proposalstatetest CirceFormatters.this.circe2spray(t)
85 1514 3418 - 3482 Apply spray.json.JsObject.apply org.make.api.proposal.proposalstatetest spray.json.JsObject.apply(x.keys.zip[spray.json.JsValue](x.values.map[spray.json.JsValue](((t: io.circe.Json) => CirceFormatters.this.circe2spray(t)))).toMap[String, spray.json.JsValue](scala.this.<:<.refl[(String, spray.json.JsValue)]))
85 2629 3438 - 3481 ApplyToImplicitArgs scala.collection.IterableOnceOps.toMap org.make.api.proposal.proposalstatetest x.keys.zip[spray.json.JsValue](x.values.map[spray.json.JsValue](((t: io.circe.Json) => CirceFormatters.this.circe2spray(t)))).toMap[String, spray.json.JsValue](scala.this.<:<.refl[(String, spray.json.JsValue)])
85 1103 3449 - 3474 Apply scala.collection.IterableOps.map org.make.api.proposal.proposalstatetest x.values.map[spray.json.JsValue](((t: io.circe.Json) => CirceFormatters.this.circe2spray(t)))
91 2757 3696 - 3707 Apply org.make.core.CirceFormatters.spray2circe org.make.api.proposal.proposalstatetest CirceFormatters.this.spray2circe(t)
91 1001 3683 - 3708 Apply scala.collection.StrictOptimizedIterableOps.map org.make.api.proposal.proposalstatetest elements.map[io.circe.Json](((t: spray.json.JsValue) => CirceFormatters.this.spray2circe(t)))
91 4139 3667 - 3709 Apply io.circe.Json.fromValues org.make.api.proposal.proposalstatetest io.circe.Json.fromValues(elements.map[io.circe.Json](((t: spray.json.JsValue) => CirceFormatters.this.spray2circe(t))))
92 1387 3785 - 3815 Apply scala.collection.IterableOps.map org.make.api.proposal.proposalstatetest fields.values.map[io.circe.Json](((t: spray.json.JsValue) => CirceFormatters.this.spray2circe(t)))
92 3157 3803 - 3814 Apply org.make.core.CirceFormatters.spray2circe org.make.api.proposal.proposalstatetest CirceFormatters.this.spray2circe(t)
92 4412 3769 - 3816 Apply scala.collection.IterableOps.zip org.make.api.proposal.proposalstatetest fields.keys.zip[io.circe.Json](fields.values.map[io.circe.Json](((t: spray.json.JsValue) => CirceFormatters.this.spray2circe(t))))
92 2509 3753 - 3817 Apply io.circe.Json.fromFields org.make.api.proposal.proposalstatetest io.circe.Json.fromFields(fields.keys.zip[io.circe.Json](fields.values.map[io.circe.Json](((t: spray.json.JsValue) => CirceFormatters.this.spray2circe(t)))))
93 1470 3861 - 3871 Select io.circe.Json.False org.make.api.proposal.proposalstatetest io.circe.Json.False
94 4682 3915 - 3924 Select io.circe.Json.True io.circe.Json.True
95 2768 3968 - 3994 Apply io.circe.Json.fromBigDecimal org.make.api.proposal.proposalstatetest io.circe.Json.fromBigDecimal(value)
96 792 4038 - 4060 Apply io.circe.Json.fromString org.make.api.proposal.proposalstatetest io.circe.Json.fromString(value)
97 4150 4104 - 4113 Select io.circe.Json.Null org.make.api.proposal.proposalstatetest io.circe.Json.Null
102 2708 4301 - 4304 Apply org.make.core.CirceFormatters.$anon.<init> org.make.api.avro.avrocompatibilitytest,org.make.api.technical.elasticsearch.proposalindexationstreamtest,org.make.api.sequence.sequencecacheactortest,org.make.api.makekafkatest,org.make.api.sequence.sequenceapitest,org.make.core.proposal.indexed.proposaltest,org.make.api.sessionhistory.sessionhistorycoordinatortest,org.make.api.technical.crm.crmservicecomponenttest new $anon()
104 4422 4399 - 4430 Apply io.circe.Decoder.apply org.make.api.proposal.proposalstatetest decoder.apply(io.circe.HCursor.fromJson(CirceFormatters.this.spray2circe(json)))
104 1060 4407 - 4429 Apply io.circe.HCursor.fromJson org.make.api.proposal.proposalstatetest io.circe.HCursor.fromJson(CirceFormatters.this.spray2circe(json))
104 3110 4424 - 4428 ApplyImplicitView org.make.core.CirceFormatters.spray2circe org.make.api.proposal.proposalstatetest CirceFormatters.this.spray2circe(json)
105 2614 4470 - 4481 Throw <nosymbol> throw error
108 1474 4584 - 4596 Apply io.circe.Encoder.apply encoder.apply(obj)
108 4955 4584 - 4596 ApplyImplicitView org.make.core.CirceFormatters.circe2spray CirceFormatters.this.circe2spray(encoder.apply(obj))