web-console-rails3 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.markdown +40 -0
  4. data/Rakefile +48 -0
  5. data/app/assets/javascripts/web_console/application.js +4 -0
  6. data/app/assets/javascripts/web_console/console_sessions.js +24 -0
  7. data/app/assets/stylesheets/web_console/application.css +13 -0
  8. data/app/assets/stylesheets/web_console/console_sessions.css +8 -0
  9. data/app/controllers/web_console/application_controller.rb +17 -0
  10. data/app/controllers/web_console/console_sessions_controller.rb +23 -0
  11. data/app/helpers/web_console/application_helper.rb +4 -0
  12. data/app/helpers/web_console/console_session_helper.rb +4 -0
  13. data/app/models/web_console/console_session.rb +110 -0
  14. data/app/views/layouts/web_console/application.html.erb +14 -0
  15. data/app/views/web_console/console_sessions/index.html.erb +4 -0
  16. data/config/routes.rb +5 -0
  17. data/lib/web-console-rails3.rb +1 -0
  18. data/lib/web-console.rb +1 -0
  19. data/lib/web_console.rb +21 -0
  20. data/lib/web_console/backport/active_model.rb +26 -0
  21. data/lib/web_console/engine.rb +40 -0
  22. data/lib/web_console/fiber.rb +48 -0
  23. data/lib/web_console/repl.rb +59 -0
  24. data/lib/web_console/repl/dummy.rb +38 -0
  25. data/lib/web_console/repl/irb.rb +62 -0
  26. data/lib/web_console/stream.rb +30 -0
  27. data/lib/web_console/version.rb +3 -0
  28. data/test/controllers/web_console/console_sessions_controller_test.rb +57 -0
  29. data/test/dummy/README.rdoc +261 -0
  30. data/test/dummy/Rakefile +7 -0
  31. data/test/dummy/app/assets/javascripts/application.js +15 -0
  32. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  33. data/test/dummy/app/controllers/application_controller.rb +3 -0
  34. data/test/dummy/app/helpers/application_helper.rb +2 -0
  35. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  36. data/test/dummy/config.ru +4 -0
  37. data/test/dummy/config/application.rb +38 -0
  38. data/test/dummy/config/boot.rb +10 -0
  39. data/test/dummy/config/database.yml +25 -0
  40. data/test/dummy/config/environment.rb +5 -0
  41. data/test/dummy/config/environments/development.rb +37 -0
  42. data/test/dummy/config/environments/production.rb +67 -0
  43. data/test/dummy/config/environments/test.rb +37 -0
  44. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  45. data/test/dummy/config/initializers/inflections.rb +15 -0
  46. data/test/dummy/config/initializers/mime_types.rb +5 -0
  47. data/test/dummy/config/initializers/secret_token.rb +7 -0
  48. data/test/dummy/config/initializers/session_store.rb +8 -0
  49. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  50. data/test/dummy/config/locales/en.yml +5 -0
  51. data/test/dummy/config/routes.rb +58 -0
  52. data/test/dummy/db/development.sqlite3 +0 -0
  53. data/test/dummy/db/schema.rb +16 -0
  54. data/test/dummy/db/test.sqlite3 +0 -0
  55. data/test/dummy/log/development.log +588 -0
  56. data/test/dummy/log/test.log +2122 -0
  57. data/test/dummy/public/404.html +26 -0
  58. data/test/dummy/public/422.html +26 -0
  59. data/test/dummy/public/500.html +25 -0
  60. data/test/dummy/public/favicon.ico +0 -0
  61. data/test/dummy/script/rails +6 -0
  62. data/test/dummy/tmp/cache/assets/C9E/AD0/sprockets%2F4a42d8916f3fa47867445f696497a92c +0 -0
  63. data/test/dummy/tmp/cache/assets/CA7/D70/sprockets%2F3e9e32bbc8c81a93002555265a36a852 +0 -0
  64. data/test/dummy/tmp/cache/assets/CBD/6E0/sprockets%2F3293dfc0984076f0e8371a9e7640f4a8 +0 -0
  65. data/test/dummy/tmp/cache/assets/CD0/FC0/sprockets%2Fbb2777627d42a216f3d9ced4322040b3 +0 -0
  66. data/test/dummy/tmp/cache/assets/CFA/E30/sprockets%2F35be1d26565dc0310c29f1a5e2f62f10 +0 -0
  67. data/test/dummy/tmp/cache/assets/D1D/FD0/sprockets%2Fa4a5ffe670666ce3d8d59179905201ef +0 -0
  68. data/test/dummy/tmp/cache/assets/D21/6B0/sprockets%2F9e242803fe56d6305274ff7e6487deda +0 -0
  69. data/test/dummy/tmp/cache/assets/D29/380/sprockets%2F92f1a0450bc4bea3364a07be42b4f645 +0 -0
  70. data/test/dummy/tmp/cache/assets/D3E/380/sprockets%2F434d98c8380bb9daf43810155aaf68ba +0 -0
  71. data/test/dummy/tmp/cache/assets/D69/670/sprockets%2Fc6b4a05846fd1b98fe9252ecdd1601c0 +0 -0
  72. data/test/dummy/tmp/cache/assets/D90/B30/sprockets%2Fe03fe93eb7fe888c9d21ee62816596ff +0 -0
  73. data/test/dummy/tmp/cache/assets/D95/C40/sprockets%2F09cb0a274209abf0391cbfce6ee67b82 +0 -0
  74. data/test/dummy/tmp/cache/assets/D9F/400/sprockets%2F7f60332f86073dc8ed80b4c2a9dfcbe1 +0 -0
  75. data/test/dummy/tmp/cache/assets/DB3/0C0/sprockets%2F689fb998e2a7add3e00db88df254c87a +0 -0
  76. data/test/dummy/tmp/cache/assets/DD4/440/sprockets%2Fa33d646ac00d8bc87a4a496af6eed96f +0 -0
  77. data/test/dummy/tmp/cache/assets/E5A/C40/sprockets%2F164cfa0fd9eb1ec1acdfaa278c83e9c5 +0 -0
  78. data/test/helpers/web_console/console_session_helper_test.rb +6 -0
  79. data/test/models/console_session_test.rb +111 -0
  80. data/test/test_helper.rb +15 -0
  81. data/test/web_console/repl/dummy_test.rb +54 -0
  82. data/test/web_console/repl/irb_test.rb +156 -0
  83. data/test/web_console/repl_test.rb +15 -0
  84. data/test/web_console_test.rb +93 -0
  85. data/vendor/assets/javascripts/jquery.console.js +727 -0
  86. metadata +249 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: edcf6e9666067ebf464f12458a6d7ce664fbccd2
4
+ data.tar.gz: f4873b4e0fdd81af7a96e81f31b4f503a880f045
5
+ SHA512:
6
+ metadata.gz: daf689f8d30f22afc92bee293fd585baeab0ab9b83ee1fa8699eb8fdc2e85873f8393179ed0e4f851654dd6c1d7bbcd1f1d7755e03428e1a494948f2c4231e74
7
+ data.tar.gz: c4c5f25e7504541322abd30518c6e76c27bf5231bb8e9884c37e4ad978a34f31b99de4c344a485eff03d80adf7b0b885ba3a9ff7258f0d20e49f87fc92395f2c
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 Genadi Samokovarov and Guillermo Iguaran
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.markdown ADDED
@@ -0,0 +1,40 @@
1
+ Web Console for Rails 3
2
+ =======================
3
+
4
+ [![Travis](https://travis-ci.org/gsamokovarov/web-console-rails3.png)](https://travis-ci.org/gsamokovarov/web-console-rails3)
5
+
6
+ [Web Console] is great and all, but by default, it only runs on _Rails 4_. If
7
+ you can't easily upgrade your application to _Rails 4_, you can use this build
8
+ to get to [Web Console] running on _Rails 3.2_.
9
+
10
+ Requirements
11
+ ------------
12
+
13
+ While _Rails 3.2_ is supported, you would still have to be running _MRI Ruby
14
+ 1.9.3_ and above. It may run on _Rubinius_ and _JRuby_, but we haven't tested
15
+ those yet.
16
+
17
+ Installation
18
+ ------------
19
+
20
+ To install it in your current application, add the following to your `Gemfile`.
21
+
22
+ ```ruby
23
+ group :development do
24
+ gem 'web-console-rails3', '~> 0.2.0'
25
+ end
26
+ ```
27
+
28
+ After you save the `Gemfile` changes, make sure to run `bundle install` and
29
+ restart your server for the [Web Console] to take affect.
30
+
31
+ By default, it should be available in your development environment under
32
+ `/console`. The route is not automatically mounted in a production environment
33
+ and we strongly encourage you to keep it that way.
34
+
35
+ More
36
+ ----
37
+
38
+ For more information visit _Web Console_ [home page][Web Console].
39
+
40
+ [Web Console]: https://github.com/gsamokovarov/web-console
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'socket'
8
+ require 'active_support/core_ext/string/strip'
9
+ require 'rake/testtask'
10
+
11
+ EXPANDED_CWD = File.expand_path(File.dirname(__FILE__))
12
+
13
+ Rake::TestTask.new(:test) do |t|
14
+ t.libs << 'lib'
15
+ t.libs << 'test'
16
+ t.pattern = 'test/**/*_test.rb'
17
+ t.verbose = false
18
+ end
19
+
20
+ # Just ignore this if rake is not runned from the current directory, as is the
21
+ # case with docker's container. BUNDLE_GEMFILE won't do for our case, since the
22
+ # Gemfile references gemspec.
23
+ Bundler::GemHelper.install_tasks if defined? Bundler::GemHelper
24
+
25
+ namespace :docker do
26
+ task :sync do
27
+ Dir.chdir(EXPANDED_CWD) do
28
+ sh "git fetch && git reset --hard origin/master", verbose: false
29
+ end
30
+ end
31
+
32
+ task run: :sync do
33
+ # Generally, the first ipv4 private address is how we would access the
34
+ # docker container from the current machine.
35
+ container_ip = Socket.ip_address_list.find(&:ipv4_private?).ip_address
36
+
37
+ puts <<-NOTICE.strip_heredoc
38
+ Go to http://#{container_ip}:3000/console to preview web-console.
39
+ If it's not showing, please give a few seconds for the server to start.
40
+ NOTICE
41
+
42
+ Dir.chdir("#{EXPANDED_CWD}/test/dummy") do
43
+ sh 'rails server', verbose: false
44
+ end
45
+ end
46
+ end
47
+
48
+ task default: :test
@@ -0,0 +1,4 @@
1
+ //= require jquery
2
+ //= require jquery_ujs
3
+ //= require jquery.console
4
+ //= require_tree .
@@ -0,0 +1,24 @@
1
+ $(function() {
2
+ var ERROR_CLASS = 'jquery-console-message-error';
3
+
4
+ var $console = $('#console');
5
+ var instance = $console.console({
6
+ autofocus: true,
7
+ promptLabel: $console.data('initial-prompt'),
8
+ commandHandle: function(line, report) {
9
+ $.ajax({
10
+ url: $console.data('remote-path'),
11
+ type: 'PUT',
12
+ dataType: 'json',
13
+ data: { input: line },
14
+ success: function(response) {
15
+ instance.promptLabel(response.prompt);
16
+ report([{msg: response.output}]);
17
+ },
18
+ error: function(xhr) {
19
+ report([{msg: xhr.responseJSON.error, className: ERROR_CLASS}]);
20
+ }
21
+ });
22
+ }
23
+ });
24
+ });
@@ -0,0 +1,13 @@
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
+ */
@@ -0,0 +1,8 @@
1
+ body, div, textarea { margin: 0; padding 0 }
2
+
3
+ #console { font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 13px; position: fixed; width: 98%; height: 98%; left: 1%; top: 1% }
4
+ #console div.jquery-console-inner { height: 100%; background: #333; color: #fff; overflow: auto }
5
+ #console div.jquery-console-focus span.jquery-console-cursor { font-weight: bold; background: #fff }
6
+ #console div.jquery-console-message { white-space: pre-wrap }
7
+ #console div.jquery-console-message-error { font-weight: bold; color: #ff530d }
8
+ #console span.jquery-console-prompt-label { font-weight: bold }
@@ -0,0 +1,17 @@
1
+ module WebConsole
2
+ class ApplicationController < ActionController::Base
3
+ class << self
4
+ # Alias before_filter to before_action for Rails 3 compatibility.
5
+ alias :before_action :before_filter unless defined?(before_filter)
6
+ end
7
+
8
+ before_action :prevent_unauthorized_requests!
9
+
10
+ private
11
+ def prevent_unauthorized_requests!
12
+ unless request.remote_ip.in?(WebConsole.config.whitelisted_ips)
13
+ render nothing: true, status: :unauthorized
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ require_dependency "web_console/application_controller"
2
+
3
+ module WebConsole
4
+ class ConsoleSessionsController < ApplicationController
5
+ rescue_from ConsoleSession::NotFound do |exception|
6
+ render json: exception, status: :gone
7
+ end
8
+
9
+ def index
10
+ @console_session = ConsoleSession.create
11
+ end
12
+
13
+ def update
14
+ @console_session = ConsoleSession.find(params[:id])
15
+ render json: @console_session.save(console_session_params)
16
+ end
17
+
18
+ private
19
+ def console_session_params
20
+ params.permit(:input)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ module WebConsole
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module WebConsole
2
+ module ConsoleSessionHelper
3
+ end
4
+ end
@@ -0,0 +1,110 @@
1
+ module WebConsole
2
+ class ConsoleSession
3
+ include Mutex_m
4
+
5
+ include ActiveModel::Model
6
+ include ActiveModel::Serializers::JSON
7
+
8
+ # In-memory storage for the console sessions. Session preservation is
9
+ # troubled on servers with multiple workers and threads.
10
+ INMEMORY_STORAGE = {}
11
+
12
+ # Store and define the available attributes.
13
+ ATTRIBUTES = [ :id, :input, :output, :prompt ].each do |attr|
14
+ attr_accessor attr
15
+ end
16
+
17
+ # Raised when trying to find a session that is no longer in the in-memory
18
+ # session storage.
19
+ class NotFound < Exception
20
+ def to_json(*)
21
+ {error: message}.to_json
22
+ end
23
+ end
24
+
25
+ class << self
26
+ # Finds a session by its id.
27
+ #
28
+ # Raises WebConsole::ConsoleSession::Expired if there is no such session.
29
+ def find(id)
30
+ INMEMORY_STORAGE[id.to_i] or raise NotFound.new('Session unavailable')
31
+ end
32
+
33
+ # Creates an already persisted consolse session.
34
+ #
35
+ # Use this method if you need to persist a session, without providing it
36
+ # any input.
37
+ def create
38
+ INMEMORY_STORAGE[(model = new).id] = model
39
+ end
40
+ end
41
+
42
+ def initialize(attributes = {})
43
+ @repl = WebConsole::REPL.default.new
44
+
45
+ super
46
+ ensure_consequential_id!
47
+ populate_repl_attributes!(initial: true)
48
+ end
49
+
50
+ # Saves the model into the in-memory storage.
51
+ #
52
+ # Returns false if the model is not valid (e.g. its missing input).
53
+ def save(attributes = {})
54
+ self.attributes = attributes if attributes.present?
55
+ populate_repl_attributes!
56
+ store!
57
+ end
58
+
59
+ # Returns true if the current session is persisted in the in-memory storage.
60
+ def persisted?
61
+ self == INMEMORY_STORAGE[id]
62
+ end
63
+
64
+ # Returns an Enumerable of all key attributes if any is set, regardless if
65
+ # the object is persisted or not.
66
+ def to_key
67
+ super if persisted?
68
+ end
69
+
70
+ protected
71
+ # Returns a hash of the attributes and their values.
72
+ def attributes
73
+ return Hash[ATTRIBUTES.zip([nil])]
74
+ end
75
+
76
+ # Sets model attributes from a hash.
77
+ def attributes=(attributes)
78
+ attributes.each do |attr, value|
79
+ next unless ATTRIBUTES.include?(attr.to_sym)
80
+ public_send(:"#{attr}=", value)
81
+ end
82
+ end
83
+
84
+ private
85
+ def ensure_consequential_id!
86
+ synchronize do
87
+ self.id = begin
88
+ @@counter ||= 0
89
+ @@counter += 1
90
+ end
91
+ end
92
+ end
93
+
94
+ def populate_repl_attributes!(options = {})
95
+ synchronize do
96
+ # Don't send any input on the initial population so we don't bump up
97
+ # the numbers in the dynamic prompts.
98
+ self.output = @repl.send_input(input) unless options[:initial]
99
+ self.prompt = @repl.prompt
100
+ end
101
+ end
102
+
103
+ def store!
104
+ synchronize { INMEMORY_STORAGE[id] = self }
105
+ end
106
+ end
107
+
108
+ # Explicitly configue include_root_in_json for Rails 3 compatibility.
109
+ ConsoleSession.include_root_in_json = false
110
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>WebConsole</title>
5
+ <%= stylesheet_link_tag "web_console/application", media: "all" %>
6
+ <%= javascript_include_tag "web_console/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,4 @@
1
+ <div id="console"
2
+ data-remote-path="<%= web_console.console_session_path(@console_session) %>"
3
+ data-initial-prompt="<%= @console_session.prompt %>">
4
+ </div>
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ WebConsole::Engine.routes.draw do
2
+ root to: 'console_sessions#index'
3
+
4
+ resources :console_sessions
5
+ end
@@ -0,0 +1 @@
1
+ require 'web_console'
@@ -0,0 +1 @@
1
+ require 'web_console'
@@ -0,0 +1,21 @@
1
+ require 'rails/version'
2
+ require 'active_support/lazy_load_hooks'
3
+ require 'web_console/engine'
4
+ require 'web_console/repl'
5
+
6
+ module WebConsole
7
+ # Shortcut the +WebConsole::Engine.config.web_console+.
8
+ def self.config
9
+ Engine.config.web_console
10
+ end
11
+
12
+ ActiveSupport.run_load_hooks(:web_console, self)
13
+ end
14
+
15
+ if Rails::VERSION::MAJOR == 3
16
+ # ActiveModel::Model is not defined in Rails 3. Use a backported version.
17
+ require 'web_console/backport/active_model'
18
+
19
+ # Explicitly require strong_parameters to make sure the users won't have to.
20
+ require 'strong_parameters'
21
+ end
@@ -0,0 +1,26 @@
1
+ module ActiveModel
2
+ # Comment stripped version of ActiveModel::Model from rails/rails revision
3
+ # 85750d43fa714f6773396b8304430f2d1f459350.
4
+ module Model
5
+ def self.included(base) #:nodoc:
6
+ base.class_eval do
7
+ extend ActiveModel::Naming
8
+ extend ActiveModel::Translation
9
+ include ActiveModel::Validations
10
+ include ActiveModel::Conversion
11
+ end
12
+ end
13
+
14
+ def initialize(params={})
15
+ params.each do |attr, value|
16
+ self.public_send("#{attr}=", value)
17
+ end if params
18
+
19
+ super()
20
+ end
21
+
22
+ def persisted?
23
+ false
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ require 'ipaddr'
2
+ require 'rails/engine'
3
+ require 'jquery-rails'
4
+
5
+ module WebConsole
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace WebConsole
8
+
9
+ config.web_console = ActiveSupport::OrderedOptions.new
10
+
11
+ config.web_console.default_mount_path = '/console'
12
+ config.web_console.whitelisted_ips = '127.0.0.1'
13
+ config.web_console.prevent_irbrc_execution = false
14
+
15
+ initializer 'web_console.add_default_route' do |app|
16
+ # While we don't need the route in the test environment, we define it
17
+ # there as well, so we can easily test it.
18
+ if Rails.env.development? || Rails.env.test?
19
+ app.routes.append do
20
+ mount WebConsole::Engine => app.config.web_console.default_mount_path
21
+ end
22
+ end
23
+ end
24
+
25
+ initializer 'web_console.process_whitelisted_ips' do
26
+ # Ensure that it is an array of IPAddr instances and it is defaulted to
27
+ # 127.0.0.1 if not precent. Only unique entries are left in the end.
28
+ config.web_console.whitelisted_ips = Array(config.web_console.whitelisted_ips)
29
+ config.web_console.whitelisted_ips.map! do |ip|
30
+ ip.is_a?(IPAddr) ? ip : IPAddr.new(ip.presence || '127.0.0.1')
31
+ end.uniq!
32
+
33
+ # IPAddr instances can cover whole networks, so simplify the #include?
34
+ # check for the most common case.
35
+ def (config.web_console.whitelisted_ips).include?(ip)
36
+ ip.is_a?(IPAddr) ? super : any? { |net| net.include?(ip.to_s) }
37
+ end
38
+ end
39
+ end
40
+ end