diff --git a/.dockerignore b/.dockerignore new file mode 100755 index 000000000..27d2dae2b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +*/node_modules +*.log diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..0dbf448a7 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "trailingComma": "es5", + "semi": true, + "singleQuote": true +} diff --git a/.travis.yml b/.travis.yml index ce15f33ef..927b5508f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: ruby -cache: bundler +cache: + bundler: true + yarn: true sudo: false bundler_args: --path vendor --local --without development env: @@ -15,3 +17,8 @@ script: addons: code_climate: repo_token: 702251f0d6eb1f569078a27c4ae3366b1e48c4c6d7e4dd3ae0ca3583fd2bc8db +deploy: + provider: script + script: bash website/travis-deploy.sh + on: + branch: master diff --git a/Dockerfile-website b/Dockerfile-website new file mode 100755 index 000000000..1a2ba482e --- /dev/null +++ b/Dockerfile-website @@ -0,0 +1,10 @@ +FROM node:8.11.4 + +WORKDIR /app/website + +EXPOSE 4000 35729 +COPY ./docs /app/docs +COPY ./website /app/website +RUN yarn install + +CMD ["yarn", "start"] diff --git a/README.md b/README.md index fe52d6fe2..2b400133e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ An all-in-one platform for managing hackathon registration & logistics, originally developed for [BrickHack](https://github.com/codeRIT/brickhack.io). +Read more at **[coderit.org/hackathon-manager/](https://coderit.org/hackathon-manager/)** + - **Hacker applications:** Enable hackers to apply to your hackathon while providing all relevant information (contact info, school, demographics, etc) - **MyMLH support:** Streamline the application process when users log in with [MyMLH](https://my.mlh.io/), a common platform for applying to any MLH hackathon. Basic info is pre-filled based on a common application, so hackers don't have to re-type it every time. - **Admissions & RSVPs**: Facilitate accepting hackers to your hackathon & enable them to RSVP @@ -35,34 +37,16 @@ HackathonManager makes use of a few different third-party services & Ruby gems: - [Blazer](https://github.com/ankane/blazer) (custom SQL queries, analytics, and charts) - [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper) (authentication via OAuth for API usage) -See [Deployment](#Deployment) for instructions to deploy. - -### Customization - -Be sure to review all of these before going live! - -- **Content**: Various settings are available at http://your-site/manage/configs -- **Emails**: Default automated emails are loaded into http://your-site/manage/messages -- **Styling**: Custom styling is not yet supported, but should be available starting Summer 2019. - -## Deployment +## Get Started -HackathonManager supports two platforms out of the box: - -- [Heroku](https://www.heroku.com) — Easiest & quickest way that requires little server knowledge, however isn't cheap (free tier not recommended) -- [Dokku](http://dokku.viewdocs.io/dokku/) — A free alternative to Heroku, runs on your own virtual machine -- [OKD/OpenShift](https://www.okd.io) — "Enterprise Kubernetes for Developers" packaged with a useful management UI + tooling - -See the platform-specific guides [on the Wiki](https://github.com/codeRIT/hackathon_manager/wiki) to get started! - -HackathonManager can also be deployed the same as any other Rails app, however this is **not** natively supported and will require you to fork this repo to integrate code changes. - -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) +**[Deploy HackathonManager for your hackathon »](https://coderit.org/hackathon-manager/docs/deployment)** ## Contributing GitHub issues and pull requests welcome! +If there's a new feature you're looking to implement, **please** file an issue to open discussion on the feature before starting work or opening a pull request. + ## Development Pre-requisite: Have a functioning, local Ruby + MySQL development environment. [See this guide for pointers.](https://gorails.com/setup) diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 000000000..924e4b005 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,89 @@ +--- +id: api +title: API Usage +--- + +Almost all of the functionality exposed to users can also be accessed as an API with OAuth credentials. This includes both public- and management-facing functionality. + +**Please note:** HackathonManager's primary audience is the web interface. + +While functionality may co-exist for both browser and API usage, API-style support might be a little rough around some edges. If you stumble upon something that works a little different than usual (e.g. returns HTML instead of JSON), open an issue and we can figure it out. + +## Endpoints + +Endpoints are shared with regular page controllers for browser-style functionality. This leverages Ruby on Rails routing (for a deep dive, see [Rails Routing from the Outside In](https://guides.rubyonrails.org/routing.html)). + +For example, listing bus lists: + +- User-facing page: https://apply.brickhack.io/manage/bus_lists +- API endpoint: https://apply.brickhack.io/manage/bus_lists.json + +Because Rails follows a standard CRUD-format, these endpoints become very REST-like. + +For example: + +- List all tags: `GET https://apply.brickhack.io/manage/trackable_tags.json` +- View specific tag: `GET https://apply.brickhack.io/manage/trackable_tags/1.json` +- Create tag: `POST https://apply.brickhack.io/manage/trackable_tags.json` (with a JSON body of parameters) +- Update tag: `PATCH https://apply.brickhack.io/manage/trackable_tags/1.json` (with a JSON body of parameters) +- Delete tag: `DELETE https://apply.brickhack.io/manage/trackable_tags/1.json` + +For a full list of endpoints, run `bin/rails routes` locally. This utility, provided by Ruby on Rails, lists all possible paths you can route too (along with their respective HTTP method). + +**Note: datatable endpoints** are highly coupled to [Datatables](https://datatables.net) functionality and are not easy to use. + +Example for questionnaire management endpoints: + +``` +... + Prefix Verb URI Pattern Controller#Action + datatable_manage_questionnaires POST /manage/questionnaires/datatable(.:format) manage/questionnaires#datatable + check_in_manage_questionnaire PATCH /manage/questionnaires/:id/check_in(.:format) manage/questionnaires#check_in + convert_to_admin_manage_questionnaire PATCH /manage/questionnaires/:id/convert_to_admin(.:format) manage/questionnaires#convert_to_admin +update_acc_status_manage_questionnaire PATCH /manage/questionnaires/:id/update_acc_status(.:format) manage/questionnaires#update_acc_status + bulk_apply_manage_questionnaires PATCH /manage/questionnaires/bulk_apply(.:format) manage/questionnaires#bulk_apply + message_events_manage_questionnaire GET /manage/questionnaires/:id/message_events(.:format) manage/questionnaires#message_events + manage_questionnaires GET /manage/questionnaires(.:format) manage/questionnaires#index + POST /manage/questionnaires(.:format) manage/questionnaires#create + new_manage_questionnaire GET /manage/questionnaires/new(.:format) manage/questionnaires#new + edit_manage_questionnaire GET /manage/questionnaires/:id/edit(.:format) manage/questionnaires#edit + manage_questionnaire GET /manage/questionnaires/:id(.:format) manage/questionnaires#show + PATCH /manage/questionnaires/:id(.:format) manage/questionnaires#update + PUT /manage/questionnaires/:id(.:format) manage/questionnaires#update + DELETE /manage/questionnaires/:id(.:format) manage/questionnaires#destroy + datatable_manage_checkins POST /manage/checkins/datatable(.:format) +... +``` + +## Request & response + +Most endpoints can operate with JSON requests & responses. Simply provide `.json` at the end of the URL to be returned JSON, and provide `Content-Type: application/json` when using POST or PATCH with a JSON body. + +Note that while most endpoints support JSON responses, some do not have this support. Redirect responses are common for some actions, for which you'll receive a 302 redirect response and no JSON body. + +The best way to see what's expected is to look at the controller source code, located at [`app/controllers/`](https://github.com/codeRIT/hackathon_manager/tree/master/app/controllers). Here, you'll see how each endpoint is configured; this maps to the routes listed by `bin/rails routes`. For example: + +```ruby +def show + respond_with(:manage, @questionnaire) +end +``` + +- This "show" endpoint is the natural mapping for something like `GET /manage/questionnaires/1.json` +- Because `respond_with` is used, it will return JSON when `.json` is used in the URL + +# Authentication + +Authentication is implemented with OAauth 2, provided by the [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper) gem. + +An OAuth app should be created by an admin at https://apply.your-hackathon.com/oauth/applications. From there, you can implement a standard OAuth 2 flow. + +For Doorkeeper endpoints + docs, see https://github.com/doorkeeper-gem/doorkeeper/wiki/API-endpoint-descriptions-and-examples + +Once appropriate authentication credentials are retrieved, they should be provided on all API requests. + +### Security note + +For a mobile- or front-end app, or any app that has API calls running on the client, you should **not** use an authorization flow involving the application secret; otherwise, you would be distributing the secret to the public, compromising the whitelist nature of controlling which apps may pose as your users. + +For most use cases, the **authorization code grant** or **implicit grant** flows should be used. Check out [this guide by Auth0](https://auth0.com/docs/api-auth/which-oauth-flow-to-use) for more info. diff --git a/docs/assets/bus-sign-up.png b/docs/assets/bus-sign-up.png new file mode 100644 index 000000000..64386a923 Binary files /dev/null and b/docs/assets/bus-sign-up.png differ diff --git a/docs/assets/promote-bus-captain.png b/docs/assets/promote-bus-captain.png new file mode 100644 index 000000000..5a3d6bac3 Binary files /dev/null and b/docs/assets/promote-bus-captain.png differ diff --git a/docs/assets/questionnaire.png b/docs/assets/questionnaire.png new file mode 100644 index 000000000..354285467 Binary files /dev/null and b/docs/assets/questionnaire.png differ diff --git a/docs/busses.md b/docs/busses.md new file mode 100644 index 000000000..67181bbb0 --- /dev/null +++ b/docs/busses.md @@ -0,0 +1,68 @@ +--- +id: busses +title: Busses +sidebar_label: Busses +--- + +HackathonManager enables you to facilitate bus sign-ups for attendees during the RSVP process. + +## Attendee sign-ups + +**Attendees can sign up for any available bus list.** This is presented to them during the RSVP process. + +By signing up, they reserve one spot on the bus. If a bus fills up, no more attendees will be able to sign up for that bus. + +![Screenshot from attendee perspective for signing up for a bus](assets/bus-sign-up.png) + +## Bus Captains + +Passengers can volunteer to be a captain when signing up for a bus. + +Bus captains: + +- Have their name, email, and phone number shared with bus passengers +- Can see the full passenger list for their bus +- Can mark passengers as boarded during boarding (mobile-friendly) + +### Promoting a passenger to captain status + +Any passenger can be promoted to a captain, even if they didn't volunteer (e.g, you've reached out to them directly). + +You'll see the option to promote a passenger to being a bus captain, as well as a separate section specifically for people that have volunteered to be captains. + +**Upon making someone a captain:** + +- Their name, email, and phone number will be visible to passengers +- The new captain will receive an email notification ([this is the default template](https://github.com/codeRIT/hackathon_manager/blob/master/app/views/mailer/bus_captain_confirmation_email.html.erb)) + +![Screenshot of list of users with link to promote to bus captain status](assets/promote-bus-captain.png) + +### Boarding flow for bus captains + +The day of your hackathon, bus captains will need to know who is allowed on the bus, and mark those that have boarded. + +Bus captains should open https://your-hackathon.com/bus_list and sign in. From there, they can view the entire list of passengers. + +Tapping/clicking on the checkbox next to each name will mark that passenger as boarded/not boarded. + +Example email to a bus captain: + +``` +Hey [name], + +Thanks again for volunteering to be a bus captain! [HackFoo]'s bus to [location] would not be possible without your help, and we greatly appreciate it. + +As a bus captain, you are in charge of who does and does not board the bus. It's incredibly important that **only people who are on the registered passenger list may board.** Not only could an extra person take someone else's seat, but they may not have been accepted to the hackathon and/or have not signed proper liability waivers. + +To help with this, open https://your-hackathon.com/bus_list on your phone. From there, your bus's full passenger list is shown. + +As people board, **tap on the checkbox next to their name** (including yourself). This will mark them as boarded, and will update your "boarded" count for an easy head-count. Once everyone has boarded, do a quick head-count on the bus to make sure these numbers match up. + +If you have any questions day-of, don't hesitate to call or text me at [your cell phone number]. + +Hope to see you soon! + + - [your name] +[your email] +[your cell phone number] +``` diff --git a/docs/customization.md b/docs/customization.md new file mode 100644 index 000000000..70ce79921 --- /dev/null +++ b/docs/customization.md @@ -0,0 +1,18 @@ +--- +id: customization +title: Customization +--- + +Be sure to review all of these before going live! + +## Content + +Various settings are available at http://your-site/manage/configs + +## Emails + +Default automated emails are loaded into http://your-site/manage/messages + +## Styling + +Custom styling is not yet supported, but should be available starting Summer 2019. diff --git a/docs/deployment-dokku.md b/docs/deployment-dokku.md new file mode 100644 index 000000000..eb9023fbb --- /dev/null +++ b/docs/deployment-dokku.md @@ -0,0 +1,151 @@ +--- +id: deployment-dokku +title: Dokku Deployment +--- + +Below are steps & notes to deploy HackathonManager on Dokku. This assumes you already have [Dokku](http://dokku.viewdocs.io/dokku/) running on a machine and can SSH into the box. DNS should likely be set up as well, but isn't required for bare minimum functionality. + +If you have any questions at all, please don't hesitate to reach out to [Stuart](https://github.com/sman591)! This doc is very much a work in progress but we want to keep it as up to date as possible. + +## Dokku plugins + +Currently used and required Dokku plugins (other than the defaults): + +- [MySQL](https://github.com/dokku/dokku-mysql) +- [Redis](https://github.com/dokku/dokku-redis) (required by Sidekiq) +- [dokku-letsencrypt](https://github.com/dokku/dokku-letsencrypt) (Optional: free, automated SSL certificates) + +### Dokku Setup Steps + +**We'll be using `hm` as the app name in these steps,** as well as sharing the same `hm` name for both the app, database, and redis name. You're free to use another names. + +```bash +dokku apps:create hm +dokku mysql:create hm +dokku mysql:link hm hm +dokku redis:create hm +dokku redis:link hm hm +dokku checks:disable hm worker +dokku config:set hm \ [environment variables] +``` + +Where `[environment-variables]` is a list of all environment variables: + +```bash +# Dokku-specific environment variables +BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-ruby.git \ +DOKKU_DEPLOY_HOOKS_PREFIX=/app \ +ENVIRONMENT="production" \ +# ...remaining general environment variables... +``` + +**See [Environment Variables](deployment-environment-variables.md) for all required environment variables** + +Once all configuration is set, add Dokku as a remote & run an initial deploy. + +### Initial deploy + +First, we have to disable our `CHECKS`. Since our initial deploy won't have a working database, checks will fail and block deploys. + +On the server, run: + +```bash +dokku checks:disable hm web +``` + +Then, do a local deploy to Dokku: + +```bash +# Run this on your LOCAL machine, NOT on the server +git clone git git@github.com:codeRIT/hackathon_manager +cd hackathon_manager +git remote add dokku dokku@your-host.example.com:hm +git push dokku master +``` + +You'll be able to easily see the progress of the build and any errors. + +Once this succeeds, return back to the server to re-enable our web checks and seed the now-prepared database. + +```bash +dokku checks:enable hm web +dokku run hm bin/rails db:seed +``` + +### Domain setup + +1. Set up a new DNS record, either by: + - CNAME record `apply.your-hackathon.com` to point to `hm.your-dokku-server.com` + - A (and AAAA if you have IPv6) record `apply.your-hackathon.com` to point to your server's IP Address +2. Attach the domain to the app + +```bash +dokku domains:add hm apply.your-hackathon.com +``` + +3. Setup HTTPS with Let's Encrypt + +```bash +dokku config:set --no-restart hm DOKKU_LETSENCRYPT_EMAIL=your-email@example.com +dokku letsencrypt hm +``` + +### Validating initial deploy + +- Deploy should succeed without any red flags in the build log +- Should be able to submit an application on the website & receive an immediate confirmation email + +### Promote account to admin + +```bash +dokku enter hm web +# Wait for a bash shell to start... +$ bin/rails c +# Wait for the Rails console to start... +User.find_by(email: "your-email@example.com").update_attribute(:role, :admin) +exit +exit +``` + +## Nginx Config + +Usually, there's no need to modify the nginx config for the apps. However, we have a few special cases. + +1. Create the directory `/home/dokku/hm/nginx.conf.d/` +2. Add files ending in `.conf` (such as `rewrites.conf`) that you want loaded +3. Restart nginx: `dokku nginx:build-config hm` + +### Sidekiq + +Sidekiq's web UI will throw a 502 Gateway error out of the box on production. To fix this, [increase the nginx buffer size](https://github.com/mperham/sidekiq/issues/3143#issuecomment-248923576). + +Create `proxy_buffer.conf` with the following: + +``` +# Fix for Sidekiq web console +proxy_buffer_size 128k; +proxy_buffers 4 256k; +proxy_busy_buffers_size 256k; +``` + +### Resumes + +Support decently-sized resumes. + +Create `upload.conf` with the following: + +``` +client_max_body_size 2M; +``` + +## MySQL + +### MySQL Timezone Tables (Groupdate) + +**Update: Looks like dokku-mysql has timezone information by default, so this shouldn't be necessary.** + +In order to support groupdate, timezone tables must be created. + +```bash +mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u $OPENSHIFT_MYSQL_DB_USERNAME -p mysql +``` diff --git a/docs/deployment-environment-variables.md b/docs/deployment-environment-variables.md new file mode 100644 index 000000000..d1465fcd0 --- /dev/null +++ b/docs/deployment-environment-variables.md @@ -0,0 +1,101 @@ +--- +id: deployment-environment-variables +title: Environment Variables +--- + +Various services require environment variables to operate. + +**The following environment variables should be present on all deployments.** Below is an example: + +```bash +SECRET_KEY_BASE="" +DEVISE_SECRET_KEY="" +HM_DOMAIN_NAME="apply.example.com" +MLH_KEY="my-mlh-application-id" +MLH_SECRET="my-mlh-secret" +AWS_BUCKET="my-example-bucket" +AWS_ACCESS_KEY_ID="" +AWS_SECRET_ACCESS_KEY="" +AWS_REGION="us-east-1" +ROLLBAR_ACCESS_TOKEN="" +SPARKPOST_API_KEY="" +SPARKPOST_CAMPAIGN_ID="my-hackathon" +``` + +_Also see [app.json](https://github.com/codeRIT/hackathon_manager/blob/master/app.json)_ + +### Secret keys + +`SECRET_KEY_BASE` and `DEVISE_SECRET_KEY` are required for the app to run. You can generate secrets via `bundle exec rake secret`. This "secret" is a 64-byte hexadecimal string (128 characters). You could also generate this with `head -c 64 /dev/urandom | xxd -ps -c 128` if you are on a standard Linux distribution. + +### Mailer domain + +```bash +HM_DOMAIN_NAME="" +HM_DOMAIN_PROTOCOL="" # optional, https by default +``` + +### Resumes and S3 + +Resumes are stored locally in development and on S3 in production. + +```bash +AWS_BUCKET="" +AWS_ACCESS_KEY_ID="" +AWS_SECRET_ACCESS_KEY="" +AWS_REGION="" +``` + +If you're using a third-party S3 provider, such as [Minio](https://min.io), also specify the custom endpoint. + +```bash +AWS_ENDPOINT="https://your-provider.com" +``` + +If your provider only works with path-style buckets (`https://your-provider.com/bucket` instead of `https://bucket.your-provider.com`), enforce path-style usage: + +```bash +S3_FORCE_PATH_STYLE=true +``` + +### E-mail + +Currently, emails are queued via Sidekiq and then sent by Sparkpost's servers. + +Create a Sparkpost API key with **Transmissions: Read/Write** and **Message Events: Read-only** permissions, limited to the production server's IP address. SMTP is _not_ required, as email is sent over the Sparkpost API rather than SMTP. + +```bash +SPARKPOST_API_KEY="" +SPARKPOST_CAMPAIGN_ID="" +``` + +### Rollbar + +Rollbar captures and notifies of errors in production, and requires a server-side access token. + +```bash +ROLLBAR_ACCESS_TOKEN="" +``` + +### My MLH + +My MLH provides us authentication & initial application information. + +1. Create an account at https://my.mlh.io +2. Click "My Apps" in the top navbar +3. Click "Create new app" +4. Fill out the app name & logo +5. For "Redirect URI", fill in https://apply.your-hackathon.com/users/auth/mlh/callback + +```bash +MLH_KEY="" +MLH_SECRET="" +``` + +### Skylight + +Skylight provides detailed performance analytics for the app, if you chose to use it. + +```bash +SKYLIGHT_AUTHENTICATION="" +``` diff --git a/docs/deployment-heroku.md b/docs/deployment-heroku.md new file mode 100644 index 000000000..373cbed03 --- /dev/null +++ b/docs/deployment-heroku.md @@ -0,0 +1,28 @@ +--- +id: deployment-heroku +title: Heroku Deployment +--- + +Heroku deployment is pretty straightforward thanks to Heroku's one-click deploys. + +Click the button below to start. You'll be prompted to fill out a few questions and environment variables. + +**See [Environment Variables](deployment-environment-variables.md) for all required environment variables** + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) + +### Validating initial deploy + +- Website should be accessible +- Should be able to submit an application on the website & receive an immediate confirmation email + +### Promote account to admin + +1. Open a Heroku shell with `bin/rails c` (short for `bin/rails console`) + +2. Once the Rails shell opens, run the following: + +```bash +User.find_by(email: "your-email@example.com").update_attribute(:role, :admin) +exit +``` diff --git a/docs/deployment-okd.md b/docs/deployment-okd.md new file mode 100644 index 000000000..07d8da239 --- /dev/null +++ b/docs/deployment-okd.md @@ -0,0 +1,132 @@ +--- +id: deployment-okd +title: OKD Deployment +--- + +Three deployments should be made: + +- HackathonManager (seen below) +- MySQL +- Redis + +Each should share a common secret, containing all relevant environment variables: + +- `RAILS_ENV=production` +- `DATABASE_URL=mysql2://username:password@mysql:3306/database` +- `REDIS_URL=redis://:password@redis:6379/` +- All remaining environment variables from [Environment Variables](deployment-environment-variables.md) + +## MySQL Deployment + +1. Set up a MySQL deployment from the standard OpenShift catalog. +2. Copy the username/password/port/host/database name to the relevant parts of `DATABSE_URL` in the shared secret config +3. Open a terminal in the MySQL pod container and run the following command: + +```bash +mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql +``` + +## Redis Deployment + +1. Set up a Redis deployment from the standard OpenShift catalog. +2. Copy the password/port/host to the relevant parts of `REDIS_URL` in the shared secret config + +## HackathonManager Deployment + +This consists of a pod with two containers: `web` and `sidekiq`. Both use the same built image; sidekiq runs with a custom command. + +```yaml +apiVersion: apps.openshift.io/v1 +kind: DeploymentConfig +metadata: + annotations: + openshift.io/generated-by: OpenShiftWebConsole + creationTimestamp: '2019-04-17T18:41:01Z' + generation: 14 + labels: + app: hackathon-manager-demo + name: hackathon-manager-demo + namespace: hackathon-manager-demo + resourceVersion: '25003711' + selfLink: >- + /apis/apps.openshift.io/v1/namespaces/hackathon-manager-demo/deploymentconfigs/hackathon-manager-demo + uid: 5987d6b5-6140-11e9-b0f8-1a373a0e2f7f +spec: + replicas: 1 + selector: + deploymentconfig: hackathon-manager-demo + strategy: + activeDeadlineSeconds: 21600 + resources: {} + rollingParams: + intervalSeconds: 1 + maxSurge: 25% + maxUnavailable: 25% + timeoutSeconds: 600 + updatePeriodSeconds: 1 + type: Rolling + template: + metadata: + creationTimestamp: null + labels: + app: hackathon-manager-demo + deploymentconfig: hackathon-manager-demo + spec: + containers: + - envFrom: + - secretRef: + name: hackathon-manager-demo + image: >- + docker-registry.default.svc:5000/hackathon-manager-demo/hackathon-manager-demo@sha256:66933712fc8cbb42ed553e5f07dd278bb12f2a1a964af8c635028f84d9149f49 + imagePullPolicy: Always + name: web + ports: + - containerPort: 8080 + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 8080 + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + - command: + - bash + - '-c' + - bundle exec sidekiq + envFrom: + - secretRef: + name: hackathon-manager-demo + image: >- + docker-registry.default.svc:5000/hackathon-manager-demo/hackathon-manager-demo@sha256:66933712fc8cbb42ed553e5f07dd278bb12f2a1a964af8c635028f84d9149f49 + imagePullPolicy: Always + name: sidekiq + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 + test: false + triggers: + - imageChangeParams: + automatic: true + containerNames: + - web + - sidekiq + from: + kind: ImageStreamTag + name: 'hackathon-manager-demo:latest' + namespace: hackathon-manager-demo + lastTriggeredImage: >- + docker-registry.default.svc:5000/hackathon-manager-demo/hackathon-manager-demo@sha256:66933712fc8cbb42ed553e5f07dd278bb12f2a1a964af8c635028f84d9149f49 + type: ImageChange + - type: ConfigChange +``` diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100755 index 000000000..9be06081c --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,37 @@ +--- +id: deployment +title: Deployment +--- + +HackathonManager is a standalone web app separate from your regular marketing website/public homepage. + +A typical setup would be: + +- **brickhack.io** — Marketing site with event info, schedule, sponsors, etc and a button to apply +- **apply.brickhack.io** — HackathonManager deployment to accept hacker applications + host management dashboard + +This allows your public marketing site to operate however you want it (e.g. GitHub pages) while HackathonManager lives in an isolated, consistent environment. + +To get started, deploy HackathonManager onto one of three supported platforms: + +## Heroku + +Easiest & quickest way that requires little server knowledge, however isn't cheap (free tier not recommended) + +[Get Started with Heroku »](deployment-heroku.md) + +## Dokku + +A free alternative to Heroku, runs on your own virtual machine + +[Get Started with Heroku »](deployment-dokku.md) + +## OKD/OpenShift + +"Enterprise Kubernetes for Developers" packaged with a useful management UI + tooling + +[Get Started with OKD »](deployment-okd.md) + +### Other methods + +HackathonManager can also be deployed the same as any other Rails app, however this is **not** natively supported and will require you to fork this repo to integrate code changes. diff --git a/docs/questionnaires.md b/docs/questionnaires.md new file mode 100644 index 000000000..f4626bc4d --- /dev/null +++ b/docs/questionnaires.md @@ -0,0 +1,12 @@ +--- +id: questionnaires +title: Questionnaires +--- + +A questionnaire is what an attendee submits **to apply to your hackathon.** + +Once a user has created an account, they complete their **questionnaire** with all required info (name, school, etc). + +More to come... + +![Screenshot of a questionnaire in the dashboard](assets/questionnaire.png) diff --git a/docs/running-a-hackathon.md b/docs/running-a-hackathon.md new file mode 100755 index 000000000..f7f409314 --- /dev/null +++ b/docs/running-a-hackathon.md @@ -0,0 +1,26 @@ +--- +id: running-a-hackathon +title: Running a hackathon with HackathonManager +sidebar_label: Running a hackathon +--- + +> HackathonManager is a full-service tool to run your hackathon from start to finish. + +Guides to get you started: + +- [Timeline of a hackathon](#timeline) +- [Busses](busses.md) +- [Questionnaires](questionnaires.md) +- _More to come..._ + +## Timeline of a hackathon + +HackathonManager helps with every step along the way. + +1. (many months before) -- Website goes up advertising event coming soon +2. (months before) -- Attendee applications open +3. (weeks to month before) -- Acceptance emails go out, RSVPs begin, bus sign-ups begin +4. (weeks leading up to event) -- Emails to communicate logistics as needed +5. (day-of event) -- Check-in attendees as they arrive at the venue +6. (during- and post-event) -- Emails for communication as needed +7. (post-event) -- Analyze data to observe trends to act on for next year (pre-generated graphs or custom queries via SQL) diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 000000000..496841488 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,5 @@ +/translated_docs +/build/ +/yarn.lock +/node_modules +/i18n/* diff --git a/website/README.md b/website/README.md new file mode 100755 index 000000000..f3da77ff3 --- /dev/null +++ b/website/README.md @@ -0,0 +1,193 @@ +This website was created with [Docusaurus](https://docusaurus.io/). + +# What's In This Document + +* [Get Started in 5 Minutes](#get-started-in-5-minutes) +* [Directory Structure](#directory-structure) +* [Editing Content](#editing-content) +* [Adding Content](#adding-content) +* [Full Documentation](#full-documentation) + +# Get Started in 5 Minutes + +1. Make sure all the dependencies for the website are installed: + +```sh +# Install dependencies +$ yarn +``` +2. Run your dev server: + +```sh +# Start the site +$ yarn start +``` + +## Directory Structure + +Your project file structure should look something like this + +``` +my-docusaurus/ + docs/ + doc-1.md + doc-2.md + doc-3.md + website/ + blog/ + 2016-3-11-oldest-post.md + 2017-10-24-newest-post.md + core/ + node_modules/ + pages/ + static/ + css/ + img/ + package.json + sidebar.json + siteConfig.js +``` + +# Editing Content + +## Editing an existing docs page + +Edit docs by navigating to `docs/` and editing the corresponding document: + +`docs/doc-to-be-edited.md` + +```markdown +--- +id: page-needs-edit +title: This Doc Needs To Be Edited +--- + +Edit me... +``` + +For more information about docs, click [here](https://docusaurus.io/docs/en/navigation) + +## Editing an existing blog post + +Edit blog posts by navigating to `website/blog` and editing the corresponding post: + +`website/blog/post-to-be-edited.md` +```markdown +--- +id: post-needs-edit +title: This Blog Post Needs To Be Edited +--- + +Edit me... +``` + +For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog) + +# Adding Content + +## Adding a new docs page to an existing sidebar + +1. Create the doc as a new markdown file in `/docs`, example `docs/newly-created-doc.md`: + +```md +--- +id: newly-created-doc +title: This Doc Needs To Be Edited +--- + +My new content here.. +``` + +1. Refer to that doc's ID in an existing sidebar in `website/sidebar.json`: + +```javascript +// Add newly-created-doc to the Getting Started category of docs +{ + "docs": { + "Getting Started": [ + "quick-start", + "newly-created-doc" // new doc here + ], + ... + }, + ... +} +``` + +For more information about adding new docs, click [here](https://docusaurus.io/docs/en/navigation) + +## Adding a new blog post + +1. Make sure there is a header link to your blog in `website/siteConfig.js`: + +`website/siteConfig.js` +```javascript +headerLinks: [ + ... + { blog: true, label: 'Blog' }, + ... +] +``` + +2. Create the blog post with the format `YYYY-MM-DD-My-Blog-Post-Title.md` in `website/blog`: + +`website/blog/2018-05-21-New-Blog-Post.md` + +```markdown +--- +author: Frank Li +authorURL: https://twitter.com/foobarbaz +authorFBID: 503283835 +title: New Blog Post +--- + +Lorem Ipsum... +``` + +For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog) + +## Adding items to your site's top navigation bar + +1. Add links to docs, custom pages or external links by editing the headerLinks field of `website/siteConfig.js`: + +`website/siteConfig.js` +```javascript +{ + headerLinks: [ + ... + /* you can add docs */ + { doc: 'my-examples', label: 'Examples' }, + /* you can add custom pages */ + { page: 'help', label: 'Help' }, + /* you can add external links */ + { href: 'https://github.com/facebook/Docusaurus', label: 'GitHub' }, + ... + ], + ... +} +``` + +For more information about the navigation bar, click [here](https://docusaurus.io/docs/en/navigation) + +## Adding custom pages + +1. Docusaurus uses React components to build pages. The components are saved as .js files in `website/pages/en`: +1. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element: + +`website/siteConfig.js` +```javascript +{ + headerLinks: [ + ... + { page: 'my-new-custom-page', label: 'My New Custom Page' }, + ... + ], + ... +} +``` + +For more information about custom pages, click [here](https://docusaurus.io/docs/en/custom-pages). + +# Full Documentation + +Full documentation can be found on the [website](https://docusaurus.io/). diff --git a/website/core/Footer.js b/website/core/Footer.js new file mode 100755 index 000000000..50e4faf6a --- /dev/null +++ b/website/core/Footer.js @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require('react'); + +class Footer extends React.Component { + docUrl(doc, language) { + const baseUrl = this.props.config.baseUrl; + const docsUrl = this.props.config.docsUrl; + const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; + const langPart = `${language ? `${language}/` : ''}`; + return `${baseUrl}${docsPart}${langPart}${doc}`; + } + + pageUrl(doc, language) { + const baseUrl = this.props.config.baseUrl; + return baseUrl + (language ? `${language}/` : '') + doc; + } + + render() { + return ( + + ); + } +} + +module.exports = Footer; diff --git a/website/docker-compose.yml b/website/docker-compose.yml new file mode 100755 index 000000000..8d180d3d1 --- /dev/null +++ b/website/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3' + +services: + docusaurus: + build: + context: ../ + dockerfile: Dockerfile-website + ports: + - 4000:4000 + - 35729:35729 + volumes: + - ../docs:/app/docs + - ./core:/app/website/core + - ./i18n:/app/website/i18n + - ./pages:/app/website/pages + - ./static:/app/website/static + - ./sidebars.json:/app/website/sidebars.json + - ./siteConfig.js:/app/website/siteConfig.js + working_dir: /app/website diff --git a/website/package.json b/website/package.json new file mode 100644 index 000000000..01c55dccf --- /dev/null +++ b/website/package.json @@ -0,0 +1,14 @@ +{ + "scripts": { + "examples": "docusaurus-examples", + "start": "docusaurus-start --port 4000", + "build": "docusaurus-build", + "publish-gh-pages": "docusaurus-publish", + "write-translations": "docusaurus-write-translations", + "version": "docusaurus-version", + "rename-version": "docusaurus-rename-version" + }, + "devDependencies": { + "docusaurus": "^1.10.0" + } +} diff --git a/website/pages/en/help.js b/website/pages/en/help.js new file mode 100755 index 000000000..2b790e460 --- /dev/null +++ b/website/pages/en/help.js @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require('react'); + +const CompLibrary = require('../../core/CompLibrary.js'); + +const Container = CompLibrary.Container; +const GridBlock = CompLibrary.GridBlock; + +function Help(props) { + const {config: siteConfig, language = ''} = props; + const {baseUrl, docsUrl} = siteConfig; + const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; + const langPart = `${language ? `${language}/` : ''}`; + const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`; + + const supportLinks = [ + { + content: `Learn more using the [documentation on this site.](${docUrl( + 'doc1.html', + )})`, + title: 'Browse Docs', + }, + { + content: 'Ask questions about the documentation and project', + title: 'Join the community', + }, + { + content: "Find out what's new with this project", + title: 'Stay up to date', + }, + ]; + + return ( +
+ +
+
+

Need help?

+
+

This project is maintained by a dedicated group of people.

+ +
+
+
+ ); +} + +module.exports = Help; diff --git a/website/pages/en/index.js b/website/pages/en/index.js new file mode 100755 index 000000000..53e71ab97 --- /dev/null +++ b/website/pages/en/index.js @@ -0,0 +1,241 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require('react'); + +const CompLibrary = require('../../core/CompLibrary.js'); + +const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */ +const Container = CompLibrary.Container; +const GridBlock = CompLibrary.GridBlock; + +class HomeSplash extends React.Component { + render() { + const { siteConfig, language = '' } = this.props; + const { baseUrl, docsUrl } = siteConfig; + const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; + const langPart = `${language ? `${language}/` : ''}`; + const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`; + + const SplashContainer = props => ( +
+
+
{props.children}
+
+
+ ); + + const ProjectTitle = () => ( +

+ {siteConfig.title} + {siteConfig.tagline} +

+ ); + + const PromoSection = props => ( +
+
+
{props.children}
+
+
+ ); + + const Button = props => ( + + ); + + return ( + +
+ + + + + + +
+
+ ); + } +} + +class Index extends React.Component { + render() { + const { config: siteConfig, language = '' } = this.props; + const { baseUrl } = siteConfig; + + const Block = props => ( + + + + ); + + const Features = () => ( + + {[ + { + content: + 'HackathonManager is the product of running various hackathons over the past 5 years', + image: `${baseUrl}img/undraw_predictive_analytics_kf9n.svg`, + imageAlign: 'top', + title: 'Battle-tested', + }, + { + content: + 'Manage every component of a hackathon that deals with attendees', + image: `${baseUrl}img/undraw_adjustments_p22m.svg`, + imageAlign: 'top', + title: 'All-in-one', + }, + { + content: + 'Scale from 200 to 2000 applicants with tools to empower your organizing team', + image: `${baseUrl}img/undraw_QA_engineers_dg5p.svg`, + imageAlign: 'top', + title: 'Production ready', + }, + ]} + + ); + + const Applications = () => ( + + {[ + { + content: + 'Enable hackers to apply to your hackathon while providing all relevant information (contact info, school, demographics, etc)', + image: `${baseUrl}img/applications.png`, + imageAlign: 'right', + title: 'Applications', + }, + ]} + + ); + + const Admissions = () => ( + + {[ + { + content: + 'Facilitate accepting hackers to your hackathon & enable them to RSVP', + image: `${baseUrl}img/rsvp.png`, + imageAlign: 'left', + title: 'Admissions & RSVPs', + }, + ]} + + ); + + const BusLists = () => ( + + {[ + { + content: + 'Coordinate bus sign-ups during the RSVP process while communicating important information to riders & captains', + image: `${baseUrl}img/editbuslist.png`, + imageAlign: 'right', + title: 'Bus Lists', + }, + ]} + + ); + + const MyMLHSupport = () => ( + + {[ + { + content: + "Streamline the application process when users log in with [MyMLH](https://my.mlh.io/), a common platform for applying to any MLH hackathon. Basic info is pre-filled based on a common application, so hackers don't have to re-type it every time.

Learn more at [my.mlh.io](https://my.mlh.io/)", + image: `${baseUrl}img/mymlh.png`, + imageAlign: 'left', + title: 'MyMLH Support', + }, + ]} +
+ ); + + const EmailCommunication = () => ( + + {[ + { + content: + 'Ensure hackers get consistent, timely information throughout their application process, while enabling your organizing team to communicate important information at any time.', + image: `${baseUrl}img/messageedit.png`, + imageAlign: 'right', + title: 'Email Communication', + }, + ]} + + ); + + const StatisticsVisualization = () => ( + + {[ + { + content: + 'Surface key analytics about your admissions, distribution of applicants, progress towards attendance, etc.', + image: `${baseUrl}img/dashboard.png`, + imageAlign: 'left', + title: 'Statistics & Visualization', + }, + ]} + + ); + + const Showcase = () => { + if ((siteConfig.users || []).length === 0) { + return null; + } + + const showcase = siteConfig.users.map(user => ( + + {user.caption} + + )); + + return ( +
+

Who is Using This?

+

This project is used by all these people

+
{showcase}
+
+ ); + }; + + return ( +
+ +
+ + + + + + + + +
+
+ ); + } +} + +module.exports = Index; diff --git a/website/pages/en/users.js b/website/pages/en/users.js new file mode 100755 index 000000000..039dc39ff --- /dev/null +++ b/website/pages/en/users.js @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require('react'); + +const CompLibrary = require('../../core/CompLibrary.js'); + +const Container = CompLibrary.Container; + +class Users extends React.Component { + render() { + const {config: siteConfig} = this.props; + if ((siteConfig.users || []).length === 0) { + return null; + } + + const editUrl = `${siteConfig.repoUrl}/edit/master/website/siteConfig.js`; + const showcase = siteConfig.users.map(user => ( + + {user.caption} + + )); + + return ( +
+ +
+
+

Who is Using This?

+

This project is used by many folks

+
+
{showcase}
+

Are you using this project?

+ + Add your company + +
+
+
+ ); + } +} + +module.exports = Users; diff --git a/website/sidebars.json b/website/sidebars.json new file mode 100755 index 000000000..136163ad6 --- /dev/null +++ b/website/sidebars.json @@ -0,0 +1,14 @@ +{ + "docs": { + "HackathonManager": ["running-a-hackathon", "busses", "questionnaires"], + "API Usage": ["api"], + "Deployment": [ + "deployment", + "deployment-dokku", + "deployment-heroku", + "deployment-okd", + "deployment-environment-variables", + "customization" + ] + } +} diff --git a/website/siteConfig.js b/website/siteConfig.js new file mode 100644 index 000000000..f02004ce4 --- /dev/null +++ b/website/siteConfig.js @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// See https://docusaurus.io/docs/site-config for all the possible +// site configuration options. + +// List of projects/orgs using your project for the users page. +const users = [ + { + caption: 'BrickHack', + image: 'img/brickhack.svg', + infoLink: 'https://brickhack.io', + }, + { + caption: 'WiCHacks', + image: 'img/wichacks.jpg', + infoLink: 'https://wichacks.io', + }, + { + caption: 'CSH Hacks', + image: 'img/csh.svg', + infoLink: 'https://csh.rit.edu', + }, +]; + +const siteConfig = { + title: 'HackathonManager', // Title for your website. + tagline: 'All-in-one platform for hackathon registration & logistics', + url: 'https://codeRIT.org', // Your website URL + baseUrl: '/hackathon-manager/', // Base URL for your project */ + // For github.io type URLs, you would set the url and baseUrl like: + // url: 'https://facebook.github.io', + // baseUrl: '/test-site/', + + editUrl: 'https://github.com/codeRIT/hackathon-manager/edit/master/docs/', + + // Used for publishing and more + projectName: 'hackathon-manager', + organizationName: 'codeRIT', + // For top-level user or org sites, the organization is still the same. + // e.g., for the https://JoelMarcey.github.io site, it would be set like... + // organizationName: 'JoelMarcey' + + // For no header links in the top nav bar -> headerLinks: [], + headerLinks: [ + { doc: 'deployment', label: 'Get Started' }, + { doc: 'running-a-hackathon', label: 'Docs' }, + { href: 'https://github.com/codeRIT/hackathon-manager', label: 'GitHub' }, + ], + + // If you have users set above, you add it here: + users, + + /* path to images for header/footer */ + headerIcon: 'img/coderit-square.svg', + footerIcon: 'img/coderit-square.svg', + favicon: 'img/favicon.png', + + /* Colors for website */ + colors: { + primaryColor: '#384859', + secondaryColor: '#F36321', + }, + + /* Custom fonts for website */ + /* + fonts: { + myFont: [ + "Times New Roman", + "Serif" + ], + myOtherFont: [ + "-apple-system", + "system-ui" + ] + }, + */ + + // This copyright info is used in /core/Footer.js and blog RSS/Atom feeds. + copyright: `Copyright © ${new Date().getFullYear()} codeRIT`, + + highlight: { + // Highlight.js theme to use for syntax highlighting in code blocks. + theme: 'default', + }, + + // Add custom scripts here that would be placed in