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
257 lines
9.0 KiB
JavaScript
5 years ago
|
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)
|