├── .browserslistrc
├── .buildpacks
├── .env.example
├── .eslintignore
├── .eslintrc.yml
├── .flowconfig
├── .gitignore
├── .hound.yml
├── .nvmrc
├── .rspec
├── .rubocop.yml
├── .ruby-gemset
├── .ruby-version
├── .tool-versions
├── .travis.yml
├── Gemfile
├── Gemfile.lock
├── Guardfile
├── LICENSE
├── Procfile
├── README.md
├── Rakefile
├── app
├── assets
│ ├── config
│ │ └── manifest.js
│ ├── images
│ │ └── .keep
│ ├── javascripts
│ │ ├── application.js
│ │ ├── cable.js
│ │ └── channels
│ │ │ └── .keep
│ └── stylesheets
│ │ ├── application.scss
│ │ ├── client.scss
│ │ └── partials
│ │ ├── _environment.scss
│ │ └── _print.scss
├── channels
│ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
├── controllers
│ ├── api
│ │ └── jwts_controller.rb
│ ├── application_controller.rb
│ ├── concerns
│ │ ├── jwt_token.rb
│ │ └── paging.rb
│ ├── home_controller.rb
│ ├── omniauth_callbacks_controller.rb
│ ├── registrations_controller.rb
│ └── sessions_controller.rb
├── helpers
│ └── application_helper.rb
├── jobs
│ └── application_job.rb
├── lib
│ ├── auth_token.rb
│ └── url_helper.rb
├── mailers
│ └── application_mailer.rb
├── models
│ ├── ability.rb
│ ├── application_record.rb
│ ├── authentication.rb
│ ├── permission.rb
│ ├── role.rb
│ └── user.rb
├── services
│ └── create_admin_service.rb
└── views
│ ├── devise
│ └── registrations
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ ├── home
│ └── index.html.erb
│ ├── layouts
│ ├── _head.html.erb
│ ├── _messages.html.erb
│ ├── _navigation.html.erb
│ ├── _show_environment.erb
│ ├── application.html.erb
│ └── client.html.erb
│ ├── shared
│ ├── _default_client_settings.html.erb
│ ├── _links.html.erb
│ └── _omniauth_error.html.erb
│ └── users
│ ├── _user.html.erb
│ ├── index.html.erb
│ └── show.html.erb
├── babel.config.js
├── bin
├── bootstrap
├── bundle
├── ci
├── deploy_heroku
├── rails
├── rake
├── setup
├── setup-linux
├── spring
├── update
├── webpack
├── webpack-dev-server
└── yarn
├── client
├── apps
│ ├── hello_world
│ │ ├── app.jsx
│ │ ├── assets
│ │ │ └── images
│ │ │ │ ├── atomicjolt.jpg
│ │ │ │ ├── atomicjolt.png
│ │ │ │ └── atomicjolt.svg
│ │ ├── components
│ │ │ ├── common
│ │ │ │ └── not_found.jsx
│ │ │ ├── home.jsx
│ │ │ ├── home.spec.jsx
│ │ │ └── layout
│ │ │ │ ├── errors.jsx
│ │ │ │ ├── index.jsx
│ │ │ │ └── index.spec.jsx
│ │ ├── html
│ │ │ ├── 404.html
│ │ │ ├── about.md
│ │ │ ├── crossdomain.xml
│ │ │ ├── humans.txt
│ │ │ ├── index.html
│ │ │ ├── layouts
│ │ │ │ ├── application.html
│ │ │ │ └── partials
│ │ │ │ │ ├── _google_analytics.html
│ │ │ │ │ ├── _head.html
│ │ │ │ │ └── _header.html
│ │ │ └── robots.txt
│ │ ├── libs
│ │ │ ├── __mocks__
│ │ │ │ └── assets.js
│ │ │ ├── assets.js
│ │ │ └── assets.spec.js
│ │ ├── middleware
│ │ │ └── api.js
│ │ ├── reducers
│ │ │ ├── application.js
│ │ │ ├── application.spec.js
│ │ │ └── index.js
│ │ ├── static
│ │ │ ├── .keep
│ │ │ ├── android-icon-144x144.png
│ │ │ ├── android-icon-192x192.png
│ │ │ ├── android-icon-36x36.png
│ │ │ ├── android-icon-48x48.png
│ │ │ ├── android-icon-72x72.png
│ │ │ ├── android-icon-96x96.png
│ │ │ ├── apple-icon-114x114.png
│ │ │ ├── apple-icon-120x120.png
│ │ │ ├── apple-icon-144x144.png
│ │ │ ├── apple-icon-152x152.png
│ │ │ ├── apple-icon-180x180.png
│ │ │ ├── apple-icon-57x57.png
│ │ │ ├── apple-icon-60x60.png
│ │ │ ├── apple-icon-72x72.png
│ │ │ ├── apple-icon-76x76.png
│ │ │ ├── apple-icon-precomposed.png
│ │ │ ├── apple-icon.png
│ │ │ ├── browserconfig.xml
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── favicon-96x96.png
│ │ │ ├── favicon.ico
│ │ │ ├── manifest.json
│ │ │ ├── ms-icon-144x144.png
│ │ │ ├── ms-icon-150x150.png
│ │ │ ├── ms-icon-310x310.png
│ │ │ └── ms-icon-70x70.png
│ │ ├── store
│ │ │ └── configure_store.js
│ │ └── styles
│ │ │ ├── .csscomb.json
│ │ │ ├── .csslintrc
│ │ │ ├── _defines.scss
│ │ │ ├── fonts
│ │ │ ├── roboto-bold-webfont.woff
│ │ │ ├── roboto-bold-webfont.woff2
│ │ │ ├── roboto-regular-webfont.woff
│ │ │ └── roboto-regular-webfont.woff2
│ │ │ ├── modules
│ │ │ └── _mixins.scss
│ │ │ ├── styles.js
│ │ │ ├── styles.less
│ │ │ └── styles.scss
│ └── hello_world_graphql
│ │ ├── app.jsx
│ │ ├── assets
│ │ └── images
│ │ │ ├── atomicjolt.jpg
│ │ │ ├── atomicjolt.png
│ │ │ └── atomicjolt.svg
│ │ ├── components
│ │ ├── common
│ │ │ └── not_found.jsx
│ │ ├── home.jsx
│ │ ├── home.spec.jsx
│ │ └── layout
│ │ │ ├── index.jsx
│ │ │ └── index.spec.jsx
│ │ ├── history.js
│ │ ├── html
│ │ ├── 404.html
│ │ ├── about.md
│ │ ├── crossdomain.xml
│ │ ├── humans.txt
│ │ ├── index.html
│ │ ├── layouts
│ │ │ ├── application.html
│ │ │ └── partials
│ │ │ │ ├── _google_analytics.html
│ │ │ │ ├── _head.html
│ │ │ │ └── _header.html
│ │ └── robots.txt
│ │ ├── libs
│ │ ├── __mocks__
│ │ │ └── assets.js
│ │ ├── assets.js
│ │ └── assets.spec.js
│ │ ├── settings.js
│ │ ├── static
│ │ ├── .keep
│ │ ├── android-icon-144x144.png
│ │ ├── android-icon-192x192.png
│ │ ├── android-icon-36x36.png
│ │ ├── android-icon-48x48.png
│ │ ├── android-icon-72x72.png
│ │ ├── android-icon-96x96.png
│ │ ├── apple-icon-114x114.png
│ │ ├── apple-icon-120x120.png
│ │ ├── apple-icon-144x144.png
│ │ ├── apple-icon-152x152.png
│ │ ├── apple-icon-180x180.png
│ │ ├── apple-icon-57x57.png
│ │ ├── apple-icon-60x60.png
│ │ ├── apple-icon-72x72.png
│ │ ├── apple-icon-76x76.png
│ │ ├── apple-icon-precomposed.png
│ │ ├── apple-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon-96x96.png
│ │ ├── favicon.ico
│ │ ├── manifest.json
│ │ ├── ms-icon-144x144.png
│ │ ├── ms-icon-150x150.png
│ │ ├── ms-icon-310x310.png
│ │ └── ms-icon-70x70.png
│ │ └── styles
│ │ ├── .csscomb.json
│ │ ├── .csslintrc
│ │ ├── _defines.scss
│ │ ├── fonts
│ │ ├── roboto-bold-webfont.woff
│ │ ├── roboto-bold-webfont.woff2
│ │ ├── roboto-regular-webfont.woff
│ │ └── roboto-regular-webfont.woff2
│ │ ├── modules
│ │ └── _mixins.scss
│ │ ├── styles.js
│ │ ├── styles.less
│ │ └── styles.scss
├── packs
│ ├── hello_world.js
│ └── hello_world_graphql.js
└── testing
│ ├── __mocks__
│ ├── file_mock.js
│ └── style_mock.js
│ ├── setup_tests.js
│ └── shim.js
├── config.ru
├── config
├── application.rb
├── boot.rb
├── cable.yml
├── ci.database.yml
├── database.example.yml
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── application_controller_renderer.rb
│ ├── assets.rb
│ ├── backtrace_silencers.rb
│ ├── content_security_policy.rb
│ ├── cookies_serializer.rb
│ ├── devise.rb
│ ├── filter_parameter_logging.rb
│ ├── inflections.rb
│ ├── mime_types.rb
│ ├── new_framework_defaults.rb
│ ├── new_framework_defaults_5_1.rb
│ ├── new_framework_defaults_5_2.rb
│ ├── session_store.rb
│ ├── webpack.rb
│ └── wrap_parameters.rb
├── locales
│ └── en.yml
├── puma.rb
├── routes.rb
├── secrets.example.yml
├── spring.rb
├── storage.yml
├── webpack
│ ├── development.js
│ ├── environment.js
│ ├── production.js
│ └── test.js
└── webpacker.yml
├── db
├── migrate
│ ├── 20120209004849_initial.rb
│ ├── 20170612172246_add_context_id_to_permission.rb
│ ├── 20170613231518_add_create_type_to_user.rb
│ ├── 20170921202325_add_authentication_index.rb
│ ├── 20171003155408_change_rr_integer_to_bigint.rb
│ ├── 20181127204956_remove_unused_fields.rb
│ └── 20190219201006_add_unique_index_to_permissions.rb
├── schema.rb
└── seeds.rb
├── lib
├── assets
│ └── .keep
└── tasks
│ └── .keep
├── log
└── .keep
├── package.json
├── postcss.config.js
├── public
├── 401.html
├── 404.html
├── 422.html
├── 500.html
├── android-icon-144x144.png
├── android-icon-192x192.png
├── android-icon-36x36.png
├── android-icon-48x48.png
├── android-icon-72x72.png
├── android-icon-96x96.png
├── apple-icon-114x114.png
├── apple-icon-120x120.png
├── apple-icon-144x144.png
├── apple-icon-152x152.png
├── apple-icon-180x180.png
├── apple-icon-57x57.png
├── apple-icon-60x60.png
├── apple-icon-72x72.png
├── apple-icon-76x76.png
├── apple-icon-precomposed.png
├── apple-icon.png
├── browserconfig.xml
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon-96x96.png
├── favicon.ico
├── logo.png
├── ms-icon-144x144.png
├── ms-icon-150x150.png
├── ms-icon-310x310.png
├── ms-icon-70x70.png
├── oauth_icon.png
└── robots.txt
├── spec
├── controllers
│ ├── api
│ │ └── jwts_controller_spec.rb
│ ├── concerns
│ │ ├── jwt_token_spec.rb
│ │ └── paging_spec.rb
│ └── home_controller_spec.rb
├── factories
│ ├── _common.rb
│ ├── authentication.rb
│ ├── permission.rb
│ ├── role.rb
│ └── users.rb
├── fixtures
│ └── avatar.jpg
├── helpers
│ └── application_helper_spec.rb
├── lib
│ ├── auth_token_spec.rb
│ └── url_helper_spec.rb
├── models
│ ├── authentication_spec.rb
│ ├── permission_spec.rb
│ ├── role_spec.rb
│ └── user_spec.rb
├── rails_helper.rb
├── spec_helper.rb
└── support
│ ├── capybara.rb
│ ├── controller_macros.rb
│ ├── http_party.rb
│ ├── omniauth.rb
│ └── webmock_requests.rb
├── template.rb
├── vendor
└── assets
│ ├── javascripts
│ └── .keep
│ └── stylesheets
│ └── .keep
└── yarn.lock
/.browserslistrc:
--------------------------------------------------------------------------------
1 | defaults
2 |
--------------------------------------------------------------------------------
/.buildpacks:
--------------------------------------------------------------------------------
1 | https://github.com/heroku/heroku-buildpack-nodejs.git#v86
2 | https://github.com/heroku/heroku-buildpack-ruby.git#v140
3 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | APP_SUBDOMAIN=reactrailsstarterapp
2 | APP_ROOT_DOMAIN=reactrailsstarterapp.dev
3 | APP_PORT=3000
4 | ASSETS_SUBDOMAIN=assets
5 | ASSETS_PORT=3035 # This is the default port used by webpacker
6 |
7 |
8 | # ASSETS_URL is used for the webpack server's public path and will set an absolute url
9 | # when loading assets. Not setting a value means the assets will be loaded from the local
10 | # server. This works fine in development and will also work if you attempt to access your
11 | # development server from a remote device (such as a mobile phone) for testing. You can set
12 | # a localhost value if desired however note that doing so will prevent the assets from loading
13 | # properly when attempting to access the server from a remote device.
14 | # ASSETS_URL is mainly in place for situations where the react client starter app is incorporated
15 | # into another project such as Ruby on Rails where there will be multiple servers. In this situation
16 | # the client application will likely be loaded via a link in a page served from the Rail (or other similar)
17 | # server. Since the webpack server will be serving assets on a different port (or domain) we can't use
18 | # the default root path since doing so will result in the scripts requesting assets from the Rails
19 | # server instead of the webpack server. In this instance setting ASSETS_URL will tell webpack to
20 | # build and serve assets from a specific url - the webpack server's url.
21 |
22 | # Use localhost
23 | ASSETS_URL=http://0.0.0.0
24 |
25 | # Use a local domain.
26 | # Change /etc/hosts (on a mac) and add sites.dev and rcsassets.sites.dev. Each entry will need to point to 127.0.0.1
27 | # ASSETS_URL=http://rcsassets.sites.dev
28 |
29 | ASSETS_URL=https://assets.reactrailsstarterapp.dev
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # /node_modules/* and /bower_components/* ignored by default
2 |
3 | # Ignore built files except build/index.js
4 | build/*
5 | !build/index.js
6 |
--------------------------------------------------------------------------------
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | ---
2 | env:
3 | browser: true
4 | es6: true
5 | extends: airbnb
6 | parser: babel-eslint
7 | plugins:
8 | - react
9 | - jsx-a11y
10 | - import
11 | globals:
12 | describe: false
13 | beforeAll: false
14 | beforeEach: false
15 | afterEach: false
16 | it: false
17 | expect: false
18 | xit: false
19 | spyOn: false
20 | jasmine: false
21 | module: false
22 | jest: false
23 | require: false
24 | rules:
25 | linebreak-style:
26 | - error
27 | - unix
28 | import/no-unresolved: 0
29 | no-multi-spaces:
30 | - 1
31 | - exceptions:
32 | VariableDeclarator: true
33 | ImportDeclaration: true
34 | AssignmentExpression: true
35 | comma-dangle:
36 | - error
37 | - only-multiline
38 | import/no-extraneous-dependencies:
39 | - error
40 | - devDependencies: true
41 | padded-blocks: 0
42 | key-spacing: 0
43 | react/require-default-props: 0
44 | react/no-danger: 0
45 | jsx-a11y/no-static-element-interactions: 0
46 | no-underscore-dangle: 0
47 | space-before-function-paren:
48 | - 2
49 | - never
50 | func-names:
51 | - 2
52 | - as-needed
53 | react/prefer-stateless-function: 0
54 | react/forbid-prop-types:
55 | - 2
56 | - forbid:
57 | - any
58 | import/extensions: 0
59 | react/prop-types: 0
60 | import/no-named-as-default: 0
61 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | .*/node_modules/.*
3 | .*/apps/.*
4 | [include]
5 |
6 | [libs]
7 |
8 | [lints]
9 |
10 | [options]
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 | /vendor/bundle
10 |
11 | # Ignore the default SQLite database.
12 | /db/*.sqlite3
13 | /db/*.sqlite3-journal
14 |
15 | # Ignore all logfiles and tempfiles.
16 | /log/*
17 | /tmp/*
18 | !/log/.keep
19 | !/tmp/.keep
20 |
21 | # Ignore Byebug command history file.
22 | .byebug_history
23 |
24 | # Ignore mac files
25 | .DS_Store
26 |
27 | # TODO Comment out these rules if you are OK with secrets being uploaded to the repo
28 | .env
29 | config/secrets.yml
30 | config/database.yml
31 | config/assets/
32 | bin/deploy
33 | s3_website.yml
34 | secrets.js
35 |
36 | # these should all be checked in to normalise the environment:
37 | # Gemfile.lock, .ruby-version, .ruby-gemset
38 |
39 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
40 | .rvmrc
41 |
42 | # if using bower-rails ignore default bower_components path bower.json files
43 | /vendor/assets/bower_components
44 | *.bowerrc
45 | bower.json
46 |
47 | # node artifacts
48 | client/node_modules
49 | node_modules
50 | npm-debug.log
51 | yarn-error.log
52 |
53 | # avoid adding built files
54 | /public/system
55 | public/assets
56 | /build
57 |
58 | # git artifacts
59 | **.orig
60 |
61 | # Test artifacts
62 | rerun.txt
63 | /coverage/
64 | /spec/tmp
65 |
66 | /.idea/
67 | /public/packs
68 | /public/packs-test
69 | /node_modules
70 | /yarn-error.log
71 | yarn-debug.log*
72 | .yarn-integrity
73 | .vscode
--------------------------------------------------------------------------------
/.hound.yml:
--------------------------------------------------------------------------------
1 | # reference: https://houndci.com/configuration
2 |
3 | fail_on_violations: true
4 |
5 | ruby:
6 | enabled: true
7 | config_file: .rubocop.yml
8 |
9 | eslint:
10 | enabled: true
11 | config_file: .eslintrc.yml
12 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 8.16.0
2 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 |
--------------------------------------------------------------------------------
/.ruby-gemset:
--------------------------------------------------------------------------------
1 | ltistarterapp
2 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.5.7
2 |
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | ruby 2.5.7
2 | nodejs 10.22.0
3 | postgres 9.5.19
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | sudo: required
3 | dist: trusty
4 |
5 | env:
6 | - CXX=g++-4.8
7 |
8 | addons:
9 | postgresql: "9.5"
10 | apt:
11 | sources:
12 | - ubuntu-toolchain-r-test
13 | packages:
14 | - g++-4.8
15 |
16 | cache:
17 | bundler: true
18 | directories:
19 | - node_modules
20 | - client/node_modules
21 | - client/apps/hello_world/node_modules
22 |
23 | branches:
24 | only:
25 | - master
26 | - staging
27 | - stable
28 |
29 | services:
30 | - postgresql
31 |
32 | before_install:
33 | - cp config/secrets.example.yml config/secrets.yml
34 | - cp config/ci.database.yml config/database.yml
35 | - cp .env.example .env
36 | - gem install bundler:1.17.3
37 | - nvm install 8.16.0
38 | - nvm use 8.16.0
39 | - npm install -g yarn
40 |
41 | install:
42 | - bundle install --path vendor/bundle
43 | - yarn
44 |
45 | before_script:
46 | - export CHROME_BIN=chromium-browser
47 | - "export DISPLAY=:99.0"
48 | - "sh -e /etc/init.d/xvfb start"
49 | - bundle exec rails db:create
50 | - bundle exec rails db:schema:load
51 |
52 | script:
53 | - ./bin/ci
54 | - yarn test
55 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # If bundler starts to act up run these commands to start over and clean up:
2 | # rm -rf ~/.bundle/ ~/.gem/; rm -rf $GEM_HOME/bundler/ $GEM_HOME/cache/bundler/; rm -rf .bundle/; rm -rf vendor/cache/; rm -rf Gemfile.lock
3 | # rvm gemset empty reactrailsstarterapp
4 | # bundle install
5 |
6 | source "https://rubygems.org"
7 |
8 | git_source(:github) do |repo_name|
9 | repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
10 | "https://github.com/#{repo_name}.git"
11 | end
12 |
13 | # Bundle edge Rails instead: gem "rails", github: "rails/rails"
14 | gem "rails", "~> 5.2.4"
15 |
16 | # Improve boot time
17 | gem "bootsnap", require: false
18 |
19 | # Database
20 | gem "pg"
21 |
22 | # authentication, authorization, integrations
23 | gem "attr_encrypted"
24 | gem "cancancan"
25 | gem "devise"
26 | gem "jwt", "~> 1.5.0" # json web token
27 | gem "oauth", "~> 0.5.0"
28 | gem "omniauth"
29 |
30 | # Email
31 | gem "sendgrid"
32 |
33 | # JSON parser
34 | gem "yajl-ruby", require: "yajl"
35 |
36 | # server
37 | gem "puma"
38 |
39 | # Used for deploying to Heroku. Can be removed if not deploying to Heroku.
40 | gem "heroku_secrets", git: "https://github.com/alexpeattie/heroku_secrets.git"
41 |
42 | # API Related
43 | gem "httparty"
44 | gem "rack-cors", require: "rack/cors"
45 |
46 | # Paging
47 | gem "will_paginate"
48 |
49 | # Javascript
50 | gem "webpacker"
51 |
52 | # Assets
53 | gem "sassc-rails"
54 |
55 | # This is only here because we are on ruby 2.4. When we upgrade ruby we can remove this
56 | gem "sprockets", "~>3.7.2"
57 |
58 | group :development do
59 | # UI
60 | gem "autoprefixer-rails"
61 | gem "non-stupid-digest-assets" # also compile assets without digest (fixes font problem)
62 | gem "uglifier"
63 |
64 | gem "better_errors"
65 | gem "binding_of_caller", platforms: [:mri_21]
66 | gem "hub", require: nil
67 | gem "mail_view"
68 | gem "rails_apps_pages"
69 | gem "rails_apps_testing"
70 | gem "rails_layout"
71 | gem "rb-fchange", require: false
72 | gem "rb-fsevent", require: false
73 | gem "rb-inotify", require: false
74 | # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
75 | gem "listen"
76 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
77 | gem "spring"
78 | gem "spring-commands-rspec"
79 | gem "spring-watcher-listen"
80 | gem "web-console"
81 | end
82 |
83 | group :linter do
84 | gem "pronto"
85 | gem "pronto-eslint_npm", require: false
86 | gem "pronto-rubocop", require: false
87 | gem "rubocop"
88 | end
89 |
90 | group :development, :test do
91 | gem "byebug", platform: :mri
92 | gem "dotenv-rails"
93 | gem "factory_bot_rails"
94 | gem "faker"
95 | gem "guard-rspec", require: false
96 | gem "rspec-rails"
97 | end
98 |
99 | group :test do
100 | gem "capybara"
101 | gem "database_cleaner"
102 | gem "launchy"
103 | gem "selenium-webdriver"
104 | gem "shoulda-matchers"
105 | gem "webmock"
106 | end
107 |
108 | group :production do
109 | gem "rails_12factor"
110 | end
111 |
112 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
113 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
114 |
--------------------------------------------------------------------------------
/Guardfile:
--------------------------------------------------------------------------------
1 | # A sample Guardfile
2 | # More info at https://github.com/guard/guard#readme
3 |
4 | ## Uncomment and set this to only include directories you want to watch
5 | # directories %w(app lib config test spec features) \
6 | # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7 |
8 | ## Note: if you are using the `directories` clause above and you are not
9 | ## watching the project directory ('.'), then you will want to move
10 | ## the Guardfile to a watched dir and symlink it back, e.g.
11 | #
12 | # $ mkdir config
13 | # $ mv Guardfile config/
14 | # $ ln -s config/Guardfile .
15 | #
16 | # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17 |
18 | # Note: The cmd option is now required due to the increasing number of ways
19 | # rspec may be run, below are examples of the most common uses.
20 | # * bundler: 'bundle exec rspec'
21 | # * bundler binstubs: 'bin/rspec'
22 | # * spring: 'bin/rspec' (This will use spring if running and you have
23 | # installed the spring binstubs per the docs)
24 | # * zeus: 'zeus rspec' (requires the server to be started separately)
25 | # * 'just' rspec: 'rspec'
26 |
27 | guard :rspec, cmd: "spring rspec" do
28 | require "guard/rspec/dsl"
29 | dsl = Guard::RSpec::Dsl.new(self)
30 |
31 | # Feel free to open issues for suggestions and improvements
32 |
33 | # RSpec files
34 | rspec = dsl.rspec
35 | watch(rspec.spec_helper) { rspec.spec_dir }
36 | watch(rspec.spec_support) { rspec.spec_dir }
37 | watch(rspec.spec_files)
38 |
39 | # Ruby files
40 | ruby = dsl.ruby
41 | dsl.watch_spec_files_for(ruby.lib_files)
42 |
43 | # Rails files
44 | rails = dsl.rails(view_extensions: %w(erb haml slim))
45 | dsl.watch_spec_files_for(rails.app_files)
46 | dsl.watch_spec_files_for(rails.views)
47 |
48 | watch(rails.controllers) do |m|
49 | [
50 | rspec.spec.call("routing/#{m[1]}_routing"),
51 | rspec.spec.call("controllers/#{m[1]}_controller"),
52 | rspec.spec.call("acceptance/#{m[1]}"),
53 | ]
54 | end
55 |
56 | # Rails config changes
57 | watch(rails.spec_helper) { rspec.spec_dir }
58 | watch(rails.routes) { "#{rspec.spec_dir}/routing" }
59 | watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
60 |
61 | # Capybara features specs
62 | watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") }
63 | watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") }
64 |
65 | # Turnip features and steps
66 | watch(%r{^spec/acceptance/(.+)\.feature$})
67 | watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
68 | Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
69 | end
70 | end
71 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2016 Atomic Jolt (http://www.atomicjolt.com)
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
13 | all 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
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: bundle exec puma -C config/puma.rb
--------------------------------------------------------------------------------
/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 File.expand_path("../config/application", __FILE__)
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../javascripts .js
3 | //= link_directory ../stylesheets .css
4 |
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/app/assets/images/.keep
--------------------------------------------------------------------------------
/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 any plugin's vendor/assets/javascripts directory 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. JavaScript code in this file should be added after the last require_* statement.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require_tree .
14 |
--------------------------------------------------------------------------------
/app/assets/javascripts/cable.js:
--------------------------------------------------------------------------------
1 | // Action Cable provides the framework to deal with WebSockets in Rails.
2 | // You can generate new channels where WebSocket features live using the rails generate channel command.
3 | //
4 | //= require action_cable
5 | //= require_self
6 | //= require_tree ./channels
7 |
8 | (function() {
9 | this.App || (this.App = {});
10 |
11 | App.cable = ActionCable.createConsumer();
12 |
13 | }).call(this);
14 |
--------------------------------------------------------------------------------
/app/assets/javascripts/channels/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/app/assets/javascripts/channels/.keep
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.scss:
--------------------------------------------------------------------------------
1 | // Partials
2 | @import "partials/print";
3 | @import "partials/environment";
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/client.scss:
--------------------------------------------------------------------------------
1 | // Environment
2 | @import "partials/print";
3 | @import "partials/environment";
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/partials/_environment.scss:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Roboto:700');
2 |
3 | .aj-env-banner {
4 | height: 26px;
5 | width: 200px;
6 | background: #272121;
7 | font-family: ‘Roboto’, sans-serif;
8 | font-size: 12px;
9 | font-weight: 700;
10 | color: #FCCC0F;
11 | text-align: center;
12 | text-transform: uppercase;
13 | line-height: 24px;
14 | letter-spacing: 1px;
15 |
16 | position: fixed;
17 | top: 35px;
18 | right: -55px;
19 | border: 1px solid white;
20 | z-index: 999;
21 | pointer-events: none;
22 |
23 | transform: rotate(45deg);
24 | -moz-transform: rotate(45deg);
25 | -webkit-transform: rotate(45deg);
26 | -ms-transform: rotate(45deg);
27 |
28 | -webkit-box-sizing: border-box;
29 | -moz-box-sizing: border-box;
30 | box-sizing: border-box;
31 | vertical-align: top;
32 | -webkit-font-smoothing: antialiased;
33 | -moz-osx-font-smoothing: grayscale;
34 | text-shadow: 1px 1px 1px rgba(0,0,0,0.004);
35 | }
36 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/partials/_print.scss:
--------------------------------------------------------------------------------
1 | @media print {
2 |
3 | .no-print {
4 | display: none !important;
5 | }
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/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/jwts_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::JwtsController < ApplicationController
2 |
3 | include Concerns::JwtToken
4 |
5 | before_action :validate_token
6 |
7 | respond_to :json
8 |
9 | def show
10 | token = AuthToken.issue_token({ user_id: current_user.id })
11 | respond_to do |format|
12 | format.json { render json: { jwt: token } }
13 | end
14 | end
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 |
3 | # Prevent CSRF attacks by raising an exception.
4 | # For APIs, you may want to use :null_session instead.
5 | protect_from_forgery with: :exception
6 | before_action :configure_permitted_parameters, if: :devise_controller?
7 |
8 | protected
9 |
10 | rescue_from CanCan::AccessDenied do |exception|
11 | respond_to do |format|
12 | format.html { redirect_to root_url, alert: exception.message }
13 | format.json { render json: { error: exception.message }, status: :unauthorized }
14 | end
15 | end
16 |
17 | def configure_permitted_parameters
18 | devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
19 | devise_parameter_sanitizer.permit(:account_update, keys: [:name])
20 | end
21 |
22 | def current_ability
23 | @current_ability ||= Ability.new(current_user)
24 | end
25 |
26 | def user_not_authorized
27 | respond_to do |format|
28 | format.html { render file: "public/401.html", status: :unauthorized }
29 | format.json { render json: {}, status: :unauthorized }
30 | end
31 | end
32 |
33 | end
34 |
--------------------------------------------------------------------------------
/app/controllers/concerns/jwt_token.rb:
--------------------------------------------------------------------------------
1 | module Concerns
2 | module JwtToken
3 | extend ActiveSupport::Concern
4 |
5 | class InvalidTokenError < StandardError; end
6 |
7 | def validate_token
8 | authorization = request.headers["Authorization"]
9 | raise InvalidTokenError if authorization.nil?
10 |
11 | token = request.headers["Authorization"].split(" ").last
12 | decoded_token = AuthToken.valid?(token)
13 |
14 | raise InvalidTokenError if Rails.application.secrets.auth0_client_id != decoded_token[0]["aud"]
15 |
16 | @user = User.find(decoded_token[0]["user_id"])
17 | sign_in(@user, event: :authentication)
18 | rescue JWT::DecodeError, InvalidTokenError
19 | render json: { error: "Unauthorized: Invalid token." }, status: :unauthorized
20 | end
21 |
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/app/controllers/concerns/paging.rb:
--------------------------------------------------------------------------------
1 | module Concerns
2 | module Paging
3 | extend ActiveSupport::Concern
4 |
5 | included do
6 | before_action :setup_will_paginate
7 | end
8 |
9 | def setup_paging
10 | @page = (params[:page] || 1).to_i
11 | @page = 1 if @page < 1
12 | @per_page = (params[:per_page] || (::Rails.env == "test" ? 1 : 40)).to_i
13 | end
14 |
15 | def set_will_paginate_string
16 | # Because I18n.locale are dynamically determined in ApplicationController,
17 | # it should not put in config/initializers/will_paginate.rb
18 | WillPaginate::ViewHelpers.pagination_options[:previous_label] = "previous"
19 | WillPaginate::ViewHelpers.pagination_options[:next_label] = "next"
20 | end
21 |
22 | def setup_will_paginate
23 | setup_paging
24 | set_will_paginate_string
25 | end
26 |
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/app/controllers/home_controller.rb:
--------------------------------------------------------------------------------
1 | class HomeController < ApplicationController
2 |
3 | layout "client"
4 |
5 | def index; end
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/app/controllers/registrations_controller.rb:
--------------------------------------------------------------------------------
1 | class RegistrationsController < Devise::RegistrationsController
2 | before_filter :update_sanitized_params, if: :devise_controller?
3 |
4 | def update_sanitized_params
5 | devise_parameter_sanitizer.for(:sign_up) do |u|
6 | u.permit(:name, :email, :password, :password_confirmation)
7 | end
8 | devise_parameter_sanitizer.for(:account_update) do |u|
9 | u.permit(:name, :email, :password, :password_confirmation, :current_password)
10 | end
11 | end
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/app/controllers/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class SessionsController < Devise::SessionsController
2 | # Require our abstraction for encoding/deconding JWT.
3 | require "auth_token"
4 |
5 | respond_to :json
6 |
7 | def create
8 | # This is the default behavior from devise - view the sessions controller source:
9 | # https://github.com/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb
10 | self.resource = warden.authenticate!(auth_options)
11 | set_flash_message(:notice, :signed_in) if is_flashing_format?
12 | sign_in(resource_name, resource)
13 | yield resource if block_given?
14 |
15 | # Here we're deviating from the standard behavior by issuing our JWT
16 | # to any JS based client.
17 | token = AuthToken.issue_token({ user_id: resource.id })
18 | respond_with resource, location: after_sign_in_path_for(resource) do |format|
19 | format.json do
20 | render json: {
21 | userId: resource.id,
22 | email: resource.email,
23 | displayName: resource.name,
24 | jwt_token: token,
25 | }
26 | end
27 | end
28 | end
29 |
30 | def destroy
31 | # Destroy all authentications when the user logs out:
32 | # current_user.authentications.where(provider: 'facebook').destroy_all
33 | super
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 |
3 | def application_base_url
4 | File.join(request.base_url, "/")
5 | end
6 |
7 | def jwt_token
8 | return unless signed_in?
9 | AuthToken.issue_token({ user_id: current_user.id })
10 | end
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | end
3 |
--------------------------------------------------------------------------------
/app/lib/auth_token.rb:
--------------------------------------------------------------------------------
1 | require "jwt"
2 |
3 | module AuthToken
4 |
5 | # More information on jwt available at
6 | # http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#rfc.section.4.1.6
7 | def self.issue_token(payload, exp = 24.hours.from_now)
8 | payload["iat"] = DateTime.now.to_i # issued at claim
9 | payload["exp"] = exp.to_i # Default expiration set to 24 hours.
10 | payload["aud"] = Rails.application.secrets.auth0_client_id
11 | JWT.encode(payload, Rails.application.secrets.auth0_client_secret, "HS512")
12 | end
13 |
14 | def self.valid?(token)
15 | JWT.decode(token, Rails.application.secrets.auth0_client_secret)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/lib/url_helper.rb:
--------------------------------------------------------------------------------
1 | class UrlHelper
2 | def self.safe_host(url)
3 | return nil if url.blank?
4 | UrlHelper.host(url)
5 | end
6 |
7 | def self.ensure_scheme(url)
8 | return nil unless url.present?
9 | url = "http://#{url}" unless url.start_with?("http")
10 | url
11 | end
12 |
13 | def self.host(url)
14 | return nil unless url.present?
15 | URI.parse(ensure_scheme(url)).host
16 | end
17 |
18 | def self.scheme_host(url)
19 | return nil unless url.present?
20 | parsed = URI.parse(ensure_scheme(url))
21 | "#{parsed.scheme}://#{parsed.host}"
22 | end
23 |
24 | def self.scheme_host_port(url)
25 | return nil unless url.present?
26 | parsed = URI.parse(ensure_scheme(url))
27 | port = parsed.port != 80 && parsed.port != 443 ? ":#{parsed.port}" : ""
28 | "#{parsed.scheme}://#{parsed.host}#{port}"
29 | end
30 |
31 | def self.host_from_instance_guid(url)
32 | url = URI.parse(ensure_scheme(url))
33 | parts = url.host.split(".")
34 | if parts.length > 2
35 | parts[1, parts.length].join(".")
36 | else
37 | parts.join(".")
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/ability.rb:
--------------------------------------------------------------------------------
1 | class Ability
2 | include CanCan::Ability
3 |
4 | def initialize(user)
5 | # Define abilities for the passed in user here. For example:
6 | #
7 | # user ||= User.new # guest user (not logged in)
8 | # if user.admin?
9 | # can :manage, :all
10 | # else
11 | # can :read, :all
12 | # end
13 | #
14 | # The first argument to `can` is the action you are giving the user
15 | # permission to do.
16 | # If you pass :manage it will apply to every action. Other common actions
17 | # here are :read, :create, :update and :destroy.
18 | #
19 | # The second argument is the resource the user can perform the action on.
20 | # If you pass :all it will apply to every resource. Otherwise pass a Ruby
21 | # class of the resource.
22 | #
23 | # The third argument is an optional hash of conditions to further filter the
24 | # objects.
25 | # For example, here the user can only update published articles.
26 | #
27 | # can :update, Article, :published => true
28 | #
29 | # See the wiki for details:
30 | # https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
31 |
32 | user ||= User.new # guest user (not logged in)
33 |
34 | basic(user)
35 | admin(user) if user.admin?
36 | end
37 |
38 | def basic(user)
39 | can :manage, User, id: user.id
40 | end
41 |
42 | def admin(_user)
43 | can :manage, :all
44 | end
45 |
46 | end
47 |
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/authentication.rb:
--------------------------------------------------------------------------------
1 | class Authentication < ApplicationRecord
2 |
3 | attr_encrypted :token, key: Rails.application.secrets.encryption_key, mode: :per_attribute_iv_and_salt
4 | attr_encrypted :secret, key: Rails.application.secrets.encryption_key, mode: :per_attribute_iv_and_salt
5 | attr_encrypted :refresh_token, key: Rails.application.secrets.encryption_key, mode: :per_attribute_iv_and_salt
6 |
7 | belongs_to :user, inverse_of: :authentications
8 |
9 | validates :provider, presence: true, uniqueness: { scope: [:uid, :user_id, :provider_url] }
10 |
11 | # Find an authentication using an auth object provided by omniauth
12 | def self.for_auth(auth)
13 | provider_url = UrlHelper.scheme_host_port(auth["info"]["url"])
14 | Authentication.find_by(
15 | uid: auth["uid"].to_s,
16 | provider: auth["provider"],
17 | provider_url: provider_url,
18 | )
19 | end
20 |
21 | # Build an authentication using an auth object provided by omniauth
22 | def self.authentication_attrs_from_auth(auth)
23 | info = auth["info"] || {}
24 | provider_url = UrlHelper.scheme_host_port(info["url"])
25 | attributes = {
26 | uid: auth["uid"].to_s,
27 | username: info["nickname"],
28 | provider: auth["provider"],
29 | provider_url: provider_url,
30 | }
31 | if credentials = auth["credentials"]
32 | attributes[:token] = credentials["token"]
33 | attributes[:secret] = credentials["secret"]
34 | attributes[:refresh_token] = credentials["refresh_token"] if credentials["refresh_token"]
35 | end
36 | attributes
37 | end
38 |
39 | end
40 |
--------------------------------------------------------------------------------
/app/models/permission.rb:
--------------------------------------------------------------------------------
1 | class Permission < ApplicationRecord
2 | belongs_to :user
3 | belongs_to :role
4 |
5 | def self.by_nil_or_context(context_id)
6 | where(context_id: [context_id, nil])
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/app/models/role.rb:
--------------------------------------------------------------------------------
1 | class Role < ApplicationRecord
2 |
3 | has_many :permissions, dependent: :destroy
4 | has_many :users, through: :permissions
5 |
6 | validates :name, presence: true, uniqueness: true
7 |
8 | def self.by_alpha
9 | order("roles.name ASC")
10 | end
11 |
12 | # roles can be defined as symbols. We want to store them as strings in the database
13 | def name=(val)
14 | write_attribute(:name, val.to_s)
15 | end
16 |
17 | end
18 |
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | class User < ApplicationRecord
2 |
3 | # Include default devise modules. Others available are:
4 | # :confirmable, :lockable, :timeoutable and :omniauthable
5 | devise :database_authenticatable, :registerable, :confirmable,
6 | :recoverable, :rememberable, :trackable, :validatable, :omniauthable
7 |
8 | has_many :authentications, dependent: :destroy, inverse_of: :user
9 | has_many :permissions
10 | has_many :roles, through: :permissions
11 |
12 | validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
13 |
14 | enum create_method: %i{sign_up oauth}
15 |
16 | def display_name
17 | name || email
18 | end
19 |
20 | ####################################################
21 | #
22 | # Omniauth related methods
23 | #
24 | def self.for_auth(auth)
25 | Authentication.for_auth(auth)&.user
26 | end
27 |
28 | def apply_oauth(auth)
29 | self.attributes = User.params_for_create(auth)
30 | setup_authentication(auth)
31 | end
32 |
33 | def update_oauth(auth)
34 | setup_authentication(auth)
35 | end
36 |
37 | def self.oauth_info(auth)
38 | info = auth["info"] || {}
39 | raw_info = auth["extra"]["raw_info"] if auth["extra"].present?
40 | raw_info ||= {}
41 | [info, raw_info]
42 | end
43 |
44 | def self.oauth_name(auth)
45 | info, raw_info = oauth_info(auth)
46 | info["name"] ||
47 | "#{info['first_name']} #{info['last_name']}" ||
48 | info["nickname"] ||
49 | raw_info["name"] ||
50 | raw_info["short_name"] ||
51 | raw_info["login_id"]
52 | end
53 |
54 | def self.oauth_email(auth)
55 | info, raw_info = oauth_info(auth)
56 | email = info["email"] ||
57 | raw_info["primary_email"] ||
58 | raw_info["login_id"]
59 |
60 | # Try a basic validation on the email
61 | if email =~ /\A[^@]+@[^@]+\Z/
62 | email
63 | else
64 | # we have to make one up
65 | domain = UrlHelper.safe_host(info["url"])
66 | name = auth["uid"]
67 | "#{name}@#{domain}"
68 | end
69 | end
70 |
71 | def self.params_for_create(auth)
72 | {
73 | email: oauth_email(auth),
74 | name: oauth_name(auth),
75 | }
76 | end
77 |
78 | def setup_authentication(auth)
79 | attributes = Authentication.authentication_attrs_from_auth(auth)
80 | if persisted? &&
81 | authentication = authentications.find_by(
82 | provider: attributes[:provider],
83 | provider_url: attributes[:provider_url],
84 | )
85 | authentication.update_attributes!(attributes)
86 | else
87 | authentications.build(attributes)
88 | end
89 | end
90 |
91 | def associate_account(auth)
92 | self.name ||= User.oauth_name(auth)
93 | save!
94 | setup_authentication(auth)
95 | end
96 |
97 | ####################################################
98 | #
99 | # Role related methods
100 | #
101 | def set_default_role
102 | self.role ||= :user
103 | end
104 |
105 | def context_roles(context_id = nil)
106 | roles.where(permissions: { context_id: context_id }).distinct
107 | end
108 |
109 | def nil_or_context_roles(context_id = nil)
110 | roles.where(permissions: { context_id: [context_id, nil] }).distinct
111 | end
112 |
113 | def role?(name, context_id = nil)
114 | has_role?(context_id, name)
115 | end
116 |
117 | def has_role?(context_id, *test_names)
118 | test_names = [test_names] unless test_names.is_a?(Array)
119 | test_names = test_names.map(&:downcase).flatten
120 | @role_names = nil_or_context_roles(context_id).map(&:name).map(&:downcase) if @role_names.blank?
121 | return false if @role_names.blank?
122 | !(@role_names & test_names).empty?
123 | end
124 |
125 | def any_role?(*test_names)
126 | has_role?(nil, *test_names)
127 | end
128 |
129 | # Add the user to a new role
130 | def add_to_role(name, context_id = nil)
131 | role = Role.where(name: name).first_or_create
132 | # Make sure that the user can only be put into a role once
133 | if context_roles(context_id).exclude?(role)
134 | Permission.create(user: self, role: role, context_id: context_id)
135 | end
136 | end
137 |
138 | def admin?
139 | role?("administrator")
140 | end
141 |
142 | def can_edit?(user)
143 | return false if user.nil?
144 | id == user.id || user.admin?
145 | end
146 |
147 | def self.convert_name_to_initials(sortable_name)
148 | parts = sortable_name.split(",")
149 | "#{parts[1].strip[0]}#{parts[0].strip[0]}".upcase
150 | rescue
151 | return "?" unless sortable_name && !sortable_name.empty?
152 | return sortable_name[0..1].upcase if sortable_name.length > 1
153 | sortable_name[0]
154 | end
155 |
156 | end
157 |
--------------------------------------------------------------------------------
/app/services/create_admin_service.rb:
--------------------------------------------------------------------------------
1 | class CreateAdminService
2 | def call
3 | user = User.find_or_initialize_by(email: Rails.application.secrets.admin_email)
4 | user.password = Rails.application.secrets.admin_password
5 | user.password_confirmation = Rails.application.secrets.admin_password
6 | user.confirm unless user.confirmed?
7 | user.add_to_role("administrator")
8 | user.save!
9 | user
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/app/views/devise/registrations/edit.html.erb:
--------------------------------------------------------------------------------
1 |
Edit <%= resource_name.to_s.humanize %>
2 |
3 | <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
4 | <%= devise_error_messages! %>
5 |
6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true %>
9 |
10 |
11 | <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
12 | Currently waiting confirmation for: <%= resource.unconfirmed_email %>
13 | <% end %>
14 |
15 |
16 | <%= f.label :name %>
17 | <%= f.text_field :name, autofocus: true %>
18 |
19 |
20 |
21 | <%= f.label :password %> (leave blank if you don't want to change it)
22 | <%= f.password_field :password, autocomplete: "off" %>
23 |
24 |
25 |
26 | <%= f.label :password_confirmation %>
27 | <%= f.password_field :password_confirmation, autocomplete: "off" %>
28 |
29 |
30 |
31 | <%= f.label :current_password %> (we need your current password to confirm your changes)
32 | <%= f.password_field :current_password, autocomplete: "off" %>
33 |
34 |
35 |
36 | <%= f.submit "Update" %>
37 |
38 | <% end %>
39 |
40 | Cancel my account
41 |
42 | Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
43 |
44 | <%= link_to "Back", :back %>
45 |
--------------------------------------------------------------------------------
/app/views/devise/registrations/new.html.erb:
--------------------------------------------------------------------------------
1 | Sign up
2 |
3 | <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
4 | <%= devise_error_messages! %>
5 |
6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true %>
9 |
10 |
11 |
12 | <%= f.label :name %>
13 | <%= f.text_field :name, autofocus: true %>
14 |
15 |
16 |
17 | <%= f.label :password %>
18 | <% if @minimum_password_length %>
19 | (<%= @minimum_password_length %> characters minimum)
20 | <% end %>
21 | <%= f.password_field :password, autocomplete: "off" %>
22 |
23 |
24 |
25 | <%= f.label :password_confirmation %>
26 | <%= f.password_field :password_confirmation, autocomplete: "off" %>
27 |
28 |
29 |
30 | <%= f.submit "Sign up" %>
31 |
32 | <% end %>
33 |
34 | <%= render "devise/shared/links" %>
35 |
--------------------------------------------------------------------------------
/app/views/home/index.html.erb:
--------------------------------------------------------------------------------
1 | <% content_for :head do -%>
2 | <%= stylesheet_pack_tag "hello_world" %>
3 | <% end -%>
4 |
5 | <%= render "shared/default_client_settings" %>
6 |
7 | <%= javascript_packs_with_chunks_tag "hello_world", "data-turbolinks-track": "reload" %>
8 |
--------------------------------------------------------------------------------
/app/views/layouts/_head.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= content_for?(:title) ? yield(:title) : Rails.application.secrets.application_name %>
5 |
6 |
7 |
8 |
9 | <%= csrf_meta_tags %>
10 | <%= yield(:head) %>
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/views/layouts/_messages.html.erb:
--------------------------------------------------------------------------------
1 | <%# Rails flash messages styled for Bootstrap 3.0 %>
2 | <% flash.each do |name, msg| %>
3 | <% if msg.is_a?(String) %>
4 |
5 | ×
6 | <%= content_tag :div, msg, :id => "flash_#{name}" %>
7 |
8 | <% end %>
9 | <% end %>
10 |
--------------------------------------------------------------------------------
/app/views/layouts/_navigation.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to 'Home', root_path %>
3 | <% if user_signed_in? %>
4 | <%= link_to 'Edit account', edit_user_registration_path %>
5 | <%= link_to 'Sign out', destroy_user_session_path, :method=>'delete' %>
6 | <% else %>
7 | <%= link_to 'Sign in', new_user_session_path %>
8 | <%= link_to 'Sign up', new_user_registration_path %>
9 | <% end %>
10 | <% if user_signed_in? %>
11 | <% if current_user.admin? %>
12 | <%= link_to 'Users', users_path %>
13 | <% end %>
14 | <% end %>
15 |
16 |
--------------------------------------------------------------------------------
/app/views/layouts/_show_environment.erb:
--------------------------------------------------------------------------------
1 | <% if !Rails.env.production? || Rails.application.secrets.deploy_env != "production" -%>
2 | <%= Rails.application.secrets.deploy_env.present? ? Rails.application.secrets.deploy_env.upcase : Rails.env.upcase %>
3 | <% end -%>
4 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= stylesheet_link_tag 'application', media: 'all' %>
5 | <%= render 'layouts/head' %>
6 |
7 |
8 | <%= render "layouts/show_environment" %>
9 | <%= render 'layouts/navigation' %>
10 |
11 | <%= render 'layouts/messages' %>
12 | <%= yield %>
13 |
14 | <%= javascript_include_tag 'application'%>
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/views/layouts/client.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= stylesheet_link_tag 'client', media: 'all' %>
5 | <%= render 'layouts/head' %>
6 |
7 |
8 | <%= render "layouts/show_environment" %>
9 | <%= yield %>
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/views/shared/_default_client_settings.html.erb:
--------------------------------------------------------------------------------
1 | <%-
2 | settings = {
3 | api_url: application_base_url,
4 | csrf_token: form_authenticity_token
5 | }
6 | if signed_in?
7 | settings[:user_id] = current_user.id
8 | settings[:email] = current_user.email
9 | settings[:display_name] = current_user.display_name
10 | end
11 | %>
12 |
--------------------------------------------------------------------------------
/app/views/shared/_links.html.erb:
--------------------------------------------------------------------------------
1 | <%- if controller_name != 'sessions' %>
2 | <%= link_to "Sign in", new_session_path(resource_name) %>
3 | <% end -%>
4 |
5 | <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
6 | <%= link_to "Sign up", new_registration_path(resource_name) %>
7 | <% end -%>
8 |
9 | <%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
10 | <%= link_to "Forgot your password?", new_password_path(resource_name) %>
11 | <% end -%>
12 |
13 | <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
14 | <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
15 | <% end -%>
16 |
17 | <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
18 | <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
19 | <% end -%>
20 |
21 | <%- if devise_mapping.omniauthable? %>
22 | <%- resource_class.omniauth_providers.each do |provider| %>
23 | <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), class: "btn btn-primary" %>
24 | <% end -%>
25 | <% end -%>
26 |
--------------------------------------------------------------------------------
/app/views/shared/_omniauth_error.html.erb:
--------------------------------------------------------------------------------
1 | An OauthError has occured
2 |
--------------------------------------------------------------------------------
/app/views/users/_user.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to user.email, user %>
3 |
4 |
5 | <%= form_for(user) do |f| %>
6 | <%= f.select(:role, User.roles.keys.map {|role| [role.titleize,role]}) %>
7 | <%= f.submit 'Change Role', :class => 'button-xs' %>
8 | <% end %>
9 |
10 |
11 | <%= link_to("Delete user", user_path(user), :data => { :confirm => "Are you sure?" }, :method => :delete, :class => 'button-xs') unless user == current_user %>
12 |
13 |
--------------------------------------------------------------------------------
/app/views/users/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Users
4 |
5 |
6 |
7 | <% @users.each do |user| %>
8 |
9 | <%= render user %>
10 |
11 | <% end %>
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/views/users/show.html.erb:
--------------------------------------------------------------------------------
1 | User
2 | Name: <%= @user.name if @user.name %>
3 | Email: <%= @user.email if @user.email %>
4 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | var validEnv = ['development', 'test', 'production']
3 | var currentEnv = api.env()
4 | var isDevelopmentEnv = api.env('development')
5 | var isProductionEnv = api.env('production')
6 | var isTestEnv = api.env('test')
7 |
8 | if (!validEnv.includes(currentEnv)) {
9 | throw new Error(
10 | 'Please specify a valid `NODE_ENV` or ' +
11 | '`BABEL_ENV` environment variables. Valid values are "development", ' +
12 | '"test", and "production". Instead, received: ' +
13 | JSON.stringify(currentEnv) +
14 | '.'
15 | )
16 | }
17 |
18 | return {
19 | presets: [
20 | isTestEnv && [
21 | '@babel/preset-env',
22 | {
23 | targets: {
24 | node: 'current'
25 | },
26 | modules: 'commonjs'
27 | },
28 | '@babel/preset-react'
29 | ],
30 | (isProductionEnv || isDevelopmentEnv) && [
31 | '@babel/preset-env',
32 | {
33 | forceAllTransforms: true,
34 | useBuiltIns: 'entry',
35 | corejs: 3,
36 | modules: false,
37 | exclude: ['transform-typeof-symbol']
38 | }
39 | ],
40 | [
41 | '@babel/preset-react',
42 | {
43 | development: isDevelopmentEnv || isTestEnv,
44 | useBuiltIns: true
45 | }
46 | ]
47 | ].filter(Boolean),
48 | plugins: [
49 | 'babel-plugin-macros',
50 | '@babel/plugin-syntax-dynamic-import',
51 | isTestEnv && 'babel-plugin-dynamic-import-node',
52 | '@babel/plugin-transform-destructuring',
53 | [
54 | '@babel/plugin-proposal-class-properties',
55 | {
56 | loose: true
57 | }
58 | ],
59 | [
60 | '@babel/plugin-proposal-object-rest-spread',
61 | {
62 | useBuiltIns: true
63 | }
64 | ],
65 | [
66 | '@babel/plugin-transform-runtime',
67 | {
68 | helpers: false,
69 | regenerator: true,
70 | corejs: false
71 | }
72 | ],
73 | [
74 | '@babel/plugin-transform-regenerator',
75 | {
76 | async: false
77 | }
78 | ],
79 | isProductionEnv && [
80 | 'babel-plugin-transform-react-remove-prop-types',
81 | {
82 | removeImport: true
83 | }
84 | ]
85 | ].filter(Boolean)
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/bin/bootstrap:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Meant to be run from root directory of project
4 | # ./bin/bootstrap
5 | DROPBOX_FOLDER=aj-dev/react_rails_starter_app
6 |
7 | # All config files for project
8 | files=("config/secrets.yml" "config/database.yml")
9 |
10 | for file in "${files[@]}"
11 | do
12 | if [ -e $file ]
13 | then
14 | rm $file
15 | fi
16 | mkdir -p $(dirname "${file}")
17 | ln -s "$HOME/Dropbox/$DROPBOX_FOLDER/$file" $file
18 | done
19 |
20 | # project specific code or symlinks
21 | # cd config
22 | # ln -s database.development.yml database.yml
23 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/ci:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Exit if any subcommand fails
4 | set -e
5 |
6 | bundle exec rspec
7 |
--------------------------------------------------------------------------------
/bin/deploy_heroku:
--------------------------------------------------------------------------------
1 | !/usr/bin/env bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | SHA=$(git rev-parse --short HEAD)
8 |
9 | function finish {
10 | git reset --hard $SHA
11 | bin/bootstrap
12 | }
13 | trap finish EXIT
14 |
15 | RAILS_ENV=production bundle exec rake assets:precompile
16 |
17 | git add -f public/assets
18 | git add -f config/assets
19 |
20 | rsync `readlink config/secrets.yml` config/secrets.yml
21 | git add -f config/secrets.yml
22 |
23 | git commit -m "parent sha: [$SHA] add precompile files"
24 |
25 | git push -f heroku master
26 |
27 | heroku run rails db:migrate
28 | heroku run rails db:seed
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path('../config/application', __dir__)
3 | require_relative '../config/boot'
4 | require 'rails/commands'
5 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/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 | spring = lockfile.specs.detect { |spec| spec.name == "spring" }
12 | if spring
13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
14 | gem 'spring', spring.version
15 | require 'spring/binstub'
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 | include FileUtils
4 |
5 | # path to your application root.
6 | APP_ROOT = File.expand_path('..', __dir__)
7 |
8 | def system!(*args)
9 | system(*args) || abort("\n== Command #{args} failed ==")
10 | end
11 |
12 | chdir APP_ROOT do
13 | # This script is a way to update your development environment automatically.
14 | # Add necessary update steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies if using Yarn
21 | # system('bin/yarn')
22 |
23 | puts "\n== Updating database =="
24 | system! 'bin/rails db:migrate'
25 |
26 | puts "\n== Removing old logs and tempfiles =="
27 | system! 'bin/rails log:clear tmp:clear'
28 |
29 | puts "\n== Restarting application server =="
30 | system! 'bin/rails restart'
31 | end
32 |
--------------------------------------------------------------------------------
/bin/webpack:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "bundler/setup"
11 |
12 | require "webpacker"
13 | require "webpacker/webpack_runner"
14 |
15 | APP_ROOT = File.expand_path("..", __dir__)
16 | Dir.chdir(APP_ROOT) do
17 | Webpacker::WebpackRunner.run(ARGV)
18 | end
19 |
--------------------------------------------------------------------------------
/bin/webpack-dev-server:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "bundler/setup"
11 |
12 | require "webpacker"
13 | require "webpacker/dev_server_runner"
14 |
15 | APP_ROOT = File.expand_path("..", __dir__)
16 | Dir.chdir(APP_ROOT) do
17 | Webpacker::DevServerRunner.run(ARGV)
18 | end
19 |
--------------------------------------------------------------------------------
/bin/yarn:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_ROOT = File.expand_path('..', __dir__)
3 | Dir.chdir(APP_ROOT) do
4 | begin
5 | exec "yarnpkg", *ARGV
6 | rescue Errno::ENOENT
7 | $stderr.puts "Yarn executable was not detected in the system."
8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
9 | exit 1
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/client/apps/hello_world/app.jsx:
--------------------------------------------------------------------------------
1 | import 'core-js';
2 | import 'regenerator-runtime/runtime';
3 | import es6Promise from 'es6-promise';
4 | import React from 'react';
5 | import ReactDOM from 'react-dom';
6 | import PropTypes from 'prop-types';
7 | import { Provider } from 'react-redux';
8 | import { BrowserRouter as Router, Route } from 'react-router-dom';
9 | import { getInitialSettings } from 'atomic-fuel/libs/reducers/settings';
10 | import jwt from 'atomic-fuel/libs/loaders/jwt';
11 | import configureStore from './store/configure_store';
12 | import Index from './components/layout/index';
13 |
14 | import './styles/styles';
15 |
16 | // Polyfill es6 promises for IE
17 | es6Promise.polyfill();
18 |
19 | class Root extends React.PureComponent {
20 | static propTypes = {
21 | store: PropTypes.object.isRequired,
22 | };
23 |
24 | render() {
25 | const { store } = this.props;
26 | return (
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | );
35 | }
36 | }
37 |
38 | const settings = getInitialSettings(window.DEFAULT_SETTINGS);
39 | const store = configureStore({ settings, jwt: window.DEFAULT_JWT });
40 | if (window.DEFAULT_JWT) { // Setup JWT refresh
41 | jwt(store.dispatch, settings.userId);
42 | }
43 |
44 | ReactDOM.render(
45 | ,
46 | document.getElementById('main-app'),
47 | );
48 |
--------------------------------------------------------------------------------
/client/apps/hello_world/assets/images/atomicjolt.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/assets/images/atomicjolt.jpg
--------------------------------------------------------------------------------
/client/apps/hello_world/assets/images/atomicjolt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/assets/images/atomicjolt.png
--------------------------------------------------------------------------------
/client/apps/hello_world/assets/images/atomicjolt.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
9 |
12 |
16 |
18 |
22 |
25 |
30 |
33 |
36 |
38 |
39 |
42 |
43 |
44 |
52 |
53 |
--------------------------------------------------------------------------------
/client/apps/hello_world/components/common/not_found.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default () => (
4 |
5 |
Page Not Found
6 |
Sorry, but the page you were trying to view does not exist.
7 |
8 | );
9 |
--------------------------------------------------------------------------------
/client/apps/hello_world/components/home.jsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import assets from '../libs/assets';
3 |
4 | export default class Home extends React.Component {
5 |
6 | render() {
7 | const img = assets('./images/atomicjolt.jpg');
8 | return (
9 |
10 |
11 |
Welcome to the React Client starter app by Atomic Jolt
12 |
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/apps/hello_world/components/home.spec.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { shallow } from 'enzyme';
3 | import Home from './home';
4 |
5 | jest.mock('../libs/assets.js');
6 |
7 | describe('home', () => {
8 | let result;
9 | let props;
10 |
11 | beforeEach(() => {
12 | props = {};
13 | result = shallow( );
14 | });
15 |
16 | it('renders the home component', () => {
17 | expect(result).toBeDefined();
18 | });
19 |
20 | });
21 |
--------------------------------------------------------------------------------
/client/apps/hello_world/components/layout/errors.jsx:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { connect } from 'react-redux';
5 |
6 | import { clearErrors } from 'atomic-fuel/libs/actions/errors';
7 |
8 | const select = state => ({ errors: state.errors });
9 |
10 | export class Errors extends React.Component {
11 |
12 | static propTypes = {
13 | clearErrors: PropTypes.func,
14 | }
15 |
16 | componentDidMount() {
17 | setTimeout(() => {
18 | this.props.clearErrors();
19 | }, 5000);
20 | }
21 |
22 | render() {
23 | const errors = _.map(this.props.errors, error => {error} );
24 | return ;
25 | }
26 | }
27 |
28 | export default connect(select, { clearErrors })(Errors);
29 |
--------------------------------------------------------------------------------
/client/apps/hello_world/components/layout/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route } from 'react-router';
3 | import Errors from './errors';
4 | import Home from '../home';
5 |
6 |
7 | export default class Index extends React.Component {
8 |
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
15 | );
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/client/apps/hello_world/components/layout/index.spec.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { shallow } from 'enzyme';
3 | import Index from './index';
4 |
5 | jest.mock('../../libs/assets.js');
6 |
7 | describe('index', () => {
8 | let result;
9 | let props;
10 |
11 | beforeEach(() => {
12 | props = {};
13 | result = shallow( );
14 | });
15 |
16 | it('renders the index', () => {
17 | expect(result).toBeDefined();
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/client/apps/hello_world/html/404.html:
--------------------------------------------------------------------------------
1 | Page Not Found
2 | Sorry, but the page you were trying to view does not exist.
--------------------------------------------------------------------------------
/client/apps/hello_world/html/about.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: About
3 | author: Atomic Jolt
4 | layout: application
5 | permalink: /about-us/
6 | categories:
7 | - About Us
8 | tags:
9 | - About Us
10 | - Atomic Jolt
11 | ---
12 | About Us
13 | ---------------
14 | <%= metadata.tags %>
--------------------------------------------------------------------------------
/client/apps/hello_world/html/crossdomain.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
--------------------------------------------------------------------------------
/client/apps/hello_world/html/humans.txt:
--------------------------------------------------------------------------------
1 | # humanstxt.org/
2 | # The humans responsible & technology colophon
3 |
4 | # TEAM
5 |
6 | -- --
7 |
8 | # THANKS
9 |
10 |
11 |
12 | # TECHNOLOGY COLOPHON
13 |
14 | HTML5, CSS3, JavaScript
15 | React, jQuery, Bootstrap
16 |
--------------------------------------------------------------------------------
/client/apps/hello_world/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/client/apps/hello_world/html/layouts/application.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%- include('./partials/_head.html') %>
5 |
6 |
7 | <%- include('./partials/_header.html') %>
8 | <%- content %>
9 | <%- include('./partials/_google_analytics.html') %>
10 |
11 |
--------------------------------------------------------------------------------
/client/apps/hello_world/html/layouts/partials/_google_analytics.html:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/client/apps/hello_world/html/layouts/partials/_head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | React Client Starter
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/client/apps/hello_world/html/layouts/partials/_header.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/html/layouts/partials/_header.html
--------------------------------------------------------------------------------
/client/apps/hello_world/html/robots.txt:
--------------------------------------------------------------------------------
1 | # www.robotstxt.org/
2 |
3 | # Allow crawling of all content
4 | User-agent: *
5 | Disallow:
6 |
--------------------------------------------------------------------------------
/client/apps/hello_world/libs/assets.js:
--------------------------------------------------------------------------------
1 | // See http://webpack.github.io/docs/context.html#dynamic-requires
2 |
3 | export default require.context('../assets', true, /^\.\//);
4 |
--------------------------------------------------------------------------------
/client/apps/hello_world/middleware/api.js:
--------------------------------------------------------------------------------
1 | import Api from 'atomic-fuel/libs/middleware/api';
2 |
3 | // This file just exports the default global api. If modifications are needed
4 | // make the modifications in this file by extending the Api or copy pasting the
5 | // code into this file.
6 | export default Api;
7 |
--------------------------------------------------------------------------------
/client/apps/hello_world/reducers/application.js:
--------------------------------------------------------------------------------
1 | const initialState = {};
2 |
3 | export default (state = initialState, action) => {
4 | switch (action.type) {
5 |
6 | default:
7 | return state;
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/client/apps/hello_world/reducers/application.spec.js:
--------------------------------------------------------------------------------
1 | import application from './application';
2 |
3 | describe('application reducer', () => {
4 | describe('initial state', () => {
5 | it('returns empty state', () => {
6 | const initialState = {};
7 | const state = application(initialState, {});
8 | expect(state).toEqual({});
9 | });
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/client/apps/hello_world/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import settings from 'atomic-fuel/libs/reducers/settings';
3 | import jwt from 'atomic-fuel/libs/reducers/jwt';
4 | import errors from 'atomic-fuel/libs/reducers/errors';
5 | import application from './application';
6 |
7 | const rootReducer = combineReducers({
8 | settings,
9 | jwt,
10 | application,
11 | errors,
12 | });
13 |
14 | export default rootReducer;
15 |
--------------------------------------------------------------------------------
/client/apps/hello_world/static/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/.keep
--------------------------------------------------------------------------------
/client/apps/hello_world/static/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/android-icon-144x144.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/android-icon-192x192.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/android-icon-36x36.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/android-icon-48x48.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/android-icon-72x72.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/android-icon-96x96.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-114x114.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-120x120.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-144x144.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-152x152.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-180x180.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-57x57.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-60x60.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-72x72.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-76x76.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/apple-icon.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/client/apps/hello_world/static/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/favicon-16x16.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/favicon-32x32.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/favicon-96x96.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/favicon.ico
--------------------------------------------------------------------------------
/client/apps/hello_world/static/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App",
3 | "icons": [
4 | {
5 | "src": "\/android-icon-36x36.png",
6 | "sizes": "36x36",
7 | "type": "image\/png",
8 | "density": "0.75"
9 | },
10 | {
11 | "src": "\/android-icon-48x48.png",
12 | "sizes": "48x48",
13 | "type": "image\/png",
14 | "density": "1.0"
15 | },
16 | {
17 | "src": "\/android-icon-72x72.png",
18 | "sizes": "72x72",
19 | "type": "image\/png",
20 | "density": "1.5"
21 | },
22 | {
23 | "src": "\/android-icon-96x96.png",
24 | "sizes": "96x96",
25 | "type": "image\/png",
26 | "density": "2.0"
27 | },
28 | {
29 | "src": "\/android-icon-144x144.png",
30 | "sizes": "144x144",
31 | "type": "image\/png",
32 | "density": "3.0"
33 | },
34 | {
35 | "src": "\/android-icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image\/png",
38 | "density": "4.0"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/client/apps/hello_world/static/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/ms-icon-144x144.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/ms-icon-150x150.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/ms-icon-310x310.png
--------------------------------------------------------------------------------
/client/apps/hello_world/static/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/static/ms-icon-70x70.png
--------------------------------------------------------------------------------
/client/apps/hello_world/store/configure_store.js:
--------------------------------------------------------------------------------
1 | import configureStore from 'atomic-fuel/libs/store/configure_store';
2 | import rootReducer from '../reducers/index';
3 | import API from '../middleware/api';
4 |
5 | const middleware = [API];
6 |
7 | // This file just exports the default configure store. If modifications are needed
8 | // make the modifications in this file by extending the configureStore
9 | // or copy pasting the code into this file.
10 | export default function(initialState) {
11 | return configureStore(initialState, rootReducer, middleware);
12 | }
13 |
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/.csslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "adjoining-classes": false,
3 | "box-sizing": false,
4 | "box-model": false,
5 | "compatible-vendor-prefixes": false,
6 | "floats": false,
7 | "font-sizes": false,
8 | "gradients": false,
9 | "important": false,
10 | "known-properties": false,
11 | "outline-none": false,
12 | "qualified-headings": false,
13 | "regex-selectors": false,
14 | "shorthand": false,
15 | "text-indent": false,
16 | "unique-headings": false,
17 | "universal-selector": false,
18 | "unqualified-attributes": false
19 | }
20 |
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/_defines.scss:
--------------------------------------------------------------------------------
1 | $white: #fff;
2 | $black: #000;
3 |
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/fonts/roboto-bold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/styles/fonts/roboto-bold-webfont.woff
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/fonts/roboto-bold-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/styles/fonts/roboto-bold-webfont.woff2
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/fonts/roboto-regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/styles/fonts/roboto-regular-webfont.woff
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/fonts/roboto-regular-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/styles/fonts/roboto-regular-webfont.woff2
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/modules/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Fonts must be relative to the main scss file (i.e. the file that includes this mixin)
2 | // That's why the urls includes/ fonts/ even though that is up one directory
3 | @font-face {
4 | font-family: "robotobold";
5 | src: url("/fonts/roboto-bold-webfont.woff2") format("woff2"),
6 | url("/fonts/roboto-bold-webfont.woff") format("woff");
7 | font-weight: normal;
8 | font-style: normal;
9 |
10 | }
11 |
12 | @font-face {
13 | font-family: "robotoregular";
14 | src: url("/fonts/roboto-regular-webfont.woff2") format("woff2"),
15 | url("/fonts/roboto-regular-webfont.woff") format("woff");
16 | font-weight: normal;
17 | font-style: normal;
18 | }
19 |
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/styles.js:
--------------------------------------------------------------------------------
1 | // This file exists to compile all css - less and scss - into one file
2 | require('./styles.less');
3 | require('./styles.scss');
4 |
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/styles.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world/styles/styles.less
--------------------------------------------------------------------------------
/client/apps/hello_world/styles/styles.scss:
--------------------------------------------------------------------------------
1 | @import "defines";
2 | @import "modules/mixins";
3 |
4 | body {
5 | text-align: center;
6 | font-family: 'robotoregular';
7 | }
8 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/app.jsx:
--------------------------------------------------------------------------------
1 | import 'core-js';
2 | import 'regenerator-runtime/runtime';
3 | import es6Promise from 'es6-promise';
4 | import React from 'react';
5 | import ReactDOM from 'react-dom';
6 | import PropTypes from 'prop-types';
7 | import _ from 'lodash';
8 | import { ApolloProvider } from '@apollo/react-hooks';
9 | import { ApolloClient } from 'apollo-client';
10 | import { HttpLink } from 'apollo-link-http';
11 | import { ApolloLink } from 'apollo-link';
12 | import { withClientState } from 'apollo-link-state';
13 | import { InMemoryCache } from 'apollo-cache-inmemory';
14 | import { Router } from 'react-router';
15 | import { Route } from 'react-router-dom';
16 | import { Jwt } from 'atomic-fuel/libs/loaders/jwt';
17 | import settings from './settings';
18 |
19 | import appHistory from './history';
20 | import Index from './components/layout/index';
21 |
22 | import './styles/styles';
23 |
24 | // Polyfill es6 promises for IE
25 | es6Promise.polyfill();
26 |
27 | const jwt = new Jwt(window.DEFAULT_JWT, window.DEFAULT_SETTINGS.api_url);
28 | jwt.enableRefresh();
29 |
30 | class Root extends React.PureComponent {
31 | static propTypes = {
32 | client: PropTypes.object,
33 | };
34 |
35 | render() {
36 | const { client } = this.props;
37 | return (
38 |
39 |
40 |
41 |
42 |
43 | );
44 | }
45 | }
46 |
47 | export default Root;
48 |
49 | const inCacheMemory = new InMemoryCache();
50 |
51 | const stateLink = withClientState({
52 | cache: inCacheMemory,
53 | resolvers: {
54 | Mutation: {},
55 | },
56 | defaults: {
57 | welcomeMessage: 'Welcome to the GraphQL starter app'
58 | }
59 | });
60 |
61 | const links = [
62 | stateLink
63 | ];
64 |
65 | if (!_.isEmpty(settings.api_url)) {
66 | const authenticationLink = new ApolloLink((operation, forward) => {
67 | operation.setContext({
68 | headers: {
69 | authorization: `Bearer ${jwt.currentJwt}`
70 | }
71 | });
72 | return forward(operation);
73 | });
74 | links.push(authenticationLink);
75 |
76 | const httpLink = new HttpLink({
77 | uri: `${settings.api_url}api/graphql`,
78 | });
79 | links.push(httpLink);
80 | }
81 |
82 | const client = new ApolloClient({
83 | link: ApolloLink.from(links),
84 | cache: inCacheMemory,
85 | });
86 |
87 | ReactDOM.render(
88 | ,
89 | document.getElementById('main-app'),
90 | );
91 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/assets/images/atomicjolt.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/assets/images/atomicjolt.jpg
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/assets/images/atomicjolt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/assets/images/atomicjolt.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/assets/images/atomicjolt.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
9 |
12 |
16 |
18 |
22 |
25 |
30 |
33 |
36 |
38 |
39 |
42 |
43 |
44 |
52 |
53 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/components/common/not_found.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default () => (
4 |
5 |
Page Not Found
6 |
Sorry, but the page you were trying to view does not exist.
7 |
8 | );
9 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/components/home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import gql from 'graphql-tag';
3 | import { useQuery } from '@apollo/react-hooks';
4 |
5 | import assets from '../libs/assets';
6 |
7 | export const GET_WELCOME = gql`
8 | query getWelcome($name: String!) {
9 | welcomeMessage(name: $name)
10 | }
11 | `;
12 |
13 | export default function home() {
14 | const { loading, error, data } = useQuery(GET_WELCOME, {
15 | variables: {
16 | name: 'World',
17 | },
18 | });
19 |
20 | if (loading) return 'Loading...';
21 | if (error) return `Error! ${error.message}`;
22 |
23 | const img = assets('./images/atomicjolt.jpg');
24 |
25 | return (
26 |
27 |
28 |
29 | {data.welcomeMessage}
30 |
31 |
32 | by
33 | Atomic Jolt
34 |
35 |
36 | );
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/components/home.spec.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TestRenderer, { act } from 'react-test-renderer';
3 | import { MockedProvider } from '@apollo/react-testing';
4 | import waitForExpect from 'wait-for-expect';
5 | import Home, { GET_WELCOME } from './home';
6 |
7 | jest.mock('../libs/assets.js');
8 |
9 | const mocks = [
10 | {
11 | request: {
12 | query: GET_WELCOME,
13 | variables: { name: 'World' },
14 | },
15 | result: {
16 | data: {
17 | welcomeMessage: 'Hello World!',
18 | },
19 | },
20 | },
21 | ];
22 |
23 | describe('home', () => {
24 | it('should render loading state initially', () => {
25 | const testRenderer = TestRenderer.create(
26 |
27 |
28 | ,
29 | );
30 |
31 | const tree = testRenderer.toJSON();
32 | expect(JSON.stringify(tree).indexOf('Hello World!') === -1).toBe(true);
33 | });
34 |
35 | it('renders the home component', async() => {
36 | let testRenderer;
37 | await act(async() => {
38 | testRenderer = TestRenderer.create(
39 |
40 |
41 | ,
42 | );
43 | });
44 |
45 | await waitForExpect(() => {
46 | expect(JSON.stringify(testRenderer.toJSON()).indexOf('Hello World!') >= 0).toBe(true);
47 | });
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/components/layout/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, Switch } from 'react-router';
3 | import Home from '../home';
4 | import NotFound from '../common/not_found';
5 |
6 | export default class Index extends React.Component {
7 |
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/components/layout/index.spec.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { shallow } from 'enzyme';
3 | import Index from './index';
4 |
5 | jest.mock('../../libs/assets.js');
6 |
7 | describe('index', () => {
8 | let result;
9 | let props;
10 |
11 | beforeEach(() => {
12 | props = {};
13 | result = shallow( );
14 | });
15 |
16 | it('renders the index', () => {
17 | expect(result).toBeDefined();
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/history.js:
--------------------------------------------------------------------------------
1 | import createHashHistory from 'history/createHashHistory';
2 |
3 | export default createHashHistory();
4 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/404.html:
--------------------------------------------------------------------------------
1 | Page Not Found
2 | Sorry, but the page you were trying to view does not exist.
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/about.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: About
3 | author: Atomic Jolt
4 | layout: application
5 | permalink: /about-us/
6 | categories:
7 | - About Us
8 | tags:
9 | - About Us
10 | - Atomic Jolt
11 | ---
12 | About Us
13 | ---------------
14 | <%= metadata.tags %>
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/crossdomain.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/humans.txt:
--------------------------------------------------------------------------------
1 | # humanstxt.org/
2 | # The humans responsible & technology colophon
3 |
4 | # TEAM
5 |
6 | -- --
7 |
8 | # THANKS
9 |
10 |
11 |
12 | # TECHNOLOGY COLOPHON
13 |
14 | HTML5, CSS3, JavaScript
15 | React, jQuery, Bootstrap
16 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/layouts/application.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%- include('./partials/_head.html') %>
5 |
6 |
7 | <%- include('./partials/_header.html') %>
8 | <%- content %>
9 | <%- include('./partials/_google_analytics.html') %>
10 |
11 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/layouts/partials/_google_analytics.html:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/layouts/partials/_head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | React Client Starter GraphQL
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/layouts/partials/_header.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/html/layouts/partials/_header.html
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/html/robots.txt:
--------------------------------------------------------------------------------
1 | # www.robotstxt.org/
2 |
3 | # Allow crawling of all content
4 | User-agent: *
5 | Disallow:
6 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/libs/assets.js:
--------------------------------------------------------------------------------
1 | // See http://webpack.github.io/docs/context.html#dynamic-requires
2 |
3 | export default require.context('../assets', true, /^\.\//);
4 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/settings.js:
--------------------------------------------------------------------------------
1 | export default window.DEFAULT_SETTINGS;
2 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/.keep
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/android-icon-144x144.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/android-icon-192x192.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/android-icon-36x36.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/android-icon-48x48.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/android-icon-72x72.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/android-icon-96x96.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-114x114.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-120x120.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-144x144.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-152x152.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-180x180.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-57x57.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-60x60.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-72x72.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-76x76.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/apple-icon.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/favicon-16x16.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/favicon-32x32.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/favicon-96x96.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/favicon.ico
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App",
3 | "icons": [
4 | {
5 | "src": "\/android-icon-36x36.png",
6 | "sizes": "36x36",
7 | "type": "image\/png",
8 | "density": "0.75"
9 | },
10 | {
11 | "src": "\/android-icon-48x48.png",
12 | "sizes": "48x48",
13 | "type": "image\/png",
14 | "density": "1.0"
15 | },
16 | {
17 | "src": "\/android-icon-72x72.png",
18 | "sizes": "72x72",
19 | "type": "image\/png",
20 | "density": "1.5"
21 | },
22 | {
23 | "src": "\/android-icon-96x96.png",
24 | "sizes": "96x96",
25 | "type": "image\/png",
26 | "density": "2.0"
27 | },
28 | {
29 | "src": "\/android-icon-144x144.png",
30 | "sizes": "144x144",
31 | "type": "image\/png",
32 | "density": "3.0"
33 | },
34 | {
35 | "src": "\/android-icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image\/png",
38 | "density": "4.0"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/ms-icon-144x144.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/ms-icon-150x150.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/ms-icon-310x310.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/static/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/static/ms-icon-70x70.png
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/.csslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "adjoining-classes": false,
3 | "box-sizing": false,
4 | "box-model": false,
5 | "compatible-vendor-prefixes": false,
6 | "floats": false,
7 | "font-sizes": false,
8 | "gradients": false,
9 | "important": false,
10 | "known-properties": false,
11 | "outline-none": false,
12 | "qualified-headings": false,
13 | "regex-selectors": false,
14 | "shorthand": false,
15 | "text-indent": false,
16 | "unique-headings": false,
17 | "universal-selector": false,
18 | "unqualified-attributes": false
19 | }
20 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/_defines.scss:
--------------------------------------------------------------------------------
1 | $white: #fff;
2 | $black: #000;
3 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/fonts/roboto-bold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/styles/fonts/roboto-bold-webfont.woff
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/fonts/roboto-bold-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/styles/fonts/roboto-bold-webfont.woff2
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/fonts/roboto-regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/styles/fonts/roboto-regular-webfont.woff
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/fonts/roboto-regular-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/styles/fonts/roboto-regular-webfont.woff2
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/modules/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Fonts must be relative to the main scss file (i.e. the file that includes this mixin)
2 | // That's why the urls includes /fonts/ even though that is up one directory
3 | @font-face {
4 | font-family: "robotobold";
5 | src: url("/fonts/roboto-bold-webfont.woff2") format("woff2"),
6 | url("/fonts/roboto-bold-webfont.woff") format("woff");
7 | font-weight: normal;
8 | font-style: normal;
9 |
10 | }
11 |
12 | @font-face {
13 | font-family: "robotoregular";
14 | src: url("/fonts/roboto-regular-webfont.woff2") format("woff2"),
15 | url("/fonts/roboto-regular-webfont.woff") format("woff");
16 | font-weight: normal;
17 | font-style: normal;
18 | }
19 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/styles.js:
--------------------------------------------------------------------------------
1 | // This file exists to compile all css - less and scss - into one file
2 | require('./styles.less');
3 | require('./styles.scss');
4 |
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/styles.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/client/apps/hello_world_graphql/styles/styles.less
--------------------------------------------------------------------------------
/client/apps/hello_world_graphql/styles/styles.scss:
--------------------------------------------------------------------------------
1 | @import "defines";
2 | @import "modules/mixins";
3 |
4 | body {
5 | text-align: center;
6 | font-family: 'robotoregular';
7 | }
8 |
--------------------------------------------------------------------------------
/client/packs/hello_world.js:
--------------------------------------------------------------------------------
1 | import '../apps/hello_world/app';
2 |
--------------------------------------------------------------------------------
/client/packs/hello_world_graphql.js:
--------------------------------------------------------------------------------
1 | import '../apps/hello_world_graphql/app';
2 |
--------------------------------------------------------------------------------
/client/testing/__mocks__/file_mock.js:
--------------------------------------------------------------------------------
1 | module.exports = 'test-file-stub';
2 |
--------------------------------------------------------------------------------
/client/testing/__mocks__/style_mock.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/client/testing/setup_tests.js:
--------------------------------------------------------------------------------
1 | import { configure } from 'enzyme';
2 | import Adapter from 'enzyme-adapter-react-16';
3 |
4 | configure({ adapter: new Adapter() });
5 |
--------------------------------------------------------------------------------
/client/testing/shim.js:
--------------------------------------------------------------------------------
1 | global.requestAnimationFrame = (callback) => {
2 | setTimeout(callback, 0);
3 | };
4 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run Rails.application
5 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative 'boot'
2 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
8 |
9 | module ReactRailsStarterApp
10 | class Application < Rails::Application
11 | # Settings in config/environments/* take precedence over those specified here.
12 | # Application configuration should go into files in config/initializers
13 | # -- all .rb files in that directory are automatically loaded.
14 |
15 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
16 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
17 | # config.time_zone = 'Central Time se(US & Canada)'
18 |
19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
20 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
21 | # config.i18n.default_locale = :de
22 |
23 | config.autoload_paths += Dir["#{config.root}/lib/**/"]
24 |
25 | config.action_dispatch.default_headers = {
26 | "X-Frame-Options" => "ALLOWALL",
27 | }
28 |
29 | config.middleware.insert_before 0, Rack::Cors do
30 | allow do
31 | origins "*"
32 | resource "*", headers: :any, methods: [:get, :post, :options]
33 | end
34 | end
35 |
36 | config.webpack = {
37 | use_manifest: false,
38 | asset_manifest: {},
39 | common_manifest: {},
40 | }
41 |
42 | # Initialize configuration defaults for originally generated Rails version.
43 | config.load_defaults 5.0
44 |
45 | # Settings in config/environments/* take precedence over those specified here.
46 | # Application configuration can go into files in config/initializers
47 | # -- all .rb files in that directory are automatically loaded after loading
48 | # the framework and any gems in your application.
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/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 | require "bootsnap/setup" # Speed up boot time by caching expensive operations.
5 |
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10 | channel_prefix: react_rails_starter_app_production
11 |
--------------------------------------------------------------------------------
/config/ci.database.yml:
--------------------------------------------------------------------------------
1 | staging:
2 | adapter: postgresql
3 | host: localhost
4 | encoding: unicode
5 | pool: 10
6 | username: <%= ENV['PG_USER'] %>
7 | template: template1
8 | password: <%= ENV['PG_PASSWORD'] %>
9 | database: development<%= ENV['TEST_ENV_NUMBER'] %>
10 | sslmode: disable
11 | development:
12 | adapter: postgresql
13 | host: localhost
14 | encoding: unicode
15 | pool: 10
16 | username: <%= ENV['PG_USER'] %>
17 | template: template1
18 | password: <%= ENV['PG_PASSWORD'] %>
19 | database: development<%= ENV['TEST_ENV_NUMBER'] %>
20 | sslmode: disable
21 | test:
22 | adapter: postgresql
23 | database: travis_ci_test
24 |
--------------------------------------------------------------------------------
/config/database.example.yml:
--------------------------------------------------------------------------------
1 | # PostgreSQL. Versions 8.2 and up are supported.
2 | #
3 | # Install the pg driver:
4 | # gem install pg
5 | # On Mac OS X with macports:
6 | # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
7 | # On Windows:
8 | # gem install pg
9 | # Choose the win32 build.
10 | # Install PostgreSQL and put its /bin directory on your path.
11 | #
12 | # Configure Using Gemfile
13 | # gem 'pg'
14 | #
15 | development:
16 | adapter: postgresql
17 | host: localhost
18 | encoding: unicode
19 | database: lti_starter_app_development
20 | pool: 5
21 | username:
22 | password:
23 | template: template0
24 |
25 | # Connect on a TCP socket. Omitted by default since the client uses a
26 | # domain socket that doesn't need configuration. Windows does not have
27 | # domain sockets, so uncomment these lines.
28 | #host: localhost
29 | #port: 5432
30 |
31 | # Schema search path. The server defaults to $user,public
32 | #schema_search_path: myapp,sharedapp,public
33 |
34 | # Minimum log levels, in increasing order:
35 | # debug5, debug4, debug3, debug2, debug1,
36 | # log, notice, warning, error, fatal, and panic
37 | # The server defaults to notice.
38 | #min_messages: warning
39 |
40 | # Warning: The database defined as "test" will be erased and
41 | # re-generated from your development database when you run "rake".
42 | # Do not set this db to the same as development or production.
43 | test:
44 | adapter: postgresql
45 | host: localhost
46 | encoding: unicode
47 | database: lti_starter_app_test
48 | pool: 5
49 | username:
50 | password:
51 | template: template0
52 |
53 | production:
54 | adapter: postgresql
55 | host: localhost
56 | encoding: unicode
57 | database: lti_starter_app_production
58 | pool: 5
59 | username:
60 | password:
61 | template: template0
62 |
--------------------------------------------------------------------------------
/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 | # Run rails dev:cache to toggle caching.
17 | if Rails.root.join("tmp", "caching-dev.txt").exist?
18 | config.action_controller.perform_caching = true
19 |
20 | config.cache_store = :memory_store
21 | config.public_file_server.headers = {
22 | "Cache-Control" => "public, max-age=#{2.days.to_i}",
23 | }
24 | else
25 | config.action_controller.perform_caching = false
26 |
27 | config.cache_store = :null_store
28 | end
29 |
30 | # Store uploaded files on the local file system (see config/storage.yml for options)
31 | config.active_storage.service = :local
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 | # Highlight code that triggered database queries in logs.
42 | config.active_record.verbose_query_logs = true
43 |
44 | # Debug mode disables concatenation and preprocessing of assets.
45 | # This option may cause significant delays in view rendering with a large
46 | # number of complex assets.
47 | config.assets.debug = true
48 |
49 | # Suppress logger output for asset requests.
50 | config.assets.quiet = true
51 |
52 | # Raises error for missing translations
53 | # config.action_view.raise_on_missing_translations = true
54 |
55 | # Use an evented file watcher to asynchronously detect changes in source code,
56 | # routes, locales, etc. This feature depends on the listen gem.
57 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
58 |
59 | #
60 | # Custom configuration
61 | #
62 | config.generators do |g|
63 | g.test_framework :rspec,
64 | fixtures: true,
65 | view_specs: false,
66 | helper_specs: false,
67 | routing_specs: false,
68 | controller_specs: false,
69 | request_specs: false
70 | g.fixture_replacement :factory_bot, dir: "spec/factories"
71 | end
72 |
73 | # ActionMailer Config
74 | config.action_mailer.default_url_options = { host: "localhost:#{ENV['APP_PORT']}" }
75 | config.action_mailer.delivery_method = :smtp
76 | config.action_mailer.raise_delivery_errors = true
77 | # Send email in development mode?
78 | config.action_mailer.perform_deliveries = false
79 |
80 | end
81 |
--------------------------------------------------------------------------------
/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=#{1.hour.to_i}",
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 |
31 | # Store uploaded files on the local file system in a temporary directory
32 | config.active_storage.service = :test
33 |
34 | config.action_mailer.perform_caching = false
35 |
36 | # Tell Action Mailer not to deliver emails to the real world.
37 | # The :test delivery method accumulates sent emails in the
38 | # ActionMailer::Base.deliveries array.
39 | config.action_mailer.delivery_method = :test
40 |
41 | # Print deprecation notices to the stderr.
42 | config.active_support.deprecation = :stderr
43 |
44 | # Raises error for missing translations
45 | # config.action_view.raise_on_missing_translations = true
46 |
47 | #
48 | # Custom configuration
49 | #
50 | config.action_mailer.default_url_options = { host: "localhost" }
51 | end
52 |
--------------------------------------------------------------------------------
/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # ActiveSupport::Reloader.to_prepare do
4 | # ApplicationController.renderer.defaults.merge!(
5 | # http_host: 'example.org',
6 | # https: false
7 | # )
8 | # end
9 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = "1.0"
5 |
6 | # Add additional assets to the asset load path.
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 | # Add Yarn node_modules folder to the asset load path.
9 | Rails.application.config.assets.paths << Rails.root.join("node_modules")
10 |
11 | # Precompile additional assets.
12 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
13 | Rails.application.config.assets.precompile += %w(client.css)
14 |
--------------------------------------------------------------------------------
/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 but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Define an application-wide content security policy
4 | # For further information see the following documentation
5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
6 |
7 | # Rails.application.config.content_security_policy do |policy|
8 | # policy.default_src :self, :https
9 | # policy.font_src :self, :https, :data
10 | # policy.img_src :self, :https, :data
11 | # policy.object_src :none
12 | # policy.script_src :self, :https
13 | # policy.style_src :self, :https
14 |
15 | # # Specify URI for violation reports
16 | # # policy.report_uri "/csp-violation-report-endpoint"
17 | # end
18 |
19 | # If you are using UJS then enable automatic nonce generation
20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
21 |
22 | # Report CSP violations to a specified URI
23 | # For further information see the following documentation:
24 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
25 | # Rails.application.config.content_security_policy_report_only = true
26 | Rails.application.config.content_security_policy do |policy|
27 | if Rails.env.development?
28 | policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035"
29 |
30 | host = "#{ENV['ASSETS_SUBDOMAIN']}.#{ENV['APP_ROOT_DOMAIN']}"
31 | policy.connect_src :self, :https, "http://#{host}", "ws://#{host}"
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Specify a serializer for the signed and encrypted cookie jars.
4 | # Valid options are :json, :marshal, and :hybrid.
5 | Rails.application.config.action_dispatch.cookies_serializer = :json
6 |
--------------------------------------------------------------------------------
/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 Guide for Upgrading Ruby on Rails for more info on each option.
6 |
7 | # Enable per-form CSRF tokens. Previous versions had false.
8 | Rails.application.config.action_controller.per_form_csrf_tokens = true
9 |
10 | # Enable origin-checking CSRF mitigation. Previous versions had false.
11 | Rails.application.config.action_controller.forgery_protection_origin_check = true
12 |
13 | # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`.
14 | # Previous versions had false.
15 | ActiveSupport.to_time_preserves_timezone = true
16 |
17 | # Require `belongs_to` associations by default. Previous versions had false.
18 | Rails.application.config.active_record.belongs_to_required_by_default = true
19 |
20 | # Configure SSL options to enable HSTS with subdomains. Previous versions had false.
21 | Rails.application.config.ssl_options = { hsts: { subdomains: true } }
22 |
--------------------------------------------------------------------------------
/config/initializers/new_framework_defaults_5_1.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.1 upgrade.
4 | #
5 | # Once upgraded flip defaults one by one to migrate to the new default.
6 | #
7 | # Read the Guide for Upgrading Ruby on Rails for more info on each option.
8 |
9 | # Make `form_with` generate non-remote forms.
10 | Rails.application.config.action_view.form_with_generates_remote_forms = false
11 |
12 | # Unknown asset fallback will return the path passed in when the given
13 | # asset is not present in the asset pipeline.
14 | # Rails.application.config.assets.unknown_asset_fallback = false
15 |
--------------------------------------------------------------------------------
/config/initializers/new_framework_defaults_5_2.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.2 upgrade.
4 | #
5 | # Once upgraded flip defaults one by one to migrate to the new default.
6 | #
7 | # Read the Guide for Upgrading Ruby on Rails for more info on each option.
8 |
9 | # Make Active Record use stable #cache_key alongside new #cache_version method.
10 | # This is needed for recyclable cache keys.
11 | # Rails.application.config.active_record.cache_versioning = true
12 |
13 | # Use AES-256-GCM authenticated encryption for encrypted cookies.
14 | # Also, embed cookie expiry in signed or encrypted cookies for increased security.
15 | #
16 | # This option is not backwards compatible with earlier Rails versions.
17 | # It's best enabled when your entire app is migrated and stable on 5.2.
18 | #
19 | # Existing cookies will be converted on read then written with the new scheme.
20 | # Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true
21 |
22 | # Use AES-256-GCM authenticated encryption as default cipher for encrypting messages
23 | # instead of AES-256-CBC, when use_authenticated_message_encryption is set to true.
24 | # Rails.application.config.active_support.use_authenticated_message_encryption = true
25 |
26 | # Add default protection from forgery to ActionController::Base instead of in
27 | # ApplicationController.
28 | # Rails.application.config.action_controller.default_protect_from_forgery = true
29 |
30 | # Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and
31 | # 'f' after migrating old data.
32 | # Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
33 |
34 | # Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header.
35 | # Rails.application.config.active_support.use_sha1_digests = true
36 |
37 | # Make `form_with` generate id attributes for any generated HTML tags.
38 | # Rails.application.config.action_view.form_with_generates_ids = true
39 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: "_react_rails_starter_app_session"
4 |
--------------------------------------------------------------------------------
/config/initializers/webpack.rb:
--------------------------------------------------------------------------------
1 |
2 | def build_manifest(manifest_name, kind)
3 | configs_dir = Rails.root.join("config", "assets")
4 | Rails.configuration.webpack[manifest_name] = {}
5 | Dir.glob("#{configs_dir}/*#{kind}") do |file|
6 | app_name = File.basename(file).gsub("-#{kind}", "")
7 | Rails.configuration.webpack[manifest_name][app_name] = JSON.parse(
8 | File.read(file),
9 | ).with_indifferent_access
10 | end
11 | end
12 |
13 | if Rails.configuration.webpack[:use_manifest]
14 | build_manifest(:asset_manifest, "webpack-assets.json")
15 | build_manifest(:common_manifest, "webpack-common-manifest.json")
16 | end
17 |
--------------------------------------------------------------------------------
/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/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 | # The following keys must be escaped otherwise they will not be retrieved by
20 | # the default I18n backend:
21 | #
22 | # true, false, on, off, yes, no
23 | #
24 | # Instead, surround them with single quotes.
25 | #
26 | # en:
27 | # 'true': 'foo'
28 | #
29 | # To learn more, please read the Rails Internationalization guide
30 | # available at http://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | hello: "Hello world"
34 |
--------------------------------------------------------------------------------
/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/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | root to: "home#index"
3 |
4 | devise_for :users, controllers: {
5 | sessions: "sessions",
6 | registrations: "registrations",
7 | omniauth_callbacks: "omniauth_callbacks",
8 | }
9 |
10 | as :user do
11 | get "/auth/failure" => "sessions#new"
12 | get "users/auth/:provider" => "users/omniauth_callbacks#passthru"
13 | get "sign_in" => "sessions#new"
14 | post "sign_in" => "sessions#create"
15 | get "sign_up" => "devise/registrations#new"
16 | delete "sign_out" => "sessions#destroy"
17 | get "sign_out" => "sessions#destroy"
18 | end
19 |
20 | resources :users
21 |
22 | namespace :api do
23 | resources :jwts
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/config/secrets.example.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 | Defaults: &defaults
13 |
14 | admin_name: Administrator
15 | admin_email: admin@example.com
16 | admin_password: changeme
17 |
18 | encryption_key: ''
19 |
20 | # Main application settings
21 | application_name: "React Starter App"
22 | application_main_domain: <%= %Q{#{ENV["APP_SUBDOMAIN"]}.#{ENV["APP_ROOT_DOMAIN"] || "lvh.me"}} %>
23 |
24 | # Email Settings
25 | application_root_domain: <%= ENV["APP_ROOT_DOMAIN"] || "reactrailsstarterapp.com" %>
26 | email_provider_username: admin@example.com
27 | email_provider_password: changeme
28 |
29 | # Assets (webpack server in dev mode)
30 | assets_url: <%= ENV["ASSETS_URL"] || "http://localhost:8080" %>
31 |
32 | auth0_client_id: react_rails_starter_app
33 | auth0_client_secret: ''
34 |
35 | development:
36 | <<: *defaults
37 |
38 | secret_key_base: ''
39 |
40 | test:
41 | <<: *defaults
42 |
43 | secret_key_base: ''
44 |
45 | # Do not keep production secrets in the repository,
46 | # instead read values from the environment.
47 | production:
48 | <<: *defaults
49 |
50 | application_main_domain: <%= "#{ENV['APP_SUBDOMAIN']}.herokuapp.com" %>
51 |
52 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
53 |
54 | encryption_key: ''
55 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/config/storage.yml:
--------------------------------------------------------------------------------
1 | test:
2 | service: Disk
3 | root: <%= Rails.root.join("tmp/storage") %>
4 |
5 | local:
6 | service: Disk
7 | root: <%= Rails.root.join("storage") %>
8 |
9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10 | # amazon:
11 | # service: S3
12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14 | # region: us-east-1
15 | # bucket: your_own_bucket
16 |
17 | # Remember not to checkin your GCS keyfile to a repository
18 | # google:
19 | # service: GCS
20 | # project: your_project
21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22 | # bucket: your_own_bucket
23 |
24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25 | # microsoft:
26 | # service: AzureStorage
27 | # storage_account_name: your_account_name
28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29 | # container: your_container_name
30 |
31 | # mirror:
32 | # service: Mirror
33 | # primary: local
34 | # mirrors: [ amazon, google, microsoft ]
35 |
--------------------------------------------------------------------------------
/config/webpack/development.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | process.env.NODE_ENV = process.env.NODE_ENV || 'development';
3 |
4 | const environment = require('./environment');
5 |
6 | module.exports = environment.toWebpackConfig();
7 |
--------------------------------------------------------------------------------
/config/webpack/environment.js:
--------------------------------------------------------------------------------
1 | const { environment } = require('@rails/webpacker');
2 |
3 | const graphqlLoader = {
4 | test: /\.(graphql|gql)$/,
5 | exclude: /node_modules/,
6 | loader: 'graphql-tag/loader'
7 | };
8 |
9 | // Insert json loader at the end of list
10 | environment.loaders.append('graphql', graphqlLoader);
11 |
12 | module.exports = environment;
13 |
--------------------------------------------------------------------------------
/config/webpack/production.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'production';
2 |
3 | const environment = require('./environment');
4 |
5 | module.exports = environment.toWebpackConfig();
6 |
--------------------------------------------------------------------------------
/config/webpack/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development';
2 |
3 | const environment = require('./environment');
4 |
5 | module.exports = environment.toWebpackConfig();
6 |
--------------------------------------------------------------------------------
/config/webpacker.yml:
--------------------------------------------------------------------------------
1 | # Note: You must restart bin/webpack-dev-server for changes to take effect
2 |
3 | default: &default
4 | source_path: client
5 | source_entry_path: packs
6 | public_root_path: public
7 | public_output_path: packs
8 | cache_path: tmp/cache/webpacker
9 | check_yarn_integrity: false
10 | webpack_compile_output: false
11 |
12 | # Additional paths webpack should lookup modules
13 | # ['app/assets', 'engine/foo/app/assets']
14 | resolved_paths: []
15 |
16 | # Reload manifest.json on all requests so we reload latest compiled packs
17 | cache_manifest: false
18 |
19 | # Extract and emit a css file
20 | extract_css: false
21 |
22 | static_assets_extensions:
23 | - .jpg
24 | - .jpeg
25 | - .png
26 | - .gif
27 | - .tiff
28 | - .ico
29 | - .svg
30 | - .eot
31 | - .otf
32 | - .ttf
33 | - .woff
34 | - .woff2
35 |
36 | extensions:
37 | - .jsx
38 | - .mjs
39 | - .js
40 | - .sass
41 | - .scss
42 | - .css
43 | - .module.sass
44 | - .module.scss
45 | - .module.css
46 | - .png
47 | - .svg
48 | - .gif
49 | - .jpeg
50 | - .jpg
51 | - .gql
52 | - .graphql
53 |
54 | development:
55 | <<: *default
56 | compile: true
57 |
58 | # Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules
59 | check_yarn_integrity: true
60 |
61 | # Reference: https://webpack.js.org/configuration/dev-server/
62 | dev_server:
63 | https: false
64 | # This path is setup in .env and requires that an entry be added to nginx
65 | # usually via bin/setup. NOTE be sure to update this value in each project
66 | public: rsa-assets.atomicjolt.xyz
67 | # hot module reload requires additional setup in each client app
68 | hmr: false
69 | # 'inline' causes the brower to refresh when changes occur. This does not
70 | # work in an lti app, since it will refresh the iframe and fail to load the
71 | # app again. It should be set to true if using HMR
72 | inline: false
73 | overlay: true
74 | compress: true
75 | disable_host_check: true
76 | use_local_ip: false
77 | quiet: false
78 | headers:
79 | 'Access-Control-Allow-Origin': '*'
80 | watch_options:
81 | ignored: '**/node_modules/**'
82 |
83 |
84 | test:
85 | <<: *default
86 | compile: false
87 |
88 | # Compile test packs to a separate directory
89 | public_output_path: packs-test
90 |
91 | production:
92 | <<: *default
93 |
94 | # Production depends on precompilation of packs prior to booting for performance.
95 | compile: false
96 |
97 | # Extract and emit a css file
98 | extract_css: true
99 |
100 | # Cache manifest.json for performance
101 | cache_manifest: true
102 |
--------------------------------------------------------------------------------
/db/migrate/20120209004849_initial.rb:
--------------------------------------------------------------------------------
1 | class Initial < ActiveRecord::Migration[4.2]
2 | create_table "authentications", force: :cascade do |t|
3 | t.integer "user_id"
4 | t.string "provider"
5 | t.datetime "created_at", null: false
6 | t.datetime "updated_at", null: false
7 | t.text "json_response"
8 | t.string "uid"
9 | t.string "provider_avatar"
10 | t.string "username"
11 | t.string "provider_url", limit: 2048
12 | t.string "encrypted_token"
13 | t.string "encrypted_token_salt"
14 | t.string "encrypted_token_iv"
15 | t.string "encrypted_secret"
16 | t.string "encrypted_secret_salt"
17 | t.string "encrypted_secret_iv"
18 | t.string "encrypted_refresh_token"
19 | t.string "encrypted_refresh_token_salt"
20 | t.string "encrypted_refresh_token_iv"
21 | end
22 |
23 | add_index "authentications", ["provider", "uid"], name: "index_authentications_on_provider_and_uid", using: :btree
24 | add_index "authentications", ["user_id"], name: "index_authentications_on_user_id", using: :btree
25 |
26 | create_table "permissions", force: :cascade do |t|
27 | t.integer "role_id"
28 | t.integer "user_id"
29 | t.datetime "created_at"
30 | t.datetime "updated_at"
31 | end
32 |
33 | add_index "permissions", ["role_id", "user_id"], name: "index_permissions_on_role_id_and_user_id", using: :btree
34 |
35 | create_table "roles", force: :cascade do |t|
36 | t.string "name"
37 | t.datetime "created_at"
38 | t.datetime "updated_at"
39 | end
40 |
41 | create_table "users", force: :cascade do |t|
42 | t.string "email", default: "", null: false
43 | t.string "encrypted_password", default: "", null: false
44 | t.string "reset_password_token"
45 | t.datetime "reset_password_sent_at"
46 | t.datetime "remember_created_at"
47 | t.integer "sign_in_count", default: 0, null: false
48 | t.datetime "current_sign_in_at"
49 | t.datetime "last_sign_in_at"
50 | t.string "current_sign_in_ip"
51 | t.string "last_sign_in_ip"
52 | t.datetime "created_at"
53 | t.datetime "updated_at"
54 | t.string "name"
55 | t.string "confirmation_token"
56 | t.datetime "confirmed_at"
57 | t.datetime "confirmation_sent_at"
58 | t.string "unconfirmed_email"
59 | t.string "time_zone", default: "UTC"
60 | t.string "password_salt"
61 | end
62 |
63 | add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
64 | add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
65 |
66 | end
--------------------------------------------------------------------------------
/db/migrate/20170612172246_add_context_id_to_permission.rb:
--------------------------------------------------------------------------------
1 | class AddContextIdToPermission < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :permissions, :context_id, :string
4 | add_index :permissions, :context_id
5 | add_index :permissions, [:role_id, :user_id, :context_id]
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20170613231518_add_create_type_to_user.rb:
--------------------------------------------------------------------------------
1 | class AddCreateTypeToUser < ActiveRecord::Migration[5.0]
2 | def change
3 | add_column :users, :create_method, :integer, default: 0
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20170921202325_add_authentication_index.rb:
--------------------------------------------------------------------------------
1 | class AddAuthenticationIndex < ActiveRecord::Migration[5.0]
2 | def change
3 | add_index :authentications, [ :uid, :provider, :provider_url ]
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20171003155408_change_rr_integer_to_bigint.rb:
--------------------------------------------------------------------------------
1 | class ChangeRrIntegerToBigint < ActiveRecord::Migration[5.0]
2 | def up
3 | change_column :authentications, :id, :bigint
4 | change_column :permissions, :id, :bigint
5 | change_column :roles, :id, :bigint
6 | change_column :users, :id, :bigint
7 |
8 | change_column :authentications, :user_id, :bigint
9 | change_column :permissions, :role_id, :bigint
10 | change_column :permissions, :user_id, :bigint
11 | change_column :users, :sign_in_count, :bigint
12 | change_column :users, :create_method, :bigint
13 | end
14 |
15 | def down
16 | change_column :authentications, :id, :integer
17 | change_column :permissions, :id, :integer
18 | change_column :roles, :id, :integer
19 | change_column :users, :id, :integer
20 |
21 | change_column :authentications, :user_id, :integer
22 | change_column :permissions, :role_id, :integer
23 | change_column :permissions, :user_id, :integer
24 | change_column :users, :sign_in_count, :integer
25 | change_column :users, :create_method, :integer
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/db/migrate/20181127204956_remove_unused_fields.rb:
--------------------------------------------------------------------------------
1 | class RemoveUnusedFields < ActiveRecord::Migration[5.1]
2 | def change
3 | remove_column :authentications, :json_response, :text
4 | remove_column :users, :time_zone, :string, default: "UTC"
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20190219201006_add_unique_index_to_permissions.rb:
--------------------------------------------------------------------------------
1 | class AddUniqueIndexToPermissions < ActiveRecord::Migration[5.1]
2 | def up
3 | remove_index :permissions, [:role_id, :user_id]
4 | remove_index :permissions, [:role_id, :user_id, :context_id]
5 | add_index :permissions, [:role_id, :user_id], unique: true, where: "(context_id IS NULL)"
6 | add_index :permissions, [:role_id, :user_id, :context_id], unique: true
7 | end
8 |
9 | def down
10 | remove_index :permissions, [:role_id, :user_id, :context_id]
11 | remove_index :permissions, [:role_id, :user_id]
12 | add_index :permissions, [:role_id, :user_id, :context_id]
13 | add_index :permissions, [:role_id, :user_id]
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/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: 20190219201006) do
14 |
15 | # These are extensions that must be enabled in order to support this database
16 | enable_extension "plpgsql"
17 |
18 | create_table "authentications", force: :cascade do |t|
19 | t.bigint "user_id"
20 | t.string "provider"
21 | t.datetime "created_at", null: false
22 | t.datetime "updated_at", null: false
23 | t.string "uid"
24 | t.string "provider_avatar"
25 | t.string "username"
26 | t.string "provider_url", limit: 2048
27 | t.string "encrypted_token"
28 | t.string "encrypted_token_salt"
29 | t.string "encrypted_token_iv"
30 | t.string "encrypted_secret"
31 | t.string "encrypted_secret_salt"
32 | t.string "encrypted_secret_iv"
33 | t.string "encrypted_refresh_token"
34 | t.string "encrypted_refresh_token_salt"
35 | t.string "encrypted_refresh_token_iv"
36 | t.index ["provider", "uid"], name: "index_authentications_on_provider_and_uid"
37 | t.index ["uid", "provider", "provider_url"], name: "index_authentications_on_uid_and_provider_and_provider_url"
38 | t.index ["user_id"], name: "index_authentications_on_user_id"
39 | end
40 |
41 | create_table "permissions", force: :cascade do |t|
42 | t.bigint "role_id"
43 | t.bigint "user_id"
44 | t.datetime "created_at"
45 | t.datetime "updated_at"
46 | t.string "context_id"
47 | t.index ["context_id"], name: "index_permissions_on_context_id"
48 | t.index ["role_id", "user_id", "context_id"], name: "index_permissions_on_role_id_and_user_id_and_context_id", unique: true
49 | t.index ["role_id", "user_id"], name: "index_permissions_on_role_id_and_user_id", unique: true, where: "(context_id IS NULL)"
50 | end
51 |
52 | create_table "roles", force: :cascade do |t|
53 | t.string "name"
54 | t.datetime "created_at"
55 | t.datetime "updated_at"
56 | end
57 |
58 | create_table "users", force: :cascade do |t|
59 | t.string "email", default: "", null: false
60 | t.string "encrypted_password", default: "", null: false
61 | t.string "reset_password_token"
62 | t.datetime "reset_password_sent_at"
63 | t.datetime "remember_created_at"
64 | t.bigint "sign_in_count", default: 0, null: false
65 | t.datetime "current_sign_in_at"
66 | t.datetime "last_sign_in_at"
67 | t.string "current_sign_in_ip"
68 | t.string "last_sign_in_ip"
69 | t.datetime "created_at"
70 | t.datetime "updated_at"
71 | t.string "name"
72 | t.string "confirmation_token"
73 | t.datetime "confirmed_at"
74 | t.datetime "confirmation_sent_at"
75 | t.string "unconfirmed_email"
76 | t.string "password_salt"
77 | t.bigint "create_method", default: 0
78 | t.index ["email"], name: "index_users_on_email", unique: true
79 | t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
80 | end
81 |
82 | end
83 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # add an admin to the default account
2 | admin = CreateAdminService.new.call
3 | puts "CREATED ADMIN USER: " << admin.email
4 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/lib/tasks/.keep
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/log/.keep
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_rails_starter_app",
3 | "version": "1.0.0",
4 | "description": "React Starter App with Rails. Uses webpacker.",
5 | "author": "atomicjolt",
6 | "license": "MIT",
7 | "homepage": "https://github.com/atomicjolt/react_rails_starter_app",
8 | "scripts": {
9 | "test": "jest --config package.json",
10 | "test_update": "jest -u --config package.json",
11 | "test_debug": "node inspect jest --runInBand --config package.json || SUCCESS=false",
12 | "hot": "./bin/webpack-dev-server",
13 | "lint": "eslint client",
14 | "lint_fix": "eslint client --fix",
15 | "nuke": "rm -rf node_modules",
16 | "inspect_fuel": "\"${EDITOR:-vi}\" ./node_modules/atomic-fuel"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "https://github.com/atomicjolt/react_rails_starter_app"
21 | },
22 | "keywords": [
23 | "React",
24 | "Rails",
25 | "Atomic Jolt"
26 | ],
27 | "jest": {
28 | "roots": [
29 | "/client"
30 | ],
31 | "verbose": true,
32 | "moduleDirectories": [
33 | "node_modules",
34 | "/client"
35 | ],
36 | "transform": {
37 | "\\.(gql|graphql)$": "jest-transform-graphql",
38 | ".*": "babel-jest"
39 | },
40 | "moduleNameMapper": {
41 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "./client/testing/__mocks__/file_mock.js",
42 | "\\.(sass|scss|css|less)$": "./client/testing/__mocks__/style_mock.js"
43 | },
44 | "setupFilesAfterEnv": [
45 | "./client/testing/shim.js",
46 | "./client/testing/setup_tests.js"
47 | ]
48 | },
49 | "dependencies": {
50 | "@apollo/react-hooks": "^4.0.0",
51 | "@apollo/react-testing": "^4.0.0",
52 | "@babel/core": "^7.11.6",
53 | "@babel/plugin-proposal-class-properties": "^7.10.4",
54 | "@babel/plugin-proposal-object-rest-spread": "^7.11.0",
55 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
56 | "@babel/plugin-transform-destructuring": "^7.10.4",
57 | "@babel/plugin-transform-regenerator": "^7.10.4",
58 | "@babel/plugin-transform-runtime": "^7.11.5",
59 | "@babel/preset-env": "^7.11.5",
60 | "@babel/preset-react": "^7.10.4",
61 | "@rails/webpacker": "^4.2.2",
62 | "apollo-cache-inmemory": "^1.6.6",
63 | "apollo-client": "^2.6.10",
64 | "apollo-link": "^1.2.14",
65 | "apollo-link-http": "^1.5.17",
66 | "apollo-link-state": "^0.4.0",
67 | "atomic-fuel": "^4.8.1",
68 | "babel-loader": "^8.1.0",
69 | "babel-plugin-dynamic-import-node": "^2.3.3",
70 | "babel-plugin-macros": "^2.8.0",
71 | "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
72 | "babel-preset-es2015": "^6.24.1",
73 | "core-js": "^3.6.5",
74 | "css-loader": "^2.1.1",
75 | "es6-promise": "^4.2.4",
76 | "file-loader": "^4.3.0",
77 | "graphql": "^15.3.0",
78 | "graphql-tag": "^2.11.0",
79 | "history": "^4.10.1",
80 | "lodash": "4.17.20",
81 | "mime": "^2.4.6",
82 | "prop-types": "^15.7.2",
83 | "react": "^16.13.1",
84 | "react-apollo": "^3.1.5",
85 | "react-dom": "^16.13.1",
86 | "react-proxy-loader": "^0.3.5",
87 | "react-redux": "^7.1.3",
88 | "react-router": "^5.1.2",
89 | "react-router-dom": "^5.1.2",
90 | "react-router3": "npm:react-router@3.2.3",
91 | "redux": "4.0.5",
92 | "regenerator-runtime": "^0.13.7",
93 | "sass-loader": "^8.0.0",
94 | "style-loader": "^1.2.1",
95 | "superagent": "^5.2.1",
96 | "uuid": "^3.3.3",
97 | "webpack": "^4.44.1",
98 | "webpack-cli": "^3.3.12"
99 | },
100 | "devDependencies": {
101 | "babel-eslint": "^10.1.0",
102 | "babel-jest": "^24.9.0",
103 | "enzyme": "^3.11.0",
104 | "enzyme-adapter-react-16": "^1.15.4",
105 | "enzyme-to-json": "^3.5.0",
106 | "eslint": "^6.8.0",
107 | "eslint-config-airbnb": "^18.2.0",
108 | "eslint-plugin-babel": "^5.3.1",
109 | "eslint-plugin-import": "^2.22.0",
110 | "eslint-plugin-jsx-a11y": "^6.3.1",
111 | "eslint-plugin-react": "^7.20.6",
112 | "eslint-plugin-react-hooks": "^2.3.0",
113 | "eventsource-polyfill": "^0.9.6",
114 | "jest": "^24.9.0",
115 | "jest-transform-graphql": "^2.1.0",
116 | "nock": "^11.7.2",
117 | "react-test-renderer": "^16.13.1",
118 | "wait-for-expect": "^3.0.2",
119 | "webpack-dev-server": "^3.10.1"
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable global-require */
2 | module.exports = {
3 | plugins: [
4 | require('postcss-import'),
5 | require('postcss-flexbugs-fixes'),
6 | require('postcss-preset-env')({
7 | autoprefixer: {
8 | flexbox: 'no-2009'
9 | },
10 | stage: 3
11 | })
12 | ]
13 | };
14 |
--------------------------------------------------------------------------------
/public/401.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Access denied (401)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
You don't have permission to access the requested page.
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/android-icon-144x144.png
--------------------------------------------------------------------------------
/public/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/android-icon-192x192.png
--------------------------------------------------------------------------------
/public/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/android-icon-36x36.png
--------------------------------------------------------------------------------
/public/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/android-icon-48x48.png
--------------------------------------------------------------------------------
/public/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/android-icon-72x72.png
--------------------------------------------------------------------------------
/public/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/android-icon-96x96.png
--------------------------------------------------------------------------------
/public/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-114x114.png
--------------------------------------------------------------------------------
/public/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-120x120.png
--------------------------------------------------------------------------------
/public/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-144x144.png
--------------------------------------------------------------------------------
/public/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-152x152.png
--------------------------------------------------------------------------------
/public/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-180x180.png
--------------------------------------------------------------------------------
/public/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-57x57.png
--------------------------------------------------------------------------------
/public/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-60x60.png
--------------------------------------------------------------------------------
/public/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-72x72.png
--------------------------------------------------------------------------------
/public/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-76x76.png
--------------------------------------------------------------------------------
/public/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/apple-icon.png
--------------------------------------------------------------------------------
/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/favicon-96x96.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/logo.png
--------------------------------------------------------------------------------
/public/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/ms-icon-144x144.png
--------------------------------------------------------------------------------
/public/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/ms-icon-150x150.png
--------------------------------------------------------------------------------
/public/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/ms-icon-310x310.png
--------------------------------------------------------------------------------
/public/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/ms-icon-70x70.png
--------------------------------------------------------------------------------
/public/oauth_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/public/oauth_icon.png
--------------------------------------------------------------------------------
/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/controllers/api/jwts_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe Api::JwtsController, type: :controller do
4 | before do
5 | @user = FactoryBot.create(:user)
6 | @user.confirm
7 | @user_token = AuthToken.issue_token({ user_id: @user.id })
8 | end
9 |
10 | context "as user" do
11 | describe "GET show" do
12 | it "should not be authorized" do
13 | get :show, params: { id: @user.id }, format: :json
14 | expect(response).to have_http_status(:unauthorized)
15 | end
16 | it "should get a new jwt" do
17 | request.headers["Authorization"] = @user_token
18 | get :show, params: { id: @user.id }, format: :json
19 | expect(response).to have_http_status(:success)
20 | result = JSON.parse(response.body)
21 | expect(result["jwt"]).to be_present
22 | end
23 | end
24 | end
25 |
26 | describe "includes JwtToken" do
27 | it { expect(Api::JwtsController.ancestors.include?(Concerns::JwtToken)).to eq(true) }
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/spec/controllers/concerns/jwt_token_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe ApplicationController, type: :controller do
4 | controller do
5 | include Concerns::JwtToken
6 |
7 | before_action :validate_token
8 | respond_to :json
9 |
10 | def index
11 | render plain: "User: #{@user.display_name}"
12 | end
13 | end
14 |
15 | context "no authorization header" do
16 | it "should not be authorized" do
17 | get :index, format: :json
18 | expect(response).to have_http_status(:unauthorized)
19 | end
20 | end
21 |
22 | context "invalid authorization header" do
23 | it "should not be authorized" do
24 | request.headers["Authorization"] = "A fake header"
25 | get :index, format: :json
26 | expect(response).to have_http_status(:unauthorized)
27 | end
28 | end
29 |
30 | context "valid authorization header" do
31 | it "should be authorized" do
32 | user = FactoryBot.create(:user)
33 | user.confirm
34 | user_token = AuthToken.issue_token({ user_id: user.id })
35 | request.headers["Authorization"] = user_token
36 | get :index, format: :json
37 | expect(response).to have_http_status(:success)
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/spec/controllers/concerns/paging_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe ApplicationController, type: :controller do
4 | controller do
5 | include Concerns::Paging
6 |
7 | respond_to :json
8 |
9 | def index
10 | render plain: "Page: #{@page} Per Page: #{@per_page}"
11 | end
12 | end
13 |
14 | describe "paging" do
15 | it "should add paging to controller" do
16 | page = 1
17 | per_page = 1
18 | get :index, format: :json
19 | expect(response).to have_http_status(:success)
20 | expect(response.body).to eq("Page: #{page} Per Page: #{per_page}")
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/controllers/home_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe HomeController, type: :controller do
4 | describe "GET index" do
5 | it "loads the home page" do
6 | get :index
7 | expect(response).to have_http_status(200)
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/spec/factories/_common.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | sequence :domain do |n|
3 | "www.example#{n}.com"
4 | end
5 |
6 | sequence :code do |n|
7 | "code#{n}"
8 | end
9 |
10 | sequence :name do |n|
11 | "user_#{n}"
12 | end
13 |
14 | sequence :email do |n|
15 | "user_#{n}@example.com"
16 | end
17 |
18 | sequence :password do |n|
19 | "password_#{n}"
20 | end
21 |
22 | sequence :title do |n|
23 | "a_title#{n}"
24 | end
25 |
26 | sequence :abbr do |n|
27 | "a#{n}"
28 | end
29 |
30 | sequence :uri do |n|
31 | "n#{n}.example.com"
32 | end
33 |
34 | sequence :description do |n|
35 | "This is the description: #{n}"
36 | end
37 |
38 | sequence :locale do |n|
39 | "a#{n}"
40 | end
41 |
42 | sequence :address do |n|
43 | "#{n} West #{n} South"
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/spec/factories/authentication.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :authentication do
3 | user
4 | provider { FactoryBot.generate(:name) }
5 | token { FactoryBot.generate(:name) }
6 | secret { FactoryBot.generate(:password) }
7 | provider_url { FactoryBot.generate(:uri) }
8 |
9 | factory :authentication_facebook do
10 | provider { "facebook" }
11 | uid { "12345" }
12 | username { "myusername" }
13 | provider_avatar { "http://graph.facebook.com/12345/picture?type=large" }
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/spec/factories/permission.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :permission do
3 | user
4 | role
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/factories/role.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :role do
3 | name { FactoryBot.generate(:name) }
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/factories/users.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :user do
3 | name { FactoryBot.generate(:name) }
4 | email { FactoryBot.generate(:email) }
5 | password { FactoryBot.generate(:password) }
6 | after(:build, &:confirm)
7 |
8 | factory :user_facebook do
9 | active_avatar { "facebook" }
10 | provider_avatar { "http://graph.facebook.com/12345/picture?type=large" }
11 | after(:build) do |user|
12 | FakeWeb.register_uri(:get, user.provider_avatar, body: File.join(Rails.root, "spec", "fixtures", "avatar.jpg"))
13 | end
14 | end
15 |
16 | factory :user_with_avatar do
17 | avatar { File.open File.join(Rails.root, "spec", "fixtures", "avatar.jpg") }
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/spec/fixtures/avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/spec/fixtures/avatar.jpg
--------------------------------------------------------------------------------
/spec/helpers/application_helper_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe ApplicationHelper do
4 | describe "application_base_url" do
5 | it "adds a trailing / onto the request's base url" do
6 | expect(helper.application_base_url).to be
7 | end
8 | end
9 |
10 | describe "jwt_token" do
11 | it "generates a new jwt token" do
12 | expect(helper).to receive("signed_in?").and_return(true)
13 | expect(helper).to receive(:current_user).and_return(double(id: 1))
14 | result = helper.jwt_token
15 | expect(result).to be
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/lib/auth_token_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe AuthToken do
4 | before do
5 | @user = FactoryBot.create(:user)
6 | end
7 |
8 | it "issues a valid jwt for the user id" do
9 | token = AuthToken.issue_token({ user_id: @user.id })
10 | decoded = AuthToken.valid?(token)
11 | decoded_token = decoded[0]
12 | expect(decoded_token["user_id"]).to eq @user.id
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/lib/url_helper_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 | require "url_helper"
3 |
4 | describe UrlHelper do
5 | describe "#ensure_scheme" do
6 | it "should add http onto url if it doesn't exist" do
7 | expect(UrlHelper.ensure_scheme("www.example.com")).to eq("http://www.example.com")
8 | end
9 | it "should not add http onto url if it does exist" do
10 | expect(UrlHelper.ensure_scheme("https://www.example.com")).to eq("https://www.example.com")
11 | end
12 | end
13 |
14 | describe "#host" do
15 | it "should get the host name from the url" do
16 | expect(UrlHelper.host("http://www.example.com")).to eq("www.example.com")
17 | expect(UrlHelper.host("http://www.example.com/some/path")).to eq("www.example.com")
18 | expect(UrlHelper.host("http://www.example.com?some=thing")).to eq("www.example.com")
19 | expect(UrlHelper.host("www.example.com")).to eq("www.example.com")
20 | expect(UrlHelper.host("www.example.com/some/path")).to eq("www.example.com")
21 | expect(UrlHelper.host("www.example.com?some=thing")).to eq("www.example.com")
22 | end
23 | it "should get the host with subdomain from the url" do
24 | expect(UrlHelper.host("http://foo.example.com")).to eq("foo.example.com")
25 | expect(UrlHelper.host("http://foo.example.com/some/path")).to eq("foo.example.com")
26 | expect(UrlHelper.host("http://foo.example.com?some=thing")).to eq("foo.example.com")
27 | expect(UrlHelper.host("foo.example.com")).to eq("foo.example.com")
28 | expect(UrlHelper.host("foo.example.com/some/path")).to eq("foo.example.com")
29 | expect(UrlHelper.host("foo.example.com?some=thing")).to eq("foo.example.com")
30 | end
31 | end
32 |
33 | describe "#scheme_host" do
34 | it "should return the scheme and host" do
35 | expect(UrlHelper.scheme_host("https://www.example.com")).to eq("https://www.example.com")
36 | expect(UrlHelper.scheme_host("https://www.example.com/some/path")).to eq("https://www.example.com")
37 | expect(UrlHelper.scheme_host("https://www.example.com?some=thing")).to eq("https://www.example.com")
38 | expect(UrlHelper.scheme_host("http://www.example.com")).to eq("http://www.example.com")
39 | expect(UrlHelper.scheme_host("http://www.example.com/some/path")).to eq("http://www.example.com")
40 | expect(UrlHelper.scheme_host("http://www.example.com?some=thing")).to eq("http://www.example.com")
41 | expect(UrlHelper.scheme_host("www.example.com")).to eq("http://www.example.com")
42 | expect(UrlHelper.scheme_host("www.example.com/some/path")).to eq("http://www.example.com")
43 | expect(UrlHelper.scheme_host("www.example.com?some=thing")).to eq("http://www.example.com")
44 | end
45 | it "should return the scheme and host with subdomain" do
46 | expect(UrlHelper.scheme_host("https://foo.example.com")).to eq("https://foo.example.com")
47 | expect(UrlHelper.scheme_host("https://foo.example.com/some/path")).to eq("https://foo.example.com")
48 | expect(UrlHelper.scheme_host("https://foo.example.com?some=thing")).to eq("https://foo.example.com")
49 | expect(UrlHelper.scheme_host("http://foo.example.com")).to eq("http://foo.example.com")
50 | expect(UrlHelper.scheme_host("http://foo.example.com/some/path")).to eq("http://foo.example.com")
51 | expect(UrlHelper.scheme_host("http://foo.example.com?some=thing")).to eq("http://foo.example.com")
52 | expect(UrlHelper.scheme_host("foo.example.com")).to eq("http://foo.example.com")
53 | expect(UrlHelper.scheme_host("foo.example.com/some/path")).to eq("http://foo.example.com")
54 | expect(UrlHelper.scheme_host("foo.example.com?some=thing")).to eq("http://foo.example.com")
55 | end
56 | end
57 |
58 | describe "#host_from_instance_guid" do
59 | it "should get the base domain" do
60 | expect(UrlHelper.host_from_instance_guid("http://www.example.com")).to eq("example.com")
61 | expect(UrlHelper.host_from_instance_guid("http://foo.example.com")).to eq("example.com")
62 | end
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/spec/models/authentication_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe Authentication, type: :model do
4 | before do
5 | @user = FactoryBot.create(:user)
6 | end
7 |
8 | it { should belong_to :user }
9 |
10 | it "Requires the provider" do
11 | authentication = FactoryBot.build(:authentication, provider: nil)
12 | expect(authentication.save).to eq(false)
13 | end
14 |
15 | describe "valid?" do
16 | it "is true when provider is unique" do
17 | provider = "asdf1234"
18 | authentication = create(:authentication, provider: provider)
19 | expect(authentication.valid?).to be true
20 | end
21 |
22 | it "is false for duplicate provider" do
23 | provider = "asdf1234"
24 | uid = "1234aoeu"
25 | provider_url = "example.com"
26 | create(
27 | :authentication,
28 | provider: provider,
29 | uid: uid,
30 | user: @user,
31 | provider_url: provider_url,
32 | )
33 | authentication = build(
34 | :authentication,
35 | provider: provider,
36 | uid: uid,
37 | user: @user,
38 | provider_url: provider_url,
39 | )
40 | expect(authentication.valid?(provider)).to be false
41 | end
42 |
43 | it "is false when provider is missing" do
44 | provider = nil
45 | authentication = build(:authentication, provider: provider)
46 | expect(authentication.valid?).to be false
47 | end
48 | end
49 |
50 | describe "for_auth" do
51 | it "finds an authentication given an auth object from omniauth" do
52 | auth = get_canvas_auth
53 | attributes = Authentication.authentication_attrs_from_auth(auth).merge(user_id: @user.id)
54 | Authentication.create!(attributes)
55 | authentication = Authentication.for_auth(auth)
56 | expect(authentication.provider_url).to eq auth["info"]["url"]
57 | end
58 | it "finds the correct authentication object when UIDs are duplicated" do
59 | canvas1 = {
60 | "uid" => "123",
61 | "info" => {
62 | "url" => "https://atomicjolt.instructure.com",
63 | },
64 | }
65 | canvas2 = {
66 | "uid" => "123",
67 | "info" => {
68 | "url" => "https://canvas.instructure.com",
69 | },
70 | }
71 | auth1 = get_canvas_auth(canvas1)
72 | auth2 = get_canvas_auth(canvas2)
73 |
74 | attributes1 = Authentication.authentication_attrs_from_auth(auth1)
75 | @user.authentications.create!(attributes1)
76 |
77 | attributes2 = Authentication.authentication_attrs_from_auth(auth2)
78 | @user.authentications.create!(attributes2)
79 |
80 | authentication1 = Authentication.for_auth(auth1)
81 | authentication2 = Authentication.for_auth(auth2)
82 |
83 | expect(authentication1.id).to_not eq(authentication2.id)
84 | expect(authentication1.uid).to eq(canvas1["uid"])
85 | expect(authentication2.uid).to eq(canvas1["uid"])
86 |
87 | expect(authentication1.provider_url).to eq(canvas1["info"]["url"])
88 | expect(authentication2.provider_url).to eq(canvas2["info"]["url"])
89 | end
90 | end
91 |
92 | describe "authentication_attrs_from_auth" do
93 | it "generates authentication attributes from an omniauth auth object" do
94 | auth = get_canvas_auth
95 | attributes = Authentication.authentication_attrs_from_auth(auth)
96 | expect(attributes[:uid]).to eq auth["uid"].to_s
97 | expect(attributes[:username]).to eq auth["info"]["nickname"]
98 | expect(attributes[:provider]).to eq auth["provider"]
99 | expect(attributes[:provider_url]).to eq auth["info"]["url"]
100 | end
101 | end
102 | end
103 |
--------------------------------------------------------------------------------
/spec/models/permission_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe Permission, type: :model do
4 | it "should find matching permissions with or without context" do
5 | context_id = "1234"
6 | permission = create(:permission)
7 | permission1 = create(:permission, context_id: context_id)
8 | permission2 = create(:permission, context_id: "asdf1234")
9 | permissions = Permission.by_nil_or_context(context_id)
10 | expect(permissions.include?(permission)).to be true
11 | expect(permissions.include?(permission1)).to be true
12 | expect(permissions.include?(permission2)).to be false
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/models/role_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe Role, type: :model do
4 | it "should order by name" do
5 | role1 = create(:role, name: "student")
6 | role2 = create(:role, name: "admin")
7 | role3 = create(:role, name: "teacher")
8 | roles = Role.by_alpha
9 | expect(roles.first).to eq(role2)
10 | expect(roles.second).to eq(role1)
11 | expect(roles.third).to eq(role3)
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # This file is copied to spec/ when you run 'rails generate rspec:install'
2 | ENV["RAILS_ENV"] ||= "test"
3 |
4 | require "spec_helper"
5 | require File.expand_path("../../config/environment", __FILE__)
6 | require "rspec/rails"
7 | require "capybara/rails"
8 | require "database_cleaner"
9 | require "shoulda/matchers"
10 | require "webmock/rspec"
11 |
12 | # Requires supporting ruby files with custom matchers and macros, etc, in
13 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
14 | # run as spec files by default. This means that files in spec/support that end
15 | # in _spec.rb will both be required and run as specs, causing the specs to be
16 | # run twice. It is recommended that you do not name files matching this glob to
17 | # end with _spec.rb. You can configure this pattern with with the --pattern
18 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
19 | Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
20 |
21 | # Checks for pending migrations before tests are run.
22 | # If you are not using ActiveRecord, you can remove this line.
23 | ActiveRecord::Migration.maintain_test_schema!
24 |
25 | RSpec.configure do |config|
26 | config.include FactoryBot::Syntax::Methods
27 | config.include Devise::Test::ControllerHelpers, type: :controller
28 | config.extend ControllerMacros, type: :controller
29 |
30 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
31 | config.fixture_path = "#{::Rails.root}/spec/fixtures"
32 |
33 | # If you're not using ActiveRecord, or you'd prefer not to run each of your
34 | # examples within a transaction, remove the following line or assign false
35 | # instead of true.
36 | config.use_transactional_fixtures = true
37 |
38 | # RSpec Rails can automatically mix in different behaviours to your tests
39 | # based on their file location, for example enabling you to call `get` and
40 | # `post` in specs under `spec/controllers`.
41 | #
42 | # You can disable this behaviour by removing the line below, and instead
43 | # explicitly tag your specs with their type, e.g.:
44 | #
45 | # RSpec.describe UsersController, :type => :controller do
46 | # # ...
47 | # end
48 | #
49 | # The different available types are documented in the features, such as in
50 | # https://relishapp.com/rspec/rspec-rails/docs
51 | config.infer_spec_type_from_file_location!
52 |
53 | config.before(:suite) do
54 | begin
55 | DatabaseCleaner.strategy = :transaction
56 | DatabaseCleaner.clean_with(:truncation)
57 | DatabaseCleaner.start
58 | # FactoryBot.lint
59 | ensure
60 | DatabaseCleaner.clean
61 | end
62 |
63 | # compile js once before tests run
64 | Webpacker.compile
65 | end
66 |
67 | config.append_after(:each) do
68 | DatabaseCleaner.clean
69 | end
70 |
71 | config.before(:each) do
72 | DatabaseCleaner.start
73 | end
74 | end
75 |
76 | Shoulda::Matchers.configure do |config|
77 | config.integrate do |with|
78 | with.test_framework :rspec
79 | with.library :rails
80 | end
81 | end
82 |
83 | Devise.setup do |config|
84 | config.omniauth :facebook, "1234", "1234", scope: "user"
85 | end
86 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all
2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3 | # The generated `.rspec` file contains `--require spec_helper` which will cause this
4 | # file to always be loaded, without a need to explicitly require it in any files.
5 | #
6 | # Given that it is always loaded, you are encouraged to keep this file as
7 | # light-weight as possible. Requiring heavyweight dependencies from this file
8 | # will add to the boot time of your test suite on EVERY test run, even for an
9 | # individual file that may not need all of that loaded. Instead, make a
10 | # separate helper file that requires this one and then use it only in the specs
11 | # that actually need it.
12 | #
13 | # The `.rspec` file also contains a few flags that are not defaults but that
14 | # users commonly want.
15 | #
16 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17 |
18 | RSpec.configure do |config|
19 | # The settings below are suggested to provide a good initial experience
20 | # with RSpec, but feel free to customize to your heart's content.
21 | begin
22 | # These two settings work together to allow you to limit a spec run
23 | # to individual examples or groups you care about by tagging them with
24 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples
25 | # get run.
26 | config.filter_run :focus
27 | config.run_all_when_everything_filtered = true
28 |
29 | # Many RSpec users commonly either run the entire suite or an individual
30 | # file, and it's useful to allow more verbose output when running an
31 | # individual spec file.
32 | if config.files_to_run.one?
33 | # Use the documentation formatter for detailed output,
34 | # unless a formatter has already been configured
35 | # (e.g. via a command-line flag).
36 | config.default_formatter = 'doc'
37 | end
38 |
39 | # Print the 10 slowest examples and example groups at the
40 | # end of the spec run, to help surface which specs are running
41 | # particularly slow.
42 | config.profile_examples = 10
43 |
44 | # Run specs in random order to surface order dependencies. If you find an
45 | # order dependency and want to debug it, you can fix the order by providing
46 | # the seed, which is printed after each run.
47 | # --seed 1234
48 | config.order = :random
49 |
50 | # Seed global randomization in this process using the `--seed` CLI option.
51 | # Setting this allows you to use `--seed` to deterministically reproduce
52 | # test failures related to randomization by passing the same `--seed` value
53 | # as the one that triggered the failure.
54 | Kernel.srand config.seed
55 |
56 | # rspec-expectations config goes here. You can use an alternate
57 | # assertion/expectation library such as wrong or the stdlib/minitest
58 | # assertions if you prefer.
59 | config.expect_with :rspec do |expectations|
60 | # Enable only the newer, non-monkey-patching expect syntax.
61 | # For more details, see:
62 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
63 | expectations.syntax = :expect
64 | end
65 |
66 | # rspec-mocks config goes here. You can use an alternate test double
67 | # library (such as bogus or mocha) by changing the `mock_with` option here.
68 | config.mock_with :rspec do |mocks|
69 | # Enable only the newer, non-monkey-patching expect syntax.
70 | # For more details, see:
71 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
72 | mocks.syntax = :expect
73 |
74 | # Prevents you from mocking or stubbing a method that does not exist on
75 | # a real object. This is generally recommended.
76 | mocks.verify_partial_doubles = true
77 | end
78 |
79 | end
80 | end
81 |
--------------------------------------------------------------------------------
/spec/support/capybara.rb:
--------------------------------------------------------------------------------
1 | Capybara.asset_host = "http://localhost:3000"
2 |
--------------------------------------------------------------------------------
/spec/support/controller_macros.rb:
--------------------------------------------------------------------------------
1 | module ControllerMacros
2 | def login_admin
3 | before(:each) do
4 | @request.env["devise.mapping"] = Devise.mappings[:admin]
5 | @admin ||= CreateAdminService.create_admin
6 | sign_in @admin
7 | end
8 | end
9 |
10 | def login_user
11 | before(:each) do
12 | @request.env["devise.mapping"] = Devise.mappings[:user]
13 | @user ||= FactoryBot.create(:user)
14 | @user.confirm # or set a confirmed_at inside the factory. Only necessary if you are using the "confirmable" module
15 | sign_in @user
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/support/http_party.rb:
--------------------------------------------------------------------------------
1 | def http_party_get_response(code = 200, code_response = "OK", body = "{foo:'bar'}")
2 | request_object = HTTParty::Request.new Net::HTTP::Get, "/"
3 | http_party_response(code, code_response, body, request_object)
4 | end
5 |
6 | def http_party_post_response(code = 200, code_response = "OK", body = "{foo:'bar'}")
7 | request_object = HTTParty::Request.new Net::HTTP::Post, "/"
8 | http_party_response(code, code_response, body, request_object)
9 | end
10 |
11 | def http_party_put_response(code = 200, code_response = "OK", body = "{foo:'bar'}")
12 | request_object = HTTParty::Request.new Net::HTTP::Put, "/"
13 | http_party_response(code, code_response, body, request_object)
14 | end
15 |
16 | def http_party_response(code, code_response, body, request_object)
17 | last_modified = Date.new(2010, 1, 15).to_s
18 | content_length = "1024"
19 | response_object = Net::HTTPOK.new("1.1", code.to_s, code_response)
20 | allow(response_object).to receive_messages(body: body)
21 | response_object["last-modified"] = last_modified
22 | response_object["content-length"] = content_length
23 | parsed_response = lambda { { "foo" => "bar" } }
24 | HTTParty::Response.new(request_object, response_object, parsed_response)
25 | end
26 |
--------------------------------------------------------------------------------
/spec/support/webmock_requests.rb:
--------------------------------------------------------------------------------
1 | require "webmock/rspec"
2 |
3 | # Don't allow real connections when testing
4 | WebMock.disable_net_connect!(allow_localhost: true)
5 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomicjolt/react_rails_starter_app/3420640523b9d503054196f649fbe93461273b35/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------