potassium 6.0.0 → 6.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +103 -38
- data/.circleci/setup-rubygems.sh +3 -0
- data/.gitignore +2 -1
- data/.rubocop.yml +530 -0
- data/CHANGELOG.md +57 -0
- data/README.md +51 -45
- data/lib/potassium/assets/.circleci/config.yml.erb +83 -34
- data/lib/potassium/assets/.eslintrc.json +13 -4
- data/lib/potassium/assets/.github/pull_request_template.md +9 -0
- data/lib/potassium/assets/.rubocop.yml +13 -0
- data/lib/potassium/assets/README.yml +7 -7
- data/lib/potassium/assets/app/graphql/graphql_controller.rb +55 -0
- data/lib/potassium/assets/app/graphql/mutations/login_mutation.rb +23 -0
- data/lib/potassium/assets/app/graphql/queries/base_query.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/base/base_argument.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/base/base_enum.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/base/base_field.rb +5 -0
- data/lib/potassium/assets/app/graphql/types/base/base_input_object.rb +5 -0
- data/lib/potassium/assets/app/graphql/types/base/base_interface.rb +7 -0
- data/lib/potassium/assets/app/graphql/types/base/base_object.rb +5 -0
- data/lib/potassium/assets/app/graphql/types/base/base_scalar.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/base/base_union.rb +4 -0
- data/lib/potassium/assets/app/graphql/types/mutation_type.rb +10 -0
- data/lib/potassium/assets/app/graphql/types/query_type.rb +13 -0
- data/lib/potassium/assets/app/javascript/app.spec.js +1 -1
- data/lib/potassium/assets/app/uploaders/base_uploader.rb +1 -3
- data/lib/potassium/assets/app/views/shared/_gtm_body.html.erb +4 -0
- data/lib/potassium/assets/app/views/shared/_gtm_head.html.erb +7 -0
- data/lib/potassium/assets/config/graphql_playground.rb +20 -0
- data/lib/potassium/assets/config/puma.rb +1 -1
- data/lib/potassium/assets/config/shrine.rb +4 -1
- data/lib/potassium/assets/redis.yml +1 -2
- data/lib/potassium/assets/testing/rails_helper.rb +2 -0
- data/lib/potassium/cli/commands/create.rb +11 -19
- data/lib/potassium/cli_options.rb +70 -10
- data/lib/potassium/helpers/template-helpers.rb +4 -0
- data/lib/potassium/newest_version_ensurer.rb +19 -36
- data/lib/potassium/node_version_ensurer.rb +30 -0
- data/lib/potassium/recipes/admin.rb +26 -16
- data/lib/potassium/recipes/api.rb +92 -27
- data/lib/potassium/recipes/background_processor.rb +62 -18
- data/lib/potassium/recipes/ci.rb +9 -39
- data/lib/potassium/recipes/database.rb +4 -0
- data/lib/potassium/recipes/draper.rb +0 -9
- data/lib/potassium/recipes/file_storage.rb +2 -1
- data/lib/potassium/recipes/front_end.rb +84 -9
- data/lib/potassium/recipes/github.rb +93 -15
- data/lib/potassium/recipes/google_tag_manager.rb +94 -0
- data/lib/potassium/recipes/heroku.rb +42 -29
- data/lib/potassium/recipes/mailer.rb +18 -5
- data/lib/potassium/recipes/monitoring.rb +5 -0
- data/lib/potassium/recipes/schedule.rb +16 -1
- data/lib/potassium/recipes/style.rb +2 -2
- data/lib/potassium/templates/application.rb +5 -2
- data/lib/potassium/version.rb +5 -2
- data/potassium.gemspec +5 -2
- data/spec/features/api_spec.rb +25 -0
- data/spec/features/background_processor_spec.rb +19 -6
- data/spec/features/ci_spec.rb +7 -4
- data/spec/features/draper_spec.rb +1 -6
- data/spec/features/file_storage_spec.rb +5 -0
- data/spec/features/front_end_spec.rb +32 -1
- data/spec/features/github_spec.rb +53 -8
- data/spec/features/google_tag_manager_spec.rb +36 -0
- data/spec/features/graphql_spec.rb +71 -0
- data/spec/features/mailer_spec.rb +16 -0
- data/spec/features/schedule_spec.rb +11 -4
- data/spec/spec_helper.rb +1 -0
- data/spec/support/fake_octokit.rb +31 -0
- data/spec/support/potassium_test_helpers.rb +0 -1
- data/tmp/.keep +0 -0
- metadata +80 -15
- data/lib/potassium/assets/Dockerfile.ci +0 -6
- data/lib/potassium/assets/api/api_error_concern.rb +0 -32
- data/lib/potassium/assets/api/base_controller.rb +0 -7
- data/lib/potassium/assets/api/draper_responder.rb +0 -62
- data/lib/potassium/assets/api/responder.rb +0 -41
- data/lib/potassium/assets/bin/cibuild.erb +0 -117
- data/lib/potassium/assets/docker-compose.ci.yml +0 -12
- data/lib/potassium/assets/sidekiq_scheduler.yml +0 -9
@@ -0,0 +1,55 @@
|
|
1
|
+
class GraphqlController < ApplicationController
|
2
|
+
# If accessing from outside this domain, nullify the session
|
3
|
+
# This allows for outside API access while preventing CSRF attacks,
|
4
|
+
# but you'll have to authenticate your user separately
|
5
|
+
# protect_from_forgery with: :null_session
|
6
|
+
|
7
|
+
def execute
|
8
|
+
variables = prepare_variables(params[:variables])
|
9
|
+
query = params[:query]
|
10
|
+
operation_name = params[:operationName]
|
11
|
+
context = { current_user: get_current_user }
|
12
|
+
result = GqlSampleSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
|
13
|
+
render json: result
|
14
|
+
rescue => e
|
15
|
+
raise e unless Rails.env.development?
|
16
|
+
handle_error_in_development e
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Handle variables in form data, JSON body, or a blank value
|
22
|
+
def prepare_variables(variables_param)
|
23
|
+
case variables_param
|
24
|
+
when String
|
25
|
+
if variables_param.present?
|
26
|
+
JSON.parse(variables_param) || {}
|
27
|
+
else
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
when Hash
|
31
|
+
variables_param
|
32
|
+
when ActionController::Parameters
|
33
|
+
variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables.
|
34
|
+
when nil
|
35
|
+
{}
|
36
|
+
else
|
37
|
+
raise ArgumentError, "Unexpected parameter: #{variables_param}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_error_in_development(e)
|
42
|
+
logger.error e.message
|
43
|
+
logger.error e.backtrace.join("\n")
|
44
|
+
|
45
|
+
render json: { errors: [{ message: e.message, backtrace: e.backtrace }], data: {} }, status: 500
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_current_user
|
49
|
+
if request.headers['Authorization']
|
50
|
+
_, token = request.headers['Authorization'].split
|
51
|
+
decoded_token = JWT.decode token, ENV['HMAC_SECRET'], true, { algorithm: 'HS256' }
|
52
|
+
User.find(decoded_token.first["id"])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'jwt'
|
2
|
+
|
3
|
+
class Mutations::LoginMutation < Mutations::BaseMutation
|
4
|
+
null true
|
5
|
+
|
6
|
+
argument :email, String, required: true
|
7
|
+
argument :password, String, required: true
|
8
|
+
|
9
|
+
|
10
|
+
field :token, String, null: true
|
11
|
+
|
12
|
+
def resolve(email:, password:)
|
13
|
+
user = User.find_by(email: email)
|
14
|
+
if user&.valid_password?(password)
|
15
|
+
payload = { id: user.id, email: user.email, exp: (Time.zone.now + 24.hours).to_i }
|
16
|
+
token = JWT.encode payload, ENV['HMAC_SECRET'], 'HS256'
|
17
|
+
return { token: token }
|
18
|
+
end
|
19
|
+
GraphQL::ExecutionError.new("User or Password invalid")
|
20
|
+
rescue ActiveRecord::RecordInvalid => e
|
21
|
+
GraphQL::ExecutionError.new("Invalid input: #{e.record.errors.full_messages.join(', ')}")
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Types
|
2
|
+
class QueryType < Types::Base::BaseObject
|
3
|
+
# Add root-level fields here.
|
4
|
+
# They will be entry points for queries on your schema.
|
5
|
+
|
6
|
+
# TODO: remove me
|
7
|
+
field :test_field, String, null: false,
|
8
|
+
description: "An example field added by the generator"
|
9
|
+
def test_field
|
10
|
+
"Hello World!"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<!-- Google Tag Manager -->
|
2
|
+
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
3
|
+
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
4
|
+
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
5
|
+
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
6
|
+
})(window,document,'script','dataLayer','<%=ENV['GTM_CONTAINER_ID']%>');</script>
|
7
|
+
<!-- End Google Tag Manager -->
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# config/initializers/graphql_playground.rb
|
2
|
+
# All config options have a default that should work out of the box
|
3
|
+
if Rails.env.development?
|
4
|
+
GraphqlPlayground::Rails.configure do |config|
|
5
|
+
# config.headers = {
|
6
|
+
# 'X-Auth-Header' => ->(view_context) { "123" }
|
7
|
+
# }
|
8
|
+
# config.title = "Playground"
|
9
|
+
# config.csrf = true
|
10
|
+
# config.playground_version = "latest"
|
11
|
+
# # Ideally the assets would be added to your projects `vendor/assets` directories
|
12
|
+
# config.favicon = "/assets/playground.ico"
|
13
|
+
# config.playground_js_url = "/assets/playground.js"
|
14
|
+
# config.playground_css_url = "/assets/playground.css"
|
15
|
+
# # see: https://github.com/prisma-labs/graphql-playground#settings
|
16
|
+
config.settings = {
|
17
|
+
"schema.polling.enable": false
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
@@ -24,7 +24,7 @@ rack_env = ENV.fetch("RACK_ENV", "development")
|
|
24
24
|
environment rack_env
|
25
25
|
|
26
26
|
# Set 1 day timeout for workers while developing
|
27
|
-
worker_timeout
|
27
|
+
worker_timeout 24 * 60 * 60 if rack_env == "development"
|
28
28
|
|
29
29
|
on_worker_boot do
|
30
30
|
# Worker specific setup for Rails 4.1+
|
@@ -24,7 +24,10 @@ elsif Rails.env.production?
|
|
24
24
|
else
|
25
25
|
require 'shrine/storage/memory'
|
26
26
|
|
27
|
-
Shrine.storages
|
27
|
+
Shrine.storages = {
|
28
|
+
cache: Shrine::Storage::Memory.new,
|
29
|
+
store: Shrine::Storage::Memory.new
|
30
|
+
}
|
28
31
|
end
|
29
32
|
|
30
33
|
Shrine.plugin :activerecord
|
@@ -26,6 +26,8 @@ Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
|
|
26
26
|
# If you are not using ActiveRecord, you can remove this line.
|
27
27
|
ActiveRecord::Migration.maintain_test_schema!
|
28
28
|
|
29
|
+
PowerTypes::Observable.observable_disabled = true
|
30
|
+
|
29
31
|
RSpec.configure do |config|
|
30
32
|
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
31
33
|
# examples within a transaction, remove the following line or assign false
|
@@ -3,37 +3,29 @@ require 'potassium/cli_options'
|
|
3
3
|
module Potassium::CLI
|
4
4
|
extend Potassium::CliOptions
|
5
5
|
|
6
|
-
desc
|
6
|
+
desc 'Create a new Potassium Rails project.'
|
7
7
|
arg 'app_path'
|
8
8
|
command :create do |c|
|
9
|
-
c.default_desc
|
10
|
-
c.switch "version-check",
|
11
|
-
default_value: true,
|
12
|
-
desc: "Performs a version check before running.",
|
13
|
-
negatable: true
|
14
|
-
|
9
|
+
c.default_desc 'Create a new project.'
|
15
10
|
create_options.each { |opts| c.send(opts.delete(:type), opts.delete(:name), opts) }
|
16
11
|
|
17
12
|
c.action do |_global_options, options, _args|
|
18
|
-
require
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
require "potassium/template_finder"
|
13
|
+
require 'potassium/newest_version_ensurer'
|
14
|
+
require 'potassium/node_version_ensurer'
|
15
|
+
require 'potassium/generators/application'
|
16
|
+
require 'potassium/template_finder'
|
23
17
|
|
18
|
+
begin
|
19
|
+
Potassium::NewestVersionEnsurer.new.ensure! if options['version-check']
|
20
|
+
Potassium::NodeVersionEnsurer.new.ensure! if options['node-version-check']
|
24
21
|
template_finder = Potassium::TemplateFinder.new
|
25
22
|
template = template_finder.default_template
|
26
23
|
template.cli_options = options
|
27
24
|
template.source_paths << Rails::Generators::AppGenerator.source_root
|
28
25
|
ARGV.push('--skip-webpack-install', '--skip-bundle')
|
29
26
|
template.start
|
30
|
-
|
31
|
-
|
32
|
-
if options["version-check"]
|
33
|
-
ensurer = Potassium::NewestVersionEnsurer.new
|
34
|
-
ensurer.ensure(&begin_creation)
|
35
|
-
else
|
36
|
-
begin_creation.call
|
27
|
+
rescue VersionError => e
|
28
|
+
print "\nError: #{e.message}" # rubocop:disable Rails/Output
|
37
29
|
end
|
38
30
|
end
|
39
31
|
end
|
@@ -1,5 +1,21 @@
|
|
1
1
|
module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
2
2
|
CREATE_OPTIONS = [
|
3
|
+
{
|
4
|
+
type: :switch,
|
5
|
+
name: 'version-check',
|
6
|
+
desc: 'Performs a version check before running.',
|
7
|
+
negatable: true,
|
8
|
+
default_value: true,
|
9
|
+
default_test_value: true
|
10
|
+
},
|
11
|
+
{
|
12
|
+
type: :switch,
|
13
|
+
name: 'node-version-check',
|
14
|
+
desc: 'Performs a node version check before running.',
|
15
|
+
negatable: true,
|
16
|
+
default_value: true,
|
17
|
+
default_test_value: true
|
18
|
+
},
|
3
19
|
{
|
4
20
|
type: :flag,
|
5
21
|
name: [:db, :database],
|
@@ -59,12 +75,11 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
59
75
|
default_test_value: false
|
60
76
|
},
|
61
77
|
{
|
62
|
-
type: :
|
78
|
+
type: :flag,
|
63
79
|
name: "api",
|
64
|
-
desc: "
|
65
|
-
negatable: true,
|
80
|
+
desc: "Which API interface to use",
|
66
81
|
default_value: "none",
|
67
|
-
default_test_value:
|
82
|
+
default_test_value: "None"
|
68
83
|
},
|
69
84
|
{
|
70
85
|
type: :flag,
|
@@ -82,10 +97,10 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
82
97
|
default_test_value: false
|
83
98
|
},
|
84
99
|
{
|
85
|
-
type: :
|
100
|
+
type: :switch,
|
86
101
|
name: "background_processor",
|
87
|
-
desc: "
|
88
|
-
default_test_value:
|
102
|
+
desc: "Whether to use Sidekiq for background processing or not",
|
103
|
+
default_test_value: false
|
89
104
|
},
|
90
105
|
{
|
91
106
|
type: :switch,
|
@@ -105,12 +120,41 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
105
120
|
},
|
106
121
|
{
|
107
122
|
type: :switch,
|
108
|
-
name: "
|
109
|
-
desc: "Whether
|
123
|
+
name: "github_private",
|
124
|
+
desc: "Whether the github repository is private or not",
|
110
125
|
negatable: true,
|
111
|
-
default_value:
|
126
|
+
default_value: "none",
|
112
127
|
default_test_value: false
|
113
128
|
},
|
129
|
+
{
|
130
|
+
type: :switch,
|
131
|
+
name: "github_has_org",
|
132
|
+
desc: "Whether the github repository should belong to an organization",
|
133
|
+
negatable: true,
|
134
|
+
default_value: "none",
|
135
|
+
default_test_value: false
|
136
|
+
},
|
137
|
+
{
|
138
|
+
type: :flag,
|
139
|
+
name: "github_org",
|
140
|
+
desc: "The github organization where the repository will be created",
|
141
|
+
default_value: "none",
|
142
|
+
default_test_value: "none"
|
143
|
+
},
|
144
|
+
{
|
145
|
+
type: :flag,
|
146
|
+
name: "github_name",
|
147
|
+
desc: "The github repository name",
|
148
|
+
default_value: "none",
|
149
|
+
default_test_value: "none"
|
150
|
+
},
|
151
|
+
{
|
152
|
+
type: :flag,
|
153
|
+
name: "github_access_token",
|
154
|
+
desc: "Github personal access token used to auth to Github API",
|
155
|
+
default_value: "none",
|
156
|
+
default_test_value: "none"
|
157
|
+
},
|
114
158
|
{
|
115
159
|
type: :switch,
|
116
160
|
name: "schedule",
|
@@ -132,6 +176,22 @@ module Potassium::CliOptions # rubocop:disable Metrics/ModuleLength
|
|
132
176
|
name: :front_end,
|
133
177
|
desc: "Decides which front-end framework to use. Available: Vue, Angular 2, None",
|
134
178
|
default_test_value: "None"
|
179
|
+
},
|
180
|
+
{
|
181
|
+
type: :switch,
|
182
|
+
name: 'google_tag_manager',
|
183
|
+
desc: 'Whether to use google tag manager',
|
184
|
+
negatable: true,
|
185
|
+
default_value: 'none',
|
186
|
+
default_test_value: false
|
187
|
+
},
|
188
|
+
{
|
189
|
+
type: :switch,
|
190
|
+
name: "test",
|
191
|
+
desc: "Whether or not it is a test project creation",
|
192
|
+
negatable: true,
|
193
|
+
default_value: false,
|
194
|
+
default_test_value: true
|
135
195
|
}
|
136
196
|
]
|
137
197
|
|
@@ -7,6 +7,10 @@ module TemplateHelpers
|
|
7
7
|
"#{Potassium::NODE_VERSION}.x"
|
8
8
|
end
|
9
9
|
|
10
|
+
def ruby_version
|
11
|
+
Semantic::Version.new(Potassium::RUBY_VERSION).instance_eval { "#{major}.#{minor}" }
|
12
|
+
end
|
13
|
+
|
10
14
|
def load_recipe(recipe_name)
|
11
15
|
@recipes ||= {}
|
12
16
|
@recipes[recipe_name] ||= get_recipe_class(recipe_name.to_sym).new(self)
|