MongoUserService for SecureSocial(Play Framework)多次持久保存同一用户

时间:2015-01-04 11:57:33

标签: mongodb scala playframework playframework-2.0 securesocial

这是我对UserService类的实现。它是此实现的略微修改版本(http://www.shrikar.com/blog/2013/10/26/playframework-securesocial-and-mongodb/

我将它与默认的securesocial FacebookProvider一起使用。一切正常,除了每次登录时都复制用户条目这一事实。我想只保留用户一次。我认为这是由插件本身处理的,但我不确定是不是这样。我是否应该检查用户是否存在并仅在同一用户没有其他条目时插入已记录的用户?或者还有其他问题?

class MongoUserService(application: Application) extends UserServicePlugin(application) with Controller with MongoController {
  def collection: JSONCollection = db.collection[JSONCollection]("users")
  def tokens: JSONCollection = db.collection[JSONCollection]("tokens")
  val outPutUser = (__ \ "id").json.prune

  def retIdentity(json: JsObject): Identity = {
    val userid = (json \ "userid").as[String]

    val provider = (json \ "provider").as[String]
    val firstname = (json \ "firstname").as[String]
    val lastname = (json \ "lastname").as[String]
    val email = (json \ "email").as[String]
    val avatar = (json \ "avatar").as[String]
    val hash = (json \ "password" \ "hasher").as[String]
    val password = (json \ "password" \ "password").as[String]
    println("password : " + password)
    val salt = (json \ "password" \ "salt").asOpt[String]
    val authmethod = (json \ "authmethod").as[String]

    val identity: IdentityId = new IdentityId(userid, authmethod)
    val authMethod: AuthenticationMethod = new AuthenticationMethod(authmethod)
    val pwdInfo: PasswordInfo = new PasswordInfo(hash, password)
    val serial:Integer=((json\"serial").as[Long]).toInt
    val user: NWOUser = new NWOUser(identity, firstname, lastname, firstname, Some(email), Some(avatar), authMethod, None, None, Some(pwdInfo),serial)
    user
  }

  def generateSerial():Integer={
    val collection = db[JSONCollection]("serial")
    val cursor = collection.find(Json.obj()).cursor[JsObject]
    val futureserial = cursor.headOption.map {
      case Some(i) => i
      case None => 0
    }
    val jobj = Await.result(futureserial, 5 seconds)
    val newSerial=jobj match {
      case x: Boolean => 0
      case _ =>retSerial(jobj.asInstanceOf[JsObject])+1

    }
    collection.update(Json.obj(), Json.obj("$set"->Json.obj("serial"->newSerial))).onComplete {
  case _=>println("updated")
}
    newSerial
  }
  def retSerial(json: JsObject): Integer = {
    println(json)
     val serial=(json \ "serial").as[Long]
     serial.toInt
  }

  def findByEmailAndProvider(email: String, providerId: String): Option[Identity] = {
    val cursor = collection.find(Json.obj("userid" -> email, "provider" -> providerId)).cursor[JsObject]
    val futureuser = cursor.headOption.map {
      case Some(user) => user
      case None => false
    }
    val jobj = Await.result(futureuser, 5 seconds)

    jobj match {
      case x: Boolean => None
      case _ => Some(retIdentity(jobj.asInstanceOf[JsObject]))

    }
  }

  def save(user: Identity): Identity = {

    val email = user.email match {
      case Some(email) => email
      case _ => "N/A"
    }

    val avatar = user.avatarUrl match {
      case Some(url) => url
      case _ => "N/A"
    }
    val savejson = Json.obj(
      "userid" -> user.identityId.userId,
      "provider" -> user.identityId.providerId,
      "firstname" -> user.firstName,
      "lastname" -> user.lastName,
      "email" -> email,
      "avatar" -> avatar,
      "authmethod" -> user.authMethod.method,
      "serial"->this.generateSerial.toLong,
       user.passwordInfo match {
       case None =>"password" -> Json.obj(   "hasher" -> "",
          "password" -> "",
          "salt" -> "")

       case x =>"password" -> Json.obj(
            "hasher" -> x.get.hasher,
          "password" -> x.get.password,
          "salt" -> x.get.salt)

      },
      "created_at" -> Json.obj("$date" -> new Date()),
      "updated_at" -> Json.obj("$date" -> new Date()))
    println(Json.toJson(savejson))
    collection.insert(savejson)
    user
  }

  def find(id: IdentityId): Option[Identity] = {
    findByEmailAndProvider(id.userId, id.providerId)
  }

  def save(token: Token) {
    val tokentosave = Json.obj(
      "uuid" -> token.uuid,
      "email" -> token.email,
      "creation_time" -> Json.obj("$date" -> token.creationTime),
      "expiration_time" -> Json.obj("$date" -> token.expirationTime),
      "isSignUp" -> token.isSignUp)
    tokens.save(tokentosave)
  }

  def findToken(token: String): Option[Token] = {

    val cursor = tokens.find(Json.obj("uuid" -> token)).cursor[JsObject]
    val futureuser = cursor.headOption.map {
      case Some(user) => user
      case None => false
    }
    val jobj = Await.result(futureuser, 5 seconds)
    jobj match {
      case x: Boolean => None
      case obj: JsObject => {
        println(obj)
        val uuid = (obj \ "uuid").as[String]
        val email = (obj \ "email").as[String]
        val created = (obj \ "creation_time" \ "$date").as[Long]
        val expire = (obj \ "expiration_time" \ "$date").as[Long]
        val signup = (obj \ "isSignUp").as[Boolean]
        val df = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
        Some(new Token(uuid, email, new DateTime(created), new DateTime(expire), signup))
      }
    }
  }

  def deleteToken(uuid: String) {}

  def deleteExpiredTokens() {}
}  

1 个答案:

答案 0 :(得分:1)

您可以db.collection.[update][1]使用upsert=true而不是insert来解决此问题。使用此标志,它将在调用不存在时插入由第一个元素(查询)标识的对象,并更新现有的对象。

所以,而不是

collection.insert(savejson)

collection.update(
    Json.obj("userid" -> user.identityId.userId), 
    savejson, 
    Json.obj("upsert" -> true)
)