vodka 0.0.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.
- data/.gitignore +7 -0
- data/.travis.yml +14 -0
- data/Gemfile +4 -0
- data/LICENCE +13 -0
- data/README.md +119 -0
- data/lib/party.rb +9 -0
- data/lib/vodka/client/exceptions/exception.rb +6 -0
- data/lib/vodka/client/exceptions/failed_action_exception.rb +6 -0
- data/lib/vodka/client/exceptions/forbidden_exception.rb +11 -0
- data/lib/vodka/client/exceptions/not_found_exception.rb +11 -0
- data/lib/vodka/client/exceptions/resource_exception.rb +6 -0
- data/lib/vodka/client/middleware/error_aware.rb +21 -0
- data/lib/vodka/client/middleware/signed_request.rb +34 -0
- data/lib/vodka/client.rb +16 -0
- data/lib/vodka/configuration.rb +25 -0
- data/lib/vodka/her/extensions/extended_orm.rb +92 -0
- data/lib/vodka/her/extensions/will_paginate.rb +32 -0
- data/lib/vodka/server/controllers/vodka_controller.rb +32 -0
- data/lib/vodka/server/handlers/resource.rb +36 -0
- data/lib/vodka/server/handlers/response.rb +34 -0
- data/lib/vodka/server/handlers/scaffold.rb +63 -0
- data/lib/vodka/server/middleware/signed_request.rb +39 -0
- data/lib/vodka/server/plugins/presentable.rb +20 -0
- data/lib/vodka/server/railtie.rb +11 -0
- data/lib/vodka/server/response.rb +34 -0
- data/lib/vodka/server.rb +15 -0
- data/lib/vodka/version.rb +3 -0
- data/lib/vodka.rb +5 -0
- data/script/bundle_dummy +4 -0
- data/script/ci +4 -0
- data/script/setup_db +7 -0
- data/script/show_logs +22 -0
- data/script/spec +14 -0
- data/script/start_server +6 -0
- data/script/stop_server +6 -0
- data/spec/client/article.rb +4 -0
- data/spec/dummy/Gemfile +9 -0
- data/spec/dummy/Gemfile.lock +113 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/vodka/articles_controller.rb +8 -0
- data/spec/dummy/app/models/article.rb +10 -0
- data/spec/dummy/config/application.rb +64 -0
- data/spec/dummy/config/boot.rb +6 -0
- data/spec/dummy/config/database.yml +17 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +32 -0
- data/spec/dummy/config/environments/production.rb +54 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/vodka_setup.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +2 -0
- data/spec/dummy/config/locales/ru.yml +2 -0
- data/spec/dummy/config/routes.rb +7 -0
- data/spec/dummy/config/thin.yml +10 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20130217185353_create_articles.rb +9 -0
- data/spec/dummy/db/schema.rb +22 -0
- data/spec/dummy/db/seeds.rb +1 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/her/extensions/extended_orm/create_spec.rb +33 -0
- data/spec/her/extensions/extended_orm/delete_spec.rb +23 -0
- data/spec/her/extensions/extended_orm/destroy_spec.rb +35 -0
- data/spec/her/extensions/extended_orm/first_spec.rb +11 -0
- data/spec/her/extensions/extended_orm/last_spec.rb +11 -0
- data/spec/her/extensions/extended_orm/update_attribute_spec.rb +44 -0
- data/spec/her/extensions/extended_orm/update_attributes_spec.rb +44 -0
- data/spec/her/extensions/extended_orm/where_spec.rb +39 -0
- data/spec/her/extensions/will_paginate/paginate_spec.rb +16 -0
- data/spec/middleware/error_aware_spec.rb +19 -0
- data/spec/middleware/response_locale_spec.rb +12 -0
- data/spec/middleware/signed_request_spec.rb +9 -0
- data/spec/spec_helper.rb +24 -0
- data/vodka.gemspec +21 -0
- metadata +190 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
rvm:
|
2
|
+
- 1.9.3
|
3
|
+
script: ./script/ci
|
4
|
+
before_script:
|
5
|
+
- ./script/bundle_dummy
|
6
|
+
- ./script/setup_db
|
7
|
+
- ./script/start_server
|
8
|
+
after_script:
|
9
|
+
- ./script/stop_server
|
10
|
+
after_failure:
|
11
|
+
- ./script/show_logs
|
12
|
+
notifications:
|
13
|
+
hipchat:
|
14
|
+
secure: "SUoVBD+3cNXuzHK/xiww4e2jWdo9GHz+YE09s+z0K51nPtlTy9NFaBF41O7W\nMc4sz0ZxktnVrpVvyOGmLj933uyyRjhfK9X3R6Fn/BMzWDI1S4Z2NqhKq3xy\nGpLjEAX8UPtWXR0Cs4GxTwxTM6rjIW/I/5IpM6hiwRErSBXBin0="
|
data/Gemfile
ADDED
data/LICENCE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENCE
|
2
|
+
Version 2, December 2004
|
3
|
+
|
4
|
+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
5
|
+
|
6
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
7
|
+
copies of this license document, and changing it is allowed as long
|
8
|
+
as the name is changed.
|
9
|
+
|
10
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
11
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
12
|
+
|
13
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# Vodka
|
2
|
+
Vodka makes communication easier. Always.
|
3
|
+
|
4
|
+
Vodka uses [Her](https://github.com/remiprev/her) as a REST client.
|
5
|
+
|
6
|
+
It currently supports ORM's on server:
|
7
|
+
- [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord)
|
8
|
+
- [MongoMapper](https://github.com/jnunemaker/mongomapper)
|
9
|
+
|
10
|
+
Plugins:
|
11
|
+
- [WillPaginate](https://github.com/mislav/will_paginate)
|
12
|
+
|
13
|
+
It is strongly recommended *NOT* to use this gem in production (yet).
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
Add this gem to both server and client application Gemfiles:
|
17
|
+
```ruby
|
18
|
+
# Server
|
19
|
+
gem 'vodka', require: 'vodka/server'
|
20
|
+
|
21
|
+
# Client
|
22
|
+
gem 'vodka', require: 'vodka/client'
|
23
|
+
```
|
24
|
+
|
25
|
+
## Configuring server
|
26
|
+
Add initializer `vodka_setup.rb` to `config/initializers`:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
Vodka::Server.configure do |c|
|
30
|
+
c.secret = 'whatever'
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
Add vodka namespaced resources to your `config/routes.rb`
|
35
|
+
```ruby
|
36
|
+
namespace :vodka do
|
37
|
+
resources :articles do
|
38
|
+
collection { get :best }
|
39
|
+
resources :comments do
|
40
|
+
member { put :approve }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
Create controllers in `app/controllers/vodka`
|
47
|
+
```ruby
|
48
|
+
# articles_controller.rb
|
49
|
+
class ArticlesController < VodkaController
|
50
|
+
def best
|
51
|
+
respond_with_collection(Article.best)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# comments_controller.rb
|
56
|
+
class CommentsController < Vodka::Server::VodkaController
|
57
|
+
def approve
|
58
|
+
vodka_response.success = resource.approve
|
59
|
+
respond_with_resource
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
Modify your models:
|
65
|
+
```ruby
|
66
|
+
# article.rb
|
67
|
+
class Article < ActiveRecord::Base
|
68
|
+
has_many :comments
|
69
|
+
scope :best, ->{ where('rating > 100') }
|
70
|
+
validates_presence_of :title, :body
|
71
|
+
|
72
|
+
# Defines fields and actions that would be used in :as_json method
|
73
|
+
present_with :id, :title, :body, :created_at
|
74
|
+
end
|
75
|
+
|
76
|
+
# comment.rb
|
77
|
+
class Comment < ActiveRecord::Base
|
78
|
+
belongs_to :article
|
79
|
+
belongs_to :user
|
80
|
+
validates_presence_of :body
|
81
|
+
|
82
|
+
# Defines fields and actions that would be used in :as_json method
|
83
|
+
present_with :id, :body, :author_name, :created_at
|
84
|
+
|
85
|
+
def approve
|
86
|
+
update_attributes(status: 'approved')
|
87
|
+
end
|
88
|
+
|
89
|
+
def author_name
|
90
|
+
[user.first_name, user.last_name].join(' ')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
## Configuring client
|
96
|
+
Add initializer `vodka_setup.rb` to `config/initializers`:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
Vodka::Client.configure do |c|
|
100
|
+
c.api_url = 'https://api.myproject.org/vodka'
|
101
|
+
c.secret = 'whatever' # Same as server's
|
102
|
+
end
|
103
|
+
Vodka::Client.configure_her!
|
104
|
+
```
|
105
|
+
|
106
|
+
## Usage
|
107
|
+
After all the configuration is done, you can use your Her-applied models with all the new possibilities.
|
108
|
+
|
109
|
+
Vodka adds some convinient methods to client and supports them on server:
|
110
|
+
- `.create!` (throws exception on error)
|
111
|
+
- `.paginate` (same as `.all`, for WillPaginate compatibility)
|
112
|
+
- `.where` (supports chaining the way you expect)
|
113
|
+
- `#update_attribute`
|
114
|
+
- `#update_attribute!` (throws exception on error)
|
115
|
+
- `#update_attributes`
|
116
|
+
- `#update_attributes!` (throws exception on error)
|
117
|
+
- `#destroy!` (throws exception on error)
|
118
|
+
- `#delete` (acts as `#destroy`)
|
119
|
+
- `#delete!` (acts as `#destroy!`)
|
data/lib/party.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Vodka
|
2
|
+
module Client
|
3
|
+
module Middleware
|
4
|
+
class ErrorAware < Faraday::Response::Middleware
|
5
|
+
def on_complete(env)
|
6
|
+
env[:body] = MultiJson.load(env[:body]) unless env[:body].is_a?(Hash)
|
7
|
+
return unless env[:body][:errors].present? && env[:body][:errors][:vodka_error].present?
|
8
|
+
|
9
|
+
case env[:body][:errors][:vodka_error]
|
10
|
+
when ForbiddenException::MESSAGE
|
11
|
+
raise ForbiddenException.new
|
12
|
+
when NotFoundException::MESSAGE
|
13
|
+
raise NotFoundException.new
|
14
|
+
else
|
15
|
+
raise Exception.new(env[:body][:errors][:vodka_error])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Vodka
|
2
|
+
module Client
|
3
|
+
module Middleware
|
4
|
+
class SignedRequest < Faraday::Middleware
|
5
|
+
attr_reader :app, :env
|
6
|
+
|
7
|
+
def initialize(app, options = {})
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(_env)
|
12
|
+
@env = _env
|
13
|
+
|
14
|
+
env[:request_headers]['X-Request-Id'] = request_id
|
15
|
+
env[:request_headers]['X-Request-Signature'] = request_signature
|
16
|
+
env[:request_headers]['X-Response-Locale'] = I18n.locale.to_s if defined?(I18n)
|
17
|
+
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
def request_id
|
22
|
+
@request_id ||= [Time.now.to_i, (rand * 100_000_000).to_i].join(?_)
|
23
|
+
end
|
24
|
+
|
25
|
+
def request_signature
|
26
|
+
Digest::SHA512.hexdigest([
|
27
|
+
env[:url].scheme, env[:url].host, env[:url].port, env[:url].path,
|
28
|
+
request_id, Vodka::Client.config.secret
|
29
|
+
].join)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/vodka/client.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'vodka'
|
2
|
+
require 'vodka/client/exceptions/exception'
|
3
|
+
require 'vodka/client/exceptions/failed_action_exception'
|
4
|
+
require 'vodka/client/exceptions/forbidden_exception'
|
5
|
+
require 'vodka/client/exceptions/not_found_exception'
|
6
|
+
require 'vodka/client/exceptions/resource_exception'
|
7
|
+
require 'vodka/client/middleware/signed_request'
|
8
|
+
require 'vodka/client/middleware/error_aware'
|
9
|
+
require 'vodka/her/extensions/extended_orm'
|
10
|
+
require 'vodka/her/extensions/will_paginate'
|
11
|
+
|
12
|
+
module Vodka
|
13
|
+
module Client
|
14
|
+
extend Configurable
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Vodka
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :secret, :api_url
|
4
|
+
end
|
5
|
+
|
6
|
+
module Configurable
|
7
|
+
def config
|
8
|
+
@config ||= Configuration.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def configure
|
12
|
+
yield config if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
def configure_her!
|
16
|
+
::Her::API.setup(url: Vodka::Client.config.api_url) do |c|
|
17
|
+
c.use Vodka::Client::Middleware::ErrorAware
|
18
|
+
c.use Vodka::Client::Middleware::SignedRequest
|
19
|
+
c.use Faraday::Request::UrlEncoded
|
20
|
+
c.use ::Her::Middleware::SecondLevelParseJSON
|
21
|
+
c.use Faraday::Adapter::NetHttp
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Vodka
|
2
|
+
module Her
|
3
|
+
module Extensions
|
4
|
+
module ExtendedOrm
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def create!(*args)
|
9
|
+
resource = create(*args)
|
10
|
+
unless resource.errors.empty?
|
11
|
+
error = [resource.errors.keys.first, resource.errors.values.first].join(' ')
|
12
|
+
raise Vodka::Client::ResourceException.new(error)
|
13
|
+
end
|
14
|
+
|
15
|
+
resource
|
16
|
+
end
|
17
|
+
|
18
|
+
def first
|
19
|
+
resources = all(vodka_special_action: 'first')
|
20
|
+
resource = resources.first
|
21
|
+
resource.errors = resources.errors
|
22
|
+
resource.metadata = resources.metadata
|
23
|
+
resource
|
24
|
+
end
|
25
|
+
|
26
|
+
def last
|
27
|
+
resources = all(vodka_special_action: 'last')
|
28
|
+
resource = resources.first
|
29
|
+
resource.errors = resources.errors
|
30
|
+
resource.metadata = resources.metadata
|
31
|
+
resource
|
32
|
+
end
|
33
|
+
|
34
|
+
def where(*args)
|
35
|
+
@where_conditions ||= []
|
36
|
+
@where_conditions << args
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def all(params = {})
|
41
|
+
unless @where_conditions.nil?
|
42
|
+
params[:vodka_special_where] = MultiJson.dump(@where_conditions)
|
43
|
+
@where_conditions = nil
|
44
|
+
end
|
45
|
+
super(params)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def update_attributes(params)
|
50
|
+
params.each do |attribute, value|
|
51
|
+
send(:"#{attribute}=", value)
|
52
|
+
end
|
53
|
+
save
|
54
|
+
end
|
55
|
+
|
56
|
+
def update_attributes!(params)
|
57
|
+
update_attributes(params)
|
58
|
+
unless errors.empty?
|
59
|
+
error = [errors.keys.first, errors.values.first].join(' ')
|
60
|
+
raise Vodka::Client::ResourceException.new(error)
|
61
|
+
end
|
62
|
+
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def update_attribute(attribute, value)
|
67
|
+
update_attributes(attribute => value)
|
68
|
+
end
|
69
|
+
|
70
|
+
def update_attribute!(attribute, value)
|
71
|
+
update_attributes!(attribute => value)
|
72
|
+
end
|
73
|
+
|
74
|
+
def destroy!
|
75
|
+
destroy
|
76
|
+
raise Vodka::Client::FailedActionException.new('Destroy failed') if metadata[:vodka_action_success] == false
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def delete
|
81
|
+
destroy
|
82
|
+
end
|
83
|
+
|
84
|
+
def delete!
|
85
|
+
destroy!
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
Her::Model.send(:include, Vodka::Her::Extensions::ExtendedOrm)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Vodka
|
2
|
+
module Her
|
3
|
+
module Extensions
|
4
|
+
module WillPaginate
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def paginate(params)
|
9
|
+
response = all(params)
|
10
|
+
PaginatedCollection.new(response, response.metadata, response.errors)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class PaginatedCollection < ::Her::Collection
|
16
|
+
def current_page
|
17
|
+
metadata[:page].to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
def per_page
|
21
|
+
metadata[:per_page].to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def total_entries
|
25
|
+
metadata[:total].to_i
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Her::Model.send(:include, Vodka::Her::Extensions::WillPaginate)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'action_controller' unless defined?(::ActionController)
|
2
|
+
|
3
|
+
module Vodka
|
4
|
+
module Server
|
5
|
+
class VodkaController < ::ActionController::Base
|
6
|
+
include Handlers::Scaffold
|
7
|
+
include Handlers::Resource
|
8
|
+
include Handlers::Response
|
9
|
+
|
10
|
+
before_filter :fix_params_names, :set_locale
|
11
|
+
before_filter :handle_not_found, only: [:show, :update, :destroy]
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def set_locale
|
16
|
+
return unless defined?(I18n)
|
17
|
+
locale = request.headers['X-Response-Locale']
|
18
|
+
I18n.locale = locale if locale.present? && locale.to_sym.in?(I18n.available_locales)
|
19
|
+
end
|
20
|
+
|
21
|
+
def fix_params_names
|
22
|
+
params[:password] = params.delete(:buzzword) unless params[:buzzword].nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def handle_not_found
|
26
|
+
not_found if resource.nil? && vodka_response.success == false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
VodkaController = Vodka::Server::VodkaController
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Vodka
|
2
|
+
module Server
|
3
|
+
module Handlers
|
4
|
+
module Resource
|
5
|
+
private
|
6
|
+
|
7
|
+
def resource
|
8
|
+
@resource ||= extract_resource
|
9
|
+
end
|
10
|
+
|
11
|
+
def extract_resource
|
12
|
+
return unless params.has_key?(:id)
|
13
|
+
|
14
|
+
new_resource = resource_class.find_by_id(params[:id])
|
15
|
+
vodka_response.success = false if new_resource.nil?
|
16
|
+
|
17
|
+
new_resource
|
18
|
+
end
|
19
|
+
|
20
|
+
def filtered_params
|
21
|
+
params.slice(*resource_class.accessible_attributes.to_a)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Resource magick
|
25
|
+
|
26
|
+
def resource_name
|
27
|
+
self.class.name.demodulize.underscore.gsub('_controller', '').singularize
|
28
|
+
end
|
29
|
+
|
30
|
+
def resource_class
|
31
|
+
resource_name.camelcase.constantize
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Vodka
|
2
|
+
module Server
|
3
|
+
module Handlers
|
4
|
+
module Response
|
5
|
+
|
6
|
+
def vodka_response
|
7
|
+
@vodka_response ||= Vodka::Server::Response.new
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def respond_with_resource(custom_resource = nil)
|
13
|
+
vodka_response.data = custom_resource || resource
|
14
|
+
respond!
|
15
|
+
end
|
16
|
+
|
17
|
+
def respond_with_collection(resources)
|
18
|
+
vodka_response.data = resources
|
19
|
+
respond!
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond!
|
23
|
+
return render text: vodka_response.json, status: vodka_response.code, content_type: 'application/json'
|
24
|
+
end
|
25
|
+
|
26
|
+
def not_found
|
27
|
+
vodka_response.errors[:vodka_error] = '404 Not Found'
|
28
|
+
vodka_response.code = 404
|
29
|
+
respond!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Vodka
|
2
|
+
module Server
|
3
|
+
module Handlers
|
4
|
+
module Scaffold
|
5
|
+
def index
|
6
|
+
if params[:vodka_special_action] == 'first'
|
7
|
+
resources = [resource_class.first]
|
8
|
+
elsif params[:vodka_special_action] == 'last'
|
9
|
+
resources = [resource_class.last]
|
10
|
+
elsif params[:vodka_special_where].present?
|
11
|
+
resources = vodka_special_where
|
12
|
+
elsif params[:page].present? && defined?(::WillPaginate)
|
13
|
+
resources = vodka_special_paginate
|
14
|
+
else
|
15
|
+
resources = resource_class.all
|
16
|
+
end
|
17
|
+
|
18
|
+
respond_with_collection(resources)
|
19
|
+
end
|
20
|
+
|
21
|
+
def show
|
22
|
+
respond_with_resource
|
23
|
+
end
|
24
|
+
|
25
|
+
def create
|
26
|
+
respond_with_resource(resource_class.create(filtered_params))
|
27
|
+
end
|
28
|
+
|
29
|
+
def update
|
30
|
+
vodka_response.success = resource.update_attributes(filtered_params)
|
31
|
+
respond_with_resource
|
32
|
+
end
|
33
|
+
|
34
|
+
def destroy
|
35
|
+
resource.destroy
|
36
|
+
vodka_response.success = resource.destroyed?
|
37
|
+
respond_with_resource
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def vodka_special_where
|
43
|
+
relation = resource_class
|
44
|
+
conditions = MultiJson.load(params[:vodka_special_where])
|
45
|
+
conditions.each do |condition|
|
46
|
+
if condition.is_a?(Hash)
|
47
|
+
relation = relation.where(condition)
|
48
|
+
else
|
49
|
+
relation = relation.where(*condition)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
relation.all
|
53
|
+
end
|
54
|
+
|
55
|
+
def vodka_special_paginate
|
56
|
+
data = resource_class.paginate(page: params[:page], per_page: params[:per_page]).all
|
57
|
+
vodka_response.metadata = { page: data.current_page, per_page: data.per_page, total: resource_class.count }
|
58
|
+
data
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Vodka
|
2
|
+
module Server
|
3
|
+
module Middleware
|
4
|
+
class SignedRequest
|
5
|
+
attr_reader :app, :env, :request
|
6
|
+
|
7
|
+
def initialize(app, options = {})
|
8
|
+
@app, @options = app, options
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
@env = env
|
13
|
+
@request = Rack::Request.new(env)
|
14
|
+
|
15
|
+
request_signature_valid? ? app.call(env) : forbidden
|
16
|
+
end
|
17
|
+
|
18
|
+
def request_signature_valid?
|
19
|
+
env['HTTP_X_REQUEST_SIGNATURE'] == request_signature
|
20
|
+
end
|
21
|
+
|
22
|
+
def request_signature
|
23
|
+
Digest::SHA512.hexdigest([
|
24
|
+
request.scheme, request.host, request.port, request.path,
|
25
|
+
env['HTTP_X_REQUEST_ID'], Vodka::Server.config.secret
|
26
|
+
].join)
|
27
|
+
end
|
28
|
+
|
29
|
+
def forbidden
|
30
|
+
[
|
31
|
+
403,
|
32
|
+
{ 'Content-Type' => 'application/json; charset=utf-8' },
|
33
|
+
['{"data":null,"errors":{"vodka_error":"403 Forbidden"},"metadata":{}}']
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Vodka
|
2
|
+
module Server
|
3
|
+
module Plugins
|
4
|
+
module Presentable
|
5
|
+
def present_with(*methods)
|
6
|
+
define_method 'present_vodka' do
|
7
|
+
json = Hash[methods.map{ |method| [method, send(method)] }]
|
8
|
+
json[:errors] = errors.messages
|
9
|
+
json[:metadata] = {}
|
10
|
+
json
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
ActiveRecord::Base.send(:extend, Vodka::Server::Plugins::Presentable) if defined?(ActiveRecord)
|
19
|
+
MongoMapper::Document.send(:extend, Vodka::Server::Plugins::Presentable) if defined?(MongoMapper)
|
20
|
+
MongoMapper::EmbeddedDocument.send(:extend, Vodka::Server::Plugins::Presentable) if defined?(MongoMapper)
|