mongo_fe 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.
- data/.DS_Store +0 -0
- data/.gitignore +34 -0
- data/.rspec +2 -0
- data/CHANGES.md +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +138 -0
- data/LICENSE +22 -0
- data/Procfile +2 -0
- data/README.md +72 -0
- data/Rakefile +14 -0
- data/TODO.tasks +9 -0
- data/bin/config.ru +28 -0
- data/bin/mongofe +54 -0
- data/lib/mongo_fe/application_controller.rb +91 -0
- data/lib/mongo_fe/controllers/collections_controller.rb +278 -0
- data/lib/mongo_fe/controllers/databases_controller.rb +94 -0
- data/lib/mongo_fe/helpers/helpers.rb +128 -0
- data/lib/mongo_fe/public/app/application.js +3 -0
- data/lib/mongo_fe/public/bootstrap/css/bootstrap-responsive.css +567 -0
- data/lib/mongo_fe/public/bootstrap/css/bootstrap.css +3380 -0
- data/lib/mongo_fe/public/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/lib/mongo_fe/public/bootstrap/img/glyphicons-halflings.png +0 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-alert.js +91 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-button.js +98 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-carousel.js +154 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-collapse.js +136 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-dropdown.js +92 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-modal.js +209 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-popover.js +95 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-scrollspy.js +125 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-tab.js +130 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-tooltip.js +270 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-transition.js +51 -0
- data/lib/mongo_fe/public/bootstrap/js/basic/bootstrap-typeahead.js +271 -0
- data/lib/mongo_fe/public/bootstrap/js/bootstrap.js +1722 -0
- data/lib/mongo_fe/public/bootstrap/js/bootstrap.min.js +1 -0
- data/lib/mongo_fe/public/bootstrap/js/jquery.js +9252 -0
- data/lib/mongo_fe/public/bootstrap/js/underscore-min.js +32 -0
- data/lib/mongo_fe/public/bootstrap/js/underscore.js +1059 -0
- data/lib/mongo_fe/public/css/digg_pagination.css +28 -0
- data/lib/mongo_fe/public/css/jsoneditor.css +70 -0
- data/lib/mongo_fe/public/css/styles.css +11 -0
- data/lib/mongo_fe/public/images/missing_avatar_small.png +0 -0
- data/lib/mongo_fe/public/js/collection-tools.js +63 -0
- data/lib/mongo_fe/public/js/db-tools.js +45 -0
- data/lib/mongo_fe/public/js/jsoneditor/jquery.jsoneditor.min.LICENSE +20 -0
- data/lib/mongo_fe/public/js/jsoneditor/jquery.jsoneditor.min.js +6 -0
- data/lib/mongo_fe/public/js/jsoneditor/json2.js +482 -0
- data/lib/mongo_fe/version.rb +6 -0
- data/lib/mongo_fe/views/collections/_document_attributes.haml +6 -0
- data/lib/mongo_fe/views/collections/_documents.haml +35 -0
- data/lib/mongo_fe/views/collections/_documents_page.haml +82 -0
- data/lib/mongo_fe/views/collections/_indexes.haml +76 -0
- data/lib/mongo_fe/views/collections/index.haml +80 -0
- data/lib/mongo_fe/views/databases/_list_users.haml +27 -0
- data/lib/mongo_fe/views/databases/info.haml +80 -0
- data/lib/mongo_fe/views/footer.haml +4 -0
- data/lib/mongo_fe/views/index.haml +7 -0
- data/lib/mongo_fe/views/layout.haml +148 -0
- data/lib/mongo_fe/views/navbar.haml +17 -0
- data/lib/mongo_fe.rb +170 -0
- data/mongo_fe.gemspec +50 -0
- data/screens/example_db_view.png +0 -0
- data/screens/example_doc_view.png +0 -0
- data/screens/example_indexes.png +0 -0
- data/spec/config_spec.rb +17 -0
- data/spec/controllers/collections_controller_spec.rb +151 -0
- data/spec/controllers/db_controller_spec.rb +69 -0
- data/spec/factories/factories.rb +19 -0
- data/spec/spec_helper.rb +88 -0
- metadata +559 -0
data/spec/config_spec.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "MongoFe" do
|
|
4
|
+
describe "the gem configuration" do
|
|
5
|
+
it "is versioned" do
|
|
6
|
+
MongoFe::VERSION.should =~ /\d+\.\d+\.\d+/
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "has access to a local database" do
|
|
10
|
+
MongoFe::MongoDB.connection.should_not be_nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "can access some data" do
|
|
14
|
+
MongoFe::MongoDB.available_databases.count.should >= 0
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "ostruct"
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
describe "Collections Controller" do
|
|
6
|
+
class Index
|
|
7
|
+
attr_accessor :name
|
|
8
|
+
attr_reader :fields
|
|
9
|
+
|
|
10
|
+
def initialize(fields="", unique=true, sparse=false)
|
|
11
|
+
@fields=fields
|
|
12
|
+
@unique=unique
|
|
13
|
+
@sparse=sparse
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def unique?
|
|
17
|
+
@unique
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def sparse?
|
|
21
|
+
@sparse
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
let(:db_name) { "mongo_fe_test_db_collections_29837419283741928374192834719283" }
|
|
26
|
+
let(:collection_name) { "my_mongo_fe_collection" }
|
|
27
|
+
let(:collection_new_name) { "my_new_mongo_fe_collection" }
|
|
28
|
+
|
|
29
|
+
# use Time.new.strftime("%d-%m-%Y")? meh
|
|
30
|
+
let(:test_doc) { {:lng => "gr", :description => "Hopa!", :created_at => Time.now.to_i} }
|
|
31
|
+
let(:test_doc_json) { test_doc.to_json }
|
|
32
|
+
|
|
33
|
+
let(:index) { Index.new("lng:asc, created_at:desc") }
|
|
34
|
+
|
|
35
|
+
# select/create a test database
|
|
36
|
+
before(:all) do
|
|
37
|
+
get "/databases/#{db_name}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# clean the test database.
|
|
41
|
+
after(:all) do
|
|
42
|
+
delete "/databases/#{db_name}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Adding a new collection to a test database
|
|
46
|
+
describe "POST /databases/:db_name/collections/" do
|
|
47
|
+
it "should create a new collection" do
|
|
48
|
+
post "/databases/#{db_name}/collections", {:collection_name => collection_name}
|
|
49
|
+
follow_redirect!
|
|
50
|
+
last_response.body.should contain("#{collection_name}, successfully created!")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# return success if a database is selected and we want to display the available
|
|
55
|
+
# collections
|
|
56
|
+
describe "GET /databases/:db_name/collections" do
|
|
57
|
+
#,{}, "rack.session" => {:session => {:db => "test"} } .... meh
|
|
58
|
+
it "should list all the collections available" do
|
|
59
|
+
get "/databases/#{db_name}/collections"
|
|
60
|
+
last_response.status.should eq(200)
|
|
61
|
+
last_response.body.should contain("#{collection_name}")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "GET /databases/:db_name/collections/:collection_name" do
|
|
66
|
+
it "should display the stats for the given collection" do
|
|
67
|
+
get "/databases/#{db_name}/collections/#{collection_name}"
|
|
68
|
+
last_response.body.should contain("\"ns\": \"#{db_name}.#{collection_name}\"")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe "PUT /databases/:db_name/collections/:collection_name" do
|
|
73
|
+
it "should rename a collection" do
|
|
74
|
+
put "/databases/#{db_name}/collections/#{collection_name}", {:collection_new_name => collection_new_name}
|
|
75
|
+
follow_redirect!
|
|
76
|
+
last_response.body.should_not contain("\"ns\": \"#{db_name}.#{collection_name}\"")
|
|
77
|
+
last_response.body.should contain("\"ns\": \"#{db_name}.#{collection_new_name}\"")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "POST /databases/:db_name/collections/:collection_name/documents" do
|
|
82
|
+
it "should insert a new document" do
|
|
83
|
+
post "/databases/#{db_name}/collections/#{collection_name}/documents", {:json_doc_attributes => test_doc_json}
|
|
84
|
+
last_response.body.should contain("added to: #{db_name}.#{collection_name}")
|
|
85
|
+
# todo verify the Document insertion
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe "DELETE /databases/:db_name/collections/:collection_name/documents" do
|
|
90
|
+
it "should delete an existing document" do
|
|
91
|
+
|
|
92
|
+
db = MongoFe::MongoDB.use db_name
|
|
93
|
+
db.should_not be_nil
|
|
94
|
+
|
|
95
|
+
c = db.collection(collection_name)
|
|
96
|
+
c.should_not be_nil
|
|
97
|
+
|
|
98
|
+
doc = c.find_one test_doc
|
|
99
|
+
doc.should_not be_nil
|
|
100
|
+
|
|
101
|
+
doc_id=doc['_id'].to_s
|
|
102
|
+
delete "/databases/#{db_name}/collections/#{collection_name}/documents", {:doc_id => doc_id}
|
|
103
|
+
follow_redirect!
|
|
104
|
+
last_response.body.should contain("deleted from: #{db_name}.#{collection_name}")
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
describe "POST /databases/:db_name/collections/:collection_name/indexes" do
|
|
109
|
+
it "should create a new index" do
|
|
110
|
+
post "/databases/#{db_name}/collections/#{collection_name}/indexes",
|
|
111
|
+
{:index_fields => index.fields, :index_unique => index.unique?, :sparse => index.sparse?}
|
|
112
|
+
|
|
113
|
+
follow_redirect!
|
|
114
|
+
# "The index: '#{index_name}' was successfully created"
|
|
115
|
+
index.name = last_response.body[/index: '([^']+)/,1]
|
|
116
|
+
last_response.body.should contain("was successfully created")
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Drop a collection index
|
|
121
|
+
describe "DELETE /databases/:db_name/collections/:collection_name/indexes" do
|
|
122
|
+
it "should delete an existing index" do
|
|
123
|
+
db = MongoFe::MongoDB.use db_name
|
|
124
|
+
db.should_not be_nil
|
|
125
|
+
|
|
126
|
+
collection = db.collection(collection_name)
|
|
127
|
+
collection.name.should_not be_nil
|
|
128
|
+
|
|
129
|
+
indexes = collection.index_information
|
|
130
|
+
indexes.should contain(index.name)
|
|
131
|
+
|
|
132
|
+
delete "/databases/#{db_name}/collections/#{collection_name}/indexes", {:index_name => index.name}
|
|
133
|
+
follow_redirect!
|
|
134
|
+
last_response.body.should contain("The index: '#{index.name}', was deleted successfully.")
|
|
135
|
+
|
|
136
|
+
indexes = collection.index_information
|
|
137
|
+
indexes.should_not contain(index.name)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Delete a collection from a test database
|
|
142
|
+
describe "DELETE /databases/:db_name/collections/:collection_name" do
|
|
143
|
+
it "should delete a collection" do
|
|
144
|
+
delete "/databases/#{db_name}/collections/#{collection_name}"
|
|
145
|
+
# , {:collection_name => collection_name}
|
|
146
|
+
follow_redirect!
|
|
147
|
+
last_response.body.should contain("#{collection_name}, deleted.")
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Databases Controller" do
|
|
4
|
+
# careful not to overwrite any existing db; todo: improve the naming solution
|
|
5
|
+
let(:db_name) { "mongo_fe_test_db_01293801983479827349832987234987234987" }
|
|
6
|
+
let(:new_db_name) { "mongo_fe_test_db_012938019747473873563872ABHEYYO827PI12" }
|
|
7
|
+
|
|
8
|
+
describe "GET /databases" do
|
|
9
|
+
it "should return success" do
|
|
10
|
+
get '/databases'
|
|
11
|
+
last_response.body.should contain("Move along, nothing to see here!")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "POST /databases" do
|
|
16
|
+
context "when a new database is successfully created" do
|
|
17
|
+
before(:all) do
|
|
18
|
+
post '/databases', {:name => db_name}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "returns a 302 response code" do
|
|
22
|
+
last_response.status.should eq(302)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should create a new database" do
|
|
26
|
+
get "/databases/#{db_name}"
|
|
27
|
+
last_response.body.should contain("#{db_name}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "GET /databases/:name" do
|
|
34
|
+
it "should return info about the newly created database" do
|
|
35
|
+
get "/databases/#{db_name}"
|
|
36
|
+
last_response.body.should contain("\"db\": \"#{db_name}\",")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# test the user creation
|
|
41
|
+
describe "POST /databases/:name/users" do
|
|
42
|
+
let(:test_user) { FactoryGirl.build(:user) }
|
|
43
|
+
it "should create a new user" do
|
|
44
|
+
post "/databases/#{db_name}/users", {:username => test_user.username,
|
|
45
|
+
:password => test_user.password, :readonly => test_user.readonly}
|
|
46
|
+
follow_redirect!
|
|
47
|
+
last_response.body.should contain("User: '#{test_user.username}', was added successfully.")
|
|
48
|
+
# or better:
|
|
49
|
+
# flash[:notice].should =~ /User: '#{test_user.username}', was added successfully./
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# test the user deletion
|
|
54
|
+
describe "DELETE /databases/:name/users" do
|
|
55
|
+
let(:test_user) { FactoryGirl.build(:user) }
|
|
56
|
+
it "should delete a user" do
|
|
57
|
+
delete "/databases/#{db_name}/users", {:username => test_user.username}
|
|
58
|
+
follow_redirect!
|
|
59
|
+
last_response.body.should contain("User deleted: '#{test_user.username}'")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe "DELETE /databases/:name" do
|
|
64
|
+
it "should delete a database" do
|
|
65
|
+
delete "/databases/#{db_name}"
|
|
66
|
+
last_response.body.should contain("Database: #{db_name} was deleted.")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
FactoryGirl.define do
|
|
2
|
+
# user.rb
|
|
3
|
+
class User
|
|
4
|
+
attr_accessor :username, :email, :password, :readonly, :created_at
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
sequence :email do |n|
|
|
8
|
+
"user#{n}@example.com"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
factory :user do
|
|
12
|
+
username "alphaville"
|
|
13
|
+
email
|
|
14
|
+
password "password"
|
|
15
|
+
readonly true
|
|
16
|
+
# created_at { rand(10).days.ago }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
ENV["RACK_ENV"] ||= "test"
|
|
2
|
+
|
|
3
|
+
require 'rack/test'
|
|
4
|
+
require "hashie/mash"
|
|
5
|
+
require 'yajl'
|
|
6
|
+
require 'cgi'
|
|
7
|
+
require "yaml"
|
|
8
|
+
require "mongo"
|
|
9
|
+
require "rspec"
|
|
10
|
+
require "SimpleCov"
|
|
11
|
+
require 'factory_girl'
|
|
12
|
+
require "webrat"
|
|
13
|
+
require 'shoulda-matchers'
|
|
14
|
+
require "sinatra/base"
|
|
15
|
+
require "sinatra/contrib"
|
|
16
|
+
require 'will_paginate'
|
|
17
|
+
require 'will_paginate/array'
|
|
18
|
+
require 'will_paginate/view_helpers/sinatra'
|
|
19
|
+
require 'will_paginate/view_helpers/link_renderer'
|
|
20
|
+
|
|
21
|
+
SimpleCov.start
|
|
22
|
+
|
|
23
|
+
Dir["./lib/**/*.rb"].each { |f| require f}
|
|
24
|
+
|
|
25
|
+
#load factories
|
|
26
|
+
Dir[File.dirname(__FILE__)+"/factories/*.rb"].each { |file| require file}
|
|
27
|
+
|
|
28
|
+
Webrat.configure do |conf|
|
|
29
|
+
conf.mode = :rack
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# see: http://bit.ly/KureJx, for a similar discussion
|
|
34
|
+
# and this is my solution:
|
|
35
|
+
module RSpecMixin
|
|
36
|
+
include Rack::Test::Methods
|
|
37
|
+
include Webrat::Methods
|
|
38
|
+
include Webrat::Matchers
|
|
39
|
+
include FactoryGirl::Syntax::Methods
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
require "./lib/mongo_fe"
|
|
43
|
+
|
|
44
|
+
config = Hashie::Mash.new (YAML.load(File.new(File.expand_path('~/.mongo_fe'))))
|
|
45
|
+
MongoFe::MongoDB.uri = config.uri
|
|
46
|
+
rescue
|
|
47
|
+
puts "You must create a file in your home directory called .mongo_fe; error: #{$!.message}"
|
|
48
|
+
exit 1
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.app=(application)
|
|
52
|
+
@app = application
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.app
|
|
56
|
+
@app
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def app
|
|
60
|
+
RSpecMixin.app ||=
|
|
61
|
+
Rack::Builder.new do
|
|
62
|
+
Dir.glob('../lib/{mongo_fe,mongo_fe/helpers,mongo_fe/controllers}/*.rb').each { |file| require file }
|
|
63
|
+
use MongoFe::ApplicationController
|
|
64
|
+
use MongoFe::DatabasesController
|
|
65
|
+
use MongoFe::CollectionsController
|
|
66
|
+
|
|
67
|
+
run Sinatra::Base
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def request
|
|
72
|
+
last_request
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def session
|
|
76
|
+
last_request.env['rack.session']
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
RSpec.configure { |c| c.include RSpecMixin }
|
|
82
|
+
|
|
83
|
+
RSpec.configure do |c|
|
|
84
|
+
c.include Rack::Test::Methods
|
|
85
|
+
c.include Webrat::Methods
|
|
86
|
+
c.include Webrat::Matchers
|
|
87
|
+
c.include FactoryGirl::Syntax::Methods
|
|
88
|
+
end
|