apress-api 1.22.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.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/.drone.yml +30 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +4 -0
  5. data/Appraisals +31 -0
  6. data/CHANGELOG.md +227 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +31 -0
  10. data/Rakefile +2 -0
  11. data/app/controllers/apress/api/deprecated_versions_controller.rb +15 -0
  12. data/app/controllers/apress/api/v1/callbacks_controller.rb +30 -0
  13. data/app/controllers/apress/api/v1/tokens_controller.rb +24 -0
  14. data/app/docs/schema/api/v1/types/apress/api/link.rb +29 -0
  15. data/app/docs/schema/api/v1/types/apress/api/links.rb +24 -0
  16. data/app/docs/swagger/v1/controllers/apress/api/tokens_controller.rb +64 -0
  17. data/app/docs/swagger/v1/default_responses/bad_request.rb +16 -0
  18. data/app/docs/swagger/v1/default_responses/not_found.rb +16 -0
  19. data/app/docs/swagger/v1/default_responses/unauthenticated.rb +16 -0
  20. data/app/docs/swagger/v1/default_responses/unauthorized.rb +16 -0
  21. data/app/docs/swagger/v1/default_responses/unprocessable.rb +16 -0
  22. data/app/docs/swagger/v1/default_responses/updates_locked.rb +13 -0
  23. data/app/docs/swagger/v1/models/apress/api/client.rb +53 -0
  24. data/app/docs/swagger/v1/models/apress/api/simple_error.rb +27 -0
  25. data/app/docs/swagger/v1/models/apress/api/unproccesable_error.rb +16 -0
  26. data/app/docs/swagger/v1/models/apress/api/unprocessable_error.rb +37 -0
  27. data/app/docs/swagger/v1/root.rb +28 -0
  28. data/app/interactors/apress/api/callbacks/base_callback.rb +42 -0
  29. data/app/interactors/apress/api/delayed_fire_callback.rb +25 -0
  30. data/app/jobs/apress/api/event_handler_enqueueing_job.rb +19 -0
  31. data/app/jobs/apress/api/fire_callback_job.rb +25 -0
  32. data/app/models/apress/api/client.rb +60 -0
  33. data/app/policies/apress/api/callback_policy.rb +15 -0
  34. data/app/services/apress/api/auth_service.rb +37 -0
  35. data/app/views/apress/api/shared/_exception.json.jbuilder +4 -0
  36. data/app/views/apress/api/shared/error.json.jbuilder +5 -0
  37. data/app/views/apress/api/shared/parameter_missing_errors.json.jbuilder +9 -0
  38. data/app/views/apress/api/shared/unprocessable_errors.json.jbuilder +9 -0
  39. data/app/views/apress/api/v1/clients/_client.json.jbuilder +2 -0
  40. data/app/views/apress/api/v1/tokens/create.json.jbuilder +4 -0
  41. data/apress-api.gemspec +46 -0
  42. data/config/routes.rb +17 -0
  43. data/db/migrate/20150716000000_create_api_clients.rb +38 -0
  44. data/dip.yml +48 -0
  45. data/docker-compose.development.yml +18 -0
  46. data/docker-compose.drone.yml +7 -0
  47. data/docker-compose.yml +20 -0
  48. data/lib/apress-api.rb +1 -0
  49. data/lib/apress/api.rb +25 -0
  50. data/lib/apress/api/api_controller/authentification.rb +33 -0
  51. data/lib/apress/api/api_controller/base.rb +63 -0
  52. data/lib/apress/api/api_controller/compatibility.rb +26 -0
  53. data/lib/apress/api/api_controller/pagination.rb +60 -0
  54. data/lib/apress/api/api_controller/pagination_helper.rb +55 -0
  55. data/lib/apress/api/api_controller/rescue.rb +89 -0
  56. data/lib/apress/api/api_controller/responds.rb +25 -0
  57. data/lib/apress/api/callbacks/config.rb +56 -0
  58. data/lib/apress/api/callbacks/fire_callback_error.rb +12 -0
  59. data/lib/apress/api/callbacks/integration.rb +28 -0
  60. data/lib/apress/api/callbacks/repeat_callback_error.rb +12 -0
  61. data/lib/apress/api/engine.rb +33 -0
  62. data/lib/apress/api/extensions/jbuilder/jbuilder_template.rb +41 -0
  63. data/lib/apress/api/rspec.rb +48 -0
  64. data/lib/apress/api/rspec/utils.rb +17 -0
  65. data/lib/apress/api/testing/json_matcher.rb +9 -0
  66. data/lib/apress/api/version.rb +5 -0
  67. data/lib/tasks/docs.rake +12 -0
  68. data/spec/controllers/api_controller/authentification_spec.rb +79 -0
  69. data/spec/controllers/api_controller/pagination_spec.rb +199 -0
  70. data/spec/controllers/api_controller/rescue_spec.rb +167 -0
  71. data/spec/controllers/deprecated_versions_controller_spec.rb +10 -0
  72. data/spec/controllers/v1/callbacks_controller_spec.rb +50 -0
  73. data/spec/controllers/v1/tokens_controller_spec.rb +53 -0
  74. data/spec/factories/client_factory.rb +4 -0
  75. data/spec/helpers/paginating_cache_spec.rb +72 -0
  76. data/spec/interactors/apress/api/delayed_fire_callback_spec.rb +43 -0
  77. data/spec/internal/app/integrations/error_client/fire_callback.rb +14 -0
  78. data/spec/internal/app/integrations/service_client/fire_callback.rb +7 -0
  79. data/spec/internal/app/jobs/handler_job.rb +5 -0
  80. data/spec/internal/app/jobs/second_handler_job.rb +5 -0
  81. data/spec/internal/app/models/dummy_model.rb +15 -0
  82. data/spec/internal/config/database.yml +5 -0
  83. data/spec/internal/config/environments/test.rb +5 -0
  84. data/spec/internal/config/initializers/api.rb +10 -0
  85. data/spec/internal/config/routes.rb +3 -0
  86. data/spec/internal/db/schema.rb +5 -0
  87. data/spec/internal/log/.gitignore +1 -0
  88. data/spec/jobs/apress/api/event_handler_equeueing_job_spec.rb +31 -0
  89. data/spec/jobs/apress/api/fire_callback_job_spec.rb +34 -0
  90. data/spec/lib/apress/api/callbacks/integration_spec.rb +24 -0
  91. data/spec/models/client_spec.rb +25 -0
  92. data/spec/services/auth_service_spec.rb +64 -0
  93. data/spec/spec_helper.rb +34 -0
  94. metadata +518 -0
@@ -0,0 +1,19 @@
1
+ module Apress
2
+ module Api
3
+ class EventHandlerEnqueueingJob
4
+ include Resque::Integration
5
+
6
+ queue :api_callbacks
7
+
8
+ def self.perform(handler, event_params)
9
+ job = handler.camelize.constantize
10
+
11
+ if job.respond_to?(:enqueue)
12
+ job.enqueue(event_params)
13
+ else
14
+ Resque.enqueue(job, event_params)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ module Apress
2
+ module Api
3
+ class FireCallbackJob
4
+ include Resque::Integration
5
+ extend Resque::Plugins::ExponentialBackoff
6
+
7
+ queue :api_callbacks
8
+
9
+ @retry_exceptions = {
10
+ Apress::Api::Callbacks::FireCallbackError => [1, 60, 300, 3600],
11
+ Apress::Api::Callbacks::RepeatCallbackError => 300
12
+ }
13
+ @ignore_exceptions = [Apress::Api::Callbacks::RepeatCallbackError]
14
+
15
+ def self.perform(service, event, params)
16
+ callback_class = "#{service}_client/fire_callback".camelize.constantize
17
+
18
+ callback_class.call!(
19
+ event: event,
20
+ params: params
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,60 @@
1
+ module Apress
2
+ module Api
3
+ class Client < ActiveRecord::Base
4
+ self.table_name = "api_clients"
5
+
6
+ validates :access_id, presence: true
7
+ validates :secret_token, presence: true
8
+ validates :secret_token_expire_at, presence: true
9
+ validates :refresh_token, presence: true
10
+ validates :refresh_token_expire_at, presence: true
11
+
12
+ before_validation :generate_access_id, on: :create
13
+ before_validation :regenerate_tokens, on: :create
14
+
15
+ def regenerate_tokens
16
+ generate_secret_token
17
+ set_secret_token_expiration
18
+ generate_refresh_token
19
+ set_refresh_token_expiration
20
+ end
21
+
22
+ def regenerate_tokens!
23
+ regenerate_tokens
24
+ save!
25
+ end
26
+
27
+ def refresh_token_expired?
28
+ refresh_token_expire_at < Time.now.utc
29
+ end
30
+
31
+ def secret_token_expired?
32
+ secret_token_expire_at < Time.now.utc
33
+ end
34
+
35
+ private
36
+
37
+ def generate_access_id
38
+ self.access_id = SecureRandom.uuid
39
+ end
40
+
41
+ def generate_secret_token
42
+ self.secret_token = ::ApiAuth.generate_secret_key
43
+ end
44
+
45
+ def set_secret_token_expiration
46
+ self.secret_token_expire_at = Rails.application.config.api[:secret_token_ttl].from_now
47
+ end
48
+
49
+ def generate_refresh_token
50
+ self.refresh_token = ::ApiAuth.generate_secret_key
51
+ end
52
+
53
+ def set_refresh_token_expiration
54
+ self.refresh_token_expire_at = Rails.application.config.api[:refresh_token_ttl].from_now
55
+ end
56
+
57
+ ActiveSupport.run_load_hooks(:"apress/api/client", self)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,15 @@
1
+ module Apress
2
+ module Api
3
+ class CallbackPolicy
4
+ attr_reader :client
5
+
6
+ def initialize(client, _callback)
7
+ @client = client
8
+ end
9
+
10
+ def create?
11
+ Apress::Api::Callbacks::Config.allowed_client?(client)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ module Apress
2
+ module Api
3
+ class AuthService
4
+ rattr_initialize :request
5
+
6
+ attr_reader :client
7
+
8
+ delegate :query_parameters, to: :request
9
+
10
+ # Find Client by access_id, check sercret_key
11
+ #
12
+ # Returns boolean
13
+ def call
14
+ return false unless access_id
15
+
16
+ @client = Apress::Api::Client.find_by_access_id(access_id)
17
+ return false unless client
18
+
19
+ return false if client.secret_token_expired?
20
+
21
+ return true if not_check_signature?
22
+ ::ApiAuth.authentic?(request, client.secret_token)
23
+ end
24
+
25
+ def access_id
26
+ @access_id ||= ApiAuth.access_id(request) || query_parameters[:access_id]
27
+ end
28
+
29
+ private
30
+
31
+ def not_check_signature?
32
+ check_signature = query_parameters[:check_signature]
33
+ check_signature.present? && check_signature.to_i.zero? && (Rails.env.staging? || !Rails.env.production?)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ json.error do
2
+ json.message exception.message
3
+ json.backtrace exception.backtrace
4
+ end
@@ -0,0 +1,5 @@
1
+ json.status @status
2
+
3
+ if @exception && show_errors?
4
+ json.partial! partial: "apress/api/shared/exception", locals: {exception: @exception}
5
+ end
@@ -0,0 +1,9 @@
1
+ json.status @status
2
+
3
+ json.errors do
4
+ json.array! @errors do |error|
5
+ error.each do |k, v|
6
+ json.set! k, v
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ json.status @status
2
+
3
+ json.errors do
4
+ json.array! @errors do |error|
5
+ error.each do |k, v|
6
+ json.set! k, v
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ json.(client, :id, :access_id, :secret_token_expire_at, :refresh_token_expire_at, :user_agent,
2
+ :updated_at, :created_at)
@@ -0,0 +1,4 @@
1
+ json.client do
2
+ json.partial! partial: "apress/api/v1/clients/client", locals: {client: @client}
3
+ json.(@client, :secret_token, :refresh_token)
4
+ end
@@ -0,0 +1,46 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'apress/api/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "apress-api"
7
+ spec.version = Apress::Api::VERSION
8
+ spec.authors = ["merkushin"]
9
+ spec.email = ["merkushin.m.s@gmail.com"]
10
+ spec.summary = "Apress-Api"
11
+ spec.homepage = "https://github.com/abak-press/apress-api"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_runtime_dependency "rails", ">= 3.1.0", "< 6.0.0"
20
+ spec.add_runtime_dependency 'pg'
21
+ spec.add_runtime_dependency "api-auth", ">= 1.3.1"
22
+ spec.add_runtime_dependency "oj", ">= 2.9.9"
23
+ spec.add_runtime_dependency "multi_json", ">= 1.11.2"
24
+ spec.add_runtime_dependency "jbuilder", ">= 2.3.1"
25
+ spec.add_runtime_dependency "attr_extras", ">= 4.4.0"
26
+ spec.add_runtime_dependency 'swagger-core', '>= 0.3.0'
27
+ spec.add_runtime_dependency 'interactor'
28
+ spec.add_runtime_dependency 'pundit'
29
+
30
+ spec.add_runtime_dependency 'resque-integration'
31
+ spec.add_runtime_dependency 'apress-documentation', '>= 0.2.0'
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.7"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rspec", ">= 3.2"
36
+ spec.add_development_dependency "rspec-rails", ">= 3.2"
37
+ spec.add_development_dependency "combustion", ">= 0.5.4"
38
+ spec.add_development_dependency "appraisal"
39
+ spec.add_development_dependency "timecop"
40
+ spec.add_development_dependency "simplecov", ">= 0.9"
41
+ spec.add_development_dependency "factory_girl_rails", ">= 4.5"
42
+ spec.add_development_dependency "json-schema"
43
+ spec.add_development_dependency "test-unit"
44
+ spec.add_development_dependency "mock_redis"
45
+ spec.add_development_dependency 'pry-byebug'
46
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,17 @@
1
+ Rails.application.routes.draw do
2
+ current_api_routes = lambda do
3
+ resources :clients, only: [] do
4
+ resources :tokens, only: [:create]
5
+ end
6
+
7
+ post 'callbacks/:service' => 'callbacks#create'
8
+ end
9
+
10
+ scope module: "apress", constraints: {domain: :current} do
11
+ namespace :api do
12
+ scope module: :v1, &current_api_routes
13
+ namespace :v1, &current_api_routes
14
+ resource :deprecated_version, only: :show
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ if Rails::VERSION::MAJOR > 4
2
+ MIGRATION_CLASS = ActiveRecord::Migration[4.2]
3
+ else
4
+ MIGRATION_CLASS = ActiveRecord::Migration
5
+ end
6
+
7
+ class CreateApiClients < MIGRATION_CLASS
8
+ def up
9
+ create_table :api_clients do |t|
10
+ t.string :access_id, null: false, limit: 36
11
+ t.string :secret_token, null: false
12
+ t.datetime :secret_token_expire_at, null: false
13
+ t.string :refresh_token, null: false
14
+ t.datetime :refresh_token_expire_at, null: false
15
+ t.string :user_agent
16
+ t.timestamps null: false
17
+ end
18
+
19
+ execute <<-SQL
20
+ COMMENT ON TABLE api_clients IS 'Пользователи API';
21
+ COMMENT ON COLUMN api_clients.access_id IS 'Уникальный ID пользователя';
22
+ COMMENT ON COLUMN api_clients.secret_token IS 'Секретный ключ для подписи запроса';
23
+ COMMENT ON COLUMN api_clients.secret_token_expire_at IS 'Время протухания';
24
+ COMMENT ON COLUMN api_clients.refresh_token IS 'Ключ для получения нового секретного ключа';
25
+ COMMENT ON COLUMN api_clients.refresh_token_expire_at IS 'Время протухания';
26
+ COMMENT ON COLUMN api_clients.user_agent IS 'User-Agent пользователя';
27
+
28
+ ALTER TABLE api_clients
29
+ ADD CONSTRAINT uniq_api_clients_on_access_id
30
+ UNIQUE(access_id)
31
+ DEFERRABLE INITIALLY DEFERRED;
32
+ SQL
33
+ end
34
+
35
+ def down
36
+ drop_table :api_clients
37
+ end
38
+ end
data/dip.yml ADDED
@@ -0,0 +1,48 @@
1
+ version: '1'
2
+
3
+ environment:
4
+ DOCKER_RUBY_VERSION: 2.2
5
+ RUBY_IMAGE_TAG: 2.2-latest
6
+ POSTGRES_IMAGE_TAG: 9.6-0.7.0
7
+ COMPOSE_FILE_EXT: development
8
+ RAILS_ENV: test
9
+ APRESS_GEMS_CREDENTIALS: ""
10
+
11
+ compose:
12
+ files:
13
+ - docker-compose.yml
14
+ - docker-compose.${COMPOSE_FILE_EXT}.yml
15
+
16
+ interaction:
17
+ sh:
18
+ service: app
19
+
20
+ irb:
21
+ service: app
22
+ command: irb
23
+
24
+ bundle:
25
+ service: app
26
+ command: bundle
27
+
28
+ rake:
29
+ service: app
30
+ command: bundle exec rake
31
+
32
+ appraisal:
33
+ service: app
34
+ command: bundle exec appraisal
35
+
36
+ rspec:
37
+ service: app
38
+ command: bundle exec appraisal bundle exec rspec
39
+
40
+ clean:
41
+ service: app
42
+ command: rm -f Gemfile.lock gemfiles/*.gemfile.*
43
+
44
+ provision:
45
+ - docker volume create --name bundler_data
46
+ - dip clean
47
+ - dip bundle install
48
+ - dip appraisal install
@@ -0,0 +1,18 @@
1
+ version: '2'
2
+
3
+ services:
4
+ app:
5
+ volumes:
6
+ - .:/app
7
+ - ../:/localgems
8
+ - ssh-data:/ssh:ro
9
+ - bundler-data:/bundle
10
+
11
+ volumes:
12
+ bundler-data:
13
+ external:
14
+ name: bundler_data
15
+
16
+ ssh-data:
17
+ external:
18
+ name: ssh_data
@@ -0,0 +1,7 @@
1
+ version: '2'
2
+
3
+ services:
4
+ app:
5
+ volumes:
6
+ - .:/app
7
+ - /bundle:/bundle
@@ -0,0 +1,20 @@
1
+ version: '2'
2
+
3
+ services:
4
+ app:
5
+ image: abakpress/ruby-app:$RUBY_IMAGE_TAG
6
+ environment:
7
+ - SSH_AUTH_SOCK=/ssh/auth/sock
8
+ - BUNDLE_PATH=/bundle/$DOCKER_RUBY_VERSION
9
+ - BUNDLE_CONFIG=/app/.bundle/config
10
+ - TEST_DB_HOST=db
11
+ - TEST_DB_NAME=docker
12
+ - TEST_DB_USERNAME=postgres
13
+ command: bash
14
+ depends_on:
15
+ - db
16
+
17
+ db:
18
+ image: abakpress/postgres-db:$POSTGRES_IMAGE_TAG
19
+ environment:
20
+ - POSTGRES_DB=docker
data/lib/apress-api.rb ADDED
@@ -0,0 +1 @@
1
+ require 'apress/api'
data/lib/apress/api.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'rails'
2
+ require "active_support"
3
+ require "active_support/lazy_load_patch" if ActiveSupport::VERSION::MAJOR == 3 && ActiveSupport::VERSION::MINOR == 1
4
+ require "multi_json"
5
+ require "jbuilder"
6
+ require "api_auth"
7
+ require "attr_extras"
8
+ require "addressable"
9
+ require 'interactor'
10
+ require 'pundit'
11
+ require 'swagger/blocks'
12
+ require 'resque/integration'
13
+ require 'apress/documentation'
14
+ require "apress/api/version"
15
+ require "apress/api/engine"
16
+
17
+ module Apress
18
+ module Api
19
+ module Swagger
20
+ def self.const_missing(name)
21
+ ::Apress::Documentation::Swagger.const_get(name)
22
+ end
23
+ end
24
+ end
25
+ end