|
1 | 1 | /**
|
2 | 2 | * Various submissions functions.
|
3 | 3 | */
|
| 4 | +/* global CONFIG */ |
| 5 | +/* eslint-disable no-param-reassign */ |
| 6 | +import _ from 'lodash'; |
| 7 | + |
| 8 | +const { AV_SCAN_SCORER_REVIEW_TYPE_ID } = CONFIG; |
| 9 | + |
| 10 | +function removeDecimal(num) { |
| 11 | + const re = new RegExp('^-?\\d+'); |
| 12 | + return num.toString().match(re)[0]; |
| 13 | +} |
| 14 | + |
| 15 | +function toAcurateFixed(num, decimal) { |
| 16 | + const re = new RegExp(`^-?\\d+(?:.\\d{0,${(decimal)}})?`); |
| 17 | + return num.toString().match(re)[0]; |
| 18 | +} |
| 19 | + |
| 20 | +function toFixed(num, decimal) { |
| 21 | + if (_.isNaN(parseFloat(num))) return num; |
| 22 | + num = parseFloat(num); |
| 23 | + |
| 24 | + const result = _.toFinite(toAcurateFixed(num, decimal)); |
| 25 | + const integerResult = _.toFinite(removeDecimal(num)); |
| 26 | + |
| 27 | + if (_.isInteger(result)) { |
| 28 | + return integerResult; |
| 29 | + } |
| 30 | + return result; |
| 31 | +} |
| 32 | + |
| 33 | +function getMMChallengeHandleStyle(handle, registrants) { |
| 34 | + const style = _.get(_.find(registrants, m => m.handle === handle), 'colorStyle', null); |
| 35 | + if (style) return JSON.parse(style.replace(/(\w+):\s*([^;]*)/g, '{"$1": "$2"}')); |
| 36 | + return {}; |
| 37 | +} |
| 38 | + |
| 39 | +/** |
| 40 | + * Process each submission rank of MM challenge |
| 41 | + * @param submissions the array of submissions |
| 42 | + */ |
| 43 | +function processRanks(submissions) { |
| 44 | + let maxFinalScore = 0; |
| 45 | + submissions.sort((a, b) => { |
| 46 | + let pA = _.get(a, 'submissions[0]', { provisionalScore: 0 }).provisionalScore; |
| 47 | + let pB = _.get(b, 'submissions[0]', { provisionalScore: 0 }).provisionalScore; |
| 48 | + if (pA === '-') pA = 0; |
| 49 | + if (pB === '-') pB = 0; |
| 50 | + if (pA === pB) { |
| 51 | + const timeA = new Date(_.get(a, 'submissions[0].submissionTime')); |
| 52 | + const timeB = new Date(_.get(b, 'submissions[0].submissionTime')); |
| 53 | + return timeA - timeB; |
| 54 | + } |
| 55 | + return pB - pA; |
| 56 | + }); |
| 57 | + _.each(submissions, (submission, i) => { |
| 58 | + submissions[i].provisionalRank = i + 1; |
| 59 | + }); |
| 60 | + |
| 61 | + submissions.sort((a, b) => { |
| 62 | + let pA = _.get(a, 'submissions[0]', { finalScore: 0 }).finalScore; |
| 63 | + let pB = _.get(b, 'submissions[0]', { finalScore: 0 }).finalScore; |
| 64 | + if (pA === '-') pA = 0; |
| 65 | + if (pB === '-') pB = 0; |
| 66 | + if (pA > 0) maxFinalScore = pA; |
| 67 | + if (pB > 0) maxFinalScore = pB; |
| 68 | + if (pA === pB) { |
| 69 | + const timeA = new Date(_.get(a, 'submissions[0].submissionTime')); |
| 70 | + const timeB = new Date(_.get(b, 'submissions[0].submissionTime')); |
| 71 | + return timeA - timeB; |
| 72 | + } |
| 73 | + return pB - pA; |
| 74 | + }); |
| 75 | + if (maxFinalScore > 0) { |
| 76 | + _.each(submissions, (submission, i) => { |
| 77 | + submissions[i].finalRank = i + 1; |
| 78 | + }); |
| 79 | + } |
| 80 | + return { submissions, maxFinalScore }; |
| 81 | +} |
4 | 82 |
|
5 | 83 | /**
|
6 | 84 | * Get provisional score of submission
|
@@ -33,3 +111,66 @@ export function getFinalScore(submission) {
|
33 | 111 | }
|
34 | 112 | return finalScore;
|
35 | 113 | }
|
| 114 | + |
| 115 | +/** |
| 116 | + * Process submissions of MM challenge |
| 117 | + * @param submissions the array of submissions |
| 118 | + * @param resources the challenge resources |
| 119 | + * @param registrants the challenge registrants |
| 120 | + */ |
| 121 | +export function processMMSubmissions(submissions, resources, registrants) { |
| 122 | + const data = {}; |
| 123 | + const result = []; |
| 124 | + |
| 125 | + _.each(submissions, (submission) => { |
| 126 | + const { memberId } = submission; |
| 127 | + let memberHandle; |
| 128 | + const resource = _.find(resources, r => _.get(r, 'userId').toString() === memberId.toString()); |
| 129 | + if (_.isEmpty(resource)) { |
| 130 | + memberHandle = memberId; |
| 131 | + } else { |
| 132 | + memberHandle = _.has(resource, 'handle') ? _.get(resource, 'handle') : memberId.toString(); |
| 133 | + } |
| 134 | + if (!data[memberHandle]) { |
| 135 | + data[memberHandle] = []; |
| 136 | + } |
| 137 | + const validReviews = _.filter(submission.review, |
| 138 | + r => !_.isEmpty(r) && (r.typeId !== AV_SCAN_SCORER_REVIEW_TYPE_ID)); |
| 139 | + validReviews.sort((a, b) => { |
| 140 | + const dateA = new Date(a.created); |
| 141 | + const dateB = new Date(b.created); |
| 142 | + return dateB - dateA; |
| 143 | + }); |
| 144 | + |
| 145 | + const provisionalScore = toFixed(_.get(validReviews, '[0].score', '-'), 5); |
| 146 | + const finalScore = toFixed(_.get(submission, 'reviewSummation[0].aggregateScore', '-'), 5); |
| 147 | + |
| 148 | + data[memberHandle].push({ |
| 149 | + submissionId: submission.id, |
| 150 | + submissionTime: submission.created, |
| 151 | + provisionalScore, |
| 152 | + finalScore, |
| 153 | + }); |
| 154 | + }); |
| 155 | + |
| 156 | + _.each(data, (value, key) => { |
| 157 | + result.push({ |
| 158 | + submissions: [...value.sort((a, b) => new Date(b.submissionTime) |
| 159 | + .getTime() - new Date(a.submissionTime).getTime())], |
| 160 | + member: key, |
| 161 | + colorStyle: getMMChallengeHandleStyle(key, registrants), |
| 162 | + }); |
| 163 | + }); |
| 164 | + |
| 165 | + const { submissions: finalSubmissions, maxFinalScore } = processRanks(result); |
| 166 | + finalSubmissions.sort((a, b) => { |
| 167 | + if (maxFinalScore === 0) { |
| 168 | + return a.provisionalRank - b.provisionalRank; |
| 169 | + } |
| 170 | + return a.finalRank - b.finalRank; |
| 171 | + }); |
| 172 | + |
| 173 | + return finalSubmissions; |
| 174 | +} |
| 175 | + |
| 176 | +export default undefined; |
0 commit comments