alpha_api 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a7ebf33759d9ccdcffa80c9fcb6692936b0b2f0cd9231b6b2cc0a7b93d0db04
4
- data.tar.gz: 5e4265a8e6d4d18037b4a73bd4820760de8af5b4a6d2cdebb204cf209587aaff
3
+ metadata.gz: 21aff10319f03b60f38c86b3f9655710d6d2a4e19914edd5e1ccd1c547f8fce7
4
+ data.tar.gz: 2856e2ef1792a1820adcb1c900004bad978b4d655f1a4383f4636973a5162f1a
5
5
  SHA512:
6
- metadata.gz: ed39edc56bf7dfe36028147842a4b35e96993fbb68055a839f5718978be44140e16b8bd9b58debe4be4278d52061e26c5a1445498b6fa93999d1350ad35b4077
7
- data.tar.gz: ba00720279c4317cb6eb3c0a8b49dddbe52750a84bf5304ab3ad9de9c17f48d144099727c969f03a1c94f45afde3491f35e78d27a33bb51e5a5cfeedc96f8ab8
6
+ metadata.gz: 6039fa1d787a8411148fe07a79bfcba4cd1b18423865a6dfffc60ae7398a04c945fc34112cba9d25e8c9a06b3032865582ff1857a2fd10031a64cd88f7a93f5f
7
+ data.tar.gz: fb6560099437d58ae4d247aba933dbc4c8e963d659c59dc15c8de7408d283c3a86aa3ee0267a0c2bd0bbf803d682315b431232a04935673db6aead6994e9e4ae
data/Gemfile CHANGED
@@ -8,10 +8,3 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "rubocop", "~> 0.80"
11
-
12
- gem "fast_jsonapi"
13
-
14
- # For actual pagination
15
- gem 'kaminari'
16
- # For rest pagination, using kaminari automatically
17
- gem 'api-pagination'
data/Gemfile.lock CHANGED
@@ -1,15 +1,24 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- alpha_api (0.1.0)
5
- activesupport
4
+ alpha_api (0.1.1)
6
5
  api-pagination
6
+ cancancan
7
+ devise
8
+ devise-jwt
7
9
  fast_jsonapi
8
10
  kaminari
9
11
 
10
12
  GEM
11
13
  remote: https://rubygems.org/
12
14
  specs:
15
+ actionpack (6.1.4.1)
16
+ actionview (= 6.1.4.1)
17
+ activesupport (= 6.1.4.1)
18
+ rack (~> 2.0, >= 2.0.9)
19
+ rack-test (>= 0.6.3)
20
+ rails-dom-testing (~> 2.0)
21
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
13
22
  actionview (6.1.4.1)
14
23
  activesupport (= 6.1.4.1)
15
24
  builder (~> 3.1)
@@ -29,14 +38,36 @@ GEM
29
38
  zeitwerk (~> 2.3)
30
39
  api-pagination (4.8.2)
31
40
  ast (2.4.2)
41
+ bcrypt (3.1.16)
32
42
  builder (3.2.4)
43
+ cancancan (3.3.0)
33
44
  concurrent-ruby (1.1.9)
34
45
  crass (1.0.6)
46
+ devise (4.8.0)
47
+ bcrypt (~> 3.0)
48
+ orm_adapter (~> 0.1)
49
+ railties (>= 4.1.0)
50
+ responders
51
+ warden (~> 1.2.3)
52
+ devise-jwt (0.8.1)
53
+ devise (~> 4.0)
54
+ warden-jwt_auth (~> 0.5)
55
+ dry-auto_inject (0.7.0)
56
+ dry-container (>= 0.3.4)
57
+ dry-configurable (0.12.1)
58
+ concurrent-ruby (~> 1.0)
59
+ dry-core (~> 0.5, >= 0.5.0)
60
+ dry-container (0.7.2)
61
+ concurrent-ruby (~> 1.0)
62
+ dry-configurable (~> 0.1, >= 0.1.3)
63
+ dry-core (0.6.0)
64
+ concurrent-ruby (~> 1.0)
35
65
  erubi (1.10.0)
36
66
  fast_jsonapi (1.5)
37
67
  activesupport (>= 4.2)
38
68
  i18n (1.8.10)
39
69
  concurrent-ruby (~> 1.0)
70
+ jwt (2.2.3)
40
71
  kaminari (1.2.1)
41
72
  activesupport (>= 4.1.0)
42
73
  kaminari-actionview (= 1.2.1)
@@ -52,21 +83,35 @@ GEM
52
83
  loofah (2.12.0)
53
84
  crass (~> 1.0.2)
54
85
  nokogiri (>= 1.5.9)
86
+ method_source (1.0.0)
55
87
  minitest (5.14.4)
56
88
  nokogiri (1.12.4-x86_64-darwin)
57
89
  racc (~> 1.4)
90
+ orm_adapter (0.5.0)
58
91
  parallel (1.20.1)
59
92
  parser (3.0.2.0)
60
93
  ast (~> 2.4.1)
61
94
  racc (1.5.2)
95
+ rack (2.2.3)
96
+ rack-test (1.1.0)
97
+ rack (>= 1.0, < 3)
62
98
  rails-dom-testing (2.0.3)
63
99
  activesupport (>= 4.2.0)
64
100
  nokogiri (>= 1.6)
65
101
  rails-html-sanitizer (1.4.2)
66
102
  loofah (~> 2.3)
103
+ railties (6.1.4.1)
104
+ actionpack (= 6.1.4.1)
105
+ activesupport (= 6.1.4.1)
106
+ method_source
107
+ rake (>= 0.13)
108
+ thor (~> 1.0)
67
109
  rainbow (3.0.0)
68
110
  rake (13.0.6)
69
111
  regexp_parser (2.1.1)
112
+ responders (3.0.1)
113
+ actionpack (>= 5.0)
114
+ railties (>= 5.0)
70
115
  rexml (3.2.5)
71
116
  rubocop (0.93.1)
72
117
  parallel (~> 1.10)
@@ -80,9 +125,17 @@ GEM
80
125
  rubocop-ast (1.11.0)
81
126
  parser (>= 3.0.1.1)
82
127
  ruby-progressbar (1.11.0)
128
+ thor (1.1.0)
83
129
  tzinfo (2.0.4)
84
130
  concurrent-ruby (~> 1.0)
85
131
  unicode-display_width (1.7.0)
132
+ warden (1.2.9)
133
+ rack (>= 2.0.9)
134
+ warden-jwt_auth (0.5.0)
135
+ dry-auto_inject (~> 0.6)
136
+ dry-configurable (~> 0.9)
137
+ jwt (~> 2.1)
138
+ warden (~> 1.2)
86
139
  zeitwerk (2.4.2)
87
140
 
88
141
  PLATFORMS
@@ -90,9 +143,6 @@ PLATFORMS
90
143
 
91
144
  DEPENDENCIES
92
145
  alpha_api!
93
- api-pagination
94
- fast_jsonapi
95
- kaminari
96
146
  rake (~> 13.0)
97
147
  rubocop (~> 0.80)
98
148
 
data/alpha_api.gemspec CHANGED
@@ -29,9 +29,14 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  # Uncomment to register a new dependency of your gem
31
31
  # spec.add_dependency "example-gem", "~> 1.0"
32
- spec.add_dependency 'activesupport'
32
+ spec.add_dependency 'devise-jwt'
33
+
33
34
  spec.add_dependency 'fast_jsonapi'
35
+ spec.add_dependency 'devise'
36
+ spec.add_dependency 'cancancan'
37
+ # For actual pagination
34
38
  spec.add_dependency 'kaminari'
39
+ # For rest pagination, using kaminari automatically
35
40
  spec.add_dependency 'api-pagination'
36
41
 
37
42
  # For more information and examples about making a new gem, checkout our
@@ -43,7 +43,7 @@ module AlphaApi
43
43
 
44
44
  # Runs before the app's initializer
45
45
  def before_initializer!
46
- puts 'before initializer'
46
+ # puts 'before initializer'
47
47
  ApiPagination.configure do |config|
48
48
  config.page_param do |params|
49
49
  if params[:page].is_a?(ActionController::Parameters) && params[:page].include?(:number)
@@ -65,7 +65,7 @@ module AlphaApi
65
65
 
66
66
  # Runs after the app's initializer
67
67
  def after_initializer!
68
- puts 'after initializer'
68
+ # puts 'after initializer'
69
69
  end
70
70
 
71
71
  private
@@ -0,0 +1,186 @@
1
+ module AlphaApi
2
+ class BaseController < ActionController::API
3
+ before_action :verify_auth_token
4
+
5
+ rescue_from StandardError do |exception|
6
+ AlphaApi.logger.error(exception.message)
7
+ AlphaApi.logger.error(exception.backtrace.join("\n"))
8
+
9
+ error = error_generator(
10
+ 'Internal Server Error',
11
+ 'Internal server error.'
12
+ )
13
+ render json: { errors: [error] }, status: :internal_server_error
14
+ end
15
+
16
+ rescue_from ActiveRecord::DeleteRestrictionError do |exception|
17
+ error = error_generator(
18
+ 'Bad Request',
19
+ exception.message
20
+ )
21
+ render json: { errors: [error] }, status: :bad_request
22
+ end
23
+
24
+ rescue_from ActionController::ParameterMissing do |exception|
25
+ error = error_generator(
26
+ 'Bad Request',
27
+ "Required parameter '#{exception.param}' is missing."
28
+ )
29
+ render json: { errors: [error] }, status: :bad_request
30
+ end
31
+
32
+ rescue_from ActionController::UnpermittedParameters do |exception|
33
+ errors = exception.params.map do |param|
34
+ error_generator(
35
+ 'Bad Request',
36
+ "Parameter '#{param}' is not permitted."
37
+ )
38
+ end
39
+ render json: { errors: errors }, status: :bad_request
40
+ end
41
+
42
+ rescue_from ActiveRecord::RecordNotFound, with: :not_found
43
+
44
+ rescue_from CanCan::AccessDenied, with: :deny_access
45
+
46
+ rescue_from AlphaApi::Exceptions::MethodNotAllowed, with: :method_not_allowed
47
+
48
+ rescue_from AlphaApi::Exceptions::InvalidRequest do |exception|
49
+ error = error_generator('Bad Request', exception.message)
50
+ render json: { errors: [error] }, status: :bad_request
51
+ end
52
+
53
+ rescue_from AlphaApi::Exceptions::ValidationErrors, with: :render_validation_errors
54
+
55
+ attr_reader :current_auth_token, :current_auth_token_payload, :current_user
56
+
57
+ def error_generator(title, detail, source = nil)
58
+ error = { title: title, detail: detail }
59
+ if source
60
+ key_mapper = {
61
+ organisation: 'organisation_id',
62
+ splash: 'splash_id',
63
+ box_hardware: 'box_hardware_id'
64
+ }
65
+ error[:source] = { pointer: "/data/attributes/#{key_mapper[source] || source}" }
66
+ end
67
+ error
68
+ end
69
+
70
+ def unsupported_media_type
71
+ head :unsupported_media_type
72
+ end
73
+
74
+ def not_found
75
+ error = error_generator(
76
+ 'Not Found',
77
+ "Resource #{request.path} is not found"
78
+ )
79
+ render json: { errors: [error] }, status: :not_found
80
+ end
81
+
82
+ def method_not_allowed
83
+ error = error_generator(
84
+ 'Method Not Allowed',
85
+ "Method #{request.method} is not allowed on #{request.path}"
86
+ )
87
+ render json: { errors: [error] }, status: :method_not_allowed
88
+ end
89
+
90
+ alias create method_not_allowed
91
+ alias destroy method_not_allowed
92
+ alias index method_not_allowed
93
+ alias update method_not_allowed
94
+ alias show not_found
95
+
96
+ def version
97
+ render json: Constants::VERSION
98
+ end
99
+
100
+ protected
101
+
102
+ def bad_request(reason)
103
+ error = error_generator('Bad Request', reason)
104
+ render json: { errors: [error] }, status: :bad_request
105
+ end
106
+
107
+ def forbidden(reason)
108
+ error = error_generator('Forbidden', reason)
109
+ render json: { errors: [error] }, status: :forbidden
110
+ end
111
+
112
+ def set_content_type_jsonapi
113
+ response.headers['Content-Type'] = 'application/vnd.api+json; charset=utf-8'
114
+ end
115
+
116
+ def set_content_type_json
117
+ response.headers['Content-Type'] = 'application/json; charset=utf-8'
118
+ end
119
+
120
+ def unauthorized(reason)
121
+ error = error_generator('Unauthorized', reason)
122
+ render json: { errors: [error] }, status: :unauthorized
123
+ end
124
+
125
+ def unprocessable_entity(errors)
126
+ errors = errors.map do |attr, message|
127
+ error_generator('Validation Error', message, attr)
128
+ end
129
+ render json: { errors: errors }, status: :unprocessable_entity
130
+ end
131
+
132
+ def verify_auth_token
133
+ # Check for HTTP Authorization header
134
+ authorization = request.headers['Authorization']
135
+ AlphaApi.logger.warn "verify_auth_token: authorization #{authorization}"
136
+ return unauthorized '缺少Authorization头文件' unless authorization.present?
137
+
138
+ # Extract token from header
139
+ matches = authorization.match(/^Bearer (.+)/)
140
+ token = matches.captures[0] if matches
141
+ return unauthorized 'Authorization头文件错误' unless token.present?
142
+
143
+ check_auth_token(token) do |user, payload|
144
+ @current_auth_token = token
145
+ @current_auth_token_payload = payload
146
+ @current_user = user
147
+ nil
148
+ end
149
+ end
150
+
151
+ private
152
+
153
+ def check_auth_token(token)
154
+ # Attempt to decode the auth token payload
155
+ payload = nil
156
+ begin
157
+ payload = Warden::JWTAuth::TokenDecoder.new.call token
158
+ rescue JWT::ExpiredSignature
159
+ payload = JWT.decode(token, nil, false)[0]
160
+ unless payload['aud'] == 'mobile'
161
+ return unauthorized '验证信息已经过期,请重新登陆.'
162
+ end
163
+ rescue StandardError => e
164
+ AlphaApi.logger.warn "Failed to decode authentication token: #{e.message}, token: #{token}"
165
+ return unauthorized '验证信息错误'
166
+ end
167
+
168
+ return unauthorized '验证信息错误' unless payload
169
+
170
+ # Check that token is still valid
171
+ user = User.find_by(id: payload['user_id'])
172
+ return unauthorized '验证信息错误' unless user
173
+ return unauthorized '验证信息已无效' if DenylistedToken.jwt_revoked?(payload, user)
174
+
175
+ yield user, payload
176
+ end
177
+
178
+ def render_validation_errors(exception)
179
+ unprocessable_entity(exception.errors)
180
+ end
181
+
182
+ def deny_access
183
+ forbidden '没有权限访问该资源'
184
+ end
185
+ end
186
+ end
@@ -1,4 +1,6 @@
1
- require "active_support/concern"
1
+ require 'active_support/concern'
2
+ require 'active_record'
3
+ require_relative '../exceptions'
2
4
 
3
5
  module AlphaApi
4
6
  module Concerns
@@ -14,7 +16,7 @@ module AlphaApi
14
16
  render status: :created, json: resource_serializer.new(new_resource).serializable_hash
15
17
  else
16
18
  errors = reformat_validation_error(new_resource)
17
- raise Exceptions::ValidationErrors.new(errors), 'Validation Errors'
19
+ raise AlphaApi::Exceptions::ValidationErrors.new(errors), 'Validation Errors'
18
20
  end
19
21
  end
20
22
 
@@ -50,7 +52,7 @@ module AlphaApi
50
52
  render json: resource_serializer.new(updated_resource, options).serializable_hash
51
53
  else
52
54
  errors = reformat_validation_error(resource)
53
- raise Exceptions::ValidationErrors.new(errors), 'Validation Errors'
55
+ raise AlphaApi::Exceptions::ValidationErrors.new(errors), 'Validation Errors'
54
56
  end
55
57
  end
56
58
 
@@ -61,10 +63,10 @@ module AlphaApi
61
63
  if resource.destroy
62
64
  head :no_content
63
65
  else
64
- raise Exceptions::ValidationErrors.new(resource.errors), 'Validation Errors'
66
+ raise AlphaApi::Exceptions::ValidationErrors.new(resource.errors), 'Validation Errors'
65
67
  end
66
68
  else
67
- raise Exceptions::MethodNotAllowed, 'Method Not Allowed'
69
+ raise AlphaApi::Exceptions::MethodNotAllowed, 'Method Not Allowed'
68
70
  end
69
71
  end
70
72
 
@@ -92,7 +94,7 @@ module AlphaApi
92
94
  # @override customised filters
93
95
  def apply_filter(query)
94
96
  if filterable_fields.empty?
95
- raise Exceptions::InvalidFilter, 'Filters are not supported for this resource type'
97
+ raise AlphaApi::Exceptions::InvalidFilter, 'Filters are not supported for this resource type'
96
98
  else
97
99
  query
98
100
  end
@@ -128,7 +130,7 @@ module AlphaApi
128
130
  elsif valid_boolean?(field, value)
129
131
  query = query.where(field => value == 'true')
130
132
  else
131
- raise Exceptions::InvalidFilter, 'Only type of string and uuid fields are supported'
133
+ raise AlphaApi::Exceptions::InvalidFilter, 'Only type of string and uuid fields are supported'
132
134
  end
133
135
  end
134
136
  query
@@ -153,10 +155,10 @@ module AlphaApi
153
155
  if allow_all && page_size == -1
154
156
  params[:page] = nil
155
157
  else
156
- raise Exceptions::InvalidRequest, 'Page number must be positive' unless page_number.positive?
157
- raise Exceptions::InvalidRequest, 'Page offset must be non-negative' if page_offset.negative?
158
- raise Exceptions::InvalidRequest, 'Page size must be positive' unless page_size.positive?
159
- raise Exceptions::InvalidRequest, 'Page size cannot be greater than 100' if page_size > 100
158
+ raise AlphaApi::Exceptions::InvalidRequest, 'Page number must be positive' unless page_number.positive?
159
+ raise AlphaApi::Exceptions::InvalidRequest, 'Page offset must be non-negative' if page_offset.negative?
160
+ raise AlphaApi::Exceptions::InvalidRequest, 'Page size must be positive' unless page_size.positive?
161
+ raise AlphaApi::Exceptions::InvalidRequest, 'Page size cannot be greater than 100' if page_size > 100
160
162
 
161
163
  params[:page] = {
162
164
  number: page_number,
@@ -173,13 +175,13 @@ module AlphaApi
173
175
  def apply_sorting(query)
174
176
  sort_params = params['sort']
175
177
  return query.order(default_sorting) unless sort_params.present?
176
- raise Exceptions::InvalidRequest, 'Sort parameter must be a string' unless sort_params.is_a? String
178
+ raise AlphaApi::Exceptions::InvalidRequest, 'Sort parameter must be a string' unless sort_params.is_a? String
177
179
  sorting = []
178
180
 
179
181
  sorts = sort_params.split(',').map(&:strip).map do |sort|
180
182
  is_desc = sort.start_with?('-')
181
183
  sort = is_desc ? sort[1..-1] : sort
182
- raise Exceptions::InvalidRequest, "Sorting by #{sort} is not allowed" unless allowed_sortings.include?(sort.to_sym)
184
+ raise AlphaApi::Exceptions::InvalidRequest, "Sorting by #{sort} is not allowed" unless allowed_sortings.include?(sort.to_sym)
183
185
  sort = association_mapper(sort)
184
186
 
185
187
  # have to includes the association to be able to sort on
@@ -213,7 +215,7 @@ module AlphaApi
213
215
  def reconcile_nested_attributes(existing_items, items_in_update)
214
216
  item_ids_in_update = items_in_update.map { |item| item['id'] }.compact
215
217
  if item_ids_in_update.uniq.length != item_ids_in_update.length
216
- raise(Exceptions::InvalidRequest, 'Nested attribute IDs must be unique')
218
+ raise(AlphaApi::Exceptions::InvalidRequest, 'Nested attribute IDs must be unique')
217
219
  end
218
220
 
219
221
  nested_attributes = []
@@ -246,7 +248,7 @@ module AlphaApi
246
248
  invalid_resources = []
247
249
  nested_resources.each { |res| invalid_resources.push(res) unless allowed_associations.include?(res.to_sym) }
248
250
  unless invalid_resources.empty?
249
- raise Exceptions::InvalidArgument, "Invalid value for include: #{invalid_resources.join(', ')}"
251
+ raise AlphaApi::Exceptions::InvalidArgument, "Invalid value for include: #{invalid_resources.join(', ')}"
250
252
  end
251
253
 
252
254
  nested_resources
@@ -291,7 +293,7 @@ module AlphaApi
291
293
  def reconcile_nested_attributes(existing_items, items_in_update)
292
294
  item_ids_in_update = items_in_update.map { |item| item['id'] }.compact
293
295
  if item_ids_in_update.uniq.length != item_ids_in_update.length
294
- raise(Exceptions::InvalidRequest, 'Nested attribute IDs must be unique')
296
+ raise(AlphaApi::Exceptions::InvalidRequest, 'Nested attribute IDs must be unique')
295
297
  end
296
298
 
297
299
  nested_attributes = []
@@ -336,7 +338,7 @@ module AlphaApi
336
338
  "#{association.table_name}.#{attr_name} #{order}"
337
339
  else
338
340
  # could potencially support that as well by includes deeply nested associations
339
- raise Exceptions::InvalidRequest, 'Sorting on deeply nested association is not supported'
341
+ raise AlphaApi::Exceptions::InvalidRequest, 'Sorting on deeply nested association is not supported'
340
342
  end
341
343
  end
342
344
 
@@ -0,0 +1,16 @@
1
+ module AlphaApi
2
+ module Exceptions
3
+ class InvalidRequest < StandardError; end
4
+ class InvalidFilter < InvalidRequest; end
5
+ class InvalidArgument < InvalidRequest; end
6
+ class MethodNotAllowed < StandardError; end
7
+ class ValidationErrors < StandardError
8
+ attr_reader :errors
9
+
10
+ def initialize(errors = [])
11
+ super
12
+ @errors = errors
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ require 'logger'
2
+
3
+ module AlphaApi
4
+ class << self
5
+ attr_writer :logger
6
+
7
+ def logger
8
+ @logger ||= Logger.new($stdout).tap do |log|
9
+ log.progname = self.name
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AlphaApi
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/alpha_api.rb CHANGED
@@ -1,12 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support'
4
+ require 'action_pack'
5
+ require 'fast_jsonapi'
6
+ require 'devise'
7
+ require 'devise/jwt'
8
+ require 'cancancan'
9
+ require 'kaminari'
10
+ require 'api-pagination'
11
+ require 'active_record'
12
+ require 'active_record/associations'
13
+
3
14
  require_relative "alpha_api/version"
4
15
  require_relative "alpha_api/application"
5
16
  require_relative "generators/resource/resource_generator"
6
17
  require_relative "generators/install/install_generator"
7
18
  require_relative 'alpha_api/application_settings'
8
19
  require_relative 'alpha_api/concerns/actionable'
20
+ require_relative 'alpha_api/base_controller'
9
21
  require_relative 'alpha_api/serializers/application_record_serializer'
22
+ require_relative 'alpha_api/exceptions'
10
23
 
11
24
  module AlphaApi
12
25
  class Error < StandardError; end
@@ -30,3 +43,4 @@ module AlphaApi
30
43
  end
31
44
  end
32
45
  end
46
+
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
- #
2
+
3
+ require 'rails/generators/active_record'
4
+
3
5
  module AlphaApi
4
6
  module Generators
5
7
  class InstallGenerator < Rails::Generators::Base
8
+ include Rails::Generators::Migration
6
9
  desc "Installs AlphaApi"
7
10
 
8
11
  source_root File.expand_path("templates", __dir__)
@@ -11,8 +14,50 @@ module AlphaApi
11
14
  template "alpha_api.rb.erb", "config/initializers/alpha_api.rb"
12
15
  end
13
16
 
14
- def something
15
- puts 'h1'
17
+ def add_device_initializer
18
+ puts 'Setup device'
19
+ system 'bundle exec rails generate devise:install'
20
+ end
21
+
22
+ def create_user_model
23
+ migration_template "create_devise_users.rb", "db/migrate/create_devise_users.rb", migration_version: migration_version
24
+ end
25
+
26
+ def add_denylisted_token_model
27
+ template "denylisted_token.rb.erb", "app/models/denylisted_token.rb"
28
+ end
29
+
30
+ def add_denylisted_token_migration
31
+ migration_template "add_denylisted_token.rb", "db/migrate/add_denylisted_token.rb", migration_version: migration_version
32
+ end
33
+
34
+ def append_jwt_devise_initializer
35
+ inject_into_file 'config/initializers/devise.rb', after: "Devise.setup do |config|\n" do
36
+ <<~HEREDOC
37
+
38
+ config.jwt do |jwt|
39
+ jwt.secret = Rails.application.secrets.secret_key_base
40
+ jwt.expiration_time = 24.hours.to_i
41
+ end
42
+
43
+ HEREDOC
44
+ end
45
+ end
46
+
47
+ def initialize_cancancan
48
+ puts 'Setup Cancancan ability class'
49
+ system 'bundle exec rails generate cancan:ability'
50
+ end
51
+
52
+ private
53
+
54
+ def self.next_migration_number(dirname)
55
+ next_migration_number = current_migration_number(dirname) + 1
56
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
57
+ end
58
+
59
+ def migration_version
60
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
16
61
  end
17
62
  end
18
63
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddDenylistedToken < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ create_table :denylisted_tokens do |t|
6
+ t.string :jti, null: false
7
+ t.datetime :exp, null: false
8
+ end
9
+ add_index :denylisted_tokens, :jti
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDeviseUsers < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ create_table :users do |t|
6
+ ## Database authenticatable
7
+ t.string :email, null: false, default: ''
8
+ t.string :encrypted_password, null: false, default: ''
9
+
10
+ ## Recoverable
11
+ t.string :reset_password_token
12
+ t.datetime :reset_password_sent_at
13
+
14
+ ## Rememberable
15
+ t.datetime :remember_created_at
16
+
17
+ ## Trackable
18
+ # t.integer :sign_in_count, default: 0, null: false
19
+ # t.datetime :current_sign_in_at
20
+ # t.datetime :last_sign_in_at
21
+ # t.inet :current_sign_in_ip
22
+ # t.inet :last_sign_in_ip
23
+
24
+ ## Confirmable
25
+ # t.string :confirmation_token
26
+ # t.datetime :confirmed_at
27
+ # t.datetime :confirmation_sent_at
28
+ # t.string :unconfirmed_email # Only if using reconfirmable
29
+
30
+ ## Lockable
31
+ # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
32
+ # t.string :unlock_token # Only if unlock strategy is :email or :both
33
+ # t.datetime :locked_at
34
+
35
+ t.timestamps null: false
36
+ end
37
+
38
+ add_index :users, :email, unique: true
39
+ add_index :users, :reset_password_token, unique: true
40
+ # add_index :users, :confirmation_token, unique: true
41
+ # add_index :users, :unlock_token, unique: true
42
+ end
43
+ end
44
+
45
+
@@ -0,0 +1,4 @@
1
+ class DenylistedToken < ApplicationRecord
2
+ include Devise::JWT::RevocationStrategies::Denylist
3
+ end
4
+
@@ -1,4 +1,4 @@
1
- class <%= @boilerplate.module_name %>::<%= class_name.pluralize %>Controller < <%= @boilerplate.module_name %>::BaseController
1
+ class <%= @boilerplate.module_name %>::<%= class_name.pluralize %>Controller < AlphaApi::BaseController
2
2
  include AlphaApi::Concerns::Actionable
3
3
 
4
4
  protected
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alpha_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alba Hoo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-12 00:00:00.000000000 Z
11
+ date: 2021-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
14
+ name: devise-jwt
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: devise
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: cancancan
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: kaminari
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -88,16 +116,22 @@ files:
88
116
  - lib/alpha_api.rb
89
117
  - lib/alpha_api/application.rb
90
118
  - lib/alpha_api/application_settings.rb
119
+ - lib/alpha_api/base_controller.rb
91
120
  - lib/alpha_api/concerns/actionable.rb
92
121
  - lib/alpha_api/dynamic_setting.rb
93
122
  - lib/alpha_api/dynamic_settings_node.rb
123
+ - lib/alpha_api/exceptions.rb
124
+ - lib/alpha_api/logger.rb
94
125
  - lib/alpha_api/namespace_settings.rb
95
126
  - lib/alpha_api/resource_collection.rb
96
127
  - lib/alpha_api/serializers/application_record_serializer.rb
97
128
  - lib/alpha_api/settings_node.rb
98
129
  - lib/alpha_api/version.rb
99
130
  - lib/generators/install/install_generator.rb
131
+ - lib/generators/install/templates/add_denylisted_token.rb
100
132
  - lib/generators/install/templates/alpha_api.rb.erb
133
+ - lib/generators/install/templates/create_devise_users.rb
134
+ - lib/generators/install/templates/denylisted_token.rb.erb
101
135
  - lib/generators/resource/resource_generator.rb
102
136
  - lib/generators/resource/templates/controller.rb.erb
103
137
  - lib/generators/resource/templates/serializer.rb.erb