mongo_browser 0.1.0

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 (47) hide show
  1. data/.gitignore +4 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +12 -0
  4. data/Gemfile +19 -0
  5. data/LICENSE +22 -0
  6. data/README.md +31 -0
  7. data/README.rdoc +19 -0
  8. data/Rakefile +61 -0
  9. data/app/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  10. data/app/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  11. data/app/assets/javascripts/app/table_filter.js.coffee +50 -0
  12. data/app/assets/javascripts/application.js.coffee +32 -0
  13. data/app/assets/javascripts/vendor/bootbox.js +508 -0
  14. data/app/assets/javascripts/vendor/bootstrap.js +2025 -0
  15. data/app/assets/javascripts/vendor/jquery.js +9266 -0
  16. data/app/assets/stylesheets/application.css.scss +22 -0
  17. data/app/assets/stylesheets/vendor/bootstrap-responsive.css +1088 -0
  18. data/app/assets/stylesheets/vendor/bootstrap.css +5893 -0
  19. data/app/views/collections/show.erb +61 -0
  20. data/app/views/databases/show.erb +59 -0
  21. data/app/views/index.erb +29 -0
  22. data/app/views/layout.erb +19 -0
  23. data/app/views/layout/_breadcrumb.erb +13 -0
  24. data/app/views/layout/_flash_messages.erb +10 -0
  25. data/app/views/layout/_navbar.erb +21 -0
  26. data/app/views/server_info.erb +20 -0
  27. data/app/views/shared/_filter.erb +14 -0
  28. data/bin/mongo_browser +53 -0
  29. data/config.ru +4 -0
  30. data/features/mongo_browser.feature +18 -0
  31. data/features/step_definitions/mongo_browser_steps.rb +1 -0
  32. data/features/support/env.rb +18 -0
  33. data/lib/mongo_browser.rb +32 -0
  34. data/lib/mongo_browser/application.rb +108 -0
  35. data/lib/mongo_browser/middleware/sprockets_sinatra.rb +24 -0
  36. data/lib/mongo_browser/version.rb +3 -0
  37. data/mongo_browser.gemspec +32 -0
  38. data/spec/features/collections_list_spec.rb +105 -0
  39. data/spec/features/databases_list_spec.rb +60 -0
  40. data/spec/features/documents_list_spec.rb +136 -0
  41. data/spec/features/server_info_spec.rb +17 -0
  42. data/spec/fixtures/databases.json +40 -0
  43. data/spec/spec_helper.rb +56 -0
  44. data/spec/support/have_flash_message_matcher.rb +16 -0
  45. data/spec/support/integration.rb +26 -0
  46. data/spec/support/mongo_test_server.rb +50 -0
  47. metadata +313 -0
@@ -0,0 +1,61 @@
1
+ <div class="page-header">
2
+ <h2>Collection <%= params[:collection_name] %></h2>
3
+ </div>
4
+
5
+ <ul class="nav nav-tabs">
6
+ <li class="active">
7
+ <a href="#documents" data-toggle="tab">Documents</a>
8
+ </li>
9
+ <li><a href="#stats" data-toggle="tab">Stats</a></li>
10
+ </ul>
11
+
12
+ <div class="tab-content">
13
+ <div class="tab-pane active" id="documents">
14
+ <%= will_paginate(@pagination, renderer: BootstrapPagination::Sinatra) %>
15
+
16
+ <table class="table table-striped table-hover documents">
17
+ <thead>
18
+ <tr>
19
+ <th>Id</th>
20
+ <th>Data</th>
21
+ <th>&nbsp;</th>
22
+ </tr>
23
+ </thead>
24
+ <tbody>
25
+ <% @documents.each do |document| %>
26
+ <tr class="document">
27
+ <td><%= document['_id'] %></td>
28
+ <td><%= document.ai(html: true) %></td>
29
+ <td>
30
+ <a href="/databases/<%= params[:db_name] %>/collections/<%= params[:collection_name] %>/<%= document['_id'] %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">
31
+ <i class="icon-remove-circle"></i>
32
+ Delete
33
+ </a>
34
+ </td>
35
+ </tr>
36
+ <% end %>
37
+ </tbody>
38
+ </table>
39
+
40
+ <%= will_paginate(@pagination, renderer: BootstrapPagination::Sinatra) %>
41
+ </div>
42
+
43
+ <div class="tab-pane" id="stats">
44
+ <table class="table table-striped table-hover">
45
+ <thead>
46
+ <tr>
47
+ <th>Property</th>
48
+ <th>Value</th>
49
+ </tr>
50
+ </thead>
51
+ <tbody>
52
+ <% @stats.each do |property, value| %>
53
+ <tr>
54
+ <td><%= property %></td>
55
+ <td><%= value %></td>
56
+ </tr>
57
+ <% end %>
58
+ </tbody>
59
+ </table>
60
+ </div>
61
+ </div>
@@ -0,0 +1,59 @@
1
+ <div class="page-header">
2
+ <h2>Database <%= params[:db_name] %></h2>
3
+ </div>
4
+
5
+ <ul class="nav nav-tabs">
6
+ <li class="active">
7
+ <a href="#collections" data-toggle="tab">Collections</a>
8
+ </li>
9
+ <li><a href="#stats" data-toggle="tab">Stats</a></li>
10
+ </ul>
11
+
12
+ <div class="tab-content">
13
+ <div class="tab-pane active" id="collections">
14
+ <%= erb :"shared/_filter", {}, { filter_for: "collections", placeholder: "Collection name" } %>
15
+
16
+ <table class="table table-striped table-hover collections">
17
+ <thead>
18
+ <tr>
19
+ <th>Name</th>
20
+ <th>Size</th>
21
+ <th>&nbsp;</th>
22
+ </tr>
23
+ </thead>
24
+ <tbody>
25
+ <% @collections.each do |collection| %>
26
+ <tr class="collection">
27
+ <td><a href="/databases/<%= params[:db_name] %>/collections/<%= collection.name %>"><%= collection.name %></a></td>
28
+ <td><%= collection.size %></td>
29
+ <td>
30
+ <a href="/databases/<%= params[:db_name] %>/collections/<%= collection.name %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">
31
+ <i class="icon-remove-circle"></i>
32
+ Delete
33
+ </a>
34
+ </td>
35
+ </tr>
36
+ <% end %>
37
+ </tbody>
38
+ </table>
39
+ </div>
40
+
41
+ <div class="tab-pane" id="stats">
42
+ <table class="table table-striped table-hover">
43
+ <thead>
44
+ <tr>
45
+ <th>Property</th>
46
+ <th>Value</th>
47
+ </tr>
48
+ </thead>
49
+ <tbody>
50
+ <% @stats.each do |property, value| %>
51
+ <tr>
52
+ <td><%= property %></td>
53
+ <td><%= value %></td>
54
+ </tr>
55
+ <% end %>
56
+ </tbody>
57
+ </table>
58
+ </div>
59
+ </div>
@@ -0,0 +1,29 @@
1
+ <div class="page-header">
2
+ <h2>Available databases</h2>
3
+ </div>
4
+
5
+ <%= erb :"shared/_filter", {}, { filter_for: "databases", placeholder: "Database name" } %>
6
+
7
+ <table class="table table-striped table-hover databases">
8
+ <thead>
9
+ <tr>
10
+ <th>Name</th>
11
+ <th>Size</th>
12
+ <th>&nbsp;</th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <% @databases.each do |db_name, db_size| %>
17
+ <tr>
18
+ <td><a href="/databases/<%= db_name %>"><%= db_name %></a></td>
19
+ <td><%= db_size %></td>
20
+ <td>
21
+ <a href="/databases/<%= db_name %>" class="btn btn-danger" data-method="delete" data-confirm="Are you sure?">
22
+ <i class="icon-remove-circle"></i>
23
+ Delete
24
+ </a>
25
+ </td>
26
+ </tr>
27
+ <% end %>
28
+ </tbody>
29
+ </table>
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Mongo Browser</title>
5
+ <link href="/assets/application.css" rel="stylesheet" media="screen">
6
+ </head>
7
+ <body>
8
+ <%= erb :"layout/_navbar" %>
9
+
10
+ <div class="container">
11
+ <%= erb :"layout/_flash_messages" %>
12
+ <%= erb :"layout/_breadcrumb" %>
13
+
14
+ <%= yield %>
15
+ </div>
16
+
17
+ <script src="/assets/application.js"></script>
18
+ </body>
19
+ </html>
@@ -0,0 +1,13 @@
1
+ <% if params[:db_name] %>
2
+ <ul class="breadcrumb">
3
+ <li><a href="/">Databases</a><span class="divider">/</span></li>
4
+
5
+ <% unless params[:collection_name] %>
6
+ <li>db: <%= params[:db_name] %></li>
7
+ <% else %>
8
+ <li><a href="/databases/<%= params[:db_name] %>">db: <%= params[:db_name] %></a>
9
+ <span class="divider">/</span></li>
10
+ <li>collection: <%= params[:collection_name] %></li>
11
+ <% end %>
12
+ </ul>
13
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <% unless flash(:flash).empty? %>
2
+ <div id="flash-messages">
3
+ <% flash(:flash).each do |message| %>
4
+ <div class="alert alert-<%= message[0] %>">
5
+ <button type="button" class="close" data-dismiss="alert">×</button>
6
+ <strong><%= message[0].capitalize %>!</strong> <%= message[1] %>
7
+ </div>
8
+ <% end %>
9
+ </div>
10
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <div class="navbar navbar navbar-fixed-top">
2
+ <div class="navbar-inner">
3
+ <div class="container">
4
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
5
+ <span class="icon-bar"></span>
6
+ <span class="icon-bar"></span>
7
+ <span class="icon-bar"></span>
8
+ </a>
9
+ <a class="brand" href="/">Mongo Browser</a>
10
+ <div class="nav-collapse collapse">
11
+ <ul class="nav">
12
+ <li><a href="/server_info">Server Info</a></li>
13
+ </ul>
14
+
15
+ <ul class="nav pull-right">
16
+ <li><a>v. <%= MongoBrowser::VERSION %></a></li>
17
+ </ul>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </div>
@@ -0,0 +1,20 @@
1
+ <div class="page-header">
2
+ <h2>Server info</h2>
3
+ </div>
4
+
5
+ <table class="table table-striped table-hover">
6
+ <thead>
7
+ <tr>
8
+ <th>Property</th>
9
+ <th>Value</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% @server_info.each do |property, value| %>
14
+ <tr>
15
+ <td><%= property %></td>
16
+ <td><%= value %></td>
17
+ </tr>
18
+ <% end %>
19
+ </tbody>
20
+ </table>
@@ -0,0 +1,14 @@
1
+ <form class="filter" data-filter-for="<%= filter_for %>">
2
+ <div class="input-append">
3
+ <input type="text" value="" class="span3" placeholder="<%= placeholder %>">
4
+
5
+ <button type="button" class="btn clear">
6
+ <i class="icon-remove-circle"></i>Clear
7
+ </button>
8
+ </div>
9
+ <span class="help-block">Press ESC to clear the filter</span>
10
+ </form>
11
+
12
+ <div class="filter alert" style="display: none;">
13
+ Nothing has been found.
14
+ </div>
data/bin/mongo_browser ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require "methadone"
5
+ require "mongo_browser"
6
+ require "forever"
7
+
8
+ class App
9
+ include Methadone::Main
10
+ include Methadone::CLILogging
11
+
12
+ main do
13
+ app_port = options[:port] || 4567
14
+ info("Running on the master node #{MongoBrowser.mongodb_host}:#{MongoBrowser.mongodb_port}")
15
+ info("Application is accessible at http://localhost:#{app_port}")
16
+
17
+ if options[:demonize]
18
+ Forever.run do
19
+ pid '/tmp/mongo_browser.pid'
20
+ log '/tmp/mongo_browser.log'
21
+
22
+ on_ready do
23
+ MongoBrowser::Application.run!(port: app_port)
24
+ end
25
+ end
26
+ else
27
+ MongoBrowser::Application.run!(port: app_port)
28
+ end
29
+ end
30
+
31
+ version MongoBrowser::VERSION
32
+
33
+ on("--port PORT", "MongoBrowser port",
34
+ "(Default: 4567)")
35
+
36
+ on("--mongodb-host HOST", "Mongodb database host",
37
+ "(Default: #{MongoBrowser.mongodb_host})") do |host|
38
+
39
+ MongoBrowser.mongodb_host = host
40
+ end
41
+
42
+ on("--mongodb-port PORT", "Mongodb database port",
43
+ "(Default: #{MongoBrowser.mongodb_port})") do |port|
44
+
45
+ MongoBrowser.mongodb_port = port.to_i
46
+ end
47
+
48
+ on("--demonize", "Run the app in the background")
49
+
50
+ use_log_level_option
51
+
52
+ go!
53
+ end
data/config.ru ADDED
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "lib"))
2
+
3
+ require "mongo_browser"
4
+ run MongoBrowser::Application
@@ -0,0 +1,18 @@
1
+ Feature: My bootstrapped app kinda works
2
+ In order to get going on coding my awesome app
3
+ I want to have aruba and cucumber setup
4
+ So I don't have to do it myself
5
+
6
+ Scenario: App just runs
7
+ When I get help for "mongo_browser"
8
+ Then the exit status should be 0
9
+ And the banner should be present
10
+ And the banner should document that this app takes options
11
+ And the following options should be documented:
12
+ | --version |
13
+ | --port |
14
+ | --mongodb-host |
15
+ | --mongodb-port |
16
+ | --demonize |
17
+ | --log-level |
18
+ And the banner should document that this app takes no arguments
@@ -0,0 +1 @@
1
+ # Put your step definitions here
@@ -0,0 +1,18 @@
1
+ require 'aruba/cucumber'
2
+ require 'methadone/cucumber'
3
+
4
+ ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
5
+ LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
6
+
7
+ Before do
8
+ @aruba_timeout_seconds = 10
9
+
10
+ # Using "announce" causes massive warnings on 1.9.2
11
+ @puts = true
12
+ @original_rubylib = ENV['RUBYLIB']
13
+ ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
14
+ end
15
+
16
+ After do
17
+ ENV['RUBYLIB'] = @original_rubylib
18
+ end
@@ -0,0 +1,32 @@
1
+ require "mongo_browser/version"
2
+
3
+ require "sinatra"
4
+ require "sinatra/reloader"
5
+ require "sinatra/flash"
6
+
7
+ require "sprockets"
8
+ require "sass"
9
+ require "coffee_script"
10
+
11
+ require "will_paginate-bootstrap"
12
+ require "mongo"
13
+ require "json"
14
+ require "ap"
15
+
16
+ module MongoBrowser
17
+ class << self
18
+ attr_writer :mongodb_host
19
+ attr_writer :mongodb_port
20
+
21
+ def mongodb_host
22
+ @mongodb_host || "localhost"
23
+ end
24
+
25
+ def mongodb_port
26
+ @mongodb_port || 27017
27
+ end
28
+ end
29
+ end
30
+
31
+ require "mongo_browser/middleware/sprockets_sinatra"
32
+ require "mongo_browser/application"
@@ -0,0 +1,108 @@
1
+ module MongoBrowser
2
+ class Application < Sinatra::Base
3
+ configure :development do
4
+ register Sinatra::Reloader
5
+ end
6
+
7
+ enable :sessions
8
+ register Sinatra::Flash
9
+
10
+ set :root, File.join(File.dirname(__FILE__), "../../app")
11
+ set :method_override, true
12
+
13
+ use MongoBrowser::Middleware::SprocketsSinatra, :root => settings.root, :path => "assets"
14
+ register WillPaginate::Sinatra
15
+
16
+ # Databases list
17
+ get "/" do
18
+ @databases = connection.database_info
19
+ erb :"index"
20
+ end
21
+
22
+ # Collections list
23
+ get "/databases/:db_name" do
24
+ database = connection.db(params[:db_name])
25
+ @collections = database.collections
26
+ @stats = database.stats
27
+
28
+ erb :"databases/show"
29
+ end
30
+
31
+ # Delete a database
32
+ delete "/databases/:db_name" do
33
+ connection.drop_database(params[:db_name])
34
+
35
+ flash[:info] = "Database #{params[:db_name]} has been deleted."
36
+ redirect "/"
37
+ end
38
+
39
+ # Documents list
40
+ get "/databases/:db_name/collections/:collection_name" do
41
+ database = connection.db(params[:db_name])
42
+ collection = database.collection(params[:collection_name])
43
+
44
+ @stats = collection.stats
45
+ @documents, @pagination = paginate_documents_for(collection, params[:page])
46
+
47
+ erb :"collections/show"
48
+ end
49
+
50
+ # Delete a collection
51
+ delete "/databases/:db_name/collections/:collection_name" do
52
+ begin
53
+ database = connection.db(params[:db_name])
54
+ database.drop_collection(params[:collection_name])
55
+
56
+ flash[:info] = "Collection #{params[:collection_name]} has been deleted."
57
+ rescue Mongo::OperationFailure => e
58
+ flash[:error] = e.message
59
+ end
60
+
61
+ redirect "/databases/#{params[:db_name]}"
62
+ end
63
+
64
+ # Delete a document
65
+ delete "/databases/:db_name/collections/:collection_name/:id" do
66
+ database = connection.db(params[:db_name])
67
+ collection = database.collection(params[:collection_name])
68
+
69
+ id = BSON::ObjectId(params[:id])
70
+ collection.remove(_id: id)
71
+
72
+ flash[:info] = "Document #{params[:id]} has been deleted."
73
+ redirect "/databases/#{params[:db_name]}/collections/#{params[:collection_name]}"
74
+ end
75
+
76
+ # Server info
77
+ get "/server_info" do
78
+ @server_info = connection.server_info
79
+ erb :"server_info"
80
+ end
81
+
82
+ private
83
+
84
+ def paginate_documents_for(collection, page = 1)
85
+ per_page = 25
86
+
87
+ count = collection.count
88
+ total_pages = (count.to_f / per_page).ceil
89
+
90
+ page = if page.to_i <= 0 then 1
91
+ else
92
+ [page.to_i, total_pages].min
93
+ end
94
+
95
+ offset = (page - 1) * per_page
96
+ documents = collection.find.skip(offset).limit(per_page)
97
+ pagination = OpenStruct.new \
98
+ total_pages: total_pages,
99
+ current_page: page
100
+
101
+ return documents, pagination
102
+ end
103
+
104
+ def connection
105
+ @connection ||= Mongo::Connection.new(MongoBrowser.mongodb_host, MongoBrowser.mongodb_port)
106
+ end
107
+ end
108
+ end