openshift-origin-console 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (291) hide show
  1. data/COPYRIGHT +1 -0
  2. data/Gemfile +21 -0
  3. data/LICENSE +203 -0
  4. data/README.md +123 -0
  5. data/Rakefile +44 -0
  6. data/app/assets/images/cartridge-edge.gif +0 -0
  7. data/app/assets/images/console/arrow-down.png +0 -0
  8. data/app/assets/images/console/console-sprite.png +0 -0
  9. data/app/assets/images/favicon-32.png +0 -0
  10. data/app/assets/images/loader-dark.gif +0 -0
  11. data/app/assets/images/loader.gif +0 -0
  12. data/app/assets/images/sprite-vert.png +0 -0
  13. data/app/assets/javascripts/console.js +10 -0
  14. data/app/assets/javascripts/console/form.js.coffee +51 -0
  15. data/app/assets/stylesheets/_alerts.scss +84 -0
  16. data/app/assets/stylesheets/_breadcrumbs.scss +31 -0
  17. data/app/assets/stylesheets/_buttons.scss +229 -0
  18. data/app/assets/stylesheets/_code.scss +86 -0
  19. data/app/assets/stylesheets/_custom.scss +207 -0
  20. data/app/assets/stylesheets/_footer.scss +54 -0
  21. data/app/assets/stylesheets/_forms.scss +710 -0
  22. data/app/assets/stylesheets/_grid.scss +28 -0
  23. data/app/assets/stylesheets/_input-prepend-append.scss +138 -0
  24. data/app/assets/stylesheets/_labels.scss +40 -0
  25. data/app/assets/stylesheets/_mixins.scss +76 -0
  26. data/app/assets/stylesheets/_override-variables.scss +1 -0
  27. data/app/assets/stylesheets/_responsive.scss +438 -0
  28. data/app/assets/stylesheets/_ribbon.scss +57 -0
  29. data/app/assets/stylesheets/_type.scss +306 -0
  30. data/app/assets/stylesheets/_utilities.scss +10 -0
  31. data/app/assets/stylesheets/_variables.scss +131 -0
  32. data/app/assets/stylesheets/common.css.scss +82 -0
  33. data/app/assets/stylesheets/console/_application.scss +194 -0
  34. data/app/assets/stylesheets/console/_base.scss +26 -0
  35. data/app/assets/stylesheets/console/_breadcrumbs.scss +32 -0
  36. data/app/assets/stylesheets/console/_buttons.scss +214 -0
  37. data/app/assets/stylesheets/console/_core.scss +1002 -0
  38. data/app/assets/stylesheets/console/_dropdowns.scss +63 -0
  39. data/app/assets/stylesheets/console/_help.scss +54 -0
  40. data/app/assets/stylesheets/console/_mixins.scss +11 -0
  41. data/app/assets/stylesheets/console/_navbar.scss +415 -0
  42. data/app/assets/stylesheets/console/_ribbon.scss +82 -0
  43. data/app/assets/stylesheets/console/_tile.scss +122 -0
  44. data/app/assets/stylesheets/origin.css.scss +37 -0
  45. data/app/controllers/account/dashboard.rb +13 -0
  46. data/app/controllers/account_controller.rb +3 -0
  47. data/app/controllers/application_types_controller.rb +80 -0
  48. data/app/controllers/applications_controller.rb +183 -0
  49. data/app/controllers/building_controller.rb +81 -0
  50. data/app/controllers/capability_aware.rb +18 -0
  51. data/app/controllers/cartridge_types_controller.rb +53 -0
  52. data/app/controllers/cartridges_controller.rb +43 -0
  53. data/app/controllers/console/auth/basic.rb +65 -0
  54. data/app/controllers/console/auth/none.rb +5 -0
  55. data/app/controllers/console/auth/remote_user.rb +69 -0
  56. data/app/controllers/console/rescue.rb +48 -0
  57. data/app/controllers/console_controller.rb +19 -0
  58. data/app/controllers/console_index_controller.rb +14 -0
  59. data/app/controllers/domain_aware.rb +26 -0
  60. data/app/controllers/domain_session_sweeper.rb +29 -0
  61. data/app/controllers/domains_controller.rb +30 -0
  62. data/app/controllers/keys_controller.rb +43 -0
  63. data/app/controllers/scaling_controller.rb +46 -0
  64. data/app/controllers/sshkey_aware.rb +23 -0
  65. data/app/controllers/sshkey_session_sweeper.rb +29 -0
  66. data/app/controllers/user_session_sweeper.rb +29 -0
  67. data/app/helpers/console/community_helper.rb +78 -0
  68. data/app/helpers/console/console_helper.rb +26 -0
  69. data/app/helpers/console/help_helper.rb +270 -0
  70. data/app/helpers/console/html5_boilerplate_helper.rb +63 -0
  71. data/app/helpers/console/layout_helper.rb +277 -0
  72. data/app/helpers/console/model_helper.rb +106 -0
  73. data/app/helpers/console/secured_helper.rb +5 -0
  74. data/app/models/alias.rb +10 -0
  75. data/app/models/application.rb +148 -0
  76. data/app/models/application_associations.rb +36 -0
  77. data/app/models/application_template.rb +90 -0
  78. data/app/models/application_type.rb +258 -0
  79. data/app/models/async_aware.rb +60 -0
  80. data/app/models/capabilities.rb +62 -0
  81. data/app/models/cartridge.rb +122 -0
  82. data/app/models/cartridge_type.rb +140 -0
  83. data/app/models/domain.rb +44 -0
  84. data/app/models/domain_associations.rb +33 -0
  85. data/app/models/embedded.rb +11 -0
  86. data/app/models/gear.rb +13 -0
  87. data/app/models/gear_group.rb +104 -0
  88. data/app/models/key.rb +87 -0
  89. data/app/models/quickstart.rb +135 -0
  90. data/app/models/rest_api.rb +130 -0
  91. data/app/models/rest_api/base.rb +781 -0
  92. data/app/models/rest_api/cacheable.rb +91 -0
  93. data/app/models/rest_api/environment.rb +13 -0
  94. data/app/models/rest_api/info.rb +34 -0
  95. data/app/models/rest_api/log_subscriber.rb +29 -0
  96. data/app/models/rest_api/railties/controller_runtime.rb +37 -0
  97. data/app/models/user.rb +27 -0
  98. data/app/models/user_associations.rb +6 -0
  99. data/app/views/account/_domain.html.haml +14 -0
  100. data/app/views/account/_keys.html.haml +20 -0
  101. data/app/views/account/_user.html.haml +5 -0
  102. data/app/views/account/show.html.haml +15 -0
  103. data/app/views/application_templates/_application_template.html.haml +5 -0
  104. data/app/views/application_types/_application_type.html.haml +19 -0
  105. data/app/views/application_types/_custom.html.haml +19 -0
  106. data/app/views/application_types/_persisted.html.haml +26 -0
  107. data/app/views/application_types/_tile.html.haml +9 -0
  108. data/app/views/application_types/index.html.haml +87 -0
  109. data/app/views/application_types/search.html.haml +67 -0
  110. data/app/views/application_types/show.html.haml +219 -0
  111. data/app/views/applications/_application.html.haml +34 -0
  112. data/app/views/applications/_applications_filter.html.haml +8 -0
  113. data/app/views/applications/_footer.html.haml +0 -0
  114. data/app/views/applications/_name.html.haml +28 -0
  115. data/app/views/applications/delete.html.haml +19 -0
  116. data/app/views/applications/get_started.html.haml +145 -0
  117. data/app/views/applications/index.html.haml +55 -0
  118. data/app/views/applications/show.html.haml +193 -0
  119. data/app/views/building/delete.html.haml +22 -0
  120. data/app/views/building/new.html.haml +57 -0
  121. data/app/views/building/show.html.haml +12 -0
  122. data/app/views/cartridge_types/_cartridge_type.html.haml +61 -0
  123. data/app/views/cartridge_types/index.html.haml +37 -0
  124. data/app/views/cartridge_types/show.html.haml +21 -0
  125. data/app/views/cartridges/next_steps.html.haml +58 -0
  126. data/app/views/cartridges/show.html.haml +1 -0
  127. data/app/views/console/error.html.haml +58 -0
  128. data/app/views/console/help.html.haml +90 -0
  129. data/app/views/console/not_found.html.haml +69 -0
  130. data/app/views/console/unauthorized.html.haml +7 -0
  131. data/app/views/domains/_domain.html.haml +14 -0
  132. data/app/views/domains/_form.html.haml +13 -0
  133. data/app/views/domains/edit.html.haml +5 -0
  134. data/app/views/domains/new.html.haml +6 -0
  135. data/app/views/keys/_form.html.haml +14 -0
  136. data/app/views/keys/_simple_form.html.haml +14 -0
  137. data/app/views/keys/new.html.haml +2 -0
  138. data/app/views/layouts/_footer.html.haml +38 -0
  139. data/app/views/layouts/_head.html.haml +35 -0
  140. data/app/views/layouts/console.html.haml +60 -0
  141. data/app/views/layouts/console/_header.html.haml +44 -0
  142. data/app/views/layouts/console/_identity.html.haml +7 -0
  143. data/app/views/layouts/console/_javascripts.html.haml +5 -0
  144. data/app/views/layouts/console/_stylesheets.html.haml +6 -0
  145. data/app/views/scaling/delete.html.haml +17 -0
  146. data/app/views/scaling/new.html.haml +24 -0
  147. data/app/views/scaling/show.html.haml +81 -0
  148. data/app/views/shared/_tracking.html.haml +0 -0
  149. data/conf/console.conf.example +108 -0
  150. data/conf/openshift_console.conf +10 -0
  151. data/config/cartridge_types.yml +54 -0
  152. data/config/initializers/barista_config.rb +86 -0
  153. data/config/initializers/cartridge_types.rb +5 -0
  154. data/config/initializers/console_security.rb +1 -0
  155. data/config/initializers/date_helper.rb +5 -0
  156. data/config/initializers/extended_logger.rb +51 -0
  157. data/config/initializers/formtastic.rb +100 -0
  158. data/config/initializers/inflections.rb +38 -0
  159. data/config/initializers/rdiscount.rb +8 -0
  160. data/config/initializers/rest_api.rb +22 -0
  161. data/config/initializers/sass.rb +30 -0
  162. data/config/initializers/session_trace.rb +32 -0
  163. data/config/initializers/x_frame_options.rb +53 -0
  164. data/config/locales/en.yml +12 -0
  165. data/lib/active_resource/associations.rb +107 -0
  166. data/lib/active_resource/associations/builder/association.rb +35 -0
  167. data/lib/active_resource/associations/builder/belongs_to.rb +5 -0
  168. data/lib/active_resource/associations/builder/has_many.rb +5 -0
  169. data/lib/active_resource/associations/builder/has_one.rb +5 -0
  170. data/lib/active_resource/persistent_connection.rb +341 -0
  171. data/lib/active_resource/persistent_http_mock.rb +68 -0
  172. data/lib/active_resource/reflection.rb +78 -0
  173. data/lib/console.rb +8 -0
  174. data/lib/console/config_file.rb +13 -0
  175. data/lib/console/configuration.rb +163 -0
  176. data/lib/console/engine.rb +28 -0
  177. data/lib/console/formtastic/bootstrap_form_builder.rb +369 -0
  178. data/lib/console/rails/app_redirector.rb +40 -0
  179. data/lib/console/rails/filter_hash.rb +15 -0
  180. data/lib/console/rails/routes.rb +51 -0
  181. data/lib/console/version.rb +5 -0
  182. data/lib/tasks/assets.rake +79 -0
  183. data/lib/tasks/stats.rake +18 -0
  184. data/lib/tasks/test_suites.rake +73 -0
  185. data/test/coverage_helper.rb +27 -0
  186. data/test/fixtures/cartridges.json +1 -0
  187. data/test/fixtures/quickstarts.csv +3 -0
  188. data/test/functional/account_controller_test.rb +14 -0
  189. data/test/functional/application_types_controller_test.rb +251 -0
  190. data/test/functional/applications_controller_sanity_test.rb +26 -0
  191. data/test/functional/applications_controller_test.rb +365 -0
  192. data/test/functional/building_controller_test.rb +203 -0
  193. data/test/functional/cartridge_types_controller_isolation_test.rb +68 -0
  194. data/test/functional/cartridge_types_controller_test.rb +48 -0
  195. data/test/functional/cartridges_controller_test.rb +83 -0
  196. data/test/functional/console_auth_basic_controller_test.rb +82 -0
  197. data/test/functional/console_auth_remote_user_controller_test.rb +90 -0
  198. data/test/functional/console_index_controller_test.rb +22 -0
  199. data/test/functional/domains_controller_test.rb +194 -0
  200. data/test/functional/keys_controller_test.rb +163 -0
  201. data/test/functional/quickstarts.json +18 -0
  202. data/test/functional/scaling_controller_test.rb +153 -0
  203. data/test/integration/assets_test.rb +34 -0
  204. data/test/integration/help_link_test.rb +43 -0
  205. data/test/integration/quickstarts_test.rb +24 -0
  206. data/test/integration/rescue_from_test.rb +25 -0
  207. data/test/integration/rest_api/application_test.rb +115 -0
  208. data/test/integration/rest_api/cartridge_test.rb +44 -0
  209. data/test/integration/rest_api/cartridge_type_test.rb +143 -0
  210. data/test/integration/rest_api/domain_test.rb +91 -0
  211. data/test/integration/rest_api/info_test.rb +9 -0
  212. data/test/integration/rest_api/key_test.rb +85 -0
  213. data/test/integration/static_pages_test.rb +44 -0
  214. data/test/rails_app/Rakefile +7 -0
  215. data/test/rails_app/app/controllers/application_controller.rb +5 -0
  216. data/test/rails_app/config.ru +4 -0
  217. data/test/rails_app/config/application.rb +48 -0
  218. data/test/rails_app/config/boot.rb +10 -0
  219. data/test/rails_app/config/database.yml +25 -0
  220. data/test/rails_app/config/environment.rb +5 -0
  221. data/test/rails_app/config/environments/development.rb +38 -0
  222. data/test/rails_app/config/environments/production.rb +70 -0
  223. data/test/rails_app/config/environments/test.rb +43 -0
  224. data/test/rails_app/config/initializers/auth.rb +0 -0
  225. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  226. data/test/rails_app/config/initializers/inflections.rb +10 -0
  227. data/test/rails_app/config/initializers/mime_types.rb +5 -0
  228. data/test/rails_app/config/initializers/secret_token.rb +7 -0
  229. data/test/rails_app/config/initializers/session_store.rb +8 -0
  230. data/test/rails_app/config/locales/en.yml +5 -0
  231. data/test/rails_app/config/routes.rb +4 -0
  232. data/test/rails_app/script/rails +6 -0
  233. data/test/support/auth.rb +111 -0
  234. data/test/support/base.rb +142 -0
  235. data/test/support/errors.rb +28 -0
  236. data/test/support/rest_api.rb +189 -0
  237. data/test/test_helper.rb +14 -0
  238. data/test/unit/active_model_compliance_test.rb +23 -0
  239. data/test/unit/async_aware_test.rb +55 -0
  240. data/test/unit/configuration_test.rb +158 -0
  241. data/test/unit/filter_hash_test.rb +64 -0
  242. data/test/unit/helpers/model_helper_test.rb +61 -0
  243. data/test/unit/overrides_test.rb +9 -0
  244. data/test/unit/rest_api_test.rb +1590 -0
  245. data/vendor/assets/javascripts/MIT-LICENSE.txt +20 -0
  246. data/vendor/assets/javascripts/bootstrap-collapse.js +157 -0
  247. data/vendor/assets/javascripts/bootstrap-dropdown.js +100 -0
  248. data/vendor/assets/javascripts/bootstrap-tab.js +135 -0
  249. data/vendor/assets/javascripts/bootstrap-transition.js +61 -0
  250. data/vendor/assets/javascripts/jquery.spin.js +47 -0
  251. data/vendor/assets/javascripts/jquery.ui.widget.js +16 -0
  252. data/vendor/assets/javascripts/jquery_cookie.js +41 -0
  253. data/vendor/assets/javascripts/jquery_validate_min.js +51 -0
  254. data/vendor/assets/javascripts/modernizr.min.js +2 -0
  255. data/vendor/assets/javascripts/plugins.js +16 -0
  256. data/vendor/assets/stylesheets/bootstrap/_accordion.scss +28 -0
  257. data/vendor/assets/stylesheets/bootstrap/_alerts.scss +70 -0
  258. data/vendor/assets/stylesheets/bootstrap/_breadcrumbs.scss +22 -0
  259. data/vendor/assets/stylesheets/bootstrap/_button-groups.scss +147 -0
  260. data/vendor/assets/stylesheets/bootstrap/_buttons.scss +183 -0
  261. data/vendor/assets/stylesheets/bootstrap/_carousel.scss +121 -0
  262. data/vendor/assets/stylesheets/bootstrap/_close.scss +18 -0
  263. data/vendor/assets/stylesheets/bootstrap/_code.scss +57 -0
  264. data/vendor/assets/stylesheets/bootstrap/_component-animations.scss +18 -0
  265. data/vendor/assets/stylesheets/bootstrap/_dropdowns.scss +130 -0
  266. data/vendor/assets/stylesheets/bootstrap/_forms.scss +522 -0
  267. data/vendor/assets/stylesheets/bootstrap/_grid.scss +8 -0
  268. data/vendor/assets/stylesheets/bootstrap/_hero-unit.scss +20 -0
  269. data/vendor/assets/stylesheets/bootstrap/_labels.scss +32 -0
  270. data/vendor/assets/stylesheets/bootstrap/_layouts.scss +17 -0
  271. data/vendor/assets/stylesheets/bootstrap/_mixins.scss +602 -0
  272. data/vendor/assets/stylesheets/bootstrap/_modals.scss +84 -0
  273. data/vendor/assets/stylesheets/bootstrap/_navbar.scss +299 -0
  274. data/vendor/assets/stylesheets/bootstrap/_navs.scss +353 -0
  275. data/vendor/assets/stylesheets/bootstrap/_pager.scss +30 -0
  276. data/vendor/assets/stylesheets/bootstrap/_pagination.scss +55 -0
  277. data/vendor/assets/stylesheets/bootstrap/_popovers.scss +49 -0
  278. data/vendor/assets/stylesheets/bootstrap/_progress-bars.scss +95 -0
  279. data/vendor/assets/stylesheets/bootstrap/_reset.scss +126 -0
  280. data/vendor/assets/stylesheets/bootstrap/_scaffolding.scss +33 -0
  281. data/vendor/assets/stylesheets/bootstrap/_sprites.scss +158 -0
  282. data/vendor/assets/stylesheets/bootstrap/_tables.scss +150 -0
  283. data/vendor/assets/stylesheets/bootstrap/_thumbnails.scss +35 -0
  284. data/vendor/assets/stylesheets/bootstrap/_tooltip.scss +35 -0
  285. data/vendor/assets/stylesheets/bootstrap/_type.scss +218 -0
  286. data/vendor/assets/stylesheets/bootstrap/_utilities.scss +23 -0
  287. data/vendor/assets/stylesheets/bootstrap/_variables.scss +107 -0
  288. data/vendor/assets/stylesheets/bootstrap/_wells.scss +17 -0
  289. data/vendor/assets/stylesheets/bootstrap/bootstrap.scss +66 -0
  290. data/vendor/assets/stylesheets/bootstrap/responsive.scss +334 -0
  291. 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?('&quot;'))
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