openshift-origin-console 1.3.2
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/COPYRIGHT +1 -0
- data/Gemfile +21 -0
- data/LICENSE +203 -0
- data/README.md +123 -0
- data/Rakefile +44 -0
- data/app/assets/images/cartridge-edge.gif +0 -0
- data/app/assets/images/console/arrow-down.png +0 -0
- data/app/assets/images/console/console-sprite.png +0 -0
- data/app/assets/images/favicon-32.png +0 -0
- data/app/assets/images/loader-dark.gif +0 -0
- data/app/assets/images/loader.gif +0 -0
- data/app/assets/images/sprite-vert.png +0 -0
- data/app/assets/javascripts/console.js +10 -0
- data/app/assets/javascripts/console/form.js.coffee +51 -0
- data/app/assets/stylesheets/_alerts.scss +84 -0
- data/app/assets/stylesheets/_breadcrumbs.scss +31 -0
- data/app/assets/stylesheets/_buttons.scss +229 -0
- data/app/assets/stylesheets/_code.scss +86 -0
- data/app/assets/stylesheets/_custom.scss +207 -0
- data/app/assets/stylesheets/_footer.scss +54 -0
- data/app/assets/stylesheets/_forms.scss +710 -0
- data/app/assets/stylesheets/_grid.scss +28 -0
- data/app/assets/stylesheets/_input-prepend-append.scss +138 -0
- data/app/assets/stylesheets/_labels.scss +40 -0
- data/app/assets/stylesheets/_mixins.scss +76 -0
- data/app/assets/stylesheets/_override-variables.scss +1 -0
- data/app/assets/stylesheets/_responsive.scss +438 -0
- data/app/assets/stylesheets/_ribbon.scss +57 -0
- data/app/assets/stylesheets/_type.scss +306 -0
- data/app/assets/stylesheets/_utilities.scss +10 -0
- data/app/assets/stylesheets/_variables.scss +131 -0
- data/app/assets/stylesheets/common.css.scss +82 -0
- data/app/assets/stylesheets/console/_application.scss +194 -0
- data/app/assets/stylesheets/console/_base.scss +26 -0
- data/app/assets/stylesheets/console/_breadcrumbs.scss +32 -0
- data/app/assets/stylesheets/console/_buttons.scss +214 -0
- data/app/assets/stylesheets/console/_core.scss +1002 -0
- data/app/assets/stylesheets/console/_dropdowns.scss +63 -0
- data/app/assets/stylesheets/console/_help.scss +54 -0
- data/app/assets/stylesheets/console/_mixins.scss +11 -0
- data/app/assets/stylesheets/console/_navbar.scss +415 -0
- data/app/assets/stylesheets/console/_ribbon.scss +82 -0
- data/app/assets/stylesheets/console/_tile.scss +122 -0
- data/app/assets/stylesheets/origin.css.scss +37 -0
- data/app/controllers/account/dashboard.rb +13 -0
- data/app/controllers/account_controller.rb +3 -0
- data/app/controllers/application_types_controller.rb +80 -0
- data/app/controllers/applications_controller.rb +183 -0
- data/app/controllers/building_controller.rb +81 -0
- data/app/controllers/capability_aware.rb +18 -0
- data/app/controllers/cartridge_types_controller.rb +53 -0
- data/app/controllers/cartridges_controller.rb +43 -0
- data/app/controllers/console/auth/basic.rb +65 -0
- data/app/controllers/console/auth/none.rb +5 -0
- data/app/controllers/console/auth/remote_user.rb +69 -0
- data/app/controllers/console/rescue.rb +48 -0
- data/app/controllers/console_controller.rb +19 -0
- data/app/controllers/console_index_controller.rb +14 -0
- data/app/controllers/domain_aware.rb +26 -0
- data/app/controllers/domain_session_sweeper.rb +29 -0
- data/app/controllers/domains_controller.rb +30 -0
- data/app/controllers/keys_controller.rb +43 -0
- data/app/controllers/scaling_controller.rb +46 -0
- data/app/controllers/sshkey_aware.rb +23 -0
- data/app/controllers/sshkey_session_sweeper.rb +29 -0
- data/app/controllers/user_session_sweeper.rb +29 -0
- data/app/helpers/console/community_helper.rb +78 -0
- data/app/helpers/console/console_helper.rb +26 -0
- data/app/helpers/console/help_helper.rb +270 -0
- data/app/helpers/console/html5_boilerplate_helper.rb +63 -0
- data/app/helpers/console/layout_helper.rb +277 -0
- data/app/helpers/console/model_helper.rb +106 -0
- data/app/helpers/console/secured_helper.rb +5 -0
- data/app/models/alias.rb +10 -0
- data/app/models/application.rb +148 -0
- data/app/models/application_associations.rb +36 -0
- data/app/models/application_template.rb +90 -0
- data/app/models/application_type.rb +258 -0
- data/app/models/async_aware.rb +60 -0
- data/app/models/capabilities.rb +62 -0
- data/app/models/cartridge.rb +122 -0
- data/app/models/cartridge_type.rb +140 -0
- data/app/models/domain.rb +44 -0
- data/app/models/domain_associations.rb +33 -0
- data/app/models/embedded.rb +11 -0
- data/app/models/gear.rb +13 -0
- data/app/models/gear_group.rb +104 -0
- data/app/models/key.rb +87 -0
- data/app/models/quickstart.rb +135 -0
- data/app/models/rest_api.rb +130 -0
- data/app/models/rest_api/base.rb +781 -0
- data/app/models/rest_api/cacheable.rb +91 -0
- data/app/models/rest_api/environment.rb +13 -0
- data/app/models/rest_api/info.rb +34 -0
- data/app/models/rest_api/log_subscriber.rb +29 -0
- data/app/models/rest_api/railties/controller_runtime.rb +37 -0
- data/app/models/user.rb +27 -0
- data/app/models/user_associations.rb +6 -0
- data/app/views/account/_domain.html.haml +14 -0
- data/app/views/account/_keys.html.haml +20 -0
- data/app/views/account/_user.html.haml +5 -0
- data/app/views/account/show.html.haml +15 -0
- data/app/views/application_templates/_application_template.html.haml +5 -0
- data/app/views/application_types/_application_type.html.haml +19 -0
- data/app/views/application_types/_custom.html.haml +19 -0
- data/app/views/application_types/_persisted.html.haml +26 -0
- data/app/views/application_types/_tile.html.haml +9 -0
- data/app/views/application_types/index.html.haml +87 -0
- data/app/views/application_types/search.html.haml +67 -0
- data/app/views/application_types/show.html.haml +219 -0
- data/app/views/applications/_application.html.haml +34 -0
- data/app/views/applications/_applications_filter.html.haml +8 -0
- data/app/views/applications/_footer.html.haml +0 -0
- data/app/views/applications/_name.html.haml +28 -0
- data/app/views/applications/delete.html.haml +19 -0
- data/app/views/applications/get_started.html.haml +145 -0
- data/app/views/applications/index.html.haml +55 -0
- data/app/views/applications/show.html.haml +193 -0
- data/app/views/building/delete.html.haml +22 -0
- data/app/views/building/new.html.haml +57 -0
- data/app/views/building/show.html.haml +12 -0
- data/app/views/cartridge_types/_cartridge_type.html.haml +61 -0
- data/app/views/cartridge_types/index.html.haml +37 -0
- data/app/views/cartridge_types/show.html.haml +21 -0
- data/app/views/cartridges/next_steps.html.haml +58 -0
- data/app/views/cartridges/show.html.haml +1 -0
- data/app/views/console/error.html.haml +58 -0
- data/app/views/console/help.html.haml +90 -0
- data/app/views/console/not_found.html.haml +69 -0
- data/app/views/console/unauthorized.html.haml +7 -0
- data/app/views/domains/_domain.html.haml +14 -0
- data/app/views/domains/_form.html.haml +13 -0
- data/app/views/domains/edit.html.haml +5 -0
- data/app/views/domains/new.html.haml +6 -0
- data/app/views/keys/_form.html.haml +14 -0
- data/app/views/keys/_simple_form.html.haml +14 -0
- data/app/views/keys/new.html.haml +2 -0
- data/app/views/layouts/_footer.html.haml +38 -0
- data/app/views/layouts/_head.html.haml +35 -0
- data/app/views/layouts/console.html.haml +60 -0
- data/app/views/layouts/console/_header.html.haml +44 -0
- data/app/views/layouts/console/_identity.html.haml +7 -0
- data/app/views/layouts/console/_javascripts.html.haml +5 -0
- data/app/views/layouts/console/_stylesheets.html.haml +6 -0
- data/app/views/scaling/delete.html.haml +17 -0
- data/app/views/scaling/new.html.haml +24 -0
- data/app/views/scaling/show.html.haml +81 -0
- data/app/views/shared/_tracking.html.haml +0 -0
- data/conf/console.conf.example +108 -0
- data/conf/openshift_console.conf +10 -0
- data/config/cartridge_types.yml +54 -0
- data/config/initializers/barista_config.rb +86 -0
- data/config/initializers/cartridge_types.rb +5 -0
- data/config/initializers/console_security.rb +1 -0
- data/config/initializers/date_helper.rb +5 -0
- data/config/initializers/extended_logger.rb +51 -0
- data/config/initializers/formtastic.rb +100 -0
- data/config/initializers/inflections.rb +38 -0
- data/config/initializers/rdiscount.rb +8 -0
- data/config/initializers/rest_api.rb +22 -0
- data/config/initializers/sass.rb +30 -0
- data/config/initializers/session_trace.rb +32 -0
- data/config/initializers/x_frame_options.rb +53 -0
- data/config/locales/en.yml +12 -0
- data/lib/active_resource/associations.rb +107 -0
- data/lib/active_resource/associations/builder/association.rb +35 -0
- data/lib/active_resource/associations/builder/belongs_to.rb +5 -0
- data/lib/active_resource/associations/builder/has_many.rb +5 -0
- data/lib/active_resource/associations/builder/has_one.rb +5 -0
- data/lib/active_resource/persistent_connection.rb +341 -0
- data/lib/active_resource/persistent_http_mock.rb +68 -0
- data/lib/active_resource/reflection.rb +78 -0
- data/lib/console.rb +8 -0
- data/lib/console/config_file.rb +13 -0
- data/lib/console/configuration.rb +163 -0
- data/lib/console/engine.rb +28 -0
- data/lib/console/formtastic/bootstrap_form_builder.rb +369 -0
- data/lib/console/rails/app_redirector.rb +40 -0
- data/lib/console/rails/filter_hash.rb +15 -0
- data/lib/console/rails/routes.rb +51 -0
- data/lib/console/version.rb +5 -0
- data/lib/tasks/assets.rake +79 -0
- data/lib/tasks/stats.rake +18 -0
- data/lib/tasks/test_suites.rake +73 -0
- data/test/coverage_helper.rb +27 -0
- data/test/fixtures/cartridges.json +1 -0
- data/test/fixtures/quickstarts.csv +3 -0
- data/test/functional/account_controller_test.rb +14 -0
- data/test/functional/application_types_controller_test.rb +251 -0
- data/test/functional/applications_controller_sanity_test.rb +26 -0
- data/test/functional/applications_controller_test.rb +365 -0
- data/test/functional/building_controller_test.rb +203 -0
- data/test/functional/cartridge_types_controller_isolation_test.rb +68 -0
- data/test/functional/cartridge_types_controller_test.rb +48 -0
- data/test/functional/cartridges_controller_test.rb +83 -0
- data/test/functional/console_auth_basic_controller_test.rb +82 -0
- data/test/functional/console_auth_remote_user_controller_test.rb +90 -0
- data/test/functional/console_index_controller_test.rb +22 -0
- data/test/functional/domains_controller_test.rb +194 -0
- data/test/functional/keys_controller_test.rb +163 -0
- data/test/functional/quickstarts.json +18 -0
- data/test/functional/scaling_controller_test.rb +153 -0
- data/test/integration/assets_test.rb +34 -0
- data/test/integration/help_link_test.rb +43 -0
- data/test/integration/quickstarts_test.rb +24 -0
- data/test/integration/rescue_from_test.rb +25 -0
- data/test/integration/rest_api/application_test.rb +115 -0
- data/test/integration/rest_api/cartridge_test.rb +44 -0
- data/test/integration/rest_api/cartridge_type_test.rb +143 -0
- data/test/integration/rest_api/domain_test.rb +91 -0
- data/test/integration/rest_api/info_test.rb +9 -0
- data/test/integration/rest_api/key_test.rb +85 -0
- data/test/integration/static_pages_test.rb +44 -0
- data/test/rails_app/Rakefile +7 -0
- data/test/rails_app/app/controllers/application_controller.rb +5 -0
- data/test/rails_app/config.ru +4 -0
- data/test/rails_app/config/application.rb +48 -0
- data/test/rails_app/config/boot.rb +10 -0
- data/test/rails_app/config/database.yml +25 -0
- data/test/rails_app/config/environment.rb +5 -0
- data/test/rails_app/config/environments/development.rb +38 -0
- data/test/rails_app/config/environments/production.rb +70 -0
- data/test/rails_app/config/environments/test.rb +43 -0
- data/test/rails_app/config/initializers/auth.rb +0 -0
- data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_app/config/initializers/inflections.rb +10 -0
- data/test/rails_app/config/initializers/mime_types.rb +5 -0
- data/test/rails_app/config/initializers/secret_token.rb +7 -0
- data/test/rails_app/config/initializers/session_store.rb +8 -0
- data/test/rails_app/config/locales/en.yml +5 -0
- data/test/rails_app/config/routes.rb +4 -0
- data/test/rails_app/script/rails +6 -0
- data/test/support/auth.rb +111 -0
- data/test/support/base.rb +142 -0
- data/test/support/errors.rb +28 -0
- data/test/support/rest_api.rb +189 -0
- data/test/test_helper.rb +14 -0
- data/test/unit/active_model_compliance_test.rb +23 -0
- data/test/unit/async_aware_test.rb +55 -0
- data/test/unit/configuration_test.rb +158 -0
- data/test/unit/filter_hash_test.rb +64 -0
- data/test/unit/helpers/model_helper_test.rb +61 -0
- data/test/unit/overrides_test.rb +9 -0
- data/test/unit/rest_api_test.rb +1590 -0
- data/vendor/assets/javascripts/MIT-LICENSE.txt +20 -0
- data/vendor/assets/javascripts/bootstrap-collapse.js +157 -0
- data/vendor/assets/javascripts/bootstrap-dropdown.js +100 -0
- data/vendor/assets/javascripts/bootstrap-tab.js +135 -0
- data/vendor/assets/javascripts/bootstrap-transition.js +61 -0
- data/vendor/assets/javascripts/jquery.spin.js +47 -0
- data/vendor/assets/javascripts/jquery.ui.widget.js +16 -0
- data/vendor/assets/javascripts/jquery_cookie.js +41 -0
- data/vendor/assets/javascripts/jquery_validate_min.js +51 -0
- data/vendor/assets/javascripts/modernizr.min.js +2 -0
- data/vendor/assets/javascripts/plugins.js +16 -0
- data/vendor/assets/stylesheets/bootstrap/_accordion.scss +28 -0
- data/vendor/assets/stylesheets/bootstrap/_alerts.scss +70 -0
- data/vendor/assets/stylesheets/bootstrap/_breadcrumbs.scss +22 -0
- data/vendor/assets/stylesheets/bootstrap/_button-groups.scss +147 -0
- data/vendor/assets/stylesheets/bootstrap/_buttons.scss +183 -0
- data/vendor/assets/stylesheets/bootstrap/_carousel.scss +121 -0
- data/vendor/assets/stylesheets/bootstrap/_close.scss +18 -0
- data/vendor/assets/stylesheets/bootstrap/_code.scss +57 -0
- data/vendor/assets/stylesheets/bootstrap/_component-animations.scss +18 -0
- data/vendor/assets/stylesheets/bootstrap/_dropdowns.scss +130 -0
- data/vendor/assets/stylesheets/bootstrap/_forms.scss +522 -0
- data/vendor/assets/stylesheets/bootstrap/_grid.scss +8 -0
- data/vendor/assets/stylesheets/bootstrap/_hero-unit.scss +20 -0
- data/vendor/assets/stylesheets/bootstrap/_labels.scss +32 -0
- data/vendor/assets/stylesheets/bootstrap/_layouts.scss +17 -0
- data/vendor/assets/stylesheets/bootstrap/_mixins.scss +602 -0
- data/vendor/assets/stylesheets/bootstrap/_modals.scss +84 -0
- data/vendor/assets/stylesheets/bootstrap/_navbar.scss +299 -0
- data/vendor/assets/stylesheets/bootstrap/_navs.scss +353 -0
- data/vendor/assets/stylesheets/bootstrap/_pager.scss +30 -0
- data/vendor/assets/stylesheets/bootstrap/_pagination.scss +55 -0
- data/vendor/assets/stylesheets/bootstrap/_popovers.scss +49 -0
- data/vendor/assets/stylesheets/bootstrap/_progress-bars.scss +95 -0
- data/vendor/assets/stylesheets/bootstrap/_reset.scss +126 -0
- data/vendor/assets/stylesheets/bootstrap/_scaffolding.scss +33 -0
- data/vendor/assets/stylesheets/bootstrap/_sprites.scss +158 -0
- data/vendor/assets/stylesheets/bootstrap/_tables.scss +150 -0
- data/vendor/assets/stylesheets/bootstrap/_thumbnails.scss +35 -0
- data/vendor/assets/stylesheets/bootstrap/_tooltip.scss +35 -0
- data/vendor/assets/stylesheets/bootstrap/_type.scss +218 -0
- data/vendor/assets/stylesheets/bootstrap/_utilities.scss +23 -0
- data/vendor/assets/stylesheets/bootstrap/_variables.scss +107 -0
- data/vendor/assets/stylesheets/bootstrap/_wells.scss +17 -0
- data/vendor/assets/stylesheets/bootstrap/bootstrap.scss +66 -0
- data/vendor/assets/stylesheets/bootstrap/responsive.scss +334 -0
- metadata +506 -0
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
require 'active_support/core_ext/hash/conversions'
|
|
2
|
+
require 'active_resource'
|
|
3
|
+
require 'active_resource/associations'
|
|
4
|
+
require 'active_resource/reflection'
|
|
5
|
+
require 'active_support/concern'
|
|
6
|
+
require 'active_model/dirty'
|
|
7
|
+
require 'active_resource/persistent_connection'
|
|
8
|
+
|
|
9
|
+
class ActiveResource::Connection
|
|
10
|
+
#
|
|
11
|
+
# Changes made in commit https://github.com/rails/rails/commit/51f1f550dab47c6ec3dcdba7b153258e2a0feb69#activeresource/lib/active_resource/base.rb
|
|
12
|
+
# make GET consistent with other verbs (return response)
|
|
13
|
+
#
|
|
14
|
+
def get(path, headers = {})
|
|
15
|
+
with_auth { request(:get, path, build_request_headers(headers, :get, self.site.merge(path))) } #changed, remove .body at end, removed format decode
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
#
|
|
19
|
+
# Allow integrated debugging
|
|
20
|
+
#
|
|
21
|
+
def new_http
|
|
22
|
+
http = if @proxy
|
|
23
|
+
Net::HTTP.new(@site.host, @site.port, @proxy.host, @proxy.port, @proxy.user, @proxy.password)
|
|
24
|
+
else
|
|
25
|
+
Net::HTTP.new(@site.host, @site.port)
|
|
26
|
+
end
|
|
27
|
+
Rails.logger.debug "Connecting to #{@site}"
|
|
28
|
+
http.set_debug_output $stderr if RestApi.debug?
|
|
29
|
+
http
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# ActiveResource association support
|
|
35
|
+
#
|
|
36
|
+
class ActiveResource::Base
|
|
37
|
+
extend ActiveResource::Associations
|
|
38
|
+
include ActiveResource::Reflection
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
def find_or_create_resource_for_collection(name)
|
|
42
|
+
return reflections[name.to_sym].klass if reflections.key?(name.to_sym)
|
|
43
|
+
find_or_create_resource_for(ActiveSupport::Inflector.singularize(name.to_s))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def find_or_create_resource_for(name)
|
|
47
|
+
# also sanitize names with dashes
|
|
48
|
+
name = name.to_s.gsub(/[^\w\:]/, '_')
|
|
49
|
+
# association support
|
|
50
|
+
return reflections[name.to_sym].klass if reflections.key?(name.to_sym)
|
|
51
|
+
|
|
52
|
+
resource_name = name.to_s.camelize
|
|
53
|
+
ancestors = self.class.name.split("::")
|
|
54
|
+
if ancestors.size > 1
|
|
55
|
+
find_resource_in_modules(resource_name, ancestors)
|
|
56
|
+
else
|
|
57
|
+
self.class.const_get(resource_name)
|
|
58
|
+
end
|
|
59
|
+
rescue NameError => e
|
|
60
|
+
begin
|
|
61
|
+
if self.class.const_defined?(resource_name)
|
|
62
|
+
resource = self.class.const_get(resource_name)
|
|
63
|
+
else
|
|
64
|
+
resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base))
|
|
65
|
+
end
|
|
66
|
+
rescue NameError # invalid constant name (starting by number for example)
|
|
67
|
+
resource_name = 'Constant' + resource_name
|
|
68
|
+
resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base))
|
|
69
|
+
end
|
|
70
|
+
resource.prefix = self.class.prefix_source
|
|
71
|
+
resource.site = self.class.site
|
|
72
|
+
resource
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
module RestApi
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# The OpenShift REST API wraps the root resource element which must
|
|
80
|
+
# be unwrapped.
|
|
81
|
+
#
|
|
82
|
+
class OpenshiftJsonFormat
|
|
83
|
+
include ActiveResource::Formats::JsonFormat
|
|
84
|
+
|
|
85
|
+
def initialize(*args)
|
|
86
|
+
@root_attrs = args
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def decode(json)
|
|
90
|
+
decoded = ActiveSupport::JSON.decode(json)
|
|
91
|
+
if decoded.is_a?(Hash) and decoded.has_key?('data')
|
|
92
|
+
attrs = root_attributes(decoded)
|
|
93
|
+
decoded = decoded['data'] || {}
|
|
94
|
+
end
|
|
95
|
+
if decoded.is_a? Array
|
|
96
|
+
decoded.map!{ |obj| delink(obj, attrs) }
|
|
97
|
+
else
|
|
98
|
+
delink(decoded, attrs)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def delink(obj, attrs)
|
|
103
|
+
obj = obj.values.first if obj.is_a?(Hash) && obj.length == 1 && obj.values.first.is_a?(Hash)
|
|
104
|
+
if obj.is_a? Hash
|
|
105
|
+
obj.delete 'links'
|
|
106
|
+
obj.merge!(attrs) if attrs
|
|
107
|
+
end
|
|
108
|
+
obj
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def root_attributes(hash)
|
|
112
|
+
hash.slice('messages', *@root_attrs)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
class Base < ActiveResource::Base
|
|
117
|
+
include ActiveModel::Dirty
|
|
118
|
+
include ActiveModel::MassAssignmentSecurity
|
|
119
|
+
include RestApi::Cacheable
|
|
120
|
+
|
|
121
|
+
# Exclude the root from JSON
|
|
122
|
+
self.include_root_in_json = false
|
|
123
|
+
|
|
124
|
+
#
|
|
125
|
+
# Connection properties
|
|
126
|
+
#
|
|
127
|
+
# Note: Only subclasses that share this format will reuse
|
|
128
|
+
# connections (allowing HTTP 1.1 persistent connections)
|
|
129
|
+
#
|
|
130
|
+
self.format = OpenshiftJsonFormat.new
|
|
131
|
+
|
|
132
|
+
#
|
|
133
|
+
# ActiveResource doesn't have a hierarchy for headers
|
|
134
|
+
#
|
|
135
|
+
class << self
|
|
136
|
+
def headers
|
|
137
|
+
@headers ||= begin
|
|
138
|
+
(superclass != ActiveResource::Base) ? superclass.headers.dup : {}
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
class_attribute :idle_timeout, :read_timeout, :open_timeout
|
|
144
|
+
|
|
145
|
+
#
|
|
146
|
+
# ActiveResource doesn't fully support alias_attribute
|
|
147
|
+
#
|
|
148
|
+
class << self
|
|
149
|
+
def alias_attribute(from, to)
|
|
150
|
+
aliased_attributes[from] = to
|
|
151
|
+
|
|
152
|
+
define_method :"#{from}" do
|
|
153
|
+
self.send :"#{to}"
|
|
154
|
+
end
|
|
155
|
+
define_method :"#{from}?" do
|
|
156
|
+
self.send :"#{to}?"
|
|
157
|
+
end
|
|
158
|
+
define_method :"#{from}=" do |val|
|
|
159
|
+
self.send :"#{to}=", val
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
def aliased_attributes
|
|
163
|
+
@aliased_attributes ||= {}
|
|
164
|
+
end
|
|
165
|
+
def attr_alters(from, *args)
|
|
166
|
+
targets = (calculated_attributes[from] ||= [])
|
|
167
|
+
targets.concat(args.flatten.uniq)
|
|
168
|
+
define_attribute_method from
|
|
169
|
+
end
|
|
170
|
+
def calculated_attributes
|
|
171
|
+
@calculated_attributes ||= {}
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
#
|
|
176
|
+
# Ensure user authorization info is duplicated
|
|
177
|
+
#
|
|
178
|
+
def dup
|
|
179
|
+
super.tap do |resource|
|
|
180
|
+
resource.as = @as
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
#
|
|
185
|
+
# Ensure Fixnums and booleans can be cloned
|
|
186
|
+
#
|
|
187
|
+
def clone
|
|
188
|
+
# Clone all attributes except the pk and any nested ARes
|
|
189
|
+
cloned = Hash[attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.map { |k, v| [k, v.duplicable? ? v.clone : v] }]
|
|
190
|
+
# Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
|
|
191
|
+
# attempts to convert hashes into member objects and arrays into collections of objects. We want
|
|
192
|
+
# the raw objects to be cloned so we bypass load by directly setting the attributes hash.
|
|
193
|
+
resource = self.class.new({})
|
|
194
|
+
resource.prefix_options = self.prefix_options
|
|
195
|
+
resource.send :instance_variable_set, '@attributes', cloned
|
|
196
|
+
resource.as = @as # not an attribute
|
|
197
|
+
resource
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def initialize(attributes = {}, persisted=false)
|
|
201
|
+
@as = attributes.delete :as
|
|
202
|
+
super attributes, persisted
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def load(attributes, remove_root=false)
|
|
206
|
+
raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
|
|
207
|
+
self.prefix_options, attributes = split_options(attributes)
|
|
208
|
+
|
|
209
|
+
attributes = attributes.dup
|
|
210
|
+
aliased = self.class.aliased_attributes
|
|
211
|
+
calculated = self.class.calculated_attributes
|
|
212
|
+
known = self.class.known_attributes
|
|
213
|
+
|
|
214
|
+
aliased.each do |from,to|
|
|
215
|
+
value = attributes.delete(from)
|
|
216
|
+
send("#{to}=", value) unless value.nil?
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
attributes.each do |key, value|
|
|
220
|
+
#Rails.logger.debug "Found nil key when deserializing #{attributes.inspect}" if key.nil?
|
|
221
|
+
if !known.include? key.to_s and !calculated.include? key and respond_to?("#{key}=")
|
|
222
|
+
send("#{key}=", value)
|
|
223
|
+
else
|
|
224
|
+
self.attributes[key.to_s] =
|
|
225
|
+
case value
|
|
226
|
+
when Array
|
|
227
|
+
resource = nil
|
|
228
|
+
value.map do |attrs|
|
|
229
|
+
if attrs.is_a?(Hash)
|
|
230
|
+
resource ||= find_or_create_resource_for_collection(key)
|
|
231
|
+
attrs[:as] = as if resource.method_defined? :as=
|
|
232
|
+
resource.new(attrs)
|
|
233
|
+
else
|
|
234
|
+
attrs.duplicable? ? attrs.dup : attrs
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
when Hash
|
|
238
|
+
resource = find_or_create_resource_for(key)
|
|
239
|
+
value[:as] = as if resource.method_defined? :as=
|
|
240
|
+
resource.new(value)
|
|
241
|
+
else
|
|
242
|
+
value.duplicable? ? value.dup : value
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
calculated.each_key { |key| send("#{key}=", attributes[key]) if attributes.include?(key) }
|
|
248
|
+
@changed_attributes.clear if @changed_attributes
|
|
249
|
+
self
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def attributes=(attrs)
|
|
253
|
+
attrs.with_indifferent_access.slice(*(
|
|
254
|
+
self.class.known_attributes +
|
|
255
|
+
self.class.aliased_attributes.keys
|
|
256
|
+
)).each_pair do |k,v|
|
|
257
|
+
send(:"#{k}=", v)
|
|
258
|
+
end
|
|
259
|
+
self
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def raise_on_invalid
|
|
263
|
+
(errors.instance_variable_get(:@codes) || {}).values.flatten(1).compact.uniq.each do |code|
|
|
264
|
+
exc = self.class.exception_for_code(code, :on_invalid)
|
|
265
|
+
raise exc.new(self) if exc
|
|
266
|
+
end
|
|
267
|
+
raise(ActiveResource::ResourceInvalid.new(self))
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def save!
|
|
271
|
+
save || raise_on_invalid
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def save_with_change_tracking(*args, &block)
|
|
275
|
+
save_without_change_tracking(*args, &block).tap do |valid|
|
|
276
|
+
if valid
|
|
277
|
+
@previously_changed = changes
|
|
278
|
+
@changed_attributes.clear
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
rescue ActiveResource::ConnectionError => error
|
|
283
|
+
# if the server returns a body that has messages, filter them through
|
|
284
|
+
# the error handler. If one or more errors were set, assume that the message
|
|
285
|
+
# is more useful than the exception and return false. Otherwise throw as ActiveResource
|
|
286
|
+
# would
|
|
287
|
+
raise unless set_remote_errors(error, true)
|
|
288
|
+
end
|
|
289
|
+
alias_method_chain :save, :change_tracking
|
|
290
|
+
|
|
291
|
+
# Copy calculated attribute errors
|
|
292
|
+
def valid?
|
|
293
|
+
super.tap { |valid| duplicate_errors unless valid }
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def duplicate_errors
|
|
297
|
+
self.class.calculated_attributes.each_pair do |from, attrs|
|
|
298
|
+
attrs.each do |to|
|
|
299
|
+
(errors[to] || []).each do |error|
|
|
300
|
+
errors.add(from, error) unless errors.has_key?(from) && errors[:from].include?(error)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
self.class.aliased_attributes.each_pair do |from, to|
|
|
305
|
+
(errors[to] || []).each do |error|
|
|
306
|
+
errors.add(from, error) unless errors.has_key?(from) && errors[:from].include?(error)
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
class << self
|
|
312
|
+
def custom_id(name, mutable=false)
|
|
313
|
+
raise "Name #{name.inspect} must be a symbol" unless name.is_a?(Symbol) && !name.is_a?(Class)
|
|
314
|
+
|
|
315
|
+
define_attribute_method name
|
|
316
|
+
|
|
317
|
+
define_method :"#{name}=" do |s|
|
|
318
|
+
send(:"#{name}_will_change!") if !send(:"#{name}_changed?") && attributes[name] != s
|
|
319
|
+
attributes[name] = s
|
|
320
|
+
end
|
|
321
|
+
define_method 'to_key' do
|
|
322
|
+
persisted? ? [send(:"#{name}_was") || send(name)] : nil
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
#
|
|
328
|
+
# singleton support as https://rails.lighthouseapp.com/projects/8994/tickets/4348-supporting-singleton-resources-in-activeresource
|
|
329
|
+
#
|
|
330
|
+
class << self
|
|
331
|
+
attr_accessor :collection_name
|
|
332
|
+
def collection_name
|
|
333
|
+
@collection_name ||= begin
|
|
334
|
+
if singleton?
|
|
335
|
+
element_name
|
|
336
|
+
else
|
|
337
|
+
ActiveSupport::Inflector.pluralize(element_name)
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def element_path(id = nil, prefix_options = {}, query_options = nil) #changed
|
|
343
|
+
check_prefix_options(prefix_options)
|
|
344
|
+
|
|
345
|
+
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
|
346
|
+
|
|
347
|
+
#begin changes
|
|
348
|
+
path = "#{prefix(prefix_options)}#{collection_name}"
|
|
349
|
+
unless singleton?
|
|
350
|
+
raise ArgumentError, "id is required for non-singleton resources #{self}" if id.nil?
|
|
351
|
+
path << "/#{URI.parser.escape id.to_s}"
|
|
352
|
+
end
|
|
353
|
+
path << ".#{format.extension}#{query_string(query_options)}"
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def find(*arguments)
|
|
357
|
+
|
|
358
|
+
scope = arguments.slice!(0)
|
|
359
|
+
options = arguments.slice!(0) || {}
|
|
360
|
+
|
|
361
|
+
scope = :one if scope.nil? && singleton? # added
|
|
362
|
+
|
|
363
|
+
case scope
|
|
364
|
+
when :all then find_every(options)
|
|
365
|
+
when :first then find_every(options).first
|
|
366
|
+
when :last then find_every(options).last
|
|
367
|
+
when :one then find_one(options)
|
|
368
|
+
else find_single(scope, options)
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def find_one(options)
|
|
373
|
+
as = options[:as] # for user context support
|
|
374
|
+
|
|
375
|
+
case from = options[:from]
|
|
376
|
+
when Symbol
|
|
377
|
+
instantiate_record(get(from, options[:params]))
|
|
378
|
+
when String
|
|
379
|
+
path = "#{from}#{query_string(options[:params])}"
|
|
380
|
+
instantiate_record(format.decode(connection(options).get(path, headers).body), as) #changed
|
|
381
|
+
when nil #begin add
|
|
382
|
+
prefix_options, query_options = split_options(options[:params])
|
|
383
|
+
path = element_path(nil, prefix_options, query_options)
|
|
384
|
+
instantiate_record(format.decode(connection(options).get(path, headers).body), as) #end add
|
|
385
|
+
end
|
|
386
|
+
rescue ActiveResource::ResourceNotFound => e
|
|
387
|
+
raise ResourceNotFound.new(self.model_name, nil, e.response)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def allow_anonymous?
|
|
391
|
+
self.anonymous_api?
|
|
392
|
+
end
|
|
393
|
+
def singleton?
|
|
394
|
+
self.singleton_api?
|
|
395
|
+
end
|
|
396
|
+
def use_patch_on_update?
|
|
397
|
+
self.use_patch_api?
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
protected
|
|
401
|
+
def allow_anonymous
|
|
402
|
+
self.anonymous_api = true
|
|
403
|
+
end
|
|
404
|
+
def singleton
|
|
405
|
+
self.singleton_api = true
|
|
406
|
+
end
|
|
407
|
+
def use_patch_on_update
|
|
408
|
+
self.use_patch_api = true
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
#
|
|
413
|
+
# Must provide OpenShift compatible error decoding
|
|
414
|
+
#
|
|
415
|
+
def self.remote_errors_for(response)
|
|
416
|
+
format.decode(response.body)['messages'].map do |m|
|
|
417
|
+
[(m['exit_code'].to_i rescue m['exit_code']),
|
|
418
|
+
m['field'],
|
|
419
|
+
m['text'],
|
|
420
|
+
]
|
|
421
|
+
end rescue []
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def load_remote_errors(remote_errors, save_cache=false, optional=false)
|
|
425
|
+
begin
|
|
426
|
+
self.class.remote_errors_for(remote_errors.response).each do |m|
|
|
427
|
+
self.class.translate_api_error(errors, *m)
|
|
428
|
+
end
|
|
429
|
+
Rails.logger.debug " Found errors on the response object: #{errors.to_hash.inspect}"
|
|
430
|
+
duplicate_errors
|
|
431
|
+
rescue ActiveResource::ConnectionError
|
|
432
|
+
raise
|
|
433
|
+
rescue Exception => e
|
|
434
|
+
Rails.logger.warn e
|
|
435
|
+
Rails.logger.warn e.backtrace
|
|
436
|
+
msg = if defined? response
|
|
437
|
+
Rails.logger.warn "Unable to read server response, #{response.inspect}"
|
|
438
|
+
Rails.logger.warn " Body: #{response.body.inspect}" if defined? response.body
|
|
439
|
+
defined?(response.body) ? response.body.to_s : 'No response body from server'
|
|
440
|
+
else
|
|
441
|
+
'No response object'
|
|
442
|
+
end
|
|
443
|
+
raise RestApi::BadServerResponseError, msg, $@ unless optional
|
|
444
|
+
end
|
|
445
|
+
optional ? !errors.empty? : errors
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
class AttributeHash < Hash
|
|
449
|
+
def initialize(hash)
|
|
450
|
+
hash.each_pair{ |k,v| self[k] = v }
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
has_many :messages, :class_name => 'rest_api/base/attribute_hash'
|
|
454
|
+
|
|
455
|
+
#FIXME may be refactored
|
|
456
|
+
def remote_results
|
|
457
|
+
(attributes[:messages] || []).select{ |m| m['field'] == 'result' }.map{ |m| m['text'].presence }.compact
|
|
458
|
+
end
|
|
459
|
+
def has_exit_code?(code, opts=nil)
|
|
460
|
+
codes = errors.instance_variable_get(:@codes) || {}
|
|
461
|
+
if opts && opts[:on]
|
|
462
|
+
(codes[opts[:on].to_sym] || []).include? code
|
|
463
|
+
else
|
|
464
|
+
codes.values.any?{ |c| c.include? code }
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
class << self
|
|
469
|
+
def on_exit_code(code, handles=nil, &block)
|
|
470
|
+
(@exit_code_conditions ||= {})[code] = handles || block
|
|
471
|
+
end
|
|
472
|
+
def translate_api_error(errors, code, field, text)
|
|
473
|
+
Rails.logger.debug " Server error: :#{field} \##{code}: #{text}"
|
|
474
|
+
if @exit_code_conditions
|
|
475
|
+
handler = @exit_code_conditions[code]
|
|
476
|
+
handler = handler[:raise] if Hash === handler
|
|
477
|
+
case handler
|
|
478
|
+
when Proc then return if handler.call errors, code, field, text
|
|
479
|
+
when Class then raise handler, text
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
message = I18n.t(code, :scope => [:rest_api, :errors], :default => text.to_s)
|
|
483
|
+
field = (field || 'base').to_sym
|
|
484
|
+
errors.add(field, message) unless message.blank?
|
|
485
|
+
|
|
486
|
+
codes = errors.instance_variable_get(:@codes)
|
|
487
|
+
codes = errors.instance_variable_set(:@codes, {}) unless codes
|
|
488
|
+
(codes[field] ||= []).push(code)
|
|
489
|
+
end
|
|
490
|
+
def exception_for_code(code, type=nil)
|
|
491
|
+
if @exit_code_conditions
|
|
492
|
+
handler = @exit_code_conditions[code]
|
|
493
|
+
handler = handler[type] if type && Hash === handler
|
|
494
|
+
handler
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
#
|
|
501
|
+
# Override method from CustomMethods to handle body objects
|
|
502
|
+
#
|
|
503
|
+
def get(custom_method_name, options = {})
|
|
504
|
+
self.class.send(:instantiate_collection, self.class.format.decode(connection.get(custom_method_element_url(custom_method_name, options), self.class.headers).body), as, prefix_options ) #changed
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
#
|
|
508
|
+
# Override methods from ActiveResource to make them contextual connection
|
|
509
|
+
# aware
|
|
510
|
+
#
|
|
511
|
+
def reload
|
|
512
|
+
self.load(prefix_options.merge(self.class.find(to_param, :params => prefix_options, :as => as).attributes))
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
class << self
|
|
516
|
+
def get(custom_method_name, options = {}, call_options = {})
|
|
517
|
+
connection(call_options).get(custom_method_collection_url(custom_method_name, options), headers)
|
|
518
|
+
end
|
|
519
|
+
def delete(id, options = {})
|
|
520
|
+
connection(options).delete(element_path(id, options)) #changed
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
#
|
|
524
|
+
# Make connection specific to the instance, and aware of user context
|
|
525
|
+
#
|
|
526
|
+
def connection(options = {}, refresh = false)
|
|
527
|
+
c = shared_connection(options, refresh)
|
|
528
|
+
if options[:as]
|
|
529
|
+
UserAwareConnection.new(c, options[:as])
|
|
530
|
+
elsif allow_anonymous?
|
|
531
|
+
c
|
|
532
|
+
else
|
|
533
|
+
raise RestApi::MissingAuthorizationError
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
def shared_connection(options = {}, refresh = false)
|
|
538
|
+
if defined?(@connection) || _format != superclass._format || superclass == Object || superclass == ActiveResource::Base
|
|
539
|
+
@connection = update_connection(ActiveResource::PersistentConnection.new(site, format)) if refresh || @connection.nil?
|
|
540
|
+
@connection
|
|
541
|
+
else
|
|
542
|
+
superclass.shared_connection(options, refresh)
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
protected
|
|
547
|
+
def find_single(scope, options)
|
|
548
|
+
prefix_options, query_options = split_options(options[:params])
|
|
549
|
+
path = element_path(scope, prefix_options, query_options)
|
|
550
|
+
instantiate_record(format.decode(connection(options).get(path, headers).body), options[:as], prefix_options) #changed
|
|
551
|
+
rescue ActiveResource::ResourceNotFound => e
|
|
552
|
+
raise ResourceNotFound.new(self.model_name, scope, e.response)
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
def find_every(options)
|
|
556
|
+
begin
|
|
557
|
+
as = options[:as]
|
|
558
|
+
case from = options[:from]
|
|
559
|
+
when Symbol
|
|
560
|
+
instantiate_collection(format.decode(get(from, options[:params], options).body), as) #changed
|
|
561
|
+
when String
|
|
562
|
+
path = "#{from}#{query_string(options[:params])}"
|
|
563
|
+
instantiate_collection(format.decode(connection(options).get(path, headers).body) || [], as) #changed
|
|
564
|
+
else
|
|
565
|
+
prefix_options, query_options = split_options(options[:params])
|
|
566
|
+
path = collection_path(prefix_options, query_options)
|
|
567
|
+
instantiate_collection(format.decode(connection(options).get(path, headers).body) || [], as, prefix_options ) #changed
|
|
568
|
+
end
|
|
569
|
+
rescue ActiveResource::ResourceNotFound => e
|
|
570
|
+
rescue_parent_missing(e, options)
|
|
571
|
+
# changed to return empty array on not found
|
|
572
|
+
# Swallowing ResourceNotFound exceptions and return nil - as per
|
|
573
|
+
# ActiveRecord.
|
|
574
|
+
[] #changed
|
|
575
|
+
end
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
def rescue_parent_missing(e, options)
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
private
|
|
582
|
+
def update_connection(connection)
|
|
583
|
+
connection.proxy = proxy if proxy
|
|
584
|
+
connection.user = user if user
|
|
585
|
+
connection.password = password if password
|
|
586
|
+
connection.auth_type = auth_type if auth_type
|
|
587
|
+
[:timeout, :idle_timeout, :read_timeout, :open_timeout].each do |sym|
|
|
588
|
+
connection.send(:"#{sym}=", send(sym)) if send(sym)
|
|
589
|
+
end
|
|
590
|
+
connection.ssl_options = ssl_options if ssl_options
|
|
591
|
+
connection.connection_name = 'rest_api'
|
|
592
|
+
connection.debug_output = $stderr if RestApi.debug?
|
|
593
|
+
connection
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
def instantiate_collection(collection, as, prefix_options = {}) #changed
|
|
597
|
+
collection.collect! { |record| instantiate_record(record, as, prefix_options) } #changed
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
def instantiate_record(record, as, prefix_options = {}) #changed
|
|
601
|
+
record[:as] = as # changed - called before new so that nested resources are created
|
|
602
|
+
new(record, true).tap do |resource| #changed for persisted flag
|
|
603
|
+
resource.prefix_options = prefix_options
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
#
|
|
609
|
+
# The user under whose context we will be accessing the remote server
|
|
610
|
+
#
|
|
611
|
+
def as
|
|
612
|
+
@as
|
|
613
|
+
end
|
|
614
|
+
def as=(as)
|
|
615
|
+
@connection = nil
|
|
616
|
+
@as = as
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
def to_json(options={})
|
|
620
|
+
super({:root => nil}.merge(options))
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
#
|
|
624
|
+
# Default mass assignment support
|
|
625
|
+
#
|
|
626
|
+
def assign_attributes(values, options = {})
|
|
627
|
+
sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
|
|
628
|
+
send("#{k}=", v)
|
|
629
|
+
end
|
|
630
|
+
self
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
protected
|
|
634
|
+
|
|
635
|
+
# Support patch
|
|
636
|
+
def update
|
|
637
|
+
connection.send(self.class.use_patch_on_update? ? :patch : :put, element_path(prefix_options), encode, self.class.headers).tap do |response|
|
|
638
|
+
load_attributes_from_response(response)
|
|
639
|
+
end
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
def load_attributes_from_response(response)
|
|
643
|
+
if (response_code_allows_body?(response.code) &&
|
|
644
|
+
(response['Content-Length'].nil? || response['Content-Length'] != "0") &&
|
|
645
|
+
!response.body.nil? && response.body.strip.size > 0)
|
|
646
|
+
load(prefix_options.merge(self.class.format.decode(response.body)), true)
|
|
647
|
+
@persisted = true
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
#
|
|
652
|
+
# Drupal 6 doesn't correctly encode JSON, and some non-HTML content needs to be
|
|
653
|
+
# decoded.
|
|
654
|
+
#
|
|
655
|
+
def entity_decoded(s)
|
|
656
|
+
if s && (s.include?('&#') || s.include?('"'))
|
|
657
|
+
CGI.unescapeHTML(s)
|
|
658
|
+
else
|
|
659
|
+
s
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
def connection(refresh = false)
|
|
664
|
+
@connection = nil if refresh
|
|
665
|
+
@connection ||= self.class.connection({:as => as})
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
# Helper to avoid subclasses forgetting to set @remote_errors
|
|
669
|
+
def set_remote_errors(error, optional=false)
|
|
670
|
+
@remote_errors = error
|
|
671
|
+
load_remote_errors(@remote_errors, true, optional)
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
class_attribute :anonymous_api, :instance_writer => false
|
|
675
|
+
class_attribute :singleton_api, :instance_writer => false
|
|
676
|
+
class_attribute :use_patch_api, :instance_writer => false
|
|
677
|
+
|
|
678
|
+
# supports presence of AttributeMethods and Dirty
|
|
679
|
+
def attribute(s)
|
|
680
|
+
#puts "attribute[#{s}] #{caller.join(" \n")}"
|
|
681
|
+
attributes[s]
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
def method_missing(method_symbol, *arguments) #:nodoc:
|
|
685
|
+
#puts "in method missing of RestApi::Base #{method_symbol}"
|
|
686
|
+
method_name = method_symbol.to_s
|
|
687
|
+
|
|
688
|
+
if method_name =~ /(=|\?)$/
|
|
689
|
+
case $1
|
|
690
|
+
when "="
|
|
691
|
+
res = :"#{method_name}_will_change!"
|
|
692
|
+
send(res) if respond_to?(res) && attributes[name] != arguments.first
|
|
693
|
+
attributes[$`] = arguments.first
|
|
694
|
+
when "?"
|
|
695
|
+
attributes[$`]
|
|
696
|
+
end
|
|
697
|
+
else
|
|
698
|
+
return attributes[method_name] if attributes.include?(method_name)
|
|
699
|
+
# not set right now but we know about it
|
|
700
|
+
return nil if known_attributes.include?(method_name)
|
|
701
|
+
super
|
|
702
|
+
end
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
#
|
|
707
|
+
# A connection class that contains an authorization object to connect as
|
|
708
|
+
#
|
|
709
|
+
class UserAwareConnection < ActiveResource::PersistentConnection
|
|
710
|
+
|
|
711
|
+
# The authorization context
|
|
712
|
+
attr_reader :as
|
|
713
|
+
|
|
714
|
+
def initialize(connection, as)
|
|
715
|
+
super connection.site, connection.format
|
|
716
|
+
@connection = connection
|
|
717
|
+
@as = as
|
|
718
|
+
unless @as.respond_to? :to_headers
|
|
719
|
+
@user = @as.login if @as.respond_to? :login
|
|
720
|
+
@password = @as.password if @as.respond_to? :password
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
def authorization_header(http_method, uri)
|
|
725
|
+
headers = super
|
|
726
|
+
if @as.respond_to? :to_headers
|
|
727
|
+
headers.merge!(@as.to_headers)
|
|
728
|
+
elsif @as.respond_to? :ticket and @as.ticket
|
|
729
|
+
(headers['Cookie'] ||= '') << "rh_sso=#{@as.ticket}"
|
|
730
|
+
end
|
|
731
|
+
headers
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
def http
|
|
735
|
+
@connection.send(:http)
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
class Base
|
|
740
|
+
self.idle_timeout = 4
|
|
741
|
+
self.open_timeout = 3
|
|
742
|
+
self.read_timeout = 180
|
|
743
|
+
|
|
744
|
+
#
|
|
745
|
+
# Update the configuration of the Rest API. Use instead of
|
|
746
|
+
# setting static variables directly.
|
|
747
|
+
#
|
|
748
|
+
def self.configuration=(config)
|
|
749
|
+
return if @last_config == config
|
|
750
|
+
|
|
751
|
+
url = URI.parse(config[:url])
|
|
752
|
+
path = url.path
|
|
753
|
+
if path[-1..1] == '/'
|
|
754
|
+
url.path = path[0..-2]
|
|
755
|
+
else
|
|
756
|
+
path = "#{path}/"
|
|
757
|
+
end
|
|
758
|
+
|
|
759
|
+
self.site = url.to_s
|
|
760
|
+
self.prefix = path
|
|
761
|
+
|
|
762
|
+
[:ssl_options, :idle_timeout, :read_timeout, :open_timeout].each do |sym|
|
|
763
|
+
self.send(:"#{sym}=", config[sym]) if config[sym]
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
self.headers.delete 'User-Agent'
|
|
767
|
+
self.headers['User-Agent'] = config[:user_agent] if config[:user_agent]
|
|
768
|
+
|
|
769
|
+
self.proxy = if config[:proxy] == 'ENV'
|
|
770
|
+
:ENV
|
|
771
|
+
elsif config[:proxy]
|
|
772
|
+
URI config[:proxy]
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
@last_config = config
|
|
776
|
+
@info = false
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
RestApi::Base.configuration = Console.config.api
|