Add support for API token authorization
To use authorization based on an API token in subsequent queries,
initialize your KorAP connection with
kco <- new("KorAPConnection", apiToken="<API Token>").
In order to make the API token persistent for the currently
used KorAPUrl (you can have one token per KorAPUrl / KorAP server
instance), use persistApiToken(kco). This will store it in your keyring
using the keyring package.
Subsequent new("KorAPConnection") calls will then automatically
retrieve the token from your keying.
To stop using a persisted token, call clearApiToken(kco).
Please note that for DeReKo, authorized queries will behave differently
inside and outside the IDS, because of the special license situation.
This concerns also cached results which do not take into account from
where a request was issued. If you experience problems or unexpected
results, please try kco <- new("KorAPConnection", cache=FALSE) or use
clearCache to clear the cache completely.
Change-Id: Ic956b0dcf03574e63b62d5036622f30a6cf27f8a
diff --git a/R/KorAPConnection.R b/R/KorAPConnection.R
index 013e5b8..d1f55aa 100644
--- a/R/KorAPConnection.R
+++ b/R/KorAPConnection.R
@@ -7,29 +7,53 @@
#' @import utils
#' @import methods
#' @export
-KorAPConnection <- setClass("KorAPConnection", slots=c(KorAPUrl="character", apiVersion="character", apiUrl="character", userAgent="character", timeout="numeric", verbose="logical", cache="logical"))
+KorAPConnection <- setClass("KorAPConnection", slots=c(KorAPUrl="character", apiVersion="character", apiUrl="character", apiToken="character", userAgent="character", timeout="numeric", verbose="logical", cache="logical"))
#' @param .Object KorAPConnection object
#' @param KorAPUrl the URL of the KorAP server instance you want to access.
#' @param apiVersion which version of KorAP's API you want to connect to.
#' @param apiUrl URL of the KorAP web service.
+#' @param apiToken OAuth2 API token. To use authorization based on an API token
+#' in subsequent queries, intialize your KorAP connection with
+#' \code{kco <- new("KorAPConnection", apiToken="<API Token>")}.
+#' In order to make the API
+#' token persistent for the currently used \code{KorAPUrl} (you can have one
+#' token per KorAPUrl / KorAP server instance), use
+#' \code{persistApiToken(kco)}. This will store it in your keyring using the
+#' \code{\link{keyring}} package. Subsequent new("KorAPConnection") calls will
+#' then automatically retrieve the token from your keying. To stop using a
+#' persisted token, call \code{clearApiToken(kco)}. Please note that for
+#' DeReKo, authorized queries will behave differently inside and outside the
+#' IDS, because of the special license situation. This concerns also cached
+#' results which do not take into account from where a request was issued. If
+#' you experience problems or unexpected results, please try \code{kco <-
+#' new("KorAPConnection", cache=FALSE)} or use
+#' \code{\link{clearCache}} to clear the cache completely.
#' @param userAgent user agent string.
#' @param timeout time out in seconds.
-#' @param verbose logical. Decides whether following operations will default to be verbose.
-#' @param cache logical. Decides if API calls are cached locally. You can clear the cache with \code{\link{clearCache}()}.
-#' @return \code{\link{KorAPConnection}} object that can be used e.g. with \code{\link{corpusQuery}}
+#' @param verbose logical. Decides whether following operations will default to
+#' be verbose.
+#' @param cache logical. Decides if API calls are cached locally. You can clear
+#' the cache with \code{\link{clearCache}()}.
+#' @return \code{\link{KorAPConnection}} object that can be used e.g. with
+#' \code{\link{corpusQuery}}
#'
#' @examples
#' kcon <- new("KorAPConnection", verbose = TRUE)
#' kq <- corpusQuery(kcon, "Ameisenplage")
#' kq <- fetchAll(kq)
#'
-#' @note Currently it is not possible to authenticate the client
+#' \dontrun{
+#' kcon <- new("KorAPConnection", verbose = TRUE, apiToken="e739u6eOzkwADQPdVChxFg")
+#' kq <- corpusQuery(kcon, "Ameisenplage", metadataOnly=FALSE)
+#' kq <- fetchAll(kq)
+#' kq@collectedMatches$snippet
+#' }
#'
#' @rdname KorAPConnection-class
#' @export
setMethod("initialize", "KorAPConnection",
- function(.Object, KorAPUrl = "https://korap.ids-mannheim.de/", apiVersion = 'v1.0', apiUrl, userAgent = "R-KorAP-Client", timeout=10, verbose = FALSE, cache = TRUE) {
+ function(.Object, KorAPUrl = "https://korap.ids-mannheim.de/", apiVersion = 'v1.0', apiUrl, apiToken = getApiToken(KorAPUrl), userAgent = "R-KorAP-Client", timeout=10, verbose = FALSE, cache = TRUE) {
.Object <- callNextMethod()
m <- regexpr("https?://[^?]+", KorAPUrl, perl = TRUE)
.Object@KorAPUrl <- regmatches(KorAPUrl, m)
@@ -41,6 +65,7 @@
} else {
.Object@apiUrl = apiUrl
}
+ .Object@apiToken = apiToken
.Object@apiVersion = apiVersion
.Object@userAgent = userAgent
.Object@timeout = timeout
@@ -49,6 +74,50 @@
.Object
})
+apiTokenServiceName <- "RKorAPClientAPIToken"
+
+setGeneric("persistApiToken", function(kco, apiToken) standardGeneric("persistApiToken") )
+
+#' @aliases persistApiToken
+#' @rdname KorAPConnection-class
+#' @import keyring
+#' @export
+#' @examples
+#' \dontrun{
+#' kco <- new("KorAPConnection", apiToken="e739u6eOzkwADQPdVChxFg")
+#' persistApiToken(kco)
+#' }
+#'
+setMethod("persistApiToken", "KorAPConnection", function(kco, apiToken = kco@apiToken) {
+ if (is.null(apiToken))
+ stop("It seems that you have not supplied any API token that could be persisted.", call. = FALSE)
+
+ kco@apiToken <- apiToken
+ key_set_with_value(apiTokenServiceName, kco@KorAPUrl, apiToken)
+})
+
+setGeneric("clearApiToken", function(kco) standardGeneric("clearApiToken") )
+
+#' @aliases clearApiToken
+#' @rdname KorAPConnection-class
+#' @import keyring
+#' @export
+#' @examples
+#' \dontrun{
+#' kco <- new("KorAPConnection")
+#' clearApiToken(kco)
+#' }
+#'
+setMethod("clearApiToken", "KorAPConnection", function(kco) {
+ key_delete("RKorAPClientAPIToken", kco@KorAPUrl)
+})
+
+#' @import keyring
+getApiToken <- function(KorAPUrl) {
+ ifelse("keyring" %in% installed.packages()[,1 ]&& has_keyring_support()
+ && KorAPUrl %in% key_list(service = "RKorAPClientAPIToken"),
+ key_get("RKorAPClientAPIToken", KorAPUrl), NULL)
+}
KorAPCacheSubDir <- function() {
paste0("RKorAPClient_", packageVersion("RKorAPClient"))
@@ -67,12 +136,15 @@
#' @export
setMethod("apiCall", "KorAPConnection", function(kco, url) {
if (kco@cache) {
- parsed <- R.cache::loadCache(dir=KorAPCacheSubDir(), key=list(url))
+ parsed <- R.cache::loadCache(dir=KorAPCacheSubDir(), key=list(url, kco@apiToken))
if (!is.null(parsed)) {
return(parsed)
}
}
- resp <- GET(url, user_agent(kco@userAgent), timeout(kco@timeout))
+ if (!is.null(kco@apiToken))
+ resp <- GET(url, user_agent(kco@userAgent), timeout(kco@timeout), add_headers(Authorization = paste("Bearer", kco@apiToken)))
+ else
+ resp <- GET(url, user_agent(kco@userAgent), timeout(kco@timeout))
if (!http_type(resp) %in% c("application/json", "application/ld+json")) {
stop("API did not return json", call. = FALSE)
}
@@ -90,7 +162,7 @@
stop(message, call. = FALSE)
}
if (kco@cache) {
- R.cache::saveCache(parsed, key = list(url), dir = KorAPCacheSubDir(), compress = TRUE)
+ R.cache::saveCache(parsed, key = list(url, kco@apiToken), dir = KorAPCacheSubDir(), compress = TRUE)
}
parsed
})
diff --git a/R/KorAPQuery.R b/R/KorAPQuery.R
index bd704d5..d9b589c 100644
--- a/R/KorAPQuery.R
+++ b/R/KorAPQuery.R
@@ -157,7 +157,9 @@
remove_rownames()
)}, {
contentFields <- c("snippet")
- fields <- fields[!fields %in% contentFields]
+ if(metadataOnly) {
+ fields <- fields[!fields %in% contentFields]
+ }
request <- paste0('?q=', URLencode(query, reserved=TRUE),
ifelse(vc != '', paste0('&cq=', URLencode(vc, reserved=TRUE)), ''), '&ql=', ql)
webUIRequestUrl <- paste0(kco@KorAPUrl, request)