Files
campaign-site-docker-API/R/cache-fundingrequired.R
2024-01-24 19:52:25 +00:00

240 lines
8.6 KiB
R

cache.fundingrequired <- function() {
monerofund.domain <- "https://monerofund.org/"
# Must have trailing "/"
env.txt <- readLines(".env")
process.env.BTCPAY_API_KEY <- gsub("(BTCPAY_API_KEY=)|( )", "", env.txt[grepl("BTCPAY_API_KEY=", env.txt)])
process.env.BTCPAY_URL <- gsub("(BTCPAY_URL=)|( )", "", env.txt[grepl("BTCPAY_URL=", env.txt)])
process.env.BTCPAY_STORE_ID <- gsub("(BTCPAY_STORE_ID=)|( )", "", env.txt[grepl("BTCPAY_STORE_ID=", env.txt)])
process.env.STRIPE_SECRET_KEY <- gsub("(STRIPE_SECRET_KEY=)|( )", "", env.txt[grepl("STRIPE_SECRET_KEY=", env.txt)])
monerofund.website.text <- tryCatch(readLines(monerofund.domain), error = function(e) {NULL})
if (length(monerofund.website.text) == 0) {
# If the monerofund website is unreachable, return an empty project list
saveRDS(list(), file = "fundingrequiredJSON.rds")
return()
}
buildId <- regmatches(monerofund.website.text, regexpr("buildId\":\"[-_0-9a-zA-Z]+", monerofund.website.text))
buildId <- gsub("buildId\":\"", "", buildId)
projects.json <- tryCatch(RJSONIO::fromJSON(paste0(
monerofund.domain, "_next/data/", buildId, "/projects.json"))$pageProps$projects,
error = function(e) {NULL})
if (length(projects.json) == 0) {
# If the monerofund website is unreachable, return an empty project list
saveRDS(list(), file = "fundingrequiredJSON.rds")
return()
}
needs.funding.index <- NULL
for (i in seq_along(projects.json)) {
if ( grepl("^F", projects.json[[i]]$isFunded, ignore.case = TRUE) ) {
needs.funding.index <- c(needs.funding.index, i)
}
}
if (length(needs.funding.index) == 0) {
saveRDS(list(), file = "fundingrequiredJSON.rds")
return()
}
USD.to.XMR <- tryCatch(
RJSONIO::fromJSON("https://min-api.cryptocompare.com/data/pricemulti?fsyms=XMR&tsyms=USD")$XMR,
error = function(e) {NULL})
if (length(USD.to.XMR) == 0) {
USD.to.XMR <- tryCatch(
as.numeric(RJSONIO::fromJSON("https://api.kraken.com/0/public/Ticker?pair=XMRUSD")$result$XXMRZUSD$a[1]),
error = function(e) {NULL})
}
if (length(USD.to.XMR) == 0) {
USD.to.XMR <- tryCatch(
RJSONIO::fromJSON("https://api.coingecko.com/api/v3/coins/monero?tickers=false&community_data=false&developer_data=false")$market_data$current_price["usd"],
error = function(e) {NULL})
}
if (length(USD.to.XMR) == 0) {
# If all exchange rate APIs are unreachable, return an empty project list
saveRDS(list(), file = "fundingrequiredJSON.rds")
return()
}
json.return <- list()
for (project.index in needs.funding.index) {
slug <- projects.json[[project.index]]$slug
BTCPay.auth <- paste0("token ", process.env.BTCPAY_API_KEY)
invoices.url <- paste0(process.env.BTCPAY_URL, "stores/", process.env.BTCPAY_STORE_ID, "/invoices")
invoices <- tryCatch(
RCurl::getForm(invoices.url,
.opts = list(httpheader = c(
"Content-Type" = "application/json",
Authorization = BTCPay.auth
))
),
error = function(e) {NULL})
if (length(invoices) == 0) {
# If BTCPay is unreachable, return an empty project list
saveRDS(list(), file = "fundingrequiredJSON.rds")
return()
}
invoices <- RJSONIO::fromJSON(invoices, asText = TRUE)
numdonationsxmr <- 0
numdonationsbtc <- 0
totaldonationsxmr <- 0
totaldonationsbtc <- 0
totaldonationsinfiatxmr <- 0
totaldonationsinfiatbtc <- 0
for (i in seq_along(invoices)) {
if (invoices[[i]]$metadata[["orderId"]] != slug) {
next
}
id <- invoices[[i]]$id
dataiter.url <- paste0(process.env.BTCPAY_URL, "stores/", process.env.BTCPAY_STORE_ID, "/invoices/", id, "/payment-methods")
responseiter <- tryCatch(RCurl::getForm(dataiter.url,
.opts = list(httpheader = c(
"Content-Type" = "application/json",
Authorization = BTCPay.auth
))
),
error = function(e) {NULL})
if (length(responseiter) == 0) {
# If BTCPay is unreachable, return an empty project list
saveRDS(list(), file = "fundingrequiredJSON.rds")
return()
}
dataiter <- RJSONIO::fromJSON(responseiter, asText = TRUE)
for (j in seq_along(dataiter)) {
if (dataiter[[j]]$cryptoCode == "XMR" && as.numeric(dataiter[[j]]$paymentMethodPaid) > 0) {
numdonationsxmr <- numdonationsxmr + 1
totaldonationsxmr <- totaldonationsxmr + as.numeric(dataiter[[j]]$paymentMethodPaid)
totaldonationsinfiatxmr <- totaldonationsinfiatxmr + as.numeric(dataiter[[j]]$paymentMethodPaid) * as.numeric(dataiter[[j]]$rate)
}
if (dataiter[[j]]$cryptoCode == "BTC" && as.numeric(dataiter[[j]]$paymentMethodPaid) > 0) {
numdonationsbtc <- numdonationsbtc + 1
totaldonationsbtc <- totaldonationsbtc + as.numeric(dataiter[[j]]$paymentMethodPaid)
totaldonationsinfiatbtc <- totaldonationsinfiatbtc + as.numeric(dataiter[[j]]$paymentMethodPaid) * as.numeric(dataiter[[j]]$rate)
}
}
}
# Get donations to the static XMR address
for (i in seq_along(invoices)) {
static.slug <- paste0(slug, "_STATIC")
if ( invoices[[i]]$metadata[["orderId"]] != static.slug) {
next
}
id <- invoices[[i]]$id
dataiter.url <- paste0(process.env.BTCPAY_URL, "stores/", process.env.BTCPAY_STORE_ID, "/invoices/", id, "/payment-methods")
responseiter <- tryCatch(RCurl::getForm(dataiter.url,
.opts = list(httpheader = c(
"Content-Type" = "application/json",
Authorization = BTCPay.auth
))
),
error = function(e) {NULL})
if (length(responseiter) == 0) {
# If BTCPay is unreachable, return an empty project list
saveRDS(list(), file = "fundingrequiredJSON.rds")
return()
}
dataiter <- RJSONIO::fromJSON(responseiter, asText = TRUE)
for (j in seq_along(dataiter)) {
if (dataiter[[j]]$cryptoCode == "XMR" && as.numeric(dataiter[[j]]$paymentMethodPaid) > 0) {
numdonationsxmr <- numdonationsxmr + length(dataiter[[j]]$payments)
totaldonationsxmr <- totaldonationsxmr + as.numeric(dataiter[[j]]$paymentMethodPaid)
totaldonationsinfiatxmr <- totaldonationsinfiatxmr + as.numeric(dataiter[[j]]$paymentMethodPaid) * as.numeric(dataiter[[j]]$rate)
}
}
}
urlstripe <- "https://api.stripe.com/v1/charges"
authstripe <- paste0("Bearer ", process.env.STRIPE_SECRET_KEY)
responsestripe <- tryCatch(RCurl::getForm(urlstripe,
.opts = list(httpheader = c(
"Content-Type" = "application/json",
Authorization = authstripe
))
),
error = function(e) {NULL})
if (length(responsestripe) == 0) {
# If Stripe is unreachable, return an empty project list
saveRDS(list(), file = "fundingrequiredJSON.rds")
return()
}
responsestripe <- RJSONIO::fromJSON(responsestripe, asText = TRUE)$data
numdonationsfiat <- 0
totaldonationsinfiat <- 0
for (i in seq_along(responsestripe)) {
if ((!("project_slug" %in% names(responsestripe[[i]]$metadata))) ||
responsestripe[[i]]$metadata[["project_slug"]] != slug) {
next
}
numdonationsfiat <- numdonationsfiat + 1
totaldonationsinfiat <- totaldonationsinfiat + responsestripe[[i]]$amount / 100
}
title <- projects.json[[project.index]]$title
date <- projects.json[[project.index]]$date
address <- projects.json[[project.index]]$staticXMRaddress
author <- projects.json[[project.index]]$nym
url <- paste0(monerofund.domain, "projects/", slug)
target_amount <- round(projects.json[[project.index]]$goal / USD.to.XMR) # Round to nearest whole XMR
target_currency <- "XMR"
raised_amount <- totaldonationsxmr + totaldonationsinfiatbtc / USD.to.XMR + totaldonationsinfiat / USD.to.XMR
raised_amount <- round(raised_amount, digits = 2) # Round to hundredths of XMR
contributions <- numdonationsxmr + numdonationsbtc + numdonationsfiat
json.return[[length(json.return) + 1]] <- list(
title = jsonlite::unbox(title),
date = jsonlite::unbox(date),
address = jsonlite::unbox(address),
author = jsonlite::unbox(author),
url = jsonlite::unbox(url),
target_amount = jsonlite::unbox(target_amount),
target_currency = jsonlite::unbox(target_currency),
raised_amount = jsonlite::unbox(raised_amount),
contributions = jsonlite::unbox(contributions)
)
# https://www.rplumber.io/articles/rendering-output.html#boxed-vs-unboxed-json
}
saveRDS(json.return, file = "fundingrequiredJSON.rds")
return()
}
cache.fundingrequired()