├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── pull_request_template.md
├── .gitignore
├── .pryrc
├── .reek.yml
├── .rubocop.yml
├── .ruby-version
├── .slugignore
├── .travis.yml
├── CHANGELOG.md
├── Gemfile
├── Gemfile.lock
├── LICENSE.md
├── Procfile
├── README.md
├── Rakefile
├── apiary.apib
├── app
├── admin
│ ├── admin_user.rb
│ ├── dashboard.rb
│ └── user.rb
├── assets
│ ├── config
│ │ └── manifest.js
│ ├── javascripts
│ │ ├── active_admin.js
│ │ └── application.js
│ └── stylesheets
│ │ ├── active_admin.scss
│ │ └── application.css
├── channels
│ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
├── controllers
│ ├── api
│ │ ├── concerns
│ │ │ └── act_as_api_request.rb
│ │ └── v1
│ │ │ ├── api_controller.rb
│ │ │ └── github_webhook_controller.rb
│ ├── application_controller.rb
│ └── concerns
│ │ └── .keep
├── jobs
│ └── application_job.rb
├── mailers
│ └── application_mailer.rb
├── models
│ ├── admin_user.rb
│ ├── application_record.rb
│ ├── concerns
│ │ └── .keep
│ └── user.rb
├── services
│ ├── pull_request.rb
│ ├── slack_bot.rb
│ └── slack_notification_service.rb
└── views
│ └── layouts
│ ├── mailer.html.haml
│ └── mailer.text.haml
├── bin
├── bundle
├── delayed_job
├── rails
├── rake
├── setup
├── spring
└── update
├── config.ru
├── config
├── application.rb
├── application.travis.yml
├── application.yml.example
├── boot.rb
├── cable.yml
├── database.travis.yml
├── database.yml.example
├── env_variables.rb
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ ├── staging.rb
│ └── test.rb
├── initializers
│ ├── active_admin.rb
│ ├── application_controller_renderer.rb
│ ├── backtrace_silencers.rb
│ ├── devise.rb
│ ├── filter_parameter_logging.rb
│ ├── inflections.rb
│ ├── mime_types.rb
│ ├── new_framework_defaults.rb
│ ├── rack_cors.rb
│ ├── slack.rb
│ └── wrap_parameters.rb
├── locales
│ ├── devise.en.yml
│ └── en.yml
├── puma.rb
├── rails_best_practices.yml
├── routes.rb
└── spring.rb
├── db
├── migrate
│ ├── 20161011151353_devise_create_users.rb
│ ├── 20161011184702_devise_create_admin_users.rb
│ ├── 20161017183759_add_devise_token_auth_fields_users.rb
│ ├── 20161027190856_create_delayed_jobs.rb
│ └── 20190418132233_modify_users.rb
├── schema.rb
└── seeds.rb
├── lib
└── tasks
│ ├── .keep
│ ├── add_blocklisted_user.rake
│ ├── auto_annotate_models.rake
│ ├── code_analysis.rake
│ └── rails_best_practices.rake
├── public
└── robots.txt
└── spec
├── admin
├── active_admin_spec.rb
└── controllers
│ └── users_controller_spec.rb
├── factories
├── spec.rb
└── user.rb
├── helpers.rb
├── models
└── user_spec.rb
├── rails_helper.rb
├── requests
└── api
│ └── v1
│ └── github_webhook
│ └── filter_spec.rb
├── services
├── slack_bot_spec.rb
└── slack_notification_service_spec.rb
└── spec_helper.rb
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at anthony@rootstrap.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing ##
2 |
3 | You can contribute to this repo if you have an issue, found a bug or think there's some functionality required that would add value to the gem. To do so, please check if there's not already an [issue](https://github.com/rootstrap/pull_requests_to_slack/issues) for that, if you find there's not, create a new one with as much detail as possible.
4 |
5 | If you want to contribute with code as well, please follow the next steps:
6 |
7 | 1. Read, understand and agree to our [code of conduct](https://github.com/rootstrap/pull_requests_to_slack/blob/master/CODE_OF_CONDUCT.md)
8 | 2. [Fork the repo](https://help.github.com/articles/about-forks/)
9 | 3. Clone the project into your machine:
10 | `$ git clone git@github.com:rootstrap/pull_requests_to_slack.git`
11 | 4. Access the repo:
12 | `$ cd pull_requests_to_slack`
13 | 5. Create your feature/bugfix branch:
14 | `$ git checkout -b your_new_feature`
15 | or
16 | `$ git checkout -b fix/your_fix` in case of a bug fix
17 | (if your PR is to address an existing issue, it would be good to name the branch after the issue, for example: if you are trying to solve issue 182, then a good idea for the branch name would be `182_your_new_feature`)
18 | 6. Write tests for your changes (feature/bug)
19 | 7. Code your (feature/bugfix)
20 | 8. Run the code analysis tool by doing:
21 | `$ rake code_analysis`
22 | 9. Run the tests:
23 | `$ bundle exec rspec`
24 | All tests must pass. If all tests (both code analysis and rspec) do pass, then you are ready to go to the next step:
25 | 10. Commit your changes:
26 | `$ git commit -m 'Your feature or bugfix title'`
27 | 11. Push to the branch `$ git push origin your_new_feature`
28 | 12. Create a new [pull request](https://help.github.com/articles/creating-a-pull-request/)
29 |
30 | Some helpful guides that will help you know how we work:
31 | 1. [Code review](https://github.com/rootstrap/tech-guides/tree/master/code-review)
32 | 2. [GIT workflow](https://github.com/rootstrap/tech-guides/tree/master/git)
33 | 3. [Ruby style guide](https://github.com/rootstrap/tech-guides/tree/master/ruby)
34 | 4. [Rails style guide](https://github.com/rootstrap/tech-guides/blob/master/ruby/rails.md)
35 | 5. [RSpec style guide](https://github.com/rootstrap/tech-guides/blob/master/ruby/rspec/README.md)
36 |
37 | For more information or guides like the ones mentioned above, please check our [tech guides](https://github.com/rootstrap/tech-guides). Keep in mind that the more you know about these guides, the easier it will be for your code to get approved and merged.
38 |
39 | Note: You can push as many commits as you want when working on a pull request, we just ask that they are descriptive and tell a story. Try to open a pull request with just one commit but if you think you need to divide what you did into more commits to convey what you are trying to do go for it.
40 |
41 | Thank you very much for your time and for considering helping in this project.
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | When posting issues, please include the following information to speed up the troubleshooting process:
2 |
3 | * **Version**: which version of this repo do you have?
4 | * **Ruby Version**: which version of ruby do you have?
5 | * **Environment**: in which env is happening?
6 | * **Rails Stacktrace**: this can be found in the `log/development.log` or `log/test.log`, if this is applicable.
7 |
8 | Use labels to categorize it and thanks for posting the issue!
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[Bug] "
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Bug report:
11 | * **Expected Behavior**:
12 | * **Actual Behavior**:
13 | * **Steps to Reproduce**:
14 | 1.
15 | 2.
16 | 3.
17 |
18 | * **Version of the repo**:
19 | * **Ruby and Rails Version**:
20 | * **Rails Stacktrace**: this can be found in the `log/development.log` or `log/test.log`, if this is applicable.
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: '[FEATURE]'
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
11 |
12 | **Is your feature request related to a problem? Please describe.**
13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
14 |
15 | **Describe the solution you'd like**
16 | A clear and concise description of what you want to happen.
17 |
18 | **Describe alternatives you've considered**
19 | A clear and concise description of any alternative solutions or features you've considered.
20 |
21 | **Additional context**
22 | Add any other context or screenshots about the feature request here.
23 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ### Summary
2 |
3 |
7 |
8 | ### Other Information
9 |
10 |
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /config/database.yml
2 | *.rbc
3 | *.swp
4 | capybara-*.html
5 | .rspec
6 | /log
7 | /tmp
8 | /db/*.sqlite3
9 | /public/system
10 | /coverage/
11 | /spec/tmp
12 | .idea/
13 | .DS_Store
14 | **.orig
15 | rerun.txt
16 | pickle-email-*.html
17 | config/initializers/secret_token.rb
18 | config/secrets.yml
19 | config/application.yml
20 |
21 | ## Environment normalisation:
22 | /.bundle
23 | /vendor/bundle
24 |
25 | # these should all be checked in to normalise the environment:
26 | # Gemfile.lock, .ruby-version, .ruby-gemset
27 |
28 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
29 | .rvmrc
30 |
31 | # Ignore byebug history
32 | .byebug_history
33 |
--------------------------------------------------------------------------------
/.pryrc:
--------------------------------------------------------------------------------
1 | if defined?(PryByebug)
2 | Pry.commands.alias_command 'c', 'continue'
3 | Pry.commands.alias_command 's', 'step'
4 | Pry.commands.alias_command 'n', 'next'
5 | Pry.commands.alias_command 'f', 'finish'
6 | end
7 |
--------------------------------------------------------------------------------
/.reek.yml:
--------------------------------------------------------------------------------
1 | detectors:
2 | Attribute:
3 | enabled: false
4 | exclude: []
5 | BooleanParameter:
6 | enabled: true
7 | exclude: []
8 | ClassVariable:
9 | enabled: false
10 | exclude: []
11 | ControlParameter:
12 | enabled: true
13 | exclude: []
14 | DataClump:
15 | enabled: true
16 | exclude: []
17 | max_copies: 2
18 | min_clump_size: 2
19 | DuplicateMethodCall:
20 | enabled: true
21 | exclude: []
22 | max_calls: 1
23 | allow_calls: []
24 | FeatureEnvy:
25 | enabled: true
26 | exclude:
27 | - "SlackBot#message"
28 | InstanceVariableAssumption:
29 | enabled: false
30 | IrresponsibleModule:
31 | enabled: false
32 | exclude: []
33 | LongParameterList:
34 | enabled: true
35 | exclude: []
36 | max_params: 4
37 | overrides:
38 | initialize:
39 | max_params: 5
40 | LongYieldList:
41 | enabled: true
42 | exclude: []
43 | max_params: 3
44 | ManualDispatch:
45 | enabled: true
46 | exclude: []
47 | MissingSafeMethod:
48 | enabled: false
49 | exclude: []
50 | ModuleInitialize:
51 | enabled: true
52 | exclude: []
53 | NestedIterators:
54 | enabled: true
55 | exclude: []
56 | max_allowed_nesting: 2
57 | ignore_iterators: []
58 | NilCheck:
59 | enabled: false
60 | exclude: []
61 | RepeatedConditional:
62 | enabled: true
63 | exclude: []
64 | max_ifs: 3
65 | SubclassedFromCoreClass:
66 | enabled: true
67 | exclude: []
68 | TooManyConstants:
69 | enabled: true
70 | exclude: []
71 | max_constants: 5
72 | TooManyInstanceVariables:
73 | enabled: true
74 | exclude: []
75 | max_instance_variables: 9
76 | TooManyMethods:
77 | enabled: true
78 | exclude: []
79 | max_methods: 25
80 | TooManyStatements:
81 | enabled: true
82 | exclude:
83 | - initialize
84 | max_statements: 12
85 | UncommunicativeMethodName:
86 | enabled: true
87 | exclude: []
88 | reject:
89 | - "/^[a-z]$/"
90 | - "/[0-9]$/"
91 | - "/[A-Z]/"
92 | accept: []
93 | UncommunicativeModuleName:
94 | enabled: true
95 | exclude: []
96 | reject:
97 | - "/^.$/"
98 | - "/[0-9]$/"
99 | accept:
100 | - Inline::C
101 | - "/V[0-9]/"
102 | UncommunicativeParameterName:
103 | enabled: true
104 | exclude: []
105 | reject:
106 | - "/^.$/"
107 | - "/[0-9]$/"
108 | - "/[A-Z]/"
109 | accept: []
110 | UncommunicativeVariableName:
111 | enabled: false
112 | exclude: []
113 | reject:
114 | - "/^.$/"
115 | - "/[0-9]$/"
116 | - "/[A-Z]/"
117 | accept:
118 | - _
119 | UnusedParameters:
120 | enabled: true
121 | exclude: []
122 | UnusedPrivateMethod:
123 | enabled: false
124 | UtilityFunction:
125 | enabled: false
126 |
127 | exclude_paths:
128 | - config
129 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | Documentation:
2 | Enabled: false
3 |
4 | Layout/ArgumentAlignment:
5 | Exclude:
6 | - config/initializers/rack_cors.rb
7 |
8 | Layout/HashAlignment:
9 | Exclude:
10 | - lib/tasks/auto_annotate_models.rake
11 |
12 | Layout/SpaceBeforeFirstArg:
13 | Exclude:
14 | - app/views/api/**/**/*
15 |
16 | Lint/AmbiguousBlockAssociation:
17 | Exclude:
18 | - spec/**/*
19 |
20 | Metrics/AbcSize:
21 | # The ABC size is a calculated magnitude, so this number can be an Integer or
22 | # a Float.
23 | Max: 15
24 |
25 | Metrics/BlockLength:
26 | CountComments: false # count full line comments?
27 | Max: 25
28 | Exclude:
29 | - config/**/*
30 | - spec/**/*
31 | - app/admin/**/*
32 |
33 | Metrics/BlockNesting:
34 | Max: 4
35 |
36 | Metrics/ClassLength:
37 | CountComments: false # count full line comments?
38 | Max: 200
39 |
40 | # Avoid complex methods.
41 | Metrics/CyclomaticComplexity:
42 | Max: 6
43 |
44 | Metrics/MethodLength:
45 | CountComments: false # count full line comments?
46 | Max: 24
47 |
48 | Metrics/ModuleLength:
49 | CountComments: false # count full line comments?
50 | Max: 200
51 |
52 | Metrics/LineLength:
53 | Max: 100
54 | # To make it possible to copy or click on URIs in the code, we allow lines
55 | # containing a URI to be longer than Max.
56 | AllowURI: true
57 | URISchemes:
58 | - http
59 | - https
60 |
61 | Metrics/ParameterLists:
62 | Max: 5
63 | CountKeywordArgs: true
64 |
65 | Metrics/PerceivedComplexity:
66 | Max: 12
67 |
68 | Style/FrozenStringLiteralComment:
69 | Enabled: false
70 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.7.2
2 |
--------------------------------------------------------------------------------
/.slugignore:
--------------------------------------------------------------------------------
1 | /spec
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 |
3 | cache: bundler
4 |
5 | before_install: gem install bundler -v 1.17
6 |
7 | rvm:
8 | - 2.6.3
9 |
10 | sudo: false
11 |
12 | services:
13 | - postgresql
14 |
15 | addons:
16 | postgresql: "9.4"
17 |
18 | env:
19 | global:
20 | - CC_TEST_REPORTER_ID=54db504b0c710f8ec07866e91808973e20566c7018b7b0d13ad2e40227c23c79
21 |
22 | before_script:
23 | - cp config/database.travis.yml config/database.yml
24 | - cp config/application.travis.yml config/application.yml
25 | - RAILS_ENV=test bundle exec rake db:create
26 | - RAILS_ENV=test bundle exec rake db:schema:load
27 | - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
28 | - chmod +x ./cc-test-reporter
29 | - ./cc-test-reporter before-build
30 |
31 | script:
32 | - bundle exec rake code_analysis
33 | - bundle exec rspec
34 |
35 | after_script:
36 | - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
37 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [v1.0.0](https://github.com/rootstrap/rails_api_base/tree/v1.0.0) (2017-09-22)
4 | **Implemented enhancements:**
5 |
6 | - Fix Code Climate Issues [\#88](https://github.com/rootstrap/rails_api_base/issues/88)
7 | - Increase version of rubocop [\#78](https://github.com/rootstrap/rails_api_base/issues/78)
8 | - Add carrierwave base 64 uploader [\#65](https://github.com/rootstrap/rails_api_base/issues/65)
9 | - Configure automatic deploy to heroku [\#62](https://github.com/rootstrap/rails_api_base/issues/62)
10 | - Add bullet to detect N+1 queries [\#60](https://github.com/rootstrap/rails_api_base/issues/60)
11 | - Migrate facebook mock to webmock [\#49](https://github.com/rootstrap/rails_api_base/issues/49)
12 | - Migrate to requests tests [\#45](https://github.com/rootstrap/rails_api_base/issues/45)
13 | - Use single resource \('user'\) instead of 'users/me' in routes [\#33](https://github.com/rootstrap/rails_api_base/issues/33)
14 | - Add shoulda [\#26](https://github.com/rootstrap/rails_api_base/issues/26)
15 | - Add api doc [\#25](https://github.com/rootstrap/rails_api_base/issues/25)
16 | - Removed email default value, now facebook users should use null, vali… [\#41](https://github.com/rootstrap/rails_api_base/pull/41) ([felipegarcia92](https://github.com/felipegarcia92))
17 | - Fixed readme instructions [\#39](https://github.com/rootstrap/rails_api_base/pull/39) ([felipegarcia92](https://github.com/felipegarcia92))
18 |
19 | **Fixed bugs:**
20 |
21 | - Increase version of rubocop [\#78](https://github.com/rootstrap/rails_api_base/issues/78)
22 | - Devise Token Auth Issue: IndexError: string not matched [\#73](https://github.com/rootstrap/rails_api_base/issues/73)
23 | - ENV variables aren't loaded yet in application.rb [\#66](https://github.com/rootstrap/rails_api_base/issues/66)
24 | - ActiveAdmin panel for users should require password [\#61](https://github.com/rootstrap/rails_api_base/issues/61)
25 | - ActionDispatch::Cookies::CookieOverflow [\#42](https://github.com/rootstrap/rails_api_base/issues/42)
26 | - Sign Up is wrongly requiring an "Accept: application/json" header to work [\#40](https://github.com/rootstrap/rails_api_base/issues/40)
27 | - In update password, the user isn't being set with the headers [\#30](https://github.com/rootstrap/rails_api_base/issues/30)
28 | - Removed email default value, now facebook users should use null, vali… [\#41](https://github.com/rootstrap/rails_api_base/pull/41) ([felipegarcia92](https://github.com/felipegarcia92))
29 |
30 | **Closed issues:**
31 |
32 | - Add/Define a new code\_climate.yml file. [\#91](https://github.com/rootstrap/rails_api_base/issues/91)
33 | - Remove Facebook revert line from readme [\#75](https://github.com/rootstrap/rails_api_base/issues/75)
34 | - Add api doc [\#24](https://github.com/rootstrap/rails_api_base/issues/24)
35 |
36 | **Merged pull requests:**
37 |
38 | - Add ratings config to Code Climate file [\#93](https://github.com/rootstrap/rails_api_base/pull/93) ([MaicolBen](https://github.com/MaicolBen))
39 | - Add Code Climate config file [\#92](https://github.com/rootstrap/rails_api_base/pull/92) ([MaicolBen](https://github.com/MaicolBen))
40 | - Import devise token auth using https [\#90](https://github.com/rootstrap/rails_api_base/pull/90) ([matiasmansilla1989](https://github.com/matiasmansilla1989))
41 | - Add badges [\#87](https://github.com/rootstrap/rails_api_base/pull/87) ([MaicolBen](https://github.com/MaicolBen))
42 | - Update devise token auth reference [\#85](https://github.com/rootstrap/rails_api_base/pull/85) ([diebarral](https://github.com/diebarral))
43 | - Fix api docs and add license [\#84](https://github.com/rootstrap/rails_api_base/pull/84) ([MaicolBen](https://github.com/MaicolBen))
44 | - Add list of features to README [\#82](https://github.com/rootstrap/rails_api_base/pull/82) ([santiagovidal](https://github.com/santiagovidal))
45 | - Remove old comment in password update spec [\#80](https://github.com/rootstrap/rails_api_base/pull/80) ([santiagovidal](https://github.com/santiagovidal))
46 | - Update rubocop and reek version [\#79](https://github.com/rootstrap/rails_api_base/pull/79) ([gabrielbursztein](https://github.com/gabrielbursztein))
47 | - Add gems to readme [\#76](https://github.com/rootstrap/rails_api_base/pull/76) ([MaicolBen](https://github.com/MaicolBen))
48 | - remove refactor tag and fix rspec test [\#74](https://github.com/rootstrap/rails_api_base/pull/74) ([GuilleLeopold](https://github.com/GuilleLeopold))
49 | - Migrate erb to haml & clean code [\#72](https://github.com/rootstrap/rails_api_base/pull/72) ([MaicolBen](https://github.com/MaicolBen))
50 | - Add password for new users in admin [\#68](https://github.com/rootstrap/rails_api_base/pull/68) ([MaicolBen](https://github.com/MaicolBen))
51 | - Add carrierwave-base64 [\#67](https://github.com/rootstrap/rails_api_base/pull/67) ([MaicolBen](https://github.com/MaicolBen))
52 | - Fix tilt engine for heroku [\#64](https://github.com/rootstrap/rails_api_base/pull/64) ([MaicolBen](https://github.com/MaicolBen))
53 | - Upgrade rails to 5.1.2 & Add bullet [\#63](https://github.com/rootstrap/rails_api_base/pull/63) ([MaicolBen](https://github.com/MaicolBen))
54 | - Fix wrong parameter after add error logging [\#59](https://github.com/rootstrap/rails_api_base/pull/59) ([MaicolBen](https://github.com/MaicolBen))
55 | - Added 500 handler & make facebook webmock more flexible [\#58](https://github.com/rootstrap/rails_api_base/pull/58) ([MaicolBen](https://github.com/MaicolBen))
56 | - Allow user registration to receive first and last name [\#57](https://github.com/rootstrap/rails_api_base/pull/57) ([santiagovidal](https://github.com/santiagovidal))
57 | - Add staging environment [\#56](https://github.com/rootstrap/rails_api_base/pull/56) ([MaicolBen](https://github.com/MaicolBen))
58 | - Fix repeated email validation message [\#54](https://github.com/rootstrap/rails_api_base/pull/54) ([MaicolBen](https://github.com/MaicolBen))
59 | - allow\_indentation\_for\_json\_responses [\#52](https://github.com/rootstrap/rails_api_base/pull/52) ([adicaff](https://github.com/adicaff))
60 | - Enable mail errors in development [\#51](https://github.com/rootstrap/rails_api_base/pull/51) ([MaicolBen](https://github.com/MaicolBen))
61 | - Migrate facebook mock to webmock [\#50](https://github.com/rootstrap/rails_api_base/pull/50) ([MaicolBen](https://github.com/MaicolBen))
62 | - Migrate controller test to request/routing tests [\#48](https://github.com/rootstrap/rails_api_base/pull/48) ([MaicolBen](https://github.com/MaicolBen))
63 | - Fix ActionDispatch::Cookies::CookieOverflow in facebook login [\#46](https://github.com/rootstrap/rails_api_base/pull/46) ([MaicolBen](https://github.com/MaicolBen))
64 | - Use user single resources instead of /users/me [\#44](https://github.com/rootstrap/rails_api_base/pull/44) ([MaicolBen](https://github.com/MaicolBen))
65 | - Change token configuration for devise token auth [\#43](https://github.com/rootstrap/rails_api_base/pull/43) ([MaicolBen](https://github.com/MaicolBen))
66 | - Set uid as email if the provider is email [\#38](https://github.com/rootstrap/rails_api_base/pull/38) ([MaicolBen](https://github.com/MaicolBen))
67 | - Add code coverage [\#37](https://github.com/rootstrap/rails_api_base/pull/37) ([MaicolBen](https://github.com/MaicolBen))
68 | - Ignore test files for the heroku slug [\#36](https://github.com/rootstrap/rails_api_base/pull/36) ([MaicolBen](https://github.com/MaicolBen))
69 | - Add api-blueprint standard documentation [\#35](https://github.com/rootstrap/rails_api_base/pull/35) ([matiasmansilla1989](https://github.com/matiasmansilla1989))
70 | - Add webmock and shoulda [\#34](https://github.com/rootstrap/rails_api_base/pull/34) ([MaicolBen](https://github.com/MaicolBen))
71 | - Use symbols instead of strings in parsed responses in tests [\#32](https://github.com/rootstrap/rails_api_base/pull/32) ([MaicolBen](https://github.com/MaicolBen))
72 | - skip tests that are having inappropriate behavior [\#31](https://github.com/rootstrap/rails_api_base/pull/31) ([GAKINDUSTRIES](https://github.com/GAKINDUSTRIES))
73 | - add exception to protect\_from\_forgery method and add skip verify\_auth… [\#29](https://github.com/rootstrap/rails_api_base/pull/29) ([GAKINDUSTRIES](https://github.com/GAKINDUSTRIES))
74 | - add byebug history to gitgnore [\#28](https://github.com/rootstrap/rails_api_base/pull/28) ([GAKINDUSTRIES](https://github.com/GAKINDUSTRIES))
75 | - Move authenticate user callback to api controller [\#27](https://github.com/rootstrap/rails_api_base/pull/27) ([MaicolBen](https://github.com/MaicolBen))
76 | - Removed deprecation warning about mime types [\#22](https://github.com/rootstrap/rails_api_base/pull/22) ([MaicolBen](https://github.com/MaicolBen))
77 | - Fix typo in sendgrid config [\#21](https://github.com/rootstrap/rails_api_base/pull/21) ([MaicolBen](https://github.com/MaicolBen))
78 | - add break to carrierwave [\#20](https://github.com/rootstrap/rails_api_base/pull/20) ([GuilleLeopold](https://github.com/GuilleLeopold))
79 | - Fix token auth persist [\#19](https://github.com/rootstrap/rails_api_base/pull/19) ([juanlacruz](https://github.com/juanlacruz))
80 | - Remove devise cookie storage in api [\#18](https://github.com/rootstrap/rails_api_base/pull/18) ([MaicolBen](https://github.com/MaicolBen))
81 | - Add login with facebook [\#16](https://github.com/rootstrap/rails_api_base/pull/16) ([MaicolBen](https://github.com/MaicolBen))
82 | - Added missing configuration [\#15](https://github.com/rootstrap/rails_api_base/pull/15) ([MaicolBen](https://github.com/MaicolBen))
83 | - Added carrierawave, delayed job and draper [\#14](https://github.com/rootstrap/rails_api_base/pull/14) ([MaicolBen](https://github.com/MaicolBen))
84 | - Added sengrid [\#13](https://github.com/rootstrap/rails_api_base/pull/13) ([MaicolBen](https://github.com/MaicolBen))
85 | - Add reset password tests [\#12](https://github.com/rootstrap/rails_api_base/pull/12) ([MaicolBen](https://github.com/MaicolBen))
86 | - Add users show/update [\#11](https://github.com/rootstrap/rails_api_base/pull/11) ([MaicolBen](https://github.com/MaicolBen))
87 | - Added sign in and logout [\#10](https://github.com/rootstrap/rails_api_base/pull/10) ([MaicolBen](https://github.com/MaicolBen))
88 | - Add signup [\#9](https://github.com/rootstrap/rails_api_base/pull/9) ([MaicolBen](https://github.com/MaicolBen))
89 | - Added rspec, factory girl, faker and database cleanner [\#8](https://github.com/rootstrap/rails_api_base/pull/8) ([MaicolBen](https://github.com/MaicolBen))
90 | - Add useful gems [\#7](https://github.com/rootstrap/rails_api_base/pull/7) ([MaicolBen](https://github.com/MaicolBen))
91 | - Add Active Admin [\#6](https://github.com/rootstrap/rails_api_base/pull/6) ([MaicolBen](https://github.com/MaicolBen))
92 | - Added devise [\#5](https://github.com/rootstrap/rails_api_base/pull/5) ([MaicolBen](https://github.com/MaicolBen))
93 | - Added CORS config [\#4](https://github.com/rootstrap/rails_api_base/pull/4) ([MaicolBen](https://github.com/MaicolBen))
94 | - Setup database [\#3](https://github.com/rootstrap/rails_api_base/pull/3) ([MaicolBen](https://github.com/MaicolBen))
95 | - Added code analysis [\#2](https://github.com/rootstrap/rails_api_base/pull/2) ([MaicolBen](https://github.com/MaicolBen))
96 | - Setup project [\#1](https://github.com/rootstrap/rails_api_base/pull/1) ([MaicolBen](https://github.com/MaicolBen))
97 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | ruby '~> 3.1.3'
3 |
4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
5 | gem 'rails', '~> 6.1.7', '>= 6.1.7.1'
6 |
7 | gem 'activeadmin', '~> 2.9'
8 | gem 'devise', '~> 4.7', '>= 4.7.2'
9 | gem 'pg', '~> 1.1', '>= 1.1.4'
10 | gem 'puma', '~> 5.6.2'
11 | gem 'rack-cors', '~> 1.0', '>= 1.0.6'
12 | gem 'sass-rails', '~> 5.1'
13 | gem 'slack-ruby-client', '~> 2.0.0'
14 | gem 'sprockets', '~> 3.7.2'
15 |
16 | group :development, :test do
17 | gem 'bullet', '~> 6.1'
18 | gem 'factory_bot_rails', '~> 6.2.0'
19 | gem 'pry-byebug', '~> 3.10.1', platform: :mri
20 | gem 'pry-rails', '~> 0.3.9'
21 | gem 'rspec-core', '~> 3.12.2'
22 | gem 'rspec-rails', '~> 6.0.1'
23 | end
24 |
25 | group :development do
26 | gem 'annotate', '~> 3.0', '>= 3.0.3'
27 | gem 'better_errors', '~> 2.8.0'
28 | gem 'brakeman', '~> 4.7.1'
29 | gem 'letter_opener', '~> 1.7'
30 | gem 'listen', '~> 3.2'
31 | gem 'rails_best_practices', '~> 1.19.4'
32 | gem 'reek', '~> 5.5'
33 | gem 'rubocop-rails', '~> 2.3.2'
34 | gem 'spring', '~> 2.1.0'
35 | gem 'spring-watcher-listen', '~> 2.0.0'
36 | end
37 |
38 | group :test do
39 | gem 'database_cleaner', '~> 1.4.1'
40 | gem 'faker', '~> 2.13'
41 | gem 'simplecov', '~> 0.13.0', require: false
42 | gem 'webmock', '~> 2.3.2'
43 | end
44 |
45 | group :assets do
46 | gem 'uglifier', '~> 4.2'
47 | end
48 |
49 | gem "ruby-lsp", "~> 0.3.8", :group => :development
50 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | actioncable (6.1.7.3)
5 | actionpack (= 6.1.7.3)
6 | activesupport (= 6.1.7.3)
7 | nio4r (~> 2.0)
8 | websocket-driver (>= 0.6.1)
9 | actionmailbox (6.1.7.3)
10 | actionpack (= 6.1.7.3)
11 | activejob (= 6.1.7.3)
12 | activerecord (= 6.1.7.3)
13 | activestorage (= 6.1.7.3)
14 | activesupport (= 6.1.7.3)
15 | mail (>= 2.7.1)
16 | actionmailer (6.1.7.3)
17 | actionpack (= 6.1.7.3)
18 | actionview (= 6.1.7.3)
19 | activejob (= 6.1.7.3)
20 | activesupport (= 6.1.7.3)
21 | mail (~> 2.5, >= 2.5.4)
22 | rails-dom-testing (~> 2.0)
23 | actionpack (6.1.7.3)
24 | actionview (= 6.1.7.3)
25 | activesupport (= 6.1.7.3)
26 | rack (~> 2.0, >= 2.0.9)
27 | rack-test (>= 0.6.3)
28 | rails-dom-testing (~> 2.0)
29 | rails-html-sanitizer (~> 1.0, >= 1.2.0)
30 | actiontext (6.1.7.3)
31 | actionpack (= 6.1.7.3)
32 | activerecord (= 6.1.7.3)
33 | activestorage (= 6.1.7.3)
34 | activesupport (= 6.1.7.3)
35 | nokogiri (>= 1.8.5)
36 | actionview (6.1.7.3)
37 | activesupport (= 6.1.7.3)
38 | builder (~> 3.1)
39 | erubi (~> 1.4)
40 | rails-dom-testing (~> 2.0)
41 | rails-html-sanitizer (~> 1.1, >= 1.2.0)
42 | activeadmin (2.13.1)
43 | arbre (~> 1.2, >= 1.2.1)
44 | formtastic (>= 3.1, < 5.0)
45 | formtastic_i18n (~> 0.4)
46 | inherited_resources (~> 1.7)
47 | jquery-rails (~> 4.2)
48 | kaminari (~> 1.0, >= 1.2.1)
49 | railties (>= 6.1, < 7.1)
50 | ransack (>= 2.1.1, < 4)
51 | activejob (6.1.7.3)
52 | activesupport (= 6.1.7.3)
53 | globalid (>= 0.3.6)
54 | activemodel (6.1.7.3)
55 | activesupport (= 6.1.7.3)
56 | activerecord (6.1.7.3)
57 | activemodel (= 6.1.7.3)
58 | activesupport (= 6.1.7.3)
59 | activestorage (6.1.7.3)
60 | actionpack (= 6.1.7.3)
61 | activejob (= 6.1.7.3)
62 | activerecord (= 6.1.7.3)
63 | activesupport (= 6.1.7.3)
64 | marcel (~> 1.0)
65 | mini_mime (>= 1.1.0)
66 | activesupport (6.1.7.3)
67 | concurrent-ruby (~> 1.0, >= 1.0.2)
68 | i18n (>= 1.6, < 2)
69 | minitest (>= 5.1)
70 | tzinfo (~> 2.0)
71 | zeitwerk (~> 2.3)
72 | addressable (2.8.4)
73 | public_suffix (>= 2.0.2, < 6.0)
74 | annotate (3.2.0)
75 | activerecord (>= 3.2, < 8.0)
76 | rake (>= 10.4, < 14.0)
77 | arbre (1.5.0)
78 | activesupport (>= 3.0.0, < 7.1)
79 | ruby2_keywords (>= 0.0.2, < 1.0)
80 | ast (2.4.2)
81 | bcrypt (3.1.18)
82 | better_errors (2.8.3)
83 | coderay (>= 1.0.0)
84 | erubi (>= 1.0.0)
85 | rack (>= 0.9.0)
86 | brakeman (4.7.2)
87 | builder (3.2.4)
88 | bullet (6.1.5)
89 | activesupport (>= 3.0.0)
90 | uniform_notifier (~> 1.11)
91 | byebug (11.1.3)
92 | code_analyzer (0.5.5)
93 | sexp_processor
94 | codeclimate-engine-rb (0.4.2)
95 | coderay (1.1.3)
96 | concurrent-ruby (1.2.2)
97 | crack (0.4.5)
98 | rexml
99 | crass (1.0.6)
100 | database_cleaner (1.4.1)
101 | date (3.3.3)
102 | devise (4.9.2)
103 | bcrypt (~> 3.0)
104 | orm_adapter (~> 0.1)
105 | railties (>= 4.1.0)
106 | responders
107 | warden (~> 1.2.3)
108 | diff-lcs (1.5.0)
109 | docile (1.1.5)
110 | erubi (1.12.0)
111 | erubis (2.7.0)
112 | execjs (2.8.1)
113 | factory_bot (6.2.1)
114 | activesupport (>= 5.0.0)
115 | factory_bot_rails (6.2.0)
116 | factory_bot (~> 6.2.0)
117 | railties (>= 5.0.0)
118 | faker (2.23.0)
119 | i18n (>= 1.8.11, < 2)
120 | faraday (2.7.4)
121 | faraday-net_http (>= 2.0, < 3.1)
122 | ruby2_keywords (>= 0.0.4)
123 | faraday-mashify (0.1.1)
124 | faraday (~> 2.0)
125 | hashie
126 | faraday-multipart (1.0.4)
127 | multipart-post (~> 2)
128 | faraday-net_http (3.0.2)
129 | ffi (1.15.5)
130 | formtastic (4.0.0)
131 | actionpack (>= 5.2.0)
132 | formtastic_i18n (0.7.0)
133 | gli (2.21.0)
134 | globalid (1.1.0)
135 | activesupport (>= 5.0)
136 | has_scope (0.8.1)
137 | actionpack (>= 5.2)
138 | activesupport (>= 5.2)
139 | hashdiff (1.0.1)
140 | hashie (5.0.0)
141 | i18n (1.12.0)
142 | concurrent-ruby (~> 1.0)
143 | inherited_resources (1.13.1)
144 | actionpack (>= 5.2, < 7.1)
145 | has_scope (~> 0.6)
146 | railties (>= 5.2, < 7.1)
147 | responders (>= 2, < 4)
148 | jquery-rails (4.5.1)
149 | rails-dom-testing (>= 1, < 3)
150 | railties (>= 4.2.0)
151 | thor (>= 0.14, < 2.0)
152 | json (2.6.3)
153 | kaminari (1.2.2)
154 | activesupport (>= 4.1.0)
155 | kaminari-actionview (= 1.2.2)
156 | kaminari-activerecord (= 1.2.2)
157 | kaminari-core (= 1.2.2)
158 | kaminari-actionview (1.2.2)
159 | actionview
160 | kaminari-core (= 1.2.2)
161 | kaminari-activerecord (1.2.2)
162 | activerecord
163 | kaminari-core (= 1.2.2)
164 | kaminari-core (1.2.2)
165 | kwalify (0.7.2)
166 | language_server-protocol (3.17.0.3)
167 | launchy (2.5.2)
168 | addressable (~> 2.8)
169 | letter_opener (1.8.1)
170 | launchy (>= 2.2, < 3)
171 | listen (3.8.0)
172 | rb-fsevent (~> 0.10, >= 0.10.3)
173 | rb-inotify (~> 0.9, >= 0.9.10)
174 | loofah (2.20.0)
175 | crass (~> 1.0.2)
176 | nokogiri (>= 1.5.9)
177 | mail (2.8.1)
178 | mini_mime (>= 0.1.1)
179 | net-imap
180 | net-pop
181 | net-smtp
182 | marcel (1.0.2)
183 | method_source (1.0.0)
184 | mini_mime (1.1.2)
185 | mini_portile2 (2.8.1)
186 | minitest (5.18.0)
187 | multipart-post (2.3.0)
188 | net-imap (0.3.4)
189 | date
190 | net-protocol
191 | net-pop (0.1.2)
192 | net-protocol
193 | net-protocol (0.2.1)
194 | timeout
195 | net-smtp (0.3.3)
196 | net-protocol
197 | nio4r (2.5.9)
198 | nokogiri (1.14.3)
199 | mini_portile2 (~> 2.8.0)
200 | racc (~> 1.4)
201 | orm_adapter (0.5.0)
202 | parallel (1.23.0)
203 | parser (2.7.2.0)
204 | ast (~> 2.4.1)
205 | pg (1.4.6)
206 | prettier_print (1.2.1)
207 | pry (0.14.2)
208 | coderay (~> 1.1)
209 | method_source (~> 1.0)
210 | pry-byebug (3.10.1)
211 | byebug (~> 11.0)
212 | pry (>= 0.13, < 0.15)
213 | pry-rails (0.3.9)
214 | pry (>= 0.10.4)
215 | psych (3.1.0)
216 | public_suffix (5.0.1)
217 | puma (5.6.5)
218 | nio4r (~> 2.0)
219 | racc (1.6.2)
220 | rack (2.2.6.4)
221 | rack-cors (1.1.1)
222 | rack (>= 2.0.0)
223 | rack-test (2.1.0)
224 | rack (>= 1.3)
225 | rails (6.1.7.3)
226 | actioncable (= 6.1.7.3)
227 | actionmailbox (= 6.1.7.3)
228 | actionmailer (= 6.1.7.3)
229 | actionpack (= 6.1.7.3)
230 | actiontext (= 6.1.7.3)
231 | actionview (= 6.1.7.3)
232 | activejob (= 6.1.7.3)
233 | activemodel (= 6.1.7.3)
234 | activerecord (= 6.1.7.3)
235 | activestorage (= 6.1.7.3)
236 | activesupport (= 6.1.7.3)
237 | bundler (>= 1.15.0)
238 | railties (= 6.1.7.3)
239 | sprockets-rails (>= 2.0.0)
240 | rails-dom-testing (2.0.3)
241 | activesupport (>= 4.2.0)
242 | nokogiri (>= 1.6)
243 | rails-html-sanitizer (1.5.0)
244 | loofah (~> 2.19, >= 2.19.1)
245 | rails_best_practices (1.19.5)
246 | activesupport
247 | code_analyzer (>= 0.5.1)
248 | erubis
249 | i18n
250 | json
251 | require_all (~> 3.0)
252 | ruby-progressbar
253 | railties (6.1.7.3)
254 | actionpack (= 6.1.7.3)
255 | activesupport (= 6.1.7.3)
256 | method_source
257 | rake (>= 12.2)
258 | thor (~> 1.0)
259 | rainbow (3.1.1)
260 | rake (13.0.6)
261 | ransack (3.2.1)
262 | activerecord (>= 6.1.5)
263 | activesupport (>= 6.1.5)
264 | i18n
265 | rb-fsevent (0.11.2)
266 | rb-inotify (0.10.1)
267 | ffi (~> 1.0)
268 | reek (5.6.0)
269 | codeclimate-engine-rb (~> 0.4.0)
270 | kwalify (~> 0.7.0)
271 | parser (>= 2.5.0.0, < 2.8, != 2.5.1.1)
272 | psych (~> 3.1.0)
273 | rainbow (>= 2.0, < 4.0)
274 | regexp_parser (2.8.0)
275 | require_all (3.0.0)
276 | responders (3.1.0)
277 | actionpack (>= 5.2)
278 | railties (>= 5.2)
279 | rexml (3.2.5)
280 | rspec-core (3.12.2)
281 | rspec-support (~> 3.12.0)
282 | rspec-expectations (3.12.3)
283 | diff-lcs (>= 1.2.0, < 2.0)
284 | rspec-support (~> 3.12.0)
285 | rspec-mocks (3.12.5)
286 | diff-lcs (>= 1.2.0, < 2.0)
287 | rspec-support (~> 3.12.0)
288 | rspec-rails (6.0.1)
289 | actionpack (>= 6.1)
290 | activesupport (>= 6.1)
291 | railties (>= 6.1)
292 | rspec-core (~> 3.11)
293 | rspec-expectations (~> 3.11)
294 | rspec-mocks (~> 3.11)
295 | rspec-support (~> 3.11)
296 | rspec-support (3.12.0)
297 | rubocop (1.7.0)
298 | parallel (~> 1.10)
299 | parser (>= 2.7.1.5)
300 | rainbow (>= 2.2.2, < 4.0)
301 | regexp_parser (>= 1.8, < 3.0)
302 | rexml
303 | rubocop-ast (>= 1.2.0, < 2.0)
304 | ruby-progressbar (~> 1.7)
305 | unicode-display_width (>= 1.4.0, < 2.0)
306 | rubocop-ast (1.4.1)
307 | parser (>= 2.7.1.5)
308 | rubocop-rails (2.3.2)
309 | rack (>= 1.1)
310 | rubocop (>= 0.72.0)
311 | ruby-lsp (0.3.8)
312 | language_server-protocol (~> 3.17.0)
313 | sorbet-runtime
314 | syntax_tree (>= 5.0.0, < 6)
315 | ruby-progressbar (1.13.0)
316 | ruby2_keywords (0.0.5)
317 | sass (3.7.4)
318 | sass-listen (~> 4.0.0)
319 | sass-listen (4.0.0)
320 | rb-fsevent (~> 0.9, >= 0.9.4)
321 | rb-inotify (~> 0.9, >= 0.9.7)
322 | sass-rails (5.1.0)
323 | railties (>= 5.2.0)
324 | sass (~> 3.1)
325 | sprockets (>= 2.8, < 4.0)
326 | sprockets-rails (>= 2.0, < 4.0)
327 | tilt (>= 1.1, < 3)
328 | sexp_processor (4.16.1)
329 | simplecov (0.13.0)
330 | docile (~> 1.1.0)
331 | json (>= 1.8, < 3)
332 | simplecov-html (~> 0.10.0)
333 | simplecov-html (0.10.2)
334 | slack-ruby-client (2.0.0)
335 | faraday (>= 2.0)
336 | faraday-mashify
337 | faraday-multipart
338 | gli
339 | hashie
340 | websocket-driver
341 | sorbet-runtime (0.5.10789)
342 | spring (2.1.1)
343 | spring-watcher-listen (2.0.1)
344 | listen (>= 2.7, < 4.0)
345 | spring (>= 1.2, < 3.0)
346 | sprockets (3.7.2)
347 | concurrent-ruby (~> 1.0)
348 | rack (> 1, < 3)
349 | sprockets-rails (3.4.2)
350 | actionpack (>= 5.2)
351 | activesupport (>= 5.2)
352 | sprockets (>= 3.0.0)
353 | syntax_tree (5.3.0)
354 | prettier_print (>= 1.2.0)
355 | thor (1.2.1)
356 | tilt (2.1.0)
357 | timeout (0.3.2)
358 | tzinfo (2.0.6)
359 | concurrent-ruby (~> 1.0)
360 | uglifier (4.2.0)
361 | execjs (>= 0.3.0, < 3)
362 | unicode-display_width (1.8.0)
363 | uniform_notifier (1.16.0)
364 | warden (1.2.9)
365 | rack (>= 2.0.9)
366 | webmock (2.3.2)
367 | addressable (>= 2.3.6)
368 | crack (>= 0.3.2)
369 | hashdiff
370 | websocket-driver (0.7.5)
371 | websocket-extensions (>= 0.1.0)
372 | websocket-extensions (0.1.5)
373 | zeitwerk (2.6.7)
374 |
375 | PLATFORMS
376 | ruby
377 |
378 | DEPENDENCIES
379 | activeadmin (~> 2.9)
380 | annotate (~> 3.0, >= 3.0.3)
381 | better_errors (~> 2.8.0)
382 | brakeman (~> 4.7.1)
383 | bullet (~> 6.1)
384 | database_cleaner (~> 1.4.1)
385 | devise (~> 4.7, >= 4.7.2)
386 | factory_bot_rails (~> 6.2.0)
387 | faker (~> 2.13)
388 | letter_opener (~> 1.7)
389 | listen (~> 3.2)
390 | pg (~> 1.1, >= 1.1.4)
391 | pry-byebug (~> 3.10.1)
392 | pry-rails (~> 0.3.9)
393 | puma (~> 5.6.2)
394 | rack-cors (~> 1.0, >= 1.0.6)
395 | rails (~> 6.1.7, >= 6.1.7.1)
396 | rails_best_practices (~> 1.19.4)
397 | reek (~> 5.5)
398 | rspec-core (~> 3.12.2)
399 | rspec-rails (~> 6.0.1)
400 | rubocop-rails (~> 2.3.2)
401 | ruby-lsp (~> 0.3.8)
402 | sass-rails (~> 5.1)
403 | simplecov (~> 0.13.0)
404 | slack-ruby-client (~> 2.0.0)
405 | spring (~> 2.1.0)
406 | spring-watcher-listen (~> 2.0.0)
407 | sprockets (~> 3.7.2)
408 | uglifier (~> 4.2)
409 | webmock (~> 2.3.2)
410 |
411 | RUBY VERSION
412 | ruby 3.1.3p185
413 |
414 | BUNDLED WITH
415 | 2.4.6
416 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Rootstrap
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | release: rake db:migrate
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rootstrap Pull request to Slack
2 |
3 | [](https://travis-ci.org/rootstrap/pull_requests_to_slack)
4 | [](https://codeclimate.com/github/rootstrap/pull_requests_to_slack/maintainability)
5 | [](https://codeclimate.com/github/rootstrap/pull_requests_to_slack/test_coverage)
6 |
7 | Send Github pull request notifications to Slack.
8 |
9 | - Each time a PR is created in your organization it will send a message to a specific Slack channel with a link to the PR and its technology emoji assigned.
10 | - When the PR is merged it will add a merged reaction emoji.
11 |
12 |
13 |
14 | - You can add ``` \slack `This is a small pr @slack_user` ``` at the end of the PR's description to add a message to the notification and to notify specific Slack users.
15 |
16 |
17 | Make sure to use ``` ` ` ``` in the message in case the Slack user name is the same as someone's GitHub name, so the github user is not notified.
18 |
19 |
20 |
21 | - It will not send a notification if the PR is a draft.
22 | - It will remove the notification if the PR has an `ON HOLD` label and resend the notification when the label is removed.
23 |
24 |
25 | ## Installation
26 |
27 | 1. Clone this repo
28 | 2. Install PostgreSQL in case you don't have it
29 | 3. Create your `database.yml` and `application.yml` files. There are sample files in `/config`
30 | 4. `bundle install`
31 | 5. Generate a secret key with `rake secret` and paste this value into the `application.yml`.
32 | 6. Fill the `SLACK_API_TOKEN` and `SLACK_BOT_TOKEN` in `application.yml`.
33 | To get the credentials: log in to https://api.slack.com/apps, select your application and then click OAuth Tokens & Redirect URLs. `SLACK_API_TOKEN` is the `OAuth Access Token` and `SLACK_BOT_TOKEN` is `Bot User OAuth Access Token`
34 | 6. `rails db:create`
35 | 7. `rails db:migrate`
36 | 8. `rails db:seed` # this will create an admin with admin@example.com:password
37 | 9. `npm install -g ngrok` Install Ngrok
38 | 10. `rspec` and make sure all tests pass
39 | 11. `rails s`
40 | 12. You are ready!
41 |
42 | ## How to test the webhook locally?
43 | - Create a dummy repository in github with a couple branches.
44 | - Run server: `rails s -p 3001`
45 | - In another terminal run ngrok: `ngrok http 3001`
46 | - Copy ngrok url to github configuration page (settings->webhooks)
47 | `http://xxxxxxx.ngrok.io/api/v1/notifications_filter`
48 | - Change CHANNEL in SlackNotificationService to your `@name` or `#some_test_channel`
49 | - Create/edit pull request adding or removing labels. This will execute the webhook.
50 |
51 | ## ActiveAdmin page
52 | You can access the admin page at `http://localhost:3001/admin/users` and add users that you want to ignore
53 |
54 | ## Deploy to Heroku
55 | Install heroku cli https://devcenter.heroku.com/articles/heroku-cli#download-and-install
56 | * Setup:
57 | ```
58 | heroku login
59 | enter credentials
60 | heroku git:remote -a rootstrap-pull-request-to-slack
61 | ```
62 |
63 | * Push:
64 | ```
65 | git push heroku master
66 | ```
67 |
68 | ## Docs
69 |
70 | #### Ngrok
71 | Public URLs for exposing your local web server
72 | https://ngrok.com/
73 |
74 | #### Github Hooks
75 | Info about github hooks and Pull request payload
76 |
77 | https://developer.github.com/webhooks/configuring/
78 | https://developer.github.com/v3/activity/events/types/#pullrequestevent
79 |
80 | #### Slack methods
81 | https://api.slack.com/methods
82 |
83 | ## Contributing
84 | Bug reports (please use Issues) and pull requests are welcome on GitHub at https://github.com/rootstrap/pull_requests_to_slack/issues. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
85 |
86 | ## License
87 | The library is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
88 |
89 | ## Credits
90 | Github for Slack is maintained by [Rootstrap](http://www.rootstrap.com) with the help of our [contributors](https://github.com/rootstrap/pull_requests_to_slack/contributors).
91 |
92 | [
](http://www.rootstrap.com)
93 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require_relative 'config/application'
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/apiary.apib:
--------------------------------------------------------------------------------
1 | FORMAT: 1A
2 | HOST: http://rails5-api-base.herokuapp.com
3 |
4 | # API BASE
5 |
6 | Rails Api Base is a boilerplate project for JSON RESTful APIs. It follows the community best practices in terms of standards, security and maintainability, integrating a variety of testing and code quality tools.
7 |
8 | ## Users Collection [/api/v1/users]
9 |
10 | ### Sign Up [POST]
11 |
12 | + Request (application/json)
13 | + Attributes
14 | + user (Profile Edition, required)
15 |
16 |
17 | + Response 200 (application/json)
18 | + Headers
19 |
20 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
21 | client: QADgNCWRJj0LyRruqzYbBg
22 | expiry: 1489009792
23 | uid: test@test.com
24 |
25 |
26 | + Attributes
27 | + user (Profile Response, required)
28 |
29 | + Response 401
30 |
31 |
32 | ## Current user's profile [/api/v1/user/profile]
33 |
34 | ### Get current user profile [GET]
35 |
36 | + Request (application/json)
37 | + Headers
38 |
39 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
40 | client: QADgNCWRJj0LyRruqzYbBg
41 | uid: test@test.com
42 |
43 |
44 | + Response 200 (application/json)
45 | + Headers
46 |
47 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
48 | client: QADgNCWRJj0LyRruqzYbBg
49 | expiry: 1489009792
50 | uid: test@test.com
51 |
52 |
53 | + Attributes
54 | + user (Profile Response, required)
55 |
56 |
57 | + Response 401
58 |
59 |
60 | ### Update current user profile [PUT]
61 |
62 | + Request (application/json)
63 | + Headers
64 |
65 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
66 | client: QADgNCWRJj0LyRruqzYbBg
67 | uid: test@test.com
68 |
69 | + Attributes
70 | + user (Profile Edition, required)
71 |
72 | + Response 200 (application/json)
73 | + Headers
74 |
75 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
76 | client: QADgNCWRJj0LyRruqzYbBg
77 | expiry: 1489009792
78 | uid: test@test.com
79 |
80 |
81 | + Attributes
82 | + user (Profile Response, required)
83 |
84 | ## Get other user's profile [/api/v1/users/{id}]
85 |
86 | ### Get user [GET]
87 |
88 | + Request (application/json)
89 | + Parameters
90 | + id (integer, required)
91 |
92 | + Headers
93 |
94 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
95 | client: QADgNCWRJj0LyRruqzYbBg
96 | uid: test@test.com
97 |
98 |
99 |
100 | + Response 200 (application/json)
101 | + Headers
102 |
103 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
104 | client: QADgNCWRJj0LyRruqzYbBg
105 | expiry: 1489009792
106 | uid: test@test.com
107 |
108 |
109 | + Attributes
110 | + user (User, required)
111 |
112 | + Response 401
113 |
114 |
115 | ## Login [/api/v1/users/sign_in]
116 |
117 | ### Login [POST]
118 |
119 | + Request (application/json)
120 |
121 | + Body
122 |
123 | {
124 | "user":
125 | {
126 | "email": "test@gmail.com",
127 | "password": "password"
128 | }
129 | }
130 |
131 |
132 | + Response 200 (application/json)
133 | + Headers
134 |
135 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
136 | client: QADgNCWRJj0LyRruqzYbBg
137 | expiry: 1489009792
138 | uid: test@test.com
139 |
140 |
141 | + Attributes
142 | + user (Profile Response, required)
143 |
144 | + Response 401
145 |
146 |
147 | ## Login with Facebook [/api/v1/user/facebook]
148 |
149 | ### Login with Facebook [POST]
150 |
151 |
152 | + Response 200 (application/json)
153 | + Headers
154 |
155 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
156 | client: QADgNCWRJj0LyRruqzYbBg
157 | uid: test@test.com
158 |
159 |
160 | + Attributes
161 | + user (Profile Response, required)
162 |
163 |
164 | ## Logout [/api/v1/users/sign_out]
165 |
166 | ### Logout [DELETE]
167 |
168 | + Request (application/json)
169 | + Headers
170 |
171 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
172 | client: QADgNCWRJj0LyRruqzYbBg
173 | expiry: 1489009792
174 | uid: test@test.com
175 |
176 | + Response 200 (application/json)
177 |
178 |
179 | ## Reset password [/api/v1/users/password]
180 |
181 | More information of how reset password works: https://github.com/lynndylanhurley/devise_token_auth/wiki/Reset-Password-Flow
182 |
183 | ### Reset password [POST]
184 |
185 | Use this route to send a password reset confirmation email
186 |
187 | + Request (application/json)
188 | + Body
189 |
190 | {
191 | "email": "test@test.com",
192 | "redirect_url": "http://www.example.com"
193 | }
194 |
195 | + Response 200 (application/json)
196 | + Body
197 |
198 | {
199 | "success": true,
200 | "message": "An email has been sent to 'example@mail.com' containing instructions for resetting your password."
201 | }
202 |
203 | ### Reset password [PUT]
204 |
205 | Use this route to change user's passwords
206 |
207 | + Request (application/json)
208 | + Parameters
209 | + reset_password_token (string, required)
210 |
211 | + Body
212 |
213 | {
214 | "password": "12345678",
215 | "password_confirmation": "12345678"
216 | }
217 |
218 | + Response 200 (application/json)
219 | + Headers
220 |
221 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
222 | client: QADgNCWRJj0LyRruqzYbBg
223 | expiry: 1489009792
224 | uid: test@test.com
225 |
226 | + Attributes (Profile Response)
227 |
228 | ## Edit reset password [/api/v1/users/password/edit]
229 |
230 | ### Edit reset password [GET]
231 |
232 | This route is the destination URL for password reset confirmation
233 |
234 | + Request (application/json)
235 | + Parameters
236 | + reset_password_token (string, required)
237 | + redirect_url (string)
238 |
239 | + Response 200 (application/json)
240 | + Headers
241 |
242 | access-token: sO2bm_Bpdyoo8r78jZ-fqg
243 | client: QADgNCWRJj0LyRruqzYbBg
244 | expiry: 1489009792
245 | uid: test@test.com
246 |
247 | # Data Structures
248 |
249 | ## Profile Response (object)
250 | + id: 100 (number)
251 | + email: test@test.com (string)
252 | + provider: email, facebook, twitter (enum[string]) - it's way the user logins
253 | + uid: test@test.com (string) - the provider identifier
254 | + first_name: John (string)
255 | + last_name: Doe (string)
256 | + username: jdoe (string)
257 | + created_at: 2017-02-23T13:54:33.283Z (string)
258 |
259 | ## Profile Edition (object)
260 | + email: test@test.com (string)
261 | + password: 12345678 (string)
262 | + first_name: John (string)
263 | + last_name: Doe (string)
264 | + username: jdoe (string)
265 |
266 | ## User (object)
267 | + email: test@test.com (string)
268 | + first_name: John (string)
269 | + last_name: Doe (string)
270 | + username: jdoe (string)
271 |
--------------------------------------------------------------------------------
/app/admin/admin_user.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin.register AdminUser do
2 | permit_params :email, :password, :password_confirmation
3 |
4 | index do
5 | selectable_column
6 | id_column
7 | column :email
8 | column :current_sign_in_at
9 | column :sign_in_count
10 | column :created_at
11 | actions
12 | end
13 |
14 | filter :email
15 | filter :current_sign_in_at
16 | filter :sign_in_count
17 | filter :created_at
18 |
19 | form do |f|
20 | f.inputs 'Admin Details' do
21 | f.input :email
22 | f.input :password
23 | f.input :password_confirmation
24 | end
25 | f.actions
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/app/admin/dashboard.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin.register_page 'Dashboard' do
2 | menu priority: 1, label: proc { I18n.t('active_admin.dashboard') }
3 |
4 | content title: proc { I18n.t('active_admin.dashboard') } do
5 | div class: 'blank_slate_container', id: 'dashboard_default_message' do
6 | span class: 'blank_slate' do
7 | span I18n.t('active_admin.dashboard_welcome.welcome')
8 | small I18n.t('active_admin.dashboard_welcome.call_to_action')
9 | end
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/admin/user.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin.register User do
2 | permit_params :email, :first_name, :last_name, :github_name, :blacklisted
3 |
4 | form do |f|
5 | f.inputs 'Details' do
6 | f.input :email
7 | f.input :first_name
8 | f.input :last_name
9 | f.input :github_name
10 | f.input :blacklisted
11 | end
12 |
13 | actions
14 | end
15 |
16 | index do
17 | selectable_column
18 | id_column
19 | column :email
20 | column :first_name
21 | column :last_name
22 | column :github_name
23 | column :blacklisted
24 | column :created_at
25 | column :updated_at
26 | actions
27 | end
28 |
29 | filter :id
30 | filter :email
31 | filter :github_name
32 | filter :first_name
33 | filter :last_name
34 | filter :blacklisted
35 | filter :created_at
36 | filter :updated_at
37 |
38 | show do
39 | attributes_table do
40 | row :id
41 | row :email
42 | row :first_name
43 | row :last_name
44 | row :github_name
45 | row :blacklisted
46 | row :created_at
47 | row :updated_at
48 | end
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../stylesheets .css
3 |
--------------------------------------------------------------------------------
/app/assets/javascripts/active_admin.js:
--------------------------------------------------------------------------------
1 | #= require active_admin/base
2 |
--------------------------------------------------------------------------------
/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file.
9 | //
10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require jquery
14 | //= require jquery_ujs
15 | //= require_tree .
16 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/active_admin.scss:
--------------------------------------------------------------------------------
1 | // SASS variable overrides must be declared before loading up Active Admin's styles.
2 | //
3 | // To view the variables that Active Admin provides, take a look at
4 | // `app/assets/stylesheets/active_admin/mixins/_variables.scss` in the
5 | // Active Admin source.
6 | //
7 | // For example, to change the sidebar width:
8 | // $sidebar-width: 242px;
9 |
10 | // Active Admin's got SASS!
11 | @import "active_admin/mixins";
12 | @import "active_admin/base";
13 |
14 | // Overriding any non-variable SASS must be done after the fact.
15 | // For example, to change the default status-tag color:
16 | //
17 | // .status_tag { background: #6090DB; }
18 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the top of the
9 | * compiled file, but it's generally better to create a new file per style scope.
10 | *
11 | *= require_self
12 | *= require_tree .
13 | */
14 |
--------------------------------------------------------------------------------
/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/controllers/api/concerns/act_as_api_request.rb:
--------------------------------------------------------------------------------
1 | module Api
2 | module Concerns
3 | module ActAsApiRequest
4 | extend ActiveSupport::Concern
5 |
6 | included do
7 | skip_before_action :verify_authenticity_token
8 | before_action :skip_session_storage
9 | before_action :check_json_request
10 | end
11 |
12 | def check_json_request
13 | return if request.content_type =~ /json/
14 |
15 | render json: { error: I18n.t('api.errors.invalid_content_type') }, status: :not_acceptable
16 | end
17 |
18 | def skip_session_storage
19 | # Devise stores the cookie by default, so in api requests, it is disabled
20 | # http://stackoverflow.com/a/12205114/2394842
21 | request.session_options[:skip] = true
22 | end
23 |
24 | def render_error(status, message, _data = nil)
25 | response = {
26 | error: message
27 | }
28 | render json: response, status: status
29 | end
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/app/controllers/api/v1/api_controller.rb:
--------------------------------------------------------------------------------
1 | module Api
2 | module V1
3 | class ApiController < ApplicationController
4 | include Concerns::ActAsApiRequest
5 |
6 | before_action :authenticate_user!, except: :status
7 |
8 | layout false
9 | respond_to :json
10 |
11 | rescue_from Exception, with: :render_error
12 | rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
13 | rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid
14 | rescue_from ActionController::RoutingError, with: :render_not_found
15 | rescue_from AbstractController::ActionNotFound, with: :render_not_found
16 | rescue_from ActionController::ParameterMissing, with: :render_parameter_missing
17 |
18 | def status
19 | render json: { online: true }
20 | end
21 |
22 | private
23 |
24 | def render_error(exception)
25 | logger.error(exception) # Report to your error managment tool here
26 | render json: { error: I18n.t('api.errors.server') }, status: 500 unless performed?
27 | end
28 |
29 | def render_not_found(exception)
30 | logger.info(exception) # for logging
31 | render json: { error: I18n.t('api.errors.not_found') }, status: :not_found
32 | end
33 |
34 | def render_record_invalid(exception)
35 | logger.info(exception) # for logging
36 | render json: { errors: exception.record.errors.as_json }, status: :bad_request
37 | end
38 |
39 | def render_parameter_missing(exception)
40 | logger.info(exception) # for logging
41 | render json: { error: I18n.t('api.errors.missing_param') }, status: :unprocessable_entity
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/app/controllers/api/v1/github_webhook_controller.rb:
--------------------------------------------------------------------------------
1 | module Api
2 | module V1
3 | class GithubWebhookController < Api::V1::ApiController
4 | protect_from_forgery with: :null_session
5 | include Concerns::ActAsApiRequest
6 | skip_before_action :authenticate_user!
7 |
8 | def filter
9 | slack_notification_service = SlackNotificationService.new(params)
10 | slack_notification_service.send_notification
11 | head :no_content
12 | end
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | # Prevent CSRF attacks by raising an exception.
3 | # For APIs, you may want to use :null_session instead.
4 | protect_from_forgery with: :exception
5 | end
6 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rootstrap/pull_requests_to_slack/67ee96a3d3f4a45a0ec977c4de3855355ff0579b/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | end
3 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/admin_user.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: admin_users
4 | #
5 | # id :integer not null, primary key
6 | # email :string default(""), not null
7 | # encrypted_password :string default(""), not null
8 | # reset_password_token :string
9 | # reset_password_sent_at :datetime
10 | # remember_created_at :datetime
11 | # sign_in_count :integer default(0), not null
12 | # current_sign_in_at :datetime
13 | # last_sign_in_at :datetime
14 | # current_sign_in_ip :inet
15 | # last_sign_in_ip :inet
16 | # created_at :datetime not null
17 | # updated_at :datetime not null
18 | #
19 | # Indexes
20 | #
21 | # index_admin_users_on_email (email) UNIQUE
22 | # index_admin_users_on_reset_password_token (reset_password_token) UNIQUE
23 | #
24 |
25 | class AdminUser < ApplicationRecord
26 | # Include default devise modules. Others available are:
27 | # :confirmable, :lockable, :timeoutable and :omniauthable
28 | devise :database_authenticatable,
29 | :recoverable, :rememberable, :trackable, :validatable
30 | end
31 |
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rootstrap/pull_requests_to_slack/67ee96a3d3f4a45a0ec977c4de3855355ff0579b/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # email :string
7 | # first_name :string default("")
8 | # last_name :string default("")
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # github_name :string
12 | # slack_name :string
13 | # blacklisted :boolean default(FALSE)
14 | #
15 | # Indexes
16 | #
17 | # index_users_on_github_name (github_name)
18 | #
19 |
20 | class User < ApplicationRecord
21 | validates :github_name, uniqueness: true
22 |
23 | def full_name
24 | return github_name unless first_name.present?
25 |
26 | "#{first_name} #{last_name}"
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/app/services/pull_request.rb:
--------------------------------------------------------------------------------
1 | class PullRequest
2 | ON_HOLD = 'ON HOLD'.freeze
3 | attr_reader :info, :username, :avatar_url, :webhook_label,
4 | :url, :body, :language, :repo_name
5 |
6 | def initialize(params)
7 | @info = params.fetch(:pull_request, {})
8 | @username = @info.dig(:user, :login)
9 | @avatar_url = @info.dig(:user, :avatar_url)
10 | @webhook_label = params.dig(:github_webhook, :label, :name)
11 | @url = @info[:html_url]
12 | @body = @info[:body]
13 | @language = params.dig(:repository, :language)
14 | @repo_name = params.dig(:repository, :name)&.downcase
15 | end
16 |
17 | def on_hold_webhook?
18 | on_hold_label? @webhook_label
19 | end
20 |
21 | def on_hold?
22 | @info[:labels]&.any? { |label| on_hold_label? label[:name] } || false
23 | end
24 |
25 | def draft?
26 | @info[:draft] == true
27 | end
28 |
29 | def merged?
30 | @info[:merged] == true
31 | end
32 |
33 | def on_hold_label?(label)
34 | label.downcase == ON_HOLD.downcase
35 | end
36 |
37 | def blacklisted?
38 | User.where(github_name: username, blacklisted: true).exists?
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/app/services/slack_bot.rb:
--------------------------------------------------------------------------------
1 | class SlackBot
2 | ON_HOLD = 'ON HOLD'.freeze
3 |
4 | EMOJI_HASH = { 'JavaScript' => ':javascript:',
5 | 'TypeScript' => ':ts:',
6 | 'Ruby' => ':ruby:',
7 | 'Java' => ':java:',
8 | 'Kotlin' => ':kotlin:',
9 | 'Swift' => ':swift:',
10 | 'React' => ':react:',
11 | 'React-Native' => ':react_native:',
12 | 'Angular' => ':angular:',
13 | 'Vue' => ':vue:',
14 | 'Node' => ':nodejs:',
15 | 'Python' => ':python:',
16 | 'HTML' => ':html5:',
17 | 'Elixir' => ':elixir:',
18 | 'R' => ':r-lang:',
19 | 'PHP' => ':php:' }.freeze
20 |
21 | attr_reader :channel
22 |
23 | def initialize(channel:)
24 | raise ArgumentError.new('Invalid channel') unless channel.present?
25 |
26 | @client = Slack::Web::Client.new
27 | @channel = channel
28 | end
29 |
30 | def notify(message, username, avatar_url)
31 | @client.chat_postMessage(channel: @channel, text: message,
32 | username: username, icon_url: avatar_url)
33 | end
34 |
35 | def add_merge_emoji(matches)
36 | matches.each do |match|
37 | timestamp = match[:ts]
38 | begin
39 | add_emoji :merged, timestamp
40 | rescue StandardError => e
41 | puts "An error of type #{e.class} happened, message is #{e.message}."
42 | end
43 | end
44 | end
45 |
46 | def add_emoji(emoji, timestamp)
47 | @client.reactions_add(name: emoji,
48 | channel: @channel,
49 | timestamp: timestamp,
50 | as_user: false)
51 | end
52 |
53 | def find_message(text)
54 | client_find = Slack::Web::Client.new(token: ENV['SLACK_API_TOKEN'])
55 | response = client_find.search_messages(channel: @channel, query: "#{text} in:#{@channel}")
56 | response.dig(:messages, :matches)
57 | end
58 |
59 | def delete_message(matches)
60 | matches.each do |match|
61 | timestamp = match[:ts]
62 | begin
63 | @client.chat_delete(channel: @channel, ts: timestamp) if timestamp
64 | rescue StandardError => e
65 | puts "An error of type #{e.class} happened, message is #{e.message}."
66 | end
67 | end
68 | end
69 |
70 | def message(pull_req)
71 | slack_body = extract_slack_body(pull_req.body)
72 | "#{pull_req.url} #{slack_body} #{language_emoji(pull_req.language, pull_req.repo_name)}"
73 | end
74 |
75 | def extract_slack_body(body)
76 | body_gsub = body&.gsub("\r\n", ' ')&.split('\slack ')
77 | body = body_gsub[1].present? ? body_gsub[1] : ''
78 | format_body body
79 | end
80 |
81 | # To show the notification @test it should be formatted like <@test>
82 | # https://api.slack.com/docs/message-formatting
83 | def format_body(body)
84 | body.gsub(/([@#][A-Za-z0-9_]+)/, '<\\1>')
85 | end
86 |
87 | def language_emoji(language, repo_name)
88 | if repo_name =~ /reactnative|react-native|-rn$/
89 | language = 'React-Native'
90 | elsif repo_name.include? 'react'
91 | language = 'React'
92 | elsif repo_name.include? 'angular'
93 | language = 'Angular'
94 | elsif repo_name.include? 'node'
95 | language = 'Node'
96 | end
97 |
98 | EMOJI_HASH.fetch language, ":#{language&.downcase}:"
99 | end
100 | end
101 |
--------------------------------------------------------------------------------
/app/services/slack_notification_service.rb:
--------------------------------------------------------------------------------
1 | class SlackNotificationService
2 | ACTION_METHODS = { 'opened' => :filter_opened_action,
3 | 'ready_for_review' => :filter_ready_for_review_action,
4 | 'unlabeled' => :filter_unlabeled_action,
5 | 'labeled' => :filter_on_hold_labeled_action,
6 | 'closed' => :filter_closed_action }.freeze
7 |
8 | DEFAULT_CHANNEL = '#code-review'.freeze
9 |
10 | LANGUAGES = {
11 | 'Ruby': 'ruby',
12 | 'Node': 'node',
13 | 'Python': 'python',
14 | 'React': 'react',
15 | 'React-Native': 'react-native',
16 | 'Dart': 'flutter',
17 | 'Objective-C': 'ios',
18 | 'Kotlin': 'android',
19 | 'Swift': 'ios',
20 | 'TypeScript': 'typescript',
21 | 'JavaScript': 'javascript'
22 | }.freeze
23 |
24 | attr_reader :action, :extra_params, :slack_bot, :pr
25 |
26 | def initialize(params)
27 | @action = params.dig(:github_webhook, :action)
28 | if @action.blank?
29 | Rails.logger.warn("Warning! No action found on params: [#{params}]")
30 | end
31 |
32 | @extra_params = params || {}
33 | @slack_bot = SlackBot.new(channel: channel(params))
34 | @pr = PullRequest.new(params)
35 | end
36 |
37 | def send_notification
38 | return if pr.blacklisted?
39 |
40 | send(ACTION_METHODS[action]) if ACTION_METHODS.key? action
41 | end
42 |
43 | private
44 |
45 | def notify_pull_request
46 | message = slack_bot.message(pr)
47 | slack_bot.notify(message, pr.username, pr.avatar_url)
48 | end
49 |
50 | def filter_unlabeled_action
51 | notify_pull_request if pr.on_hold_webhook?
52 | end
53 |
54 | def filter_on_hold_labeled_action
55 | return unless pr.on_hold_webhook?
56 |
57 | matches = slack_bot.find_message pr.url
58 | slack_bot.delete_message matches
59 | end
60 |
61 | def channel(params)
62 | lang = LANGUAGES[params.dig(:repository, :language)&.to_sym]
63 | repository_info = params[:repository]
64 |
65 | channel = build_channel(lang, repository_info)
66 | channel_name = "##{channel}"
67 |
68 | if channel.present? && search_channel(channel_name)
69 | channel_name
70 | else
71 | DEFAULT_CHANNEL
72 | end
73 | end
74 |
75 | def search_channel(channel)
76 | Slack::Web::Client.new.conversations_info(channel: channel)
77 | rescue StandardError => e
78 | Rails.logger.error("Error #{e.inspect} for channel #{channel}")
79 | nil
80 | end
81 |
82 | def build_channel(lang, repository_info)
83 | return 'devops-code-review' if devops_pr?(repository_info)
84 |
85 | return build_lang_channel(lang, repository_info) if lang
86 | end
87 |
88 | def build_lang_channel(lang, repository_info)
89 | return js_channels(repository_info, lang) if %w[javascript typescript].include?(lang)
90 |
91 | "#{lang}-code-review"
92 | end
93 |
94 | def devops_pr?(repository_info)
95 | return false unless repository_info
96 |
97 | repo_name = repository_info[:name]
98 | repo_topics = repository_info[:topics]
99 |
100 | (repo_name&.include? 'devops') ||
101 | (repo_name&.include? 'infra') ||
102 | (repo_topics&.include? 'terraform')
103 | end
104 |
105 | def filter_opened_action
106 | notify_pull_request unless pr.on_hold? || pr.draft?
107 | end
108 |
109 | def filter_ready_for_review_action
110 | notify_pull_request unless pr.on_hold?
111 | end
112 |
113 | def filter_closed_action
114 | filter_merged_action if pr.merged?
115 | end
116 |
117 | def filter_merged_action
118 | matches = slack_bot.find_message pr.url
119 | slack_bot.add_merge_emoji matches
120 | end
121 |
122 | def js_channels(pull_request, _lang)
123 | return unless pull_request[:name]
124 |
125 | repo_name = pull_request[:name].downcase
126 | topics = pull_request[:topics].present? ? pull_request[:topics] : []
127 |
128 | js_repo_name(repo_name, topics)
129 | end
130 |
131 | # rubocop:disable Metrics/CyclomaticComplexity
132 | def js_repo_name(repo_name, topics)
133 | if ((repo_name.include? 'react') &&
134 | (repo_name.include? 'native')) ||
135 | (topics.include? 'react-native')
136 | "#{LANGUAGES[:'React-Native']}-code-review"
137 | elsif (repo_name.include? 'react') || (topics.include? 'react')
138 | "#{LANGUAGES[:React]}-code-review"
139 | elsif (repo_name.include? 'node') || (topics.include? 'node')
140 | "#{LANGUAGES[:Node]}-code-review"
141 | end
142 | end
143 | # rubocop:enable Metrics/CyclomaticComplexity
144 | end
145 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/
5 | :css
6 | /* Email styles need to be inline */
7 | %body
8 | = yield
9 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.haml:
--------------------------------------------------------------------------------
1 | = yield
2 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/delayed_job:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
4 | require 'delayed/command'
5 | Delayed::Command.new(ARGV).daemonize
6 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | APP_PATH = File.expand_path('../config/application', __dir__)
8 | require_relative '../config/boot'
9 | require 'rails/commands'
10 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require_relative '../config/boot'
8 | require 'rake'
9 | Rake.application.run
10 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 | require 'fileutils'
4 | include FileUtils
5 |
6 | # path to your application root.
7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
8 |
9 | def system!(*args)
10 | system(*args) || abort("\n== Command #{args} failed ==")
11 | end
12 |
13 | chdir APP_ROOT do
14 | # This script is a starting point to setup your application.
15 | # Add necessary setup steps to this file.
16 |
17 | puts '== Installing dependencies =='
18 | system! 'gem install bundler --conservative'
19 | system('bundle check') || system!('bundle install')
20 |
21 | # puts "\n== Copying sample files =="
22 | # unless File.exist?('config/database.yml')
23 | # cp 'config/database.yml.sample', 'config/database.yml'
24 | # end
25 |
26 | puts "\n== Preparing database =="
27 | system! 'bin/rails db:setup'
28 |
29 | puts "\n== Removing old logs and tempfiles =="
30 | system! 'bin/rails log:clear tmp:clear'
31 |
32 | puts "\n== Restarting application server =="
33 | system! 'bin/rails restart'
34 | end
35 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
11 | if spring = lockfile.specs.detect { |spec| spec.name == "spring" }
12 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
13 | gem 'spring', spring.version
14 | require 'spring/binstub'
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 | require 'fileutils'
4 | include FileUtils
5 |
6 | # path to your application root.
7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
8 |
9 | def system!(*args)
10 | system(*args) || abort("\n== Command #{args} failed ==")
11 | end
12 |
13 | chdir APP_ROOT do
14 | # This script is a way to update your development environment automatically.
15 | # Add necessary update steps to this file.
16 |
17 | puts '== Installing dependencies =='
18 | system! 'gem install bundler --conservative'
19 | system('bundle check') || system!('bundle install')
20 |
21 | puts "\n== Updating database =="
22 | system! 'bin/rails db:migrate'
23 |
24 | puts "\n== Removing old logs and tempfiles =="
25 | system! 'bin/rails log:clear tmp:clear'
26 |
27 | puts "\n== Restarting application server =="
28 | system! 'bin/rails restart'
29 | end
30 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative 'config/environment'
4 |
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative 'boot'
2 |
3 | require 'rails'
4 | # Pick the frameworks you want:
5 | require 'active_model/railtie'
6 | require 'active_job/railtie'
7 | require 'active_record/railtie'
8 | require 'action_controller/railtie'
9 | require 'action_mailer/railtie'
10 | require 'action_view/railtie'
11 | require 'action_cable/engine'
12 | require 'sprockets/railtie'
13 | require 'rails/test_unit/railtie'
14 |
15 | # Require the gems listed in Gemfile, including any gems
16 | # you've limited to :test, :development, or :production.
17 | Bundler.require(*Rails.groups)
18 |
19 | require_relative 'env_variables'
20 |
21 | module App
22 | class Application < Rails::Application
23 | # Settings in config/environments/* take precedence over those specified here.
24 | # Application configuration should go into files in config/initializers
25 | # -- all .rb files in that directory are automatically loaded.
26 |
27 | config.secret_key_base = ENV['SECRET_KEY_BASE']
28 |
29 | config.autoload_paths += %W[#{config.root}/lib]
30 |
31 | ActionMailer::Base.smtp_settings = {
32 | address: 'smtp.sendgrid.net',
33 | port: 25,
34 | domain: 'www.api.com',
35 | authentication: :plain,
36 | user_name: ENV['SENDGRID_USERNAME'],
37 | password: ENV['SENDGRID_PASSWORD']
38 | }
39 | config.action_mailer.default_url_options = { host: ENV['SERVER_URL'] }
40 | config.action_mailer.default_options = {
41 | from: 'no-reply@api.com'
42 | }
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/config/application.travis.yml:
--------------------------------------------------------------------------------
1 | SECRET_KEY_BASE: <%= ENV["SECRET_KEY_BASE"] %>
2 |
--------------------------------------------------------------------------------
/config/application.yml.example:
--------------------------------------------------------------------------------
1 | SECRET_KEY_BASE:
2 | SERVER_URL: 'localhost:3000'
3 | PASSWORD_RESET_URL: 'http://127.0.0.1:3000'
4 | SENDGRID_USERNAME:
5 | SENDGRID_PASSWORD:
6 | AWS_ACCESS_KEY_ID:
7 | AWS_SECRET_ACCESS_KEY:
8 | S3_BUCKET_NAME:
9 | AWS_BUCKET_REGION:
10 | SLACK_API_TOKEN:
11 | SLACK_BOT_TOKEN:
12 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 |
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: redis://localhost:6379/1
10 |
--------------------------------------------------------------------------------
/config/database.travis.yml:
--------------------------------------------------------------------------------
1 | test:
2 | adapter: postgresql
3 | database: pull_request_slack_test
4 | username: postgres
5 |
--------------------------------------------------------------------------------
/config/database.yml.example:
--------------------------------------------------------------------------------
1 | default: &default
2 | adapter: postgresql
3 | encoding: unicode
4 | pool: 5
5 | username:
6 | password:
7 | host: localhost
8 | port: 5432
9 |
10 | development:
11 | <<: *default
12 | database:
13 |
14 | test:
15 | <<: *default
16 | database:
17 |
18 | production:
19 | <<: *default
20 | database:
21 |
--------------------------------------------------------------------------------
/config/env_variables.rb:
--------------------------------------------------------------------------------
1 | begin
2 | ENV.update YAML.safe_load(File.read('config/application.yml'))
3 | rescue Errno::ENOENT
4 | puts 'You have to add a correct application.yml file'
5 | end
6 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative 'application'
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports.
13 | config.consider_all_requests_local = true
14 |
15 | # Enable/disable caching. By default caching is disabled.
16 | if Rails.root.join('tmp/caching-dev.txt').exist?
17 | config.action_controller.perform_caching = true
18 |
19 | config.cache_store = :memory_store
20 | config.public_file_server.headers = {
21 | 'Cache-Control' => 'public, max-age=172800'
22 | }
23 | else
24 | config.action_controller.perform_caching = false
25 |
26 | config.cache_store = :null_store
27 | end
28 |
29 | # Don't care if the mailer can't send.
30 | config.action_mailer.raise_delivery_errors = true
31 | config.action_mailer.delivery_method = :letter_opener
32 |
33 | config.action_mailer.perform_caching = false
34 |
35 | # Print deprecation notices to the Rails logger.
36 | config.active_support.deprecation = :log
37 |
38 | # Raise an error on page load if there are pending migrations.
39 | config.active_record.migration_error = :page_load
40 |
41 | # Raises error for missing translations
42 | # config.action_view.raise_on_missing_translations = true
43 |
44 | # Use an evented file watcher to asynchronously detect changes in source code,
45 | # routes, locales, etc. This feature depends on the listen gem.
46 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
47 |
48 | config.after_initialize do
49 | Bullet.enable = true
50 | Bullet.alert = false
51 | Bullet.bullet_logger = true
52 | Bullet.console = true
53 | Bullet.rails_logger = true
54 | Bullet.add_footer = true
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Disable serving static files from the `/public` folder by default since
18 | # Apache or NGINX already handles this.
19 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
20 |
21 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
22 | # config.action_controller.asset_host = 'http://assets.example.com'
23 | config.assets.js_compressor = :uglifier
24 | config.assets.compile = true
25 | config.assets.digest = true
26 |
27 | # Version of your assets, change this if you want to expire all your assets.
28 | config.assets.version = '1.0'
29 |
30 | # Specifies the header that your server uses for sending files.
31 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
32 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
33 |
34 | # Mount Action Cable outside main process or domain
35 | # config.action_cable.mount_path = nil
36 | # config.action_cable.url = 'wss://example.com/cable'
37 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
38 |
39 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
40 | # config.force_ssl = true
41 |
42 | # Use the lowest log level to ensure availability of diagnostic information
43 | # when problems arise.
44 | config.log_level = :info
45 |
46 | # Prepend all log lines with the following tags.
47 | config.log_tags = [:request_id]
48 |
49 | # Use a different cache store in production.
50 | # config.cache_store = :mem_cache_store
51 |
52 | # Use a real queuing backend for Active Job (and separate queues per environment)
53 | # config.active_job.queue_adapter = :resque
54 | # config.active_job.queue_name_prefix = "rails5_api_base_#{Rails.env}"
55 | config.action_mailer.perform_caching = false
56 |
57 | # Ignore bad email addresses and do not raise email delivery errors.
58 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
59 | # config.action_mailer.raise_delivery_errors = false
60 |
61 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
62 | # the I18n.default_locale when a translation cannot be found).
63 | config.i18n.fallbacks = true
64 |
65 | # Send deprecation notices to registered listeners.
66 | config.active_support.deprecation = :notify
67 |
68 | # Use default logging formatter so that PID and timestamp are not suppressed.
69 | config.log_formatter = ::Logger::Formatter.new
70 |
71 | # Use a different logger for distributed setups.
72 | # require 'syslog/logger'
73 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
74 |
75 | if ENV['RAILS_LOG_TO_STDOUT'].present?
76 | logger = ActiveSupport::Logger.new(STDOUT)
77 | logger.formatter = config.log_formatter
78 | config.logger = ActiveSupport::TaggedLogging.new(logger)
79 | end
80 |
81 | # Do not dump schema after migrations.
82 | config.active_record.dump_schema_after_migration = false
83 |
84 | config.assets.precompile += %w[
85 | active_admin.js
86 | active_admin.css
87 | ]
88 | end
89 |
--------------------------------------------------------------------------------
/config/environments/staging.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('production', __dir__)
2 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure public file server for tests with Cache-Control for performance.
16 | config.public_file_server.enabled = true
17 | config.public_file_server.headers = {
18 | 'Cache-Control' => 'public, max-age=3600'
19 | }
20 |
21 | # Show full error reports and disable caching.
22 | config.consider_all_requests_local = true
23 | config.action_controller.perform_caching = false
24 |
25 | # Raise exceptions instead of rendering exception templates.
26 | config.action_dispatch.show_exceptions = false
27 |
28 | # Disable request forgery protection in test environment.
29 | config.action_controller.allow_forgery_protection = false
30 | config.action_mailer.perform_caching = false
31 |
32 | # Tell Action Mailer not to deliver emails to the real world.
33 | # The :test delivery method accumulates sent emails in the
34 | # ActionMailer::Base.deliveries array.
35 | config.action_mailer.delivery_method = :test
36 |
37 | # Print deprecation notices to the stderr.
38 | config.active_support.deprecation = :stderr
39 |
40 | # Raises error for missing translations
41 | # config.action_view.raise_on_missing_translations = true
42 |
43 | config.after_initialize do
44 | Bullet.enable = true
45 | Bullet.bullet_logger = true
46 | Bullet.raise = true # raise an error if n+1 query occurs
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/config/initializers/active_admin.rb:
--------------------------------------------------------------------------------
1 | ActiveAdmin.setup do |config|
2 | # == Site Title
3 | #
4 | # Set the title that is displayed on the main layout
5 | # for each of the active admin pages.
6 | #
7 | config.site_title = 'App'
8 |
9 | # Set the link url for the title. For example, to take
10 | # users to your main site. Defaults to no link.
11 | #
12 | # config.site_title_link = "/"
13 |
14 | # Set an optional image to be displayed for the header
15 | # instead of a string (overrides :site_title)
16 | #
17 | # Note: Aim for an image that's 21px high so it fits in the header.
18 | #
19 | # config.site_title_image = "logo.png"
20 |
21 | # == Default Namespace
22 | #
23 | # Set the default namespace each administration resource
24 | # will be added to.
25 | #
26 | # eg:
27 | # config.default_namespace = :hello_world
28 | #
29 | # This will create resources in the HelloWorld module and
30 | # will namespace routes to /hello_world/*
31 | #
32 | # To set no namespace by default, use:
33 | # config.default_namespace = false
34 | #
35 | # Default:
36 | # config.default_namespace = :admin
37 | #
38 | # You can customize the settings for each namespace by using
39 | # a namespace block. For example, to change the site title
40 | # within a namespace:
41 | #
42 | # config.namespace :admin do |admin|
43 | # admin.site_title = "Custom Admin Title"
44 | # end
45 | #
46 | # This will ONLY change the title for the admin section. Other
47 | # namespaces will continue to use the main "site_title" configuration.
48 |
49 | # == User Authentication
50 | #
51 | # Active Admin will automatically call an authentication
52 | # method in a before filter of all controller actions to
53 | # ensure that there is a currently logged in admin user.
54 | #
55 | # This setting changes the method which Active Admin calls
56 | # within the application controller.
57 | config.authentication_method = :authenticate_admin_user!
58 |
59 | # == User Authorization
60 | #
61 | # Active Admin will automatically call an authorization
62 | # method in a before filter of all controller actions to
63 | # ensure that there is a user with proper rights. You can use
64 | # CanCanAdapter or make your own. Please refer to documentation.
65 | # config.authorization_adapter = ActiveAdmin::CanCanAdapter
66 |
67 | # In case you prefer Pundit over other solutions you can here pass
68 | # the name of default policy class. This policy will be used in every
69 | # case when Pundit is unable to find suitable policy.
70 | # config.pundit_default_policy = "MyDefaultPunditPolicy"
71 |
72 | # You can customize your CanCan Ability class name here.
73 | # config.cancan_ability_class = "Ability"
74 |
75 | # You can specify a method to be called on unauthorized access.
76 | # This is necessary in order to prevent a redirect loop which happens
77 | # because, by default, user gets redirected to Dashboard. If user
78 | # doesn't have access to Dashboard, he'll end up in a redirect loop.
79 | # Method provided here should be defined in application_controller.rb.
80 | # config.on_unauthorized_access = :access_denied
81 |
82 | # == Current User
83 | #
84 | # Active Admin will associate actions with the current
85 | # user performing them.
86 | #
87 | # This setting changes the method which Active Admin calls
88 | # (within the application controller) to return the currently logged in user.
89 | config.current_user_method = :current_admin_user
90 |
91 | # == Logging Out
92 | #
93 | # Active Admin displays a logout link on each screen. These
94 | # settings configure the location and method used for the link.
95 | #
96 | # This setting changes the path where the link points to. If it's
97 | # a string, the strings is used as the path. If it's a Symbol, we
98 | # will call the method to return the path.
99 | #
100 | # Default:
101 | config.logout_link_path = :destroy_admin_user_session_path
102 |
103 | # This setting changes the http method used when rendering the
104 | # link. For example :get, :delete, :put, etc..
105 | #
106 | # Default:
107 | # config.logout_link_method = :get
108 |
109 | # == Root
110 | #
111 | # Set the action to call for the root path. You can set different
112 | # roots for each namespace.
113 | #
114 | # Default:
115 | # config.root_to = 'dashboard#index'
116 |
117 | # == Admin Comments
118 | #
119 | # This allows your users to comment on any resource registered with Active Admin.
120 | #
121 | # You can completely disable comments:
122 | config.comments = false
123 | #
124 | # You can change the name under which comments are registered:
125 | # config.comments_registration_name = 'AdminComment'
126 | #
127 | # You can change the order for the comments and you can change the column
128 | # to be used for ordering:
129 | # config.comments_order = 'created_at ASC'
130 | #
131 | # You can disable the menu item for the comments index page:
132 | # config.comments_menu = false
133 | #
134 | # You can customize the comment menu:
135 | # config.comments_menu = { parent: 'Admin', priority: 1 }
136 |
137 | # == Batch Actions
138 | #
139 | # Enable and disable Batch Actions
140 | #
141 | config.batch_actions = true
142 |
143 | # == Controller Filters
144 | #
145 | # You can add before, after and around filters to all of your
146 | # Active Admin resources and pages from here.
147 | #
148 | # config.before_action :do_something_awesome
149 |
150 | # == Localize Date/Time Format
151 | #
152 | # Set the localize format to display dates and times.
153 | # To understand how to localize your app with I18n, read more at
154 | # https://github.com/svenfuchs/i18n/blob/master/lib%2Fi18n%2Fbackend%2Fbase.rb#L52
155 | #
156 | config.localize_format = :long
157 |
158 | # == Setting a Favicon
159 | #
160 | # config.favicon = 'favicon.ico'
161 |
162 | # == Meta Tags
163 | #
164 | # Add additional meta tags to the head element of active admin pages.
165 | #
166 | # Add tags to all pages logged in users see:
167 | # config.meta_tags = { author: 'My Company' }
168 |
169 | # By default, sign up/sign in/recover password pages are excluded
170 | # from showing up in search engine results by adding a robots meta
171 | # tag. You can reset the hash of meta tags included in logged out
172 | # pages:
173 | # config.meta_tags_for_logged_out_pages = {}
174 |
175 | # == Removing Breadcrumbs
176 | #
177 | # Breadcrumbs are enabled by default. You can customize them for individual
178 | # resources or you can disable them globally from here.
179 | #
180 | # config.breadcrumb = false
181 |
182 | # == Register Stylesheets & Javascripts
183 | #
184 | # We recommend using the built in Active Admin layout and loading
185 | # up your own stylesheets / javascripts to customize the look
186 | # and feel.
187 | #
188 | # To load a stylesheet:
189 | # config.register_stylesheet 'my_stylesheet.css'
190 | #
191 | # You can provide an options hash for more control,
192 | # which is passed along to stylesheet_link_tag():
193 | # config.register_stylesheet 'my_print_stylesheet.css', media: :print
194 | #
195 | # To load a javascript file:
196 | # config.register_javascript 'my_javascript.js'
197 |
198 | # == CSV options
199 | #
200 | # Set the CSV builder separator
201 | # config.csv_options = { col_sep: ';' }
202 | #
203 | # Force the use of quotes
204 | # config.csv_options = { force_quotes: true }
205 |
206 | # == Menu System
207 | #
208 | # You can add a navigation menu to be used in your application, or configure a provided menu
209 | #
210 | # To change the default utility navigation to show a link to your website & a logout btn
211 | #
212 | # config.namespace :admin do |admin|
213 | # admin.build_menu :utility_navigation do |menu|
214 | # menu.add label: "My Great Website",
215 | # url: "http://www.mygreatwebsite.com", html_options: { target: :blank }
216 | # admin.add_logout_button_to_menu menu
217 | # end
218 | # end
219 | #
220 | # If you wanted to add a static menu item to the default menu provided:
221 | #
222 | # config.namespace :admin do |admin|
223 | # admin.build_menu :default do |menu|
224 | # menu.add label: "My Great Website",
225 | # url: "http://www.mygreatwebsite.com", html_options: { target: :blank }
226 | # end
227 | # end
228 |
229 | # == Download Links
230 | #
231 | # You can disable download links on resource listing pages,
232 | # or customize the formats shown per namespace/globally
233 | #
234 | # To disable/customize for the :admin namespace:
235 | #
236 | # config.namespace :admin do |admin|
237 | #
238 | # # Disable the links entirely
239 | # admin.download_links = false
240 | #
241 | # # Only show XML & PDF options
242 | # admin.download_links = [:xml, :pdf]
243 | #
244 | # # Enable/disable the links based on block
245 | # # (for example, with cancan)
246 | # admin.download_links = proc { can?(:view_download_links) }
247 | #
248 | # end
249 |
250 | # == Pagination
251 | #
252 | # Pagination is enabled by default for all resources.
253 | # You can control the default per page count for all resources here.
254 | #
255 | # config.default_per_page = 30
256 | #
257 | # You can control the max per page count too.
258 | #
259 | # config.max_per_page = 10_000
260 |
261 | # == Filters
262 | #
263 | # By default the index screen includes a "Filters" sidebar on the right
264 | # hand side with a filter for each attribute of the registered model.
265 | # You can enable or disable them for all resources here.
266 | #
267 | # config.filters = true
268 | #
269 | # By default the filters include associations in a select, which means
270 | # that every record will be loaded for each association.
271 | # You can enabled or disable the inclusion
272 | # of those filters by default here.
273 | #
274 | # config.include_default_association_filters = true
275 | end
276 |
--------------------------------------------------------------------------------
/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # ApplicationController.renderer.defaults.merge!(
4 | # http_host: 'example.org',
5 | # https: false
6 | # )
7 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using
4 | # but don't wish to see in your backtraces.
5 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
6 |
7 | # You can also remove all the silencers if you're trying to debug a problem
8 | # that might stem from framework code.
9 | # Rails.backtrace_cleaner.remove_silencers!
10 |
--------------------------------------------------------------------------------
/config/initializers/devise.rb:
--------------------------------------------------------------------------------
1 | # Use this hook to configure devise mailer, warden hooks and so forth.
2 | # Many of these configuration options can be set straight in your model.
3 | Devise.setup do |config|
4 | # ==> Mailer Configuration
5 | # Configure the e-mail address which will be shown in Devise::Mailer,
6 | # note that it will be overwritten if you use your own mailer class
7 | # with default "from" parameter.
8 | config.mailer_sender = 'no-reply@yourapi.com'
9 |
10 | # Configure the class responsible to send e-mails.
11 | # config.mailer = 'Devise::Mailer'
12 |
13 | # Configure the parent class responsible to send e-mails.
14 | # config.parent_mailer = 'ActionMailer::Base'
15 |
16 | # ==> ORM configuration
17 | # Load and configure the ORM. Supports :active_record (default) and
18 | # :mongoid (bson_ext recommended) by default. Other ORMs may be
19 | # available as additional gems.
20 | require 'devise/orm/active_record'
21 |
22 | # ==> Configuration for any authentication mechanism
23 | # Configure which keys are used when authenticating a user. The default is
24 | # just :email. You can configure it to use [:username, :subdomain], so for
25 | # authenticating a user, both parameters are required. Remember that those
26 | # parameters are used only when authenticating and not when retrieving from
27 | # session. If you need permissions, you should implement that in a before filter.
28 | # You can also supply a hash where the value is a boolean determining whether
29 | # or not authentication should be aborted when the value is not present.
30 | # config.authentication_keys = [:email]
31 |
32 | # Configure parameters from the request object used for authentication. Each entry
33 | # given should be a request method and it will automatically be passed to the
34 | # find_for_authentication method and considered in your model lookup. For instance,
35 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
36 | # The same considerations mentioned for authentication_keys also apply to request_keys.
37 | # config.request_keys = []
38 |
39 | # Configure which authentication keys should be case-insensitive.
40 | # These keys will be downcased upon creating or modifying a user and when used
41 | # to authenticate or find a user. Default is :email.
42 | config.case_insensitive_keys = [:email]
43 |
44 | # Configure which authentication keys should have whitespace stripped.
45 | # These keys will have whitespace before and after removed upon creating or
46 | # modifying a user and when used to authenticate or find a user. Default is :email.
47 | config.strip_whitespace_keys = [:email]
48 |
49 | # Tell if authentication through request.params is enabled. True by default.
50 | # It can be set to an array that will enable params authentication only for the
51 | # given strategies, for example, `config.params_authenticatable = [:database]` will
52 | # enable it only for database (email + password) authentication.
53 | # config.params_authenticatable = true
54 |
55 | # Tell if authentication through HTTP Auth is enabled. False by default.
56 | # It can be set to an array that will enable http authentication only for the
57 | # given strategies, for example, `config.http_authenticatable = [:database]` will
58 | # enable it only for database authentication. The supported strategies are:
59 | # :database = Support basic authentication with authentication key + password
60 | # config.http_authenticatable = false
61 |
62 | # If 401 status code should be returned for AJAX requests. True by default.
63 | # config.http_authenticatable_on_xhr = true
64 |
65 | # The realm used in Http Basic Authentication. 'Application' by default.
66 | # config.http_authentication_realm = 'Application'
67 |
68 | # It will change confirmation, password recovery and other workflows
69 | # to behave the same regardless if the e-mail provided was right or wrong.
70 | # Does not affect registerable.
71 | # config.paranoid = true
72 |
73 | # By default Devise will store the user in session. You can skip storage for
74 | # particular strategies by setting this option.
75 | # Notice that if you are skipping storage for all authentication paths, you
76 | # may want to disable generating routes to Devise's sessions controller by
77 | # passing skip: :sessions to `devise_for` in your config/routes.rb
78 | config.skip_session_storage = [:http_auth]
79 |
80 | # By default, Devise cleans up the CSRF token on authentication to
81 | # avoid CSRF token fixation attacks. This means that, when using AJAX
82 | # requests for sign in and sign up, you need to get a new CSRF token
83 | # from the server. You can disable this option at your own risk.
84 | # config.clean_up_csrf_token_on_authentication = true
85 |
86 | # When false, Devise will not attempt to reload routes on eager load.
87 | # This can reduce the time taken to boot the app but if your application
88 | # requires the Devise mappings to be loaded during boot time the application
89 | # won't boot properly.
90 | # config.reload_routes = true
91 |
92 | # ==> Configuration for :database_authenticatable
93 | # For bcrypt, this is the cost for hashing the password and defaults to 11. If
94 | # using other algorithms, it sets how many times you want the password to be hashed.
95 | #
96 | # Limiting the stretches to just one in testing will increase the performance of
97 | # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use
98 | # a value less than 10 in other environments. Note that, for bcrypt (the default
99 | # algorithm), the cost increases exponentially with the number of stretches (e.g.
100 | # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation).
101 | config.stretches = Rails.env.test? ? 1 : 11
102 |
103 | # Set up a pepper to generate the hashed password.
104 | # config.pepper = '74b9703c1236923e970d8586f6d7b9e6e12faae5d680c46d006b86d595ea811e5e2c37c'
105 |
106 | # Send a notification email when the user's password is changed
107 | # config.send_password_change_notification = false
108 |
109 | # ==> Configuration for :confirmable
110 | # A period that the user is allowed to access the website even without
111 | # confirming their account. For instance, if set to 2.days, the user will be
112 | # able to access the website for two days without confirming their account,
113 | # access will be blocked just in the third day. Default is 0.days, meaning
114 | # the user cannot access the website without confirming their account.
115 | # config.allow_unconfirmed_access_for = 2.days
116 |
117 | # A period that the user is allowed to confirm their account before their
118 | # token becomes invalid. For example, if set to 3.days, the user can confirm
119 | # their account within 3 days after the mail was sent, but on the fourth day
120 | # their account can't be confirmed with the token any more.
121 | # Default is nil, meaning there is no restriction on how long a user can take
122 | # before confirming their account.
123 | # config.confirm_within = 3.days
124 |
125 | # If true, requires any email changes to be confirmed (exactly the same way as
126 | # initial account confirmation) to be applied. Requires additional unconfirmed_email
127 | # db field (see migrations). Until confirmed, new email is stored in
128 | # unconfirmed_email column, and copied to email column on successful confirmation.
129 | config.reconfirmable = true
130 |
131 | # Defines which key will be used when confirming an account
132 | # config.confirmation_keys = [:email]
133 |
134 | # ==> Configuration for :rememberable
135 | # The time the user will be remembered without asking for credentials again.
136 | # config.remember_for = 2.weeks
137 |
138 | # Invalidates all the remember me tokens when the user signs out.
139 | config.expire_all_remember_me_on_sign_out = true
140 |
141 | # If true, extends the user's remember period when remembered via cookie.
142 | # config.extend_remember_period = false
143 |
144 | # Options to be passed to the created cookie. For instance, you can set
145 | # secure: true in order to force SSL only cookies.
146 | # config.rememberable_options = {}
147 |
148 | # ==> Configuration for :validatable
149 | # Range for password length.
150 | config.password_length = 8..128
151 |
152 | # Email regex used to validate email formats. It simply asserts that
153 | # one (and only one) @ exists in the given string. This is mainly
154 | # to give user feedback and not to assert the e-mail validity.
155 | config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
156 |
157 | # ==> Configuration for :timeoutable
158 | # The time you want to timeout the user session without activity. After this
159 | # time the user will be asked for credentials again. Default is 30 minutes.
160 | # config.timeout_in = 30.minutes
161 |
162 | # ==> Configuration for :lockable
163 | # Defines which strategy will be used to lock an account.
164 | # :failed_attempts = Locks an account after a number of failed attempts to sign in.
165 | # :none = No lock strategy. You should handle locking by yourself.
166 | # config.lock_strategy = :failed_attempts
167 |
168 | # Defines which key will be used when locking and unlocking an account
169 | # config.unlock_keys = [:email]
170 |
171 | # Defines which strategy will be used to unlock an account.
172 | # :email = Sends an unlock link to the user email
173 | # :time = Re-enables login after a certain amount of time (see :unlock_in below)
174 | # :both = Enables both strategies
175 | # :none = No unlock strategy. You should handle unlocking by yourself.
176 | # config.unlock_strategy = :both
177 |
178 | # Number of authentication tries before locking an account if lock_strategy
179 | # is failed attempts.
180 | # config.maximum_attempts = 20
181 |
182 | # Time interval to unlock the account if :time is enabled as unlock_strategy.
183 | # config.unlock_in = 1.hour
184 |
185 | # Warn on the last attempt before the account is locked.
186 | # config.last_attempt_warning = true
187 |
188 | # ==> Configuration for :recoverable
189 | #
190 | # Defines which key will be used when recovering the password for an account
191 | # config.reset_password_keys = [:email]
192 |
193 | # Time interval you can reset your password with a reset password key.
194 | # Don't put a too small interval or your users won't have the time to
195 | # change their passwords.
196 | config.reset_password_within = 6.hours
197 |
198 | # When set to false, does not sign a user in automatically after their password is
199 | # reset. Defaults to true, so a user is signed in automatically after a reset.
200 | # config.sign_in_after_reset_password = true
201 |
202 | # ==> Configuration for :encryptable
203 | # Allow you to use another hashing or encryption algorithm besides bcrypt (default).
204 | # You can use :sha1, :sha512 or algorithms from others authentication tools as
205 | # :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20
206 | # for default behavior) and :restful_authentication_sha1 (then you should set
207 | # stretches to 10, and copy REST_AUTH_SITE_KEY to pepper).
208 | #
209 | # Require the `devise-encryptable` gem when using anything other than bcrypt
210 | # config.encryptor = :sha512
211 |
212 | # ==> Scopes configuration
213 | # Turn scoped views on. Before rendering "sessions/new", it will first check for
214 | # "users/sessions/new". It's turned off by default because it's slower if you
215 | # are using only default views.
216 | # config.scoped_views = false
217 |
218 | # Configure the default scope given to Warden. By default it's the first
219 | # devise role declared in your routes (usually :user).
220 | # config.default_scope = :user
221 |
222 | # Set this configuration to false if you want /users/sign_out to sign out
223 | # only the current scope. By default, Devise signs out all scopes.
224 | # config.sign_out_all_scopes = true
225 |
226 | # ==> Navigation configuration
227 | # Lists the formats that should be treated as navigational. Formats like
228 | # :html, should redirect to the sign in page when the user does not have
229 | # access, but formats like :xml or :json, should return 401.
230 | #
231 | # If you have any extra navigational formats, like :iphone or :mobile, you
232 | # should add them to the navigational formats lists.
233 | #
234 | # The "*/*" below is required to match Internet Explorer requests.
235 | config.navigational_formats = ['*/*', :html, :json]
236 |
237 | # The default HTTP method used to sign out a resource. Default is :delete.
238 | config.sign_out_via = :delete
239 |
240 | # ==> OmniAuth
241 | # Add a new OmniAuth provider. Check the wiki for more information on setting
242 | # up on your models and hooks.
243 | # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
244 |
245 | # ==> Warden configuration
246 | # If you want to use other strategies, that are not supported by Devise, or
247 | # change the failure app, you can configure them inside the config.warden block.
248 | #
249 | # config.warden do |manager|
250 | # manager.intercept_401 = false
251 | # manager.default_strategies(scope: :user).unshift :some_external_strategy
252 | # end
253 |
254 | # ==> Mountable engine configurations
255 | # When using Devise inside an engine, let's call it `MyEngine`, and this engine
256 | # is mountable, there are some extra configurations to be taken into account.
257 | # The following options are available, assuming the engine is mounted as:
258 | #
259 | # mount MyEngine, at: '/my_engine'
260 | #
261 | # The router that invoked `devise_for`, in the example above, would be:
262 | # config.router_name = :my_engine
263 | #
264 | # When using OmniAuth, Devise cannot automatically set OmniAuth path,
265 | # so you need to do it manually. For the users scope, it would be:
266 | # config.omniauth_path_prefix = '/my_engine/users/auth'
267 | end
268 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/config/initializers/new_framework_defaults.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 | #
3 | # This file contains migration options to ease your Rails 5.0 upgrade.
4 | #
5 | # Read the Rails 5.0 release notes for more info on each option.
6 |
7 | # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`.
8 | # Previous versions had false.
9 | ActiveSupport.to_time_preserves_timezone = true
10 |
11 | # Require `belongs_to` associations by default. Previous versions had false.
12 | Rails.application.config.active_record.belongs_to_required_by_default = true
13 |
14 | # Configure SSL options to enable HSTS with subdomains. Previous versions had false.
15 | Rails.application.config.ssl_options = { hsts: { subdomains: true } }
16 |
--------------------------------------------------------------------------------
/config/initializers/rack_cors.rb:
--------------------------------------------------------------------------------
1 | module App
2 | class Application < Rails::Application
3 | config.middleware.insert_before 0, Rack::Cors do
4 | allow do
5 | origins '*'
6 | resource '*',
7 | headers: :any,
8 | methods: %i[get post options put delete],
9 | expose: %w[access-token uid client]
10 | end
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/config/initializers/slack.rb:
--------------------------------------------------------------------------------
1 | Slack.configure do |config|
2 | config.token = ENV['SLACK_BOT_TOKEN']
3 | end
4 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json]
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/config/locales/devise.en.yml:
--------------------------------------------------------------------------------
1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
2 |
3 | en:
4 | devise:
5 | confirmations:
6 | confirmed: "Your email address has been successfully confirmed."
7 | send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes."
8 | send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes."
9 | failure:
10 | already_authenticated: "You are already signed in."
11 | inactive: "Your account is not activated yet."
12 | invalid: "Invalid %{authentication_keys} or password."
13 | locked: "Your account is locked."
14 | last_attempt: "You have one more attempt before your account is locked."
15 | not_found_in_database: "Invalid %{authentication_keys} or password."
16 | timeout: "Your session expired. Please sign in again to continue."
17 | unauthenticated: "You need to sign in or sign up before continuing."
18 | unconfirmed: "You have to confirm your email address before continuing."
19 | mailer:
20 | confirmation_instructions:
21 | subject: "Confirmation instructions"
22 | reset_password_instructions:
23 | subject: "Reset password instructions"
24 | unlock_instructions:
25 | subject: "Unlock instructions"
26 | password_change:
27 | subject: "Password Changed"
28 | omniauth_callbacks:
29 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
30 | success: "Successfully authenticated from %{kind} account."
31 | passwords:
32 | no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
33 | send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."
34 | send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
35 | updated: "Your password has been changed successfully. You are now signed in."
36 | updated_not_active: "Your password has been changed successfully."
37 | registrations:
38 | destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon."
39 | signed_up: "Welcome! You have signed up successfully."
40 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
41 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
42 | signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
43 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address."
44 | updated: "Your account has been updated successfully."
45 | sessions:
46 | signed_in: "Signed in successfully."
47 | signed_out: "Signed out successfully."
48 | already_signed_out: "Signed out successfully."
49 | unlocks:
50 | send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes."
51 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes."
52 | unlocked: "Your account has been unlocked successfully. Please sign in to continue."
53 | errors:
54 | messages:
55 | already_confirmed: "was already confirmed, please try signing in"
56 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
57 | expired: "has expired, please request a new one"
58 | not_found: "not found"
59 | not_locked: "was not locked"
60 | not_saved:
61 | one: "1 error prohibited this %{resource} from being saved:"
62 | other: "%{count} errors prohibited this %{resource} from being saved:"
63 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | api:
24 | errors:
25 | server: 'An error ocurred'
26 | not_found: "Couldn't find the record"
27 | missing_param: 'A required param is missing'
28 | invalid_content_type: 'Invalid content type header'
29 | facebook:
30 | not_authorized: 'Not Authorized'
31 | already_registerd: 'User already registered with email/password'
32 |
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | # Puma can serve each request in a thread from an internal thread pool.
2 | # The `threads` method setting takes two numbers a minimum and maximum.
3 | # Any libraries that use thread pools should be configured to match
4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
5 | # and maximum, this matches the default thread size of Active Record.
6 | #
7 | threads_count = ENV.fetch('RAILS_MAX_THREADS') { 5 }.to_i
8 | threads threads_count, threads_count
9 |
10 | # Specifies the `port` that Puma will listen on to receive requests, default is 3000.
11 | #
12 | port ENV.fetch('PORT') { 3000 }
13 |
14 | # Specifies the `environment` that Puma will run in.
15 | #
16 | environment ENV.fetch('RAILS_ENV') { 'development' }
17 |
18 | # Specifies the number of `workers` to boot in clustered mode.
19 | # Workers are forked webserver processes. If using threads and workers together
20 | # the concurrency of the application would be max `threads` * `workers`.
21 | # Workers do not work on JRuby or Windows (both of which do not support
22 | # processes).
23 | #
24 | # workers ENV.fetch('WEB_CONCURRENCY') { 2 }
25 |
26 | # Use the `preload_app!` method when specifying a `workers` number.
27 | # This directive tells Puma to first boot the application and load code
28 | # before forking the application. This takes advantage of Copy On Write
29 | # process behavior so workers use less memory. If you use this option
30 | # you need to make sure to reconnect any threads in the `on_worker_boot`
31 | # block.
32 | #
33 | # preload_app!
34 |
35 | # The code in the `on_worker_boot` will be called if you are using
36 | # clustered mode by specifying a number of `workers`. After each worker
37 | # process is booted this block will be run, if you are using `preload_app!`
38 | # option you will want to use this block to reconnect to any threads
39 | # or connections that may have been created at application boot, Ruby
40 | # cannot share connections between processes.
41 | #
42 | # on_worker_boot do
43 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
44 | # end
45 |
46 | # Allow puma to be restarted by `rails restart` command.
47 | plugin :tmp_restart
48 |
--------------------------------------------------------------------------------
/config/rails_best_practices.yml:
--------------------------------------------------------------------------------
1 | AddModelVirtualAttributeCheck: { }
2 | AlwaysAddDbIndexCheck: { }
3 | #CheckSaveReturnValueCheck: { }
4 | DefaultScopeIsEvilCheck: { }
5 | DryBundlerInCapistranoCheck: { }
6 | #HashSyntaxCheck: { }
7 | IsolateSeedDataCheck: { }
8 | KeepFindersOnTheirOwnModelCheck: { }
9 | LawOfDemeterCheck: { }
10 | #LongLineCheck: { max_line_length: 80 }
11 | MoveCodeIntoControllerCheck: { }
12 | MoveCodeIntoHelperCheck: { array_count: 3 }
13 | MoveCodeIntoModelCheck: { use_count: 2 }
14 | MoveFinderToNamedScopeCheck: { }
15 | MoveModelLogicIntoModelCheck: { use_count: 4 }
16 | NeedlessDeepNestingCheck: { nested_count: 2 }
17 | NotRescueExceptionCheck: { }
18 | NotUseDefaultRouteCheck: { }
19 | NotUseTimeAgoInWordsCheck: { }
20 | OveruseRouteCustomizationsCheck: { customize_count: 10 }
21 | ProtectMassAssignmentCheck: { }
22 | RemoveEmptyHelpersCheck: { }
23 | #RemoveTabCheck: { }
24 | RemoveTrailingWhitespaceCheck: { }
25 | # RemoveUnusedMethodsInControllersCheck: { except_methods: []}
26 | RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
27 | # RemoveUnusedMethodsInModelsCheck: { ignored_files: ['.*typeable\.rb'], except_methods: [] }
28 | ReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 2 }
29 | ReplaceInstanceVariableWithLocalVariableCheck: { }
30 | RestrictAutoGeneratedRoutesCheck: { }
31 | SimplifyRenderInControllersCheck: { }
32 | SimplifyRenderInViewsCheck: { }
33 | #UseBeforeFilterCheck: { customize_count: 2 }
34 | UseModelAssociationCheck: { }
35 | # UseMultipartAlternativeAsContentTypeOfEmailCheck: { }
36 | #UseParenthesesInMethodDefCheck: { }
37 | UseObserverCheck: { }
38 | UseQueryAttributeCheck: { }
39 | UseSayWithTimeInMigrationsCheck: { }
40 | UseScopeAccessCheck: { }
41 | UseTurboSprocketsRails3Check: { }
42 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | devise_for :admin_users, ActiveAdmin::Devise.config
3 | ActiveAdmin.routes(self)
4 |
5 | namespace :api do
6 | namespace :v1, defaults: { format: :json } do
7 | post '/notifications_filter', to: 'github_webhook#filter'
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/config/spring.rb:
--------------------------------------------------------------------------------
1 | %w[
2 | .ruby-version
3 | .rbenv-vars
4 | tmp/restart.txt
5 | tmp/caching-dev.txt
6 | ].each { |path| Spring.watch(path) }
7 |
--------------------------------------------------------------------------------
/db/migrate/20161011151353_devise_create_users.rb:
--------------------------------------------------------------------------------
1 | class DeviseCreateUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :users do |t|
4 | ## Database authenticatable
5 | t.string :email
6 | t.string :encrypted_password, null: false, default: ""
7 |
8 | ## Recoverable
9 | t.string :reset_password_token
10 | t.datetime :reset_password_sent_at
11 | t.boolean :allow_password_change, :default => false
12 |
13 | ## Rememberable
14 | t.datetime :remember_created_at
15 |
16 | ## Trackable
17 | t.integer :sign_in_count, default: 0, null: false
18 | t.datetime :current_sign_in_at
19 | t.datetime :last_sign_in_at
20 | t.inet :current_sign_in_ip
21 | t.inet :last_sign_in_ip
22 |
23 | ## Confirmable
24 | # t.string :confirmation_token
25 | # t.datetime :confirmed_at
26 | # t.datetime :confirmation_sent_at
27 | # t.string :unconfirmed_email # Only if using reconfirmable
28 |
29 | ## Lockable
30 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
31 | # t.string :unlock_token # Only if unlock strategy is :email or :both
32 | # t.datetime :locked_at
33 |
34 | t.string :first_name, default: ""
35 | t.string :last_name, default: ""
36 | t.string :username, default: ""
37 |
38 |
39 | t.timestamps null: false
40 | end
41 |
42 | add_index :users, :email, unique: true
43 | add_index :users, :reset_password_token, unique: true
44 | # add_index :users, :confirmation_token, unique: true
45 | # add_index :users, :unlock_token, unique: true
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/db/migrate/20161011184702_devise_create_admin_users.rb:
--------------------------------------------------------------------------------
1 | class DeviseCreateAdminUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | create_table :admin_users do |t|
4 | ## Database authenticatable
5 | t.string :email, null: false, default: ""
6 | t.string :encrypted_password, null: false, default: ""
7 |
8 | ## Recoverable
9 | t.string :reset_password_token
10 | t.datetime :reset_password_sent_at
11 |
12 | ## Rememberable
13 | t.datetime :remember_created_at
14 |
15 | ## Trackable
16 | t.integer :sign_in_count, default: 0, null: false
17 | t.datetime :current_sign_in_at
18 | t.datetime :last_sign_in_at
19 | t.inet :current_sign_in_ip
20 | t.inet :last_sign_in_ip
21 |
22 | ## Confirmable
23 | # t.string :confirmation_token
24 | # t.datetime :confirmed_at
25 | # t.datetime :confirmation_sent_at
26 | # t.string :unconfirmed_email # Only if using reconfirmable
27 |
28 | ## Lockable
29 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
30 | # t.string :unlock_token # Only if unlock strategy is :email or :both
31 | # t.datetime :locked_at
32 |
33 |
34 | t.timestamps null: false
35 | end
36 |
37 | add_index :admin_users, :email, unique: true
38 | add_index :admin_users, :reset_password_token, unique: true
39 | # add_index :admin_users, :confirmation_token, unique: true
40 | # add_index :admin_users, :unlock_token, unique: true
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/db/migrate/20161017183759_add_devise_token_auth_fields_users.rb:
--------------------------------------------------------------------------------
1 | class AddDeviseTokenAuthFieldsUsers < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :users, :provider, :string, null: false, default: 'email'
4 | add_column :users, :uid, :string, null: false, default: ''
5 | add_column :users, :tokens, :json
6 |
7 | add_index :users, [:uid, :provider], unique: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20161027190856_create_delayed_jobs.rb:
--------------------------------------------------------------------------------
1 | class CreateDelayedJobs < ActiveRecord::Migration[5.0]
2 | def self.up
3 | create_table :delayed_jobs, force: true do |table|
4 | table.integer :priority, default: 0, null: false # Allows some jobs to jump to the front of the queue
5 | table.integer :attempts, default: 0, null: false # Provides for retries, but still fail eventually.
6 | table.text :handler, null: false # YAML-encoded string of the object that will do work
7 | table.text :last_error # reason for last failure (See Note below)
8 | table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
9 | table.datetime :locked_at # Set when a client is working on this object
10 | table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
11 | table.string :locked_by # Who is working on this object (if locked)
12 | table.string :queue # The name of the queue this job is in
13 | table.timestamps null: true
14 | end
15 |
16 | add_index :delayed_jobs, [:priority, :run_at], name: "delayed_jobs_priority"
17 | end
18 |
19 | def self.down
20 | drop_table :delayed_jobs
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/db/migrate/20190418132233_modify_users.rb:
--------------------------------------------------------------------------------
1 | class ModifyUsers < ActiveRecord::Migration[5.1]
2 | def change
3 | remove_column :users, :provider, :string, null: false, default: 'email'
4 | remove_column :users, :uid, :string, null: false, default: ''
5 | remove_column :users, :tokens, :json
6 | remove_column :users, :encrypted_password, :string, null: false, default: ''
7 | remove_column :users, :reset_password_token, :string
8 | remove_column :users, :reset_password_sent_at, :datetime
9 | remove_column :users, :allow_password_change, :boolean, default: false
10 | remove_column :users, :remember_created_at, :datetime
11 | remove_column :users, :sign_in_count, :integer, null: false, default: 0
12 | remove_column :users, :current_sign_in_at, :datetime
13 | remove_column :users, :last_sign_in_at, :datetime
14 | remove_column :users, :current_sign_in_ip, :inet
15 | remove_column :users, :last_sign_in_ip, :inet
16 | remove_column :users, :username, :string, default: ''
17 | remove_index :users, :email
18 |
19 | add_column :users, :github_name, :string
20 | add_index :users, :github_name
21 | add_column :users, :slack_name, :string
22 | add_column :users, :blacklisted, :boolean, default: false
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/db/schema.rb:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from the current state of the database. Instead
2 | # of editing this file, please use the migrations feature of Active Record to
3 | # incrementally modify your database, and then regenerate this schema definition.
4 | #
5 | # Note that this schema.rb definition is the authoritative source for your
6 | # database schema. If you need to create the application database on another
7 | # system, you should be using db:schema:load, not running all the migrations
8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 | # you'll amass, the slower it'll run and the greater likelihood for issues).
10 | #
11 | # It's strongly recommended that you check this file into your version control system.
12 |
13 | ActiveRecord::Schema.define(version: 20190418132233) do
14 |
15 | # These are extensions that must be enabled in order to support this database
16 | enable_extension "plpgsql"
17 |
18 | create_table "admin_users", id: :serial, force: :cascade do |t|
19 | t.string "email", default: "", null: false
20 | t.string "encrypted_password", default: "", null: false
21 | t.string "reset_password_token"
22 | t.datetime "reset_password_sent_at"
23 | t.datetime "remember_created_at"
24 | t.integer "sign_in_count", default: 0, null: false
25 | t.datetime "current_sign_in_at"
26 | t.datetime "last_sign_in_at"
27 | t.inet "current_sign_in_ip"
28 | t.inet "last_sign_in_ip"
29 | t.datetime "created_at", null: false
30 | t.datetime "updated_at", null: false
31 | t.index ["email"], name: "index_admin_users_on_email", unique: true
32 | t.index ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true
33 | end
34 |
35 | create_table "delayed_jobs", id: :serial, force: :cascade do |t|
36 | t.integer "priority", default: 0, null: false
37 | t.integer "attempts", default: 0, null: false
38 | t.text "handler", null: false
39 | t.text "last_error"
40 | t.datetime "run_at"
41 | t.datetime "locked_at"
42 | t.datetime "failed_at"
43 | t.string "locked_by"
44 | t.string "queue"
45 | t.datetime "created_at"
46 | t.datetime "updated_at"
47 | t.index ["priority", "run_at"], name: "delayed_jobs_priority"
48 | end
49 |
50 | create_table "users", id: :serial, force: :cascade do |t|
51 | t.string "email"
52 | t.string "first_name", default: ""
53 | t.string "last_name", default: ""
54 | t.datetime "created_at", null: false
55 | t.datetime "updated_at", null: false
56 | t.string "github_name"
57 | t.string "slack_name"
58 | t.boolean "blacklisted", default: false
59 | t.index ["github_name"], name: "index_users_on_github_name"
60 | end
61 |
62 | end
63 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | AdminUser.create!(email: 'admin@example.com', password: 'password')
2 |
3 | User.create!(github_name: 'dependabot', blacklisted: true)
4 |
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rootstrap/pull_requests_to_slack/67ee96a3d3f4a45a0ec977c4de3855355ff0579b/lib/tasks/.keep
--------------------------------------------------------------------------------
/lib/tasks/add_blocklisted_user.rake:
--------------------------------------------------------------------------------
1 | desc 'Adds a user to the blocklist. ' \
2 | 'Use "rake add_blocklisted_user some_gh_name"'
3 | task add_blocklisted_user: [:environment] do
4 | ARGV.each { |a| task(a.to_sym {}) }
5 | name = ARGV[1]
6 |
7 | if name.present?
8 | User.create!(github_name: name, blacklisted: true)
9 | else
10 | warn 'Invalid or missing GitHub name param'
11 | warn 'Use "rake add_blocklisted_user some_gh_name"'
12 | exit(255)
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/tasks/auto_annotate_models.rake:
--------------------------------------------------------------------------------
1 | # NOTE: only doing this in development as some production environments (Heroku)
2 | # NOTE: are sensitive to local FS writes, and besides -- it's just not proper
3 | # NOTE: to have a dev-mode tool do its thing in production.
4 | if Rails.env.development?
5 | task :set_annotation_options do
6 | # You can override any of these by setting an environment variable of the
7 | # same name.
8 | Annotate.set_defaults(
9 | 'position_in_routes' => 'before',
10 | 'position_in_class' => 'before',
11 | 'position_in_test' => 'before',
12 | 'position_in_fixture' => 'before',
13 | 'position_in_factory' => 'before',
14 | 'show_indexes' => 'true',
15 | 'simple_indexes' => 'false',
16 | 'model_dir' => 'app/models',
17 | 'include_version' => 'false',
18 | 'require' => '',
19 | 'exclude_tests' => 'false',
20 | 'exclude_fixtures' => 'false',
21 | 'exclude_factories' => 'false',
22 | 'ignore_model_sub_dir' => 'false',
23 | 'skip_on_db_migrate' => 'false',
24 | 'format_bare' => 'true',
25 | 'format_rdoc' => 'false',
26 | 'format_markdown' => 'false',
27 | 'sort' => 'false',
28 | 'force' => 'false',
29 | 'trace' => 'false'
30 | )
31 | end
32 |
33 | Annotate.load_tasks
34 | end
35 |
--------------------------------------------------------------------------------
/lib/tasks/code_analysis.rake:
--------------------------------------------------------------------------------
1 | task :code_analysis do
2 | sh 'bundle exec brakeman . -z -q'
3 | sh 'bundle exec rubocop app config lib spec'
4 | sh 'bundle exec reek app config lib'
5 | sh 'bundle exec rails_best_practices .'
6 | end
7 |
--------------------------------------------------------------------------------
/lib/tasks/rails_best_practices.rake:
--------------------------------------------------------------------------------
1 | task :rails_best_practices do
2 | sh 'bundle exec rails_best_practices .'
3 | end
4 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/spec/admin/active_admin_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe 'activeadmin resources' do
4 | let(:all_resources) { ActiveAdmin.application.namespaces[:admin].resources }
5 |
6 | it 'should have admin user resource' do
7 | expect(all_resources[:AdminUser]).to be
8 | end
9 |
10 | it 'should have user resource' do
11 | expect(all_resources[:User]).to be
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/admin/controllers/users_controller_spec.rb:
--------------------------------------------------------------------------------
1 | describe Admin::UsersController, type: :controller do
2 | describe 'index' do
3 | it 'redirect to login page when not logged in' do
4 | get :index
5 | expect(response).to redirect_to new_admin_user_session_path
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/factories/spec.rb:
--------------------------------------------------------------------------------
1 | describe FactoryBot do
2 | FactoryBot.factories.map(&:name).each do |factory_name|
3 | describe "The #{factory_name} factory" do
4 | it { expect(FactoryBot.build(factory_name)).to be_valid }
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/factories/user.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :user do
3 | email { Faker::Internet.unique.email }
4 | github_name { Faker::Internet.unique.user_name }
5 | blacklisted { false }
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/helpers.rb:
--------------------------------------------------------------------------------
1 | module Helpers
2 | # Helper method to parse a response
3 | #
4 | # @return [Hash]
5 | def json
6 | JSON.parse(response.body).with_indifferent_access
7 | end
8 |
9 | def auth_headers
10 | user.create_new_auth_token
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/models/user_spec.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # email :string
7 | # first_name :string default("")
8 | # last_name :string default("")
9 | # created_at :datetime not null
10 | # updated_at :datetime not null
11 | # github_name :string
12 | # slack_name :string
13 | # blacklisted :boolean default(FALSE)
14 | #
15 | # Indexes
16 | #
17 | # index_users_on_github_name (github_name)
18 | #
19 |
20 | require 'rails_helper'
21 |
22 | describe User do
23 | context 'when was created with regular login' do
24 | let!(:user) { create(:user) }
25 | let(:full_name) { user.full_name }
26 |
27 | it 'returns the correct name' do
28 | expect(full_name).to eq(user.github_name)
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # This file is copied to spec/ when you run 'rails generate rspec:install'
2 | ENV['RAILS_ENV'] ||= 'test'
3 | require File.expand_path('../config/environment', __dir__)
4 | # Prevent database truncation if the environment is production
5 | abort('The Rails environment is running in production mode!') if Rails.env.production?
6 | require 'rspec/core'
7 | require 'spec_helper'
8 | require 'rspec/rails'
9 | require 'simplecov'
10 |
11 | # save to CircleCI's artifacts directory if we're on CircleCI
12 | if ENV['CIRCLE_ARTIFACTS']
13 | dir = File.join(ENV['CIRCLE_ARTIFACTS'], 'coverage')
14 | SimpleCov.coverage_dir(dir)
15 | end
16 | SimpleCov.start
17 |
18 | ActiveRecord::Migration.maintain_test_schema!
19 | WebMock.disable_net_connect!(allow_localhost: true)
20 |
21 | RSpec.configure do |config|
22 | config.include Devise::Test::ControllerHelpers, type: :controller
23 | config.use_transactional_fixtures = true
24 | config.infer_spec_type_from_file_location!
25 | end
26 |
--------------------------------------------------------------------------------
/spec/requests/api/v1/github_webhook/filter_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe 'GET api/v1/notifications_filter', type: :request do
4 | let(:channel) { '#code-review' }
5 | let(:pull_request_link) { 'https://github.com/rootstrap/example-project/pull/1' }
6 | let(:message) { "#{pull_request_link} <@user> Tiny PR :javascript:" }
7 | let(:pull_request) do
8 | {
9 | html_url: pull_request_link,
10 | title: 'Update the README with new information',
11 | ts: '1234',
12 | body: 'This is the body \slack @user Tiny PR',
13 | user: {
14 | login: 'user',
15 | avatar_url: 'image.png'
16 | }
17 | }
18 | end
19 |
20 | let(:recovered_channel) do
21 | Slack::Messages::Message.new(channel: channel)
22 | end
23 |
24 | before { mock_channel_response(nil) }
25 |
26 | context 'when there is an open pull request notification' do
27 | let(:params) do
28 | {
29 | action: 'opened',
30 | pull_request: pull_request,
31 | repository: {
32 | language: 'JavaScript',
33 | name: 'example'
34 | }
35 | }
36 | end
37 |
38 | it 'sends a slack notification to a given channel with the PR notification' do
39 | expect_notification
40 | end
41 |
42 | context 'when repository includes angular code' do
43 | it 'sends message to correct channel' do
44 | params[:repository][:name] = 'example-Angular-repository'
45 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :angular:")
46 | end
47 | end
48 |
49 | context 'when repository is a devops repository' do
50 | let(:channel) { '#devops-code-review' }
51 | before { mock_channel_response(channel) }
52 |
53 | it 'sends message to correct channel' do
54 | params[:repository][:name] = 'repository-devops-project '
55 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :javascript:")
56 | end
57 |
58 | it 'sends message to correct channel' do
59 | params[:repository][:name] = 'repository-infrastructure '
60 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :javascript:")
61 | end
62 |
63 | it 'sends message to correct channel' do
64 | params[:repository][:topics] = ['terraform']
65 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :javascript:")
66 | end
67 | end
68 |
69 | context 'repository name includes a technology' do
70 | before { mock_channel_response(channel) }
71 |
72 | context 'technology is react native' do
73 | let(:channel) { '#react-native-code-review' }
74 |
75 | it 'sends a slack notification with the PR link and language emoji' do
76 | params[:repository][:name] = 'example-React-Native'
77 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :react_native:")
78 | end
79 | end
80 |
81 | context 'technology is node' do
82 | let(:channel) { '#node-code-review' }
83 |
84 | it 'sends a slack notification with the PR link and language emoji' do
85 | params[:repository][:name] = 'example-Node-repo'
86 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :nodejs:")
87 | end
88 | end
89 | end
90 |
91 | context 'with a technology topic' do
92 | context 'with node topic' do
93 | let(:channel) { '#node-code-review' }
94 | before { mock_channel_response(channel) }
95 |
96 | it 'sends a slack notification with the PR link and language emoji' do
97 | params[:repository][:topics] = ['github', 'node', 'bot', 'slakbot']
98 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :javascript:")
99 | end
100 | end
101 |
102 | context 'with react-native topic' do
103 | let(:channel) { '#react-native-code-review' }
104 | before { mock_channel_response(channel) }
105 |
106 | it 'sends a slack notification with the PR link and language emoji' do
107 | params[:repository][:topics] = ['github', 'react-native', 'bot', 'slakbot']
108 | params[:repository][:language] = 'TypeScript'
109 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :ts:")
110 | end
111 | end
112 | end
113 |
114 | context 'with a language not supported' do
115 | let(:channel) { '#code-review' }
116 |
117 | it 'sends a slack notification with the PR link to #code-reviewers channel' do
118 | params[:repository][:language] = 'gherkin'
119 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :gherkin:")
120 | end
121 | end
122 |
123 | context 'with a language with no channel created' do
124 | let(:channel) { '#code-review' }
125 |
126 | it 'sends a slack notification with the PR link to #code-reviewers channel' do
127 | params[:repository][:language] = 'Makefile'
128 | expect_notification(text: "#{pull_request_link} <@user> Tiny PR :makefile:")
129 | end
130 | end
131 |
132 | context 'pr body does not include a \slack message' do
133 | it 'sends a slack notification with the PR link and language emoji' do
134 | pull_request[:body] = 'This is a simple body'
135 | expect_notification(text: "#{pull_request_link} :javascript:")
136 | end
137 | end
138 |
139 | context 'when the user is blacklisted' do
140 | let!(:user) { create(:user, github_name: 'blacklisted_user', blacklisted: true) }
141 | it 'does not sends a slack notification with the PR link' do
142 | pull_request[:user][:login] = 'blacklisted_user'
143 | expect_not_notification
144 | end
145 | end
146 | end
147 |
148 | context 'when there is a closed pull request notification' do
149 | let(:params) do
150 | {
151 | action: 'closed',
152 | pull_request: pull_request
153 | }
154 | end
155 |
156 | it 'does NOT send a notification' do
157 | expect_not_notification
158 | end
159 | end
160 |
161 | context 'when there is a merged pull request notification' do
162 | let(:params) do
163 | {
164 | action: 'closed',
165 | pull_request: pull_request.merge('merged' => true)
166 | }
167 | end
168 |
169 | it ' adds the merged reaction' do
170 | expect_any_instance_of(Slack::Web::Client).to receive(:search_messages)
171 | .and_return(messages: { matches: [{ ts: '1234' }] })
172 | expect_any_instance_of(Slack::Web::Client).to receive(:reactions_add)
173 | .with(name: :merged, channel: channel, timestamp: '1234', as_user: false)
174 |
175 | post api_v1_notifications_filter_path, params: params, as: :json
176 | end
177 | end
178 |
179 | context 'when there is an draft request notification' do
180 | let(:params) do
181 | {
182 | action: 'opened',
183 | pull_request: pull_request.merge('draft' => true),
184 | repository: {
185 | language: 'JavaScript',
186 | name: 'example'
187 | }
188 | }
189 | end
190 |
191 | it 'does not sends a slack notification to a given channel with the PR notification' do
192 | expect_not_notification
193 | end
194 | end
195 |
196 | context 'when there is an ready_for_review request notification' do
197 | let(:params) do
198 | {
199 | action: 'ready_for_review',
200 | pull_request: pull_request,
201 | repository: {
202 | language: 'JavaScript',
203 | name: 'example'
204 | }
205 | }
206 | end
207 |
208 | it 'sends a slack notification to a given channel with the PR notification' do
209 | expect_notification
210 | end
211 | end
212 |
213 | context 'when the "on hold" label is removed' do
214 | let(:params) do
215 | {
216 | action: 'unlabeled',
217 | pull_request: pull_request,
218 | label: { name: 'ON HOLD' },
219 | repository: {
220 | language: 'JavaScript',
221 | name: 'example'
222 | }
223 | }
224 | end
225 |
226 | it 'sends a slack notification with the PR link and language emoji' do
227 | expect_notification
228 | end
229 | end
230 |
231 | context 'when there is an open pull request notification with the "ON HOLD" label' do
232 | let(:params) do
233 | {
234 | action: 'opened',
235 | pull_request: {
236 | html_url: pull_request_link,
237 | title: 'Update the README with new information',
238 | labels: [
239 | { name: 'ON HOLD' },
240 | { name: 'bug' }
241 | ]
242 | },
243 | repository: {
244 | language: 'JavaScript'
245 | }
246 | }
247 | end
248 |
249 | it 'does NOT send a notification' do
250 | expect_not_notification
251 | end
252 | end
253 |
254 | context 'when the "ON HOLD" label is added' do
255 | let(:params) do
256 | {
257 | action: 'labeled',
258 | pull_request: pull_request,
259 | label: { name: 'ON HOLD' }
260 | }
261 | end
262 |
263 | it 'deletes the messages that contains the PR link' do
264 | expect_any_instance_of(Slack::Web::Client).to receive(:search_messages)
265 | .and_return(messages: { matches: [{ ts: '1234' }] })
266 | expect_any_instance_of(Slack::Web::Client).to receive(:chat_delete)
267 | .with(channel: channel, ts: '1234')
268 | post api_v1_notifications_filter_path, params: params, as: :json
269 | end
270 | end
271 | end
272 |
273 | def expect_notification(text: message)
274 | expect_any_instance_of(Slack::Web::Client).to receive(:chat_postMessage)
275 | .with(channel: channel, text: text, username: 'user', icon_url: 'image.png')
276 |
277 | post api_v1_notifications_filter_path, params: params, as: :json
278 | end
279 |
280 | def expect_not_notification
281 | expect_any_instance_of(Slack::Web::Client).to_not receive(:chat_postMessage)
282 | post api_v1_notifications_filter_path, params: params, as: :json
283 | end
284 |
285 | def mock_channel_response(return_value)
286 | allow_any_instance_of(SlackNotificationService)
287 | .to receive(:search_channel)
288 | .and_return(return_value)
289 | end
290 |
--------------------------------------------------------------------------------
/spec/services/slack_bot_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe 'SlackBot' do
4 | let(:subject) { SlackBot.new(channel: 'demo_channel') }
5 |
6 | describe 'initialization' do
7 | it 'raise an error if channel is not present' do
8 | expect { SlackBot.new(channel: nil) }.to raise_error(ArgumentError, 'Invalid channel')
9 | expect { SlackBot.new(channel: '') }.to raise_error(ArgumentError, 'Invalid channel')
10 | end
11 | end
12 |
13 | describe '#language_emoji' do
14 | context 'when the repo includes React' do
15 | it 'returns the correct emoji' do
16 | expect(subject.language_emoji('javascript', 'this-is-react-repo')).to eq ':react:'
17 | end
18 | end
19 |
20 | context 'when there is no emoji in the hash' do
21 | it 'returns the default emoji (downcase language)' do
22 | expect(subject.language_emoji('Exotic', 'repo_name')).to eq ':exotic:'
23 | end
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/spec/services/slack_notification_service_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe SlackNotificationService do
4 | before do
5 | stub_request(:post, 'https://slack.com/api/conversations.list')
6 | .to_return(status: 200, body: '', headers: {})
7 | end
8 |
9 | describe 'initialization' do
10 | subject { described_class.new({}) }
11 |
12 | it 'logs an error if no "action" is set in params' do
13 | expect(Rails.logger).to receive(:warn).with('Warning! No action found on params: [{}]')
14 | subject
15 | end
16 | end
17 |
18 | describe '#send_notification' do
19 | subject { described_class.new(params).send_notification }
20 |
21 | let(:username) { Faker::Internet.username }
22 | let!(:user) do
23 | User.create(github_name: username, blacklisted: false)
24 | end
25 |
26 | context 'with valid params' do
27 | let(:random_action) { described_class::ACTION_METHODS.keys.sample }
28 | let(:channel_name) { described_class::DEFAULT_CHANNEL }
29 | let(:some_language) { 'Node' }
30 | let(:params) do
31 | {
32 | github_webhook: {
33 | action: random_action,
34 | label: { name: Faker::Internet.slug(words: '_') }
35 | },
36 | channel: channel_name,
37 | pull_request: {
38 | user: { login: username },
39 | body: Faker::Lorem.sentence
40 | },
41 | repository: {
42 | name: Faker::Internet.slug,
43 | language: some_language
44 | }
45 | }
46 | end
47 |
48 | before do
49 | stub_request(:post, 'https://slack.com/api/chat.postMessage')
50 | .with(
51 | body: {
52 | 'channel': channel_name,
53 | 'text': ' :nodejs:',
54 | 'username': username
55 | }
56 | ).to_return(status: 200, body: '', headers: {})
57 | end
58 |
59 | it 'sends the message' do
60 | expect_any_instance_of(described_class)
61 | .to receive(:send)
62 | .with(described_class::ACTION_METHODS[random_action])
63 | .and_call_original
64 | subject
65 | end
66 |
67 | context 'with a PR from a blacklisted user' do
68 | let!(:user) { User.create(github_name: username, blacklisted: true) }
69 |
70 | it 'does NOT send the message' do
71 | expect_any_instance_of(described_class).not_to receive(:send)
72 | subject
73 | end
74 | end
75 | end
76 | end
77 | end
78 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
2 | ENV['RAILS_ENV'] ||= 'test'
3 | require File.expand_path('../config/environment', __dir__)
4 |
5 | require 'factory_bot_rails'
6 | require 'helpers'
7 | require 'webmock/rspec'
8 |
9 | FactoryBot.factories.clear
10 | FactoryBot.reload
11 |
12 | Dir[Rails.root.join('spec/support/**/*.rb')].sort.each { |file| require file }
13 |
14 | RSpec.configure do |config|
15 | config.include Helpers
16 | config.expect_with :rspec do |expectations|
17 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
18 | end
19 |
20 | config.mock_with :rspec do |mocks|
21 | mocks.verify_partial_doubles = true
22 | end
23 |
24 | config.filter_run_excluding on_refactor: true
25 |
26 | config.shared_context_metadata_behavior = :apply_to_host_groups
27 | config.order = 'random'
28 | config.expect_with :rspec do |c|
29 | c.syntax = :expect
30 | end
31 | config.include FactoryBot::Syntax::Methods
32 |
33 | config.before :each do
34 | DatabaseCleaner.strategy = :transaction
35 | DatabaseCleaner.start
36 | ActionMailer::Base.deliveries.clear
37 | end
38 |
39 | config.after do
40 | DatabaseCleaner.clean
41 | end
42 |
43 | config.color = true
44 | end
45 |
--------------------------------------------------------------------------------