You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
9.0 KiB
JavaScript

const config = require('../config')
const express = require('../node_modules/express')
const bodyParser = require('../node_modules/body-parser')
const querystring = require('../node_modules/querystring')
const microService = express()
microService.use(bodyParser.json(true))
// MongoDB
const { mongoose, Models } = require('../database')
// MCD API
const rqt = require('../node_modules/rqt')
const MCDSession = new rqt.Session({
host: config.mcdEndpointLegacy,
headers: config.mcdHeadersLegacy,
})
const login = async (botId) => {
let dbId = mongoose.Types.ObjectId(botId)
let $user = await Models.Account.findById(dbId)
console.log('logging in', $user._id)
const res = await MCDSession.jqt('/v2/customer/security/authentication?type=traditional', {
method: 'POST',
type: 'json',
data: {
password: $user.password,
type: "email",
loginUsername: $user.email,
}
})
if (res.status == "ok") {
await Models.Account.findByIdAndUpdate(dbId, {
token: res.details.token,
lastLogin: new Date(),
})
return true
} else
console.error('logging in', $user._id, 'failed', res)
return false
}
const redeemCode = async (userName, token, storeId, offerId, retryOnError) => {
if (retryOnError == undefined) retryOnError = true
console.log('redeemCode', userName, storeId, offerId, retryOnError)
const res = await MCDSession.jqt('/v3/customer/offer/redemption', {
method: 'POST',
type: 'json',
data: {
"marketId": "DE",
"application": "MOT",
"languageName": "de-DE",
"platform": "android",
"offersIds": [`${ offerId }`],
"storeId": storeId,
"userName": userName,
},
headers: {
'Authorization': `Bearer ${ token }`
}
})
if (!!res.Data && !!res.Data.QrCode) {
console.log('SUCC', res)
return res
} else {
if (retryOnError) {
switch (parseInt(res.statusCode)) {
case 10022:
case 10018:
console.log('not logged in')
break;
case -28006: //McDoofnald Exploded
console.error('McDoofnald Exploded')
break;
}
let retry = await redeemCode(userName, token, storeId, offerId, false)
return retry
}
console.error('error', res)
return false
}
}
const removeMCDType = (obj) => {
for(prop in obj) {
if (prop === '$type')
delete obj[prop]
else if (typeof obj[prop] === 'object')
removeMCDType(obj[prop])
}
}
const compressOffers = (users) => {
let output = {}
let uniqueOffers = {}
let $users = Object.keys(users)
for (let i=0;i < $users.length;i++) {
let $user = $users[i]
let $offers = users[ $user ]
for (let j=0;j< $offers.length; j++) {
let $offer = $offers[ j ]
if (!uniqueOffers[ $offer.Id ]) {
uniqueOffers[ $offer.Id ] = {
...$offer,
tokens: []
}
}
uniqueOffers[ $offer.Id ].tokens.push($user)
}
}
return Object.values(uniqueOffers)
}
const customerOffer = async (userName, token, lat, lng, storeId, retryOnError) => {
if (retryOnError == undefined) retryOnError = true
const res = await MCDSession.jqt('/v3/customer/offer?' + querystring.stringify({
marketId: 'DE',
application: 'MOT',
languageName:'de-DE',
platform: 'ios',
userName: userName,
latitude: lat,
longitude: lng,
storeId: storeId || '[]'
}), {
method: 'GET',
headers: {
'Authorization': `Bearer ${ token }`
}
})
if (!!res.ResultCode && parseInt(res.ResultCode) == 1) {
console.log(res)
return res
} else {
console.error('ERROR', res)
if (retryOnError) {
switch (parseInt(res.statusCode)) {
case 10022:
case 10018:
console.log('not logged in')
break;
case -28006: //McDoofnald Exploded
console.error('McDoofnald Exploded')
break;
}
let retry = await customerOffer(userName, token, lat, lng, storeId, false)
return retry
}
return false
}
}
microService
/**
* Creating a Session
*/
.post('/sitzung/:user', async (req, res) => {
const userId = parseInt(req.params.user)
let freeAccounts = await Models.Account
.count({ free: true, active: true })
.limit(config.sessionManager.accountsPerSession);
if (freeAccounts < config.sessionManager.accountsPerSession) {
return res.status(500).json('Bitte versuchen sie es später erneut, es werden gerade neue Accounts erstellt.')
}
let accountsForSession = await Models.Account
.find({ free: true, active: true })
.limit(config.sessionManager.accountsPerSession);
for (let account of accountsForSession) {
await Models.Account.findByIdAndUpdate(account._id, {
free: false,
lastLogin: new Date(),
})
await login(account._id)
}
if (await Models.Session.count({ userId: userId }) > 0) {
await Models.Session.findOneAndDelete({ userId: userId })
}
let session = await Models.Session.create({
userId: userId,
accounts: accountsForSession.map(a => mongoose.Types.ObjectId(a._id)),
})
//console.log(session)
res.json(session)
})
/**
* Selecting a Restaurant and sending fetched Offers to rabbitmq
*/
.post('/sitzung/:user/restaurant/:restaurant', async (req, res) => {
const userId = parseInt(req.params.user)
const restaurantId = mongoose.Types.ObjectId(req.params.restaurant)
if (await Models.Session.count({ userId: userId }) > 0) {
if (await Models.Store.count({ _id: restaurantId }) === 0) {
return res.json('Fehler: Kein Restaurant mit dieser ID')
}
await Models.Session
.findOne({ userId })
.update({ store: restaurantId });
const sessionData = await Models.Session
.findOne({ userId })
.populate('store')
.populate('accounts');
// ES6 <3
const { latitude: storeLat, longitude: storeLon, storeId } = sessionData.store
const output = {}
for (let sessionAccount of sessionData.accounts) {
let offers = await customerOffer(sessionAccount.email, sessionAccount.token, storeLat, storeLon, storeId)
if (!offers || !offers.Data || offers.Data.length === 0) continue; // skip empty responses, in case they somehow are
//offers.Data.map((offer) => console.log(offer.Archived, offer.Expired, offer.Redeemed))
offers.Data = offers.Data.filter((offer) => !offer.Archived && !offer.Expired && !offer.Redeemed)
offers.Data = offers.Data.map((offer) => {
removeMCDType(offer)
return offer
})
output[ sessionAccount._id.toString() ] = offers.Data
}
const cOffers = compressOffers(output)
//console.log(JSON.stringify(cOffers, null, "\t"))
await Models.Session
.findOne({ userId })
.update({ offers: cOffers })
return res.json(cOffers)
}
res.json(false)
})
/**
* Redeems the Offer
*/
.get('/sitzung/:user/angebot/:offer', async (req, res) => {
const userId = parseInt(req.params.user)
const offerId = parseInt(req.params.offer)
const sessionData = await Models.Session
.findOne({ userId })
.populate('store');
let selectedOffer = sessionData.offers.filter((offer) => offer.Id === offerId)
if (selectedOffer.length === 0) return res.json('Kein Angebot mit der ID gefunden')
selectedOffer = selectedOffer[0]
let offerResult = false
for (let i in selectedOffer.tokens) {
let offerAccountID = selectedOffer.tokens[ i ]
try {
// console.log('trying code redemtion with account', offerAccountID)
let account = await Models.Account.findById(mongoose.Types.ObjectId(offerAccountID))
offerResult = await redeemCode(account.email, account.token, sessionData.store.storeId, offerId)
} catch (ex) {
console.error(ex)
}
}
if (!!offerResult) {
removeMCDType(offerResult)
if (offerResult.ResultCode == 1)
return res.json(offerResult.Data)
}
res.json(false)
})
microService.listen(config.sessionManager.port, config.sessionManager.host)