Alexis Hernandez
7 years ago
7 changed files with 213 additions and 0 deletions
@ -0,0 +1,16 @@ |
|||
package controllers |
|||
|
|||
import javax.inject.Inject |
|||
|
|||
import com.xsn.explorer.services.TransactionService |
|||
import controllers.common.{MyJsonController, MyJsonControllerComponents} |
|||
|
|||
class TransactionsController @Inject() ( |
|||
transactionService: TransactionService, |
|||
cc: MyJsonControllerComponents) |
|||
extends MyJsonController(cc) { |
|||
|
|||
def getTransaction(txid: String) = publicNoInput { _ => |
|||
transactionService.getTransaction(txid) |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
package controllers.common |
|||
|
|||
import com.alexitc.playsonify.AbstractAuthenticatorService |
|||
import com.alexitc.playsonify.core.FutureApplicationResult |
|||
import org.scalactic.Good |
|||
import play.api.libs.json.JsValue |
|||
import play.api.mvc.Request |
|||
|
|||
import scala.concurrent.Future |
|||
|
|||
class MyAuthenticatorService extends AbstractAuthenticatorService[Nothing] { |
|||
|
|||
override def authenticate(request: Request[JsValue]): FutureApplicationResult[Nothing] = { |
|||
Future.successful(Good(???)) |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
package controllers.common |
|||
|
|||
import com.alexitc.playsonify.AbstractJsonController |
|||
import com.alexitc.playsonify.models.{ErrorId, ServerError} |
|||
import org.slf4j.LoggerFactory |
|||
|
|||
abstract class MyJsonController(cc: MyJsonControllerComponents) extends AbstractJsonController[Nothing](cc) { |
|||
|
|||
protected val logger = LoggerFactory.getLogger(this.getClass) |
|||
|
|||
override def onServerError(error: ServerError, errorId: ErrorId): Unit = { |
|||
val message = s"Unexpected server error, id = ${errorId.string}, error = $error" |
|||
|
|||
error |
|||
.cause |
|||
.orElse { |
|||
logger.warn(message) |
|||
None |
|||
} |
|||
.foreach { cause => |
|||
// we'll log as error when there is an exception involved |
|||
logger.error(message, cause) |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
package controllers.common |
|||
|
|||
import javax.inject.Inject |
|||
|
|||
import com.alexitc.playsonify.{JsonControllerComponents, PublicErrorRenderer} |
|||
import play.api.mvc.MessagesControllerComponents |
|||
|
|||
import scala.concurrent.ExecutionContext |
|||
|
|||
class MyJsonControllerComponents @Inject() ( |
|||
override val messagesControllerComponents: MessagesControllerComponents, |
|||
override val executionContext: ExecutionContext, |
|||
override val publicErrorRenderer: PublicErrorRenderer, |
|||
override val authenticatorService: MyAuthenticatorService) |
|||
extends JsonControllerComponents[Nothing] |
@ -0,0 +1,121 @@ |
|||
package controllers |
|||
|
|||
import com.alexitc.playsonify.PublicErrorRenderer |
|||
import com.alexitc.playsonify.core.FutureApplicationResult |
|||
import com.xsn.explorer.errors.TransactionNotFoundError |
|||
import com.xsn.explorer.models.TransactionId |
|||
import com.xsn.explorer.services.XSNService |
|||
import controllers.common.MyAPISpec |
|||
import org.scalactic.{Bad, Good} |
|||
import play.api.inject.bind |
|||
import play.api.libs.json.{JsValue, Json} |
|||
import play.api.test.Helpers._ |
|||
|
|||
import scala.concurrent.Future |
|||
|
|||
class TransactionsControllerSpec extends MyAPISpec { |
|||
|
|||
val customXSNService = new XSNService { |
|||
val map = Map( |
|||
TransactionId.from("024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c").get -> |
|||
s""" |
|||
|{ |
|||
| "blockhash": "000003fb382f6892ae96594b81aa916a8923c70701de4e7054aac556c7271ef7", |
|||
| "blocktime": 1520276270, |
|||
| "confirmations": 5347, |
|||
| "height": 1, |
|||
| "hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff010000000000000000232103e8c52f2c5155771492907095753a43ce776e1fa7c5e769a67a9f3db4467ec029ac00000000", |
|||
| "locktime": 0, |
|||
| "size": 98, |
|||
| "time": 1520276270, |
|||
| "txid": "024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c", |
|||
| "version": 1, |
|||
| "vin": [ |
|||
| { |
|||
| "coinbase": "510101", |
|||
| "sequence": 4294967295 |
|||
| } |
|||
| ], |
|||
| "vout": [ |
|||
| { |
|||
| "n": 0, |
|||
| "scriptPubKey": { |
|||
| "addresses": [ |
|||
| "XdJnCKYNwzCz8ATv8Eu75gonaHyfr9qXg9" |
|||
| ], |
|||
| "asm": "03e8c52f2c5155771492907095753a43ce776e1fa7c5e769a67a9f3db4467ec029 OP_CHECKSIG", |
|||
| "hex": "2103e8c52f2c5155771492907095753a43ce776e1fa7c5e769a67a9f3db4467ec029ac", |
|||
| "reqSigs": 1, |
|||
| "type": "pubkey" |
|||
| }, |
|||
| "value": 0, |
|||
| "valueSat": 0 |
|||
| } |
|||
| ] |
|||
|} |
|||
""".stripMargin.trim |
|||
) |
|||
|
|||
override def getTransaction(txid: TransactionId): FutureApplicationResult[JsValue] = { |
|||
val result = map.get(txid) |
|||
.map(s => Json.toJson(s)) |
|||
.map(Good(_)) |
|||
.getOrElse { |
|||
Bad(TransactionNotFoundError).accumulating |
|||
} |
|||
|
|||
Future.successful(result) |
|||
} |
|||
} |
|||
|
|||
override val application = guiceApplicationBuilder |
|||
.overrides(bind[XSNService].to(customXSNService)) |
|||
.build() |
|||
|
|||
"GET /transactions/:txid" should { |
|||
def url(txid: String) = s"/transactions/$txid" |
|||
|
|||
"return an existing transaction" in { |
|||
val txid = "024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c" |
|||
val response = GET(url(txid)) |
|||
|
|||
status(response) mustEqual OK |
|||
// TODO: Match result |
|||
//val json = contentAsJson(response) |
|||
//(json \ "txid").as[String] mustEqual txid |
|||
} |
|||
|
|||
"fail on wrong transaction format" in { |
|||
// 63 characters |
|||
val txid = "000001d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c" |
|||
val response = GET(url(txid)) |
|||
|
|||
status(response) mustEqual BAD_REQUEST |
|||
val json = contentAsJson(response) |
|||
val errorList = (json \ "errors").as[List[JsValue]] |
|||
|
|||
errorList.size mustEqual 1 |
|||
val error = errorList.head |
|||
|
|||
(error \ "type").as[String] mustEqual PublicErrorRenderer.FieldValidationErrorType |
|||
(error \ "field").as[String] mustEqual "transactionId" |
|||
(error \ "message").as[String].nonEmpty mustEqual true |
|||
} |
|||
|
|||
"fail on unknown transaction" in { |
|||
val txid = "0000001d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c" |
|||
val response = GET(url(txid)) |
|||
|
|||
status(response) mustEqual BAD_REQUEST |
|||
val json = contentAsJson(response) |
|||
val errorList = (json \ "errors").as[List[JsValue]] |
|||
|
|||
errorList.size mustEqual 1 |
|||
val error = errorList.head |
|||
|
|||
(error \ "type").as[String] mustEqual PublicErrorRenderer.FieldValidationErrorType |
|||
(error \ "field").as[String] mustEqual "transactionId" |
|||
(error \ "message").as[String].nonEmpty mustEqual true |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,18 @@ |
|||
package controllers.common |
|||
|
|||
import com.alexitc.playsonify.test.PlayAPISpec |
|||
import org.slf4j.LoggerFactory |
|||
import play.api.mvc.Result |
|||
import play.api.test.FakeRequest |
|||
import play.api.test.Helpers._ |
|||
|
|||
import scala.concurrent.Future |
|||
|
|||
trait MyAPISpec extends PlayAPISpec { |
|||
|
|||
protected val logger = LoggerFactory.getLogger(this.getClass) |
|||
|
|||
override protected def log[T](request: FakeRequest[T], response: Future[Result]): Unit = { |
|||
logger.info(s"> REQUEST, $request; < RESPONSE, status = ${status(response)}, body = ${contentAsString(response)}") |
|||
} |
|||
} |
Loading…
Reference in new issue