Hello,
I am using Silhouette seed project (https://github.com/mohiva/play-silhouette-seed) together with Silhouette Persistence ReactiveMongo (https://github.com/mohiva/play-silhouette-persistence-reactivemongo) and recieveing an error when user is trying to activate an account.
P.S. There are no errors/warnings during the compiliation.
! @79c262ep5 - Internal server error, for (GET) [/account/activate/e82e0354-a243-411a-8f32-6053ce2c54ca] ->
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[JsResultException: JsResultException(errors:List((/id,List(JsonValidationError(List(error.path.missing),WrappedArray())))))]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:251)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:178)
at play.core.server.AkkaHttpServer$$anonfun$1.applyOrElse(AkkaHttpServer.scala:363)
at play.core.server.AkkaHttpServer$$anonfun$1.applyOrElse(AkkaHttpServer.scala:361)
at scala.concurrent.Future.$anonfun$recoverWith$1(Future.scala:413)
at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55)
at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:91)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
Caused by: play.api.libs.json.JsResultException: JsResultException(errors:List((/id,List(JsonValidationError(List(error.path.missing),WrappedArray())))))
at reactivemongo.play.json.JSONSerializationPack$.deserialize(JSONSerializationPack.scala:61)
at reactivemongo.play.json.JSONSerializationPack$.deserialize(JSONSerializationPack.scala:33)
at reactivemongo.core.protocol.ReplyDocumentIterator$.$anonfun$parse$1(protocol.scala:141)
at scala.collection.Iterator$$anon$10.next(Iterator.scala:457)
at scala.collection.Iterator$ConcatIterator.next(Iterator.scala:227)
at reactivemongo.api.DefaultCursor$Impl.$anonfun$headOption$2(DefaultCursor.scala:332)
at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:654)
at scala.util.Success.$anonfun$map$1(Try.scala:251)
at scala.util.Success.map(Try.scala:209)
at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
AuthTokenDAOImpl.scala looks like this:
/**
* Give access to the [[AuthToken]] object.
*/
class AuthTokenDAOImpl @Inject() (val reactiveMongoApi: ReactiveMongoApi) extends AuthTokenDAO {
def collection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection("silhouette.token"))
def find(id: UUID): Future[Option[AuthToken]] = {
val query = Json.obj("id" -> id)
collection.flatMap(_.find(query, projection = Some(Json.obj("id" -> 0))).one[AuthToken])
}
def findExpired(dateTime: DateTime): Future[Seq[AuthToken]] = {
val query = Json.obj("expiry" -> Json.obj("$lt" -> dateTime))
collection.flatMap(_.find(query, projection = Some(Json.obj("expiry" -> 0)))
.cursor[AuthToken](readPreference = ReadPreference.primary)
.collect[Seq](100, Cursor.FailOnError[Seq[AuthToken]]())
)
}
def save(token: AuthToken): Future[AuthToken] = {
collection.flatMap(_.insert(token))
Future.successful(token)
}
def remove(id: UUID) = onSuccess(collection.flatMap(_.delete().one(Json.obj("_id" -> id))), ())
/**
* Returns some result on success and None on error.
*
* @param result The last result.
* @param entity The entity to return.
* @tparam T The type of the entity.
* @return The entity on success or an exception on error.
*/
private def onSuccess[T](result: Future[WriteResult], entity: T): Future[T] = result.recoverWith {
case e => Future.failed(new MongoException("Got exception from MongoDB", e.getCause))
}.map { r =>
WriteResult.lastError(r) match {
case Some(e) => throw new MongoException(e.message, e)
case _ => entity
}
}
}
AuthTokenServiceImpl.scala
class AuthTokenServiceImpl @Inject() (
authTokenDAO: AuthTokenDAO,
clock: Clock
)(
implicit
ex: ExecutionContext
) extends AuthTokenService {
def create(userID: UUID, expiry: FiniteDuration = 5 minutes) = {
val token = AuthToken(UUID.randomUUID(), userID, clock.now.withZone(DateTimeZone.UTC).plusSeconds(expiry.toSeconds.toInt))
authTokenDAO.save(token)
}
def validate(id: UUID) = authTokenDAO.find(id)
def clean = authTokenDAO.findExpired(clock.now.withZone(DateTimeZone.UTC)).flatMap { tokens =>
Future.sequence(tokens.map { token =>
authTokenDAO.remove(token.id).map(_ => token)
})
}
}
AuthToken.scala
case class AuthToken(id: UUID, userID: UUID, expiry: DateTime)
object AuthToken {
implicit val jsonFormat: OFormat[AuthToken] = Json.format[AuthToken]
}
Activate account method in ActivateAccountController.scala
def activate(token: UUID) = silhouette.UnsecuredAction.async { implicit request: Request[AnyContent] =>
authTokenService.validate(token).flatMap {
case Some(authToken) => userService.retrieve(authToken.userID).flatMap {
case Some(user) if user.loginInfo.providerID == CredentialsProvider.ID =>
userService.save(user.copy(activated = true)).map { _ =>
Redirect(routes.SignInController.view()).flashing("success" -> Messages("account.activated"))
}
case _ => Future.successful(Redirect(routes.SignInController.view()).flashing("error" -> Messages("invalid.activation.link")))
}
case None => Future.successful(Redirect(routes.SignInController.view()).flashing("error" -> Messages("invalid.activation.link")))
}
}
build.sbt libraries:
libraryDependencies ++= Seq(
"com.mohiva" %% "play-silhouette" % "5.0.6",
"com.mohiva" %% "play-silhouette-password-bcrypt" % "5.0.6",
"com.mohiva" %% "play-silhouette-persistence" % "5.0.6",
"com.mohiva" %% "play-silhouette-crypto-jca" % "5.0.6",
"org.webjars" %% "webjars-play" % "2.6.3",
"org.webjars" % "bootstrap" % "3.3.7-1" exclude("org.webjars", "jquery"),
"org.webjars" % "jquery" % "3.2.1",
"net.codingwell" %% "scala-guice" % "4.2.1",
"com.iheart" %% "ficus" % "1.4.3",
"com.typesafe.play" %% "play-mailer" % "6.0.1",
"com.typesafe.play" %% "play-mailer-guice" % "6.0.1",
"com.enragedginger" %% "akka-quartz-scheduler" % "1.6.1-akka-2.5.x",
"com.adrianhurt" %% "play-bootstrap" % "1.4-P26-B3-SNAPSHOT",
"com.mohiva" %% "play-silhouette-testkit" % "5.0.6" % "test",
"org.reactivemongo" %% "play2-reactivemongo" % "0.16.0-play26",
"com.typesafe.play" %% "play-json" % "2.6.10",
"com.typesafe.play" % "play-json-joda_2.12" % "2.6.10",
"com.mohiva" %% "play-silhouette-persistence-reactivemongo" % "5.0.6",
specs2 % Test,
ehcache,
guice,
filters
)
Any ideas what could be wrong ? Seems like instead of /id
it got an List, but it does not seem that I am somwhere defining a List :(.