Commit 6ad651bc authored by Magnus Westergaard's avatar Magnus Westergaard
Browse files

Removed patron-client code.

parent 6e8e2e46
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
const bcrypt = require('bcrypt-nodejs')
module.exports = (app) => {
const fetch = require('../fetch')(app)
app.post('/api/v1/login', jsonParser, (request, response) => {
if (!request.body.username || !request.body.password) {
return response.sendStatus(403)
}
let borrowerNumber
let homeBranch
let category
captchaHandler(request.body.captcha)
.then(res => loginHandler(request.body.username))
.then(res => {
if (res.status === 200) {
return res.json()
} else {
return Promise.reject({ message: 'User not found', status: 403 })
}
})
.then(json => {
// only unique user should be able to create user session
if (json.length !== 1) {
return Promise.reject({ message: 'User not unique', status: 403 })
} else {
borrowerNumber = json[ 0 ].borrowernumber
homeBranch = json[ 0 ].branchcode
category = json[ 0 ].categorycode
return fetch('http://xkoha:8081/api/v1/auth/session', {
method: 'POST',
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: `userid=${encodeURIComponent(json[ 0 ].userid)}&password=${encodeURIComponent(request.body.password)}`
})
}
})
.then(res => {
if (res.status === 201) {
request.session.borrowerNumber = borrowerNumber
request.session.homeBranch = homeBranch
request.session.kohaSession = res.headers._headers[ 'set-cookie' ][ 0 ]
request.session.passwordHash = bcrypt.hashSync(request.body.password)
request.session.category = category
return res.json()
} else if (res.status === 429 && process.env.RECAPTCHA_SECRET) {
return Promise.reject({ message: 'To many failed attempts', status: 429 })
} else {
return Promise.reject({ message: 'Could not create session', status: 403 })
}
})
.then(json => {
const borrowerName = request.session.borrowerName = `${json.firstname ? json.firstname : ''}${json.firstname && json.surname ? ' ' : ''}${json.surname ? json.surname : ''}`
response.send({
isLoggedIn: true,
borrowerNumber: request.session.borrowerNumber,
borrowerName: borrowerName,
homeBranch: request.session.homeBranch,
category: request.session.category
})
})
.catch(error => {
console.log(error.message)
response.sendStatus(error.status)
})
})
app.post('/api/v1/logout', (request, response) => {
request.session.destroy((error) => error ? response.sendStatus(500) : response.sendStatus(200))
})
app.get('/api/v1/loginStatus', (request, response) => {
response.send({
isLoggedIn: request.session.borrowerNumber !== undefined,
borrowerNumber: request.session.borrowerNumber,
borrowerName: request.session.borrowerName,
homeBranch: request.session.homeBranch,
category: request.session.category
})
})
function loginHandler (username) {
if (/^[^@ ]+@[^@ ]+$/i.test(username)) {
return fetch(`http://xkoha:8081/api/v1/patrons?email=${username}`)
} else {
return fetch(`http://xkoha:8081/api/v1/patrons?userid=${username}`)
}
}
function captchaHandler (captcha) {
if (!captcha || !process.env.RECAPTCHA_SECRET) {
return Promise.resolve({})
}
return fetch('https://www.google.com/recaptcha/api/siteverify', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: `secret=${process.env.RECAPTCHA_SECRET}&response=${captcha}`
})
.then(res => res.json())
.then(res => {
if (!res.success) {
console.log(res)
return Promise.reject({ message: 'Recaptcha server-side vaildation failed', status: 429 })
}
})
}
}
const isofetch = require('isomorphic-fetch')
const parseString = require('xml2js').parseString
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
module.exports = (app) => {
const fetch = require('../fetch')(app)
app.put('/api/v1/checkouts', jsonParser, (request, response) => {
fetch(`http://xkoha:8081/api/v1/checkouts/${request.body.checkoutId}`, {
method: 'PUT'
}).then(res => {
if (res.status === 200 || res.status === 403) {
return res.json()
} else {
throw Error(`Could not renew loan, status ${res.status}`)
}
})
.then(json => {
if (json && json.date_due) {
response.status(200).send({ newDueDate: json.date_due, issueId: json.issue_id })
} else if (json.error) {
// 403 error needs to be parsed, as it contains reason for renewal not allowed
const msg = parseCheckoutErrorMsg(json)
response.status(403).send(msg)
} else {
throw Error(`Could not parse renewal answer: ${json}`)
}
})
.catch(error => {
console.log(error)
response.sendStatus(500)
})
})
function parseCheckoutErrorMsg (json) {
// get actual error message coming from unauthorised renewal
let msg = ''
if (json.error) {
const m = json.error.match(/\(([^)]+)\)/)
if (m) {
msg = m[1]
}
}
return msg
}
async function xml2jsPromiseParser (xml) {
return new Promise((resolve, reject) => {
parseString(xml, (err, result) => {
if (err) {
reject(err)
} else {
resolve(result)
}
})
})
}
/**
* Register transaction at Nets. The received transactionId can be used as a key to the transaction
*/
app.post('/api/v1/checkouts/start-pay-fine', jsonParser, async (request, response) => {
const merchantId = process.env.NETS_MERCHANT_ID
const token = process.env.NETS_TOKEN
const netsUrl = process.env.NETS_URL
const registerUrl = `${netsUrl}/Netaxept/Register.aspx?merchantId=${encodeURIComponent(merchantId)}&token=${encodeURIComponent(token)}&orderNumber=${request.body.fineId}&amount=10000&CurrencyCode=NOK&redirectUrl=${request.body.origin}/profile/payment-response/`
const terminalUrl = `${netsUrl}/Terminal/default.aspx`
try {
const res = await isofetch(registerUrl)
const xmlResponse = await res.text()
const jsonResponse = await xml2jsPromiseParser(xmlResponse)
console.log(jsonResponse)
const transactionId = jsonResponse.RegisterResponse.TransactionId
const kohaRes = await fetch(`http://xkoha:8081/api/v1/payments/`, {
method: 'POST',
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: `purre_id=${encodeURIComponent(request.body.fineId)}&nets_id=${encodeURIComponent(transactionId)}`
})
const kohaResJson = await kohaRes.json()
console.log('response from koha', kohaResJson)
response.send({
transactionId: transactionId,
merchantId: merchantId,
terminalUrl: terminalUrl
})
} catch (error) {
console.log(error)
response.sendStatus(500)
}
})
/**
* Process transaction at Nets. Operation = SALE to capture instantly
* Flow:
* Process the transaction at nets
* If response from nets is ok, get all loans with fines from koha
* Send extend request for all those loans
* Keep the ids and results for all extend requests
* Capture transaction in Koha
* Send response with ids and results to frontend
*/
app.put('/api/v1/checkouts/process-fine-payment', jsonParser, async (request, response) => {
const merchantId = process.env.NETS_MERCHANT_ID
const token = process.env.NETS_TOKEN
const netsUrl = process.env.NETS_URL
const processUrl = `${netsUrl}/Netaxept/Process.aspx?merchantId=${encodeURIComponent(merchantId)}&token=${encodeURIComponent(token)}&transactionId=${request.body.transactionId}&operation=SALE`
try {
const res = await isofetch(processUrl)
const xmlResponse = await res.text()
const jsonResponse = await xml2jsPromiseParser(xmlResponse)
console.log(JSON.stringify(jsonResponse))
if (jsonResponse.Exception) {
throw Error(`Transaction exception from Nets: ${JSON.stringify(jsonResponse.Exception)}`)
}
const authorizationId = jsonResponse.ProcessResponse.AuthorizationId.join('')
const batchNumber = jsonResponse.ProcessResponse.BatchNumber.join('')
const responseCode = jsonResponse.ProcessResponse.ResponseCode.join('')
const transactionId = jsonResponse.ProcessResponse.TransactionId.join('')
// Get all loans from koha
const loansRes = await fetch(`http://xkoha:8081/api/v1/patrons/${request.session.borrowerNumber}/loansandreservations`)
const loans = await loansRes.json()
// Extend all loans with isPurresak
const successfulExtends = []
for (const loan of loans.loans) {
if (loan.isPurresak) {
const extendRes = await fetch(`http://xkoha:8081/api/v1/checkouts/${loan.id}?override_days=3`, {
method: 'PUT'
})
if (extendRes.status === 200) {
const extend = await extendRes.json()
if (extend && extend.date_due) {
successfulExtends.push(loan.id)
}
}
}
}
const kohaRes = await fetch(`http://xkoha:8081/api/v1/payments/`, {
method: 'PUT',
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: `nets_id=${encodeURIComponent(transactionId)}`
})
const kohaResJson = await kohaRes.json()
console.log(kohaResJson)
response.send({
transactionId: transactionId,
responseCode: responseCode,
authorizationId: authorizationId,
batchNumber: batchNumber,
successfulExtends: successfulExtends
})
} catch (error) {
console.log(error)
response.sendStatus(500)
}
})
app.put('/api/v1/checkouts/email-receipt', jsonParser, async (request, response) => {
const transactionId = request.body.transactionId
const email = request.body.email
const authorizationId = request.body.authorizationId
const successfulExtends = request.body.successfulExtends
console.log(request.body)
try {
if (!/^[^@ ]+@[^@ ]+$/i.test(email)) {
const errors = Object.assign({})
errors['email'] = 'invalidEmail'
response.status(400).send({ errors: errors })
return
}
const kohaRes = await fetch(`http://xkoha:8081/api/v1/messaging/payment-receipt/${request.session.borrowerNumber}`, {
method: 'PUT',
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: `nets_id=${encodeURIComponent(transactionId)}&email=${encodeURIComponent(email)}&authorizationId=${encodeURIComponent(authorizationId)}&successfulExtends=${encodeURIComponent(successfulExtends)}`
})
const kohaResJson = await kohaRes.json()
console.log(kohaResJson)
response.send({
})
} catch (error) {
console.log(error)
response.sendStatus(500)
}
})
}
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
module.exports = (app) => {
const fetch = require('../fetch')(app)
app.post('/api/v1/holds', jsonParser, (request, response) => {
fetch('http://xkoha:8081/api/v1/holds', {
method: 'POST',
body: JSON.stringify({
borrowernumber: Number(request.session.borrowerNumber),
biblionumber: Number(request.body.recordId),
branchcode: request.body.branchCode
})
}).then(res => {
if (res.status === 201) {
response.sendStatus(201)
} else if (res.status === 403) {
return res.json()
} else {
throw Error(`Could not reserve publication ${res.status}`)
}
}).then(err => {
response.status(403)
response.send(err) // pass along Koha's error reason message to client side
}).catch(error => {
console.log(error)
response.sendStatus(500)
})
})
app.delete('/api/v1/holds', jsonParser, (request, response) => {
fetch(`http://xkoha:8081/api/v1/holds/${request.body.reserveId}`, {
method: 'DELETE'
}).then(res => {
if (res.status === 200) {
response.sendStatus(200)
} else {
throw Error('Could not delete reservation')
}
}).catch(error => {
console.log(error)
response.sendStatus(500)
})
})
app.patch('/api/v1/holds', jsonParser, (request, response) => {
const reserveModifications = {}
if (request.body.branchCode !== undefined) {
reserveModifications.branchcode = request.body.branchCode
}
if (request.body.suspended !== undefined) {
reserveModifications.suspend = request.body.suspended ? 1 : 0
}
if (request.body.suspendUntil !== undefined) {
reserveModifications.suspend_until = request.body.suspendUntil
}
fetch(`http://xkoha:8081/api/v1/holds/${request.body.reserveId}`, {
method: 'PATCH',
body: JSON.stringify(reserveModifications)
}).then(res => {
if (res.status === 200) {
response.sendStatus(200)
} else {
response.sendStatus(500)
throw Error('Could not perform holds api operation')
}
}).catch(error => {
console.log(error)
response.sendStatus(500)
})
})
// TODO: add reservationComment to Koha ill backend
app.post('/api/v1/illrequests', jsonParser, (request, response) => {
console.log(request.session)
console.log(request.body)
fetch('http://xkoha:8081/api/v1/illrequests', {
method: 'POST',
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: `remote_library=${encodeURIComponent(request.session.borrowerNumber)}` +
`&biblionumber=${encodeURIComponent(request.body.recordId)}` +
`&userid=${encodeURIComponent(request.body.userId)}` +
`&comment=${encodeURIComponent(request.body.reservationComment)}`
})
.then(res => {
if (res.status === 201) {
response.sendStatus(201)
} else if (res.status >= 400 && res.status <= 409) {
return res.json()
} else {
throw Error(`Unhandled error when placing ill request, status ${res.status}`)
}
})
.then(err => {
response.status(400)
response.send(err) // pass along Koha's error reason message to client side
})
.catch(error => {
console.log(error)
response.sendStatus(500)
})
})
}
const path = require('path')
module.exports = (app) => {
require('./auth')(app)
require('./checkouts')(app)
require('./holds')(app)
require('./profile')(app)
require('./libraries')(app)
require('./registration')(app)
require('./resources')(app)
require('./search')(app)
require('./validation')(app)
app.get('*', (request, response) => {
response.sendFile(path.resolve(__dirname, '..', '..', '..', 'public', 'dist', 'index.html'))
})
}
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
module.exports = (app) => {
const fetch = require('../fetch')(app)
app.get('/api/v1/libraries', jsonParser, (request, response) => {
fetch('http://xkoha:8081/api/v1/libraries')
.then(res => {
if (res.status === 200) {
return res.json()
} else {
response.status(res.status).send(res.statusText)
throw Error()
}
}).then(json => response.status(200).send(filterLibraries(json)))
.catch(error => {
console.log(error)
response.sendStatus(500)
})
})
function filterLibraries (libraries) {
return libraries.filter(l => {
return l.branchnotes === null // filter out branches with branchnotes
}).filter(l => {
if ([ 'hutl', 'fbje', 'fbjo', 'fbol', 'ffur', 'fgry', 'fhol',
'flam', 'fmaj', 'fnor', 'fnyd', 'fopp', 'frik', 'frmm', 'from', 'froa',
'fsme', 'fsto', 'ftor', 'fgam' ].includes(l.branchcode)) {
return true
} else {
// allow test branch codes also
return (/^[a-f0-9]{8}$/.test(l.branchcode))
}
})
}
}
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
const userSettingsMapper = require('../utils/userSettingsMapper')
const bcrypt = require('bcrypt-nodejs')
const userInfoForm = require('../../common/forms/userInfoForm')
const contactDetailsForm = require('../../common/forms/contactDetailsForm')
const extendedValidatorUserInfo = require('../utils/extendedValidator')(userInfoForm)
const extendedValidatorContactDetails = require('../utils/extendedValidator')(contactDetailsForm)
const querystring = require('querystring')
module.exports = (app) => {
const fetch = require('../fetch')(app)
app.post('/api/v1/profile/settings/history', jsonParser, async (request, response) => {
try {
await updatePatronPrivacy(request.session.borrowerNumber, request.body.privacy)
await updateHistoryConsent(request.session.borrowerNumber, request.body.privacy === 0, request.body.hist_cons)
response.status(200).send({success: true})
} catch (error) {
console.log(error)
response.sendStatus(500)
}
})
app.post('/api/v1/profile/settings/historyconsent', jsonParser, async (request, response) => {
const consent = request.body.consent
const privacy = consent ? 0 : 2
const borrowernumber = request.session.borrowerNumber
try {
await updateHistoryConsent(borrowernumber, consent, request.body.previous)
await updatePatronPrivacy(borrowernumber, privacy)
response.status(200).send({success: true})
} catch (error) {
console.log(error)
response.sendStatus(500)
}
})
app.post('/api/v1/profile/history', jsonParser, (request, response) => {
const params = {
offset: request.body.offset || 0,
limit: request.body.limit || 20
}
fetch(`http://xkoha:8081/api/v1/patrons/${request.session.borrowerNumber}/history?${querystring.stringify(params)}`)
.then(res => {
if (res.status === 200) {
return res.json()
} else {
throw Error(res.statusText)
}
}).then(json => response.status(200).send(json))
.catch(error => {
console.log(error)
response.sendStatus(500)
})
})
app.delete('/api/v1/profile/history', jsonParser, (request, response) => {
fetch(`http://xkoha:8081/api/v1/patrons/${request.session.borrowerNumber}/history`, { method: 'DELETE' })
.then(res => {
if (res.status === 200) {
return res.json()
} else {
throw Error(res.statusText)
}
}).then(json => response.status(200).send(json))
.catch(error => {
console.log(error)
response.sendStatus(500)
})
})
app.delete('/api/v1/profile/history/:id', jsonParser, (request, response) => {
fetch(`http://xkoha:8081/api/v1/checkouts/${request.params.id}`, { method: 'DELETE' })
.then(res => {
if (res.status === 200) {
return res.json()
} else {
throw Error(res.statusText)
}
}).then(json => response.status(200).send(json))
.catch(error => {
console.log(error)
response.sendStatus(500)
})