<commit_before>package com.anchortab.constantcontact

import net.liftweb._
  import common._
  import json._
  import util._
    import Helpers._

import dispatch._
import com.ning.http.client.{Request, RequestBuilder, Response}

object ConstantContact {
  private val endpointBase = "api.constantcontact.com"
  private val endpointVersion = "v2"

  private val oauthBase = "oauth2.constantcontact.com"

  private val clientId = "<KEY>"
  private val clientSecret = "ea69bae4fcf349fd9d413baed8e362c6"
  private val redirectUrl = "https://anchortab.com/oauth/constant-contact"

  case class CodeJsonResponse(code:Int, json:Box[JValue])

  protected object AsCodeJsonResponse extends (Response => CodeJsonResponse) {
    def apply(r:Response) = {
      CodeJsonResponse(
        r.getStatusCode(),
        tryo(as.lift.Json(r))
      )
    }
  }

  case class OAuth2Token(access_token:String, expires_in:Long, token_type:String)

  def oauthAuthorizeUrl = {
    (host(oauthBase) / "oauth2" / "oauth" / "siteowner" / "authorize" <<?
      Map("response_type" -> "code", "client_id" -> clientId, "redirect_uri" -> redirectUrl)).secure.build.getRawUrl
  }

  def retrieveAccessTokenForCode(code:String) = {
    implicit val formats = DefaultFormats
    implicit val accessToken = "" // Don't need this for oauth

    val tokenResponse = runRequest {
      (host(oauthBase) / "oauth2" / "oauth" / "token") <<?
        Map("grant_type" -> "authorization_code", "client_id" -> clientId, "client_secret" -> clientSecret, "code" -> code,
            "redirect_uri" -> redirectUrl)
    }

    for {
      tokenJson <- tokenResponse
      token <- tryo(tokenJson.extract[OAuth2Token])
    } yield {
      token.access_token
    }
  }

  private def runRequest(request:RequestBuilder)(implicit accessToken:String) : Box[JValue] = {
    val response = Http(request.secure > AsCodeJsonResponse).either

    // For the promise to materialize and generate a result based on what we got
    // back from dispatch/the remote service.
    response() match {
      case Right(CodeJsonResponse(code, Full(json))) if code < 300 => Full(json)
      case Right(CodeJsonResponse(code, parseError:Failure)) if code < 300 =>
        Failure("ConstantContact response was not valid JSON.", Empty, parseError)

      case Right(CodeJsonResponse(401, _)) => Failure("Authentication with ConstantContact failed.")
      case Right(CodeJsonResponse(code, _)) => Failure("ConstantContact returned code " + code)
<commit_msg>Parse out error messages when things go wrong.<commit_after>package com.anchortab.constantcontact

import net.liftweb._
  import common._
  import json._
  import util._
    import Helpers._

import dispatch._
import com.ning.http.client.{Request, RequestBuilder, Response}

object ConstantContact {
  private val endpointBase = "api.constantcontact.com"
  private val endpointVersion = "v2"

  private val oauthBase = "oauth2.constantcontact.com"

  private val clientId = "16589cf8-86ae-4fda-82c6-9b4111d3ff98"
  private val clientSecret = "ea69bae4fcf349fd9d413baed8e362c6"
  private val redirectUrl = "https://anchortab.com/oauth/constant-contact"

  case class ConstantContactError(error_key: String, error_message: String)

  case class CodeJsonResponse(code:Int, json:Box[JValue])

  protected object AsCodeJsonResponse extends (Response => CodeJsonResponse) {
    def apply(r:Response) = {
      CodeJsonResponse(
        r.getStatusCode(),
        tryo(as.lift.Json(r))
      )
    }
  }

  case class OAuth2Token(access_token:String, expires_in:Long, token_type:String)

  def oauthAuthorizeUrl = {
    (host(oauthBase) / "oauth2" / "oauth" / "siteowner" / "authorize" <<?
      Map("response_type" -> "code", "client_id" -> clientId, "redirect_uri" -> redirectUrl)).secure.build.getRawUrl
  }

  def retrieveAccessTokenForCode(code:String) = {
    implicit val formats = DefaultFormats
    implicit val accessToken = "" // Don't need this for oauth

    val tokenResponse = runRequest {
      (host(oauthBase) / "oauth2" / "oauth" / "token") <<?
        Map("grant_type" -> "authorization_code", "client_id" -> clientId, "client_secret" -> clientSecret, "code" -> code,
            "redirect_uri" -> redirectUrl)
    }

    for {
      tokenJson <- tokenResponse
      token <- tryo(tokenJson.extract[OAuth2Token])
    } yield {
      token.access_token
    }
  }

  private def runRequest(request:RequestBuilder)(implicit accessToken:String) : Box[JValue] = {
    val response = Http(request.secure > AsCodeJsonResponse).either

    // For the promise to materialize and generate a result based on what we got
    // back from dispatch/the remote service.
    response() match {
      case Right(CodeJsonResponse(code, Full(json))) if code < 300 => Full(json)
      case Right(CodeJsonResponse(code, parseError:Failure)) if code < 300 =>
        Failure("ConstantContact response was not valid JSON.", Empty, parseError)

      case Right(CodeJsonResponse(401, _)) => Failure("Authentication with ConstantContact failed.")

      case Right(CodeJsonResponse(code, Full(json))) =>
        implicit val formats = DefaultFormats
        val errorList = json.extract[List[ConstantContactError]]
        val errorStrings = errorList.map(_.error_message)

        Failure("ConstantContact returned code " + code + " with errors: " + errorStrings)

      case Right(CodeJsonResponse(code, _)) => Failure("ConstantContact returned code: " + code)

{'fraction_non_alphanumeric': 0.1121117441646756, 'fraction_numerical': 0.014703179562580408, 'mean_word_length': 3.732173913043478, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 33, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3835240', 'n_tokens_mistral': 1687, 'n_tokens_neox': 1602, 'n_words': 389}