From 6badb9120d59415db364cfd32090efc23a9771b0 Mon Sep 17 00:00:00 2001 From: Evangelos Papakonstantis Date: Sat, 30 Apr 2016 12:16:40 +0200 Subject: [PATCH] #34 point calculation is now less complex --- .meteor/release | 2 +- .meteor/versions | 162 +++++++++--------- client/layout/message.html | 16 +- client/pages/points.html | 2 +- client/pages/rankings.html | 4 +- client/pages/rankings.js | 105 ------------ common/points.js | 1 + server/observers.js | 21 +-- server/points.js | 336 +++++++++++++++++++++++-------------- 9 files changed, 316 insertions(+), 333 deletions(-) diff --git a/.meteor/release b/.meteor/release index ef5046b..940e0b5 100644 --- a/.meteor/release +++ b/.meteor/release @@ -1 +1 @@ -METEOR@1.3.1 +METEOR@1.3.2.4 diff --git a/.meteor/versions b/.meteor/versions index 972ae30..8e4c4f4 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -1,42 +1,42 @@ -accounts-base@1.2.5 -accounts-password@1.1.7 -allow-deny@1.0.3 -autoupdate@1.2.7 -babel-compiler@6.6.1 -babel-runtime@0.1.7 -base64@1.0.7 -binary-heap@1.0.7 -blaze@2.1.6 -blaze-html-templates@1.0.3 -blaze-tools@1.0.7 -boilerplate-generator@1.0.7 -caching-compiler@1.0.3 -caching-html-compiler@1.0.5 -callback-hook@1.0.7 -check@1.1.3 +accounts-base@1.2.7 +accounts-password@1.1.8 +allow-deny@1.0.4 +autoupdate@1.2.9 +babel-compiler@6.6.4 +babel-runtime@0.1.8 +base64@1.0.8 +binary-heap@1.0.8 +blaze@2.1.7 +blaze-html-templates@1.0.4 +blaze-tools@1.0.8 +boilerplate-generator@1.0.8 +caching-compiler@1.0.4 +caching-html-compiler@1.0.6 +callback-hook@1.0.8 +check@1.2.1 chrismbeckett:toastr@2.1.2_1 -coffeescript@1.0.16 -ddp@1.2.4 -ddp-client@1.2.4 -ddp-common@1.2.4 -ddp-rate-limiter@1.0.3 -ddp-server@1.2.5 -deps@1.0.11 -diff-sequence@1.0.4 -ecmascript@0.4.2 -ecmascript-runtime@0.2.9 -ejson@1.0.10 -email@1.0.11 +coffeescript@1.0.17 +ddp@1.2.5 +ddp-client@1.2.7 +ddp-common@1.2.5 +ddp-rate-limiter@1.0.4 +ddp-server@1.2.6 +deps@1.0.12 +diff-sequence@1.0.5 +ecmascript@0.4.3 +ecmascript-runtime@0.2.10 +ejson@1.0.11 +email@1.0.12 ephemer:reactive-datatables@1.1.0 -es5-shim@4.5.9 -fastclick@1.0.10 +es5-shim@4.5.10 +fastclick@1.0.11 fortawesome:fontawesome@4.5.0 -geojson-utils@1.0.7 -hot-code-push@1.0.3 -html-tools@1.0.8 -htmljs@1.0.8 -http@1.1.4 -id-map@1.0.6 +geojson-utils@1.0.8 +hot-code-push@1.0.4 +html-tools@1.0.9 +htmljs@1.0.9 +http@1.1.5 +id-map@1.0.7 idorecall:email-normalize@1.0.0 iron:controller@1.0.12 iron:core@1.0.11 @@ -49,53 +49,53 @@ iron:url@1.0.11 jparker:crypto-core@0.1.0 jparker:crypto-md5@0.1.1 jparker:gravatar@0.4.1 -jquery@1.11.7 -launch-screen@1.0.10 -livedata@1.0.17 -localstorage@1.0.8 -logging@1.0.11 -meteor@1.1.13 -meteor-base@1.0.3 -minifier-css@1.1.10 -minifier-js@1.1.10 -minimongo@1.0.13 -mobile-experience@1.0.3 -mobile-status-bar@1.0.11 -modules@0.5.2 -modules-runtime@0.6.2 -momentjs:moment@2.12.0 -mongo@1.1.6 -mongo-id@1.0.3 +jquery@1.11.8 +launch-screen@1.0.11 +livedata@1.0.18 +localstorage@1.0.9 +logging@1.0.12 +meteor@1.1.14 +meteor-base@1.0.4 +minifier-css@1.1.11 +minifier-js@1.1.11 +minimongo@1.0.16 +mobile-experience@1.0.4 +mobile-status-bar@1.0.12 +modules@0.6.1 +modules-runtime@0.6.3 +momentjs:moment@2.13.1 +mongo@1.1.7 +mongo-id@1.0.4 nimble:restivus@0.8.10 -npm-bcrypt@0.7.8_2 -npm-mongo@1.4.42 -observe-sequence@1.0.10 -ordered-dict@1.0.6 -promise@0.6.6 +npm-bcrypt@0.8.5 +npm-mongo@1.4.43 +observe-sequence@1.0.11 +ordered-dict@1.0.7 +promise@0.6.7 rajit:bootstrap3-datepicker@1.5.1 -random@1.0.8 -rate-limit@1.0.3 -reactive-dict@1.1.6 -reactive-var@1.0.8 -reload@1.1.7 -retry@1.0.6 -routepolicy@1.0.9 -service-configuration@1.0.8 -session@1.1.4 -sha@1.0.6 +random@1.0.9 +rate-limit@1.0.4 +reactive-dict@1.1.7 +reactive-var@1.0.9 +reload@1.1.8 +retry@1.0.7 +routepolicy@1.0.10 +service-configuration@1.0.9 +session@1.1.5 +sha@1.0.7 simple:json-routes@2.1.0 -spacebars@1.0.10 -spacebars-compiler@1.0.10 -srp@1.0.7 -standard-minifier-css@1.0.5 -standard-minifier-js@1.0.5 -templating@1.1.8 -templating-tools@1.0.3 -tracker@1.0.12 +spacebars@1.0.11 +spacebars-compiler@1.0.11 +srp@1.0.8 +standard-minifier-css@1.0.6 +standard-minifier-js@1.0.6 +templating@1.1.9 +templating-tools@1.0.4 +tracker@1.0.13 twbs:bootstrap@3.3.6 -ui@1.0.10 -underscore@1.0.7 -url@1.0.8 -webapp@1.2.7 -webapp-hashing@1.0.8 +ui@1.0.11 +underscore@1.0.8 +url@1.0.9 +webapp@1.2.8 +webapp-hashing@1.0.9 zenorocha:clipboard@1.5.10 diff --git a/client/layout/message.html b/client/layout/message.html index 6257220..9258bc0 100644 --- a/client/layout/message.html +++ b/client/layout/message.html @@ -1,10 +1,10 @@ diff --git a/client/pages/points.html b/client/pages/points.html index 3822712..0aaa64c 100644 --- a/client/pages/points.html +++ b/client/pages/points.html @@ -18,7 +18,7 @@ {{> matchRules}} {{else}} {{#with getSelectedCompetition}}

{{label}} starts on the {{prettyDate startDate}}.

-

Please come back when the competition starts to view user predictions and points.

+

This user has not made any predictions yet.

{{/with}} {{/if}} diff --git a/client/pages/rankings.html b/client/pages/rankings.html index 755ec20..ce6bcf7 100755 --- a/client/pages/rankings.html +++ b/client/pages/rankings.html @@ -49,11 +49,11 @@ {{rank}} image {{username}} - {{prettyDate date}} + {{prettyDate lastPredictionDate}} {{#if isSelectedPaid}} Yes ({{paidDate}}) {{/if}} - {{points}} + {{points}} diff --git a/client/pages/rankings.js b/client/pages/rankings.js index 6241e7e..1e0c383 100755 --- a/client/pages/rankings.js +++ b/client/pages/rankings.js @@ -5,111 +5,6 @@ Template.rankings.helpers({ var isPaid = isSelectedPaid(); return calculateRankings(group._id, competition._id, isPaid); - - - // var competition = Session.get('selectedCompetition'); - // var group = Session.get('selectedGroup'); - // var isPaid = isSelectedPaid(); - // var nowDate = new Date(); - // - // var predictionMap = Predictions.find({ - // competitionId: competition._id - // }).fetch().reduce(function (map, obj) { - // if (!map[obj.userId]) { - // map[obj.userId] = {} - // } - // map[obj.userId][obj._id] = obj; - // return map; - // }, {}); - // - // var resultMap = Results.find({ - // competitionId: competition._id - // }).fetch().reduce(function (map, obj) { - // //TODO: consider the highest weighted here if multiple exists - // map[obj.itemId] = obj; - // return map; - // }, {}); - // - // var users = []; - // Object.keys(predictionMap).forEach(function (userId) { - // var user = CustomUsers.findOne({ - // _id: userId - // }); - // var hasUserPaid = user[getPaidAttribute()]; - // if (!isPaid || (user.emails[0].verified && hasUserPaid)) { - // //if the user belongs to the selected group - // if (user.groups.indexOf(group._id) >= 0) { - // user.points = 0; - // Object.keys(predictionMap[userId]).forEach(function (predictionId) { - // var prediction = predictionMap[userId][predictionId]; - // if (!user.date || user.date < prediction.date) { - // user.date = prediction.date; - // } - // - // //if there is an actual result then calculate the points accordingly - // if (resultMap[prediction.itemId]) { - // var result = resultMap[prediction.itemId]; - // if (result.answer) { - // var question = Questions.findOne({ - // _id: prediction.itemId - // }); - // if (question.date < nowDate) { - // if (question.optionType == 'INTEGER') { - // if (Math.abs(result.answer - prediction.answer) <= question.threshold) { - // user.points += parseInt(question.points); - // } - // } else if (result.answer == prediction.answer) { - // user.points += parseInt(question.points); - // } - // } - // } else { - // var match = Matches.findOne({ - // _id: prediction.itemId - // }); - // if (match.date < nowDate) { - // //calculate the actual points - // if (result.homeScore == prediction.homeScore && result.awayScore == prediction.awayScore) { - // user.points += 3; - // } else if ((result.homeScore - result.awayScore) == (prediction.homeScore - prediction.awayScore)) { - // user.points += 2; - // } else if ((result.homeScore > result.awayScore && prediction.awayScore > prediction.awayScore) || (result.homeScore < result.awayScore && prediction.awayScore < prediction.awayScore)) { - // user.points += 1; - // } - // } - // } - // } - // }); - // users.push(user); - // } - // } - // }); - // - // - // users.sort(function (a, b) { - // if (a.points < b.points) - // return 1; - // else if (a.points > b.points) - // return -1; - // else if (a.date < b.date) - // return -1; - // else if (a.date > b.date) - // return 1; - // else - // return 0; - // }); - // - // var rank = 1; - // var points = Number.POSITIVE_INFINITY; - // users.forEach(function (user) { - // if (user.points == points) { - // user.rank = '-'; - // } else { - // user.rank = rank++; - // points = user.points; - // } - // }); - // - // return users; } }); diff --git a/common/points.js b/common/points.js index 625db4b..a8dee39 100644 --- a/common/points.js +++ b/common/points.js @@ -14,6 +14,7 @@ calculateRankings = function (groupId, competitionId, isPaid = false) { if (!isPaid || (user.emails[0].verified && user[getPaidAttribute()])) { if (!data[userPointInfo.userId]) { data[userPointInfo.userId] = {} + data[userPointInfo.userId].id = user._id; data[userPointInfo.userId].username = user.username; data[userPointInfo.userId].avatar = user.profile.avatar; data[userPointInfo.userId].points = 0; diff --git a/server/observers.js b/server/observers.js index e5f55b3..137fec3 100644 --- a/server/observers.js +++ b/server/observers.js @@ -48,25 +48,22 @@ Meteor.startup(function () { }); //TODO resolve issue where this is called multiple time on startup - Results.find({}).observeChanges({ + Predictions.find({}).observeChanges({ added: function (id, doc) { - upsertCalculatePoints(doc.competitionId); + upsertPointInfoByPrediction(id); }, changed: function (id, doc) { - var result = Results.findOne({ - _id: id - }); - upsertCalculatePoints(result.competitionId); + upsertPointInfoByPrediction(id); } }); - Predictions.find({}).observeChanges({ + + Results.find({}).observeChanges({ added: function (id, doc) { - if (!Points.findOne({ - _id: id - })) { - upsertCalculatePoints(doc.competitionId); - } + upsertPointInfoByResult(id); + }, + changed: function (id, doc) { + upsertPointInfoByResult(id); } }); }); diff --git a/server/points.js b/server/points.js index 6e3f3df..a34e954 100644 --- a/server/points.js +++ b/server/points.js @@ -1,123 +1,213 @@ - calculatePoints = function (competitionId) { - var matches = Matches.find({ - competitionId: competitionId, - }); - - var questions = Questions.find({ - competitionId: competitionId, - }); - - var predictionMap = Predictions.find({ - competitionId: competitionId - }).fetch().reduce(function (map, obj) { - if (!map[obj.userId]) { - map[obj.userId] = {} - } - map[obj.userId][obj.itemId] = obj; - return map; - }, {}); - - var resultMap = Results.find({ - competitionId: competitionId - }, { - sort: { - date: 1 - } - }).fetch().reduce(function (map, obj) { - //TODO: consider the highest weighted here if multiple exists - map[obj.itemId] = obj; - return map; - }, {}); - - var infos = []; - - Object.keys(predictionMap).forEach(function (userId) { - matches.forEach(function (match) { - var info = {}; - info._id = match._id + '_' + userId; - info.matchId = match._id; - info.userId = userId; - info.competitionId = competitionId; - info.endDate = match.date; - info.points = 0; - - if (match.date < new Date()) { - var prediction = predictionMap[userId][match._id]; - if (prediction) { - info.predictionId = prediction._id; - info.predictionDate = prediction.date; - } - - var result = resultMap[match._id]; - if (result) { - info.resultId = result._id; - } - - if (prediction && result) { - //calculate the actual points - if (result.homeScore == prediction.homeScore && result.awayScore == prediction.awayScore) { - info.points = 3; - } else if ((result.homeScore - result.awayScore) == (prediction.homeScore - prediction.awayScore)) { - info.points = 2; - } else if ((result.homeScore > result.awayScore && prediction.awayScore > prediction.awayScore) || (result.homeScore < result.awayScore && prediction.awayScore < prediction.awayScore)) { - info.points = 1; - } - } - } - - infos.push(info); - }); - - questions.forEach(function (question) { - var info = {}; - info._id = question._id + '_' + userId; - info.questionId = question._id; - info.userId = userId; - info.competitionId = competitionId; - info.endDate = question.date; - info.points = 0; - - if (question.date < new Date()) { - var prediction = predictionMap[userId][question._id]; - if (prediction) { - info.predictionId = prediction._id; - info.predictionDate = prediction.date; - } - - var result = resultMap[question._id]; - if (result) { - info.resultId = result._id; - } - - if (prediction && result) { - if (question.optionType == 'INTEGER') { - if (Math.abs(result.answer - prediction.answer) <= question.threshold) { - info.points = question.points; - } else { - info.points = 0; - } - } else if (result.answer == prediction.answer) { - info.points = question.points; - } - } - } - - infos.push(info); - }); - }); - - return infos; - } - - upsertCalculatePoints = function (competitionId) { - console.info('calculating points for ' + competitionId); - var points = calculatePoints(competitionId); - points.forEach(function (point) { - Points.upsert({ - _id: point._id - }, point); - }); - } - - upsertCalculatePoints('EURO2016') - upsertCalculatePoints('EURO2016TEST') +getPointInfoByPrediction = function (predictionId) { + var infos = []; + + var prediction = Predictions.findOne({ + _id: predictionId + }); + + var match = Matches.findOne({ + _id: prediction.itemId + }); + + var question = Questions.findOne({ + _id: prediction.itemId + }); + + if (match) { + var info = getMatchInfo(match, prediction); + infos.push(info); + } + + if (question) { + var info = getQuestionInfo(question, prediction); + infos.push(info); + } + + return infos; +} + +getPointInfoByResult = function (resultId) { + var infos = []; + + var result = Results.findOne({ + _id: resultId + }); + + var match = Matches.findOne({ + _id: result.itemId + }); + + var question = Questions.findOne({ + _id: result.itemId + }); + + var predictions = Predictions.find({ + itemId: result.itemId + }); + + predictions.forEach(function (prediction) { + if (match) { + var info = getMatchInfo(match, prediction, result); + infos.push(info); + } + + if (question) { + var info = getQuestionInfo(question, prediction, result); + infos.push(info); + } + + }); + + return infos; +} + +getPointInfoByCompetition = function (competitionId) { + var matches = Matches.find({ + competitionId: competitionId, + }); + + var questions = Questions.find({ + competitionId: competitionId, + }); + + var predictionMap = Predictions.find({ + competitionId: competitionId + }).fetch().reduce(function (map, obj) { + if (!map[obj.userId]) { + map[obj.userId] = {} + } + map[obj.userId][obj.itemId] = obj; + return map; + }, {}); + + var resultMap = Results.find({ + competitionId: competitionId + }, { + sort: { + date: 1 + } + }).fetch().reduce(function (map, obj) { + //TODO: consider the highest weighted here if multiple exists + map[obj.itemId] = obj; + return map; + }, {}); + + var infos = []; + + Object.keys(predictionMap).forEach(function (userId) { + matches.forEach(function (match) { + var prediction = predictionMap[userId][match._id]; + if (prediction) { + var result = resultMap[match._id]; + var info = getMatchInfo(match, prediction, result); + infos.push(info); + } + }); + + questions.forEach(function (question) { + var prediction = predictionMap[userId][question._id]; + if (prediction) { + var result = resultMap[question._id]; + var info = getQuestionInfo(question, prediction, result); + infos.push(info); + } + }); + }); + + return infos; +} + +var getMatchInfo = function (match, prediction, result = undefined) { + var info = {}; + info._id = match._id + '_' + prediction.userId; + info.matchId = match._id; + info.userId = prediction.userId; + info.competitionId = match.competitionId; + info.endDate = match.date; + info.points = 0; + + if (match.date < new Date()) { + if (result) { + info.resultId = result._id; + } + + if (prediction && result) { + //calculate the actual points + if (result.homeScore == prediction.homeScore && result.awayScore == prediction.awayScore) { + info.points = 3; + } else if ((result.homeScore - result.awayScore) == (prediction.homeScore - prediction.awayScore)) { + info.points = 2; + } else if ((result.homeScore > result.awayScore && prediction.awayScore > prediction.awayScore) || (result.homeScore < result.awayScore && prediction.awayScore < prediction.awayScore)) { + info.points = 1; + } + } + info.predictionId = prediction._id; + } + + info.predictionDate = prediction.date; + + return info; +} + +var getQuestionInfo = function (question, prediction, result = undefined) { + var info = {}; + info._id = question._id + '_' + prediction.userId; + info.questionId = question._id; + info.userId = prediction.userId; + info.competitionId = question.competitionId; + info.endDate = question.date; + info.points = 0; + + if (question.date < new Date()) { + if (result) { + info.resultId = result._id; + } + + if (prediction && result) { + if (question.optionType == 'INTEGER') { + if (Math.abs(result.answer - prediction.answer) <= question.threshold) { + info.points = question.points; + } else { + info.points = 0; + } + } else if (result.answer == prediction.answer) { + info.points = question.points; + } + } + info.predictionId = prediction._id; + } + + info.predictionDate = prediction.date; + + return info; +} + +upsertPointInfoByPrediction = function (predictionId) { + console.info('prediction change ' + predictionId); + var points = getPointInfoByPrediction(predictionId); + points.forEach(function (point) { + Points.upsert({ + _id: point._id + }, point); + }); +} + +upsertPointInfoByResult = function (resultId) { + console.info('result change ' + resultId); + var points = getPointInfoByResult(resultId); + points.forEach(function (point) { + Points.upsert({ + _id: point._id + }, point); + }); +} + +upsertPointInfoByCompetition = function (competitionId) { + console.info('competition change ' + competitionId); + var points = getPointInfoByCompetition(competitionId); + points.forEach(function (point) { + Points.upsert({ + _id: point._id + }, point); + }); +}