Showing preview only (212K chars total). Download the full file or copy to clipboard to get everything.
Repository: ryotarai/waker
Branch: master
Commit: 24b15020a036
Files: 270
Total size: 156.8 KB
Directory structure:
gitextract_ao1b4jon/
├── .dockerignore
├── .github/
│ └── workflows/
│ └── rails.yml
├── .gitignore
├── .rspec
├── .rubocop.yml
├── Dockerfile
├── Gemfile
├── LICENSE.txt
├── Procfile
├── Procfile.docker
├── README.md
├── Rakefile
├── app/
│ ├── assets/
│ │ ├── images/
│ │ │ └── .keep
│ │ ├── javascripts/
│ │ │ ├── application.js
│ │ │ ├── comments.coffee
│ │ │ ├── escalation_series.coffee
│ │ │ ├── escalations.coffee
│ │ │ ├── home.coffee
│ │ │ ├── incident_events.coffee
│ │ │ ├── incidents.coffee
│ │ │ ├── maintenances.coffee
│ │ │ ├── notifier_providers.coffee
│ │ │ ├── notifiers.coffee
│ │ │ ├── sessions.coffee
│ │ │ ├── slack.coffee
│ │ │ ├── topics.coffee
│ │ │ └── users.coffee
│ │ └── stylesheets/
│ │ ├── application.css
│ │ ├── comments.scss
│ │ ├── escalation_series.scss
│ │ ├── escalations.scss
│ │ ├── home.scss
│ │ ├── incident_events.scss
│ │ ├── incidents.scss
│ │ ├── maintenances.scss
│ │ ├── notifier_providers.scss
│ │ ├── notifiers.scss
│ │ ├── scaffolds.scss
│ │ ├── sessions.scss
│ │ ├── slack.scss
│ │ ├── topics.scss
│ │ └── users.scss
│ ├── controllers/
│ │ ├── application_controller.rb
│ │ ├── comments_controller.rb
│ │ ├── concerns/
│ │ │ └── .keep
│ │ ├── escalation_series_controller.rb
│ │ ├── escalations_controller.rb
│ │ ├── home_controller.rb
│ │ ├── incident_events_controller.rb
│ │ ├── incidents_controller.rb
│ │ ├── maintenances_controller.rb
│ │ ├── notifier_providers_controller.rb
│ │ ├── notifiers_controller.rb
│ │ ├── sessions_controller.rb
│ │ ├── slack_controller.rb
│ │ ├── topics_controller.rb
│ │ └── users_controller.rb
│ ├── helpers/
│ │ ├── application_helper.rb
│ │ ├── comments_helper.rb
│ │ ├── escalation_series_helper.rb
│ │ ├── escalations_helper.rb
│ │ ├── home_helper.rb
│ │ ├── incident_events_helper.rb
│ │ ├── incidents_helper.rb
│ │ ├── maintenances_helper.rb
│ │ ├── notifier_providers_helper.rb
│ │ ├── notifiers_helper.rb
│ │ ├── sessions_helper.rb
│ │ ├── slack_helper.rb
│ │ ├── topics_helper.rb
│ │ └── users_helper.rb
│ ├── mailers/
│ │ └── .keep
│ ├── models/
│ │ ├── .keep
│ │ ├── application_record.rb
│ │ ├── comment.rb
│ │ ├── concerns/
│ │ │ └── .keep
│ │ ├── escalation.rb
│ │ ├── escalation_series.rb
│ │ ├── escalation_update_worker.rb
│ │ ├── escalation_worker.rb
│ │ ├── incident.rb
│ │ ├── incident_event.rb
│ │ ├── maintenance.rb
│ │ ├── notification_worker.rb
│ │ ├── notifier.rb
│ │ ├── notifier_provider.rb
│ │ ├── topic.rb
│ │ └── user.rb
│ └── views/
│ ├── comments/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── escalation_series/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── escalations/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── home/
│ │ └── index.html.erb
│ ├── incident_events/
│ │ └── twilio.html.erb
│ ├── incidents/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── layouts/
│ │ └── application.html.erb
│ ├── maintenances/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── notifier_providers/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── hipchat/
│ │ │ ├── acknowledged.text.erb
│ │ │ ├── escalated.text.erb
│ │ │ ├── opened.text.erb
│ │ │ └── resolved.text.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── mailgun/
│ │ │ ├── default.html.erb
│ │ │ └── default.text.erb
│ │ ├── new.html.erb
│ │ ├── rails_logger/
│ │ │ └── default.text.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── notifiers/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── sessions/
│ │ └── create.html.erb
│ ├── slack/
│ │ └── interactive.html.erb
│ ├── topics/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ └── users/
│ ├── _form.html.erb
│ ├── edit.html.erb
│ ├── index.html.erb
│ ├── index.json.jbuilder
│ ├── new.html.erb
│ ├── show.html.erb
│ └── show.json.jbuilder
├── bin/
│ ├── bundle
│ ├── rails
│ ├── rake
│ ├── setup
│ └── spring
├── config/
│ ├── application.rb
│ ├── boot.rb
│ ├── database.yml
│ ├── environment.rb
│ ├── environments/
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers/
│ │ ├── assets.rb
│ │ ├── backtrace_silencers.rb
│ │ ├── cookies_serializer.rb
│ │ ├── field_with_errors.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── omniauth.rb
│ │ ├── session_store.rb
│ │ ├── sidekiq.rb
│ │ ├── url_options.rb
│ │ └── wrap_parameters.rb
│ ├── locales/
│ │ └── en.yml
│ ├── routes.rb
│ └── secrets.yml
├── config.ru
├── db/
│ ├── migrate/
│ │ ├── 20150120134616_create_topics.rb
│ │ ├── 20150120134747_create_users.rb
│ │ ├── 20150120134905_create_notifiers.rb
│ │ ├── 20150120135017_create_shifts.rb
│ │ ├── 20150120135123_create_escalations.rb
│ │ ├── 20150120135244_create_escalation_series.rb
│ │ ├── 20150120135351_add_escalation_series_to_escalation.rb
│ │ ├── 20150120141627_rename_type_with_kind_of_topic.rb
│ │ ├── 20150120142452_create_incidents.rb
│ │ ├── 20150120151642_add_escalation_series_to_topic.rb
│ │ ├── 20150120154438_add_name_to_shift.rb
│ │ ├── 20150121150043_add_user_to_notifier.rb
│ │ ├── 20150121150857_rename_type_with_kind_of_notifier.rb
│ │ ├── 20150123132415_remove_shift.rb
│ │ ├── 20150123150518_add_status_to_incident.rb
│ │ ├── 20150123150947_create_incident_events.rb
│ │ ├── 20150125050529_create_notifier_providers.rb
│ │ ├── 20150125050556_add_provider_to_notifier.rb
│ │ ├── 20150125101901_remove_kind_from_notifier.rb
│ │ ├── 20150127142530_remove_user_by_from_incident_event.rb
│ │ ├── 20150127152127_add_info_to_incident_event.rb
│ │ ├── 20150128064248_add_email_to_user.rb
│ │ ├── 20150131120557_add_enable_to_topic.rb
│ │ ├── 20150131121143_set_default_of_enable_of_topic_true.rb
│ │ ├── 20150131122151_rename_enable_with_enabled_of_topic.rb
│ │ ├── 20150201033946_add_login_token_to_user.rb
│ │ ├── 20150202144538_add_token_to_user.rb
│ │ ├── 20150202151740_add_refresh_token_to_user.rb
│ │ ├── 20150202152015_add_settings_to_escalation_series.rb
│ │ ├── 20150202155726_add_token_expires_at_to_user.rb
│ │ ├── 20150203010332_remove_escalation_series_from_escalation_series.rb
│ │ ├── 20150203010417_add_settings_to_escalation_series_again.rb
│ │ ├── 20150207164010_add_topic_to_notifier.rb
│ │ ├── 20150218071007_add_enable_to_notifier.rb
│ │ ├── 20151117011141_add_active_to_user.rb
│ │ ├── 20151117013824_add_provider_and_uid_to_user.rb
│ │ ├── 20151118061253_add_credentials_to_user.rb
│ │ ├── 20151118061938_delete_token_from_user.rb
│ │ ├── 20160210010310_create_maintenances.rb
│ │ ├── 20160907123728_create_comments.rb
│ │ ├── 20160914063913_add_comment_index.rb
│ │ └── 20161207045554_add_filter_to_maintenance.rb
│ ├── schema.rb
│ └── seeds.rb
├── docker/
│ └── puma.rb
├── docker-compose.yml
├── lib/
│ ├── assets/
│ │ └── .keep
│ └── tasks/
│ └── .keep
├── log/
│ └── .keep
├── public/
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ └── robots.txt
├── script/
│ └── update-escalations-from-google-calendar
├── spec/
│ ├── controllers/
│ │ └── slack_controller_spec.rb
│ ├── factories/
│ │ ├── escalation.rb
│ │ ├── escalation_series.rb
│ │ ├── incident.rb
│ │ ├── incident_events.rb
│ │ ├── maintenances.rb
│ │ ├── notifier.rb
│ │ ├── notifier_provider.rb
│ │ ├── topic.rb
│ │ └── user.rb
│ ├── helpers/
│ │ └── slack_helper_spec.rb
│ ├── models/
│ │ ├── comment_spec.rb
│ │ ├── escalation_series_spec.rb
│ │ ├── incident_spec.rb
│ │ └── maintenance_spec.rb
│ ├── rails_helper.rb
│ ├── requests/
│ │ ├── incident_envets_spec.rb
│ │ ├── maintenances_spec.rb
│ │ └── topics_spec.rb
│ ├── spec_helper.rb
│ ├── support/
│ │ ├── factory_girl.rb
│ │ └── sidekiq.rb
│ └── views/
│ └── slack/
│ └── interactive.html.erb_spec.rb
└── vendor/
└── assets/
├── javascripts/
│ └── .keep
└── stylesheets/
└── .keep
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
logs/*
doc/*
vendor/*
coverage/*
tmp/*
================================================
FILE: .github/workflows/rails.yml
================================================
name: Rails
on: [push]
jobs:
build:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
env:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
container:
image: ruby:2.6.5
env:
MYSQL_HOST: mysql
steps:
- uses: actions/checkout@v1
- name: Setup YARN and NodeJS
run: |
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
curl -sL https://deb.nodesource.com/setup_12.x | bash -
apt-get install -y yarn nodejs
- name: Build and setup
run: |
gem install bundler --no-document
bundle install --jobs 4 --retry 3 --deployment
bundle exec rails yarn:install db:setup assets:precompile
bundle exec rake
env:
RAILS_ENV: "test"
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config.
/.bundle
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*
!/log/.keep
/tmp
*.rdb
.env
coverage
================================================
FILE: .rspec
================================================
--color
--require spec_helper
================================================
FILE: .rubocop.yml
================================================
AllCops:
TargetRubyVersion: 2.4
DisplayCopNames: true
DisabledByDefault: true
Exclude:
- 'db/**/*'
- 'vendor/**/*'
Rails:
Enabled: true
Rails/ActionFilter:
EnforcedStyle: action
Enabled: true
Style/HashSyntax:
Enabled: true
Style/MethodDefParentheses:
Enabled: true
Style/Encoding:
Enabled: true
Style/For:
EnforcedStyle: each
Enabled: true
Style/FrozenStringLiteralComment:
EnforcedStyle: never
Enabled: true
Style/NumericLiteralPrefix:
EnforcedOctalStyle: zero_only
Enabled: true
Style/StabbyLambdaParentheses:
EnforcedStyle: require_parentheses
Enabled: true
Layout/EmptyLines:
Enabled: true
Layout/TrailingBlankLines:
Enabled: true
Layout/TrailingWhitespace:
Enabled: true
Layout/AccessModifierIndentation:
EnforcedStyle: indent
Enabled: true
Layout/CaseIndentation:
EnforcedStyle: end
Enabled: true
Layout/MultilineHashBraceLayout:
EnforcedStyle: symmetrical
Enabled: true
================================================
FILE: Dockerfile
================================================
FROM ruby:2.6.5
RUN apt update -qqy && apt -qqy install nodejs
WORKDIR /tmp
ADD Gemfile* /tmp/
RUN gem install bundler:2.1.4
RUN bundle install --deployment -j4 --without development test
ADD . /app
WORKDIR /app
RUN cp -a /tmp/vendor/bundle /app/vendor/bundle && \
bundle exec rake assets:precompile
CMD ["bundle", "exec", "foreman", "start", "-f", "Procfile.docker"]
================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '5.2.4.1'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
# Use Unicorn as the app server
# gem 'unicorn'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
gem 'sidekiq', '~> 3.3.0'
gem 'sinatra'
gem 'faraday', '~> 0.15.4'
gem 'holiday_jp'
gem 'hipchat'
gem 'kaminari'
gem 'puma'
gem 'rack-health'
gem 'omniauth-google-oauth2', '~> 0.6'
gem 'retriable', '3.0.1'
gem 'twilio-ruby'
gem 'mysql2'
gem 'google-api-client', '~> 0.7.1'
gem 'foreman'
group :development do
gem 'web-console'
end
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug'
# Access an IRB console on exception pages or by using <%= console %> in views
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'rspec-rails'
gem 'database_rewinder'
gem 'pry-byebug'
gem 'dotenv-rails'
gem 'factory_bot_rails'
gem 'rubocop', require: false
end
group :test do
gem 'simplecov', require: false
end
gem 'dogapi'
gem 'aws-sdk'
gem 'rails_autolink'
================================================
FILE: LICENSE.txt
================================================
The MIT License (MIT)
Copyright (c) 2014-2015 Ryota Arai
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Procfile
================================================
web: bin/rails s
worker: bundle exec sidekiq
update_escalations: while true; do bundle exec rails runner 'EscalationUpdateWorker.perform_async()'; sleep 60; done
================================================
FILE: Procfile.docker
================================================
web: puma -C docker/puma.rb
worker: bundle exec sidekiq
update_escalations: while true; do bundle exec rails runner 'EscalationUpdateWorker.perform_async()'; sleep 60; done
================================================
FILE: README.md
================================================
# Waker [](https://travis-ci.org/ryotarai/waker)
Alert Escalation System

## Overview


## Tutorial
### 1. (Optional) Configure auth provider
You can use external auth provider **optionally**. Currently, Google Auth is only supported (Patches are welcome :) )
```
$ echo 'GOOGLE_CLIENT_ID=...' >> .env
$ echo 'GOOGLE_CLIENT_SECRET=...' >> .env
$ echo 'GOOGLE_DOMAIN=...' >> .env # If you restrict to use Google Apps domain
```
### 2. Start the server
```
$ bundle install
$ foreman start
```
It starts an application server and a Sidekiq worker.
### 3. (If you uses auth provider) Log in
Visit [http://localhost:3000](http://localhost:3000) and log in with your credentials.
A new user account is automatically created and suspended by default. You can activate a user from [http://localhost:3000/users](http://localhost:3000/users) but you have to activate it from `rails console` because you are the first user:
```
$ bundle exec rails c
> User.first.update!(active: true)
```
### 4. Create users
Visit [http://localhost:3000/users/new](http://localhost:3000/users/new) and create new users.
### 5. Create a notifier provider
Visit [http://localhost:3000/notifier_providers/new](http://localhost:3000/notifier_providers/new) and create a notifier provider. See [Notifier Providers](https://github.com/ryotarai/waker#notifier-providers) section for detailed information.
### 6. Create a notifier
Visit [http://localhost:3000/notifiers/new](http://localhost:3000/notifiers/new) and create a notifier. See [Notifier](https://github.com/ryotarai/waker#notifiers) section for detailed information.
### 7. Create an escalation series
Visit [http://localhost:3000/escalation_series/new](http://localhost:3000/escalation_series/new) and create a escalation series. Escalation series is a series of escalations.
### 8. Create escalations
Visit [http://localhost:3000/escalations/new](http://localhost:3000/escalations/new) and create escalations.
- `Escalate to`: Who gets escalated incidents
- `Escalate after sec`: Seconds to escalate incidents since the incidents created
### 9. Create a topic
Visit [http://localhost:3000/topics/new](http://localhost:3000/topics/new) and create topics.
### 10. Send alerts to the topic
Suppoted alerts generaters are below:
- Mailgun ( `http://localhost:3000/topics/1/mailgun` )
- Mackerel ( `http://localhost:3000/topics/1/mackerel` )
- Alertmanager ( `http://localhost:3000/topics/1/alertmanager` )
- Slack( `http://localhost:3000/topics/1/slack` )
If you want to use Mailgun, you can configure Mailgun route setting with Mailgun endpoint you can see in [http://localhost:3000/topics/1/mailgun](http://localhost:3000/topics/1/mailgun)
## Configuration
### Notifier Providers
#### HipChat
- `api_token`
- `api_version`: `v1` or `v2`
#### Twilio
- `account_sid`
- `auth_token`
- `from`: Phone number
#### Mailgun
- `api_key`
- `from`: Email address
### Notifiers
#### Common fields
These are supported by all notifier provider
```
or_conditions:
- japanese_weekday: true
not_between: 9:30+0900-18:30+0900
- not_japanese_weekday: true
```
#### HipChat
- `room`: Room name or ID
#### Twilio
- `to`: Phone number
#### Mailgun
- `to`: Email address
================================================
FILE: Rakefile
================================================
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks
================================================
FILE: app/assets/images/.keep
================================================
================================================
FILE: app/assets/javascripts/application.js
================================================
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require_tree .
================================================
FILE: app/assets/javascripts/comments.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/escalation_series.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/escalations.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/home.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/incident_events.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/incidents.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/maintenances.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/notifier_providers.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/notifiers.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/sessions.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/slack.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/topics.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/users.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/stylesheets/application.css
================================================
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any styles
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope.
*
*= require_tree .
*= require_self
*/
================================================
FILE: app/assets/stylesheets/comments.scss
================================================
// Place all the styles related to the comments controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/escalation_series.scss
================================================
// Place all the styles related to the EscalationSeries controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/escalations.scss
================================================
// Place all the styles related to the escalations controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/home.scss
================================================
// Place all the styles related to the home controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/incident_events.scss
================================================
// Place all the styles related to the incident_events controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/incidents.scss
================================================
// Place all the styles related to the incidents controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/maintenances.scss
================================================
// Place all the styles related to the maintenances controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/notifier_providers.scss
================================================
// Place all the styles related to the NotifierProviders controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/notifiers.scss
================================================
// Place all the styles related to the notifiers controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/scaffolds.scss
================================================
body {
background-color: #fff;
color: #333;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}
p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}
pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
}
a {
color: #000;
&:visited {
color: #666;
}
&:hover {
color: #fff;
background-color: #000;
}
}
div {
&.field, &.actions {
margin-bottom: 10px;
}
}
#notice {
color: green;
}
.field_with_errors {
padding: 2px;
background-color: red;
display: table;
}
#error_explanation {
width: 450px;
border: 2px solid red;
padding: 7px;
padding-bottom: 0;
margin-bottom: 20px;
background-color: #f0f0f0;
h2 {
text-align: left;
font-weight: bold;
padding: 5px 5px 5px 15px;
font-size: 12px;
margin: -7px;
margin-bottom: 0px;
background-color: #c00;
color: #fff;
}
ul li {
font-size: 12px;
list-style: square;
}
}
================================================
FILE: app/assets/stylesheets/sessions.scss
================================================
// Place all the styles related to the sessions controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/slack.scss
================================================
// Place all the styles related to the slack controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/topics.scss
================================================
// Place all the styles related to the topics controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/assets/stylesheets/users.scss
================================================
// Place all the styles related to the users controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
================================================
FILE: app/controllers/application_controller.rb
================================================
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :null_session
helper_method :current_user
if ENV["GOOGLE_CLIENT_ID"]
before_action :login_required
end
def login_required
unless current_user
session[:user_id] = nil
redirect_to '/auth/google_oauth2_with_calendar'
return
end
unless current_user.active
render text: "You are not activated yet. Please ask administrator to activate you"
return
end
end
private
def current_user=(user)
session[:user_id] = user.id
end
def current_user
if user_id = session[:user_id]
User.find(user_id)
elsif login_token = request.headers['X-Login-Token']
User.find_by(login_token: login_token)
end
end
end
================================================
FILE: app/controllers/comments_controller.rb
================================================
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :set_incident
# GET /comments
# GET /comments.json
def index
@comments = Comment.where(incident: @incident)
end
# GET /comments/1
# GET /comments/1.json
def show
end
# GET /comments/new
def new
@comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
p comment_params
@comment = Comment.new(comment_params)
respond_to do |format|
if @comment.save
format.html { redirect_to [@incident, @comment], notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: [@incident, @comment] }
else
format.html { render :new }
format.json { render json: @comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if @comment.update(comment_params)
format.html { redirect_to [@incident, @comment], notice: 'Comment was successfully updated.' }
format.json { render :show, status: :ok, location: [@incident, @comment] }
else
format.html { render :edit }
format.json { render json: @comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
@comment.destroy
respond_to do |format|
format.html { redirect_to incident_comments_url, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
@comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:incident_id, :user_id, :comment)
end
def set_incident
@incident = Incident.find(params[:incident_id])
end
end
================================================
FILE: app/controllers/concerns/.keep
================================================
================================================
FILE: app/controllers/escalation_series_controller.rb
================================================
class EscalationSeriesController < ApplicationController
before_action :set_escalation_series, only: [:show, :edit, :update, :destroy, :update_escalations]
# GET /escalation_series
# GET /escalation_series.json
def index
@escalation_series = EscalationSeries.all
end
# GET /escalation_series/1
# GET /escalation_series/1.json
def show
end
# GET /escalation_series/new
def new
@escalation_series = EscalationSeries.new
end
# GET /escalation_series/1/edit
def edit
end
# POST /escalation_series
# POST /escalation_series.json
def create
@escalation_series = EscalationSeries.new(escalation_series_params)
respond_to do |format|
if @escalation_series.save
format.html { redirect_to @escalation_series, notice: 'Escalation series was successfully created.' }
format.json { render :show, status: :created, location: @escalation_series }
else
format.html { render :new }
format.json { render json: @escalation_series.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /escalation_series/1
# PATCH/PUT /escalation_series/1.json
def update
respond_to do |format|
if @escalation_series.update(escalation_series_params)
format.html { redirect_to @escalation_series, notice: 'Escalation series was successfully updated.' }
format.json { render :show, status: :ok, location: @escalation_series }
else
format.html { render :edit }
format.json { render json: @escalation_series.errors, status: :unprocessable_entity }
end
end
end
# DELETE /escalation_series/1
# DELETE /escalation_series/1.json
def destroy
@escalation_series.destroy
respond_to do |format|
format.html { redirect_to escalation_series_index_url, notice: 'Escalation series was successfully destroyed.' }
format.json { head :no_content }
end
end
def update_escalations
@escalation_series.update_escalations!
end
private
# Use callbacks to share common setup or constraints between actions.
def set_escalation_series
@escalation_series = EscalationSeries.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def escalation_series_params
params.require(:escalation_series).permit(:name, :settings).tap do |v|
v[:settings] = YAML.load(v[:settings])
end
end
end
================================================
FILE: app/controllers/escalations_controller.rb
================================================
class EscalationsController < ApplicationController
before_action :set_escalation, only: [:show, :edit, :update, :destroy]
# GET /escalations
# GET /escalations.json
def index
@escalations = Escalation.all.order('escalate_after_sec')
end
# GET /escalations/1
# GET /escalations/1.json
def show
end
# GET /escalations/new
def new
@escalation = Escalation.new
end
# GET /escalations/1/edit
def edit
end
# POST /escalations
# POST /escalations.json
def create
@escalation = Escalation.new(escalation_params)
respond_to do |format|
if @escalation.save
format.html { redirect_to @escalation, notice: 'Escalation was successfully created.' }
format.json { render :show, status: :created, location: @escalation }
else
format.html { render :new }
format.json { render json: @escalation.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /escalations/1
# PATCH/PUT /escalations/1.json
def update
respond_to do |format|
if @escalation.update(escalation_params)
format.html { redirect_to @escalation, notice: 'Escalation was successfully updated.' }
format.json { render :show, status: :ok, location: @escalation }
else
format.html { render :edit }
format.json { render json: @escalation.errors, status: :unprocessable_entity }
end
end
end
# DELETE /escalations/1
# DELETE /escalations/1.json
def destroy
@escalation.destroy
respond_to do |format|
format.html { redirect_to escalations_url, notice: 'Escalation was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_escalation
@escalation = Escalation.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def escalation_params
params.require(:escalation).permit(:escalate_to_id, :escalate_after_sec, :escalation_series_id)
end
end
================================================
FILE: app/controllers/home_controller.rb
================================================
class HomeController < ApplicationController
def index
redirect_to incidents_path
end
end
================================================
FILE: app/controllers/incident_events_controller.rb
================================================
require 'securerandom'
class IncidentEventsController < ApplicationController
skip_before_action :login_required, only: [:twilio], raise: false
def twilio
@event = IncidentEvent.find(params[:id])
language = ENV['TWILIO_LANGUAGE'] || 'en-US'
resp = nil
if params[:Digits]
case params[:Digits]
when '1'
@event.incident.acknowledge! rescue nil
when '2'
@event.incident.resolve! rescue nil
end
resp = Twilio::TwiML::VoiceResponse.new do |r|
r.say message: @event.incident.status, voice: 'alice', language: language
r.hangup
end
else
resp = Twilio::TwiML::VoiceResponse.new do |r|
r.gather timeout: 10, numDigits: 1 do |g|
g.say message: "This is Waker alert.", voice: 'alice', language: language
g.say message: @event.incident.subject, voice: 'alice', language: language
g.say message: "To acknowledge, press 1.", voice: 'alice', language: language
g.say message: "To resolve, press 2.", voice: 'alice', language: language
end
end
end
render xml: resp.to_s
end
end
================================================
FILE: app/controllers/incidents_controller.rb
================================================
class IncidentsController < ApplicationController
before_action :set_incidents, only: [:index, :bulk_acknowledge, :bulk_resolve]
before_action :set_incident, only: [:show, :edit, :update, :destroy, :acknowledge, :resolve]
before_action :ensure_hash, only: [:acknowledge, :resolve]
skip_before_action :login_required, only: [:acknowledge, :resolve], raise: false
# GET /incidents
# GET /incidents.json
def index
@page = (params[:page] || 1).to_i
@incidents = @incidents.order('id DESC').page(@page).per(25)
end
# GET /incidents/1
# GET /incidents/1.json
def show
end
# GET /incidents/new
def new
@incident = Incident.new
end
# GET /incidents/1/edit
def edit
end
# POST /incidents
# POST /incidents.json
def create
@incident = Incident.new(incident_params)
respond_to do |format|
if @incident.save
format.html { redirect_to @incident, notice: 'Incident was successfully created.' }
format.json { render :show, status: :created, location: @incident }
else
format.html { render :new }
format.json { render json: @incident.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /incidents/1
# PATCH/PUT /incidents/1.json
def update
respond_to do |format|
if @incident.update(incident_params)
format.html { redirect_to @incident, notice: 'Incident was successfully updated.' }
format.json { render :show, status: :ok, location: @incident }
else
format.html { render :edit }
format.json { render json: @incident.errors, status: :unprocessable_entity }
end
end
end
def bulk_acknowledge
@incidents.opened.update_all(status: Incident.statuses[:acknowledged])
respond_to do |format|
format.html { redirect_to incidents_url, notice: 'Incidents were successfully acknowledged.' }
format.json { head :no_content }
end
end
def bulk_resolve
@incidents.update_all(status: Incident.statuses[:resolved])
respond_to do |format|
format.html { redirect_to incidents_url, notice: 'Incidents were successfully resolved.' }
format.json { head :no_content }
end
end
# DELETE /incidents/1
# DELETE /incidents/1.json
def destroy
@incident.destroy
respond_to do |format|
format.html { redirect_to incidents_url, notice: 'Incident was successfully destroyed.' }
format.json { head :no_content }
end
end
def acknowledge
@incident.acknowledge!
respond_to do |format|
if current_user
format.html { redirect_to incidents_url, notice: 'Incident was successfully acknowledged.' }
else
format.html { render text: "Acknowledged" }
end
format.json { render json: {status: 'ok'} }
end
end
def resolve
@incident.resolve!
respond_to do |format|
if current_user
format.html { redirect_to incidents_url, notice: 'Incident was successfully resolved.' }
else
format.html { render text: "Resolved" }
end
format.json { render json: {status: 'ok'} }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_incident
@incident = Incident.find(params[:id])
end
def set_incidents
set_visible_statuses
set_visible_topic
@incidents = Incident.all
if @visible_statuses
@incidents = @incidents.where(status: @visible_statuses)
end
if @visible_topic
@incidents = @incidents.where(topic: @visible_topic)
end
end
def set_visible_statuses
@visible_statuses = session[:incidents_statuses]
# for transition from rev 0a2dd42 or earlier
@visible_statuses = nil if @visible_statuses.try(:empty?)
if params[:statuses]
if params[:statuses] == ''
@visible_statuses = nil # all
else
@visible_statuses = params[:statuses].split(',').map(&:to_i)
end
session[:incidents_statuses] = @visible_statuses
end
end
def set_visible_topic
@visible_topic = session[:incidents_topic]
# for transition from rev 0a2dd42 or earlier
@visible_topic = nil if @visible_topic == 'all'
if params[:topic]
if params[:topic] == 'all'
@visible_topic = nil # all
else
@visible_topic = params[:topic].to_i
end
session[:incidents_topic] = @visible_topic
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def incident_params
params.require(:incident).permit(:subject, :description, :topic_id, :occured_at)
end
def ensure_hash
unless params[:hash] == @incident.confirmation_hash
render text: "Wrong hash", status: 403
end
end
end
================================================
FILE: app/controllers/maintenances_controller.rb
================================================
class MaintenancesController < ApplicationController
before_action :set_maintenance, only: [:show, :edit, :update, :destroy]
# GET /maintenances
# GET /maintenances.json
def index
@maintenances = Maintenance.not_expired
end
# GET /maintenances/1
# GET /maintenances/1.json
def show
end
# GET /maintenances/new
def new
now = Time.now
@maintenance = Maintenance.new(
start_time: now,
end_time: now + 60*60
)
end
# GET /maintenances/1/edit
def edit
end
# POST /maintenances
# POST /maintenances.json
def create
@maintenance = Maintenance.new(maintenance_params)
respond_to do |format|
if @maintenance.save
format.html { redirect_to @maintenance, notice: 'Maintenance was successfully created.' }
format.json { render :show, status: :created, location: @maintenance }
else
format.html { render :new }
format.json { render json: @maintenance.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /maintenances/1
# PATCH/PUT /maintenances/1.json
def update
respond_to do |format|
if @maintenance.update(maintenance_params)
format.html { redirect_to @maintenance, notice: 'Maintenance was successfully updated.' }
format.json { render :show, status: :ok, location: @maintenance }
else
format.html { render :edit }
format.json { render json: @maintenance.errors, status: :unprocessable_entity }
end
end
end
# DELETE /maintenances/1
# DELETE /maintenances/1.json
def destroy
@maintenance.destroy
respond_to do |format|
format.html { redirect_to maintenances_url, notice: 'Maintenance was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_maintenance
@maintenance = Maintenance.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def maintenance_params
params.require(:maintenance).permit(:topic_id, :start_time, :end_time, :filter)
end
end
================================================
FILE: app/controllers/notifier_providers_controller.rb
================================================
class NotifierProvidersController < ApplicationController
before_action :set_notifier_provider, only: [:show, :edit, :update, :destroy]
# GET /notifier_providers
# GET /notifier_providers.json
def index
@notifier_providers = NotifierProvider.all
end
# GET /notifier_providers/1
# GET /notifier_providers/1.json
def show
end
# GET /notifier_providers/new
def new
@notifier_provider = NotifierProvider.new
end
# GET /notifier_providers/1/edit
def edit
end
# POST /notifier_providers
# POST /notifier_providers.json
def create
@notifier_provider = NotifierProvider.new(notifier_provider_params)
respond_to do |format|
if @notifier_provider.save
format.html { redirect_to @notifier_provider, notice: 'Notifier provider was successfully created.' }
format.json { render :show, status: :created, location: @notifier_provider }
else
format.html { render :new }
format.json { render json: @notifier_provider.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /notifier_providers/1
# PATCH/PUT /notifier_providers/1.json
def update
respond_to do |format|
if @notifier_provider.update(notifier_provider_params)
format.html { redirect_to @notifier_provider, notice: 'Notifier provider was successfully updated.' }
format.json { render :show, status: :ok, location: @notifier_provider }
else
format.html { render :edit }
format.json { render json: @notifier_provider.errors, status: :unprocessable_entity }
end
end
end
# DELETE /notifier_providers/1
# DELETE /notifier_providers/1.json
def destroy
@notifier_provider.destroy
respond_to do |format|
format.html { redirect_to notifier_providers_url, notice: 'Notifier provider was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_notifier_provider
@notifier_provider = NotifierProvider.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def notifier_provider_params
params.require(:notifier_provider).permit(:name, :kind, :settings).tap do |v|
v[:settings] = YAML.load(v[:settings])
end
end
end
================================================
FILE: app/controllers/notifiers_controller.rb
================================================
class NotifiersController < ApplicationController
before_action :set_notifier, only: [:show, :edit, :update, :destroy]
# GET /notifiers
# GET /notifiers.json
def index
@notifiers = Notifier.all
end
# GET /notifiers/1
# GET /notifiers/1.json
def show
end
# GET /notifiers/new
def new
@notifier = Notifier.new
end
# GET /notifiers/1/edit
def edit
end
# POST /notifiers
# POST /notifiers.json
def create
@notifier = Notifier.new(notifier_params)
respond_to do |format|
if @notifier.save
format.html { redirect_to @notifier, notice: 'Notifier was successfully created.' }
format.json { render :show, status: :created, location: @notifier }
else
format.html { render :new }
format.json { render json: @notifier.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /notifiers/1
# PATCH/PUT /notifiers/1.json
def update
respond_to do |format|
if @notifier.update(notifier_params)
format.html { redirect_to @notifier, notice: 'Notifier was successfully updated.' }
format.json { render :show, status: :ok, location: @notifier }
else
format.html { render :edit }
format.json { render json: @notifier.errors, status: :unprocessable_entity }
end
end
end
# DELETE /notifiers/1
# DELETE /notifiers/1.json
def destroy
@notifier.destroy
respond_to do |format|
format.html { redirect_to notifiers_url, notice: 'Notifier was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_notifier
@notifier = Notifier.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def notifier_params
params.require(:notifier).permit(:user_id, :kind, :settings, :notify_after_sec, :provider_id, :topic_id, :enabled).tap do |v|
v[:settings] = YAML.load(v[:settings])
end
end
end
================================================
FILE: app/controllers/sessions_controller.rb
================================================
class SessionsController < ApplicationController
skip_before_action :login_required, only: [:create]
def create
@user = User.find_or_create_from_auth_hash(auth_hash)
@user.update_credentials_from_auth_hash(auth_hash)
self.current_user = @user
redirect_to '/'
end
private
def auth_hash
request.env['omniauth.auth']
end
end
================================================
FILE: app/controllers/slack_controller.rb
================================================
class SlackController < ApplicationController
skip_before_action :login_required, only: [:interactive], raise: false
def interactive
verify!
message = payload['original_message']
message['attachments'][0].delete('actions')
user = payload['user']['name']
text = ''
payload['actions'].each do |a|
case a['value']
when 'acknowledge'
incident.acknowledge!
text = ":white_check_mark: @#{user} acknowledged"
when 'resolve'
incident.resolve!
text = ":white_check_mark: @#{user} resolved"
end
end
message['attachments'][0]['fields'] = [{
'title' => text,
'value' => '',
'short' => false,
}]
render json: message
end
private def payload
JSON.parse(params[:payload])
end
private def verify!
verified = false
Notifier.preload(:provider).find_each do |n|
settings = n.provider.settings.merge(n.settings)
token = settings['verification_token']
if n.provider.slack? && settings['enable_buttons'] && payload['token'] == token
verified = true
break
end
end
unless verified
raise 'token verification failed'
end
end
private def incident_id
payload['callback_id'].match(/\Aincident\.(\d+)\z/)[1].to_i
end
private def incident
Incident.find(incident_id)
end
end
================================================
FILE: app/controllers/topics_controller.rb
================================================
class TopicsController < ApplicationController
before_action :set_topic, only: [:show, :edit, :update, :destroy, :mailgun, :mackerel, :alertmanager, :slack]
skip_before_action :login_required, only: [:mailgun, :mackerel, :alertmanager, :slack], raise: false
# GET /topics
# GET /topics.json
def index
@topics = Topic.all
end
# GET /topics/1
# GET /topics/1.json
def show
end
# GET /topics/new
def new
@topic = Topic.new
end
# GET /topics/1/edit
def edit
end
# POST /topics
# POST /topics.json
def create
@topic = Topic.new(topic_params)
respond_to do |format|
if @topic.save
format.html { redirect_to @topic, notice: 'Topic was successfully created.' }
format.json { render :show, status: :created, location: @topic }
else
format.html { render :new }
format.json { render json: @topic.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /topics/1
# PATCH/PUT /topics/1.json
def update
respond_to do |format|
if @topic.update(topic_params)
format.html { redirect_to @topic, notice: 'Topic was successfully updated.' }
format.json { render :show, status: :ok, location: @topic }
else
format.html { render :edit }
format.json { render json: @topic.errors, status: :unprocessable_entity }
end
end
end
# DELETE /topics/1
# DELETE /topics/1.json
def destroy
@topic.destroy
respond_to do |format|
format.html { redirect_to topics_url, notice: 'Topic was successfully destroyed.' }
format.json { head :no_content }
end
end
# POST /topics/1/mailgun
def mailgun
unless @topic.enabled
Rails.logger.info "Incident creation is skipped because the topic is disabled."
render json: {}, status: 200
return
end
# http://documentation.mailgun.com/user_manual.html#routes
subject = params[:subject]
description = params['body-plain']
if @topic.in_maintenance?(subject, description)
Rails.logger.info "Incident creation is skipped because the topic is in maintenance."
render json: {}, status: 200
return
end
@topic.incidents.create!(
subject: subject,
description: description,
)
render json: {}, status: 200
end
# POST /topics/1/mackerel
def mackerel
data = JSON.parse(request.body.read)
return render json: {}, status: 200 if data.dig('alert', 'status') == 'ok' || data.dig('alertGroup', 'status') == 'OK'
unless @topic.enabled
Rails.logger.info "Incident creation is skipped because the topic is disabled."
render json: {}, status: 200
return
end
if data['event'] == 'alertGroup' then
subject = "[#{data['alertGroup']['status']}] #{data['alertGroupSetting']['name']}"
else
name = data.key?('host') ? data['host']['name'] : data['alert']['monitorName']
subject = "[#{data['alert']['status']}] #{name}"
end
description = JSON.pretty_generate(data)
if @topic.in_maintenance?(subject, description)
Rails.logger.info "Incident creation is skipped because the topic is in maintenance"
render json: {}, status: 200
return
end
@topic.incidents.create!(
subject: subject,
description: description,
)
render json: {}, status: 200
end
# POST /topics/1/alertmanager
def alertmanager
data = JSON.parse(request.body.read)
unless @topic.enabled
Rails.logger.info "Incident creation is skipped because the topic is disabled."
render json: {}, status: 200
return
end
subject = "[#{data['commonLabels']['severity']}] #{data['commonLabels']['alertname']}: #{data['commonAnnotations']['summary']}"
description = JSON.pretty_generate(data)
if @topic.in_maintenance?(subject, description)
Rails.logger.info "Incident creation is skipped because the topic is in maintenance"
render json: {}, status: 200
return
end
@topic.incidents.create!(
subject: subject,
description: description,
)
render json: {}, status: 200
end
def slack
unless @topic.enabled
Rails.logger.info "Incident creation is skipped because the topic is disabled."
render json: {}, status: 200
return
end
subject = "escalation from slack,channel name:#{params['channel_name']} #{params['text']}"
description = "channel:#{params['channel_name']} user:#{params['user_name']} #{params['text']}"
if @topic.in_maintenance?(subject, description)
Rails.logger.info "Incident creation is skipped because the topic is in maintenance."
render json: {}, status: 200
return
end
@topic.incidents.create!(
subject: subject,
description: description,
)
render json: {text: 'accept your page'}, status: 200
end
private
# Use callbacks to share common setup or constraints between actions.
def set_topic
@topic = Topic.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def topic_params
params.require(:topic).permit(:name, :kind, :escalation_series_id, :enabled)
end
end
================================================
FILE: app/controllers/users_controller.rb
================================================
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy, :activation, :deactivation]
# GET /users
# GET /users.json
def index
@users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
@user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
@user = User.new(user_params)
respond_to do |format|
if @user.save
format.html { redirect_to @user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: @user }
else
format.html { render :new }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if @user.update(user_params)
format.html { redirect_to @user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: @user }
else
format.html { render :edit }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
@user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
# PATCH/PUT /users/1/activation
def activation
@user.update!(active: true)
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully activated.' }
end
end
# PATCH/PUT /users/1/deactivation
def deactivation
@user.update!(active: false)
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully deactivated.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
@user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name)
end
end
================================================
FILE: app/helpers/application_helper.rb
================================================
module ApplicationHelper
end
================================================
FILE: app/helpers/comments_helper.rb
================================================
module CommentsHelper
end
================================================
FILE: app/helpers/escalation_series_helper.rb
================================================
module EscalationSeriesHelper
end
================================================
FILE: app/helpers/escalations_helper.rb
================================================
module EscalationsHelper
end
================================================
FILE: app/helpers/home_helper.rb
================================================
module HomeHelper
end
================================================
FILE: app/helpers/incident_events_helper.rb
================================================
module IncidentEventsHelper
end
================================================
FILE: app/helpers/incidents_helper.rb
================================================
module IncidentsHelper
end
================================================
FILE: app/helpers/maintenances_helper.rb
================================================
module MaintenancesHelper
end
================================================
FILE: app/helpers/notifier_providers_helper.rb
================================================
module NotifierProvidersHelper
end
================================================
FILE: app/helpers/notifiers_helper.rb
================================================
module NotifiersHelper
end
================================================
FILE: app/helpers/sessions_helper.rb
================================================
module SessionsHelper
end
================================================
FILE: app/helpers/slack_helper.rb
================================================
module SlackHelper
end
================================================
FILE: app/helpers/topics_helper.rb
================================================
module TopicsHelper
end
================================================
FILE: app/helpers/users_helper.rb
================================================
module UsersHelper
end
================================================
FILE: app/mailers/.keep
================================================
================================================
FILE: app/models/.keep
================================================
================================================
FILE: app/models/application_record.rb
================================================
# Base ApplicationRecord Class
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
================================================
FILE: app/models/comment.rb
================================================
class Comment < ApplicationRecord
belongs_to :incident
belongs_to :user
validates :incident, presence: true
validates :user, presence: true
validates :comment, presence: true
end
================================================
FILE: app/models/concerns/.keep
================================================
================================================
FILE: app/models/escalation.rb
================================================
class Escalation < ApplicationRecord
belongs_to :escalation_series
belongs_to :escalate_to, class_name: 'User'
validates :escalation_series, presence: true
validates :escalate_to, presence: true
validates :escalate_after_sec, numericality: {greater_than_or_equal_to: 5}
end
================================================
FILE: app/models/escalation_series.rb
================================================
class EscalationSeries < ApplicationRecord
has_many :escalations, dependent: :destroy
has_many :topics, dependent: :destroy
validates :name, presence: true
serialize :settings, JSON
after_initialize :set_defaults
def set_defaults
self.settings ||= {}
end
def update_escalations!
updater_class = case self.settings['update_by']
when 'google_calendar'
GoogleCalendarEscalationUpdater
else
nil
end
if updater_class
updater = updater_class.new(self)
updater.update!
end
end
class EscalationUpdater
def initialize(series)
@series = series
end
def update!
raise NotImplementedError
end
private
def settings
@series.settings
end
end
class GoogleCalendarEscalationUpdater < EscalationUpdater
def initialize(*)
super
require 'google/api_client'
end
def update!
Rails.logger.info "Update #{@series.inspect} by Google Calendar"
if user_as.provider && user_as.provider != 'google_oauth2_with_calendar'
raise "User ##{user_as.id} is not authenticated by 'google_oauth2_with_calendar' provider"
end
client = Google::APIClient.new(
application_name: "Waker",
application_version: "2.0.0",
user_agent: "Waker/2.0.0 google-api-client"
)
auth = client.authorization
expired = Time.at(user_as.credentials.fetch('expires_at')) < Time.now
if user_as.credentials.fetch('expires') && expired
Rails.logger.info "Refreshing access token..."
auth.client_id = ENV["GOOGLE_CLIENT_ID"]
auth.client_secret = ENV["GOOGLE_CLIENT_SECRET"]
auth.refresh_token = user_as.credentials.fetch('refresh_token')
auth.grant_type = "refresh_token"
auth.refresh!
user_as.update!(
credentials: user_as.credentials.merge(
'token' => auth.access_token,
'expires_at' => auth.expires_at.to_i,
)
)
else
auth.access_token = user_as.credentials.fetch('token')
end
calendar_api = client.discovered_api('calendar', 'v3')
calendar = client.execute(
api_method: calendar_api.calendar_list.list,
parameters: {},
).data.items.find do |cal|
cal['summary'] == calendar_name
end
events = client.execute(
api_method: calendar_api.events.list,
parameters: {
'calendarId' => calendar['id'],
'timeMax' => (Time.now + 1).iso8601,
'timeMin' => (Time.now).iso8601,
'singleEvents' => true,
},
).data.items
events.each do |event|
unless event['end']['dateTime'] && event['start']['dateTime']
raise "dateTime field is not found (The event may be all-day event)\n#{event}"
end
end
events.sort! do |a, b|
a['end']['dateTime'] - a['start']['dateTime'] <=>
b['end']['dateTime'] - b['start']['dateTime']
end
# shortest event
event = events.first
persons = event['summary'].split(event_delimiter).map(&:strip)
escalations = @series.escalations.order('escalate_after_sec')
persons.each_with_index do |name, i|
user = User.find_by(name: name)
raise "User '#{name}' is not found." unless user
escalation = escalations[i]
escalation.update!(escalate_to: user)
end
end
private
def user_as
User.find(settings.fetch('user_as_id'))
end
def calendar_name
settings.fetch('calendar')
end
def event_delimiter
settings.fetch('event_delimiter')
end
end
end
================================================
FILE: app/models/escalation_update_worker.rb
================================================
class EscalationUpdateWorker
include Sidekiq::Worker
def perform
EscalationSeries.all.each do |series|
handle_series(series)
end
rescue => err
Rails.logger.error "#{err.class}: #{err}\n#{err.backtrace.join("\n")}"
end
private
def handle_series(series)
series.update_escalations!
end
end
================================================
FILE: app/models/escalation_worker.rb
================================================
class EscalationWorker
include Sidekiq::Worker
def self.enqueue(incident, escalation)
Rails.logger.info "Enqueue EscalaionWorker job"
self.perform_in(escalation.escalate_after_sec, incident.id, escalation.id)
end
def perform(incident_id, escalation_id)
incident = Incident.find(incident_id)
escalation = Escalation.find(escalation_id)
if incident.opened?
incident.events.create(
kind: :escalated,
info: {
escalation: escalation,
escalated_to: escalation.escalate_to,
},
)
end
end
end
================================================
FILE: app/models/incident.rb
================================================
require 'digest/sha1'
class Incident < ApplicationRecord
STATUSES = [:opened, :acknowledged, :resolved]
belongs_to :topic
has_many :events, class_name: 'IncidentEvent', dependent: :destroy
enum status: STATUSES
has_many :comments
validates :topic, presence: true
validates :subject, presence: true
validates :description, presence: true
validates :occured_at, presence: true
after_initialize :set_defaults
after_create :enqueue
def acknowledge!
return if self.acknowledged? || self.resolved?
self.acknowledged!
events.create(kind: :acknowledged)
end
def resolve!
return if self.resolved?
self.resolved!
events.create(kind: :resolved)
end
def confirmation_hash
Digest::SHA1.hexdigest("#{Rails.application.secrets.secret_key_base}#{self.id}")
end
private
def set_defaults
self.status ||= :opened
self.occured_at ||= Time.now
end
def enqueue
topic.escalation_series.escalations.each do |escalation|
EscalationWorker.enqueue(self, escalation)
end
events.create(kind: :opened)
end
end
================================================
FILE: app/models/incident_event.rb
================================================
class IncidentEvent < ApplicationRecord
belongs_to :incident
enum kind: [:opened, :acknowledged, :resolved, :escalated, :commented, :notified]
validates :incident, presence: true
validates :kind, presence: true
serialize :info, JSON
after_create :notify
after_initialize :set_defaults
def set_defaults
self.info ||= {}
end
def notify
return if self.notified?
Notifier.all.each do |notifier|
next if notifier.topic && self.incident.topic != notifier.topic
notifier.notify(self)
end
end
def escalated_to
self.info['escalated_to'] && User.find(self.info['escalated_to']['id'])
end
def escalation
self.info['escalation'] && Escalation.find(self.info['escalation']['id'])
end
def notifier
self.info['notifier'] && Notifier.find(self.info['notifier']['id'])
end
def event
self.info['event'] && IncidentEvent.find(self.info['event']['id'])
end
end
================================================
FILE: app/models/maintenance.rb
================================================
class Maintenance < ApplicationRecord
scope :active, -> { t = Time.now; where('start_time <= ? AND ? <= end_time', t, t) }
scope :not_expired, -> { where('? <= end_time', Time.now) }
scope :expired, -> { where('end_time < ?', Time.now) }
belongs_to :topic
def filter_regexp
Regexp.new(filter)
end
end
================================================
FILE: app/models/notification_worker.rb
================================================
class NotificationWorker
include Sidekiq::Worker
def self.enqueue(event:, notifier:)
Rails.logger.info "Enqueue NotificationWorker job"
self.perform_in(notifier.notify_after_sec, event.id, notifier.id)
end
def perform(event_id, notifier_id)
event = IncidentEvent.find(event_id)
notifier = Notifier.find(notifier_id)
if notifier.enabled
notifier.notify_immediately(event)
end
end
end
================================================
FILE: app/models/notifier.rb
================================================
class Notifier < ApplicationRecord
belongs_to :provider, class_name: 'NotifierProvider'
belongs_to :user
belongs_to :topic
validates :provider, presence: true
validates :notify_after_sec, numericality: {greater_than_or_equal_to: 5}
serialize :settings, JSON
after_initialize :set_defaults
def set_defaults
self.settings ||= {}
end
def notify(event)
NotificationWorker.enqueue(event: event, notifier: self)
end
def notify_immediately(event)
provider.notify(event: event, notifier: self)
end
end
================================================
FILE: app/models/notifier_provider.rb
================================================
class NotifierProvider < ApplicationRecord
serialize :settings, JSON
enum kind: [:mailgun, :file, :rails_logger, :hipchat, :twilio, :slack, :datadog, :sns]
validates :name, presence: true
after_initialize :set_defaults
def set_defaults
self.settings ||= {}
end
def concrete_class
self.class.const_get("#{kind.to_s.camelize}ConcreteProvider")
end
def notify(event:, notifier:)
concrete_class.new(provider: self, notifier: notifier, event: event).notify
end
class ConcreteProvider
def initialize(provider:, notifier:, event:)
@provider = provider
@notifier = notifier
@event = event
end
def notify
if skip?
Rails.logger.info "Notification skipped."
else
if target_events.include?(kind_of_event)
_notify
@event.incident.events.create(
kind: :notified,
info: {notifier: @notifier, event: @event}
)
else
Rails.logger.info "Notification skipped due to target events (#{target_events} doesn't include #{kind_of_event})"
end
end
end
def _notify
raise NotImplementedError
end
def settings
@provider.settings.merge(@notifier.settings)
end
def skip?
# or_conditions = [
# {
# 'only_japanese_weekday' => true,
# 'not_between' => '9:30-18:30',
# },
# {
# 'not_japanese_weekday' => true,
# }
# ]
return skip_due_to_or_conditions? ||
skip_due_to_status_of_incident?
end
def skip_due_to_status_of_incident?
if !@event.incident.opened? && !([:acknowledged, :resolved].include?(kind_of_event))
return true
end
false
end
def skip_due_to_or_conditions?
or_conditions = settings['or_conditions']
return false unless or_conditions
matched = or_conditions.any? do |condition|
# japanese_weekday
holiday = HolidayJp.holiday?(Date.today) || Time.now.saturday? || Time.now.sunday?
if holiday && condition['japanese_weekday']
next false
end
if !holiday && condition['not_japanese_weekday']
next false
end
# between
skip_due_to_between_condition = %w!between not_between!.any? do |k|
if s = condition[k]
start_time, end_time = s.split('-')
start_time = Time.parse(start_time)
end_time = Time.parse(end_time)
between = start_time < Time.now && Time.now < end_time
if (between && k == 'not_between') || (!between && k == 'between')
next true
end
end
false
end
next false if skip_due_to_between_condition
true
end
return !matched
end
def all_events
[:escalated, :escalated_to_me, :opened, :acknowledged, :resolved, :commented]
end
def target_events
settings['events'] &&
settings['events'].map {|v| v.to_sym }
end
def body(formats: [:text])
template_names = [kind_of_event, 'default']
template_names.each_with_index do |template_name, i|
begin
rendered = ApplicationController.new.render_to_string(
template: "notifier_providers/#{@provider.kind}/#{template_name}",
formats: formats,
layout: nil,
locals: {event: @event},
)
return rendered.strip
rescue ActionView::MissingTemplate
raise if template_names.size - 1 == i
end
end
end
def kind_of_event
if @event.escalated? && @event.escalated_to == @notifier.user
:escalated_to_me
else
@event.kind.to_sym
end
end
end
class FileConcreteProvider < ConcreteProvider
def _notify
end
end
class RailsLoggerConcreteProvider < ConcreteProvider
def _notify
Rails.logger.info(body)
end
def target_events
all_events
end
end
class HipchatConcreteProvider < ConcreteProvider
def _notify
case kind_of_event
when :opened
color = 'red'
when :acknowledged, :escalated
color = 'yellow'
when :resolved
color = 'green'
else
return
end
client = HipChat::Client.new(api_token, api_version: api_version)
client[room].send('Waker', body, color: color, notify: notify?)
end
private
def api_token
settings.fetch('api_token')
end
def room
settings.fetch('room')
end
def api_version
case settings.fetch('api_version')
when '2', 'v2'
'v2'
when '1', 'v1'
'v1'
else
'v2'
end
end
def notify?
!!settings['notify']
end
def target_events
super || [:escalated, :opened, :acknowledged, :resolved]
end
end
class MailgunConcreteProvider < ConcreteProvider
def _notify
conn = Faraday.new(url: 'https://api.mailgun.net') do |faraday|
faraday.request :url_encoded
faraday.response :logger
faraday.adapter Faraday.default_adapter
end
conn.basic_auth('api', api_key)
response = conn.post "/v2/#{domain}/messages", {
from: from,
to: to,
subject: "[Waker] #{@event.incident.subject}",
text: body,
html: body(formats: [:html]),
}
Rails.logger.info "response status: #{response.status}"
Rails.logger.info JSON.parse(response.body)
end
private
def api_key
settings.fetch('api_key')
end
def domain
from.split('@').last
end
def from
settings.fetch('from')
end
def to
settings.fetch('to')
end
def target_events
super || [:escalated_to_me]
end
end
class TwilioConcreteProvider < ConcreteProvider
def _notify
options = {}
options[:user] = basic_auth_user if basic_auth_user
options[:password] = basic_auth_password if basic_auth_password
url = Rails.application.routes.url_helpers.twilio_incident_event_url(
@event, options
)
Twilio::REST::Client.new(account_sid, auth_token).calls.create(
from: from,
to: to,
url: url,
)
end
def account_sid
settings.fetch('account_sid')
end
def auth_token
settings.fetch('auth_token')
end
def from
settings.fetch('from')
end
def to
settings.fetch('to')
end
def target_events
super || [:escalated_to_me]
end
def basic_auth_user
ENV['BASIC_AUTH_USER']
end
def basic_auth_password
ENV['BASIC_AUTH_PASSWORD']
end
end
class SlackConcreteProvider < ConcreteProvider
def _notify
fields = []
acknowledge_url = Rails.application.routes.url_helpers.acknowledge_incident_url(@event.incident, hash: @event.incident.confirmation_hash)
resolve_url = Rails.application.routes.url_helpers.resolve_incident_url(@event.incident, hash: @event.incident.confirmation_hash)
comment_url = Rails.application.routes.url_helpers.new_incident_comment_url(@event.incident)
actions = []
case kind_of_event
when :opened
color = 'danger'
title = 'New incident opened'
if buttons_enabled?
action_links = "<#{comment_url}|Comment>"
actions = [:acknowledge, :resolve]
else
action_links = "<#{acknowledge_url}|Acknowledge> or <#{resolve_url}|Resolve> | <#{comment_url}|Comment>"
end
when :acknowledged
color = 'warning'
title = 'Incident acknowledged'
if buttons_enabled?
action_links = "<#{comment_url}|Comment>"
actions = [:resolve]
else
action_links = "<#{resolve_url}|Resolve> | <#{comment_url}|Comment>"
end
when :escalated
color = 'warning'
title = "Incident escalated to #{@event.escalated_to.name}"
if buttons_enabled?
action_links = "<#{comment_url}|Comment>"
actions = [:acknowledge, :resolve]
else
action_links = "<#{acknowledge_url}|Acknowledge> or <#{resolve_url}|Resolve> | <#{comment_url}|Comment>"
end
when :resolved
color = 'good'
title = 'Incident resolved'
action_links = "<#{comment_url}|Comment>"
end
text = @event.incident.subject
if action_links
text += " (#{action_links})"
end
action_types = {
acknowledge: {
"name" => "response",
"text" => "Acknowledge",
"type" => "button",
"value" => "acknowledge",
},
resolve: {
"name" => "response",
"text" => "Resolve",
"type" => "button",
"value" => "resolve",
"style" => "primary",
},
}
attachments = [{
"fallback" => "[#{kind_of_event.to_s.capitalize}] #{@event.incident.subject}",
"color" => color,
"title" => title,
"text" => text,
"fields" => fields,
"callback_id" => "incident.#{@event.incident.id}",
"actions" => actions.map {|t| action_types[t] },
}]
payload = {'attachments' => attachments}
if channel
payload['channel'] = channel
end
url = URI.parse(webhook_url)
conn = Faraday.new(url: "#{url.scheme}://#{url.host}") do |faraday|
faraday.adapter Faraday.default_adapter
end
conn.post do |req|
req.url url.path
req.headers['Content-Type'] = 'application/json'
req.body = payload.to_json
end
end
private
def webhook_url
settings.fetch('webhook_url')
end
def channel
settings['channel']
end
def buttons_enabled?
settings['enable_buttons']
end
def target_events
[:escalated, :opened, :acknowledged, :resolved]
end
end
class DatadogConcreteProvider < ConcreteProvider
def _notify
dog = Dogapi::Client.new(api_key, app_key)
res = dog.emit_event(Dogapi::Event.new(
@event.incident.description, {
msg_title: @event.incident.subject,
alert_type: alert_type,
tags: tags,
source_type_name: source_type_name,
}
))
Rails.logger.info res
end
private
def api_key
settings.fetch('api_key')
end
def app_key
settings.fetch('app_key')
end
def alert_type
settings['alert_type'] || 'error'
end
def tags
settings['tags'] || 'waker'
end
def source_type_name
settings['source_type_name'] || 'waker'
end
def target_events
[:opened]
end
end
class SnsConcreteProvider < ConcreteProvider
def _notify
aws_config = {}
aws_config[:region] = region if region
aws_config[:access_key_id] = access_key_id if access_key_id
aws_config[:secret_access_key] = secret_access_key if secret_access_key
sns = Aws::SNS::Client.new(aws_config)
res = sns.publish(
topic_arn: topic_arn,
message: @event.incident.description,
subject: @event.incident.subject,
message_attributes: {
'kind_of_event' => {
data_type: 'String',
string_value: kind_of_event.to_s,
}
}
)
Rails.logger.info res
end
private
def topic_arn
settings.fetch('topic_arn')
end
def region
settings['region']
end
def access_key_id
settings['access_key_id']
end
def secret_access_key
settings['secret_access_key']
end
def target_events
all_events
end
end
end
================================================
FILE: app/models/topic.rb
================================================
class Topic < ApplicationRecord
enum kind: [:api]
belongs_to :escalation_series
has_many :incidents
validates :name, presence: true
validates :kind, presence: true
validates :escalation_series, presence: true
def in_maintenance?(*bodies)
maints = Maintenance.active.where(topic: self)
maints.any? do |m|
if m.filter.blank?
true
else
r = m.filter_regexp
bodies.any? do |body|
!!r.match(body)
end
end
end
end
end
================================================
FILE: app/models/user.rb
================================================
require 'securerandom'
class User < ApplicationRecord
scope :active, -> { where(active: true) }
has_many :notifiers
serialize :credentials, JSON
validates :name, presence: true
before_save :set_defaults
def self.find_or_create_from_auth_hash(auth_hash)
user = self.find_by(provider: auth_hash[:provider], uid: auth_hash[:uid])
return user if user
user = self.find_by(email: auth_hash[:info][:email])
if user
# email is deprecated
user.update!(provider: auth_hash[:provider], uid: auth_hash[:uid], email: nil)
return user
end
self.create!(provider: auth_hash[:provider], uid: auth_hash[:uid], name: auth_hash[:info][:name])
end
def update_credentials_from_auth_hash(auth_hash)
self.update!(credentials: auth_hash.fetch(:credentials))
end
private
def set_defaults
self.login_token ||= SecureRandom.hex
end
end
================================================
FILE: app/views/comments/_form.html.erb
================================================
<%= form_for([@incident, @comment]) do |f| %>
<% if @comment.errors.any? %>
<div class="alert alert-danger">
<h2><%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% @comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :incident_id, value: @incident.id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<p>
<strong>Incident:</strong>
<pre><%= @incident.subject %></pre>
</p>
<div class="form-group">
<%= f.label :comment %>
<%= f.text_area :comment, class: 'form-control', rows: 8 %>
</div>
<div class="actions">
<%= f.submit(class: 'btn btn-default') %>
</div>
<% end %>
================================================
FILE: app/views/comments/edit.html.erb
================================================
<h1>Editing Comment</h1>
<%= render 'form' %>
<%= link_to 'Show', [@incident, @comment] %> |
<%= link_to 'Back', incident_comments_path %>
================================================
FILE: app/views/comments/index.html.erb
================================================
<h1>Listing Comments</h1>
<p>
<strong>Incident:</strong>
<pre><%= @incident.subject %></pre>
</p>
<table class="table">
<thead>
<tr>
<th>Comment</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @comments.each do |comment| %>
<tr>
<td><%= comment.comment %> (<%= comment.user.name %>)</td>
<td><%= link_to 'Show', [@incident, comment] %></td>
<td><%= link_to 'Edit', edit_incident_comment_path(@incident, comment) %></td>
<td><%= link_to 'Destroy', [@incident, comment], method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Comment', new_incident_comment_path %> |
<%= link_to 'Incident', @incident %>
================================================
FILE: app/views/comments/index.json.jbuilder
================================================
json.array!(@comments) do |comment|
json.extract! comment, :id
json.url comment_url(comment, format: :json)
end
================================================
FILE: app/views/comments/new.html.erb
================================================
<h1>New Comment</h1>
<%= render 'form' %>
<%= link_to 'Back', incident_comments_path %>
================================================
FILE: app/views/comments/show.html.erb
================================================
<p>
<strong>Incident:</strong>
<pre><%= @incident.subject %></pre>
</p>
<p>
<strong>Comment:</strong>
<pre style=><%= auto_link(@comment.comment, :html => { :target => '_blank' }) %></pre>
</p>
<p>
<strong>User:</strong>
<pre><%= @comment.user.name %></pre>
</p>
<%= link_to 'Edit', edit_incident_comment_path(@incident, @comment) %> |
<%= link_to 'Back', incident_comments_path %>
================================================
FILE: app/views/comments/show.json.jbuilder
================================================
json.extract! @comment, @user, :id, :created_at, :updated_at
================================================
FILE: app/views/escalation_series/_form.html.erb
================================================
<%= form_for(@escalation_series) do |f| %>
<% if @escalation_series.errors.any? %>
<div class="alert alert-danger">
<h2><%= pluralize(@escalation_series.errors.count, "error") %> prohibited this escalation_series from being saved:</h2>
<ul>
<% @escalation_series.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, required: true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :settings %>
<%= f.text_area :settings, value: @escalation_series.settings.to_yaml, class: 'form-control', rows: 8 %>
</div>
<%= f.submit(class: 'btn btn-default') %>
<% end %>
================================================
FILE: app/views/escalation_series/edit.html.erb
================================================
<h1>Editing Escalation Series</h1>
<%= render 'form' %>
<%= link_to 'Show', @escalation_series %> |
<%= link_to 'Back', escalation_series_index_path %>
================================================
FILE: app/views/escalation_series/index.html.erb
================================================
<h1>Listing Escalation Series</h1>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @escalation_series.each do |escalation_series| %>
<tr>
<td><%= escalation_series.name %></td>
<td><%= link_to 'Show', escalation_series %></td>
<td><%= link_to 'Edit', edit_escalation_series_path(escalation_series) %></td>
<td><%= link_to 'Destroy', escalation_series, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Escalation series', new_escalation_series_path %>
================================================
FILE: app/views/escalation_series/index.json.jbuilder
================================================
json.array!(@escalation_series) do |escalation_series|
json.extract! escalation_series, :id, :name
json.url escalation_series_url(escalation_series, format: :json)
end
================================================
FILE: app/views/escalation_series/new.html.erb
================================================
<h1>New Escalation Series</h1>
<%= render 'form' %>
<%= link_to 'Back', escalation_series_index_path %>
================================================
FILE: app/views/escalation_series/show.html.erb
================================================
<p>
<strong>Name:</strong>
<%= @escalation_series.name %>
</p>
<table class="table">
<% @escalation_series.escalations.order("escalate_after_sec").each do |escalation| %>
<tr>
<td><%= escalation.escalate_to.name %></td>
<td>escalate after <%= escalation.escalate_after_sec %> sec</td>
</tr>
<% end %>
</table>
<ul>
</ul>
<%= link_to 'Edit', edit_escalation_series_path(@escalation_series) %> |
<%= link_to 'Back', escalation_series_index_path %>
================================================
FILE: app/views/escalation_series/show.json.jbuilder
================================================
json.extract! @escalation_series, :id, :name, :created_at, :updated_at
================================================
FILE: app/views/escalations/_form.html.erb
================================================
<%= form_for(@escalation) do |f| %>
<% if @escalation.errors.any? %>
<div class="alert alert-danger">
<h2><%= pluralize(@escalation.errors.count, "error") %> prohibited this escalation from being saved:</h2>
<ul>
<% @escalation.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :escalate_to_id %>
<%= f.collection_select(:escalate_to_id, User.all, :id, :name, {}, class: 'form-control') %>
</div>
<div class="form-group">
<%= f.label :escalate_after_sec %>
<%= f.number_field :escalate_after_sec, min: 5, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :escalation_series_id %>
<%= f.collection_select(:escalation_series_id, EscalationSeries.all, :id, :name, {}, class: 'form-control') %>
</div>
<%= f.submit(class: 'btn btn-default') %>
<% end %>
================================================
FILE: app/views/escalations/edit.html.erb
================================================
<h1>Editing Escalation</h1>
<%= render 'form' %>
<%= link_to 'Show', @escalation %> |
<%= link_to 'Back', escalations_path %>
================================================
FILE: app/views/escalations/index.html.erb
================================================
<h1>Listing Escalations</h1>
<table class="table">
<thead>
<tr>
<th>Escalation Series</th>
<th>Escalate to</th>
<th>Escalate after sec</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @escalations.each do |escalation| %>
<tr>
<td><%= escalation.escalation_series.name %></td>
<td><%= escalation.escalate_to.name %></td>
<td><%= escalation.escalate_after_sec %></td>
<td><%= link_to 'Show', escalation %></td>
<td><%= link_to 'Edit', edit_escalation_path(escalation) %></td>
<td><%= link_to 'Destroy', escalation, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Escalation', new_escalation_path %>
================================================
FILE: app/views/escalations/index.json.jbuilder
================================================
json.array!(@escalations) do |escalation|
json.extract! escalation, :id, :escalate_to_id, :escalate_after_sec, :escalation_series_id
json.url escalation_url(escalation, format: :json)
end
================================================
FILE: app/views/escalations/new.html.erb
================================================
<h1>New Escalation</h1>
<%= render 'form' %>
<%= link_to 'Back', escalations_path %>
================================================
FILE: app/views/escalations/show.html.erb
================================================
<p>
<strong>Escalation series:</strong>
<%= @escalation.escalation_series.name %>
</p>
<p>
<strong>Escalate to:</strong>
<%= @escalation.escalate_to.name %>
</p>
<p>
<strong>Escalate after sec:</strong>
<%= @escalation.escalate_after_sec %>
</p>
<%= link_to 'Edit', edit_escalation_path(@escalation) %> |
<%= link_to 'Back', escalations_path %>
================================================
FILE: app/views/escalations/show.json.jbuilder
================================================
json.extract! @escalation, :id, :escalate_to_id, :escalate_after_sec, :created_at, :updated_at
================================================
FILE: app/views/home/index.html.erb
================================================
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>
================================================
FILE: app/views/incident_events/twilio.html.erb
================================================
<h1>IncidentEvents#twilio</h1>
<p>Find me in app/views/incident_events/twilio.html.erb</p>
================================================
FILE: app/views/incidents/_form.html.erb
================================================
<%= form_for(@incident) do |f| %>
<% if @incident.errors.any? %>
<div class="alert alert-danger">
<h2><%= pluralize(@incident.errors.count, "error") %> prohibited this incident from being saved:</h2>
<ul>
<% @incident.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :subject %>
<%= f.text_field :subject, required: true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, required: true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :topic_id %>
<%= f.collection_select(:topic_id, Topic.all, :id, :name, {}, class: 'form-control') %>
</div>
<div class="form-group">
<%= f.label :occured_at %>
<%= f.datetime_select :occured_at %>
</div>
<%= f.submit(class: 'btn btn-default') %>
<% end %>
================================================
FILE: app/views/incidents/edit.html.erb
================================================
<h1>Editing Incident</h1>
<%= render 'form' %>
<%= link_to 'Show', @incident %> |
<%= link_to 'Back', incidents_path %>
================================================
FILE: app/views/incidents/index.html.erb
================================================
<h1>Listing Incidents</h1>
<div class="btn-toolbar" role="toolbar" style="margin-bottom: 15px">
<div class="btn-group" role="group">
<%-
{
nil => 'All',
Incident.statuses.values_at(*%w!opened acknowledged!) => 'Opened or Acked',
Incident.statuses.values_at(*%w!opened!) => 'Opened',
Incident.statuses.values_at(*%w!acknowledged!) => 'Acked',
Incident.statuses.values_at(*%w!resolved!) => 'Resolved',
}.each do |statuses, desc| -%>
<a href="<%= "?statuses=#{statuses && statuses.join(',')}" %>" class="btn btn-default">
<%- if statuses == @visible_statuses %>
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
<%- end -%>
<%= desc %>
</a>
<%- end -%>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
Topic
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="?topic=all">
<%- if @visible_topic.nil? -%>
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
<%- end -%>
All
</a></li>
<% Topic.all.each do |topic| %>
<li><a href="?topic=<%= topic.id %>">
<%- if @visible_topic == topic.id -%>
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
<%- end -%>
<%= topic.name %>
</a></li>
<% end %>
</ul>
</div>
</div>
<table class="table">
<thead>
<tr>
<th>Status</th>
<th>Subject</th>
<th>Topic</th>
<th>Occured at</th>
<th colspan="4"></th>
</tr>
</thead>
<tbody>
<% @incidents.each do |incident| %>
<tr>
<td rowspan="<%= incident.comments.present? ? 2 : 1 %>">
<% if incident.opened? %>
<span class="label label-danger">Opened</span>
<% elsif incident.acknowledged? %>
<span class="label label-warning">Acknowledged</span>
<% elsif incident.resolved? %>
<span class="label label-success">Resolved</span>
<% end %>
</td>
<td><%= incident.subject %></td>
<td><%= incident.topic.name %></td>
<td><%= incident.occured_at %></td>
<td><%= link_to 'Show', incident %></td>
<td><%= link_to 'Ack', acknowledge_incident_path(incident, hash: incident.confirmation_hash) %></td>
<td><%= link_to 'Resolve', resolve_incident_path(incident, hash: incident.confirmation_hash) %></td>
<td><%= link_to 'Comment', new_incident_comment_path(incident) %></td>
</tr>
<% if incident.comments.present? %>
<tr>
<td colspan="7">
<% incident.comments.each_with_index do |comment, i| %>
<pre style="font-size: xx-small;"><%= auto_link(comment.comment, :html => { :target => '_blank' }) %><br>(<%= comment.user.name %>)</pre>
<% end %>
</td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
<%= paginate @incidents %>
<br>
<%= link_to 'Ack All', acknowledge_incidents_path, class: "btn btn-default", method: :patch, data: { confirm: "#{@incidents.count} incidents will be marked as acked. Are you sure?" } %>
<%= link_to 'Resolve All', resolve_incidents_path, class: "btn btn-success", method: :patch, data: { confirm: "#{@incidents.count} incidents will be marked as resolved. Are you sure?" } %>
================================================
FILE: app/views/incidents/index.json.jbuilder
================================================
json.array!(@incidents) do |incident|
json.extract! incident, :id, :subject, :description, :topic_id, :occured_at
json.url incident_url(incident, format: :json)
end
================================================
FILE: app/views/incidents/new.html.erb
================================================
<h1>New Incident</h1>
<%= render 'form' %>
<%= link_to 'Back', incidents_path %>
================================================
FILE: app/views/incidents/show.html.erb
================================================
<p>
<strong>Subject:</strong>
<%= @incident.subject %>
</p>
<p>
<strong>Description:</strong>
<pre><%= @incident.description %></pre>
</p>
<p>
<strong>Topic:</strong>
<%= @incident.topic.name %>
</p>
<p>
<strong>Occured at:</strong>
<%= @incident.occured_at %>
</p>
<table class="table">
<tr>
<th>Time</th>
<th>Event</th>
<th>Description</th>
</tr>
<% @incident.events.each do |event| %>
<tr>
<td><%= event.created_at %></td>
<td><%= event.kind %></td>
<td>
<% if event.escalated? %>
to <%= link_to(event.escalated_to.name, event.escalated_to) %>
<% elsif event.notified? %>
notified by <%= link_to('notifier', event.notifier) %>
<% end %>
</td>
</tr>
<% end %>
</table>
<p>
<strong>Comment:</strong>
</p>
<table class="table">
<tr>
<th>Time</th>
<th>Comment</th>
</tr>
<% @incident.comments.each do |comment| %>
<tr>
<td><%= comment.created_at %></td>
<td><%= comment.comment %> (<%= comment.user.name %>)</td>
</tr>
<% end %>
</table>
<%= link_to 'Edit', edit_incident_path(@incident) %> |
<%= link_to 'Destroy', @incident, method: :delete, data: { confirm: 'Are you sure?' } %> |
<%= link_to 'Back', incidents_path %>
================================================
FILE: app/views/incidents/show.json.jbuilder
================================================
json.extract! @incident, :id, :subject, :description, :topic_id, :occured_at, :created_at, :updated_at
================================================
FILE: app/views/layouts/application.html.erb
================================================
<!DOCTYPE html>
<html>
<head>
<title>Waker</title>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<style>
body {
padding-top: 70px;
}
</style>
<%= csrf_meta_tags %>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Waker</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><%= link_to 'Incidents', incidents_path %></li>
<li><%= link_to 'Topics', topics_path %></li>
<li><%= link_to 'Escalation Series', escalation_series_index_path %></li>
<li><%= link_to 'Escalations', escalations_path %></li>
<li><%= link_to 'Users', users_path %></li>
<li><%= link_to 'Notifiers', notifiers_path %></li>
<li><%= link_to 'Notifier Providers', notifier_providers_path %></li>
<li><%= link_to 'Maintenances', maintenances_path %></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<%- if current_user -%>
<p class="navbar-text">Logged in as <%= current_user.name %></p>
<%- end -%>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container">
<% if notice %>
<div class="alert alert-success" role="alert"><%= notice %></div>
<% end %>
<%= yield %>
</div><!-- /.container -->
<!-- Latest compiled and minified JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
</body>
</html>
================================================
FILE: app/views/maintenances/_form.html.erb
================================================
<%= form_for(@maintenance) do |f| %>
<% if @maintenance.errors.any? %>
<div class="alert alert-danger">
<h2><%= pluralize(@maintenance.errors.count, "error") %> prohibited this maintenance from being saved:</h2>
<ul>
<% @maintenance.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :topic_id %><br>
<%= f.collection_select(:topic_id, Topic.all, :id, :name, {}, class: 'form-control') %>
</div>
<div class="form-group">
<%= f.label :filter %><br>
<%= f.text_field(:filter, class: 'form-control', placeholder: 'regexp') %>
</div>
<div class="form-group">
<%= f.label :start_time %><br>
<%= f.datetime_select :start_time, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :end_time %><br>
<%= f.datetime_select :end_time, class: 'form-control' %>
</div>
<%= f.submit(class: 'btn btn-default') %>
<% end %>
================================================
FILE: app/views/maintenances/edit.html.erb
================================================
<h1>Editing Maintenance</h1>
<%= render 'form' %>
<%= link_to 'Show', @maintenance %> |
<%= link_to 'Back', maintenances_path %>
================================================
FILE: app/views/maintenances/index.html.erb
================================================
<h1>Listing Maintenances</h1>
<p>Expired maintanances are not shown</p>
<table class="table">
<thead>
<tr>
<th>Topic</th>
<th>Filter Regexp</th>
<th>Start time</th>
<th>End time</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @maintenances.each do |maintenance| %>
<tr>
<td><%= maintenance.topic.name %></td>
<td><code><%= maintenance.filter %></code></td>
<td><%= maintenance.start_time %></td>
<td><%= maintenance.end_time %></td>
<td><%= link_to 'Show', maintenance %></td>
<td><%= link_to 'Edit', edit_maintenance_path(maintenance) %></td>
<td><%= link_to 'Destroy', maintenance, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Maintenance', new_maintenance_path %>
================================================
FILE: app/views/maintenances/index.json.jbuilder
================================================
json.array!(@maintenances) do |maintenance|
json.extract! maintenance, :id, :topic_id, :start_time, :end_time
json.url maintenance_url(maintenance, format: :json)
end
================================================
FILE: app/views/maintenances/new.html.erb
================================================
<h1>New Maintenance</h1>
<%= render 'form' %>
<%= link_to 'Back', maintenances_path %>
================================================
FILE: app/views/maintenances/show.html.erb
================================================
<p id="notice"><%= notice %></p>
<p>
<strong>Topic:</strong>
<%= @maintenance.topic.name %>
</p>
<p>
<strong>Filter (regexp):</strong>
<code><%= @maintenance.filter %></code>
</p>
<p>
<strong>Start time:</strong>
<%= @maintenance.start_time %>
</p>
<p>
<strong>End time:</strong>
<%= @maintenance.end_time %>
</p>
<%= link_to 'Edit', edit_maintenance_path(@maintenance) %> |
<%= link_to 'Back', maintenances_path %>
================================================
FILE: app/views/maintenances/show.json.jbuilder
================================================
json.extract! @maintenance, :id, :topic_id, :start_time, :end_time, :created_at, :updated_at
================================================
FILE: app/views/notifier_providers/_form.html.erb
================================================
<%= form_for(@notifier_provider) do |f| %>
<% if @notifier_provider.errors.any? %>
<div class="alert alert-danger">
<h2><%= pluralize(@notifier_provider.errors.count, "error") %> prohibited this notifier_provider from being saved:</h2>
<ul>
<% @notifier_provider.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, required: true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :kind %>
<%= f.select :kind, nil, {}, class: 'form-control' do %>
<%= options_for_select(
NotifierProvider.kinds.map do |kind, _|
[kind.camelize, kind, {}]
end, @notifier_provider.kind
) %>
<% end %>
</div>
<div class="form-group">
<%= f.label :settings %>
<%= f.text_area :settings, value: @notifier_provider.settings.to_yaml, class: 'form-control', rows: 8 %>
</div>
<%= f.submit(class: 'btn btn-default') %>
<% end %>
================================================
FILE: app/views/notifier_providers/edit.html.erb
================================================
<h1>Editing Notifier Provider</h1>
<%= render 'form' %>
<%= link_to 'Show', @notifier_provider %> |
<%= link_to 'Back', notifier_providers_path %>
================================================
FILE: app/views/notifier_providers/hipchat/acknowledged.text.erb
================================================
Incident acknowledged: <%= event.incident.subject %> (<a href="<%= Rails.application.routes.url_helpers.resolve_incident_url(event.incident, hash: event.incident.confirmation_hash) %>">Resolve</a>)
================================================
FILE: app/views/notifier_providers/hipchat/escalated.text.erb
================================================
Incident escalated to <%= event.escalated_to.name %>: <%= event.incident.subject %> (<a href="<%= Rails.application.routes.url_helpers.acknowledge_incident_url(event.incident, hash: event.incident.confirmation_hash) %>">Acknowledge</a>) (<a href="<%= Rails.application.routes.url_helpers.resolve_incident_url(event.incident, hash: event.incident.confirmation_hash) %>">Resolve</a>)
================================================
FILE: app/views/notifier_providers/hipchat/opened.text.erb
================================================
New incident opened: <%= event.incident.subject %> (<a href="<%= Rails.application.routes.url_helpers.acknowledge_incident_url(event.incident, hash: event.incident.confirmation_hash) %>">Acknowledge</a>) (<a href="<%= Rails.application.routes.url_helpers.resolve_incident_url(event.incident, hash: event.incident.confirmation_hash) %>">Resolve</a>)
================================================
FILE: app/views/notifier_providers/hipchat/resolved.text.erb
================================================
Incident resolved: <%= event.incident.subject %>
================================================
FILE: app/views/notifier_providers/index.html.erb
================================================
<h1>Listing Notifier Providers</h1>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Kind</th>
<th>Settings</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @notifier_providers.each do |notifier_provider| %>
<tr>
<td><%= notifier_provider.name %></td>
<td><%= notifier_provider.kind %></td>
<td><%= notifier_provider.settings %></td>
<td><%= link_to 'Show', notifier_provider %></td>
<td><%= link_to 'Edit', edit_notifier_provider_path(notifier_provider) %></td>
<td><%= link_to 'Destroy', notifier_provider, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Notifier provider', new_notifier_provider_path %>
================================================
FILE: app/views/notifier_providers/index.json.jbuilder
================================================
json.array!(@notifier_providers) do |notifier_provider|
json.extract! notifier_provider, :id, :name, :kind, :settings
json.url notifier_provider_url(notifier_provider, format: :json)
end
================================================
FILE: app/views/notifier_providers/mailgun/default.html.erb
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>[Waker] <%= event.incident.subject %></title>
</head>
<body>
<%
ack_url = Rails.application.routes.url_helpers.acknowledge_incident_url(event.incident, hash: event.incident.confirmation_hash)
ack_url_json = Rails.application.routes.url_helpers.acknowledge_incident_url(event.incident, hash: event.incident.confirmation_hash, format: :json)
resolve_url = Rails.application.routes.url_helpers.resolve_incident_url(event.incident, hash: event.incident.confirmation_hash)
email_markup = {
"@context" => "http://schema.org",
"@type" => "EmailMessage",
"potentialAction" => {
"@type" => "ConfirmAction",
"name" => "Acknowledge incident",
"handler" => {
"@type" => "HttpActionHandler",
"url" => ack_url_json,
},
},
"description" => "Acknowledge incident: #{event.incident.subject}",
}
%>
<script type="application/ld+json"><%= email_markup.to_json.html_safe %></script>
<h1><%= event.incident.subject %></h1>
<div>
<%
btn_style = 'border-radius: 4px;' \
'text-decoration: none;' \
'display: inline-block;' \
'font-size: 1.3em;' \
'padding: 5px 8px;' \
'margin-right: 12px;' \
%>
<a href="<%= ack_url %>"><div style="<%= btn_style %>; border: 1px solid #ccc; color: black;">Acknowledge</div></a> <a href="<%= resolve_url %>"><div style="<%= btn_style %>; background-color: #5cb85c; color: white;">Resolve</div></a>
</div>
<div style="margin-top: 12px;">
<pre style="font-size: 1.1em; white-space: pre; word-wrap: break-word;"><code>
<%= event.incident.description %>
</code></pre>
</div>
</body>
</body>
================================================
FILE: app/views/notifier_providers/mailgun/default.text.erb
================================================
<%= event.incident.subject %>
====
Actions:
- To ack: <%= Rails.application.routes.url_helpers.acknowledge_incident_url(event.incident, hash: event.incident.confirmation_hash) %>
- To resolve: <%= Rails.application.routes.url_helpers.resolve_incident_url(event.incident, hash: event.incident.confirmation_hash) %>
----
<%= event.incident.description %>
================================================
FILE: app/views/notifier_providers/new.html.erb
================================================
<h1>New Notifier Provider</h1>
<%= render 'form' %>
<%= link_to 'Back', notifier_providers_path %>
================================================
FILE: app/views/notifier_providers/rails_logger/default.text.erb
================================================
Notification: <%= event.kind %>
================================================
FILE: app/views/notifier_providers/show.html.erb
================================================
<p>
<strong>Name:</strong>
<%= @notifier_provider.name %>
</p>
<p>
<strong>Kind:</strong>
<%= @notifier_provider.kind %>
</p>
<p>
<strong>Settings:</strong>
<%= @notifier_provider.settings %>
</p>
<%= link_to 'Edit', edit_notifier_provider_path(@notifier_provider) %> |
<%= link_to 'Back', notifier_providers_path %>
================================================
FILE: app/views/notifier_providers/show.json.jbuilder
================================================
json.extract! @notifier_provider, :id, :name, :kind, :settings, :created_at, :updated_at
================================================
FILE: app/views/notifiers/_form.html.erb
================================================
<%= form_for(@notifier) do |f| %>
<% if @notifier.errors.any? %>
<div class="alert alert-danger">
<h2><%= pluralize(@notifier.errors.count, "error") %> prohibited this notifier from being saved:</h2>
<ul>
<% @notifier.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :user_id %>
<%= f.collection_select(:user_id, User.all, :id, :name, { include_blank: true }, class: 'form-control') %>
</div>
<div class="form-group">
<%= f.label :topic_id %>
<%= f.collection_select(:topic_id, Topic.all, :id, :name, { include_blank: true }, class: 'form-control') %>
</div>
<div class="form-group">
<%= f.label :provider_id %>
<%= f.collection_select(:provider_id, NotifierProvider.all, :id, :name, {}, class: 'form-control') %>
</div>
<div class="form-group">
<%= f.label :settings %>
<%= f.text_area :settings, value: @notifier.settings.to_yaml, class: 'form-control', rows: 8 %>
</div>
<div class="form-group">
<%= f.label :notify_after_sec %>
<%= f.number_field :notify_after_sec, min: 5, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :enabled do %>
<%= f.check_box :enabled %>
Enabled
<% end %>
</div>
<%= f.submit(class: 'btn btn-default') %>
<% end %>
================================================
FILE: app/views/notifiers/edit.html.erb
================================================
<h1>Editing Notifier</h1>
<%= render 'form' %>
<%= link_to 'Show', @notifier %> |
<%= link_to 'Back', notifiers_path %>
================================================
FILE: app/views/notifiers/index.html.erb
================================================
<h1>Listing Notifiers</h1>
<table class="table">
<thead>
<tr>
<th>User</th>
<th>Topic</th>
<th>Provider</th>
<th>Settings</th>
<th>Notify after sec</th>
<th>Enabled</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @notifiers.each do |notifier| %>
<tr>
<td><%= notifier.user && notifier.user.name %></td>
<td><%= notifier.topic && notifier.topic.name %></td>
<td><%= notifier.provider.name %></td>
<td><%= notifier.settings %></td>
<td><%= notifier.notify_after_sec %></td>
<td><%= notifier.enabled %></td>
<td><%= link_to 'Show', notifier %></td>
<td><%= link_to 'Edit', edit_notifier_path(notifier) %></td>
<td><%= link_to 'Destroy', notifier, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Notifier', new_notifier_path %>
================================================
FILE: app/views/notifiers/index.json.jbuilder
================================================
json.array!(@notifiers) do |notifier|
json.extract! notifier, :id, :settings, :provider_id, :provider, :topic_id, :user_id, :notify_after_sec, :created_at, :updated_at
json.url notifier_url(notifier, format: :json)
end
================================================
FILE: app/views/notifiers/new.html.erb
================================================
<h1>New Notifier</h1>
<%= render 'form' %>
<%= link_to 'Back', notifiers_path %>
================================================
FILE: app/views/notifiers/show.html.erb
================================================
<p>
<strong>Provider:</strong>
<%= @notifier.provider.name %>
</p>
<p>
<strong>User:</strong>
<%= @notifier.user && @notifier.user.name %>
</p>
<p>
<strong>Topic:</strong>
<%= @notifier.topic && @notifier.topic.name %>
</p>
<p>
<strong>Settings:</strong>
<%= @notifier.settings %>
</p>
<p>
<strong>Notify after sec:</strong>
<%= @notifier.notify_after_sec %>
</p>
<p>
<strong>Enabled:</strong>
<%= @notifier.enabled %>
</p>
<%= link_to 'Edit', edit_notifier_path(@notifier) %> |
<%= link_to 'Back', notifiers_path %>
================================================
FILE: app/views/notifiers/show.json.jbuilder
================================================
json.extract! @notifier, :id, :settings, :provider_id, :provider, :topic_id, :user_id, :notify_after_sec, :created_at, :updated_at
================================================
FILE: app/views/sessions/create.html.erb
================================================
<h1>Sessions#create</h1>
<p>Find me in app/views/sessions/create.html.erb</p>
================================================
FILE: app/views/slack/interactive.html.erb
================================================
<h1>Slack#interactive</h1>
<p>Find me in app/views/slack/interactive.html.erb</p>
================================================
FILE: app/views/topics/_form.html.erb
================================================
<%= form_for(@topic) do |f| %>
<% if @topic.errors.any? %>
<div class="alert alert-danger">
<h2><%= pluralize(@topic.errors.count, "error") %> prohibited this topic from being saved:</h2>
<ul>
<% @topic.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, required: true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :kind %>
<%= f.select :kind, nil, {}, class: 'form-control' do %>
<% Topic.kinds.each do |kind, _| %>
<%= content_tag(:option, kind.to_s.split('_').map {|s| s.capitalize }.join(' '), value: kind) %>
<% end %>
<% end %>
</div>
<div class="form-group">
<%= f.label :escalation_series_id %>
<%= f.collection_select(:escalation_series_id, EscalationSeries.all, :id, :name, {}, class: 'form-control') %>
</div>
<div class="checkbox">
<%= f.label :enabled do %>
<%= f.check_box :enabled %>
Enabled
<% end %>
</div>
<%= f.submit(class: 'btn btn-default') %>
<% end %>
================================================
FILE: app/views/topics/edit.html.erb
================================================
<h1>Editing Topic</h1>
<%= render 'form' %>
<%= link_to 'Show', @topic %> |
<%= link_to 'Back', topics_path %>
================================================
FILE: app/views/topics/index.html.erb
================================================
<h1>Listing Topics</h1>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Kind</th>
<th>Escalation Series</th>
<th>Enabled</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @topics.each do |topic| %>
<tr>
<td><%= topic.name %></td>
<td><%= topic.kind %></td>
<td><%= topic.escalation_series.name %></td>
<td><%= topic.enabled ? 'Yes' : 'No' %></td>
<td><%= link_to 'Show', topic %></td>
<td><%= link_to 'Edit', edit_topic_path(topic) %></td>
<td><%= link_to 'Destroy', topic, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Topic', new_topic_path %>
================================================
FILE: app/views/topics/index.json.jbuilder
================================================
json.array!(@topics) do |topic|
json.extract! topic, :id, :name, :type
json.url topic_url(topic, format: :json)
end
================================================
FILE: app/views/topics/new.html.erb
================================================
<h1>New Topic</h1>
<%= render 'form' %>
<%= link_to 'Back', topics_path %>
================================================
FILE: app/views/topics/show.html.erb
================================================
<p>
<strong>Name:</strong>
<%= @topic.name %>
</p>
<p>
<strong>Kind:</strong>
<%= @topic.kind %>
</p>
<p>
<strong>Escalation Series:</strong>
<%= @topic.escalation_series.name %>
</p>
<p>
<strong>Enabled:</strong>
<%= @topic.enabled ? 'Yes' : 'No' %>
</p>
<p>
<strong>Mailgun Endpoint:</strong>
<pre><%= mailgun_topic_url(@topic, format: :json) %></pre>
</p>
<p>
<strong>Mackerel Endpoint:</strong>
<pre><%= mackerel_topic_url(@topic, format: :json) %></pre>
</p>
<p>
<strong>AlertManagerEndpoint:</strong>
<pre><%= alertmanager_topic_url(@topic, format: :json) %></pre>
</p>
<p>
<strong>SlackEndpoint:</strong>
<pre><%= slack_topic_url(@topic, format: :json) %></pre>
</p>
<%= link_to 'Edit', edit_topic_path(@topic) %> |
<%= link_to 'Back', topics_path %>
================================================
FILE: app/views/topics/show.json.jbuilder
================================================
json.extract! @topic, :id, :name, :type, :created_at, :updated_at
================================================
FILE: app/views/users/_form.html.erb
================================================
<%= form_for(@user) do |f| %>
<% if @user.errors.any? %>
<div class="alert alert-danger">
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% @user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, required: true, class: 'form-control' %>
</div>
<%= f.submit(class: 'btn btn-default') %>
<% end %>
================================================
FILE: app/views/users/edit.html.erb
================================================
<h1>Editing User</h1>
<%= render 'form' %>
<%= link_to 'Show', @user %> |
<%= link_to 'Back', users_path %>
================================================
FILE: app/views/users/index.html.erb
================================================
<h1>Listing Users</h1>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr>
<td>
<%= user.name %>
</td>
<td>
<%- unless user.active -%>
<span class="label label-default">Deactivated</span>
<%- end -%>
</td>
<td><%= link_to 'Show', user %></td>
<td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
<%- if user.active -%>
<td><%= link_to 'Deactivate', deactivation_user_path(user), method: :patch, data: { confirm: 'Are you sure?' } %></td>
<%- else -%>
<td><%= link_to 'Activate', activation_user_path(user), method: :patch, data: { confirm: 'Are you sure?' } %></td>
<%- end -%>
</tr>
<% end %>
</tbody>
</table>
<br>
================================================
FILE: app/views/users/index.json.jbuilder
================================================
json.array!(@users) do |user|
json.extract! user, :id, :name
json.url user_url(user, format: :json)
end
================================================
FILE: app/views/users/new.html.erb
================================================
<h1>New User</h1>
<%= render 'form' %>
<%= link_to 'Back', users_path %>
================================================
FILE: app/views/users/show.html.erb
================================================
<p>
<strong>Name:</strong>
<%= @user.name %>
</p>
<p>
<strong>Provider:</strong>
<%= @user.provider %>
</p>
<p>
<strong>UID:</strong>
<%= @user.uid %>
</p>
<%= link_to 'Back', users_path %>
================================================
FILE: app/views/users/show.json.jbuilder
================================================
json.extract! @user, :id, :name, :created_at, :updated_at
================================================
FILE: bin/bundle
================================================
#!/usr/bin/env ruby
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
load Gem.bin_path('bundler', 'bundle')
================================================
FILE: bin/rails
================================================
#!/usr/bin/env ruby
begin
load File.expand_path("../spring", __FILE__)
rescue LoadError
end
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'
================================================
FILE: bin/rake
================================================
#!/usr/bin/env ruby
begin
load File.expand_path("../spring", __FILE__)
rescue LoadError
end
require_relative '../config/boot'
require 'rake'
Rake.application.run
================================================
FILE: bin/setup
================================================
#!/usr/bin/env ruby
require 'pathname'
# path to your application root.
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
Dir.chdir APP_ROOT do
# This script is a starting point to setup your application.
# Add necessary setup steps to this file:
puts "== Installing dependencies =="
system "gem install bundler --conservative"
system "bundle check || bundle install"
# puts "\n== Copying sample files =="
# unless File.exist?("config/database.yml")
# system "cp config/database.yml.sample config/database.yml"
# end
puts "\n== Preparing database =="
system "bin/rake db:setup"
puts "\n== Removing old logs and tempfiles =="
system "rm -f log/*"
system "rm -rf tmp/cache"
puts "\n== Restarting application server =="
system "touch tmp/restart.txt"
end
================================================
FILE: bin/spring
================================================
#!/usr/bin/env ruby
# This file loads spring without using Bundler, in order to be fast
# It gets overwritten when you run the `spring binstub` command
unless defined?(Spring)
require "rubygems"
require "bundler"
if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)
ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR)
ENV["GEM_HOME"] = ""
Gem.paths = ENV
gem "spring", match[1]
require "spring/binstub"
end
end
================================================
FILE: config/application.rb
================================================
require File.expand_path('../boot', __FILE__)
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "sprockets/railtie"
# require "rails/test_unit/railtie"
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Waker
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
if time_zone = ENV['TIME_ZONE']
config.time_zone = time_zone
end
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
# Do not swallow errors in after_commit/after_rollback callbacks.
config.middleware.use Rack::Health
config.middleware.use OmniAuth::Builder do
config = {}
config[:hd] = ENV['GOOGLE_DOMAIN'] if ENV['GOOGLE_DOMAIN']
provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"],
config.merge(scope: 'userinfo.profile,userinfo.email,calendar',
name: 'google_oauth2_with_calendar',
access_type: 'offline', approval_prompt: 'force', prompt: 'consent')
end
end
end
================================================
FILE: config/boot.rb
================================================
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
================================================
FILE: config/database.yml
================================================
production:
adapter: mysql2
database: waker
encoding: utf8mb4
username : <%= ENV['MYSQL_USER'] || 'root' %>
password: <%= ENV['MYSQL_PASSWORD'] %>
host: <%= ENV['MYSQL_HOST'] || 'localhost' %>
development:
adapter: mysql2
database: waker_development
encoding: utf8mb4
username : <%= ENV['MYSQL_USER'] || 'root' %>
password: <%= ENV['MYSQL_PASSWORD'] %>
host: <%= ENV['MYSQL_HOST'] || 'localhost' %>
test:
adapter: mysql2
database: waker_test
encoding: utf8mb4
username : <%= ENV['MYSQL_USER'] || 'root' %>
password: <%= ENV['MYSQL_PASSWORD'] %>
host: <%= ENV['MYSQL_HOST'] || 'localhost' %>
================================================
FILE: config/environment.rb
================================================
# Load the Rails application.
require File.expand_path('../application', __FILE__)
# Initialize the Rails application.
Rails.application.initialize!
================================================
FILE: config/environments/development.rb
================================================
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
# yet still be able to expire them through the digest params.
config.assets.digest = true
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
config.assets.raise_runtime_errors = true
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
Rails.application.routes.default_url_options[:host] = 'localhost:3000'
================================================
FILE: config/environments/production.rb
================================================
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Enable Rack::Cache to put a simple HTTP cache in front of your application
# Add `rack-cache` to your Gemfile before enabling this.
# For large-scale production use, consider using a caching reverse proxy like
# NGINX, varnish or squid.
# config.action_dispatch.rack_cache = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
# yet still be able to expire them through the digest params.
config.assets.digest = true
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :debug
# Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
# Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
if log_dir = ENV['LOG_DIR']
config.logger = ::Logger.new(File.expand_path('production.log', log_dir))
end
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = 'http://assets.example.com'
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
end
================================================
FILE: config/environments/test.rb
================================================
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Configure static file server for tests with Cache-Control for performance.
config.serve_static_files = true
config.static_cache_control = 'public, max-age=3600'
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Randomize the order test cases are executed.
config.active_support.test_order = :random
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
================================================
FILE: config/initializers/assets.rb
================================================
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'
# Add additional assets to the asset load path
# Rails.application.config.assets.paths << Emoji.images_path
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# Rails.application.config.assets.precompile += %w( search.js )
================================================
FILE: config/initializers/backtrace_silencers.rb
================================================
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
================================================
FILE: config/initializers/cookies_serializer.rb
================================================
# Be sure to restart your server when you modify this file.
Rails.application.config.action_dispatch.cookies_serializer = :json
================================================
FILE: config/initializers/field_with_errors.rb
================================================
Rails.application.configure do
config.action_view.field_error_proc = lambda do |html_tag, instance|
%Q{<div class="has-error">#{html_tag}</div>}.html_safe
end
end
================================================
FILE: config/initializers/filter_parameter_logging.rb
================================================
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:password]
================================================
FILE: config/initializers/inflections.rb
================================================
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym 'RESTful'
# end
================================================
FILE: config/initializers/mime_types.rb
================================================
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
================================================
FILE: config/initializers/omniauth.rb
================================================
OmniAuth.config.logger = Rails.logger
================================================
FILE: config/initializers/session_store.rb
================================================
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cookie_store, key: '_waker_session'
================================================
FILE: config/initializers/sidekiq.rb
================================================
namespace = ENV['REDIS_NAMESPACE'] || "waker-#{Rails.env}"
host = ENV['REDIS_HOST'] || 'localhost'
port = ENV['REDIS_PORT'] || 6379
Sidekiq.configure_server do |config|
config.poll_interval = 5
config.redis = {url: "redis://#{host}:#{port}", namespace: namespace}
end
Sidekiq.configure_client do |config|
config.redis = {url: "redis://#{host}:#{port}", namespace: namespace}
end
Sidekiq::Logging.logger = Rails.logger
================================================
FILE: config/initializers/url_options.rb
================================================
if default_host = ENV['DEFAULT_HOST']
Rails.application.routes.default_url_options[:host] = default_host
end
if default_protocol = ENV['DEFAULT_PROTOCOL']
Rails.application.routes.default_url_options[:protocol] = default_protocol
end
================================================
FILE: config/initializers/wrap_parameters.rb
================================================
# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
end
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
# self.include_root_in_json = true
# end
================================================
FILE: config/locales/en.yml
================================================
# Files in the config/locales directory are used for internationalization
# and are automatically loaded by Rails. If you want to use locales other
# than English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t 'hello'
#
# In views, this is aliased to just `t`:
#
# <%= t('hello') %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# To learn more, please read the Rails Internationalization guide
# available at http://guides.rubyonrails.org/i18n.html.
en:
hello: "Hello world"
================================================
FILE: config/routes.rb
================================================
Rails.application.routes.draw do
post 'slack/interactive'
get '/auth/:provider/callback', to: 'sessions#create'
resources :incident_events, only: [] do
member do
post 'twilio'
get 'twilio'
end
end
resources :incidents do
member do
get 'acknowledge'
get 'resolve'
end
collection do
patch 'acknowledge', to: "incidents#bulk_acknowledge"
patch 'resolve', to: "incidents#bulk_resolve"
end
resources :comments
end
resources :escalation_series do
member do
get 'update_escalations'
end
end
resources :escalations
resources :shifts
resources :notifiers
resources :notifier_providers
resources :maintenances
resources :users, only: [:index, :show, :destroy] do
member do
patch 'activation'
patch 'deactivation'
end
end
resources :topics do
member do
post 'mailgun'
post 'mackerel'
post 'alertmanager'
post 'slack'
end
end
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'
root 'home#index'
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
# Example resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end
# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable
# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
end
================================================
FILE: config/secrets.yml
================================================
# Be sure to restart your server when you modify this file.
# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.
# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.
development:
secret_key_base: d50e30eb49152fcfff420c795f7d0f559934a6497808d4c8a34e83f1ec4807f7c36b4ca47af41bdb4d5a757e9a756f4425c748defb4054f89e63cea1788eb2d3
test:
secret_key_base: 5206b6e3c7cd04a83e4743c3f0d631e025f196223d8d13742f0bd71c6e1c5d0b0a443398a4536f503d8399c8c7e58e20dadc3553e64bcdb1f4cb7dbc95a7fe0c
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
================================================
FILE: config.ru
================================================
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run Rails.application
================================================
FILE: db/migrate/20150120134616_create_topics.rb
================================================
class CreateTopics < ActiveRecord::Migration
def change
create_table :topics do |t|
t.string :name
t.integer :type
t.timestamps null: false
end
end
end
================================================
FILE: db/migrate/20150120134747_create_users.rb
================================================
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.timestamps null: false
end
end
end
================================================
FILE: db/migrate/20150120134905_create_notifiers.rb
================================================
class CreateNotifiers < ActiveRecord::Migration
def change
create_table :notifiers do |t|
t.integer :type
t.text :settings
t.integer :notify_after_sec
t.timestamps null: false
end
end
end
================================================
FILE: db/migrate/20150120135017_create_shifts.rb
================================================
class CreateShifts < ActiveRecord::Migration
def change
create_table :shifts do |t|
t.references :user, index: true
t.timestamps null: false
end
add_foreign_key :shifts, :users
end
end
================================================
FILE: db/migrate/20150120135123_create_escalations.rb
================================================
class CreateEscalations < ActiveRecord::Migration
def change
create_table :escalations do |t|
t.references :escalate_to, index: true
t.integer :escalate_after_sec
t.timestamps null: false
end
add_foreign_key :escalations, :users, column: 'escalate_to_id'
end
end
================================================
FILE: db/migrate/20150120135244_create_escalation_series.rb
================================================
class CreateEscalationSeries < ActiveRecord::Migration
def change
create_table :escalation_series do |t|
t.string :name
t.timestamps null: false
end
end
end
================================================
FILE: db/migrate/20150120135351_add_escalation_series_to_escalation.rb
================================================
class AddEscalationSeriesToEscalation < ActiveRecord::Migration
def change
add_reference :escalations, :escalation_series, index: true
add_foreign_key :escalations, :escalation_series
end
end
================================================
FILE: db/migrate/20150120141627_rename_type_with_kind_of_topic.rb
================================================
class RenameTypeWithKindOfTopic < ActiveRecord::Migration
def change
rename_column :topics, :type, :kind
end
end
================================================
FILE: db/migrate/20150120142452_create_incidents.rb
================================================
class CreateIncidents < ActiveRecord::Migration
def change
create_table :incidents do |t|
t.string :subject
t.text :description
t.references :topic, index: true
t.datetime :occured_at
t.timestamps null: false
end
add_foreign_key :incidents, :topics
end
end
================================================
FILE: db/migrate/20150120151642_add_escalation_series_to_topic.rb
================================================
class AddEscalationSeriesToTopic < ActiveRecord::Migration
def change
add_reference :topics, :escalation_series, index: true
add_foreign_key :topics, :escalation_series
end
end
================================================
FILE: db/migrate/20150120154438_add_name_to_shift.rb
================================================
class AddNameToShift < ActiveRecord::Migration
def change
add_column :shifts, :name, :string
end
end
================================================
FILE: db/migrate/20150121150043_add_user_to_notifier.rb
================================================
class AddUserToNotifier < ActiveRecord::Migration
def change
add_reference :notifiers, :user, index: true
add_foreign_key :notifiers, :users
end
end
================================================
FILE: db/migrate/20150121150857_rename_type_with_kind_of_notifier.rb
================================================
class RenameTypeWithKindOfNotifier < ActiveRecord::Migration
def change
rename_column :notifiers, :type, :kind
end
end
================================================
FILE: db/migrate/20150123132415_remove_shift.rb
================================================
class RemoveShift < ActiveRecord::Migration
def change
drop_table :shifts
end
end
================================================
FILE: db/migrate/20150123150518_add_status_to_incident.rb
================================================
class AddStatusToIncident < ActiveRecord::Migration
def change
add_column :incidents, :status, :integer
end
end
================================================
FILE: db/migrate/20150123150947_create_incident_events.rb
================================================
class CreateIncidentEvents < ActiveRecord::Migration
def change
create_table :incident_events do |t|
t.references :incident, index: true
t.integer :kind
t.text :text
t.references :user_by, index: true
t.timestamps null: false
end
add_foreign_key :incident_events, :incidents
add_foreign_key :incident_events, :users, column: 'user_by_id'
end
end
================================================
FILE: db/migrate/20150125050529_create_notifier_providers.rb
================================================
class CreateNotifierProviders < ActiveRecord::Migration
def change
create_table :notifier_providers do |t|
t.string :name
t.integer :kind
t.text :settings
t.timestamps null: false
end
end
end
================================================
FILE: db/migrate/20150125050556_add_provider_to_notifier.rb
================================================
class AddProviderToNotifier < ActiveRecord::Migration
def change
add_reference :notifiers, :provider, index: true
add_foreign_key :notifiers, :notifier_providers, column: 'provider_id'
end
end
================================================
FILE: db/migrate/20150125101901_remove_kind_from_notifier.rb
================================================
class RemoveKindFromNotifier < ActiveRecord::Migration
def change
remove_column :notifiers, :kind
end
end
================================================
FILE: db/migrate/20150127142530_remove_user_by_from_incident_event.rb
================================================
class RemoveUserByFromIncidentEvent < ActiveRecord::Migration
def change
remove_foreign_key :incident_events, column: "user_by_id"
remove_index :incident_events, :user_by_id
remove_column :incident_events, :user_by_id
end
end
================================================
FILE: db/migrate/20150127152127_add_info_to_incident_event.rb
================================================
class AddInfoToIncidentEvent < ActiveRecord::Migration
def change
add_column :incident_events, :info, :text
end
end
================================================
FILE: db/migrate/20150128064248_add_email_to_user.rb
================================================
class AddEmailToUser < ActiveRecord::Migration
def change
add_column :users, :email, :string
end
end
================================================
FILE: db/migrate/20150131120557_add_enable_to_topic.rb
================================================
class AddEnableToTopic < ActiveRecord::Migration
def change
add_column :topics, :enable, :boolean
end
end
================================================
FILE: db/migrate/20150131121143_set_default_of_enable_of_topic_true.rb
================================================
class SetDefaultOfEnableOfTopicTrue < ActiveRecord::Migration
def change
change_column :topics, :enable, :boolean, default: true
end
end
================================================
FILE: db/migrate/20150131122151_rename_enable_with_enabled_of_topic.rb
================================================
class RenameEnableWithEnabledOfTopic < ActiveRecord::Migration
def change
rename_column :topics, :enable, :enabled
end
end
================================================
FILE: db/migrate/20150201033946_add_login_token_to_user.rb
================================================
class AddLoginTokenToUser < ActiveRecord::Migration
def change
add_column :users, :login_token, :string
end
end
================================================
FILE: db/migrate/20150202144538_add_token_to_user.rb
================================================
class AddTokenToUser < ActiveRecord::Migration
def change
add_column :users, :token, :string
end
end
================================================
FILE: db/migrate/20150202151740_add_refresh_token_to_user.rb
================================================
class AddRefreshTokenToUser < ActiveRecord::Migration
def change
add_column :users, :refresh_token, :string
end
end
================================================
FILE: db/migrate/20150202152015_add_settings_to_escalation_series.rb
================================================
class AddSettingsToEscalationSeries < ActiveRecord::Migration
def change
add_column :escalation_series, :escalation_series, :text
end
end
================================================
FILE: db/migrate/20150202155726_add_token_expires_at_to_user.rb
================================================
class AddTokenExpiresAtToUser < ActiveRecord::Migration
def change
add_column :users, :token_expires_at, :datetime
end
end
================================================
FILE: db/migrate/20150203010332_remove_escalation_series_from_escalation_series.rb
================================================
class RemoveEscalationSeriesFromEscalationSeries < ActiveRecord::Migration
def change
remove_column :escalation_series, :escalation_series
end
end
================================================
FILE: db/migrate/20150203010417_add_settings_to_escalation_series_again.rb
================================================
class AddSettingsToEscalationSeriesAgain < ActiveRecord::Migration
def change
add_column :escalation_series, :settings, :text
end
end
================================================
FILE: db/migrate/20150207164010_add_topic_to_notifier.rb
================================================
class AddTopicToNotifier < ActiveRecord::Migration
def change
add_reference :notifiers, :topic, index: true
add_foreign_key :notifiers, :topics
end
end
================================================
FILE: db/migrate/20150218071007_add_enable_to_notifier.rb
================================================
class AddEnableToNotifier < ActiveRecord::Migration
def change
add_column :notifiers, :enabled, :boolean, default: true
end
end
================================================
FILE: db/migrate/20151117011141_add_active_to_user.rb
================================================
class AddActiveToUser < ActiveRecord::Migration
def change
add_column :users, :active, :boolean, default: false
end
end
================================================
FILE: db/migrate/20151117013824_add_provider_and_uid_to_user.rb
================================================
class AddProviderAndUidToUser < ActiveRecord::Migration
def change
add_column :users, :provider, :string
add_column :users, :uid, :string
end
end
================================================
FILE: db/migrate/20151118061253_add_credentials_to_user.rb
================================================
class AddCredentialsToUser < ActiveRecord::Migration
def change
add_column :users, :credentials, :text
end
end
================================================
FILE: db/migrate/20151118061938_delete_token_from_user.rb
================================================
class DeleteTokenFromUser < ActiveRecord::Migration
def change
User.all.each do |u|
if u.token
u.update!(credentials: {
token: u.token,
refresh_token: u.refresh_token,
expires_at: u.token_expires_at.to_i,
expires: true,
})
end
end
remove_column :users, :token
remove_column :users, :token_expires_at
remove_column :users, :refresh_token
end
end
================================================
FILE: db/migrate/20160210010310_create_maintenances.rb
================================================
class CreateMaintenances < ActiveRecord::Migration
def change
create_table :maintenances do |t|
t.references :topic, index: true
t.datetime :start_time
t.datetime :end_time
t.timestamps null: false
end
add_foreign_key :maintenances, :topics
end
end
================================================
FILE: db/migrate/20160907123728_create_comments.rb
================================================
class CreateComments < ActiveRecord::Migration
def change
create_table "comments", force: :cascade do |t|
t.integer "incident_id", limit: 4, null: false
t.integer "user_id", limit: 4, null: false
t.text "comment", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
end
================================================
FILE: db/migrate/20160914063913_add_comment_index.rb
================================================
class AddCommentIndex < ActiveRecord::Migration
def change
add_index :comments, :incident_id
end
end
================================================
FILE: db/migrate/20161207045554_add_filter_to_maintenance.rb
================================================
class AddFilterToMaintenance < ActiveRecord::Migration
def change
add_column :maintenances, :filter, :string
end
end
================================================
FILE: db/schema.rb
================================================
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20161207045554) do
create_table "comments", force: :cascade do |t|
t.integer "incident_id", limit: 4, null: false
t.integer "user_id", limit: 4, null: false
t.text "comment", limit: 65535, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "comments", ["incident_id"], name: "index_comments_on_incident_id", using: :btree
create_table "escalation_series", force: :cascade do |t|
t.string "name", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "settings", limit: 65535
end
create_table "escalations", force: :cascade do |t|
t.bigint "escalate_to_id", limit: 4
t.integer "escalate_after_sec", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "escalation_series_id", limit: 4
end
add_index "escalations", ["escalate_to_id"], name: "index_escalations_on_escalate_to_id", using: :btree
add_index "escalations", ["escalation_series_id"], name: "index_escalations_on_escalation_series_id", using: :btree
create_table "incident_events", force: :cascade do |t|
t.bigint "incident_id", limit: 4
t.integer "kind", limit: 4
t.text "text", limit: 65535
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "info", limit: 65535
end
add_index "incident_events", ["incident_id"], name: "index_incident_events_on_incident_id", using: :btree
create_table "incidents", force: :cascade do |t|
t.string "subject", limit: 255
t.text "description", limit: 65535
t.bigint "topic_id", limit: 4
t.datetime "occured_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "status", limit: 4
end
add_index "incidents", ["topic_id"], name: "index_incidents_on_topic_id", using: :btree
create_table "maintenances", force: :cascade do |t|
t.bigint "topic_id", limit: 4
t.datetime "start_time"
t.datetime "end_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "filter", limit: 255
end
add_index "maintenances", ["topic_id"], name: "index_maintenances_on_topic_id", using: :btree
create_table "notifier_providers", force: :cascade do |t|
t.string "name", limit: 255
t.integer "kind", limit: 4
t.text "settings", limit: 65535
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "notifiers", force: :cascade do |t|
t.text "settings", limit: 65535
t.integer "notify_after_sec", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "user_id", limit: 4
t.bigint "provider_id", limit: 4
t.bigint "topic_id", limit: 4
t.boolean "enabled", default: true
end
add_index "notifiers", ["provider_id"], name: "index_notifiers_on_provider_id", using: :btree
add_index "notifiers", ["topic_id"], name: "index_notifiers_on_topic_id", using: :btree
add_index "notifiers", ["user_id"], name: "index_notifiers_on_user_id", using: :btree
create_table "topics", force: :cascade do |t|
t.string "name", limit: 255
t.integer "kind", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "escalation_series_id", limit: 4
t.boolean "enabled", default: true
end
add_index "topics", ["escalation_series_id"], name: "index_topics_on_escalation_series_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "name", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", limit: 255
t.string "login_token", limit: 255
t.boolean "active", default: false
t.string "provider", limit: 255
t.string "uid", limit: 255
t.text "credentials", limit: 65535
end
add_foreign_key "escalations", "escalation_series"
add_foreign_key "escalations", "users", column: "escalate_to_id"
add_foreign_key "incident_events", "incidents"
add_foreign_key "incidents", "topics"
add_foreign_key "maintenances", "topics"
add_foreign_key "notifiers", "notifier_providers", column: "provider_id"
add_foreign_key "notifiers", "topics"
add_foreign_key "notifiers", "users"
add_foreign_key "topics", "escalation_series"
end
================================================
FILE: db/seeds.rb
================================================
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first)
================================================
FILE: docker/puma.rb
================================================
require 'fileutils'
listen_unix = ENV['LISTEN_UNIX']
if listen_unix
bind "unix://#{listen_unix}"
end
environment ENV['RAILS_ENV']
port = ENV['PORT'] || 8080
bind "tcp://0.0.0.0:#{port}"
================================================
FILE: docker-compose.yml
================================================
version: '3'
services:
app:
build: .
ports:
- 5000:5000
environment:
DATABASE_URL: 'mysql2://database/waker_development?encoding=utf8mb4&collation=utf8mb4_unicode_ci'
REDIS_HOST: cache
depends_on:
- database
- cache
database:
image: mysql:5
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
MYSQL_DATABASE: waker_development
cache:
image: redis
================================================
FILE: lib/assets/.keep
================================================
================================================
FILE: lib/tasks/.keep
================================================
================================================
FILE: log/.keep
================================================
================================================
FILE: public/404.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>The page you were looking for doesn't exist (404)</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
body {
background-color: #EFEFEF;
color: #2E2F30;
text-align: center;
font-family: arial, sans-serif;
margin: 0;
}
div.dialog {
width: 95%;
max-width: 33em;
margin: 4em auto 0;
}
div.dialog > div {
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #BBB;
border-top: #B00100 solid 4px;
border-top-left-radius: 9px;
border-top-right-radius: 9px;
background-color: white;
padding: 7px 12% 0;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
h1 {
font-size: 100%;
color: #730E15;
line-height: 1.5em;
}
div.dialog > p {
margin: 0 0 1em;
padding: 1em;
background-color: #F7F7F7;
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #999;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top-color: #DADADA;
color: #666;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
</style>
</head>
<body>
<!-- This file lives in public/404.html -->
<div class="dialog">
<div>
<h1>The page you were looking for doesn't exist.</h1>
<p>You may have mistyped the address or the page may have moved.</p>
</div>
<p>If you are the application owner check the logs for more information.</p>
</div>
</body>
</html>
================================================
FILE: public/422.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>The change you wanted was rejected (422)</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
body {
background-color: #EFEFEF;
color: #2E2F30;
text-align: center;
font-family: arial, sans-serif;
margin: 0;
}
div.dialog {
width: 95%;
max-width: 33em;
margin: 4em auto 0;
}
div.dialog > div {
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #BBB;
border-top: #B00100 solid 4px;
border-top-left-radius: 9px;
border-top-right-radius: 9px;
background-color: white;
padding: 7px 12% 0;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
h1 {
font-size: 100%;
color: #730E15;
line-height: 1.5em;
}
div.dialog > p {
margin: 0 0 1em;
padding: 1em;
background-color: #F7F7F7;
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #999;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top-color: #DADADA;
color: #666;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
</style>
</head>
<body>
<!-- This file lives in public/422.html -->
<div class="dialog">
<div>
<h1>The change you wanted was rejected.</h1>
<p>Maybe you tried to change something you didn't have access to.</p>
</div>
<p>If you are the application owner check the logs for more information.</p>
</div>
</body>
</html>
================================================
FILE: public/500.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>We're sorry, but something went wrong (500)</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
body {
background-color: #EFEFEF;
color: #2E2F30;
text-align: center;
font-family: arial, sans-serif;
margin: 0;
}
div.dialog {
width: 95%;
max-width: 33em;
margin: 4em auto 0;
}
div.dialog > div {
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #BBB;
border-top: #B00100 solid 4px;
border-top-left-radius: 9px;
border-top-right-radius: 9px;
background-color: white;
padding: 7px 12% 0;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
h1 {
font-size: 100%;
color: #730E15;
line-height: 1.5em;
}
div.dialog > p {
margin: 0 0 1em;
padding: 1em;
background-color: #F7F7F7;
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #999;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top-color: #DADADA;
color: #666;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
</style>
</head>
<body>
<!-- This file lives in public/500.html -->
<div class="dialog">
<div>
<h1>We're sorry, but something went wrong.</h1>
</div>
<p>If you are the application owner check the logs for more information.</p>
</div>
</body>
</html>
================================================
FILE: public/robots.txt
================================================
# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
#
# To ban all spiders from the entire site uncomment the next two lines:
User-agent: *
Disallow: /
================================================
FILE: script/update-escalations-from-google-calendar
================================================
#!/usr/bin/env ruby
require 'optparse'
require 'json'
require 'faraday'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/file_storage'
require 'google/api_client/auth/installed_app'
class Configuration < Struct.new(:client_secret_file, :credential_store_file, :calendar_name, :delimiter, :url, :escalation_series, :login_token)
def self.from_command_line_options
self.new.tap do |config|
opt = OptionParser.new
opt.on('--client-secret-file VAL') {|v| config.client_secret_file = v }
opt.on('--credential-store-file VAL') {|v| config.credential_store_file = v }
opt.on('--calendar-name VAL') {|v| config.calendar_name = v }
opt.on('--delimiter VAL') {|v| config.delimiter = v }
opt.on('--url VAL') {|v| config.url = v }
opt.on('--escalation-series VAL') {|v| config.escalation_series = v }
opt.on('--login-token VAL') {|v| config.login_token = v }
opt.parse!(ARGV)
config.validate!
end
end
def validate!
members.each do |member|
unless self[member]
raise "#{member} is required."
end
end
end
end
class WakerClient
InvalidResponseError = Class.new(StandardError)
def initialize(url:, token:)
@url = url
@token = token
end
def users
get('/users.json')
end
def escalation_series
get('/escalation_series.json')
end
def escalations
get('/escalations.json')
end
def update_escalation(escalation, escalate_to: nil)
params = {}
params['escalation[escalate_to_id]'] = escalate_to.id if escalate_to
update("/escalations/#{escalation.id}.json", params)
end
private
def conn
@conn ||= Faraday.new(url: @url) do |faraday|
faraday.request :url_encoded
faraday.response :logger if ENV['DEBUG']
faraday.adapter Faraday.default_adapter
end
end
def get(path)
res = conn.get do |req|
req.url path
req.headers['X-Login-Token'] = @token
end
parse_response(res)
end
def update(path, params = {})
res = conn.put do |req|
req.url path
req.params = params
req.headers['X-Login-Token'] = @token
end
parse_response(res)
end
def parse_response(res)
unless 200 <= res.status && res.status < 300
raise InvalidResponseError, "status #{res.status}\nbody: #{res.body}"
end
body = JSON.parse(res.body)
if body.is_a?(Array)
body.map {|v| OpenStruct.new(v) }
elsif body.is_a?(Hash)
OpenStruct.new(body)
end
end
end
def setup_google_client
client = Google::APIClient.new(application_name: 'Waker',
application_version: '1.0.0')
file_storage = Google::APIClient::FileStorage.new($config.credential_store_file)
if file_storage.authorization.nil?
client_secrets = Google::APIClient::ClientSecrets.load($config.client_secret_file)
flow = Google::APIClient::InstalledAppFlow.new(
client_id: client_secrets.client_id,
client_secret: client_secrets.client_secret,
scope: ['https://www.googleapis.com/auth/calendar.readonly']
)
client.authorization = flow.authorize(file_storage)
else
client.authorization = file_storage.authorization
end
return client
end
$config = Configuration.from_command_line_options
client = setup_google_client
calendar_api = client.discovered_api('calendar', 'v3')
calendar = client.execute(
api_method: calendar_api.calendar_list.list,
parameters: {},
).data.items.find do |cal|
cal['summary'] == $config.calendar_name
end
events = client.execute(
api_method: calendar_api.events.list,
parameters: {
'calendarId' => calendar['id'],
'timeMax' => (Time.now + 1).strftime('%FT%T%:z'),
'timeMin' => (Time.now).strftime('%FT%T%:z'),
'singleEvents' => true,
},
).data.items
events.each do |event|
unless event['end']['dateTime'] && event['start']['dateTime']
raise "dateTime field is not found (The event may be all-day event)\n#{event}"
end
end
events.sort! do |a, b|
a['end']['dateTime'] - a['start']['dateTime'] <=>
b['end']['dateTime'] - b['start']['dateTime']
end
# shortest event
event = events.first
persons = event['summary'].split($config.delimiter).map(&:strip)
client = WakerClient.new(url: $config.url, token: $config.login_token)
escalation_series = client.escalation_series.find do |series|
[series.id, series.name].include?($config.escalation_series)
end
escalations = client.escalations.select do |escalation|
escalation.escalation_series_id == escalation_series.id
end.sort_by do |escalation|
escalation.escalate_after_sec
end
users = client.users
persons.each_with_index do |name, i|
user = users.find {|u| u.name == name }
raise "#{name} user is not found." unless user
escalation = escalations[i]
client.update_escalation(escalation, escalate_to: user)
end
================================================
FILE: spec/controllers/slack_controller_spec.rb
================================================
require 'rails_helper'
RSpec.describe SlackController, type: :controller do
describe "GET interactive" do
it "raises token verification failed error" do
expect(get: 'slack/interactive').not_to be_routable
expect{get :interactive}.to raise_error(RuntimeError, /token verification failed/)
end
end
end
================================================
FILE: spec/factories/escalation.rb
================================================
FactoryBot.define do
factory :escalation do
association :escalate_to, factory: :user
escalate_after_sec { 60 }
escalation_series
end
end
================================================
FILE: spec/factories/escalation_series.rb
================================================
FactoryBot.define do
factory :escalation_series do
name { "Infra" }
end
end
================================================
FILE: spec/factories/incident.rb
================================================
FactoryBot.define do
factory :incident do
id { 1 }
topic
subject { "mysql-01 is down" }
description { "alert" }
end
end
================================================
FILE: spec/factories/incident_events.rb
================================================
FactoryBot.define do
factory :incident_event do
incident_id { 1 }
kind { :opened }
end
end
================================================
FILE: spec/factories/maintenances.rb
================================================
FactoryBot.define do
factory :maintenance do
topic nil
start_time { "2016-02-10 10:03:10" }
end_time { "2016-02-10 10:03:10" }
end
end
================================================
FILE: spec/factories/notifier.rb
================================================
FactoryBot.define do
factory :notifier do
user
association :provider, factory: :notifier_provider
notify_after_sec { 60 }
end
end
================================================
FILE: spec/factories/notifier_provider.rb
================================================
FactoryBot.define do
factory :notifier_provider do
name { "Logger" }
kind { :rails_logger }
end
end
================================================
FILE: spec/factories/topic.rb
================================================
FactoryBot.define do
factory :topic do
name { "Infra" }
kind { "api" }
escalation_series
end
end
================================================
FILE: spec/factories/user.rb
================================================
FactoryBot.define do
factory :user do
name { "Ryota Arai" }
end
end
================================================
FILE: spec/helpers/slack_helper_spec.rb
================================================
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the SlackHelper. For example:
#
# describe SlackHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe SlackHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end
================================================
FILE: spec/models/comment_spec.rb
================================================
require 'rails_helper'
RSpec.describe Comment, type: :model do
let(:incident) { create(:incident) }
let(:user) { create(:user) }
it 'should be valid' do
comment = Comment.new(
incident: incident,
user: user,
comment: 'Help Me',
)
expect(comment).to be_valid
end
it 'should be invalid without incident' do
comment = Comment.new(
incident: nil,
user: user,
comment: 'Help Me',
)
expect(comment).not_to be_valid
end
it 'should be invalid without user' do
comment = Comment.new(
incident: incident,
user: nil,
comment: 'Help Me',
)
expect(comment).not_to be_valid
end
it 'should be invalid without comment' do
comment = Comment.new(
incident: incident,
user: user,
comment: '',
)
expect(comment).not_to be_valid
end
end
================================================
FILE: spec/models/escalation_series_spec.rb
================================================
require 'rails_helper'
require 'ostruct'
require 'google/api_client'
require 'json'
RSpec.describe EscalationSeries, type: :model do
describe "after_create enqueue" do
before do
# I understand that this is not the recommended method, but it is enough.
allow_any_instance_of(Google::APIClient).to receive(:execute).and_return(
OpenStruct.new(
{
data: OpenStruct.new({
items: [{
'id' => 1,
'summary' => 'test_calendar'
}]
})
}
),
OpenStruct.new(
{
data: OpenStruct.new({
items: [{
'summary' => 'c,b,a',
'start' => { 'dateTime' => Time.now },
'end' => { 'dateTime' => Time.now + 300 },
}]
})
}
),
)
end
it "#update_escalations" do
users = %w(a b c).map { |n| create(:user, name: n, credentials: { expires_at: Time.now.to_i + 300, token: "dummy", expires: nil, }) }
series = create(:escalation_series, settings: {
update_by: 'google_calendar',
user_as_id: users.first.id,
calendar: 'test_calendar',
event_delimiter: ',',
})
escalations = users.map { |u| create(:escalation, escalation_series: series, escalate_to: u ) }
expect(series.update_escalations!).to be_truthy
users.reverse.each_with_index do |u,i|
expect(Escalation.find(escalations[i].id).escalate_to.id).to eq(u.id)
end
end
end
end
================================================
FILE: spec/models/incident_spec.rb
================================================
require 'rails_helper'
RSpec.describe Incident, type: :model do
describe "after_create enqueue" do
it "creates escalation jobs" do
series = create(:escalation_series)
escalation = create(:escalation, escalation_series: series)
notifier = create(:notifier, user: escalation.escalate_to)
topic = create(:topic, escalation_series: series)
incident = nil
expect {
incident = create(:incident, topic: topic)
}.to change(EscalationWorker.jobs, :size).by(1).and change(NotificationWorker.jobs, :size).by(1)
expect {
EscalationWorker.drain
}.to change(incident.events, :count).by(1)
event = incident.events.last
expect(event.kind).to eq('escalated')
expect(event.escalation).to eq(escalation)
expect(NotificationWorker.jobs.size).to eq(2)
end
end
end
================================================
FILE: spec/models/maintenance_spec.rb
================================================
require 'rails_helper'
RSpec.describe Maintenance, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end
================================================
FILE: spec/rails_helper.rb
================================================
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
end
================================================
FILE: spec/requests/incident_envets_spec.rb
================================================
require 'rails_helper'
RSpec.describe "IncidentEvent", type: :request do
describe "POST /incident_events/:id/twilio" do
let(:incident) { create(:incident) }
let(:event) { create(:incident_event, incident_id: incident.id) }
describe 'without params[:Digits]' do
it "works!" do
post "/incident_events/#{event.id}/twilio"
expect(response).to have_http_status(200)
end
end
describe 'with params[:Digits]' do
before do
post "/incident_events/#{event.id}/twilio", params: { Digits: digit}
incident.reload
end
context '1' do
let(:digit) { 1 }
it "acknowledged" do
expect(response).to have_http_status(200)
expect(incident.status).to eq 'acknowledged'
end
end
context '2' do
let(:digit) { 2 }
it "resolved" do
expect(response).to have_http_status(200)
expect(incident.status).to eq 'resolved'
end
end
end
end
end
================================================
FILE: spec/requests/maintenances_spec.rb
================================================
require 'rails_helper'
RSpec.describe "Maintenances", type: :request do
describe "GET /maintenances" do
it "works! (now write some real specs)" do
get maintenances_path
expect(response).to have_http_status(200)
end
end
end
================================================
FILE: spec/requests/topics_spec.rb
================================================
require "rails_helper"
RSpec.describe "Topics", type: :request do
describe "POST /topics/1/mailgun" do
let(:subject) { 'New Alert' }
let(:body) { "Your server is on fire" }
it "creates a new incident" do
topic = create(:topic)
post mailgun_topic_path(topic, format: :json), params: {
'subject' => subject,
'body-plain' => body,
}
expect(response).to have_http_status(200)
incident = Incident.last
expect(incident.subject).to eq(subject)
expect(incident.description).to eq(body)
end
end
describe "POST /topics/1/slack" do
it "creates a new incident" do
topic = create(:topic)
post slack_topic_path(topic, format: :json), params: {
'channel_name' => 'test_channel',
'user_name' => 'test_user',
'text' => 'help me',
}
expect(response).to have_http_status(200)
incident = Incident.last
expect(incident.subject).to eq("escalation from slack,channel name:test_channel help me")
expect(incident.description).to eq("channel:test_channel user:test_user help me")
end
end
end
================================================
FILE: spec/spec_helper.rb
================================================
require 'simplecov'
SimpleCov.start 'rails' do
add_filter '/vendor/'
add_filter '/.bundle/'
end
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause this
# file to always be loaded, without a need to explicitly require it in any files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, consider making
# a separate helper file that requires the additional dependencies and performs
# the additional setup, and require it from the spec files that actually need it.
#
# The `.rspec` file also contains a few flags that are not defaults but that
# users commonly want.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
config.before :suite do
DatabaseRewinder.clean_all
end
config.after :each do
DatabaseRewinder.clean
end
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = :random
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
# These two settings work together to allow you to limit a spec run
# to individual examples or groups you care about by tagging them with
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
# get run.
config.filter_run :focus
config.run_all_when_everything_filtered = true
# Limits the available syntax to the non-monkey patched syntax that is recommended.
# For more details, see:
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
config.disable_monkey_patching!
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = 'doc'
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
=end
end
================================================
FILE: spec/support/factory_girl.rb
================================================
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
config.before(:suite) do
begin
FactoryBot.lint
ensure
DatabaseRewinder.clean_all
end
end
end
================================================
FILE: spec/support/sidekiq.rb
================================================
require 'sidekiq/testing'
RSpec.configure do |config|
config.before(:each) do
Sidekiq::Worker.clear_all
end
end
================================================
FILE: spec/views/slack/interactive.html.erb_spec.rb
================================================
require 'rails_helper'
RSpec.describe "slack/interactive.html.erb", type: :view do
pending "add some examples to (or delete) #{__FILE__}"
end
================================================
FILE: vendor/assets/javascripts/.keep
================================================
================================================
FILE: vendor/assets/stylesheets/.keep
================================================
gitextract_ao1b4jon/
├── .dockerignore
├── .github/
│ └── workflows/
│ └── rails.yml
├── .gitignore
├── .rspec
├── .rubocop.yml
├── Dockerfile
├── Gemfile
├── LICENSE.txt
├── Procfile
├── Procfile.docker
├── README.md
├── Rakefile
├── app/
│ ├── assets/
│ │ ├── images/
│ │ │ └── .keep
│ │ ├── javascripts/
│ │ │ ├── application.js
│ │ │ ├── comments.coffee
│ │ │ ├── escalation_series.coffee
│ │ │ ├── escalations.coffee
│ │ │ ├── home.coffee
│ │ │ ├── incident_events.coffee
│ │ │ ├── incidents.coffee
│ │ │ ├── maintenances.coffee
│ │ │ ├── notifier_providers.coffee
│ │ │ ├── notifiers.coffee
│ │ │ ├── sessions.coffee
│ │ │ ├── slack.coffee
│ │ │ ├── topics.coffee
│ │ │ └── users.coffee
│ │ └── stylesheets/
│ │ ├── application.css
│ │ ├── comments.scss
│ │ ├── escalation_series.scss
│ │ ├── escalations.scss
│ │ ├── home.scss
│ │ ├── incident_events.scss
│ │ ├── incidents.scss
│ │ ├── maintenances.scss
│ │ ├── notifier_providers.scss
│ │ ├── notifiers.scss
│ │ ├── scaffolds.scss
│ │ ├── sessions.scss
│ │ ├── slack.scss
│ │ ├── topics.scss
│ │ └── users.scss
│ ├── controllers/
│ │ ├── application_controller.rb
│ │ ├── comments_controller.rb
│ │ ├── concerns/
│ │ │ └── .keep
│ │ ├── escalation_series_controller.rb
│ │ ├── escalations_controller.rb
│ │ ├── home_controller.rb
│ │ ├── incident_events_controller.rb
│ │ ├── incidents_controller.rb
│ │ ├── maintenances_controller.rb
│ │ ├── notifier_providers_controller.rb
│ │ ├── notifiers_controller.rb
│ │ ├── sessions_controller.rb
│ │ ├── slack_controller.rb
│ │ ├── topics_controller.rb
│ │ └── users_controller.rb
│ ├── helpers/
│ │ ├── application_helper.rb
│ │ ├── comments_helper.rb
│ │ ├── escalation_series_helper.rb
│ │ ├── escalations_helper.rb
│ │ ├── home_helper.rb
│ │ ├── incident_events_helper.rb
│ │ ├── incidents_helper.rb
│ │ ├── maintenances_helper.rb
│ │ ├── notifier_providers_helper.rb
│ │ ├── notifiers_helper.rb
│ │ ├── sessions_helper.rb
│ │ ├── slack_helper.rb
│ │ ├── topics_helper.rb
│ │ └── users_helper.rb
│ ├── mailers/
│ │ └── .keep
│ ├── models/
│ │ ├── .keep
│ │ ├── application_record.rb
│ │ ├── comment.rb
│ │ ├── concerns/
│ │ │ └── .keep
│ │ ├── escalation.rb
│ │ ├── escalation_series.rb
│ │ ├── escalation_update_worker.rb
│ │ ├── escalation_worker.rb
│ │ ├── incident.rb
│ │ ├── incident_event.rb
│ │ ├── maintenance.rb
│ │ ├── notification_worker.rb
│ │ ├── notifier.rb
│ │ ├── notifier_provider.rb
│ │ ├── topic.rb
│ │ └── user.rb
│ └── views/
│ ├── comments/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── escalation_series/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── escalations/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── home/
│ │ └── index.html.erb
│ ├── incident_events/
│ │ └── twilio.html.erb
│ ├── incidents/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── layouts/
│ │ └── application.html.erb
│ ├── maintenances/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── notifier_providers/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── hipchat/
│ │ │ ├── acknowledged.text.erb
│ │ │ ├── escalated.text.erb
│ │ │ ├── opened.text.erb
│ │ │ └── resolved.text.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── mailgun/
│ │ │ ├── default.html.erb
│ │ │ └── default.text.erb
│ │ ├── new.html.erb
│ │ ├── rails_logger/
│ │ │ └── default.text.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── notifiers/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ ├── sessions/
│ │ └── create.html.erb
│ ├── slack/
│ │ └── interactive.html.erb
│ ├── topics/
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── index.json.jbuilder
│ │ ├── new.html.erb
│ │ ├── show.html.erb
│ │ └── show.json.jbuilder
│ └── users/
│ ├── _form.html.erb
│ ├── edit.html.erb
│ ├── index.html.erb
│ ├── index.json.jbuilder
│ ├── new.html.erb
│ ├── show.html.erb
│ └── show.json.jbuilder
├── bin/
│ ├── bundle
│ ├── rails
│ ├── rake
│ ├── setup
│ └── spring
├── config/
│ ├── application.rb
│ ├── boot.rb
│ ├── database.yml
│ ├── environment.rb
│ ├── environments/
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers/
│ │ ├── assets.rb
│ │ ├── backtrace_silencers.rb
│ │ ├── cookies_serializer.rb
│ │ ├── field_with_errors.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── omniauth.rb
│ │ ├── session_store.rb
│ │ ├── sidekiq.rb
│ │ ├── url_options.rb
│ │ └── wrap_parameters.rb
│ ├── locales/
│ │ └── en.yml
│ ├── routes.rb
│ └── secrets.yml
├── config.ru
├── db/
│ ├── migrate/
│ │ ├── 20150120134616_create_topics.rb
│ │ ├── 20150120134747_create_users.rb
│ │ ├── 20150120134905_create_notifiers.rb
│ │ ├── 20150120135017_create_shifts.rb
│ │ ├── 20150120135123_create_escalations.rb
│ │ ├── 20150120135244_create_escalation_series.rb
│ │ ├── 20150120135351_add_escalation_series_to_escalation.rb
│ │ ├── 20150120141627_rename_type_with_kind_of_topic.rb
│ │ ├── 20150120142452_create_incidents.rb
│ │ ├── 20150120151642_add_escalation_series_to_topic.rb
│ │ ├── 20150120154438_add_name_to_shift.rb
│ │ ├── 20150121150043_add_user_to_notifier.rb
│ │ ├── 20150121150857_rename_type_with_kind_of_notifier.rb
│ │ ├── 20150123132415_remove_shift.rb
│ │ ├── 20150123150518_add_status_to_incident.rb
│ │ ├── 20150123150947_create_incident_events.rb
│ │ ├── 20150125050529_create_notifier_providers.rb
│ │ ├── 20150125050556_add_provider_to_notifier.rb
│ │ ├── 20150125101901_remove_kind_from_notifier.rb
│ │ ├── 20150127142530_remove_user_by_from_incident_event.rb
│ │ ├── 20150127152127_add_info_to_incident_event.rb
│ │ ├── 20150128064248_add_email_to_user.rb
│ │ ├── 20150131120557_add_enable_to_topic.rb
│ │ ├── 20150131121143_set_default_of_enable_of_topic_true.rb
│ │ ├── 20150131122151_rename_enable_with_enabled_of_topic.rb
│ │ ├── 20150201033946_add_login_token_to_user.rb
│ │ ├── 20150202144538_add_token_to_user.rb
│ │ ├── 20150202151740_add_refresh_token_to_user.rb
│ │ ├── 20150202152015_add_settings_to_escalation_series.rb
│ │ ├── 20150202155726_add_token_expires_at_to_user.rb
│ │ ├── 20150203010332_remove_escalation_series_from_escalation_series.rb
│ │ ├── 20150203010417_add_settings_to_escalation_series_again.rb
│ │ ├── 20150207164010_add_topic_to_notifier.rb
│ │ ├── 20150218071007_add_enable_to_notifier.rb
│ │ ├── 20151117011141_add_active_to_user.rb
│ │ ├── 20151117013824_add_provider_and_uid_to_user.rb
│ │ ├── 20151118061253_add_credentials_to_user.rb
│ │ ├── 20151118061938_delete_token_from_user.rb
│ │ ├── 20160210010310_create_maintenances.rb
│ │ ├── 20160907123728_create_comments.rb
│ │ ├── 20160914063913_add_comment_index.rb
│ │ └── 20161207045554_add_filter_to_maintenance.rb
│ ├── schema.rb
│ └── seeds.rb
├── docker/
│ └── puma.rb
├── docker-compose.yml
├── lib/
│ ├── assets/
│ │ └── .keep
│ └── tasks/
│ └── .keep
├── log/
│ └── .keep
├── public/
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ └── robots.txt
├── script/
│ └── update-escalations-from-google-calendar
├── spec/
│ ├── controllers/
│ │ └── slack_controller_spec.rb
│ ├── factories/
│ │ ├── escalation.rb
│ │ ├── escalation_series.rb
│ │ ├── incident.rb
│ │ ├── incident_events.rb
│ │ ├── maintenances.rb
│ │ ├── notifier.rb
│ │ ├── notifier_provider.rb
│ │ ├── topic.rb
│ │ └── user.rb
│ ├── helpers/
│ │ └── slack_helper_spec.rb
│ ├── models/
│ │ ├── comment_spec.rb
│ │ ├── escalation_series_spec.rb
│ │ ├── incident_spec.rb
│ │ └── maintenance_spec.rb
│ ├── rails_helper.rb
│ ├── requests/
│ │ ├── incident_envets_spec.rb
│ │ ├── maintenances_spec.rb
│ │ └── topics_spec.rb
│ ├── spec_helper.rb
│ ├── support/
│ │ ├── factory_girl.rb
│ │ └── sidekiq.rb
│ └── views/
│ └── slack/
│ └── interactive.html.erb_spec.rb
└── vendor/
└── assets/
├── javascripts/
│ └── .keep
└── stylesheets/
└── .keep
SYMBOL INDEX (338 symbols across 85 files)
FILE: app/controllers/application_controller.rb
class ApplicationController (line 1) | class ApplicationController < ActionController::Base
method login_required (line 11) | def login_required
method current_user= (line 25) | def current_user=(user)
method current_user (line 29) | def current_user
FILE: app/controllers/comments_controller.rb
class CommentsController (line 1) | class CommentsController < ApplicationController
method index (line 7) | def index
method show (line 13) | def show
method new (line 17) | def new
method edit (line 22) | def edit
method create (line 27) | def create
method update (line 44) | def update
method destroy (line 58) | def destroy
method set_comment (line 68) | def set_comment
method comment_params (line 73) | def comment_params
method set_incident (line 77) | def set_incident
FILE: app/controllers/escalation_series_controller.rb
class EscalationSeriesController (line 1) | class EscalationSeriesController < ApplicationController
method index (line 6) | def index
method show (line 12) | def show
method new (line 16) | def new
method edit (line 21) | def edit
method create (line 26) | def create
method update (line 42) | def update
method destroy (line 56) | def destroy
method update_escalations (line 64) | def update_escalations
method set_escalation_series (line 70) | def set_escalation_series
method escalation_series_params (line 75) | def escalation_series_params
FILE: app/controllers/escalations_controller.rb
class EscalationsController (line 1) | class EscalationsController < ApplicationController
method index (line 6) | def index
method show (line 12) | def show
method new (line 16) | def new
method edit (line 21) | def edit
method create (line 26) | def create
method update (line 42) | def update
method destroy (line 56) | def destroy
method set_escalation (line 66) | def set_escalation
method escalation_params (line 71) | def escalation_params
FILE: app/controllers/home_controller.rb
class HomeController (line 1) | class HomeController < ApplicationController
method index (line 2) | def index
FILE: app/controllers/incident_events_controller.rb
class IncidentEventsController (line 3) | class IncidentEventsController < ApplicationController
method twilio (line 6) | def twilio
FILE: app/controllers/incidents_controller.rb
class IncidentsController (line 1) | class IncidentsController < ApplicationController
method index (line 9) | def index
method show (line 16) | def show
method new (line 20) | def new
method edit (line 25) | def edit
method create (line 30) | def create
method update (line 46) | def update
method bulk_acknowledge (line 58) | def bulk_acknowledge
method bulk_resolve (line 66) | def bulk_resolve
method destroy (line 76) | def destroy
method acknowledge (line 84) | def acknowledge
method resolve (line 96) | def resolve
method set_incident (line 110) | def set_incident
method set_incidents (line 114) | def set_incidents
method set_visible_statuses (line 128) | def set_visible_statuses
method set_visible_topic (line 144) | def set_visible_topic
method incident_params (line 161) | def incident_params
method ensure_hash (line 165) | def ensure_hash
FILE: app/controllers/maintenances_controller.rb
class MaintenancesController (line 1) | class MaintenancesController < ApplicationController
method index (line 6) | def index
method show (line 12) | def show
method new (line 16) | def new
method edit (line 25) | def edit
method create (line 30) | def create
method update (line 46) | def update
method destroy (line 60) | def destroy
method set_maintenance (line 70) | def set_maintenance
method maintenance_params (line 75) | def maintenance_params
FILE: app/controllers/notifier_providers_controller.rb
class NotifierProvidersController (line 1) | class NotifierProvidersController < ApplicationController
method index (line 6) | def index
method show (line 12) | def show
method new (line 16) | def new
method edit (line 21) | def edit
method create (line 26) | def create
method update (line 42) | def update
method destroy (line 56) | def destroy
method set_notifier_provider (line 66) | def set_notifier_provider
method notifier_provider_params (line 71) | def notifier_provider_params
FILE: app/controllers/notifiers_controller.rb
class NotifiersController (line 1) | class NotifiersController < ApplicationController
method index (line 6) | def index
method show (line 12) | def show
method new (line 16) | def new
method edit (line 21) | def edit
method create (line 26) | def create
method update (line 42) | def update
method destroy (line 56) | def destroy
method set_notifier (line 66) | def set_notifier
method notifier_params (line 71) | def notifier_params
FILE: app/controllers/sessions_controller.rb
class SessionsController (line 1) | class SessionsController < ApplicationController
method create (line 4) | def create
method auth_hash (line 13) | def auth_hash
FILE: app/controllers/slack_controller.rb
class SlackController (line 1) | class SlackController < ApplicationController
method interactive (line 4) | def interactive
method payload (line 33) | def payload
method verify! (line 37) | def verify!
method incident_id (line 53) | def incident_id
method incident (line 57) | def incident
FILE: app/controllers/topics_controller.rb
class TopicsController (line 1) | class TopicsController < ApplicationController
method index (line 7) | def index
method show (line 13) | def show
method new (line 17) | def new
method edit (line 22) | def edit
method create (line 27) | def create
method update (line 43) | def update
method destroy (line 57) | def destroy
method mailgun (line 66) | def mailgun
method mackerel (line 92) | def mackerel
method alertmanager (line 124) | def alertmanager
method slack (line 149) | def slack
method set_topic (line 175) | def set_topic
method topic_params (line 180) | def topic_params
FILE: app/controllers/users_controller.rb
class UsersController (line 1) | class UsersController < ApplicationController
method index (line 6) | def index
method show (line 12) | def show
method new (line 16) | def new
method edit (line 21) | def edit
method create (line 26) | def create
method update (line 42) | def update
method destroy (line 56) | def destroy
method activation (line 65) | def activation
method deactivation (line 73) | def deactivation
method set_user (line 82) | def set_user
method user_params (line 87) | def user_params
FILE: app/helpers/application_helper.rb
type ApplicationHelper (line 1) | module ApplicationHelper
FILE: app/helpers/comments_helper.rb
type CommentsHelper (line 1) | module CommentsHelper
FILE: app/helpers/escalation_series_helper.rb
type EscalationSeriesHelper (line 1) | module EscalationSeriesHelper
FILE: app/helpers/escalations_helper.rb
type EscalationsHelper (line 1) | module EscalationsHelper
FILE: app/helpers/home_helper.rb
type HomeHelper (line 1) | module HomeHelper
FILE: app/helpers/incident_events_helper.rb
type IncidentEventsHelper (line 1) | module IncidentEventsHelper
FILE: app/helpers/incidents_helper.rb
type IncidentsHelper (line 1) | module IncidentsHelper
FILE: app/helpers/maintenances_helper.rb
type MaintenancesHelper (line 1) | module MaintenancesHelper
FILE: app/helpers/notifier_providers_helper.rb
type NotifierProvidersHelper (line 1) | module NotifierProvidersHelper
FILE: app/helpers/notifiers_helper.rb
type NotifiersHelper (line 1) | module NotifiersHelper
FILE: app/helpers/sessions_helper.rb
type SessionsHelper (line 1) | module SessionsHelper
FILE: app/helpers/slack_helper.rb
type SlackHelper (line 1) | module SlackHelper
FILE: app/helpers/topics_helper.rb
type TopicsHelper (line 1) | module TopicsHelper
FILE: app/helpers/users_helper.rb
type UsersHelper (line 1) | module UsersHelper
FILE: app/models/application_record.rb
class ApplicationRecord (line 2) | class ApplicationRecord < ActiveRecord::Base
FILE: app/models/comment.rb
class Comment (line 1) | class Comment < ApplicationRecord
FILE: app/models/escalation.rb
class Escalation (line 1) | class Escalation < ApplicationRecord
FILE: app/models/escalation_series.rb
class EscalationSeries (line 1) | class EscalationSeries < ApplicationRecord
method set_defaults (line 10) | def set_defaults
method update_escalations! (line 14) | def update_escalations!
class EscalationUpdater (line 27) | class EscalationUpdater
method initialize (line 28) | def initialize(series)
method update! (line 32) | def update!
method settings (line 38) | def settings
class GoogleCalendarEscalationUpdater (line 43) | class GoogleCalendarEscalationUpdater < EscalationUpdater
method initialize (line 44) | def initialize(*)
method update! (line 49) | def update!
method user_as (line 129) | def user_as
method calendar_name (line 133) | def calendar_name
method event_delimiter (line 137) | def event_delimiter
FILE: app/models/escalation_update_worker.rb
class EscalationUpdateWorker (line 1) | class EscalationUpdateWorker
method perform (line 4) | def perform
method handle_series (line 14) | def handle_series(series)
FILE: app/models/escalation_worker.rb
class EscalationWorker (line 1) | class EscalationWorker
method enqueue (line 4) | def self.enqueue(incident, escalation)
method perform (line 9) | def perform(incident_id, escalation_id)
FILE: app/models/incident.rb
class Incident (line 3) | class Incident < ApplicationRecord
method acknowledge! (line 19) | def acknowledge!
method resolve! (line 27) | def resolve!
method confirmation_hash (line 35) | def confirmation_hash
method set_defaults (line 41) | def set_defaults
method enqueue (line 46) | def enqueue
FILE: app/models/incident_event.rb
class IncidentEvent (line 1) | class IncidentEvent < ApplicationRecord
method set_defaults (line 13) | def set_defaults
method notify (line 17) | def notify
method escalated_to (line 26) | def escalated_to
method escalation (line 30) | def escalation
method notifier (line 34) | def notifier
method event (line 38) | def event
FILE: app/models/maintenance.rb
class Maintenance (line 1) | class Maintenance < ApplicationRecord
method filter_regexp (line 8) | def filter_regexp
FILE: app/models/notification_worker.rb
class NotificationWorker (line 1) | class NotificationWorker
method enqueue (line 4) | def self.enqueue(event:, notifier:)
method perform (line 10) | def perform(event_id, notifier_id)
FILE: app/models/notifier.rb
class Notifier (line 1) | class Notifier < ApplicationRecord
method set_defaults (line 12) | def set_defaults
method notify (line 16) | def notify(event)
method notify_immediately (line 20) | def notify_immediately(event)
FILE: app/models/notifier_provider.rb
class NotifierProvider (line 1) | class NotifierProvider < ApplicationRecord
method set_defaults (line 9) | def set_defaults
method concrete_class (line 13) | def concrete_class
method notify (line 17) | def notify(event:, notifier:)
class ConcreteProvider (line 21) | class ConcreteProvider
method initialize (line 22) | def initialize(provider:, notifier:, event:)
method notify (line 28) | def notify
method _notify (line 44) | def _notify
method settings (line 48) | def settings
method skip? (line 52) | def skip?
method skip_due_to_status_of_incident? (line 66) | def skip_due_to_status_of_incident?
method skip_due_to_or_conditions? (line 74) | def skip_due_to_or_conditions?
method all_events (line 113) | def all_events
method target_events (line 117) | def target_events
method body (line 122) | def body(formats: [:text])
method kind_of_event (line 140) | def kind_of_event
class FileConcreteProvider (line 149) | class FileConcreteProvider < ConcreteProvider
method _notify (line 150) | def _notify
class RailsLoggerConcreteProvider (line 154) | class RailsLoggerConcreteProvider < ConcreteProvider
method _notify (line 155) | def _notify
method target_events (line 159) | def target_events
class HipchatConcreteProvider (line 164) | class HipchatConcreteProvider < ConcreteProvider
method _notify (line 165) | def _notify
method api_token (line 183) | def api_token
method room (line 187) | def room
method api_version (line 191) | def api_version
method notify? (line 202) | def notify?
method target_events (line 206) | def target_events
class MailgunConcreteProvider (line 211) | class MailgunConcreteProvider < ConcreteProvider
method _notify (line 212) | def _notify
method api_key (line 234) | def api_key
method domain (line 238) | def domain
method from (line 242) | def from
method to (line 246) | def to
method target_events (line 250) | def target_events
class TwilioConcreteProvider (line 255) | class TwilioConcreteProvider < ConcreteProvider
method _notify (line 256) | def _notify
method account_sid (line 272) | def account_sid
method auth_token (line 276) | def auth_token
method from (line 280) | def from
method to (line 284) | def to
method target_events (line 288) | def target_events
method basic_auth_user (line 292) | def basic_auth_user
method basic_auth_password (line 296) | def basic_auth_password
class SlackConcreteProvider (line 301) | class SlackConcreteProvider < ConcreteProvider
method _notify (line 302) | def _notify
method webhook_url (line 393) | def webhook_url
method channel (line 397) | def channel
method buttons_enabled? (line 401) | def buttons_enabled?
method target_events (line 405) | def target_events
class DatadogConcreteProvider (line 410) | class DatadogConcreteProvider < ConcreteProvider
method _notify (line 411) | def _notify
method api_key (line 428) | def api_key
method app_key (line 432) | def app_key
method alert_type (line 436) | def alert_type
method tags (line 440) | def tags
method source_type_name (line 444) | def source_type_name
method target_events (line 448) | def target_events
class SnsConcreteProvider (line 453) | class SnsConcreteProvider < ConcreteProvider
method _notify (line 454) | def _notify
method topic_arn (line 479) | def topic_arn
method region (line 483) | def region
method access_key_id (line 487) | def access_key_id
method secret_access_key (line 491) | def secret_access_key
method target_events (line 495) | def target_events
FILE: app/models/topic.rb
class Topic (line 1) | class Topic < ApplicationRecord
method in_maintenance? (line 10) | def in_maintenance?(*bodies)
FILE: app/models/user.rb
class User (line 3) | class User < ApplicationRecord
method find_or_create_from_auth_hash (line 14) | def self.find_or_create_from_auth_hash(auth_hash)
method update_credentials_from_auth_hash (line 28) | def update_credentials_from_auth_hash(auth_hash)
method set_defaults (line 34) | def set_defaults
FILE: config/application.rb
type Waker (line 17) | module Waker
class Application (line 18) | class Application < Rails::Application
FILE: db/migrate/20150120134616_create_topics.rb
class CreateTopics (line 1) | class CreateTopics < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120134747_create_users.rb
class CreateUsers (line 1) | class CreateUsers < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120134905_create_notifiers.rb
class CreateNotifiers (line 1) | class CreateNotifiers < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120135017_create_shifts.rb
class CreateShifts (line 1) | class CreateShifts < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120135123_create_escalations.rb
class CreateEscalations (line 1) | class CreateEscalations < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120135244_create_escalation_series.rb
class CreateEscalationSeries (line 1) | class CreateEscalationSeries < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120135351_add_escalation_series_to_escalation.rb
class AddEscalationSeriesToEscalation (line 1) | class AddEscalationSeriesToEscalation < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120141627_rename_type_with_kind_of_topic.rb
class RenameTypeWithKindOfTopic (line 1) | class RenameTypeWithKindOfTopic < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120142452_create_incidents.rb
class CreateIncidents (line 1) | class CreateIncidents < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120151642_add_escalation_series_to_topic.rb
class AddEscalationSeriesToTopic (line 1) | class AddEscalationSeriesToTopic < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150120154438_add_name_to_shift.rb
class AddNameToShift (line 1) | class AddNameToShift < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150121150043_add_user_to_notifier.rb
class AddUserToNotifier (line 1) | class AddUserToNotifier < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150121150857_rename_type_with_kind_of_notifier.rb
class RenameTypeWithKindOfNotifier (line 1) | class RenameTypeWithKindOfNotifier < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150123132415_remove_shift.rb
class RemoveShift (line 1) | class RemoveShift < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150123150518_add_status_to_incident.rb
class AddStatusToIncident (line 1) | class AddStatusToIncident < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150123150947_create_incident_events.rb
class CreateIncidentEvents (line 1) | class CreateIncidentEvents < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150125050529_create_notifier_providers.rb
class CreateNotifierProviders (line 1) | class CreateNotifierProviders < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150125050556_add_provider_to_notifier.rb
class AddProviderToNotifier (line 1) | class AddProviderToNotifier < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150125101901_remove_kind_from_notifier.rb
class RemoveKindFromNotifier (line 1) | class RemoveKindFromNotifier < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150127142530_remove_user_by_from_incident_event.rb
class RemoveUserByFromIncidentEvent (line 1) | class RemoveUserByFromIncidentEvent < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150127152127_add_info_to_incident_event.rb
class AddInfoToIncidentEvent (line 1) | class AddInfoToIncidentEvent < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150128064248_add_email_to_user.rb
class AddEmailToUser (line 1) | class AddEmailToUser < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150131120557_add_enable_to_topic.rb
class AddEnableToTopic (line 1) | class AddEnableToTopic < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150131121143_set_default_of_enable_of_topic_true.rb
class SetDefaultOfEnableOfTopicTrue (line 1) | class SetDefaultOfEnableOfTopicTrue < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150131122151_rename_enable_with_enabled_of_topic.rb
class RenameEnableWithEnabledOfTopic (line 1) | class RenameEnableWithEnabledOfTopic < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150201033946_add_login_token_to_user.rb
class AddLoginTokenToUser (line 1) | class AddLoginTokenToUser < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150202144538_add_token_to_user.rb
class AddTokenToUser (line 1) | class AddTokenToUser < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150202151740_add_refresh_token_to_user.rb
class AddRefreshTokenToUser (line 1) | class AddRefreshTokenToUser < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150202152015_add_settings_to_escalation_series.rb
class AddSettingsToEscalationSeries (line 1) | class AddSettingsToEscalationSeries < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150202155726_add_token_expires_at_to_user.rb
class AddTokenExpiresAtToUser (line 1) | class AddTokenExpiresAtToUser < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150203010332_remove_escalation_series_from_escalation_series.rb
class RemoveEscalationSeriesFromEscalationSeries (line 1) | class RemoveEscalationSeriesFromEscalationSeries < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150203010417_add_settings_to_escalation_series_again.rb
class AddSettingsToEscalationSeriesAgain (line 1) | class AddSettingsToEscalationSeriesAgain < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150207164010_add_topic_to_notifier.rb
class AddTopicToNotifier (line 1) | class AddTopicToNotifier < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20150218071007_add_enable_to_notifier.rb
class AddEnableToNotifier (line 1) | class AddEnableToNotifier < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20151117011141_add_active_to_user.rb
class AddActiveToUser (line 1) | class AddActiveToUser < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20151117013824_add_provider_and_uid_to_user.rb
class AddProviderAndUidToUser (line 1) | class AddProviderAndUidToUser < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20151118061253_add_credentials_to_user.rb
class AddCredentialsToUser (line 1) | class AddCredentialsToUser < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20151118061938_delete_token_from_user.rb
class DeleteTokenFromUser (line 1) | class DeleteTokenFromUser < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20160210010310_create_maintenances.rb
class CreateMaintenances (line 1) | class CreateMaintenances < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20160907123728_create_comments.rb
class CreateComments (line 1) | class CreateComments < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20160914063913_add_comment_index.rb
class AddCommentIndex (line 1) | class AddCommentIndex < ActiveRecord::Migration
method change (line 2) | def change
FILE: db/migrate/20161207045554_add_filter_to_maintenance.rb
class AddFilterToMaintenance (line 1) | class AddFilterToMaintenance < ActiveRecord::Migration
method change (line 2) | def change
Condensed preview — 270 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (184K chars).
[
{
"path": ".dockerignore",
"chars": 39,
"preview": "logs/*\ndoc/*\nvendor/*\ncoverage/*\ntmp/*\n"
},
{
"path": ".github/workflows/rails.yml",
"chars": 888,
"preview": "name: Rails\n\non: [push]\n\njobs:\n\n build:\n runs-on: ubuntu-latest\n services:\n mysql:\n image: mysql:5.7\n"
},
{
"path": ".gitignore",
"chars": 494,
"preview": "# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring t"
},
{
"path": ".rspec",
"chars": 30,
"preview": "--color\n--require spec_helper\n"
},
{
"path": ".rubocop.yml",
"chars": 955,
"preview": "AllCops:\n TargetRubyVersion: 2.4\n DisplayCopNames: true\n DisabledByDefault: true\n Exclude:\n - 'db/**/*'\n - 've"
},
{
"path": "Dockerfile",
"chars": 376,
"preview": "FROM ruby:2.6.5\n\nRUN apt update -qqy && apt -qqy install nodejs\n\nWORKDIR /tmp\nADD Gemfile* /tmp/\n\nRUN gem install bundle"
},
{
"path": "Gemfile",
"chars": 1812,
"preview": "source 'https://rubygems.org'\n\n# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'\ngem 'rails', '5.2.4.1'\n\n#"
},
{
"path": "LICENSE.txt",
"chars": 1082,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014-2015 Ryota Arai\n\nPermission is hereby granted, free of charge, to any person o"
},
{
"path": "Procfile",
"chars": 162,
"preview": "web: bin/rails s\nworker: bundle exec sidekiq\nupdate_escalations: while true; do bundle exec rails runner 'EscalationUpda"
},
{
"path": "Procfile.docker",
"chars": 173,
"preview": "web: puma -C docker/puma.rb\nworker: bundle exec sidekiq\nupdate_escalations: while true; do bundle exec rails runner 'Esc"
},
{
"path": "README.md",
"chars": 3532,
"preview": "# Waker [](https://travis-ci.org/ryotarai/waker)\n"
},
{
"path": "Rakefile",
"chars": 249,
"preview": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they wil"
},
{
"path": "app/assets/images/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/assets/javascripts/application.js",
"chars": 644,
"preview": "// This is a manifest file that'll be compiled into application.js, which will include all the files\n// listed below.\n//"
},
{
"path": "app/assets/javascripts/comments.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/escalation_series.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/escalations.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/home.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/incident_events.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/incidents.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/maintenances.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/notifier_providers.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/notifiers.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/sessions.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/slack.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/topics.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/users.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/stylesheets/application.css",
"chars": 686,
"preview": "/*\n * This is a manifest file that'll be compiled into application.css, which will include all the files\n * listed below"
},
{
"path": "app/assets/stylesheets/comments.scss",
"chars": 179,
"preview": "// Place all the styles related to the comments controller here.\n// They will automatically be included in application.c"
},
{
"path": "app/assets/stylesheets/escalation_series.scss",
"chars": 187,
"preview": "// Place all the styles related to the EscalationSeries controller here.\n// They will automatically be included in appli"
},
{
"path": "app/assets/stylesheets/escalations.scss",
"chars": 182,
"preview": "// Place all the styles related to the escalations controller here.\n// They will automatically be included in applicatio"
},
{
"path": "app/assets/stylesheets/home.scss",
"chars": 175,
"preview": "// Place all the styles related to the home controller here.\n// They will automatically be included in application.css.\n"
},
{
"path": "app/assets/stylesheets/incident_events.scss",
"chars": 186,
"preview": "// Place all the styles related to the incident_events controller here.\n// They will automatically be included in applic"
},
{
"path": "app/assets/stylesheets/incidents.scss",
"chars": 180,
"preview": "// Place all the styles related to the incidents controller here.\n// They will automatically be included in application."
},
{
"path": "app/assets/stylesheets/maintenances.scss",
"chars": 183,
"preview": "// Place all the styles related to the maintenances controller here.\n// They will automatically be included in applicati"
},
{
"path": "app/assets/stylesheets/notifier_providers.scss",
"chars": 188,
"preview": "// Place all the styles related to the NotifierProviders controller here.\n// They will automatically be included in appl"
},
{
"path": "app/assets/stylesheets/notifiers.scss",
"chars": 180,
"preview": "// Place all the styles related to the notifiers controller here.\n// They will automatically be included in application."
},
{
"path": "app/assets/stylesheets/scaffolds.scss",
"chars": 1027,
"preview": "body {\n background-color: #fff;\n color: #333;\n font-family: verdana, arial, helvetica, sans-serif;\n font-size: 13px;"
},
{
"path": "app/assets/stylesheets/sessions.scss",
"chars": 179,
"preview": "// Place all the styles related to the sessions controller here.\n// They will automatically be included in application.c"
},
{
"path": "app/assets/stylesheets/slack.scss",
"chars": 176,
"preview": "// Place all the styles related to the slack controller here.\n// They will automatically be included in application.css."
},
{
"path": "app/assets/stylesheets/topics.scss",
"chars": 177,
"preview": "// Place all the styles related to the topics controller here.\n// They will automatically be included in application.css"
},
{
"path": "app/assets/stylesheets/users.scss",
"chars": 176,
"preview": "// Place all the styles related to the users controller here.\n// They will automatically be included in application.css."
},
{
"path": "app/controllers/application_controller.rb",
"chars": 877,
"preview": "class ApplicationController < ActionController::Base\n # Prevent CSRF attacks by raising an exception.\n # For APIs, you"
},
{
"path": "app/controllers/comments_controller.rb",
"chars": 2138,
"preview": "class CommentsController < ApplicationController\n before_action :set_comment, only: [:show, :edit, :update, :destroy]\n "
},
{
"path": "app/controllers/concerns/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/controllers/escalation_series_controller.rb",
"chars": 2453,
"preview": "class EscalationSeriesController < ApplicationController\n before_action :set_escalation_series, only: [:show, :edit, :u"
},
{
"path": "app/controllers/escalations_controller.rb",
"chars": 2094,
"preview": "class EscalationsController < ApplicationController\n before_action :set_escalation, only: [:show, :edit, :update, :dest"
},
{
"path": "app/controllers/home_controller.rb",
"chars": 98,
"preview": "class HomeController < ApplicationController\n def index\n redirect_to incidents_path\n end\nend\n"
},
{
"path": "app/controllers/incident_events_controller.rb",
"chars": 1135,
"preview": "require 'securerandom'\n\nclass IncidentEventsController < ApplicationController\n skip_before_action :login_required, onl"
},
{
"path": "app/controllers/incidents_controller.rb",
"chars": 4838,
"preview": "class IncidentsController < ApplicationController\n before_action :set_incidents, only: [:index, :bulk_acknowledge, :bul"
},
{
"path": "app/controllers/maintenances_controller.rb",
"chars": 2174,
"preview": "class MaintenancesController < ApplicationController\n before_action :set_maintenance, only: [:show, :edit, :update, :de"
},
{
"path": "app/controllers/notifier_providers_controller.rb",
"chars": 2373,
"preview": "class NotifierProvidersController < ApplicationController\n before_action :set_notifier_provider, only: [:show, :edit, :"
},
{
"path": "app/controllers/notifiers_controller.rb",
"chars": 2075,
"preview": "class NotifiersController < ApplicationController\n before_action :set_notifier, only: [:show, :edit, :update, :destroy]"
},
{
"path": "app/controllers/sessions_controller.rb",
"chars": 357,
"preview": "class SessionsController < ApplicationController\n skip_before_action :login_required, only: [:create]\n\n def create\n "
},
{
"path": "app/controllers/slack_controller.rb",
"chars": 1368,
"preview": "class SlackController < ApplicationController\n skip_before_action :login_required, only: [:interactive], raise: false\n\n"
},
{
"path": "app/controllers/topics_controller.rb",
"chars": 5229,
"preview": "class TopicsController < ApplicationController\n before_action :set_topic, only: [:show, :edit, :update, :destroy, :mail"
},
{
"path": "app/controllers/users_controller.rb",
"chars": 2233,
"preview": "class UsersController < ApplicationController\n before_action :set_user, only: [:show, :edit, :update, :destroy, :activa"
},
{
"path": "app/helpers/application_helper.rb",
"chars": 29,
"preview": "module ApplicationHelper\nend\n"
},
{
"path": "app/helpers/comments_helper.rb",
"chars": 26,
"preview": "module CommentsHelper\nend\n"
},
{
"path": "app/helpers/escalation_series_helper.rb",
"chars": 34,
"preview": "module EscalationSeriesHelper\nend\n"
},
{
"path": "app/helpers/escalations_helper.rb",
"chars": 29,
"preview": "module EscalationsHelper\nend\n"
},
{
"path": "app/helpers/home_helper.rb",
"chars": 22,
"preview": "module HomeHelper\nend\n"
},
{
"path": "app/helpers/incident_events_helper.rb",
"chars": 32,
"preview": "module IncidentEventsHelper\nend\n"
},
{
"path": "app/helpers/incidents_helper.rb",
"chars": 27,
"preview": "module IncidentsHelper\nend\n"
},
{
"path": "app/helpers/maintenances_helper.rb",
"chars": 30,
"preview": "module MaintenancesHelper\nend\n"
},
{
"path": "app/helpers/notifier_providers_helper.rb",
"chars": 35,
"preview": "module NotifierProvidersHelper\nend\n"
},
{
"path": "app/helpers/notifiers_helper.rb",
"chars": 27,
"preview": "module NotifiersHelper\nend\n"
},
{
"path": "app/helpers/sessions_helper.rb",
"chars": 26,
"preview": "module SessionsHelper\nend\n"
},
{
"path": "app/helpers/slack_helper.rb",
"chars": 23,
"preview": "module SlackHelper\nend\n"
},
{
"path": "app/helpers/topics_helper.rb",
"chars": 24,
"preview": "module TopicsHelper\nend\n"
},
{
"path": "app/helpers/users_helper.rb",
"chars": 23,
"preview": "module UsersHelper\nend\n"
},
{
"path": "app/mailers/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/models/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/models/application_record.rb",
"chars": 109,
"preview": "# Base ApplicationRecord Class\nclass ApplicationRecord < ActiveRecord::Base\n self.abstract_class = true\nend\n"
},
{
"path": "app/models/comment.rb",
"chars": 190,
"preview": "class Comment < ApplicationRecord\n belongs_to :incident\n belongs_to :user\n\n validates :incident, presence: true\n val"
},
{
"path": "app/models/concerns/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/models/escalation.rb",
"chars": 285,
"preview": "class Escalation < ApplicationRecord\n belongs_to :escalation_series\n belongs_to :escalate_to, class_name: 'User'\n\n va"
},
{
"path": "app/models/escalation_series.rb",
"chars": 3738,
"preview": "class EscalationSeries < ApplicationRecord\n has_many :escalations, dependent: :destroy\n has_many :topics, dependent: :"
},
{
"path": "app/models/escalation_update_worker.rb",
"chars": 326,
"preview": "class EscalationUpdateWorker\n include Sidekiq::Worker\n\n def perform\n EscalationSeries.all.each do |series|\n ha"
},
{
"path": "app/models/escalation_worker.rb",
"chars": 577,
"preview": "class EscalationWorker\n include Sidekiq::Worker\n\n def self.enqueue(incident, escalation)\n Rails.logger.info \"Enqueu"
},
{
"path": "app/models/incident.rb",
"chars": 1093,
"preview": "require 'digest/sha1'\n\nclass Incident < ApplicationRecord\n STATUSES = [:opened, :acknowledged, :resolved]\n\n belongs_to"
},
{
"path": "app/models/incident_event.rb",
"chars": 933,
"preview": "class IncidentEvent < ApplicationRecord\n belongs_to :incident\n\n enum kind: [:opened, :acknowledged, :resolved, :escala"
},
{
"path": "app/models/maintenance.rb",
"chars": 323,
"preview": "class Maintenance < ApplicationRecord\n scope :active, -> { t = Time.now; where('start_time <= ? AND ? <= end_time', t, "
},
{
"path": "app/models/notification_worker.rb",
"chars": 427,
"preview": "class NotificationWorker\n include Sidekiq::Worker\n\n def self.enqueue(event:, notifier:)\n Rails.logger.info \"Enqueue"
},
{
"path": "app/models/notifier.rb",
"chars": 537,
"preview": "class Notifier < ApplicationRecord\n belongs_to :provider, class_name: 'NotifierProvider'\n belongs_to :user\n belongs_t"
},
{
"path": "app/models/notifier_provider.rb",
"chars": 11791,
"preview": "class NotifierProvider < ApplicationRecord\n serialize :settings, JSON\n enum kind: [:mailgun, :file, :rails_logger, :hi"
},
{
"path": "app/models/topic.rb",
"chars": 501,
"preview": "class Topic < ApplicationRecord\n enum kind: [:api]\n belongs_to :escalation_series\n has_many :incidents\n\n validates :"
},
{
"path": "app/models/user.rb",
"chars": 893,
"preview": "require 'securerandom'\n\nclass User < ApplicationRecord\n scope :active, -> { where(active: true) }\n\n has_many :notifier"
},
{
"path": "app/views/comments/_form.html.erb",
"chars": 796,
"preview": "<%= form_for([@incident, @comment]) do |f| %>\n <% if @comment.errors.any? %>\n <div class=\"alert alert-danger\">\n "
},
{
"path": "app/views/comments/edit.html.erb",
"chars": 141,
"preview": "<h1>Editing Comment</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Show', [@incident, @comment] %> |\n<%= link_to 'Back', incid"
},
{
"path": "app/views/comments/index.html.erb",
"chars": 758,
"preview": "<h1>Listing Comments</h1>\n\n<p>\n <strong>Incident:</strong>\n <pre><%= @incident.subject %></pre>\n</p>\n\n<table class=\"ta"
},
{
"path": "app/views/comments/index.json.jbuilder",
"chars": 116,
"preview": "json.array!(@comments) do |comment|\n json.extract! comment, :id\n json.url comment_url(comment, format: :json)\nend\n"
},
{
"path": "app/views/comments/new.html.erb",
"chars": 90,
"preview": "<h1>New Comment</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Back', incident_comments_path %>\n"
},
{
"path": "app/views/comments/show.html.erb",
"chars": 398,
"preview": "\n<p>\n <strong>Incident:</strong>\n <pre><%= @incident.subject %></pre>\n</p>\n\n<p>\n <strong>Comment:</strong>\n <pre sty"
},
{
"path": "app/views/comments/show.json.jbuilder",
"chars": 61,
"preview": "json.extract! @comment, @user, :id, :created_at, :updated_at\n"
},
{
"path": "app/views/escalation_series/_form.html.erb",
"chars": 772,
"preview": "<%= form_for(@escalation_series) do |f| %>\n <% if @escalation_series.errors.any? %>\n <div class=\"alert alert-danger\""
},
{
"path": "app/views/escalation_series/edit.html.erb",
"chars": 154,
"preview": "<h1>Editing Escalation Series</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Show', @escalation_series %> |\n<%= link_to 'Back'"
},
{
"path": "app/views/escalation_series/index.html.erb",
"chars": 652,
"preview": "\n<h1>Listing Escalation Series</h1>\n\n<table class=\"table\">\n <thead>\n <tr>\n <th>Name</th>\n <th colspan=\"3\">"
},
{
"path": "app/views/escalation_series/index.json.jbuilder",
"chars": 172,
"preview": "json.array!(@escalation_series) do |escalation_series|\n json.extract! escalation_series, :id, :name\n json.url escalati"
},
{
"path": "app/views/escalation_series/new.html.erb",
"chars": 106,
"preview": "<h1>New Escalation Series</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Back', escalation_series_index_path %>\n"
},
{
"path": "app/views/escalation_series/show.html.erb",
"chars": 477,
"preview": "\n<p>\n <strong>Name:</strong>\n <%= @escalation_series.name %>\n</p>\n\n<table class=\"table\">\n <% @escalation_series.escal"
},
{
"path": "app/views/escalation_series/show.json.jbuilder",
"chars": 71,
"preview": "json.extract! @escalation_series, :id, :name, :created_at, :updated_at\n"
},
{
"path": "app/views/escalations/_form.html.erb",
"chars": 945,
"preview": "<%= form_for(@escalation) do |f| %>\n <% if @escalation.errors.any? %>\n <div class=\"alert alert-danger\">\n <h2><%"
},
{
"path": "app/views/escalations/edit.html.erb",
"chars": 128,
"preview": "<h1>Editing Escalation</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Show', @escalation %> |\n<%= link_to 'Back', escalations_"
},
{
"path": "app/views/escalations/index.html.erb",
"chars": 782,
"preview": "\n<h1>Listing Escalations</h1>\n\n<table class=\"table\">\n <thead>\n <tr>\n <th>Escalation Series</th>\n <th>Escal"
},
{
"path": "app/views/escalations/index.json.jbuilder",
"chars": 192,
"preview": "json.array!(@escalations) do |escalation|\n json.extract! escalation, :id, :escalate_to_id, :escalate_after_sec, :escala"
},
{
"path": "app/views/escalations/new.html.erb",
"chars": 87,
"preview": "<h1>New Escalation</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Back', escalations_path %>\n"
},
{
"path": "app/views/escalations/show.html.erb",
"chars": 361,
"preview": "\n<p>\n <strong>Escalation series:</strong>\n <%= @escalation.escalation_series.name %>\n</p>\n\n<p>\n <strong>Escalate to:<"
},
{
"path": "app/views/escalations/show.json.jbuilder",
"chars": 95,
"preview": "json.extract! @escalation, :id, :escalate_to_id, :escalate_after_sec, :created_at, :updated_at\n"
},
{
"path": "app/views/home/index.html.erb",
"chars": 68,
"preview": "<h1>Home#index</h1>\n<p>Find me in app/views/home/index.html.erb</p>\n"
},
{
"path": "app/views/incident_events/twilio.html.erb",
"chars": 91,
"preview": "<h1>IncidentEvents#twilio</h1>\n<p>Find me in app/views/incident_events/twilio.html.erb</p>\n"
},
{
"path": "app/views/incidents/_form.html.erb",
"chars": 967,
"preview": "<%= form_for(@incident) do |f| %>\n <% if @incident.errors.any? %>\n <div class=\"alert alert-danger\">\n <h2><%= pl"
},
{
"path": "app/views/incidents/edit.html.erb",
"chars": 122,
"preview": "<h1>Editing Incident</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Show', @incident %> |\n<%= link_to 'Back', incidents_path %"
},
{
"path": "app/views/incidents/index.html.erb",
"chars": 3489,
"preview": "\n<h1>Listing Incidents</h1>\n\n<div class=\"btn-toolbar\" role=\"toolbar\" style=\"margin-bottom: 15px\">\n <div class=\"btn-grou"
},
{
"path": "app/views/incidents/index.json.jbuilder",
"chars": 169,
"preview": "json.array!(@incidents) do |incident|\n json.extract! incident, :id, :subject, :description, :topic_id, :occured_at\n js"
},
{
"path": "app/views/incidents/new.html.erb",
"chars": 83,
"preview": "<h1>New Incident</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Back', incidents_path %>\n"
},
{
"path": "app/views/incidents/show.html.erb",
"chars": 1279,
"preview": "\n<p>\n <strong>Subject:</strong>\n <%= @incident.subject %>\n</p>\n\n<p>\n <strong>Description:</strong>\n <pre><%= @incide"
},
{
"path": "app/views/incidents/show.json.jbuilder",
"chars": 103,
"preview": "json.extract! @incident, :id, :subject, :description, :topic_id, :occured_at, :created_at, :updated_at\n"
},
{
"path": "app/views/layouts/application.html.erb",
"chars": 2175,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <title>Waker</title>\n <%= stylesheet_link_tag 'application', media: 'all' %>\n <%= j"
},
{
"path": "app/views/maintenances/_form.html.erb",
"chars": 1011,
"preview": "<%= form_for(@maintenance) do |f| %>\n <% if @maintenance.errors.any? %>\n <div class=\"alert alert-danger\">\n <h2>"
},
{
"path": "app/views/maintenances/edit.html.erb",
"chars": 131,
"preview": "<h1>Editing Maintenance</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Show', @maintenance %> |\n<%= link_to 'Back', maintenanc"
},
{
"path": "app/views/maintenances/index.html.erb",
"chars": 871,
"preview": "\n<h1>Listing Maintenances</h1>\n\n<p>Expired maintanances are not shown</p>\n\n<table class=\"table\">\n <thead>\n <tr>\n "
},
{
"path": "app/views/maintenances/index.json.jbuilder",
"chars": 171,
"preview": "json.array!(@maintenances) do |maintenance|\n json.extract! maintenance, :id, :topic_id, :start_time, :end_time\n json.u"
},
{
"path": "app/views/maintenances/new.html.erb",
"chars": 89,
"preview": "<h1>New Maintenance</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Back', maintenances_path %>\n"
},
{
"path": "app/views/maintenances/show.html.erb",
"chars": 437,
"preview": "<p id=\"notice\"><%= notice %></p>\n\n<p>\n <strong>Topic:</strong>\n <%= @maintenance.topic.name %>\n</p>\n\n<p>\n <strong>Fil"
},
{
"path": "app/views/maintenances/show.json.jbuilder",
"chars": 93,
"preview": "json.extract! @maintenance, :id, :topic_id, :start_time, :end_time, :created_at, :updated_at\n"
},
{
"path": "app/views/notifier_providers/_form.html.erb",
"chars": 1070,
"preview": "<%= form_for(@notifier_provider) do |f| %>\n <% if @notifier_provider.errors.any? %>\n <div class=\"alert alert-danger\""
},
{
"path": "app/views/notifier_providers/edit.html.erb",
"chars": 149,
"preview": "<h1>Editing Notifier Provider</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Show', @notifier_provider %> |\n<%= link_to 'Back'"
},
{
"path": "app/views/notifier_providers/hipchat/acknowledged.text.erb",
"chars": 198,
"preview": "Incident acknowledged: <%= event.incident.subject %> (<a href=\"<%= Rails.application.routes.url_helpers.resolve_incident"
},
{
"path": "app/views/notifier_providers/hipchat/escalated.text.erb",
"chars": 382,
"preview": "Incident escalated to <%= event.escalated_to.name %>: <%= event.incident.subject %> (<a href=\"<%= Rails.application.rout"
},
{
"path": "app/views/notifier_providers/hipchat/opened.text.erb",
"chars": 349,
"preview": "New incident opened: <%= event.incident.subject %> (<a href=\"<%= Rails.application.routes.url_helpers.acknowledge_incide"
},
{
"path": "app/views/notifier_providers/hipchat/resolved.text.erb",
"chars": 49,
"preview": "Incident resolved: <%= event.incident.subject %>\n"
},
{
"path": "app/views/notifier_providers/index.html.erb",
"chars": 796,
"preview": "\n<h1>Listing Notifier Providers</h1>\n\n<table class=\"table\">\n <thead>\n <tr>\n <th>Name</th>\n <th>Kind</th>\n "
},
{
"path": "app/views/notifier_providers/index.json.jbuilder",
"chars": 191,
"preview": "json.array!(@notifier_providers) do |notifier_provider|\n json.extract! notifier_provider, :id, :name, :kind, :settings\n"
},
{
"path": "app/views/notifier_providers/mailgun/default.html.erb",
"chars": 1940,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initia"
},
{
"path": "app/views/notifier_providers/mailgun/default.text.erb",
"chars": 357,
"preview": "<%= event.incident.subject %>\n====\n\nActions:\n\n- To ack: <%= Rails.application.routes.url_helpers.acknowledge_incident_ur"
},
{
"path": "app/views/notifier_providers/new.html.erb",
"chars": 101,
"preview": "<h1>New Notifier Provider</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Back', notifier_providers_path %>\n"
},
{
"path": "app/views/notifier_providers/rails_logger/default.text.erb",
"chars": 32,
"preview": "Notification: <%= event.kind %>\n"
},
{
"path": "app/views/notifier_providers/show.html.erb",
"chars": 333,
"preview": "\n<p>\n <strong>Name:</strong>\n <%= @notifier_provider.name %>\n</p>\n\n<p>\n <strong>Kind:</strong>\n <%= @notifier_provid"
},
{
"path": "app/views/notifier_providers/show.json.jbuilder",
"chars": 89,
"preview": "json.extract! @notifier_provider, :id, :name, :kind, :settings, :created_at, :updated_at\n"
},
{
"path": "app/views/notifiers/_form.html.erb",
"chars": 1392,
"preview": "<%= form_for(@notifier) do |f| %>\n <% if @notifier.errors.any? %>\n <div class=\"alert alert-danger\">\n <h2><%= pl"
},
{
"path": "app/views/notifiers/edit.html.erb",
"chars": 122,
"preview": "<h1>Editing Notifier</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Show', @notifier %> |\n<%= link_to 'Back', notifiers_path %"
},
{
"path": "app/views/notifiers/index.html.erb",
"chars": 952,
"preview": "\n<h1>Listing Notifiers</h1>\n\n<table class=\"table\">\n <thead>\n <tr>\n <th>User</th>\n <th>Topic</th>\n <th"
},
{
"path": "app/views/notifiers/index.json.jbuilder",
"chars": 223,
"preview": "json.array!(@notifiers) do |notifier|\n json.extract! notifier, :id, :settings, :provider_id, :provider, :topic_id, :use"
},
{
"path": "app/views/notifiers/new.html.erb",
"chars": 83,
"preview": "<h1>New Notifier</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Back', notifiers_path %>\n"
},
{
"path": "app/views/notifiers/show.html.erb",
"chars": 548,
"preview": "\n<p>\n <strong>Provider:</strong>\n <%= @notifier.provider.name %>\n</p>\n\n<p>\n <strong>User:</strong>\n <%= @notifier.us"
},
{
"path": "app/views/notifiers/show.json.jbuilder",
"chars": 131,
"preview": "json.extract! @notifier, :id, :settings, :provider_id, :provider, :topic_id, :user_id, :notify_after_sec, :created_at, :"
},
{
"path": "app/views/sessions/create.html.erb",
"chars": 78,
"preview": "<h1>Sessions#create</h1>\n<p>Find me in app/views/sessions/create.html.erb</p>\n"
},
{
"path": "app/views/slack/interactive.html.erb",
"chars": 82,
"preview": "<h1>Slack#interactive</h1>\n<p>Find me in app/views/slack/interactive.html.erb</p>\n"
},
{
"path": "app/views/topics/_form.html.erb",
"chars": 1156,
"preview": "<%= form_for(@topic) do |f| %>\n <% if @topic.errors.any? %>\n <div class=\"alert alert-danger\">\n <h2><%= pluraliz"
},
{
"path": "app/views/topics/edit.html.erb",
"chars": 113,
"preview": "<h1>Editing Topic</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Show', @topic %> |\n<%= link_to 'Back', topics_path %>\n"
},
{
"path": "app/views/topics/index.html.erb",
"chars": 751,
"preview": "\n<h1>Listing Topics</h1>\n\n<table class=\"table\">\n <thead>\n <tr>\n <th>Name</th>\n <th>Kind</th>\n <th>Esc"
},
{
"path": "app/views/topics/index.json.jbuilder",
"chars": 120,
"preview": "json.array!(@topics) do |topic|\n json.extract! topic, :id, :name, :type\n json.url topic_url(topic, format: :json)\nend\n"
},
{
"path": "app/views/topics/new.html.erb",
"chars": 77,
"preview": "<h1>New Topic</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Back', topics_path %>\n"
},
{
"path": "app/views/topics/show.html.erb",
"chars": 799,
"preview": "\n<p>\n <strong>Name:</strong>\n <%= @topic.name %>\n</p>\n\n<p>\n <strong>Kind:</strong>\n <%= @topic.kind %>\n</p>\n\n<p>\n <"
},
{
"path": "app/views/topics/show.json.jbuilder",
"chars": 66,
"preview": "json.extract! @topic, :id, :name, :type, :created_at, :updated_at\n"
},
{
"path": "app/views/users/_form.html.erb",
"chars": 533,
"preview": "<%= form_for(@user) do |f| %>\n <% if @user.errors.any? %>\n <div class=\"alert alert-danger\">\n <h2><%= pluralize("
},
{
"path": "app/views/users/edit.html.erb",
"chars": 110,
"preview": "<h1>Editing User</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Show', @user %> |\n<%= link_to 'Back', users_path %>\n"
},
{
"path": "app/views/users/index.html.erb",
"chars": 940,
"preview": "\n<h1>Listing Users</h1>\n\n<table class=\"table\">\n <thead>\n <tr>\n <th>Name</th>\n <th>Status</th>\n <th co"
},
{
"path": "app/views/users/index.json.jbuilder",
"chars": 108,
"preview": "json.array!(@users) do |user|\n json.extract! user, :id, :name\n json.url user_url(user, format: :json)\nend\n"
},
{
"path": "app/views/users/new.html.erb",
"chars": 75,
"preview": "<h1>New User</h1>\n\n<%= render 'form' %>\n\n<%= link_to 'Back', users_path %>\n"
},
{
"path": "app/views/users/show.html.erb",
"chars": 206,
"preview": "\n<p>\n <strong>Name:</strong>\n <%= @user.name %>\n</p>\n\n<p>\n <strong>Provider:</strong>\n <%= @user.provider %>\n</p>\n\n<"
},
{
"path": "app/views/users/show.json.jbuilder",
"chars": 58,
"preview": "json.extract! @user, :id, :name, :created_at, :updated_at\n"
},
{
"path": "bin/bundle",
"chars": 129,
"preview": "#!/usr/bin/env ruby\nENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)\nload Gem.bin_path('bundler', '"
},
{
"path": "bin/rails",
"chars": 219,
"preview": "#!/usr/bin/env ruby\nbegin\n load File.expand_path(\"../spring\", __FILE__)\nrescue LoadError\nend\nAPP_PATH = File.expand_pat"
},
{
"path": "bin/rake",
"chars": 164,
"preview": "#!/usr/bin/env ruby\nbegin\n load File.expand_path(\"../spring\", __FILE__)\nrescue LoadError\nend\nrequire_relative '../confi"
},
{
"path": "bin/setup",
"chars": 805,
"preview": "#!/usr/bin/env ruby\nrequire 'pathname'\n\n# path to your application root.\nAPP_ROOT = Pathname.new File.expand_path('../.."
},
{
"path": "bin/spring",
"chars": 517,
"preview": "#!/usr/bin/env ruby\n\n# This file loads spring without using Bundler, in order to be fast\n# It gets overwritten when you "
},
{
"path": "config/application.rb",
"chars": 1816,
"preview": "require File.expand_path('../boot', __FILE__)\n\n# Pick the frameworks you want:\nrequire \"active_model/railtie\"\nrequire \"a"
},
{
"path": "config/boot.rb",
"chars": 132,
"preview": "ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)\n\nrequire 'bundler/setup' # Set up gems listed in t"
},
{
"path": "config/database.yml",
"chars": 629,
"preview": "production:\n adapter: mysql2\n database: waker\n encoding: utf8mb4\n username : <%= ENV['MYSQL_USER'] || 'root' %>\n pa"
},
{
"path": "config/environment.rb",
"chars": 150,
"preview": "# Load the Rails application.\nrequire File.expand_path('../application', __FILE__)\n\n# Initialize the Rails application.\n"
},
{
"path": "config/environments/development.rb",
"chars": 1673,
"preview": "Rails.application.configure do\n # Settings specified here will take precedence over those in config/application.rb.\n\n "
},
{
"path": "config/environments/production.rb",
"chars": 3629,
"preview": "Rails.application.configure do\n # Settings specified here will take precedence over those in config/application.rb.\n\n "
},
{
"path": "config/environments/test.rb",
"chars": 1755,
"preview": "Rails.application.configure do\n # Settings specified here will take precedence over those in config/application.rb.\n\n "
},
{
"path": "config/initializers/assets.rb",
"chars": 486,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Version of your assets, change this if you want to expire"
},
{
"path": "config/initializers/backtrace_silencers.rb",
"chars": 404,
"preview": "# Be sure to restart your server when you modify this file.\n\n# You can add backtrace silencers for libraries that you're"
},
{
"path": "config/initializers/cookies_serializer.rb",
"chars": 129,
"preview": "# Be sure to restart your server when you modify this file.\n\nRails.application.config.action_dispatch.cookies_serializer"
},
{
"path": "config/initializers/field_with_errors.rb",
"chars": 171,
"preview": "Rails.application.configure do\n config.action_view.field_error_proc = lambda do |html_tag, instance|\n %Q{<div class="
},
{
"path": "config/initializers/filter_parameter_logging.rb",
"chars": 194,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Configure sensitive parameters which will be filtered fro"
},
{
"path": "config/initializers/inflections.rb",
"chars": 647,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Add new inflection rules using the following format. Infl"
},
{
"path": "config/initializers/mime_types.rb",
"chars": 156,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Add new mime types for use in respond_to blocks:\n# Mime::"
},
{
"path": "config/initializers/omniauth.rb",
"chars": 38,
"preview": "OmniAuth.config.logger = Rails.logger\n"
},
{
"path": "config/initializers/session_store.rb",
"chars": 137,
"preview": "# Be sure to restart your server when you modify this file.\n\nRails.application.config.session_store :cookie_store, key: "
},
{
"path": "config/initializers/sidekiq.rb",
"chars": 427,
"preview": "namespace = ENV['REDIS_NAMESPACE'] || \"waker-#{Rails.env}\"\nhost = ENV['REDIS_HOST'] || 'localhost'\nport = ENV['REDIS_POR"
},
{
"path": "config/initializers/url_options.rb",
"chars": 239,
"preview": "if default_host = ENV['DEFAULT_HOST']\n Rails.application.routes.default_url_options[:host] = default_host\nend\n\nif defau"
},
{
"path": "config/initializers/wrap_parameters.rb",
"chars": 517,
"preview": "# Be sure to restart your server when you modify this file.\n\n# This file contains settings for ActionController::ParamsW"
},
{
"path": "config/locales/en.yml",
"chars": 634,
"preview": "# Files in the config/locales directory are used for internationalization\n# and are automatically loaded by Rails. If yo"
},
{
"path": "config/routes.rb",
"chars": 2641,
"preview": "Rails.application.routes.draw do\n post 'slack/interactive'\n\n get '/auth/:provider/callback', to: 'sessions#create'\n\n "
},
{
"path": "config/secrets.yml",
"chars": 964,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Your secret key is used for verifying the integrity of si"
},
{
"path": "config.ru",
"chars": 153,
"preview": "# This file is used by Rack-based servers to start the application.\n\nrequire ::File.expand_path('../config/environment',"
},
{
"path": "db/migrate/20150120134616_create_topics.rb",
"chars": 183,
"preview": "class CreateTopics < ActiveRecord::Migration\n def change\n create_table :topics do |t|\n t.string :name\n t.i"
},
{
"path": "db/migrate/20150120134747_create_users.rb",
"chars": 159,
"preview": "class CreateUsers < ActiveRecord::Migration\n def change\n create_table :users do |t|\n t.string :name\n\n t.ti"
},
{
"path": "db/migrate/20150120134905_create_notifiers.rb",
"chars": 225,
"preview": "class CreateNotifiers < ActiveRecord::Migration\n def change\n create_table :notifiers do |t|\n t.integer :type\n "
},
{
"path": "db/migrate/20150120135017_create_shifts.rb",
"chars": 214,
"preview": "class CreateShifts < ActiveRecord::Migration\n def change\n create_table :shifts do |t|\n t.references :user, inde"
},
{
"path": "db/migrate/20150120135123_create_escalations.rb",
"chars": 298,
"preview": "class CreateEscalations < ActiveRecord::Migration\n def change\n create_table :escalations do |t|\n t.references :"
},
{
"path": "db/migrate/20150120135244_create_escalation_series.rb",
"chars": 182,
"preview": "class CreateEscalationSeries < ActiveRecord::Migration\n def change\n create_table :escalation_series do |t|\n t.s"
},
{
"path": "db/migrate/20150120135351_add_escalation_series_to_escalation.rb",
"chars": 204,
"preview": "class AddEscalationSeriesToEscalation < ActiveRecord::Migration\n def change\n add_reference :escalations, :escalation"
},
{
"path": "db/migrate/20150120141627_rename_type_with_kind_of_topic.rb",
"chars": 121,
"preview": "class RenameTypeWithKindOfTopic < ActiveRecord::Migration\n def change\n rename_column :topics, :type, :kind\n end\nend"
},
{
"path": "db/migrate/20150120142452_create_incidents.rb",
"chars": 304,
"preview": "class CreateIncidents < ActiveRecord::Migration\n def change\n create_table :incidents do |t|\n t.string :subject\n"
}
]
// ... and 70 more files (download for full content)
About this extraction
This page contains the full source code of the ryotarai/waker GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 270 files (156.8 KB), approximately 50.7k tokens, and a symbol index with 338 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.