ilp-core
Version:
ILP core module managing ledger abstraction
208 lines (162 loc) • 6.67 kB
JavaScript
'use strict'
module.exports = SettlementsControllerFactory
// const co = require('co')
const uuid = require('uuid4')
const Auth = require('../lib/auth')
const Log = require('../lib/log')
const Config = require('../lib/config')
const Connector = require('../lib/connector')
const Paypal = require('../lib/paypal')
const Activity = require('../lib/activity')
const SettlementFactory = require('../models/settlement')
const SettlementMethodFactory = require('../models/settlement_method')
const UserFactory = require('../models/user')
const PeerFactory = require('../models/peer')
const NotFoundError = require('../errors/not-found-error')
const InvalidBodyError = require('../errors/invalid-body-error')
SettlementsControllerFactory.constitute = [Auth, Config, Log, SettlementFactory, SettlementMethodFactory, UserFactory, PeerFactory, Connector, Paypal, Activity]
function SettlementsControllerFactory (auth, config, log, Settlement, SettlementMethod, User, Peer, connector, paypal, activity) {
log = log('settlements')
const getDestination = function * (destination) {
return (yield User.findOne({ where: { destination } })) || (yield Peer.findOne({ where: { destination } }))
}
return class SettlementsController {
static init (router) {
// Public
router.get('/destinations/:destination', this.getDestination)
router.post('/settlements/:destination/paypal', this.paypal)
router.get('/settlements/:destination/paypal/execute', this.paypalExecute)
router.get('/settlements/:destination/paypal/cancel', this.paypalCancel)
// User
router.get('/settlements/:id', auth.checkAuth, this.getResource)
// Admin
router.post('/settlements/:destination', auth.checkAuth, this.checkAdmin, this.custom)
}
// TODO move to auth
static * checkAdmin (next) {
if (this.req.user.username === config.data.getIn(['ledger', 'admin', 'user'])) {
return yield next
}
throw new NotFoundError()
}
static * getDestination () {
const destination = yield getDestination(this.params.destination)
if (!destination) {
throw new NotFoundError('Invalid destination')
}
this.body = {
type: destination.hostname ? 'peer' : 'user',
hostname: destination.hostname
}
}
static * settle (params) {
const destination = params.destination
const amount = params.amount
const currency = params.currency
const prefix = `settlement.${uuid()}.`
let ilpAddress
if (destination.hostname) {
ilpAddress = connector.peers[destination.destination].ledgerName + connector.peers[destination.destination].publicKey
} else {
ilpAddress = config.data.getIn(['ledger', 'prefix']) + destination.username
}
// Add the plugin to the connector
yield connector.instance.addPlugin(prefix, {
plugin: 'ilp-plugin-settlement-adapter',
currency,
options: {
prefix,
currency,
amount,
destination: ilpAddress,
connectors: [`${prefix}connector`]
}
})
// Emit a payment that gets routed to destination
yield connector.instance.getPlugin(prefix).receive()
// Remove the plugin
yield connector.instance.removePlugin(prefix)
// Store the settlement in the database
let settlement = new Settlement()
settlement.settlement_method_id = params.settlementMethod.id
if (destination.hostname) {
settlement.peer_id = destination.id
} else {
settlement.user_id = destination.id
}
settlement.amount = amount
settlement.currency = currency
settlement = yield settlement.save()
yield activity.processSettlement(settlement)
return settlement
}
static * custom () {
const destination = yield getDestination(this.params.destination)
if (!destination) throw new NotFoundError('Invalid destination')
const settlementMethod = yield SettlementMethod.findOne({
where: { id: this.body.settlement_method }
})
if (!settlementMethod) {
throw new InvalidBodyError('Invalid settlement method')
}
return yield SettlementsController.settle({
destination,
settlementMethod,
amount: this.body.amount,
currency: this.body.currency
})
}
static * paypal () {
const destination = yield getDestination(this.params.destination)
if (!destination) throw new NotFoundError('Invalid destination')
this.body = {
approvalLink: yield paypal.createPayment(destination.destination, this.body.amount)
}
}
static * paypalExecute () {
const destination = yield getDestination(this.params.destination)
if (!destination) throw new NotFoundError('Invalid destination')
try {
const payment = yield paypal.executePayment(this.query)
// Weird
if (destination.destination !== payment.destination) {
// TODO this is caught locally
throw new InvalidBodyError("Payment destination doesn't match the expected destination")
}
const settlementMethod = yield SettlementMethod.findOne({ where: { type: 'paypal' } })
const settlement = yield SettlementsController.settle({
destination,
settlementMethod,
amount: payment.amount,
// TODO support other currencies
currency: 'USD'
})
// TODO:BEFORE_DEPLOY handle destination.hostname, destination.currency for user
this.redirect(`${config.data.get('client_host')}/settlement/${settlement.id}`)
} catch (e) {
console.log('settlements:174', e)
this.redirect(`${config.data.get('client_host')}/settlement/cancel`)
}
}
static * paypalCancel () {
const destination = yield getDestination(this.params.destination)
if (!destination) throw new NotFoundError('Invalid destination')
this.redirect(`${config.data.get('client_host')}/settle/paypal/${destination.destination}/cancel`)
}
static * getResource () {
const settlement = yield Settlement.findOne({
where: { id: this.params.id },
include: [{ all: true }]
})
if (!settlement) throw new NotFoundError()
this.body = {
amount: settlement.amount,
currency: settlement.currency,
method: settlement.SettlementMethod.type,
date: settlement.created_at,
peer: settlement.Peer && settlement.Peer.hostname,
user: settlement.User && settlement.User.username
}
}
}
}