Giter Site home page Giter Site logo

pairmotron's Introduction

Pairmotron

Build Status

Pairmotron is an app powered by Phoenix that randomly pairs up users within groups on a weekly basis to work on a project or just write some code!

Local Installation

Prerequisites

  • Elixir >= 1.4.0
  • PostgreSQL

Running it

  • Install dependencies with mix deps.get
  • Setup environment variables for your PostgreSQL user (PG_USER) and password (PG_PASSWORD)
    • On Mac or Linux add this to your .bashrc or .zshrc:
export PG_USER="example_username"
export PG_PASSWORD="example_password"
export PG_HOST="localhost"
  • Create and migrate your database with mix ecto.create && mix ecto.migrate
  • Install Node.js dependencies with npm install
  • Start Phoenix endpoint with mix phoenix.server

Developing and Testing with Docker

Using this model of development allows you to not install anything other than docker.

Running it

  • docker-compose up -d web
  • docker-compose exec web mix deps.get
  • docker-compose exec web mix ecto.create
  • docker-compose exec web mix ecto.migrate
  • docker-compose exec web npm install
  • docker-compose restart web

Run the Tests in Docker

  • docker-compose run -e "MIX_ENV=test" web mix test
  • Only test a specific test file
    • docker-compose run -e "MIX_ENV=test" web mix test test/controllers/group_controller_test.exs

Check it out in a browser

Now you can visit localhost:4000 from your browser.

Deploy to Production

Ready to run in production?

Environment Variables to set

  • SECRET_KEY_BASE - Used to generate session cookies.
  • PAIRMOTRON_EMAIL_DOMAIN - The domain configured in Mailgun to send password reset email.
  • PAIRMOTRON_MAILGUN_API_KEY - The API key given by Mailgun for the configured domain.

JWT Key Configuration

Pairmotron uses the ES512 algorithm to generate JSON Web Tokens. You will need to generate a key and set the appropriate environment variables.

To generate a key do the following from the root pairmotron directory:

iex -S mix

iex> JOSE.JWK.generate_key({:ec, "P-521"}) |> JOSE.JWK.to_map
{%{kty: :jose_jwk_kty_ec},
 %{"crv" => "P-521",
   "d" => "Ae-wdbGhjfpxapevgJDAxaiGHmKYoyWnYDLeAb9jALSBNBzkyelSL-FUHcdFw1B7V2FvPy3YaHEkrVqwPwBwNvLP",
   "kty" => "EC",
   "x" => "AWFw34kJJaT8Lwew8IG4LcDDr8sMcURn4PhUWMBiMW5vGGonteVvZQAVdW652GFOY9z1nlhymKYXBwNy3PHlz9Z_",
   "y" => "APLY5Rww4oI1fhUI7JrIkmHPymzgpGOKsNXHhxoMJDycdoQPWfaimoOX-afOHoJiGWwh2m_EbTSC-4lC4Cz0uzPk"}}

And then set the following environment variables:

  • GUARDIAN_JWK_ES512_D - The "d" value of the key generated above.
  • GUARDIAN_JWK_ES512_X - The "x" value of the key generated above.
  • GUARDIAN_JWK_ES512_Y - The "y" value of the key generated above.

pairmotron's People

Contributors

adeverteuil-cmm avatar austenmadden avatar ericworkman avatar joelbyler avatar mbramson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pairmotron's Issues

Implement Private/Public groups

Add a field to groups denoting whether they are public or private. Public should be the default.

a private group:

  • Should not be listed on the groups index
  • Should not be viewable by people not in that group

And eventually:

  • Should only be joinable if the owner of the group (or someone with proper group role) invites a user to the group
  • Should be viewable for a user that is not in the group if that user has received an invite to that group.

Disable the ability to generate pairs for weeks that are not the current week

Currently, if you go to a week that is in the past, new pairs are automatically generated for that week. We should disable this functionality for past weeks. Maybe a screen that says "There were no pairs for this week".

Note that this is different than issue #23, as this issue is about disabling the automatic generation of new pairs when you go to a previous week where there were no existing pairs.

Add the ability to state what you have paired on

This could either just be a string field on the Pair model, or perhaps a link to a specific project. I think that it should at the very least have a string field so that we gain some metrics on what users have been pairing on.

This would necessitate a new "post-pair" UI. Perhaps this would be accessible from the main /pairs route?

You should only be able to post about a pair that you actually participated in.

Add created_by association to projects

Add a created_by association on projects that specify who created the project originally.

Right now once a project is created, the only person that can edit a project is the owner of the group that the project is associated with. This is partially good, because we want to protect someone's project, but this causes issues in the situation where a user creates a project, but makes a mistake (or later wants to change the description or something).

The authorization for editing/updating/deleting a project should be changes to additionally allow the creator of the project to do these things.

On the projects index, the user that created a given project should also be able to see the edit/delete buttons which are currently only seen by the owner of the group associated with a given project.

Refactor pair_retro :create action to use Canary

The pair_retro create route is reimplementing a lot of logic that should in theory be handled by Canary. Evaluate whether this code can be improved through the use of Canary.

Some fiddling reveals that this is probably a bit more complicated than simply adding the :create action to the load_and_authorize_resource, as the Canada protocol doesn't seem to pick up the user_id of the retro, as it is passed in as a parameter nested in the pair_retro parameter. So conn.assigns.authorized will be true for admins, but not when the passed in nested user_id parameter matches the user id of the logged in user in .conn.assigns.current_user.

This might be as simple as figuring out what to match on in this case in the Canada protocol, or it may involve some more in depth logic. Could be a good opportunity for a PR to Canada or Canary.

It's also possible that the solution is actually less elegant than the currently existing code. In which case this would be closed with no code change.

Add forward and back buttons to the main page

It would nice to have some way to traverse weeks (forward and backwards) on the main page that displays pairs.

Going back is definitely useful so that you can comment on previous pairs when it isn't the current week (without knowing the route to do this off the top of your head) as per #32.

Going forward will be useful to be able to specify a user you'd like to pair with for a coming week for #34.

Can't create local database

crees  ~  workspace  elixir  pairmotron  mix ecto.create && mix ecto.migrate                                                                                                                    1   bug/missing-whitespace

12:50:02.945 [error] GenServer #PID<0.192.0> terminating
** (KeyError) key :username not found in: [types: true, backoff_type: :stop, pool: DBConnection.Connection, database: "template1", otp_app: :pairmotron, repo: Pairmotron.Repo, adapter: Ecto.Adapters.Postgres, hostname: "localhost", pool_size: 10]
    (elixir) lib/keyword.ex:333: Keyword.fetch!/2
    (postgrex) lib/postgrex/protocol.ex:414: Postgrex.Protocol.startup/2
    (postgrex) lib/postgrex/protocol.ex:353: Postgrex.Protocol.handshake/2
    (db_connection) lib/db_connection/connection.ex:134: DBConnection.Connection.connect/2
    (connection) lib/connection.ex:622: Connection.enter_connect/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: nil
State: Postgrex.Protocol
** (Mix) The database for Pairmotron.Repo couldn't be created: an exception was raised:
    ** (KeyError) key :username not found in: [types: true, backoff_type: :stop, pool: DBConnection.Connection, database: "template1", otp_app: :pairmotron, repo: Pairmotron.Repo, adapter: Ecto.Adapters.Postgres, hostname: "localhost", pool_size: 10]
        (elixir) lib/keyword.ex:333: Keyword.fetch!/2
        (postgrex) lib/postgrex/protocol.ex:414: Postgrex.Protocol.startup/2
        (postgrex) lib/postgrex/protocol.ex:353: Postgrex.Protocol.handshake/2
        (db_connection) lib/db_connection/connection.ex:134: DBConnection.Connection.connect/2
        (connection) lib/connection.ex:622: Connection.enter_connect/5
        (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

Make the url and description not required for projects

Urls should not be a required field for projects. Not all potential projects to pair on are code related or on the internet. It could be "put together that table in the corner", for example.

Descriptions also should not always be required. Sometimes a project is simple enough that the title is sufficient.

Allow group owners to transfer ownership

Currently there is no way for an owner of a group to give ownership to another user. Implement this.

If the current user is the owner of a group, when they are editing the group, they should be able to transfer ownership of the group. This updates the group with a new owner.

Users with the group roles (not yet implemented) sufficient to edit a group, should not be allowed to transfer ownership of the group (or see the UI for this).

It will likely make sense to add a validation step to the group changeset, that ensures that any user changing the owner of a group is either the current owner of the group or an admin.

Implement group-specific pairs

Pairs should not be global, they should be filtered by group. This might mean that the route to get to pairs changes.

To get to the pairs for a specific group, the route should be /groups/:group_id/pairs. I don't think that this should deprecate the /pairs route, perhaps this just redirects to the first group's (or some default group specified by the user in the future) pairs.

This will involve adding an association between pairs and groups.

This work should be decoupled from the work to redesign the pairing engine currently being spearheaded by @ericworkman.

Warn when deleting a project with associated retrospectives

Currently, when a project is deleted, the project_id of the associated retrospective is set to nil. Although this is the desired behavior, it would be nice if the user was warned before deleting a project with associated retrospectives.

The thinking here is that eventually there will be some interesting data seeing what people have worked on, so we'd want to keep projects associated with retrospectives if at all possible.

Add Pair Model

Add a pair model that captures a given pairing session. This will be useful for a number of things down the line including histories and preventing users from being paired with users they paired with the week previous,

At a minimum it would have the following fields:

  • Date of Pair
  • Many users
    • 2 or more (I wouldn't think there should be any limit)

Some other fields to think about that probably don't make sense yet:

  • Subject of the pairing session
  • Boolean for whether the pairing session actually occurred

Change current page display to a date range

Per the conversation in #28, the current method of displaying which week it is:

Pairs for Week 40 of 2016

runs into some user experience problems at the end of the year for certain years. Users might see a year that is actually the current week, but isn't actually the correct year.

A better method of displaying the current week would be something like:

Pairs for 11/14/2016 to 11/20/2016

Some things to note:
Weeks start on Mondays and end on Sundays.
There should be a new test for a week that wraps around the end of the year.

Fix being able to create a retrospective for a pair you are not a part of

Currently, you can post to the pair_retro create route to create a retrospective for a pair that you are not a part of. This should result in an error.

The change should occur in the pair_retro changeset function. More information may need to be given to the changeset for this validation to occur.

Add Administrator Role

Add a role table. Each role should have a has_many relationship to users.

Add user and administrator roles. The first user should be made the administrator. This should be the user with the lowest id.

Administrators should be able to make other users administrators as well. Users should not be able to change the role of other users.

Some things to think about:

  • If there are no users, and a user is registered/created, they should be made an administrator.
    • Thought about this, probably safer just to see an admin user/role or maybe just the role itself.
    • First user being an admin, might be convenient for someone hosting pairmotron, but might actually be confusing from a development standpoint for newer contributors down the line.
  • In the migration that adds the administrator role, the user with the lowest id should be made an administrator.
    • After some thought, probably not a good idea.
  • Only administrators should be allowed to delete users.
  • If an administrator is deleted and there are no more administrators, the user with the lowest id should be made an administrator.
    • After some thought, probably not a good idea.
    • There should be some sort of warning or confirmation when a user tries to delete the last administrator that informs them that they are doing so and that a new user will be selected to be the only administrator.
    • A warning might still be nice, but I think this is outside of the scope of the issue.

Make PairRetroController :new and :edit actions pass projects parameter

Currently, the PairRetroController assigns the list of all projects to the conn.assigns where it is retrieved through a method on PairRetroView and then passed to the form in the web/templates/pair_retro/new.html.eex and web/templates/pair_retro/edit.html.eex.

This should probably be refactored so that the PairRetroController passes the projects as a parameter directly to the new.html.eex and edit.html.eex templates. This eliminates the View method, and generally cleans up the code.

Disable recalculation of pairs for weeks that are not the current week

Pairs for past weeks can be recalculated by clicking Repairify for routes in the past. This shouldn't be possible, as theoretically a past week's pairs already happened and should be set in stone. This will be useful if we eventually want to generate statistics on pairing over time.

Note that this issue is different from #24, as this is about disabling the Repairify button for weeks in the past where there were already existing pairs.

Allow users to leave groups they are members of from their Profile

Users should be able to remove themselves from groups they are in from the Profile screen.

There should be confirmation when they try to do this, to prevent users from accidentally doing so.

Think about how this should be handled for groups where the user is an owner. A naive approach would be to allow it but keep them as the owner since that is technically a valid state. Perhaps prevent them from doing so entirely if they are the owner of the group? This would force them to either delete the group, or transfer ownership to someone else (second of which is not yet implemented as of writing this).

Fix repairify deleting pairs when nothing changes

Currently when the repairify button is clicked, all pairs are deleted, and then new ones are created. If nothing changes about the users in the pool of active users, the same pairs are created, but the original pairs in the database are still deleted. Not only is this a bit wasteful, but it has the side effect of deleting any retrospectives that have been completed for any pairs in that week.

It would be nice to have some sort of mechanism for retaining the pairs in the database in the case that the pool of active users hasn't changed so that the retrospectives aren't deleted for no apparent reason. If the pool of users has changed, then deleting the retrospectives is fine, as the most people will likely be paired with someone else.

Fix redirect issue when signing up for pairmotron

When signing up, when the user submits their information to create a new account and hits submit, the user should be logged in and taken to the /pairs page. There appears to be a bug during that process that results in the following:

register-redirect-bug

Implement Request for Membership and Invitations to Groups

Currently, the only way for a user to join a group is through the /admin interface, which is obviously very much less than ideal.

Users should be able to request membership for a group. When they do so, they should be able to see that they have done so somehow (and not be able to request membership again while the first has not been acted upon). The owner of the group that the user has asked to join should be able to see that the user has requested membership (ideally in a centralized location with all requests for membership for that group). They should be able to either deny membership, or accept the request for membership. If they accept, the user should then be associated with that group.

Owners should be able to invite users to be a member of the group that they own. Users should be able to see a list of all the groups that they've been invited to. They should be able to accept or deny the invitation. If they accept, the user should then be associated with that group.

Change PageController to PairController

All of the functionality in the PageController is specific to pairs, and should just be the PairController. The decision to make it the PageController was made in the very first commit, and is no longer appropriate. Outside of perhaps the show route for the controller changing from "/year/week" to "pairs/year/week" (and the same for the delete route), the functionality should remain identical.

Add Potential Project Model

It would be nice to have a few suggested pairing projects accessible somewhere on the UI. This would be an updatable list of projects that someone can pair on. Examples: Pairmotron, Nermesterts, BoardGameGeekClient, etc.

Some thoughts on fields:

  • Name
  • Description of the project
  • Link to project

Add User Authentication

Doesn't have to be super fancy or secure, but it would be nice to get something in place so that a current user can be put in session for other functionality down the line such as groups, admin, etc.

Make projects group-specific

Projects should not be global, rather they should be per group.

The project model will have to be updated with a group relation.

If a user is not a member of a group, they should not be able to see projects associated with that group.

There should be a dropdown in the projects index with all of the groups that the current user is a part of.

Add ability to specify that you are pairing with a specific user for a week

If a user knows that they would like to pair with a specific person the following week, there should be some way for them to specify this intention. If both users specify that they would like to pair with one another, they should be paired that following week.

Some things to think about:

  • This should be something that can occur for weeks that have yet to pair.
  • Since currently pairs are only made if there are no existing pairs for that specific week, this logic shouldn't get in the way of that. If there are 10 users and Users 1 and 2 specify that they would like to pair for the following week, when that week is reached, Users 1 and 2 should be paired, but the rest of the users should be paired randomly.
  • If two users have specified that they'd like to pair for a specific week, when you hit repairify for that week, they should remain paired (although the others users would still potentially be shuffled)
  • This should bypass the logic that prevents users from being paired with the users that they were paired with the previous week (implemented for #7)

This is blocked by #43 as you should be able to do this for coming weeks, which #43 will enable (without route memorization) from a UI perspective.

Add links to the projects index

Currently the /projects index lists the url for each project, but it is not clickable. It would be nice if there was a link to those projects somewhere.

Implementation options include:

  • Make the "Url" column a hyperlink
  • Make the "Name" column a link the the url for that project and omit the "Url" column entirely.
    • If this option is chosen, make sure that the name is not a hyperlink if there is no url specified for a given project.

Disallow creation of retrospectives for projects not belonging to group associated with pair

Once pairs and projects are associated with groups, users should not be able to select a project when creating a retrospective that is not associated with their group.

This would change the projects in the selection box of the new action form for projects and also make sure that the changeset used to create a retro validates that the project is actually associated with the group associated with the pair.

Properly handle the update of a retrospective's associated project

There are some edge cases associated with updating a retrospective's associated project.

The list should only contain the projects associated with the group that the pair is associated with.

If the user has been removed from a group and edits an existing retrospective associated with a pair (associated with that group) they had when they were still in that group, they should not be allowed to change the project.

They should be able to edit the project field if they are still in the group associated with the retrospective (through the pair).

Add Active column to the /users index page

To see whether a user is active, you currently need to be look at a specific user. It would be nice if we could see which users were active at a glance when looking at all users. Bonus points if you could also toggle them active/inactive from the list as well.

Disable ability to delete other users

Users can delete other users right now. This should not be possible. You should be able to delete your own user but not someone else's. You should be able to use an out of the box authorize_resource plug from Canary to do this.

For now, you should still be able to edit other users. Once #35 has been addressed, all user edit and update actions should also be limited to the logged in user or an administrator.

No links to get back to the main page

The logo is a link, but it's not super obvious. There should either be some sort of Home link or there should be Back buttons on the Users and Projects pages

Allow group owners to remove users from their groups

Group owners should be able to remove specific members from their group. The users in a group should be added to the group edit action. In this listing/table, a button/link should be present allowing the removal of that user from the group. This would be a deletion of the UserGroup record.

If the remove action is selected, a confirmation dialog should appear.

Implement Logic Preventing Repeat Pairs

When pairs are made, prevent pairs from forming where that pair occurred the week before.

Some thinking could go into this, but I'm thinking a 3 person pair of person A, B, and C is distinct from a pair of A and B.

Obviously a pair of A and B is the same as a pair of B and A. Same thing goes for a three person pair of A, B, and C and a three person pair of C, B, and A.

If #34 is implemented before this is complete, we shouldn't disallow users that were paired last week from specifying that they'd like to pair the following week too if they both select one another.

Fix Readme

Change from the default Phoenix Readme to one that actually describes pairmotron.

One thing to touch on:

  • Setting up db credentials

Add ability to toggle users active/inactive

Currently, all users that exist are paired. Add some toggle on a user to make it be skipped for the purpose of pairing. This is to accommodate users being on vacation or any other reason they might not want to pair.

Make activity group-specific

Currently, users can be active or inactive globally for the purposes of pairing. Add the ability to toggle user activity for specific groups individually.

Users will want to be able to be active for certain group pairings, but not others.

This card should leave the is_active field on Users present, as using this group-specific activity is outside the scope of this card, as it will be a part of redesigning pairing.

First week of the year via Timex.iso_week

Timex.iso_week implements ISO weeks which have an interesting implication for the first week of the year. The first ISO week of the year is the first week with a Thursday in it. For example, January 1, 2005 lands on a Saturday. Its ISO week is 2004 week 53.

This gets us in trouble if we want to look up a pair for the first week of January. January 1, 2016 was 2015 week 53. We should consider replacing Timex.iso_week with something more natural, change the /year/week lookup to a date (so ISO week can be calculated), or by adding the covered dates to the pair page.

This won't affect us for 2017 or 2018 at least, but its something to consider. @mbramson discovered this issue.

Add Groups

Add groups so that users can be members of (multiple groups per user? Some more thinking here). Each user would then be paired within their own group.

There would need to be some sort of way to decide which group you were looking at in the page controller. The displayed pairs would filter accordingly.

Projects would also need to be associated with groups.

It would be nice if there was an invite mechanism for groups, so that the user that creates a group becomes an admin of that group, and is then the one that distributes invites to the group.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.