No description, website, or topics provided.
Switch branches/tags
Clone or download
Latest commit 017227b Dec 12, 2018
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci Configure circle ci to read from eslint Dec 4, 2018
.github Add Pull Request Template Dec 4, 2018
app Fix issue with lint Dec 10, 2018
bin Implement rubocop and rubocop-rspec Dec 3, 2018
config Pull out GreenhouseWebhook logic into a seperate GreenhouseWebhooksCo… Dec 5, 2018
db Implement rubocop and rubocop-rspec Dec 3, 2018
frontend Use jest's it.each instead of duplicating tests Dec 12, 2018
lib Implement rubocop and rubocop-rspec Dec 3, 2018
log first commit Aug 16, 2018
public first commit Aug 16, 2018
spec Permit more specific parameters, add spec for when interviews is empty Dec 10, 2018
storage first commit Aug 16, 2018
test/fixtures/files add User redux cycle, incomplete Sep 17, 2018
tmp first commit Aug 16, 2018
vendor first commit Aug 16, 2018
.DS_Store update gemfile and package.json for deployment to Heroku Sep 5, 2018
.babelrc Setup ESLint to work with Jest Oct 13, 2018
.eslintrc.json Add react version to eslint config Dec 4, 2018
.gitignore Add logs to gitignore Dec 10, 2018
.rspec Add RSpec tests; implement login and logout Sep 14, 2018
.rubocop.yml Rubocop ignore spec_helper; fixup rubocop Dec 3, 2018
.ruby-version Upgrade to ruby v2.5.3 Nov 28, 2018
Gemfile Add webmock to gemfile Dec 7, 2018
Gemfile.lock Add webmock to gemfile Dec 7, 2018
README.md Fix various issues with Rubocop Dec 3, 2018
Rakefile Implement rubocop and rubocop-rspec Dec 3, 2018
config.ru Implement rubocop and rubocop-rspec Dec 3, 2018
jest.config.js Add reporters to jest config Dec 6, 2018
package-lock.json Include eslint-babel as part of the linting process Dec 4, 2018
package.json Add jsx to file extensions to lint Dec 7, 2018
webpack.config.js working skeleton here Aug 16, 2018

README.md

CircleCI

Hello! Welcome to BenchPress ATS for and by Stride Consulting!

Live Site

This is a super quick and dirty readme to get you started with the most basic information a benched Strider might need to continue development on this app.

"What is BenchPress ATS?"

BenchPress? Great name!

I might as well start by getting the important stuff out of the way: While BenchPress is a great name, I cannot take credit for it. That honor belongs to fellow Strider Boris P. Also, shout outs for amazing jobs by Sean M., Travis V., and James Y. for their efforts and collaboration which really helped the project take a giant leap forward!

BenchPress was designed to replace the current code test pull queue which populates to Google Sheets. As the volume of incoming code tests to be graded grows, recruiting was looking for a more robust system which could publicize code tests anonymously for grading while storing the information in a more manageable and useful way.

BenchPress solves this problem by collecting candidate test information inside a database instead of a spreadsheet allowing the data to be much more flexible in how it is stored and retrieved. BenchPress receives it's input primarily from a webhook fired from recruiting's GreenHouse ATS whenever a candidate submits a code test (sort of).

Project Management

To see the project's current feature pipeline, simply install the wonderful ZenHub Chrome Extension.

  • visit ZenHub.io, install the ZenHub Chrome Extension, and authorize when prompted
    • Note: this installation assumes you visit zenhub.io using Chrome
  • once the extension is installed, you should be able to visit the boards by typing 'b', or, if clicking is more your speed, simply click the "Boards" tab on the repo's homepage

Getting Started

Backend

Get the ruby version specified in .ruby-version. Should use a ruby version manager like rbenv to ensure you can gracefully switch between them in the future.

Then do bundle, if you don't have bundler, do gem install bundler. You'll probably need postgres if you haven't installed it already. This is helpful to install postgres.

Next, ping one of the devs for the config/master.key file, and put it in your local directory.

Then, create the db by doing rake db:create and rake db:migrate. Seed data with rake db:seed.

Frontend

You need to run webpack in order to have views rendered. First, ensure you have npm and node installed. I recommend using a Node version manager to keep track of Node versons.

Then, do npm i on the main directory. Then run npm run webpack

Finally, you can start your app with rails s and visit localhost:3000.

Running tests

Currently there are only rspec tests written for this project. Future test coverage for BenchPress should include running javascript tests as well as potentially running code linters such as eslint and rubocop.

bundle exec rspec

Run rubocop with rubocop at project root

Deploying

Benchpress uses a CircleCI worflow for continuous integration and can be found here.

After getting anoter Stride team member to review and approve your pull request, simply merge the pull requests into master and CircleCI will do the rest. If the new code changes are green the code will be deployed automatically to Heroku through CircleCI and if for some reason the build fails a notification will be sent to the #benchpress Slack channel.

"How does it work?"

BenchPress is essentially a Rails API serving up a PostgreSQL database on the backend. Frontend Views are generated with React and manipulated through the use of Redux actions. Finally, user authentication is being handled by the Ruby "Devise" gem. This gem generates its own html views for sign-in.

Credentials Setup

  • Create a master.key file in the top-level config directory. Do not commit this file.
  • Contact James Yoo to receive a Google OAuth credential key. Paste the key into the master.key file.
  • Execute bin/rails server to start the Rails server.

Backend

BenchPress utilizes PostgreSQL to store and model candidate test information. A typical test follows this schema:

== Schema Information

Table name: tests

 id              :bigint(8)        not null, primary key
 applicant_name  :string           not null
 download_url    :string
 language        :string           not null
 due_date        :date
 greenhouse_url  :string
 priority        :integer          default("normal")
 created_at      :datetime         not null
 updated_at      :datetime         not null
 pass            :boolean
 grader_id       :integer
 done            :boolean          default(FALSE)
 manual_priority :integer

The API currently contains all RESTful routes and action for tests, though some of them are not used in this current iteration. The API also contains an endpoint known as "tests#webhook" which will receive post requests directly from GreenHouse and populate the database and views accordingly (again, sort of. It currently appears in the view only on refresh.)

#routes.rb

Rails.application.routes.draw do
  devise_for :users, controllers: {
    sessions: 'users/sessions',
    omniauth_callbacks: 'users/omniauth_callbacks'
  }
  root to: "static_pages#react_root"                  #Serves up the SPA react views

  namespace :api do
    resources :tests, except: [:new, :edit]
    post 'webhook', to: 'tests#webhook'               #Receives POST requests from GreenHouse
    get 'current_user', to: "users#user"
  end

end

As for Devise... There's lots of "Rails Magic" involved but the gem is pretty well documented. You can find more info here.

Frontend

BenchPress' React Frontend is served up by the "StaticPagesController." The "root" view rendered in this controller is a simple HTML element with id="root" into which our React virtual DOM will be rendered. Rails checks for a current_user before allowing access to This view.

Redux State

The Redux State contains slices for tests and ui. The ui slice of state is currently also handling the tracking of the current_user.

"state": {
  "errors": [],
  "tests" : {
    "1": {"id": 1, "applicant_name": "Rose Tyler", "download_url": "www.dropbox.com/...", "language": "Python", "due_date": "2018-09-17", "..."},
    "2": {"id": 2, "applicant_name": "Martha Jones", "download_url": "www.dropbox.com/...", "language": "Ruby", "due_date": "2018-09-17", "..."},
    "3": {"id": 3, "applicant_name": "Jack Harkness", "download_url": "www.dropbox.com/...", "language": "Node", "due_date": "2018-09-17", "..."},
    "4": {"id": 4, "applicant_name": "Amy Pond", "download_url": "www.dropbox.com/...", "language": "Java", "due_date": "2018-09-18", "..."},
    "5": {"id": 5, "applicant_name": "Rory Williams", "download_url": "www.dropbox.com/...", "language": "Python", "due_date": "2018-09-18", "..."},
    "6": {"id": 6, "applicant_name": "River Song", "download_url": "www.dropbox.com/...", "language": "Ruby", "due_date": "2018-09-18", "..."},
    "7": {"id": 7, "applicant_name": "Donna Noble", "download_url": "www.dropbox.com/...", "language": "Node", "due_date": "2018-09-19", "..."},
    "8": {"id": 8, "applicant_name": "Clara Oswald", "download_url": "www.dropbox.com/...", "language": "Java", "due_date": "2018-09-19", "..."},
    "9": {"id": 9, "applicant_name": "Bill Potts", "download_url": "www.dropbox.com/...", "language": "Python", "due_date": "2018-09-20", "..."}
  },
  "ui": {
    "filters": {"language": "All", "priority": "All"},
    "modal": {"type": null, "testId": null},
    "session": {"current_user": 1, "isAdmin": true}
  }
}

Admin status

One of the problems BenchPress was created to solve was to allow for a single source of information to provide interfaces for Graders (which would be anonymous) and Admins (Which would provide access to further information and function).

We take care of this mainly with frontend rendering. Many of our core components contain variations to be displayed if the component receives the admin prop, derived from Redux state.

const NavBar = ({ admin, openAddTestModal }) => {
  // ...

  const addTestButton = admin ?
    <div className="nav-button add-test" onClick={openAddTestModal}>
      <FontAwesomeIcon icon={faPlusCircle} size="lg"/> Add New Test
    </div>
    : null;

  // ...
};

Given the admin prop components display the applicants name and the mark as done checkboxes

Heroku

The App is currently hosted at this url. I have created a Stride account on Heroku and transferred the app there so we can better collaborate on it. Stride is also paying for the hobby dyno so that the app is up and running 24/7. If you're a fellow Strider interested in working on this project just reach out to me and I can get you the Heroku Credentials.

So to sum up...

BenchPress ATS is a very basic CRUD application, which renders information conditionally based on the viewers admin status. I started developing the app when I had time on the bench waiting for my first client and much of it was done without collaboration in a vacuum, this to say that there's loads of opportunities for it to be improved and redesigned and I very much welcome feedback and collaboration on this project.

BenchPress was designed with the intent to help streamline the the process of screening new applicants so that we can focus more on what really matters when meeting people. This is a pursuit which we all have ownership of as we decide who we want to work as part of our team and so in that spirit we should all feel like we have ownership over this project if we so choose.

Future Directions & Room For Improvement

Thanks to Ian for a great start on the project. I've updated the ReadMe to more accurately reflect the state of the application, and we've successfully collaborated to launch an MVP, but there are a few loose ends if anyone would like to hop on the project.

  • Creating interface for admins to manually request a second grader after a code test has been claimed. This one is a big one, and will require some DB schema changing to allow multiple graders. (4 points)
  • Further validation/sanitization of form inputs for admins who manually add or update a test (e.g. the external links generated by submitting these forms won't work unless the url begins with "https://" or "http://" due to ReactRouter -- instead they lead to something silly like "stride-benchpress.herokuapp.com/google.com") (2 points)
  • Finding a good way to determine the language of code test submissions that do not fall under the core 4 (Ruby, JS, Python, Java). (2 points)
  • Creating interface for graders to "unclaim" tests (1 point)
  • Styling (for the sake of expediency the width of cells on the TestIndexTab and TestIndexHeader are fixed, but using a grid format to more correctly align elements would be helpful) (1 point)

Design decisions that may prove unsuitable

Requirement defined by recruiting team: Code test submissions should be normal priority by default, and be automatically upgraded to high priority after 2 days if still ungraded. Should an admin manually change the priority, the code test priority should remain fixed and no longer upgrade/downgrade unless specified by an admin.

Implementation: After some debate, I approached this problem by creating two separate attributes on the Test model, priority (required by Rails validations) and manual_priority (optional attribute). A Rake task, run on a fixed interval by Heroku Scheduler, will upgrade the priority attribute on the appropriate code tests. When serving up JSON data for the frontend, manual_priority (if defined) will take precedence over priority. When sending a patch request from the front-end, any priority changes by the admin will be saved in the manual_priority attribute. (Thus, in theory, a code test can have a high priority due to Rake task automation, and a low manual priority, and the rendered view would only display a low priority).