Skip to content

Commit

Permalink
Add PoC% to terse report
Browse files Browse the repository at this point in the history
Progress toward #6

Assumes existing PoC data for now
  • Loading branch information
backspace committed Feb 8, 2015
1 parent 21c9b7f commit fab4be6
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 41 deletions.
20 changes: 20 additions & 0 deletions migrations/20150207220606-add-is-person-of-colour.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use strict";

module.exports = {
up: function(migration, DataTypes, done) {
migration.addColumn(
'Users',
'isPersonOfColour',
DataTypes.BOOLEAN
);
done();
},

down: function(migration, DataTypes, done) {
migration.removeColumn(
'Users',
'isPersonOfColour'
);
done();
}
};
1 change: 1 addition & 0 deletions models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define("User", {
isMan: DataTypes.BOOLEAN,
isPersonOfColour: DataTypes.BOOLEAN,
slackID: DataTypes.STRING,
hasBeenQueried: DataTypes.BOOLEAN
}, {
Expand Down
31 changes: 31 additions & 0 deletions src/calculators/race-message-count.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// FIXME extract a generalised solution from this and GenderMessageCount

class RaceMessageCount {
constructor(statistics, userIsPersonOfColour) {
this.statistics = statistics;
this.userIsPersonOfColour = userIsPersonOfColour;
}

generate() {
var userIDs = Object.keys(this.statistics);

var counts = userIDs.reduce(function(counts, userID) {
var isPersonOfColour = this.userIsPersonOfColour[userID];
var count = this.statistics[userID];

if (isPersonOfColour) {
counts.peopleOfColour += count;
} else if (isPersonOfColour === false) {
counts.whitePeople += count;
} else {
counts.unknown += count;
}

return counts;
}.bind(this), {peopleOfColour: 0, whitePeople: 0, unknown: 0});

return counts;
}
}

module.exports = RaceMessageCount;
29 changes: 0 additions & 29 deletions src/reports/terse-gender.js

This file was deleted.

37 changes: 37 additions & 0 deletions src/reports/terse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// TODO also untested except by integration

var moment = require('moment');
var values = require('amp-values');

var GenderMessageCountStatisticsGenerator = require('../calculators/gender-message-count');
var RaceMessageCount = require('../calculators/race-message-count');

class TerseReportGenerator {
constructor(userMessageCount, userIsMan, userIsPersonOfColour, startTime, statsChannel) {
this.userMessageCount = userMessageCount;
// FIXME should collect attributes into an object?
// also querying the table multiple times, inefficient
this.userIsMan = userIsMan;
this.userIsPersonOfColour = userIsPersonOfColour;
this.startTime = startTime;
this.statsChannel = statsChannel;
}

generate() {
var genderMessageCountStatistics = new GenderMessageCountStatisticsGenerator(this.userMessageCount, this.userIsMan).generate();
var raceMessageCount = new RaceMessageCount(this.userMessageCount, this.userIsPersonOfColour).generate();

var total = genderMessageCountStatistics.men + genderMessageCountStatistics.notMen + genderMessageCountStatistics.unknown;

var notMenPercent = (100*genderMessageCountStatistics.notMen/total).toFixed(0);
var peopleOfColourPercent = (100*raceMessageCount.peopleOfColour/total).toFixed(0);



var report = `Since ${moment(this.startTime).fromNow()}, not-men sent ${notMenPercent}% of messages and people of colour sent ${peopleOfColourPercent}% of messages. See #${this.statsChannel} for more details.`;

return report;
}
}

module.exports = TerseReportGenerator;
14 changes: 9 additions & 5 deletions src/statsbot.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var MessageLog = require('./message-log');
var RepositoryAttributeExtractor = require('./persistence/repository-attribute-extractor');

var VerboseGenderReportGenerator = require('./reports/verbose-gender');
var TerseGenderReportGenerator = require('./reports/terse-gender');
var TerseReportGenerator = require('./reports/terse');

var DirectMessageHandler = require('./direct-message-handler');

Expand Down Expand Up @@ -100,11 +100,15 @@ class StatsBot {
count: this.topUnknownsToQuery
});

var fullReport = new VerboseGenderReportGenerator(statistics, userIsMan, metadata.startTime, channel.name).generate();
botChannel.send(fullReport);
var isPersonOfColourExtractor = new RepositoryAttributeExtractor(this.userRepository, 'isPersonOfColour', Object.keys(statistics));

var terseReport = new TerseGenderReportGenerator(statistics, userIsMan, metadata.startTime, botChannel.name).generate();
channel.send(terseReport);
isPersonOfColourExtractor.extract().then(function(userIsPersonOfColour) {
var fullReport = new VerboseGenderReportGenerator(statistics, userIsMan, metadata.startTime, channel.name).generate();
botChannel.send(fullReport);

var terseReport = new TerseReportGenerator(statistics, userIsMan, userIsPersonOfColour, metadata.startTime, botChannel.name).generate();
channel.send(terseReport);
});
}.bind(this));
}

Expand Down
30 changes: 30 additions & 0 deletions test/calculators/race-message-count.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env iojs --es_staging --use-strict

var test = require('tape');

var RaceMessageCount = require('../../src/calculators/race-message-count');

test('RaceMessageCount groups messages by race', function(t) {
var statistics = {
'White': 4,
'Also-white': 3,
'Person-of-colour': 2,
'Unknown': 1
};

var userIsPersonOfColour = {
'White': false,
'Also-white': false,
'Person-of-colour': true,
'Unknown': undefined
};

var generator = new RaceMessageCount(statistics, userIsPersonOfColour);
statistics = generator.generate();

t.equal(statistics.whitePeople, 7, 'counts 7 messages from white people');
t.equal(statistics.peopleOfColour, 2, 'counts 2 messages from people of colour');
t.equal(statistics.unknown, 1, 'counts 1 message from unknown');

t.end();
});
18 changes: 11 additions & 7 deletions test/statsbot.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,17 @@ test('StatsBot reports a channel\'s message counts when requested', function(t)
var adapter = new SlackAdapter(fakeClient);
var bot = new StatsBot(adapter, fakeUserRepository, {statsChannel: 'statsbot', reportingThreshold: 2});

var alice = {id: '1', name: 'Alice', isMan: true};
var bob = {id: '2', name: 'Bob', isMan: false};
var alice = {id: '1', name: 'Alice', isMan: true, isPersonOfColour: false};
var bob = {id: '2', name: 'Bob', isMan: false, isPersonOfColour: true};
var carol = {id: '3', name: 'Carol', isMan: true, isPersonOfColour: true};

var userStub = sinon.stub(adapter, 'getUser');
var retrieveAttributeStub = sinon.stub(fakeUserRepository, 'retrieveAttribute');

[alice, bob].forEach(function(person) {
[alice, bob, carol].forEach(function(person) {
userStub.withArgs(person.id).returns(person);
retrieveAttributeStub.withArgs(person.id, 'isMan').returns(Promise.resolve(person.isMan));
retrieveAttributeStub.withArgs(person.id, 'isPersonOfColour').returns(Promise.resolve(person.isPersonOfColour));
});

var xenon = {id: 'Xe', name: 'Xenon', send: sinon.stub()};
Expand Down Expand Up @@ -96,7 +98,7 @@ test('StatsBot reports a channel\'s message counts when requested', function(t)
});

bot.handleChannelMessage(xenon, {
user: alice.id,
user: carol.id,
channel: xenon.id,
subtype: 'me_message'
});
Expand Down Expand Up @@ -129,17 +131,19 @@ test('StatsBot reports a channel\'s message counts when requested', function(t)
t.ok(botChannel.send.calledWithMatch(/men sent 100%/), 'reports that only men spoke in one channel');

t.ok(ytterbium.send.calledWithMatch(/not-men sent 0% of messages/), 'reports in the channel that not-men sent no messages');
t.ok(ytterbium.send.calledWithMatch(/people of colour sent 0% of messages/), 'reports in the channel that people of colour sent no messages');

t.ok(botChannel.send.calledWithMatch(/#Xenon/), 'reports #Xenon statistics in the bot channel');
t.ok(botChannel.send.calledWithMatch(/the 3 messages/), 'reports a message count of 3');
t.ok(botChannel.send.calledWithMatch(/men sent 67%/), 'reports that men spoke ⅔ of the time in the other channel');
t.ok(botChannel.send.calledWithMatch(/not-men sent 33%/), 'reports that not-men spoke ⅓ of the time in the other channel');

t.ok(botChannel.send.calledWithMatch(/Of the 2 participants/), 'reports that there were 2 participants');
t.ok(botChannel.send.calledWithMatch(/50% of participants were men/), 'reports that men made up ½ of participants');
t.ok(botChannel.send.calledWithMatch(/50% were not-men/), 'reports that not-men made up ½ of participants');
t.ok(botChannel.send.calledWithMatch(/Of the 3 participants/), 'reports that there were 3 participants');
t.ok(botChannel.send.calledWithMatch(/67% of participants were men/), 'reports that men made up 67% of participants');
t.ok(botChannel.send.calledWithMatch(/33% were not-men/), 'reports that not-men made up 33% of participants');

t.ok(xenon.send.calledWithMatch(/not-men sent 33% of messages/), 'reports in the channel that not-men sent 33% of messages');
t.ok(xenon.send.calledWithMatch(/people of colour sent 67% of messages/), 'reports in the channel that people of colour sent 67% of messages');

bot.handleChannelMessage(xenon, {
user: alice.id,
Expand Down

0 comments on commit fab4be6

Please sign in to comment.