Skip to content

Commit

Permalink
Should be done with minimal breakage... testing phase now.
Browse files Browse the repository at this point in the history
Applies to #264
  • Loading branch information
Martii committed Jul 15, 2014
1 parent af46e15 commit 82dc007
Show file tree
Hide file tree
Showing 20 changed files with 762 additions and 758 deletions.
38 changes: 19 additions & 19 deletions libs/collectiveRating.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@

var Script = require('../models/script').Script;

function median(values) {
var middle = Math.floor(values.length / 2);
values.sort(function (a, b) { return a - b; });
function median(aValues) {
var middle = Math.floor(aValues.length / 2);
aValues.sort(function (aA, aB) { return aA - aB; });

return values.length % 2 ? values[middle] :
(values[middle - 1] + values[middle]) / 2;
return aValues.length % 2 ? aValues[middle] :
(aValues[middle - 1] + aValues[middle]) / 2;
}

function mean(values) {
function mean(aValues) {
var sum = 0;
var i = 0;
for (; i < values.length; ++i) {
sum += values[i];
for (; i < aValues.length; ++i) {
sum += aValues[i];
}

return sum / values.length;
return sum / aValues.length;
}

// Generate a collective rating by averaging the median and mean of
// scripts in a group. I think this gives a more fair rating than just
// using one of them alone.
function getRating(scripts) {
function getRating(aScripts) {
var ratings = null;

if (scripts.length < 2) { return 0; }
if (aScripts.length < 2) { return 0; }

ratings = scripts.map(function (script) {
return script.rating;
ratings = aScripts.map(function (aScript) {
return aScript.rating;
});

return Math.round((median(ratings) + mean(ratings)) / 2);
Expand All @@ -39,15 +39,15 @@ exports.getRating = getRating;
// TODO: Memoize this function with an
// expiring cache (either memory or DB based) to
// speed up voting and flagging
exports.getKarma = function (user, maxKarma, callback) {
exports.getKarma = function (aUser, aMaxKarma, aCallback) {
var ratings = [];
var karma = 0;
Script.find({ _authorId: user._id }, 'rating', function (err, scripts) {
if (err) { return callback(karma); }
Script.find({ _authorId: aUser._id }, 'rating', function (aErr, aScripts) {
if (aErr) { return aCallback(karma); }

karma = Math.floor(getRating(scripts) / 10);
if (karma > maxKarma) { karma = maxKarma; }
karma = Math.floor(getRating(aScripts) / 10);
if (karma > aMaxKarma) { karma = aMaxKarma; }

callback(karma);
aCallback(karma);
});
};
118 changes: 59 additions & 59 deletions libs/flag.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,134 +9,134 @@ var maxKarma = 10;
// Determine whether content can be flagged by a user.
// This is heavily commented so that my logic and
// reasoning is documented for myself and others.
function flaggable(model, content, user, callback) {
function flaggable(aModel, aContent, aUser, aCallback) {
// Not logged in.
if (!user) { return callback(false); }
if (!aUser) { return aCallback(false); }


// You can't flag yourself
// Only someone less than an admin can be flagged
// It is not the responsibility of the community
// to police the site administration
if (model.modelName === 'User') {
return getFlag(model, content, user, function (flag) {
callback(content._id != user._id && content.role > 2, content, flag);
if (aModel.modelName === 'User') {
return getFlag(aModel, aContent, aUser, function (aFlag) {
aCallback(aContent._id != aUser._id && aContent.role > 2, aContent, aFlag);
});
}

getAuthor(content, function (author) {
getAuthor(aContent, function (aAuthor) {
// Content without an author shouldn't exist
if (!author) { return callback(false); }
if (!aAuthor) { return aCallback(false); }

// You can't flag your own content
if (author._id == user._id) { return callback(false); }
if (aAuthor._id == aUser._id) { return aCallback(false); }

// Content belonging to an admin or above cannot be flagged
if (author.role < 3) { return callback(author.role > 2, author); }
if (aAuthor.role < 3) { return aCallback(aAuthor.role > 2, aAuthor); }

// You can't flag something twice
getFlag(model, content, user, function (flag) {
return callback(!flag, author, flag);
getFlag(aModel, aContent, aUser, function (aFlag) {
return aCallback(!aFlag, aAuthor, aFlag);
});
});
}
exports.flaggable = flaggable;

function getFlag(model, content, user, callback) {
function getFlag(aModel, aContent, aUser, aCallback) {
Flag.findOne({
'model': model.modelName,
'_contentId': content._id,
'_userId': user._id
}, function (err, flag) {
callback(err || !flag ? null : flag);
'model': aModel.modelName,
'_contentId': aContent._id,
'_userId': aUser._id
}, function (aErr, aFlag) {
aCallback(aErr || !aFlag ? null : aFlag);
});
}

function getAuthor(content, callback) {
User.findOne({ _id: content._authorId }, function (err, author) {
function getAuthor(aContent, aCallback) {
User.findOne({ _id: aContent._authorId }, function (aErr, aAuthor) {
// Content without an author shouldn't exist
if (err || !author) { return callback(null); }
if (aErr || !aAuthor) { return aCallback(null); }

callback(author);
aCallback(aAuthor);
});
}
exports.getAuthor = getAuthor;

function getThreshold(model, content, author, callback) {
function getThreshold(aModel, aContent, aAuthor, aCallback) {
// Admins can't be flagged so they have no threshold
if (author.role < 3) { return callback(null); }
if (aAuthor.role < 3) { return aCallback(null); }

// Hardcode the threshold at 1.
// modelQuery.applyModelListQueryFlaggedFilter supports this hardcoded number.
// return callback(1);
// return aCallback(1);

// Moderators have a doubled threshold
var threshold = thresholds[model.modelName] * (author.role < 4 ? 2 : 1);
var threshold = thresholds[aModel.modelName] * (aAuthor.role < 4 ? 2 : 1);

// Calculate karma and add it to the threshold
getKarma(author, maxKarma, function (karma) {
return callback(threshold + karma);
getKarma(aAuthor, maxKarma, function (aKarma) {
return aCallback(threshold + aKarma);
});
}
exports.getThreshold = getThreshold;

function saveContent(model, content, author, flags, callback) {
if (!content.flags) { content.flags = 0; }
content.flags += flags;
function saveContent(aModel, aContent, aAuthor, flags, aCallback) { // TODO: Ambiguous
if (!aContent.flags) { aContent.flags = 0; }
aContent.flags += flags;

This comment has been minimized.

Copy link
@Martii

Martii Aug 12, 2014

Member
if (content.flags >= thresholds[model.modelName] * (author.role < 4 ? 2 : 1)) {
return getThreshold(model, content, author, function (threshold) {
content.flagged = content.flags >= threshold;
content.save(function (err, content) { callback(content.flagged); });
if (aContent.flags >= thresholds[aModel.modelName] * (aAuthor.role < 4 ? 2 : 1)) {
return getThreshold(aModel, aContent, aAuthor, function (aThreshold) {
aContent.flagged = aContent.flags >= aThreshold;
aContent.save(function (aErr, aContent) { aCallback(aContent.flagged); });
});
}

content.save(function (err, content) { callback(content.flagged); });
aContent.save(function (aErr, aContent) { aCallback(aContent.flagged); });
}
exports.saveContent = saveContent;

function flag(model, content, user, author, callback) {
function flag(aModel, aContent, aUser, aAuthor, aCallback) {
var flag = new Flag({
'model': model.modelName,
'_contentId': content._id,
'_userId': user._id
'model': aModel.modelName,
'_contentId': aContent._id,
'_userId': aUser._id
});

flag.save(function (err, flag) {
if (!content.flags) { content.flags = 0; }
if (!content.flagged) { content.flagged = false; }
flag.save(function (aErr, aFlag) {
if (!aContent.flags) { aContent.flags = 0; }
if (!aContent.flagged) { aContent.flagged = false; }

saveContent(model, content, author, user.role < 4 ? 2 : 1, callback)
saveContent(aModel, aContent, aAuthor, aUser.role < 4 ? 2 : 1, aCallback)
});
}

exports.flag = function (model, content, user, callback) {
flaggable(model, content, user, function (canFlag, author) {
if (!canFlag) { return callback(false); }
exports.flag = function (aModel, aContent, aUser, aCallback) {
flaggable(aModel, aContent, aUser, function (aCanFlag, aAuthor) {
if (!aCanFlag) { return aCallback(false); }

flag(model, content, user, author, callback);
flag(aModel, aContent, aUser, aAuthor, aCallback);
});
};

exports.unflag = function (model, content, user, callback) {
if (!user) { return callback(null); }
exports.unflag = function (aModel, aContent, aUser, aCallback) {
if (!aUser) { return aCallback(null); }

getFlag(model, content, user, function (flag) {
if (!flag) { return callback(null); }
getFlag(aModel, aContent, aUser, function (aFlag) {
if (!aFlag) { return aCallback(null); }

if (!content.flags) { content.flags = 0; }
if (!content.flagged) { content.flagged = false; }
if (!aContent.flags) { aContent.flags = 0; }
if (!aContent.flagged) { aContent.flagged = false; }

function removeFlag(author) {
flag.remove(function (err) {
saveContent(model, content, author, user.role < 4 ? -2 : -1, callback);
function removeFlag(aAuthor) {
aFlag.remove(function (aErr) {
saveContent(aModel, aContent, aAuthor, aUser.role < 4 ? -2 : -1, aCallback);
});
}

if (model.modelName === 'User') {
removeFlag(content);
if (aModel.modelName === 'User') {
removeFlag(aContent);
} else {
getAuthor(content, removeFlag);
getAuthor(aContent, removeFlag);
}
});
};
72 changes: 36 additions & 36 deletions libs/githubClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ module.exports = github;

// Authenticate Client
var Strategy = require('../models/strategy').Strategy;
Strategy.findOne({ name: 'github' }, function (err, strat) {
if (err)
console.error(err);
Strategy.findOne({ name: 'github' }, function (aErr, aStrat) {
if (aErr)
console.error(aErr);

if (strat) {
if (aStrat) {
github.authenticate({
type: 'oauth',
key: strat.id,
secret: strat.key,
key: aStrat.id,
secret: aStrat.key,
});
console.log('GitHub client authenticated');
} else {
Expand All @@ -34,63 +34,63 @@ Strategy.findOne({ name: 'github' }, function (err, strat) {
// Util functions for the client.
github.usercontent = github.usercontent || {};

var githubGitDataGetBlobAsUtf8 = function (msg, callback) {
var githubGitDataGetBlobAsUtf8 = function (aMsg, aCallback) {
async.waterfall([
function (callback) {
github.gitdata.getBlob(msg, callback);
function (aCallback) {
github.gitdata.getBlob(aMsg, aCallback);
},
function (blob, callback) {
var content = blob.content;
if (blob.encoding == 'base64') {
function (aBlob, aCallback) {
var content = aBlob.content;
if (aBlob.encoding == 'base64') {
var buf = new Buffer(content, 'base64');
content = buf.toString('utf8');
}
callback(null, content);
aCallback(null, content);
},
], callback);
], aCallback);
};
github.gitdata.getBlobAsUtf8 = githubGitDataGetBlobAsUtf8;

var githubUserContentBuildUrl = function (user, repo, path) {
return util.format('https://raw.githubusercontent.com/%s/%s/HEAD/%s', user, repo, path);
var githubUserContentBuildUrl = function (aUser, aRepo, aPath) {
return util.format('https://raw.githubusercontent.com/%s/%s/HEAD/%s', aUser, aRepo, aPath);
};
github.usercontent.buildUrl = githubUserContentBuildUrl;

var githubUserContentGetBlobAsUtf8 = function (msg, callback) {
var githubUserContentGetBlobAsUtf8 = function (aMsg, aCallback) {
async.waterfall([
function (callback) {
var url = githubUserContentBuildUrl(msg.user, msg.repo, msg.path);
request.get(url, callback);
function (aCallback) {
var url = githubUserContentBuildUrl(aMsg.user, aMsg.repo, aMsg.path);
request.get(url, aCallback);
},
function (response, body, callback) {
if (response.statusCode != 200)
return callback(util.format('Status Code %s', response.statusCode));
function (aResponse, aBody, aCallback) {
if (aResponse.statusCode != 200)
return aCallback(util.format('Status Code %s', aResponse.statusCode));

callback(null, body);
aCallback(null, aBody);
},
], callback);
], aCallback);
};

github.usercontent.getBlobAsUtf8 = githubUserContentGetBlobAsUtf8;

var githubGitDataIsJavascriptBlob = function (blob) {
return blob.path.match(/\.js$/);
var githubGitDataIsJavascriptBlob = function (aBlob) {
return aBlob.path.match(/\.js$/);
};
github.gitdata.isJavascriptBlob = githubGitDataIsJavascriptBlob;

var githubGitDataGetJavascriptBlobs = function (msg, callback) {
var githubGitDataGetJavascriptBlobs = function (aMsg, aCallback) {
async.waterfall([
function (callback) {
msg.sha = 'HEAD';
msg.recursive = true;
github.gitdata.getTree(msg, callback);
function (aCallback) {
aMsg.sha = 'HEAD';
aMsg.recursive = true;
github.gitdata.getTree(aMsg, aCallback);
},
function (repoTree, callback) {
var entries = repoTree.tree;
function (aRepoTree, aCallback) {
var entries = aRepoTree.tree;
var blobs = _.where(entries, { type: 'blob' });
var javascriptBlobs = _.filter(blobs, githubGitDataIsJavascriptBlob);
callback(null, javascriptBlobs);
aCallback(null, javascriptBlobs);
},
], callback);
], aCallback);
};
github.gitdata.getJavascriptBlobs = githubGitDataGetJavascriptBlobs;
Loading

0 comments on commit 82dc007

Please sign in to comment.