Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e85e946
Add interview option
backspace Jul 9, 2016
1e8319d
Add server with handling of interview rejection
backspace Jul 9, 2016
d7a7cba
Add web process
backspace Jul 9, 2016
96af731
Add handling of more information response
backspace Jul 9, 2016
f5686b5
Add placeholder handling of interview acceptance
backspace Jul 9, 2016
50cf7fe
Add partial first attribute question
backspace Jul 9, 2016
39e79b4
Add attribute-to-question converter
backspace Jul 9, 2016
93a9de2
Add script to start web server
backspace Jul 9, 2016
14b8322
Add interview strings for attributes
backspace Jul 9, 2016
80a8710
Correct imports
backspace Jul 9, 2016
2ada128
Add handling of response to first question
backspace Jul 9, 2016
99fb6ca
Add handling for final interview question
backspace Jul 9, 2016
7a64ae5
Split wrongness suggestion from update message
backspace Jul 9, 2016
c47defb
Add update message before next question
backspace Jul 9, 2016
bfcd59c
Update first question lead-in
backspace Jul 10, 2016
b0a6c36
Add database backing for interview questions
backspace Jul 10, 2016
d7560a7
Correct manness interview answers
backspace Jul 10, 2016
4778124
Add ability to decline attribute identification
backspace Jul 10, 2016
c84d436
Add preliminary handling of OAuth request
backspace Jul 24, 2016
75b6732
Add handling for an OAuth request missing code
backspace Jul 24, 2016
3ef6581
Add handling of an error from the Slack API
backspace Jul 24, 2016
f7fe2e8
Rename bot access token container
backspace Jul 24, 2016
4527ffc
Move manness answers to align with pocness answers
backspace Jul 24, 2016
7a30485
Fix response assertions
backspace Jul 25, 2016
57f19a9
Extract function to generate information report
backspace Jul 25, 2016
3eb185f
Add summary at end of interview
backspace Jul 25, 2016
eba6910
Add checking of verification token
backspace Jul 31, 2016
b05e424
Add disclaimer to interview introduction
backspace Sep 9, 2016
999f968
Replace initial interview response with experiment
backspace Sep 9, 2016
3881412
Remove superfluous response
backspace Sep 10, 2016
395943f
Remove array wrapper around question determination
backspace Sep 10, 2016
306e089
Add assertion descriptions
backspace Sep 10, 2016
d92b61c
Add replacement handling for non-last responses
backspace Sep 10, 2016
505cf83
Add replacement for ultimate attribute answer
backspace Sep 10, 2016
dea7615
Send 200 response explicitly
backspace Sep 10, 2016
ec028fe
Remove colour-setting for interview questions
backspace Sep 10, 2016
05ef311
Remove colour from interview request
backspace Sep 10, 2016
fccd559
Change interview decline answer
backspace Sep 10, 2016
1392b09
Add trimming for direct messages
backspace Sep 10, 2016
6777583
Merge branch 'primary' into buttons
backspace Oct 27, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
web: npm run web
worker: npm start
10 changes: 10 additions & 0 deletions adapter-repl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
var conf = require('./config');

var SlackAdapter = require('./src/slack-adapter');

var SlackClient = require('slack-client');

var client = new SlackClient(conf.get('slackToken'));
var adapter = new SlackAdapter(client);

module.exports = adapter;
45 changes: 26 additions & 19 deletions attributes/manness.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
{
"name": "manness",
"interviewQuestion": "Are you a man?",
"values": [
{
"value": "a man",
"matcherSets": [
[{"matches": "true"}],
[{"matches": "man"}, {"doesNotMatch": "not"}, {"doesNotMatch": "woman"}],
[{"matches": "woman"}, {"matches": "not"}]
],
"texts": {
"information": "you are a man",
"update": "Okay, we have noted that you are a man. ",
"wrong": "If I got it wrong, try saying “I am *not* a man!”",
"statistics": "men",
"table": "men",
"short": "M",
"interviewAnswer": "Yes"
}
},
{
"value": "not a man",
"matcherSets": [
Expand All @@ -10,26 +28,13 @@
],
"texts": {
"information": "you are not a man",
"update": "Okay, we have noted that you are not a man. If I got it wrong, try saying “I am a man”.",
"update": "Okay, we have noted that you are not a man.",
"wrong": "If I got it wrong, try saying “I am a man”.",
"statistics": "notMen",
"table": "not-men",
"terse": "not-men",
"short": "NM"
}
},
{
"value": "a man",
"matcherSets": [
[{"matches": "true"}],
[{"matches": "man"}, {"doesNotMatch": "not"}, {"doesNotMatch": "woman"}],
[{"matches": "woman"}, {"matches": "not"}]
],
"texts": {
"information": "you are a man",
"update": "Okay, we have noted that you are a man. If I got it wrong, try saying “I am *not* a man!”",
"statistics": "men",
"table": "men",
"short": "M"
"short": "NM",
"interviewAnswer": "No"
}
},
{
Expand All @@ -43,7 +48,8 @@
"update": "We have noted that it’s complicated whether you are a man. If I got it wrong, try saying “I am not a man.”",
"statistics": "complicated",
"table": "complicated",
"short": "‽"
"short": "‽",
"interviewAnswer": "It’s complicated"
}
},
{
Expand All @@ -57,7 +63,8 @@
"update": "Okay, we have erased our record of whether you are a man.",
"statistics": "unknown",
"table": "unknown",
"short": "?"
"short": "?",
"interviewAnswer": "Decline"
}
}
],
Expand Down
22 changes: 15 additions & 7 deletions attributes/pocness.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "pocness",
"interviewQuestion": "Are you a person of colour?",
"values": [
{
"value": "a PoC",
Expand All @@ -9,11 +10,13 @@
],
"texts": {
"information": "you are a person of colour",
"update": "We have noted that you are a person of colour. If I got it wrong, try saying “I am not a person of colour”",
"update": "We have noted that you are a person of colour.",
"wrong": "If I got it wrong, try saying “I am not a person of colour”",
"statistics": "peopleOfColour",
"table": "PoC",
"terse": "people of colour",
"short": "PoC"
"short": "PoC",
"interviewAnswer": "Yes"
}
},
{
Expand All @@ -24,10 +27,12 @@
],
"texts": {
"information": "you are not a person of colour",
"update": "We have noted that you are not a person of colour. If I got it wrong, try saying “I am a person of colour”",
"update": "We have noted that you are not a person of colour.",
"wrong": "If I got it wrong, try saying “I am a person of colour”",
"statistics": "nonPeopleOfColour",
"table": "not-PoC",
"short": "N"
"short": "N",
"interviewAnswer": "No"
}
},
{
Expand All @@ -38,10 +43,12 @@
],
"texts": {
"information": "it’s complicated whether you are a person of colour",
"update": "We have noted that it’s complicated whether you are a person of colour. If I got it wrong, try saying “I am a person of colour”",
"update": "We have noted that it’s complicated whether you are a person of colour.",
"wrong": "If I got it wrong, try saying “I am a person of colour”",
"statistics": "complicated",
"table": "complicated",
"short": "‽"
"short": "‽",
"interviewAnswer": "It’s complicated"
}
},
{
Expand All @@ -55,7 +62,8 @@
"update": "We have erased our record of whether you are a person of colour.",
"statistics": "unknown",
"table": "unknown",
"short": "?"
"short": "?",
"interviewAnswer": "Decline"
}
}
],
Expand Down
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"scripts": {
"start": "node --use-strict index.js",
"debug": "node debug --use-strict index.js",
"test": "tap --strict test/*"
"test": "tap --strict test/*",
"web": "node --use-strict web.js"
},
"repository": {
"type": "git",
Expand All @@ -26,14 +27,19 @@
"devDependencies": {
"grunt": "^0.4.5",
"grunt-tape": "0.0.2",
"nock": "^8.0.0",
"require-subvert": "^0.1.0",
"sinon": "^1.12.2",
"supertest-koa-agent": "^0.2.1",
"tape": "^3.4.0"
},
"dependencies": {
"cli-table": "^0.3.1",
"convict": "^0.6.1",
"cron-parser": "^0.6.1",
"koa": "^1.2.0",
"koa-body": "^1.4.0",
"koa-router": "^5.4.0",
"lodash.every": "^3.2.0",
"lodash.find": "^3.2.0",
"lodash.map": "^3.1.4",
Expand All @@ -46,6 +52,7 @@
"sequelize": "^3.21.0",
"sequelize-cli": "1.1.0",
"slack-client": "^1.3.1",
"superagent": "^2.1.0",
"tap": "^0.5.0",
"validator": "^3.28.0"
},
Expand Down
72 changes: 39 additions & 33 deletions src/direct-message-handler.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// TODO this should probably be further decomposed
// Also should maybe just return a reply which the bot actually sends?

var every = require('lodash.every');
var find = require('lodash.find');

var UpdateParser = require('./update-parser');

var attributeConfigurations = require('./attribute-configurations');
var userInformation = require('./reports/user-information');

class DirectMessageHandler {
constructor({userRepository, channelRepository, adapter}) {
Expand All @@ -20,11 +20,39 @@ class DirectMessageHandler {

handle(channel, message) {
if (!message.text || message.subtype === 'bot_message') return;
var text = message.text.toLowerCase();
var text = message.text.toLowerCase().trim();

var user = this.adapter.getUser(message.user);

if (text === 'info') {
// TODO replace the self-identification request with this
if (text === 'interview') {
channel.postMessage({
text: DirectMessageHandler.INTERVIEW_INTRODUCTION,
attachments: [{
title: 'Would you like to self-identify?',
callback_id: 'initial',
attachment_type: 'default',
actions: [
{
name: 'yes',
text: 'Yes',
type: 'button',
value: 'yes'
}, {
name: 'no',
text: 'No',
type: 'button',
value: 'no'
}, {
name: 'more',
text: 'Tell me more',
type: 'button',
value: 'more'
}
]
}]
});
} else if (text === 'info') {
this.handleInformationRequest(channel, message);
} else if (text === 'help') {
this.handleHelpRequest(channel, message);
Expand All @@ -40,34 +68,11 @@ class DirectMessageHandler {
}

handleInformationRequest(channel, message) {
// FIXME fetch the entire user rather than run multiple queries
Promise.all(this.attributeConfigurations.map(function(configuration) {
return this.userRepository.retrieveAttribute(message.user, configuration.name);
}.bind(this))).then(function(values) {
var reply;

if (every(values, function(value) {return value == null || value == undefined})) {
reply = `We don’t have you on record! ${DirectMessageHandler.HELP_MESSAGE}`;
} else {
reply = 'Our records indicate that:\n\n';

this.attributeConfigurations.forEach(function(attributeConfiguration, index) {
var value = values[index];

var valueConfiguration = find(attributeConfiguration.values, function(valueConfiguration) {
return valueConfiguration.value == value;
});

if (valueConfiguration) {
reply += `* ${valueConfiguration.texts.information}\n`;
} else {
reply += `* ${attributeConfiguration.unknownValue.texts.information}\n`;
}
});
}

channel.send(reply);
}.bind(this));
userInformation(message.user, {
userRepository: this.userRepository,
helpMessage: DirectMessageHandler.HELP_MESSAGE,
attributeConfigurations: this.attributeConfigurations
}).then(reply => channel.send(reply));
}

handleInformationUpdate(channel, message) {
Expand Down Expand Up @@ -102,7 +107,7 @@ class DirectMessageHandler {
});

if (matchingValue) {
reply = matchingValue.texts.update;
reply = `${matchingValue.texts.update} ${matchingValue.texts.wrong || ''}`;
}

channel.send(reply);
Expand Down Expand Up @@ -179,6 +184,7 @@ class DirectMessageHandler {
// TODO maybe messages should be collected somewhere central, and parameterised

DirectMessageHandler.HELP_MESSAGE = 'You can let me know “I’m not a man”, “I am a person of colour”, “it’s complicated whether I am white” and other such variations, or ask for my current information on you with “info”. To erase what you’ve previously told me, say “It is unknown whether I am a man”, “it is unknown whether I am white”, and so on. View my source at https://github.com/backspace/slack-statsbot';
DirectMessageHandler.VERBOSE_HELP_MESSAGE = `Hey, I’m a bot that collects statistics on who is taking up space in the channels I’m in. For now, I only track whether or not a participant is a man and/or a person of colour. ${DirectMessageHandler.HELP_MESSAGE}. Please note that, while I won’t directly reveal the answers you provide, it is sometimes possible to deduce them from the statistics I provide and channel logs.`;
DirectMessageHandler.INTERVIEW_INTRODUCTION = 'Hey, I’m a bot that collects statistics on who is taking up space in the channels I’m in. For now, I only track whether or not a participant is a man and/or a person of colour. If you feel comfortable answering questions about this, we can continue.';
DirectMessageHandler.VERBOSE_HELP_MESSAGE = `${DirectMessageHandler.INTERVIEW_INTRODUCTION} ${DirectMessageHandler.HELP_MESSAGE}`;

module.exports = DirectMessageHandler;
16 changes: 16 additions & 0 deletions src/message-buttons/question-for-attribute-configuration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

module.exports = function questionForAttributeConfiguration(attributeConfiguration) {
return {
title: attributeConfiguration.interviewQuestion,
callback_id: attributeConfiguration.name,
attachment_type: 'default',
actions: attributeConfiguration.values.map(value => {
return {
name: attributeConfiguration.name,
text: value.texts.interviewAnswer,
type: 'button',
value: value.value || 'decline'
};
})
};
}
Loading