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.
- checksums.yaml +7 -0
- data/.drone.yml +30 -0
- data/.gitignore +15 -0
- data/.rspec +4 -0
- data/Appraisals +31 -0
- data/CHANGELOG.md +227 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/app/controllers/apress/api/deprecated_versions_controller.rb +15 -0
- data/app/controllers/apress/api/v1/callbacks_controller.rb +30 -0
- data/app/controllers/apress/api/v1/tokens_controller.rb +24 -0
- data/app/docs/schema/api/v1/types/apress/api/link.rb +29 -0
- data/app/docs/schema/api/v1/types/apress/api/links.rb +24 -0
- data/app/docs/swagger/v1/controllers/apress/api/tokens_controller.rb +64 -0
- data/app/docs/swagger/v1/default_responses/bad_request.rb +16 -0
- data/app/docs/swagger/v1/default_responses/not_found.rb +16 -0
- data/app/docs/swagger/v1/default_responses/unauthenticated.rb +16 -0
- data/app/docs/swagger/v1/default_responses/unauthorized.rb +16 -0
- data/app/docs/swagger/v1/default_responses/unprocessable.rb +16 -0
- data/app/docs/swagger/v1/default_responses/updates_locked.rb +13 -0
- data/app/docs/swagger/v1/models/apress/api/client.rb +53 -0
- data/app/docs/swagger/v1/models/apress/api/simple_error.rb +27 -0
- data/app/docs/swagger/v1/models/apress/api/unproccesable_error.rb +16 -0
- data/app/docs/swagger/v1/models/apress/api/unprocessable_error.rb +37 -0
- data/app/docs/swagger/v1/root.rb +28 -0
- data/app/interactors/apress/api/callbacks/base_callback.rb +42 -0
- data/app/interactors/apress/api/delayed_fire_callback.rb +25 -0
- data/app/jobs/apress/api/event_handler_enqueueing_job.rb +19 -0
- data/app/jobs/apress/api/fire_callback_job.rb +25 -0
- data/app/models/apress/api/client.rb +60 -0
- data/app/policies/apress/api/callback_policy.rb +15 -0
- data/app/services/apress/api/auth_service.rb +37 -0
- data/app/views/apress/api/shared/_exception.json.jbuilder +4 -0
- data/app/views/apress/api/shared/error.json.jbuilder +5 -0
- data/app/views/apress/api/shared/parameter_missing_errors.json.jbuilder +9 -0
- data/app/views/apress/api/shared/unprocessable_errors.json.jbuilder +9 -0
- data/app/views/apress/api/v1/clients/_client.json.jbuilder +2 -0
- data/app/views/apress/api/v1/tokens/create.json.jbuilder +4 -0
- data/apress-api.gemspec +46 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20150716000000_create_api_clients.rb +38 -0
- data/dip.yml +48 -0
- data/docker-compose.development.yml +18 -0
- data/docker-compose.drone.yml +7 -0
- data/docker-compose.yml +20 -0
- data/lib/apress-api.rb +1 -0
- data/lib/apress/api.rb +25 -0
- data/lib/apress/api/api_controller/authentification.rb +33 -0
- data/lib/apress/api/api_controller/base.rb +63 -0
- data/lib/apress/api/api_controller/compatibility.rb +26 -0
- data/lib/apress/api/api_controller/pagination.rb +60 -0
- data/lib/apress/api/api_controller/pagination_helper.rb +55 -0
- data/lib/apress/api/api_controller/rescue.rb +89 -0
- data/lib/apress/api/api_controller/responds.rb +25 -0
- data/lib/apress/api/callbacks/config.rb +56 -0
- data/lib/apress/api/callbacks/fire_callback_error.rb +12 -0
- data/lib/apress/api/callbacks/integration.rb +28 -0
- data/lib/apress/api/callbacks/repeat_callback_error.rb +12 -0
- data/lib/apress/api/engine.rb +33 -0
- data/lib/apress/api/extensions/jbuilder/jbuilder_template.rb +41 -0
- data/lib/apress/api/rspec.rb +48 -0
- data/lib/apress/api/rspec/utils.rb +17 -0
- data/lib/apress/api/testing/json_matcher.rb +9 -0
- data/lib/apress/api/version.rb +5 -0
- data/lib/tasks/docs.rake +12 -0
- data/spec/controllers/api_controller/authentification_spec.rb +79 -0
- data/spec/controllers/api_controller/pagination_spec.rb +199 -0
- data/spec/controllers/api_controller/rescue_spec.rb +167 -0
- data/spec/controllers/deprecated_versions_controller_spec.rb +10 -0
- data/spec/controllers/v1/callbacks_controller_spec.rb +50 -0
- data/spec/controllers/v1/tokens_controller_spec.rb +53 -0
- data/spec/factories/client_factory.rb +4 -0
- data/spec/helpers/paginating_cache_spec.rb +72 -0
- data/spec/interactors/apress/api/delayed_fire_callback_spec.rb +43 -0
- data/spec/internal/app/integrations/error_client/fire_callback.rb +14 -0
- data/spec/internal/app/integrations/service_client/fire_callback.rb +7 -0
- data/spec/internal/app/jobs/handler_job.rb +5 -0
- data/spec/internal/app/jobs/second_handler_job.rb +5 -0
- data/spec/internal/app/models/dummy_model.rb +15 -0
- data/spec/internal/config/database.yml +5 -0
- data/spec/internal/config/environments/test.rb +5 -0
- data/spec/internal/config/initializers/api.rb +10 -0
- data/spec/internal/config/routes.rb +3 -0
- data/spec/internal/db/schema.rb +5 -0
- data/spec/internal/log/.gitignore +1 -0
- data/spec/jobs/apress/api/event_handler_equeueing_job_spec.rb +31 -0
- data/spec/jobs/apress/api/fire_callback_job_spec.rb +34 -0
- data/spec/lib/apress/api/callbacks/integration_spec.rb +24 -0
- data/spec/models/client_spec.rb +25 -0
- data/spec/services/auth_service_spec.rb +64 -0
- data/spec/spec_helper.rb +34 -0
- 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,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
|
data/apress-api.gemspec
ADDED
|
@@ -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, ¤t_api_routes
|
|
13
|
+
namespace :v1, ¤t_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
|
data/docker-compose.yml
ADDED
|
@@ -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
|