potassium 5.2.2 → 6.3.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 -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
|