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.
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