Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Slack pairings #553

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open

feat: Slack pairings #553

wants to merge 14 commits into from

Conversation

tarikeshaq
Copy link

@tarikeshaq tarikeshaq commented Oct 12, 2020

fixes #514 , closes https://github.com/ubclaunchpad/ideas/issues/8

Details

Creates basic donut style matching for Rocket.

What implemented so far:

  • A donut scheduler that currently runs every minute (for debugging purposes, will bump to a reasonable number once this is ready to land)
  • Some initial refactoring to allow the schedulers to have access to the db
  • Slack api calls needed to:
    • Get a slack channel's id by name
    • Create a private conversation given a list of users
  • Basic persistence of pairings in a new pairings table

TODOs before this is ready:

  • Add persistence, to prevent users from getting matched again
  • Add TTL to entries in the Pairings table I can file a follow up for this, we can live without it for now
  • Add tests
    • For slack API calls
    • For persistence
  • Add documentation
    • General documentation for the feature
    • For the new environment variable
    • Documentation for the new pairings table

Where I am currently:

Contemplating if I should add a table for the pairings or if it should be a part of the User model, leaning towards the latter with possibly opening a ticket for the former beyond this pr.
Went with creating a new table 😄 Now working on adding the TTL and making sure edge cases don't explode on us

I'll be updating the above as I go.

@bobheadxi
Copy link
Member

config/__init__.py Outdated Show resolved Hide resolved
@chuck-sys
Copy link
Collaborator

Contemplating if I should add a table for the pairings or if it should be a part of the User model, leaning towards the latter with possibly opening a ticket for the former beyond this pr.

IMO I think you should go with the former (though the difference in work is pretty significant). Seems less hacky and wouldn't leak too much information (example: /rocket user view can potentially see who you matched with).

And it would set the precedent for similar things in the future.

@bobheadxi bobheadxi removed the ⚒WIP label Oct 12, 2020
Copy link
Member

@bobheadxi bobheadxi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice progress! 🎉

(also, it seems your commit authors arent attached to your GitHub, not sure if intentional?)

app/scheduler/modules/pairing.py Outdated Show resolved Hide resolved
def get_job_args(self) -> Dict[str, Any]:
"""Get job configuration arguments for apscheduler."""
return {'trigger': 'cron',
'minute': '*',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing this is just temporary for testing, but could also just make this a configuration option! SLACK_PAIRING_FREQUENCY for example

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alrighty made it an env variable as a cron job string... not the cleanest so happy for recommendations!

interface/slack.py Outdated Show resolved Hide resolved
@bobheadxi bobheadxi changed the title [WIP] Adds donut feature to rocket feat: Slack pairings Oct 15, 2020
@codecov
Copy link

codecov bot commented Nov 1, 2020

Codecov Report

Merging #553 into master will decrease coverage by 0.54%.
The diff coverage is 83.52%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #553      +/-   ##
==========================================
- Coverage   93.01%   92.46%   -0.55%     
==========================================
  Files          42       44       +2     
  Lines        2420     2589     +169     
  Branches      323      346      +23     
==========================================
+ Hits         2251     2394     +143     
- Misses        110      131      +21     
- Partials       59       64       +5     
Impacted Files Coverage Δ
db/dynamodb.py 85.71% <57.14%> (-4.80%) ⬇️
app/model/pairing.py 65.00% <65.00%> (ø)
tests/memorydb.py 91.17% <76.92%> (+1.06%) ⬆️
app/scheduler/__init__.py 92.30% <80.00%> (-2.94%) ⬇️
interface/slack.py 95.77% <87.50%> (-2.41%) ⬇️
app/model/__init__.py 100.00% <100.00%> (ø)
app/scheduler/modules/pairing.py 100.00% <100.00%> (ø)
config/__init__.py 100.00% <100.00%> (ø)
db/facade.py 100.00% <100.00%> (ø)
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 255ce39...d2e2b87. Read the comment docs.

@tarikeshaq
Copy link
Author

OK I got some time to work on this again (after like 20 days 😢) and Added a few tests.

I think this is ready for a round of review so I'll change it from a draft. My next focus will be docs and addressing any feedback that pops up. No rush on the review, we are all busy and this is decently large.

@tarikeshaq tarikeshaq marked this pull request as ready for review November 1, 2020 07:25
@tarikeshaq tarikeshaq requested review from a team as code owners November 1, 2020 07:25
Copy link
Member

@bobheadxi bobheadxi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fantastic progress, really excited to see this land! Thanks for taking the time to do this ❤️

app/model/pairing.py Outdated Show resolved Hide resolved
app/scheduler/modules/pairing.py Outdated Show resolved Hide resolved
app/scheduler/modules/pairing.py Outdated Show resolved Hide resolved
Comment on lines +43 to +46
self.bot.send_to_channel("Hello! \
You have been matched by Rocket \
please use this channel to get to know each other!",
group_name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should have a configuration option SLACK_PAIRING_TIPS_LINK that can generate a button that links to tips for what to do in a pairing (i.e. "set up video call, talk about x and y") - for Launch Pad this could be a handbook page, for example

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm Can we do this on a follow up or do ya think it's important? Could be a really good first issue for someone!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! Can you add all the TODO items for follow-up issues in the PR description as a checklist, to make sure we don't forget?

db/dynamodb.py Outdated Show resolved Hide resolved
interface/slack.py Outdated Show resolved Hide resolved
config/__init__.py Show resolved Hide resolved
@bobheadxi
Copy link
Member

rocket-pairing-hd

Copy link
Collaborator

@chuck-sys chuck-sys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really good job on this! Seems to just need the docs now.

Comment on lines +51 to +53
self.bot.send_to_channel("Hello! \
You have been matched by Rocket \
please use this channel to get to know each other!",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a long string. Can you put it refactor it to be a static member for easy changing?

Comment on lines +58 to +63
Creates pairs of users that haven't been matched before

:param users: A list of slack ids of all users to match

If a pairing cannot be done, then the history of pairings is
purged, and the algorithm is run again.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talk about what kind of algorithm is used here please.

Comment on lines +83 to +84
not_paired = list(
filter(lambda user: user not in already_added, users))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
not_paired = list(
filter(lambda user: user not in already_added, users))
not_paired = [user for user in users if user not in already_added]

Feel free to not use this. I just want everything to fit nicely on one line.

P Y T h O n I C

Comment on lines +25 to +26
self.user1_slack_id = user1_slack_id
self.user2_slack_id = user2_slack_id
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would 3 people models be represented in the database? Or is it intended that 3 people pairings are a one-off?

Comment on lines +85 to +87
# If we have an odd number of people that is not 1
# We put the odd person out in one of the groups
# So we might have a group of 3
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# If we have an odd number of people that is not 1
# We put the odd person out in one of the groups
# So we might have a group of 3
# If we have an odd number of people that is not 1,
# or if there is 1 person left unpaired:
# We put the odd person out in one of the groups
# So we might have a group of 3

Comment on lines +322 to +326
table_name = self.CONST.get_table_name(Model)
table = self.ddb.Table(table_name)
table.delete()
table.wait_until_not_exists()
self.__create_table(table_name)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May want to comment that this is the best way to remove all items from a table, because it makes fewer calls.


:param users: the list of users to add to the private chat

:raise SlackAPIError if the slack API returned error openning the chat
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
:raise SlackAPIError if the slack API returned error openning the chat
:raise SlackAPIError if the slack API returned error opening the chat

@@ -18,6 +18,7 @@ AWS_ACCESS_KEYID='53'
AWS_SECRET_KEY='itsa secret'
AWS_USERS_TABLE='users'
AWS_TEAMS_TABLE='teams'
AWS_PAIRINGS_TABLE='pairings'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May want to add the optional config options for others to see how it works.


def test_valid_pairing(self):
"""Test the pairing static method is_valid()."""
self.assertTrue(Pairing.is_valid(self.p0))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to test the invalid cases as well!

Comment on lines +38 to +40
assert 'user1' in args
assert 'user2' in args
assert len(args) == 2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assert 'user1' in args
assert 'user2' in args
assert len(args) == 2
self.assertIn('user1', args)
self.assertIn('user2', args)
self.assertEqual(len(args), 2)

There are others.

@bobheadxi
Copy link
Member

Nothing that this closes https://github.com/ubclaunchpad/ideas/issues/8 as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

donut-style random pairing for members in a certain channel
3 participants