<commit_before>package com.wbillingsley.handy.appbase

import play.api.mvc.{Request, RequestHeader, AnyContent, AcceptExtractors, BodyParser, BodyParsers, Action, SimpleResult, Result, Results}
import play.api.libs.json.Json
import play.api.libs.iteratee.Enumerator
import com.wbillingsley.handy._
import com.wbillingsley.handyplay.RefConversions._
import JsonConverter._
import scala.language.implicitConversions
import play.api.mvc.EssentialAction
import play.api.libs.iteratee.{Iteratee, Input, Step, Done}    
import scala.concurrent.{Future, Promise}      


case class DataAction[U](implicit ufr:UserFromRequest[U]) extends AcceptExtractors {

  import DataAction._
  
  
  /**
   * An action returning a single item that can be converted into JSON for the requesting user
   */
  def result(block: AppbaseRequest[AnyContent, U] => Ref[Result]) = EssentialAction { implicit request =>
    try {
      val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
        val wrapped = new AppbaseRequest(request)
        val res = for (item <- block(wrapped)) yield ensuringSessionKey(wrapped, item)
        val it = for (r <- res) yield doneIteratee(r)
        
        println("it is " + it)
        
        refEE(it)
      })
      println("ba is " + ba)
      val res = ba.apply(request)
      println("res is " + res)
      res
    } catch {
      case exc:Throwable => {
        println("exc is " + exc)
        refEE(RefFailed(exc))
      }
    }
  }  
    
  
  /**
   * An action returning a single item that can be converted into JSON for the requesting user
   */
  def one[T](block: => Ref[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val res = for (item <- block; j <- jc.toJsonFor(item, wrapped.approval)) yield ensuringSessionKey(wrapped, Results.Ok(j))
            val it = for (r <- res) yield doneIteratee(r)
            refEE(it)
          })
          ba.apply(request)
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }    
  }  
  

  /**
   * An action returning a single item that can be converted into JSON for the requesting user
   */
  def one[T](block: AppbaseRequest[AnyContent, U] => Ref[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val res = for (item <- block(wrapped); j <- jc.toJsonFor(item, wrapped.approval)) yield ensuringSessionKey(wrapped, Results.Ok(j))
            val it = for (r <- res) yield doneIteratee(r)
            refEE(it)
          })
          ba.apply(request)          
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }     
  }


  /**
   * An action returning a single item that can be converted into JSON for the requesting user
   */
  def one[T, A](bodyParser: BodyParser[A])(block: AppbaseRequest[A, U] => Ref[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {    
          val ba = new BodyAction(bodyParser)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val res = for (item <- block(wrapped); j <- jc.toJsonFor(item, wrapped.approval)) yield ensuringSessionKey(wrapped, Results.Ok(j))
            val it = for (r <- res) yield doneIteratee(r)
            refEE(it)
          })
          ba.apply(request)           
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }         
  }
  
  
  /**
   * An action returning a many items that can be converted into JSON for the requesting user
   */
  def many[T](block: => RefMany[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val j = for (item <- block; j <- jc.toJsonFor(item, wrapped.approval)) yield j          
            val en = Enumerator("[") andThen j.enumerate.stringify andThen Enumerator("]") andThen Enumerator.eof[String]
            val r = ensuringSessionKey(wrapped, Results.Ok.stream(en).as("application/json"))
            doneIteratee(r)
          })
          ba.apply(request) 
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }    
  }  
  
  /**
   * An action returning a many items that can be converted into JSON for the requesting user
   */
  def many[T](block: AppbaseRequest[AnyContent, U] => RefMany[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val j = for (item <- block(wrapped); j <- jc.toJsonFor(item, wrapped.approval)) yield j          
            val en = Enumerator("[") andThen j.enumerate.stringify andThen Enumerator("]") andThen Enumerator.eof[String]
            val r = ensuringSessionKey(wrapped, Results.Ok.stream(en).as("application/json"))
            doneIteratee(r)
          })
          ba.apply(request) 
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }        
      }
    }     
  }  
  
  /**
   * An action returning a many items that can be converted into JSON for the requesting user
   */
  def many[T, A](bodyParser: BodyParser[A])(block: AppbaseRequest[A, U] => RefMany[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val action = Action(bodyParser) { implicit request => 
            val wrapped = new AppbaseRequest(request)
            val j = for (item <- block(wrapped); j <- jc.toJsonFor(item, wrapped.approval)) yield j          
            val en = Enumerator("[") andThen j.enumerate.stringify andThen Enumerator("]") andThen Enumerator.eof[String]
            ensuringSessionKey(wrapped, Results.Ok.stream(en).as("application/json"))
          }
          action(request)
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }         
  }  
}


object DataAction extends AcceptExtractors {
  
  def doneIteratee[A](res:Result) = Done[Array[Byte], Result](res, Input.Empty)     
    
  
  /**
   * Solves an annoying issue with EssentialAction and Action not playing nicely together
   * (You can't get back from a Request[B] to a Request[AnyContent])
   */
  class BodyAction[A](parser:BodyParser[A])(block: Request[A] => Iteratee[Array[Byte], Result]) {
    
    
	def apply(rh: RequestHeader): Iteratee[Array[Byte], Result] = {
      
      parser(rh) flatMap { parseResult =>
        parseResult match {
          case Left(r) => doneIteratee(r)
          case Right(a) => {
            val request = Request(rh, a)
            block(request)
          }
        }        
      }
    }
  }  
  
  
  var homeAction:EssentialAction = Action(Results.NotFound("No home action has been set"))
  
  var onNotFound:EssentialAction = Action(Results.NotFound("No 404 action has been set"))
  
  var onForbidden: Refused => EssentialAction = { (refused) => Action(Results.Forbidden("No forbidden action has been set")) }
  
  var onInternalServerError: Throwable => EssentialAction = { (exc) => Action(Results.InternalServerError("No 500 action has been set")) }
    
  
  /**
   * Ensures that the session key is set after this response. 
   * This might however prevent other session variables set in the contained action from sticking
   */
  def forceSession[A](a:Action[A])(implicit ufr:UserFromRequest[_]) = Action(a.parser) { implicit request =>
    val wrapped = new AppbaseRequest(request)
    ensuringSessionKey(wrapped, a(request))
  }
  
  protected def ensuringSessionKey(wrapped:AppbaseRequest[_, _], result:Result) = {
    if (wrapped.session.get("sessionKey") == Some(wrapped.sessionKey)) {
      result
    } else {
      result.withSession(wrapped.session + ("sessionKey" -> wrapped.sessionKey))
    }
  }
  
  
  /**
   * Maps exceptions to HTTP error codes. For instance, you may wish to register your UserError exceptions as BadRequest
   */
  val errorCodeMap = scala.collection.mutable.Map.empty[Class[_], Int]
  
  /**
   * Converts a Ref[Result] to an asychronous result
   */
  implicit def refEE(r:Ref[Iteratee[Array[Byte], Result]])(implicit request:RequestHeader):Iteratee[Array[Byte], Result] = { 
      import scala.concurrent._
      
      val p = promise[Iteratee[Array[Byte], Result]]
      r onComplete(
        onSuccess = p success _,
        onNone = p success {
          request match {
            case Accepts.Html() => onNotFound(request)
            case Accepts.Json() => Action(Results.NotFound(Json.obj("error" -> "not found")))(request)
            case _ => Action(Results.NotFound)(request)
          }
        },
        onFail = _ match {
          case Refused(msg) => p success {
            request match {
              case Accepts.Html() => onForbidden(Refused(msg))(request)
              case Accepts.Json() => Action(Results.Forbidden(Json.obj("error" -> msg)))(request)
              case _ => Action(Results.Forbidden(msg))(request)
            }            
          }
          case exc:Throwable if errorCodeMap.contains(exc.getClass()) => p success {
            request match {
              case Accepts.Json() => Action(Results.Status(errorCodeMap(exc.getClass))(Json.obj("error" -> exc.getMessage())))(request)
              case _ => Action(Results.Status(errorCodeMap(exc.getClass))("User error in non-JSON request: " + exc.getMessage()))(request)
            }            
          }
          case exc:Throwable => p success {
            
            exc.printStackTrace()
            
            request match {
              case Accepts.Html() => onInternalServerError(exc)(request)
              case Accepts.Json() => Action(Results.InternalServerError(Json.obj("error" -> exc.getMessage)))(request)
              case _ => Action(Results.InternalServerError(exc.getMessage))(request)
            }                        
          }
        }
      )
      Iteratee.flatten(p.future)
    
  }
  
  
  /**
   * Converts a Ref[Result] to an asychronous result
   *
  implicit def refResultToResult(r:Ref[Result])(implicit request:Request[AnyContent]) = {
    Results.Async {
      import scala.concurrent._
      
      val p = promise[Result]
      r onComplete(
        onSuccess = p success _,
        onNone = p success {
          request match {
            case Accepts.Html() => onNotFound(request)
            case Accepts.Json() => Results.NotFound(Json.obj("error" -> "not found"))
            case _ => Results.NotFound
          }
        },
        onFail = _ match {
          case Refused(msg) => p success {
            request match {
              case Accepts.Html() => onForbidden(Refused(msg), request)
              case Accepts.Json() => Results.Forbidden(Json.obj("error" -> msg))
              case _ => Results.Forbidden(msg)
            }            
          }
          case exc:Throwable if errorCodeMap.contains(exc.getClass()) => p success {
            request match {
              case Accepts.Json() => Results.Status(errorCodeMap(exc.getClass))(Json.obj("error" -> exc.getMessage()))
              case _ => Results.Status(errorCodeMap(exc.getClass))("User error in non-JSON request: " + exc.getMessage())
            }            
          }
          case exc:Throwable => p success {
            
            exc.printStackTrace()
            
            request match {
              case Accepts.Html() => onInternalServerError(exc, request)
              case Accepts.Json() => Results.InternalServerError(Json.obj("error" -> exc.getMessage))
              case _ => Results.InternalServerError(exc.getMessage)
            }                        
          }
        }
      )
      p.future
    }
  }  */
  
  
  
}<commit_msg>Supported DataAction.returning.one notation<commit_after>package com.wbillingsley.handy.appbase

import play.api.mvc.{Request, RequestHeader, AnyContent, AcceptExtractors, BodyParser, BodyParsers, Action, SimpleResult, Result, Results}
import play.api.libs.json.Json
import play.api.libs.iteratee.Enumerator
import com.wbillingsley.handy._
import com.wbillingsley.handyplay.RefConversions._
import JsonConverter._
import scala.language.implicitConversions
import play.api.mvc.EssentialAction
import play.api.libs.iteratee.{Iteratee, Input, Step, Done}    
import scala.concurrent.{Future, Promise}      


case class DataAction[U](implicit ufr:UserFromRequest[U]) extends AcceptExtractors {

  import DataAction._
  
  /**
   * An action returning a Result
   */
  def result(block: AppbaseRequest[AnyContent, U] => Ref[Result]) = EssentialAction { implicit request =>
    try {
      val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
        val wrapped = new AppbaseRequest(request)
        val res = for (item <- block(wrapped)) yield ensuringSessionKey(wrapped, item)
        val it = for (r <- res) yield doneIteratee(r)
        refEE(it)
      })
      ba.apply(request)
    } catch {
      case exc:Throwable => refEE(RefFailed(exc))
    }
  }
    
  /**
   * An action returning a Result
   */
  def result(block: => Ref[Result]) = EssentialAction { implicit request =>
    try {
      val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
        val wrapped = new AppbaseRequest(request)
        val res = for (item <- block) yield ensuringSessionKey(wrapped, item)
        val it = for (r <- res) yield doneIteratee(r)
        refEE(it)
      })
      val res = ba.apply(request)
      res
    } catch {
      case exc:Throwable => refEE(RefFailed(exc))
    }
  }
  
  /**
   * An action returning a Result
   */
  def result[A](bodyParser: BodyParser[A])(block: AppbaseRequest[A, U] => Ref[Result]) = EssentialAction { implicit request =>
    try {
      val ba = new BodyAction(bodyParser)({ implicit request => 
        val wrapped = new AppbaseRequest(request)
        val res = for (item <- block(wrapped)) yield ensuringSessionKey(wrapped, item)
        val it = for (r <- res) yield doneIteratee(r)
        refEE(it)
      })
      ba.apply(request)
    } catch {
      case exc:Throwable => refEE(RefFailed(exc))
    }
  }  
  
  
  /**
   * An action returning a single item that can be converted into JSON for the requesting user
   */
  def one[T](block: => Ref[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val res = for (item <- block; j <- jc.toJsonFor(item, wrapped.approval)) yield ensuringSessionKey(wrapped, Results.Ok(j))
            val it = for (r <- res) yield doneIteratee(r)
            refEE(it)
          })
          ba.apply(request)
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }    
  }  
  

  /**
   * An action returning a single item that can be converted into JSON for the requesting user
   */
  def one[T](block: AppbaseRequest[AnyContent, U] => Ref[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val res = for (item <- block(wrapped); j <- jc.toJsonFor(item, wrapped.approval)) yield ensuringSessionKey(wrapped, Results.Ok(j))
            val it = for (r <- res) yield doneIteratee(r)
            refEE(it)
          })
          ba.apply(request)          
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }     
  }


  /**
   * An action returning a single item that can be converted into JSON for the requesting user
   */
  def one[T, A](bodyParser: BodyParser[A])(block: AppbaseRequest[A, U] => Ref[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {    
          val ba = new BodyAction(bodyParser)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val res = for (item <- block(wrapped); j <- jc.toJsonFor(item, wrapped.approval)) yield ensuringSessionKey(wrapped, Results.Ok(j))
            val it = for (r <- res) yield doneIteratee(r)
            refEE(it)
          })
          ba.apply(request)           
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }         
  }
  
  
  /**
   * An action returning a many items that can be converted into JSON for the requesting user
   */
  def many[T](block: => RefMany[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val j = for (item <- block; j <- jc.toJsonFor(item, wrapped.approval)) yield j          
            val en = Enumerator("[") andThen j.enumerate.stringify andThen Enumerator("]") andThen Enumerator.eof[String]
            val r = ensuringSessionKey(wrapped, Results.Ok.stream(en).as("application/json"))
            doneIteratee(r)
          })
          ba.apply(request) 
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }    
  }  
  
  /**
   * An action returning a many items that can be converted into JSON for the requesting user
   */
  def many[T](block: AppbaseRequest[AnyContent, U] => RefMany[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val ba = new BodyAction(BodyParsers.parse.anyContent)({ implicit request => 
            val wrapped = new AppbaseRequest(request)
            val j = for (item <- block(wrapped); j <- jc.toJsonFor(item, wrapped.approval)) yield j          
            val en = Enumerator("[") andThen j.enumerate.stringify andThen Enumerator("]") andThen Enumerator.eof[String]
            val r = ensuringSessionKey(wrapped, Results.Ok.stream(en).as("application/json"))
            doneIteratee(r)
          })
          ba.apply(request) 
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }        
      }
    }     
  }  
  
  /**
   * An action returning a many items that can be converted into JSON for the requesting user
   */
  def many[T, A](bodyParser: BodyParser[A])(block: AppbaseRequest[A, U] => RefMany[T])(implicit jc:JsonConverter[T, U]) = EssentialAction { implicit request =>
	request match {
      case Accepts.Html() => homeAction(request)
      case Accepts.Json() => {
        try {
          val action = Action(bodyParser) { implicit request => 
            val wrapped = new AppbaseRequest(request)
            val j = for (item <- block(wrapped); j <- jc.toJsonFor(item, wrapped.approval)) yield j          
            val en = Enumerator("[") andThen j.enumerate.stringify andThen Enumerator("]") andThen Enumerator.eof[String]
            ensuringSessionKey(wrapped, Results.Ok.stream(en).as("application/json"))
          }
          action(request)
        } catch {
          case exc:Throwable => refEE(RefFailed(exc))
        }
      }
    }         
  }  
}


object DataAction extends AcceptExtractors {
  
  // Allows syntactic sugar of "DataAction returning one"
  def returning[U](implicit ufr:UserFromRequest[U]) = DataAction()(ufr)
  
  def doneIteratee[A](res:Result) = Done[Array[Byte], Result](res, Input.Empty)     
    
  
  /**
   * Solves an annoying issue with EssentialAction and Action not playing nicely together
   * (You can't get back from a Request[B] to a Request[AnyContent])
   */
  class BodyAction[A](parser:BodyParser[A])(block: Request[A] => Iteratee[Array[Byte], Result]) {
    
    
	def apply(rh: RequestHeader): Iteratee[Array[Byte], Result] = {
      
      parser(rh) flatMap { parseResult =>
        parseResult match {
          case Left(r) => doneIteratee(r)
          case Right(a) => {
            val request = Request(rh, a)
            block(request)
          }
        }        
      }
    }
  }
  
  var homeAction:EssentialAction = Action(Results.NotFound("No home action has been set"))
  
  var onNotFound:EssentialAction = Action(Results.NotFound("No 404 action has been set"))
  
  var onForbidden: Refused => EssentialAction = { (refused) => Action(Results.Forbidden("No forbidden action has been set")) }
  
  var onInternalServerError: Throwable => EssentialAction = { (exc) => Action(Results.InternalServerError("No 500 action has been set")) }
    
  
  /**
   * Ensures that the session key is set after this response. 
   * This might however prevent other session variables set in the contained action from sticking
   */
  def forceSession[A](a:Action[A])(implicit ufr:UserFromRequest[_]) = Action(a.parser) { implicit request =>
    val wrapped = new AppbaseRequest(request)
    ensuringSessionKey(wrapped, a(request))
  }
  
  protected def ensuringSessionKey(wrapped:AppbaseRequest[_, _], result:Result) = {
    if (wrapped.session.get("sessionKey") == Some(wrapped.sessionKey)) {
      result
    } else {
      result.withSession(wrapped.session + ("sessionKey" -> wrapped.sessionKey))
    }
  }
  
  
  /**
   * Maps exceptions to HTTP error codes. For instance, you may wish to register your UserError exceptions as BadRequest
   */
  val errorCodeMap = scala.collection.mutable.Map.empty[Class[_], Int]
  
  /**
   * Converts a Ref[Result] to an asychronous result
   */
  implicit def refEE(r:Ref[Iteratee[Array[Byte], Result]])(implicit request:RequestHeader):Iteratee[Array[Byte], Result] = { 
      import scala.concurrent._
      
      val p = promise[Iteratee[Array[Byte], Result]]
      r onComplete(
        onSuccess = p success _,
        onNone = p success {
          request match {
            case Accepts.Html() => onNotFound(request)
            case Accepts.Json() => Action(Results.NotFound(Json.obj("error" -> "not found")))(request)
            case _ => Action(Results.NotFound)(request)
          }
        },
        onFail = _ match {
          case Refused(msg) => p success {
            request match {
              case Accepts.Html() => onForbidden(Refused(msg))(request)
              case Accepts.Json() => Action(Results.Forbidden(Json.obj("error" -> msg)))(request)
              case _ => Action(Results.Forbidden(msg))(request)
            }            
          }
          case exc:Throwable if errorCodeMap.contains(exc.getClass()) => p success {
            request match {
              case Accepts.Json() => Action(Results.Status(errorCodeMap(exc.getClass))(Json.obj("error" -> exc.getMessage())))(request)
              case _ => Action(Results.Status(errorCodeMap(exc.getClass))("User error in non-JSON request: " + exc.getMessage()))(request)
            }            
          }
          case exc:Throwable => p success {
            
            exc.printStackTrace()
            
            request match {
              case Accepts.Html() => onInternalServerError(exc)(request)
              case Accepts.Json() => Action(Results.InternalServerError(Json.obj("error" -> exc.getMessage)))(request)
              case _ => Action(Results.InternalServerError(exc.getMessage))(request)
            }                        
          }
        }
      )
      Iteratee.flatten(p.future)
    
  }
  
}
{'fraction_non_alphanumeric': 0.11797031688728439, 'fraction_numerical': 0.0004813477737665463, 'mean_word_length': 2.356354334948842, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 165, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6443449', 'n_tokens_mistral': 7269, 'n_tokens_neox': 7196, 'n_words': 1749}