heroku_config_vars 0.0.2.pre

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 (94) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +1 -0
  3. data/Rakefile +30 -0
  4. data/app/assets/javascripts/heroku_config_vars/application.js +15 -0
  5. data/app/assets/javascripts/heroku_config_vars/var_form.js +28 -0
  6. data/app/assets/stylesheets/heroku_config_vars/application.css +31 -0
  7. data/app/assets/stylesheets/heroku_config_vars/button.css.scss +54 -0
  8. data/app/assets/stylesheets/heroku_config_vars/menu.css.scss +36 -0
  9. data/app/assets/stylesheets/heroku_config_vars/table.css.scss +28 -0
  10. data/app/controllers/heroku_config_vars/application_controller.rb +46 -0
  11. data/app/controllers/heroku_config_vars/heroku_apps_controller.rb +50 -0
  12. data/app/helpers/heroku_config_vars/application_helper.rb +8 -0
  13. data/app/models/heroku_config_vars/heroku_app.rb +138 -0
  14. data/app/views/heroku_config_vars/application/env.html.erb +14 -0
  15. data/app/views/heroku_config_vars/application/recommend_https.html.erb +6 -0
  16. data/app/views/heroku_config_vars/heroku_apps/_errors.html.erb +5 -0
  17. data/app/views/heroku_config_vars/heroku_apps/confirmation.html.erb +73 -0
  18. data/app/views/heroku_config_vars/heroku_apps/edit.html.erb +37 -0
  19. data/app/views/heroku_config_vars/heroku_apps/new.html.erb +21 -0
  20. data/app/views/heroku_config_vars/heroku_apps/show.html.erb +20 -0
  21. data/app/views/layouts/heroku_config_vars/application.html.erb +20 -0
  22. data/config/routes.rb +5 -0
  23. data/lib/heroku_config_vars/engine.rb +12 -0
  24. data/lib/heroku_config_vars/version.rb +3 -0
  25. data/lib/heroku_config_vars.rb +5 -0
  26. data/lib/tasks/heroku_config_vars_tasks.rake +4 -0
  27. data/spec/dummy/README.rdoc +261 -0
  28. data/spec/dummy/Rakefile +7 -0
  29. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  30. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  31. data/spec/dummy/app/controllers/application_controller.rb +8 -0
  32. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  33. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  34. data/spec/dummy/config/application.rb +49 -0
  35. data/spec/dummy/config/boot.rb +10 -0
  36. data/spec/dummy/config/environment.rb +5 -0
  37. data/spec/dummy/config/environments/development.rb +29 -0
  38. data/spec/dummy/config/environments/test.rb +29 -0
  39. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  40. data/spec/dummy/config/initializers/inflections.rb +15 -0
  41. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  42. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  43. data/spec/dummy/config/initializers/session_store.rb +8 -0
  44. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  45. data/spec/dummy/config/locales/en.yml +5 -0
  46. data/spec/dummy/config/routes.rb +4 -0
  47. data/spec/dummy/config.ru +4 -0
  48. data/spec/dummy/log/test.log +6002 -0
  49. data/spec/dummy/public/404.html +26 -0
  50. data/spec/dummy/public/422.html +26 -0
  51. data/spec/dummy/public/500.html +25 -0
  52. data/spec/dummy/public/favicon.ico +0 -0
  53. data/spec/dummy/script/rails +6 -0
  54. data/spec/dummy/tmp/cache/assets/C20/540/sprockets%2F9f7052464a49612e023f9088fa442053 +0 -0
  55. data/spec/dummy/tmp/cache/assets/C97/2C0/sprockets%2F3945d527e8ea800568e77dd095c67391 +0 -0
  56. data/spec/dummy/tmp/cache/assets/C9B/060/sprockets%2Fa20484759fec963d3f51839934c3848f +0 -0
  57. data/spec/dummy/tmp/cache/assets/CAC/5E0/sprockets%2F425b0f4900e04b7736af6e64c4f46902 +0 -0
  58. data/spec/dummy/tmp/cache/assets/CBA/440/sprockets%2F8291695bea92c347d6a509dfa2379810 +0 -0
  59. data/spec/dummy/tmp/cache/assets/CBF/C20/sprockets%2Fdd57917c8268e99fe0a17332550ef632 +0 -0
  60. data/spec/dummy/tmp/cache/assets/CD9/8E0/sprockets%2F0681932233ab9af521f58c34cbf091f5 +0 -0
  61. data/spec/dummy/tmp/cache/assets/CF0/D20/sprockets%2F6997e8f2f3f34b07c51d6689d3ec5120 +0 -0
  62. data/spec/dummy/tmp/cache/assets/CFA/C10/sprockets%2Fca5852e7ebc212e12405091c0ca7a449 +0 -0
  63. data/spec/dummy/tmp/cache/assets/D0C/BD0/sprockets%2F7e5673b3d2e6c24b8a290ff222a4843d +0 -0
  64. data/spec/dummy/tmp/cache/assets/D0F/CF0/sprockets%2Fa54d897b366850d6aff2583dcd21141b +0 -0
  65. data/spec/dummy/tmp/cache/assets/D11/650/sprockets%2Fa79c1979284b6712e0a09bdde83c711b +0 -0
  66. data/spec/dummy/tmp/cache/assets/D2A/5E0/sprockets%2F8f9f3295a33983dafe83cbc75895a346 +0 -0
  67. data/spec/dummy/tmp/cache/assets/D2F/830/sprockets%2Fd6b510595130dc04df17a75eae623ee0 +0 -0
  68. data/spec/dummy/tmp/cache/assets/D3A/0E0/sprockets%2F12c0c4243a0757c81af09989ece2d4dc +0 -0
  69. data/spec/dummy/tmp/cache/assets/D3A/B10/sprockets%2Fa6033a4a85f3d8f4f5a68c3215bc64b6 +0 -0
  70. data/spec/dummy/tmp/cache/assets/D44/BB0/sprockets%2F6f8a1b369f3e20121751ff9356bebf8c +0 -0
  71. data/spec/dummy/tmp/cache/assets/D70/B70/sprockets%2Fa1415c8ffaef728e4e786c0e48061ac2 +0 -0
  72. data/spec/dummy/tmp/cache/assets/D94/CA0/sprockets%2Fb36822d80e1aee3257c5cf2f4ddeb043 +0 -0
  73. data/spec/dummy/tmp/cache/assets/DAA/850/sprockets%2F7e2ddb2b088e0c526941fef48af19ff5 +0 -0
  74. data/spec/dummy/tmp/cache/assets/DC3/970/sprockets%2Fd5d2e0cc86cec4e411aa31c549fcb870 +0 -0
  75. data/spec/dummy/tmp/capybara/capybara-201302162255389397158257.html +56 -0
  76. data/spec/dummy/tmp/capybara/capybara-201302162255545698499887.html +56 -0
  77. data/spec/dummy/tmp/capybara/capybara-201302162256212974676040.html +56 -0
  78. data/spec/dummy/tmp/capybara/capybara-201302162256278576954261.html +56 -0
  79. data/spec/dummy/tmp/capybara/capybara-201302200948319507521481.html +26 -0
  80. data/spec/dummy/tmp/capybara/capybara-20130220094839395273181.html +46 -0
  81. data/spec/dummy/tmp/pids/server.pid +1 -0
  82. data/spec/features/config_vars/edit_spec.rb +102 -0
  83. data/spec/features/config_vars/show_spec.rb +39 -0
  84. data/spec/features/env/show_spec.rb +16 -0
  85. data/spec/features/security/requires_admin_spec.rb +9 -0
  86. data/spec/features/security/suggests_ssl_spec.rb +28 -0
  87. data/spec/features/setup/new_app_spec.rb +42 -0
  88. data/spec/helpers/application_helper_spec.rb +15 -0
  89. data/spec/lib/heroku_config_vars_spec.rb +6 -0
  90. data/spec/models/heroku_config_vars/heroku_app_spec.rb +185 -0
  91. data/spec/spec_helper.rb +39 -0
  92. data/spec/support/heroku_responses.rb +35 -0
  93. data/spec/views/heroku_config_vars/application/recommend_https_spec.rb +14 -0
  94. metadata +336 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1 @@
1
+ TODO
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'HerokuConfigVars'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ load "rspec/rails/tasks/rspec.rake"
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,28 @@
1
+
2
+ $(function(){
3
+
4
+ // Make deleting nice
5
+ $('td.delete').each(function(){
6
+ var $td = $(this);
7
+ var $tr = $td.parents('tr');
8
+ var $box = $td.find('[type="checkbox"]');
9
+ //$box.hide()
10
+ $box.change(function(){
11
+ $box.get(0).checked ? $tr.addClass('deleted') : $tr.removeClass('deleted');
12
+ });
13
+ });
14
+
15
+ // Dynamically add new text fields as they're used
16
+ $('tr.new input.new_key').blur(function(){
17
+ var $input = $(this)
18
+ var input = this;
19
+ var $tr = $input.parents('tr');
20
+
21
+ if ( $input.val() == '' || $tr.next().length > 0 ) return;
22
+
23
+ $tr.clone(true).insertAfter($tr).find('input').each(function(){
24
+ $(this).val('');
25
+ });
26
+ });
27
+
28
+ });
@@ -0,0 +1,31 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
14
+
15
+ body {
16
+ font-family: helvetica;
17
+ font-size: smaller;
18
+ }
19
+
20
+ a {
21
+ color: #66f;
22
+ text-decoration: none;
23
+ }
24
+
25
+ a:hover {
26
+ color: #fff;
27
+ background-color: #66f; }
28
+
29
+ label {
30
+ cursor: pointer;
31
+ }
@@ -0,0 +1,54 @@
1
+ .button {
2
+ color: #fff;
3
+ border: 1px solid;
4
+ border-radius: 3px;
5
+ text-align: center;
6
+ padding: 5px 16px;
7
+ font-size: 13px;
8
+ font-weight: 600;
9
+ cursor: pointer;
10
+ overflow: visible;
11
+ text-decoration: none;
12
+
13
+ &.happy {
14
+ $hue-adjustment: 260;
15
+ border-top-color: adjust-hue(#2270ab, $hue-adjustment);
16
+ border-right-color: adjust-hue(#18639a, $hue-adjustment);
17
+ border-bottom-color: adjust-hue(#0f568b, $hue-adjustment);
18
+ border-left-color: adjust-hue(#18639a, $hue-adjustment);
19
+ background: adjust-hue(#2180ce, $hue-adjustment);
20
+ background: -webkit-gradient(linear, left top, left bottom, from(adjust-hue(#33a0e8, $hue-adjustment)), to(adjust-hue(#2180ce, $hue-adjustment)));
21
+ text-shadow: adjust-hue(#355782, $hue-adjustment) 0 1px 2px;
22
+ box-shadow: 0 1px 1px rgba(0,0,0,0.3),inset 0px 1px 0px adjust-hue(#83c5f1, $hue-adjustment);
23
+
24
+ &:hover {
25
+ border-top-color: adjust-hue(#0070cc, $hue-adjustment);
26
+ border-right-color: adjust-hue(#006ac1, $hue-adjustment);
27
+ border-bottom-color: adjust-hue(#005ca6, $hue-adjustment);
28
+ border-left-color: adjust-hue(#006ac1, $hue-adjustment);
29
+ box-shadow: 0 1px 1px rgba(0,0,0,0.3),inset 0 0 3px adjust-hue(#35bff4, $hue-adjustment);
30
+ background: -webkit-gradient(linear, left top, left bottom, from(adjust-hue(#43b0f8, $hue-adjustment)), to(adjust-hue(#3190de, $hue-adjustment)));
31
+ }
32
+ }
33
+
34
+ &.sad {
35
+ $hue-adjustment: 150;
36
+ border-top-color: adjust-hue(#2270ab, $hue-adjustment);
37
+ border-right-color: adjust-hue(#18639a, $hue-adjustment);
38
+ border-bottom-color: adjust-hue(#0f568b, $hue-adjustment);
39
+ border-left-color: adjust-hue(#18639a, $hue-adjustment);
40
+ background: adjust-hue(#2180ce, $hue-adjustment);
41
+ background: -webkit-gradient(linear, left top, left bottom, from(adjust-hue(#33a0e8, $hue-adjustment)), to(adjust-hue(#2180ce, $hue-adjustment)));
42
+ text-shadow: adjust-hue(#355782, $hue-adjustment) 0 1px 2px;
43
+ box-shadow: 0 1px 1px rgba(0,0,0,0.3),inset 0px 1px 0px adjust-hue(#83c5f1, $hue-adjustment);
44
+
45
+ &:hover {
46
+ border-top-color: adjust-hue(#0070cc, $hue-adjustment);
47
+ border-right-color: adjust-hue(#006ac1, $hue-adjustment);
48
+ border-bottom-color: adjust-hue(#005ca6, $hue-adjustment);
49
+ border-left-color: adjust-hue(#006ac1, $hue-adjustment);
50
+ box-shadow: 0 1px 1px rgba(0,0,0,0.3),inset 0 0 3px adjust-hue(#35bff4, $hue-adjustment);
51
+ background: -webkit-gradient(linear, left top, left bottom, from(adjust-hue(#43b0f8, $hue-adjustment)), to(adjust-hue(#3190de, $hue-adjustment)));
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,36 @@
1
+ ul.submenu {
2
+ height: 32px;
3
+ list-style: none;
4
+ margin: 0 -20px;
5
+ padding: 0 20px;
6
+ background: #eee;
7
+ border-bottom: 1px #ccc solid;
8
+ clear: both;
9
+
10
+ li.admin {
11
+ float: right;
12
+ }
13
+ .menu-option {
14
+ font-size: 16px;
15
+ float: left;
16
+ padding: 0.25em 1em;
17
+ margin: 5px 10px -1px 0;
18
+ border: 1px solid #ccc;
19
+ height: 18px;
20
+ border-bottom-color: #fff;
21
+ background: #fff;
22
+ }
23
+
24
+ a {
25
+ padding: 0;
26
+ }
27
+
28
+ a .menu-option {
29
+ border-bottom: none;
30
+ }
31
+
32
+ a:hover .menu-option {
33
+ background: #aaa;
34
+ }
35
+
36
+ }
@@ -0,0 +1,28 @@
1
+ table {
2
+ border-collapse: collapse;
3
+
4
+ th {
5
+ text-align: left;
6
+ }
7
+
8
+ td, th {
9
+ border: 1px #ccc;
10
+ border-style: solid none;
11
+ padding: 0.5em;
12
+ }
13
+
14
+ input {
15
+ padding: 0.25em;
16
+ }
17
+
18
+ input.new_value,
19
+ input.var_value {
20
+ width: 50em;
21
+ }
22
+
23
+ tr.deleted, tr.deleted input {
24
+ text-decoration: line-through;
25
+ color: #bbb;
26
+ }
27
+ }
28
+
@@ -0,0 +1,46 @@
1
+ class HerokuConfigVars::ApplicationController < ApplicationController
2
+
3
+ before_filter :require_authenticated
4
+ before_filter :recommend_https, :if => :insecure?
5
+
6
+ AUTH_METHOD = :heroku_config_authorized?
7
+
8
+ def env
9
+ @env = ENV
10
+ end
11
+
12
+ private
13
+
14
+ def require_authenticated
15
+ # This is where we shell out to ApplicationController
16
+ # raising RoutingError will render 404 in production
17
+ if not respond_to? AUTH_METHOD
18
+ raise ActionController::RoutingError.new <<-ERROR.strip_heredoc
19
+ `#{AUTH_METHOD}` must be implemented in ApplicationController and return true for authorized users.
20
+
21
+ e.g.
22
+ class ApplicationController < ActionController::Base
23
+ ...
24
+
25
+ def #{AUTH_METHOD}
26
+ current_user.admin?
27
+ end
28
+
29
+ ...
30
+ end
31
+ ERROR
32
+ elsif not heroku_config_authorized?
33
+ raise ActionController::RoutingError.new ':heroku_config_authorized? returned false'
34
+ end
35
+ end
36
+
37
+
38
+ def recommend_https
39
+ render :recommend_https
40
+ end
41
+
42
+ def insecure?
43
+ not request.ssl? and (session[:insecure] ||= params[:insecure]) != 'ok'
44
+ end
45
+
46
+ end
@@ -0,0 +1,50 @@
1
+ module HerokuConfigVars
2
+ class HerokuAppsController < ApplicationController
3
+
4
+ before_filter :require_heroku_app, :only => [:show, :edit, :update]
5
+
6
+ def new
7
+ @heroku_app = HerokuApp.find
8
+ end
9
+
10
+ def create
11
+ @heroku_app = HerokuApp.new params[:heroku_app]
12
+ if @heroku_app.save
13
+ redirect_to heroku_app_path
14
+ else
15
+ render :new
16
+ end
17
+ end
18
+
19
+ def update
20
+ vars = params[:heroku_app][:vars]
21
+ vars.merge! hashify_new_vars
22
+ vars.except! *params[:remove].keys if params[:remove]
23
+ heroku_app.vars = vars
24
+ return render :confirmation unless params[:confirmation]
25
+ if heroku_app.save
26
+ redirect_to edit_heroku_app_path, notice: 'Configuration updated'
27
+ else
28
+ heroku_app.load_vars
29
+ render :edit
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def require_heroku_app
36
+ redirect_to new_heroku_app_path unless heroku_app && heroku_app.loaded?
37
+ end
38
+
39
+ def heroku_app
40
+ @heroku_app ||= HerokuApp.find
41
+ end
42
+
43
+ def hashify_new_vars
44
+ {}.tap do |vars|
45
+ params[:add].each {|h| vars.store h['key'], h['value'] if h['key'].present? } if params[:add]
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,8 @@
1
+ module HerokuConfigVars
2
+ module ApplicationHelper
3
+ def menu_link(text, url, html_options={})
4
+ text = content_tag :span, text, :class => 'menu-option'
5
+ link_to_unless_current text, url, html_options
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,138 @@
1
+ module HerokuConfigVars
2
+ class HerokuApp
3
+ extend ActiveModel::Naming
4
+ include ActiveModel::Conversion
5
+ include ActiveModel::Validations
6
+
7
+ attr_accessor :vars
8
+
9
+ attr_reader :loaded
10
+ attr_reader :current_vars
11
+
12
+ alias_method :loaded?, :loaded
13
+ alias_method :persisted?, :loaded
14
+
15
+ validates_presence_of :app_name
16
+ validates_presence_of :api_key
17
+
18
+ def self.find
19
+ attrs = {
20
+ app_name: ENV['HEROKU_APP_NAME'],
21
+ api_key: ENV['HEROKU_API_KEY']
22
+ }
23
+
24
+ new(attrs) do |app|
25
+ app.load_vars if app.valid?
26
+ end
27
+ end
28
+
29
+ def initialize(attrs={})
30
+ @vars = {}
31
+ @current_vars = {}
32
+ @loaded = false
33
+
34
+ self.attributes = attrs
35
+
36
+ yield self if block_given?
37
+ end
38
+
39
+ def attributes=(attrs={})
40
+ attrs.each do |key, value|
41
+ self.send "#{key}=", value
42
+ end
43
+ end
44
+
45
+ def app_name
46
+ @app_name ||= @vars['HEROKU_APP_NAME'].presence
47
+ end
48
+
49
+ def app_name=(value)
50
+ @app_name = @vars['HEROKU_APP_NAME'] = value
51
+ end
52
+
53
+ def api_key
54
+ @api_key ||= @vars['HEROKU_API_KEY'].presence
55
+ end
56
+
57
+ def api_key=(value)
58
+ @api_key = @vars['HEROKU_API_KEY'] = value
59
+ end
60
+
61
+ def id
62
+ app_name
63
+ end
64
+
65
+ def load_vars
66
+ catch_heroku_errors do
67
+ Rails.logger.debug 'Loading config'
68
+ @vars = connection.get_config_vars(app_name).body
69
+ @current_vars = @vars.dup.freeze
70
+ @loaded = true
71
+ end
72
+ end
73
+
74
+ def save
75
+ save_to_heroku and save_to_env if valid?
76
+ end
77
+
78
+ def removed_vars
79
+ current_vars ? current_vars.except(*vars.keys) : {}
80
+ end
81
+
82
+ def added_vars
83
+ vars.except *current_vars.keys
84
+ end
85
+
86
+ def kept_vars
87
+ current_vars.slice *vars.keys
88
+ end
89
+
90
+ def updated_vars
91
+ changes.slice(*kept_vars.keys)
92
+ end
93
+
94
+ def updated_and_added_vars
95
+ changes.slice(*vars.keys)
96
+ end
97
+
98
+ def changes
99
+ @changes ||= vars.diff current_vars
100
+ end
101
+
102
+ private
103
+
104
+ def connection
105
+ Heroku::API.new api_key: api_key
106
+ end
107
+
108
+ def catch_heroku_errors
109
+ Rails.logger.debug "Connecting to Heroku"
110
+ begin
111
+ yield
112
+ rescue Heroku::API::Errors::Unauthorized => e
113
+ errors.add :api_key, "is invalid (#{e.class.name})"
114
+ rescue Heroku::API::Errors::Forbidden, Heroku::API::Errors::NotFound => e
115
+ errors.add :app_name, "is invalid (#{e.class.name})"
116
+ rescue Heroku::API::Errors::RequestFailed => e
117
+ errors.add :base, "Request failed: " << e.response.body
118
+ end
119
+ errors.blank?
120
+ end
121
+
122
+ def save_to_heroku
123
+ Rails.logger.debug 'Updating config'
124
+ catch_heroku_errors { connection.put_config_vars(app_name, updated_and_added_vars) }
125
+ removed_vars.each do |key, _|
126
+ Rails.logger.debug "deleting #{key}"
127
+ catch_heroku_errors { connection.delete_config_var(app_name, key) }
128
+ end
129
+ errors.blank?
130
+ end
131
+
132
+ def save_to_env
133
+ ENV.update vars
134
+ removed_vars.each { |key, _| ENV.delete key }
135
+ end
136
+
137
+ end
138
+ end
@@ -0,0 +1,14 @@
1
+ <h2>ENV</h2>
2
+
3
+ <table>
4
+ <%- @env.sort.each do |key, value| -%>
5
+ <tr>
6
+ <th>
7
+ <%= key %>
8
+ </th>
9
+ <td>
10
+ <%= value %>
11
+ </td>
12
+ </tr>
13
+ <%- end -%>
14
+ </table>
@@ -0,0 +1,6 @@
1
+ <h2>WARNING</h2>
2
+
3
+ <p>You are trying to view sensitive application configuration over an <strong>insecure connection</strong>.</p>
4
+ <p>It is highly recommended that you view this over https.</p>
5
+ <%= link_to 'Switch to secure connection', {only_path: false, protocol: 'https'}, class: 'happy button' %>
6
+ <%= link_to 'Continue insecurely', {insecure: :ok}, class: 'sad button' %>
@@ -0,0 +1,5 @@
1
+ <ul>
2
+ <%- heroku_app.errors.full_messages.each do |msg| -%>
3
+ <li><%= msg %></li>
4
+ <%- end -%>
5
+ </ul>
@@ -0,0 +1,73 @@
1
+ <h2>Please confirm...</h2>
2
+
3
+ <%- if @heroku_app.changes.any? %>
4
+ <%- if @heroku_app.added_vars.any? -%>
5
+ <h3>These configuration variables will be added:</h3>
6
+ <table>
7
+ <%- @heroku_app.added_vars.each do |key, value| -%>
8
+ <tr>
9
+ <th>
10
+ <%= key %>
11
+ </th>
12
+ <td>
13
+ <%= value %>
14
+ </td>
15
+ </tr>
16
+ <%- end -%>
17
+ </table>
18
+ <%- end -%>
19
+
20
+ <%- if @heroku_app.updated_vars.any? -%>
21
+ <h3>These configuration variables will be updated:</h3>
22
+ <table>
23
+ <%- @heroku_app.updated_vars.each do |key, value| -%>
24
+ <tr>
25
+ <th>
26
+ <%= key %>
27
+ </th>
28
+ <td>
29
+ <%= @heroku_app.current_vars[key] %>
30
+ </td>
31
+ <td>
32
+ &rarr;
33
+ </td>
34
+ <td>
35
+ <%= value %>
36
+ </td>
37
+ </tr>
38
+ <%- end -%>
39
+ </table>
40
+ <%- end -%>
41
+
42
+ <%- if @heroku_app.removed_vars.any? -%>
43
+ <h3>These configuration variables will be removed:</h3>
44
+ <table>
45
+ <%- @heroku_app.removed_vars.each do |key, value| -%>
46
+ <tr class="deleted">
47
+ <th>
48
+ <%= key %>
49
+ </th>
50
+ <td>
51
+ <%= value %>
52
+ </td>
53
+ </tr>
54
+ <%- end -%>
55
+ </table>
56
+ <%- end -%>
57
+
58
+ <%= form_for @heroku_app, url: {confirmation: true} do |f| %>
59
+ <%- @heroku_app.vars.each do |key, value| -%>
60
+ <%= hidden_field_tag "heroku_app[vars][#{key}]", value %>
61
+ <%- end -%>
62
+
63
+ <p>
64
+ <%= submit_tag "Update and restart app" %>
65
+ </p>
66
+ <%- end -%>
67
+
68
+ <%- else -%>
69
+ <p>No changes made.</p>
70
+ <%- end -%>
71
+
72
+
73
+ <p><%= link_to 'Cancel', edit_heroku_app_path %></p>
@@ -0,0 +1,37 @@
1
+ <h2>
2
+ <%= link_to @heroku_app.app_name, heroku_app_path %>
3
+ &rarr;
4
+ Edit Configuration
5
+ </h2>
6
+
7
+ <%= render 'errors', heroku_app: @heroku_app if @heroku_app.errors.any? %>
8
+
9
+ <%= form_for @heroku_app, url: heroku_app_path do |f| %>
10
+ <table>
11
+ <%- @heroku_app.vars.sort.each do |key, value| -%>
12
+ <tr>
13
+ <th><%= label_tag "heroku_app[vars][#{key}]", key %></th>
14
+ <td><%= text_field_tag "heroku_app[vars][#{key}]", value, class: 'var_value' %></td>
15
+ <td class="delete">
16
+ <%= label_tag "remove[#{key}]" do %>
17
+ <%= check_box_tag "remove[#{key}]" %>
18
+ Delete
19
+ <%- end -%>
20
+ </td>
21
+ </tr>
22
+ <%- end -%>
23
+ <tr class="new">
24
+ <th><%= text_field_tag "add[][key]", nil, id: nil, class: 'new_key' %></th>
25
+ <td><%= text_field_tag "add[][value]", nil, id: nil, class: 'new_value' %></td>
26
+ <td></td>
27
+ </tr>
28
+ </table>
29
+
30
+ <p>
31
+ <%= f.submit "Prepare..." %>
32
+ </p>
33
+ <%- end -%>
34
+
35
+ <p>
36
+ <%= link_to 'Cancel', heroku_app_path %>
37
+ </p>
@@ -0,0 +1,21 @@
1
+ <h2>One Time Setup</h2>
2
+
3
+ <%= render 'errors', heroku_app: @heroku_app if @heroku_app.errors.any? %>
4
+
5
+ <%= form_for @heroku_app, url: heroku_app_path do |f| %>
6
+ <h3>Connection Details</h3>
7
+ <table>
8
+ <tr>
9
+ <th><%= f.label :app_name, "App Name" %></th>
10
+ <td><%= f.text_field :app_name %></td>
11
+ </tr>
12
+ <tr>
13
+ <th><%= f.label :api_key, "API Key" %></th>
14
+ <td><%= f.text_field :api_key %></td>
15
+ </tr>
16
+ </table>
17
+
18
+ <p>
19
+ <%= f.submit "Save" %>
20
+ </p>
21
+ <%- end -%>
@@ -0,0 +1,20 @@
1
+ <h2>
2
+ <%= @heroku_app.app_name %>
3
+ </h2>
4
+
5
+ <table>
6
+ <%- @heroku_app.vars.sort.each do |key, value| -%>
7
+ <tr>
8
+ <th>
9
+ <%= key %>
10
+ </th>
11
+ <td>
12
+ <%= value %>
13
+ </td>
14
+ </tr>
15
+ <%- end -%>
16
+ </table>
17
+
18
+ <p>
19
+ <%= link_to 'Edit', edit_heroku_app_path %>
20
+ </p>