potassium 5.2.2 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +103 -28
- data/.circleci/setup-rubygems.sh +3 -0
- data/.gitignore +2 -1
- data/.node-version +1 -0
- data/.rubocop.yml +530 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +92 -1
- data/README.md +51 -45
- data/docs/DSL.md +5 -5
- data/lib/potassium/assets/.circleci/config.yml.erb +151 -0
- data/lib/potassium/assets/.eslintrc.json +352 -0
- data/lib/potassium/assets/.github/pull_request_template.md +9 -0
- data/lib/potassium/assets/.rubocop.yml +528 -0
- data/lib/potassium/assets/.stylelintrc.json +46 -0
- data/lib/potassium/assets/Makefile.erb +21 -32
- data/lib/potassium/assets/README.yml +59 -15
- data/lib/potassium/assets/active_admin/admin-component.vue +35 -0
- data/lib/potassium/assets/active_admin/admin_application.js +14 -0
- data/lib/potassium/assets/active_admin/init_activeadmin_vue.rb +10 -0
- 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 +14 -0
- data/lib/potassium/assets/app/uploaders/base_uploader.rb +11 -0
- data/lib/potassium/assets/app/uploaders/image_uploader.rb +5 -0
- 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/bin/release +1 -1
- data/lib/potassium/assets/bin/setup.erb +1 -1
- data/lib/potassium/assets/config/database_mysql.yml.erb +2 -2
- data/lib/potassium/assets/config/database_postgresql.yml.erb +2 -2
- 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 +36 -0
- data/lib/potassium/assets/lib/tasks/auto_annotate_models.rake +2 -1
- data/lib/potassium/assets/package.json +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 +12 -19
- data/lib/potassium/cli_options.rb +77 -26
- data/lib/potassium/helpers/gem-helpers.rb +1 -1
- data/lib/potassium/helpers/template-helpers.rb +8 -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 +3 -3
- data/lib/potassium/recipes/annotate.rb +1 -1
- data/lib/potassium/recipes/api.rb +93 -21
- data/lib/potassium/recipes/background_processor.rb +66 -19
- data/lib/potassium/recipes/ci.rb +10 -38
- data/lib/potassium/recipes/data_migrate.rb +44 -0
- data/lib/potassium/recipes/database.rb +4 -0
- data/lib/potassium/recipes/database_container.rb +7 -5
- data/lib/potassium/recipes/draper.rb +1 -10
- data/lib/potassium/recipes/file_storage.rb +66 -0
- data/lib/potassium/recipes/front_end.rb +225 -9
- data/lib/potassium/recipes/github.rb +93 -15
- data/lib/potassium/recipes/google_tag_manager.rb +90 -0
- data/lib/potassium/recipes/heroku.rb +42 -29
- data/lib/potassium/recipes/mailer.rb +18 -2
- data/lib/potassium/recipes/monitoring.rb +5 -0
- data/lib/potassium/recipes/node.rb +21 -0
- data/lib/potassium/recipes/rack_cors.rb +18 -15
- data/lib/potassium/recipes/schedule.rb +17 -2
- data/lib/potassium/recipes/style.rb +21 -3
- data/lib/potassium/recipes/vue_admin.rb +124 -0
- data/lib/potassium/templates/application.rb +10 -7
- data/lib/potassium/version.rb +7 -4
- data/potassium.gemspec +11 -6
- 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/data_migrate_spec.rb +14 -0
- data/spec/features/database_container_spec.rb +1 -5
- data/spec/features/draper_spec.rb +1 -6
- data/spec/features/file_storage_spec.rb +75 -0
- data/spec/features/front_end_spec.rb +102 -0
- data/spec/features/github_spec.rb +53 -8
- data/spec/features/google_tag_manager_spec.rb +59 -0
- data/spec/features/graphql_spec.rb +71 -0
- data/spec/features/heroku_spec.rb +1 -1
- data/spec/features/mailer_spec.rb +16 -0
- data/spec/features/new_project_spec.rb +6 -14
- data/spec/features/node_spec.rb +28 -0
- data/spec/features/power_types_spec.rb +5 -16
- data/spec/features/schedule_spec.rb +11 -4
- data/spec/features/vue_admin_spec.rb +47 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/fake_octokit.rb +31 -0
- data/spec/support/potassium_test_helpers.rb +26 -9
- data/tmp/.keep +0 -0
- metadata +152 -46
- data/lib/potassium/assets/.circleci/config.yml +0 -20
- data/lib/potassium/assets/Dockerfile.ci +0 -6
- data/lib/potassium/assets/active_admin/active_admin.js.coffee +0 -4
- data/lib/potassium/assets/active_admin/init_activeadmin_angular.rb +0 -8
- data/lib/potassium/assets/api/api_error_concern.rb +0 -32
- data/lib/potassium/assets/api/base_controller.rb +0 -9
- data/lib/potassium/assets/api/draper_responder.rb +0 -62
- data/lib/potassium/assets/api/responder.rb +0 -41
- data/lib/potassium/assets/aws.rb +0 -1
- data/lib/potassium/assets/bin/cibuild.erb +0 -100
- data/lib/potassium/assets/docker-compose.ci.yml +0 -11
- data/lib/potassium/assets/sidekiq_scheduler.yml +0 -9
- data/lib/potassium/assets/testing/paperclip.rb +0 -59
- data/lib/potassium/recipes/active_storage.rb +0 -40
- data/lib/potassium/recipes/angular_admin.rb +0 -56
- data/lib/potassium/recipes/aws_sdk.rb +0 -7
- data/lib/potassium/recipes/paperclip.rb +0 -47
- data/spec/features/active_storage_spec.rb +0 -30
- data/spec/features/front_end.rb +0 -30
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rules": {
|
|
3
|
+
"declaration-bang-space-before": "always",
|
|
4
|
+
"declaration-bang-space-after": "never",
|
|
5
|
+
"declaration-property-value-blacklist": {
|
|
6
|
+
"/^border/": ["none"]
|
|
7
|
+
},
|
|
8
|
+
"color-named": "never",
|
|
9
|
+
"declaration-block-no-duplicate-properties": true,
|
|
10
|
+
"rule-empty-line-before": ["always-multi-line", {
|
|
11
|
+
"except": ["after-single-line-comment", "first-nested"]
|
|
12
|
+
}],
|
|
13
|
+
"block-no-empty": true,
|
|
14
|
+
"no-missing-end-of-source-newline": true,
|
|
15
|
+
"color-hex-length": "short",
|
|
16
|
+
"color-hex-case": "lower",
|
|
17
|
+
"color-no-invalid-hex": true,
|
|
18
|
+
"selector-max-id": 0,
|
|
19
|
+
"declaration-no-important": true,
|
|
20
|
+
"indentation": 2,
|
|
21
|
+
"number-leading-zero": "never",
|
|
22
|
+
"no-duplicate-selectors": true,
|
|
23
|
+
"max-nesting-depth": 3,
|
|
24
|
+
"selector-pseudo-element-colon-notation": "double",
|
|
25
|
+
"selector-no-qualifying-type": true,
|
|
26
|
+
"shorthand-property-no-redundant-values": true,
|
|
27
|
+
"declaration-block-semicolon-newline-after": "always-multi-line",
|
|
28
|
+
"selector-list-comma-newline-after": "always",
|
|
29
|
+
"function-comma-space-after": "always-single-line",
|
|
30
|
+
"declaration-colon-space-after": "always",
|
|
31
|
+
"declaration-colon-space-before": "never",
|
|
32
|
+
"block-opening-brace-space-before": "always",
|
|
33
|
+
"function-parentheses-space-inside": "never",
|
|
34
|
+
"string-quotes": "single",
|
|
35
|
+
"declaration-block-trailing-semicolon": "always",
|
|
36
|
+
"no-eol-whitespace": true,
|
|
37
|
+
"number-no-trailing-zeros": true,
|
|
38
|
+
"function-url-quotes": "always",
|
|
39
|
+
"property-no-vendor-prefix": true,
|
|
40
|
+
"selector-no-vendor-prefix": true,
|
|
41
|
+
"media-feature-name-no-vendor-prefix": true,
|
|
42
|
+
"at-rule-no-vendor-prefix": true,
|
|
43
|
+
"value-no-vendor-prefix": true,
|
|
44
|
+
"length-zero-no-unit": true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
PROJECT ?= <%= get(:
|
|
2
|
-
DOCKER_COMPOSE_FILE ?= docker-compose.yml
|
|
3
|
-
|
|
4
|
-
DOCKER_COMPOSE_ARGS ?= -p $(PROJECT) -f $(DOCKER_COMPOSE_FILE)
|
|
1
|
+
PROJECT ?= <%= get(:dasherized_app_name) %>
|
|
5
2
|
|
|
6
3
|
SHELL := /bin/bash
|
|
7
4
|
|
|
@@ -11,36 +8,28 @@ BOLD ?= $(shell tput bold)
|
|
|
11
8
|
NORMAL ?= $(shell tput sgr0)
|
|
12
9
|
|
|
13
10
|
help:
|
|
14
|
-
@echo
|
|
15
|
-
@echo " ${BOLD}make
|
|
16
|
-
@echo ""
|
|
17
|
-
@echo Runing the services like mysql:
|
|
18
|
-
@echo " ${BOLD}make services-up${NORMAL}"
|
|
11
|
+
@echo "Generate a backup in the environment (staging|production) database:"
|
|
12
|
+
@echo " ${BOLD}make backup-<environment>${NORMAL}"
|
|
19
13
|
@echo ""
|
|
20
|
-
@echo "
|
|
21
|
-
@echo " ${BOLD}make
|
|
14
|
+
@echo "Copy latest database backup from the environment (staging|production) to local database:"
|
|
15
|
+
@echo " ${BOLD}make restore-from-<environment>${NORMAL}"
|
|
22
16
|
@echo ""
|
|
23
17
|
|
|
24
|
-
setup:
|
|
25
|
-
bin/setup
|
|
26
|
-
|
|
27
|
-
services: services-up
|
|
28
|
-
|
|
29
|
-
services-ps:
|
|
30
|
-
docker-compose $(DOCKER_COMPOSE_ARGS) ps
|
|
31
|
-
|
|
32
|
-
services-up:
|
|
33
|
-
docker-compose $(DOCKER_COMPOSE_ARGS) up -d
|
|
34
|
-
|
|
35
|
-
services-stop:
|
|
36
|
-
docker-compose $(DOCKER_COMPOSE_ARGS) stop
|
|
37
|
-
|
|
38
|
-
services-down:
|
|
39
|
-
docker-compose $(DOCKER_COMPOSE_ARGS) down --volumes
|
|
40
|
-
|
|
41
|
-
services-logs:
|
|
42
|
-
docker-compose $(DOCKER_COMPOSE_ARGS) logs -f
|
|
43
|
-
|
|
44
18
|
services-port:
|
|
45
19
|
@set -o pipefail; \
|
|
46
|
-
docker-compose
|
|
20
|
+
docker-compose port ${SERVICE} ${PORT} 2> /dev/null | cut -d':' -f2 || echo ${PORT}
|
|
21
|
+
|
|
22
|
+
backup-staging: ROLE=staging
|
|
23
|
+
backup-production: ROLE=production
|
|
24
|
+
backup-%:
|
|
25
|
+
@echo Capturing $(ROLE)....
|
|
26
|
+
@heroku pg:backups:capture --remote $(ROLE)
|
|
27
|
+
|
|
28
|
+
restore-from-staging: ROLE=staging
|
|
29
|
+
restore-from-production: ROLE=production
|
|
30
|
+
restore-from-%:
|
|
31
|
+
$(eval TEMP_FILE=$(shell mktemp))
|
|
32
|
+
@echo Restoring from $(ROLE)....
|
|
33
|
+
@heroku pg:backups:download --remote $(ROLE) --output $(TEMP_FILE)
|
|
34
|
+
@pg_restore --verbose --clean --no-acl --no-owner -h localhost \
|
|
35
|
+
-U postgres -p $(shell make services-port SERVICE=postgresql PORT=5432) -d $(PROJECT)_development $(TEMP_FILE)
|
|
@@ -22,16 +22,27 @@ readme:
|
|
|
22
22
|
$ heroku local
|
|
23
23
|
|
|
24
24
|
[Heroku Local]: https://devcenter.heroku.com/articles/heroku-local
|
|
25
|
+
webpack:
|
|
26
|
+
title: "Development"
|
|
27
|
+
body: |
|
|
28
|
+
For hot-reloading and fast webpacker compilation you need to run webpack's dev server along with the rails server:
|
|
29
|
+
|
|
30
|
+
$ ./bin/webpack-dev-server
|
|
31
|
+
|
|
32
|
+
Running the dev server will also solve problems with the cache not refreshing between changes and provide better error messages if something fails to compile.
|
|
33
|
+
|
|
34
|
+
For even faster in-place component refreshing (with no page reloads), you can enable Hot Module Reloading in `config/webpacker.yml`
|
|
35
|
+
|
|
36
|
+
development:
|
|
37
|
+
dev_server:
|
|
38
|
+
hmr: true
|
|
25
39
|
ci:
|
|
26
40
|
title: "Continuous Integrations"
|
|
27
41
|
body: |
|
|
28
42
|
The project is setup to run tests
|
|
29
43
|
in [CircleCI](https://circleci.com/gh/platanus/<%= get(:dasherized_app_name) %>/tree/master)
|
|
30
44
|
|
|
31
|
-
You can also run the test locally simulating the production environment using
|
|
32
|
-
Just make sure you have docker installed and run:
|
|
33
|
-
|
|
34
|
-
bin/cibuild
|
|
45
|
+
You can also run the test locally simulating the production environment using [CircleCI's method](https://circleci.com/docs/2.0/local-cli/).
|
|
35
46
|
deployment:
|
|
36
47
|
title: "Deployment"
|
|
37
48
|
body: |
|
|
@@ -61,10 +72,17 @@ readme:
|
|
|
61
72
|
style_guide:
|
|
62
73
|
title: "Style Guides"
|
|
63
74
|
body: |
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
Style guides are enforced through a CircleCI [job](.circleci/config.yml) with [reviewdog](https://github.com/reviewdog/reviewdog) as a reporter, using per-project dependencies and style configurations.
|
|
76
|
+
Please note that this reviewdog implementation requires a GitHub user token to comment on pull requests. A token can be generated [here](https://github.com/settings/tokens), and it should have at least the `repo` option checked.
|
|
77
|
+
The included `config.yml` assumes your CircleCI organization has a context named `org-global` with the required token under the environment variable `REVIEWDOG_GITHUB_API_TOKEN`.
|
|
78
|
+
|
|
79
|
+
The project comes bundled with configuration files available in this repository.
|
|
80
|
+
|
|
81
|
+
Linting dependencies like `rubocop` or `rubocop-rspec` must be locked in your `Gemfile`. Similarly, packages like `eslint` or `eslint-plugin-vue` must be locked in your `package.json`.
|
|
66
82
|
|
|
67
|
-
You can add
|
|
83
|
+
You can add or modify rules by editing the [`.rubocop.yml`](.rubocop.yml), [`.eslintrc.json`](.eslintrc.json) or [`.stylelintrc.json`](.stylelintrc.json) files.
|
|
84
|
+
|
|
85
|
+
You can (and should) use linter integrations for your text editor of choice, using the project's configuration.
|
|
68
86
|
mailing:
|
|
69
87
|
title: "Sending Emails"
|
|
70
88
|
body: |
|
|
@@ -82,18 +100,15 @@ readme:
|
|
|
82
100
|
devise:
|
|
83
101
|
title: "Authentication"
|
|
84
102
|
body: "We are using the great [Devise](https://github.com/plataformatec/devise) library by [PlataformaTec](http://plataformatec.com.br/)"
|
|
85
|
-
|
|
86
|
-
title: "
|
|
87
|
-
body: "For managing uploads, this project uses [Paperclip](https://github.com/thoughtbot/paperclip), a gem made by the awesome [Thoughbot](https://thoughtbot.com/) team."
|
|
88
|
-
storage:
|
|
89
|
-
title: "Active Storage"
|
|
103
|
+
active_storage:
|
|
104
|
+
title: "File Storage"
|
|
90
105
|
body: "For managing uploads, this project uses [Active Storage](https://github.com/rails/rails/tree/master/activestorage)."
|
|
106
|
+
shrine:
|
|
107
|
+
title: "File Storage"
|
|
108
|
+
body: "For managing uploads, this project uses [Shrine](https://github.com/shrinerb/shrine)."
|
|
91
109
|
pundit:
|
|
92
110
|
title: "Authorization"
|
|
93
111
|
body: "For defining which parts of the system each user has access to, we have chosen to include the [Pundit](https://github.com/elabs/pundit) gem, by [Elabs](http://elabs.se/)."
|
|
94
|
-
delayed_job:
|
|
95
|
-
title: "Queue System"
|
|
96
|
-
body: "For managing tasks in the background, this project uses [DelayedJob](https://github.com/collectiveidea/delayed_job)"
|
|
97
112
|
sidekiq:
|
|
98
113
|
title: "Queue System"
|
|
99
114
|
body: "For managing tasks in the background, this project uses [Sidekiq](https://github.com/mperham/sidekiq)"
|
|
@@ -109,6 +124,35 @@ readme:
|
|
|
109
124
|
power_types:
|
|
110
125
|
title: "Rails pattern enforcing types"
|
|
111
126
|
body: "This projects uses [Power-Types](https://github.com/platanus/power-types) to generate Services, Commands, Utils and Values."
|
|
127
|
+
power_api:
|
|
128
|
+
title: "API Support"
|
|
129
|
+
body: "This projects uses [Power API](https://github.com/platanus/power_api). It's a Rails engine that gathers a set of gems and configurations designed to build incredible REST APIs."
|
|
130
|
+
graphql:
|
|
131
|
+
title: "API Support"
|
|
132
|
+
body: "This projects uses [graphql-ruby](https://graphql-ruby.org/) to generate a GraphQL API."
|
|
133
|
+
active_admin:
|
|
134
|
+
title: "Administration"
|
|
135
|
+
body: |
|
|
136
|
+
This project uses [Active Admin](https://github.com/activeadmin/activeadmin) which is a Ruby on Rails framework for creating elegant backends for website administration.
|
|
137
|
+
<% if get(:vue_admin) %>
|
|
138
|
+
This project supports Vue inside ActiveAdmin
|
|
139
|
+
- The main package is located in `app/javascript/packs/admin_application.js`, here you will declare the components you want to include in your ActiveAdmin views as you would in a normal Vue App.
|
|
140
|
+
- Additionally, to be able to use Vue components as [Arbre](https://github.com/activeadmin/arbre) Nodes the component names are also declared in `config/initializers/active_admin.rb`
|
|
141
|
+
- The generator includes an example component called `admin_component`, you can use this component inside any ActiveAdmin view by just writing `admin_component` as you would with any `html` tag.
|
|
142
|
+
- For example:
|
|
143
|
+
```
|
|
144
|
+
admin_component(class:"myCustomClass",id:"myCustomId") do
|
|
145
|
+
admin_component(id:"otherCustomId")
|
|
146
|
+
end
|
|
147
|
+
```
|
|
148
|
+
- (Keep in mind that the example works with ruby blocks because `AdminComponent` has a `<slot>` tag defined, therefore children can be added to the component)
|
|
149
|
+
- The integration supports passing props to the components and converts them to their corresponing javascript objects.
|
|
150
|
+
- For example, the following works
|
|
151
|
+
```
|
|
152
|
+
admin_component(testList:[1,2,3,4],testObject:{"name":"Vue component"})
|
|
153
|
+
```
|
|
154
|
+
- You can also use **any** vue bindings such as `v-for` , `:key` etc.
|
|
155
|
+
<% end %>
|
|
112
156
|
seeds:
|
|
113
157
|
title: "Seeds"
|
|
114
158
|
body: |
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
I am a Vue Component {{ test }} {{ message }}
|
|
4
|
+
<slot />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
export default {
|
|
10
|
+
props: {
|
|
11
|
+
test: {
|
|
12
|
+
type: String,
|
|
13
|
+
default: '',
|
|
14
|
+
},
|
|
15
|
+
testNumber: {
|
|
16
|
+
type: Number,
|
|
17
|
+
default: 0,
|
|
18
|
+
},
|
|
19
|
+
testObject: {
|
|
20
|
+
type: Object,
|
|
21
|
+
default: null,
|
|
22
|
+
},
|
|
23
|
+
testList: {
|
|
24
|
+
type: Array,
|
|
25
|
+
default: null,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
data() {
|
|
30
|
+
return {
|
|
31
|
+
message: 'Hello World',
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
</script>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Vue from 'vue/dist/vue.esm';
|
|
2
|
+
import AdminComponent from '../components/admin-component';
|
|
3
|
+
|
|
4
|
+
Vue.component('admin_component', AdminComponent);
|
|
5
|
+
|
|
6
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
7
|
+
if (document.getElementById('wrapper') !== null) {
|
|
8
|
+
return new Vue({
|
|
9
|
+
el: '#wrapper',
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return null;
|
|
14
|
+
});
|
|
@@ -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
|