Skip to content

Commit

Permalink
Merge pull request #12 from Fusselwurm/float-point-status
Browse files Browse the repository at this point in the history
Float point status
  • Loading branch information
Fusselwurm committed Jan 8, 2017
2 parents 29fb4e6 + 9300fe2 commit 5b5627c
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 83 deletions.
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -25,6 +25,9 @@ ex.

wget --progress=dot --method=POST --header="Content-Type:application/json" --body-data='{"type":"yes"}' --save-headers -O - "http://localhost:4567/api/attendance/1"

### GET /api/attendance/:tid/user/:uid/history



----

Expand Down
133 changes: 79 additions & 54 deletions lib/persistence-float.js
@@ -1,72 +1,97 @@
var db;

var async = require('async');
var _ = require('underscore');
var noop = function () {};

function getRedisZsetProbabiltiesKey(tid) {
return 'tid:%d:attendance:probabilities'.replace('%d', tid);
function getRedisZsetKeyAttendanceInfo(tid, infoName) {
return 'tid:%d:attendance:%s'.replace('%d', tid).replace('%s', infoName);
}
function getRedisZsetLastUpdateKey(tid) {
return 'tid:%d:attendance:last_updated_at'.replace('%d', tid);

function getRedisListKeyAttendanceHistory(tid, uid) {
return 'tid:%d:attendance:user:%d:history'.replace('%d', tid).replace('%d', uid);
}

function setAsyncParallelAttendanceInfo(tid, infoName, infoNameRedis, userAttendanceInfo, next) {
db.sortedSetAdd(
getRedisZsetKeyAttendanceInfo(tid, infoNameRedis),
userAttendanceInfo[infoName],
userAttendanceInfo.uid,
next
);
}

function setAsyncParallelAttendanceHistory(tid, userAttendanceInfo, next) {
db.listPrepend(
getRedisListKeyAttendanceHistory(tid, userAttendanceInfo.uid),
[userAttendanceInfo.timestamp, userAttendanceInfo.probability].join(':'),
next
);
db.listTrim(getRedisListKeyAttendanceHistory(tid, userAttendanceInfo.uid), 0, 100, noop);
}

function getAsyncParallelAttendanceHistory(tid, uid, next) {
db.getListRange(getRedisListKeyAttendanceHistory(tid, uid), 0, -1, function (err, results) {
if (err) {
return next(err);
}

return next(null, results.map(function (item) {
var bits = item.split(':');
return {
timestamp: parseInt(bits[0], 10),
probability: parseFloat(bits[1] || -1)
};
}));
});
}

function getAsyncParallelAttendanceInfo(tid, infoNameRedis, next) {
db.getSortedSetRangeWithScores(getRedisZsetKeyAttendanceInfo(tid, infoNameRedis), 0, -1, next);
}

function mergeAttendanceInfos(propertyNames, callback, err, results /*[probabilityInfos, lastUpdatedAtInfos]*/) {
if (err) {
return callback(err);
}
var userAttendanceInfos = {};

function setSomeValue(someValueName, info) {
var userValue = userAttendanceInfos[info.value] = (userAttendanceInfos[info.value] || { uid: info.value });
userValue[someValueName] = info.score;
}

propertyNames.forEach(function (propertyName, idx) {
results[idx].forEach(function (result) {
setSomeValue(propertyName, result);
});
});

callback(null, _.values(userAttendanceInfos));
}

module.exports.setDatabase = function (databaseModule) {
db = databaseModule;
};

module.exports.set = function (tid, userAttendanceInfo /* {uid, probability, lastUpdatedAt} */, callback) {
module.exports.set = function (tid, userAttendanceInfo /* {uid, probability, timestamp} */, callback) {
async.parallel([
function (next) {
db.sortedSetAdd(
getRedisZsetLastUpdateKey(tid),
userAttendanceInfo.lastUpdatedAt,
userAttendanceInfo.uid,
next
);
},
function (next) {
db.sortedSetAdd(
getRedisZsetProbabiltiesKey(tid),
userAttendanceInfo.probability,
userAttendanceInfo.uid,
next
);
}
_.partial(setAsyncParallelAttendanceInfo, tid, 'timestamp', 'last_updated_at', userAttendanceInfo),
_.partial(setAsyncParallelAttendanceInfo, tid, 'probability', 'probability', userAttendanceInfo),
_.partial(setAsyncParallelAttendanceHistory, tid, userAttendanceInfo)
], callback);
};

module.exports.get = function (tid, callback) {
async.parallel([
function () {
db.getSortedSetRangeWithScores(getRedisZsetProbabiltiesKey(tid), 0, -1, next);
},
function () {
db.getSortedSetRangeWithScores(getRedisZsetLastUpdateKey(tid), 0, -1, next);
}
], function (err, results) {
if (err) {
return callback(err);
}
var probabilityInfos /*Array<{score, value}>*/ = results[0];
var lastUpdatedAtInfos /*Array<{score, value}>*/ = results[1];

var userAttendanceInfos = {};

probabilityInfos.forEach(function (probabilityInfo) {
var userValue = userAttendanceInfos[probabilityInfo.value] || {
uid: probabilityInfo.value
};
userValue.probability = probabilityInfo.score;
userAttendanceInfos[userValue.uid] = userValue;
});

lastUpdatedAtInfos.forEach(function (lastUpdateInfo) {
var userValue = userAttendanceInfos[lastUpdateInfo.value] || {
uid: lastUpdateInfo.value
};
userValue.lastUpdatedAt = lastUpdateInfo.score;
userAttendanceInfos[userValue.uid] = userValue;
});
async.parallel(
[
_.partial(getAsyncParallelAttendanceInfo, tid, 'probability'),
_.partial(getAsyncParallelAttendanceInfo, tid, 'last_updated_at')
],
_.partial(mergeAttendanceInfos, ['probability', 'timestamp'], callback)
);
};

callback(null, userAttendanceInfos);
});
module.exports.getUserHistory = function (tid, uid, callback) {
getAsyncParallelAttendanceHistory(tid, uid, callback);
};
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -3,7 +3,8 @@
"version": "0.5.4",
"dependencies": {
"async": "^2.0",
"winston": "*"
"winston": "*",
"underscore": "*"
},
"engines" : {
"npm" : ">3.0"
Expand Down
2 changes: 1 addition & 1 deletion public/templates/partials/topic_detailsRow.ejs
Expand Up @@ -14,7 +14,7 @@
<td class="member-name">
<a href="<%= config.relative_path %>/user/<%= attendant.userslug %>"><%- attendant.username %></a>
<div class="pull-right">
<%= attendant.timestamp %>
<%= nodebbPluginAttendanceCustomISODateString(attendant.timestamp) %>
</div>
</td>
</tr>
13 changes: 12 additions & 1 deletion public/updateTopicList.js
Expand Up @@ -13,6 +13,7 @@
$(document).on('click', '.attendance-control', function () {
var $button = $(this);
var value = getCurrentButtonValue($button);
var probability = $button.data('probability');
var tid = $button.attr('data-tid');
var btnType = $button.attr('data-id');
console.log(value, tid, btnType);
Expand All @@ -31,7 +32,7 @@
$.post({
url: config.relative_path + '/api/attendance/' + tid,
contentType: 'application/json',
data: JSON.stringify({"type": value}),
data: JSON.stringify({type: value, probability: probability}),
success: function () {
$button.disabled = true;
var myfuckingButtonForReal = document.querySelectorAll('button.attendance-control');
Expand Down Expand Up @@ -337,3 +338,13 @@ var hideAttendanceDetails = function () {
document.querySelector('[component="topic/attendance/details"]').style.display = 'none';
document.querySelector('[component="topic/attendance/backdrop"]').style.display = 'none';
};

function nodebbPluginAttendanceCustomISODateString (d) {
d = new Date(d);
function pad(n) {return n<10 ? '0'+n : n}
return d.getUTCFullYear()+'-'
+ pad(d.getUTCMonth()+1)+'-'
+ pad(d.getUTCDate())+' '
+ pad(d.getUTCHours())+':'
+ pad(d.getUTCMinutes())
}
62 changes: 36 additions & 26 deletions registerApi.js
Expand Up @@ -52,15 +52,6 @@ var getUserAttendance = function (attendance, uid) {
}).pop();
};

function customISODateString(d) {
function pad(n) {return n<10 ? '0'+n : n}
return d.getUTCFullYear()+'-'
+ pad(d.getUTCMonth()+1)+'-'
+ pad(d.getUTCDate())+' '
+ pad(d.getUTCHours())+':'
+ pad(d.getUTCMinutes())
}

/*
var getCurrentUser = function (attendance, uid) {
return types.filter(function (type) {
Expand All @@ -70,6 +61,7 @@ var getCurrentUser = function (attendance, uid) {

var async = require('async');
var winston = require('winston');
var _ = require('underscore');

var db = require('../../src/database');
var users = require('../../src/user');
Expand All @@ -83,6 +75,7 @@ module.exports = function (params, callback) {
router.post('/api/attendance/:tid',
function (req, res, next) {
var type = req.body.type;
var probability = req.body.probability;
var tid = req.params.tid;
var uid = req.uid;
var stringType = floatTypeStringMap[type] || type;
Expand Down Expand Up @@ -116,8 +109,8 @@ module.exports = function (params, callback) {
tid,
{
uid: uid,
probability: ensureFloatType(type),
lastUpdatedAt: (new Date()).getTime()
probability: probability || ensureFloatType(type),
timestamp: timestamp
},
function (err, result) {
if (err) {
Expand All @@ -136,7 +129,11 @@ module.exports = function (params, callback) {
}

async.parallel(
types.map(function (type) { return getAsyncAttendancesGetter(tid, type); }),
types.map(function (type) { return getAsyncAttendancesGetter(tid, type); }).concat([
function (next) {
floatPersistence.get(tid, next);
}
]),
function (err, results) {
if (err) {
return res.status(500).json({error: err});
Expand All @@ -155,30 +152,43 @@ module.exports = function (params, callback) {
}

types.forEach(function (type) {
attendance[type].forEach(function (attendance) {
var u = users.filter(function (user) { return user.uid == attendance.value; }).pop();
attendance.uid = u.uid;
delete attendance.value;
attendance.timestamp = customISODateString(new Date(attendance.score));

// attendance.timestamp = (new Date(attendance.score)).toISOString('[]', {hour: '2-digit', minute:'2-digit'});
delete attendance.score;
attendance.username = u.username;
attendance.userslug = u.userslug;
attendance.picture = u.picture;
attendance['icon:bgColor'] = u['icon:bgColor'];
attendance['icon:text'] = u['icon:text'];
attendance[type].forEach(function (attendant) {
var u = users.filter(function (user) { return user.uid == attendant.value; }).pop();
attendant.uid = u.uid;
attendant.probability = stringTypeFloatMap[type];
delete attendant.value;
attendant.timestamp = attendant.score;
delete attendant.score;
_(attendant).extend(_(u).pick(['username', 'userslug', 'picture', 'icon:bgColor', 'icon:text']));
});
});

results[types.length].forEach(function (attendant) {
var u = users.filter(function (user) { return user.uid == attendant.uid; }).pop();

_(attendant).extend(_(u).pick(['username', 'userslug', 'picture', 'icon:bgColor', 'icon:text']));
});

res.status(200).json({
myAttendance: getUserAttendance(attendance, currentUser),
attendance: attendance
attendance: attendance,
attendants: results[types.length]
});
});
}
);
});

router.get('/api/attendance/:tid/user/:uid/history', function (req, res, next) {
var tid = req.params.tid;
var uid = req.params.uid;

floatPersistence.getUserHistory(tid, uid, function (err, results) {
if (err) {
return res.status(500).json({err: err});
}
res.status(200).json(results);
});
});
callback();
};

0 comments on commit 5b5627c

Please sign in to comment.