sinatra-admin 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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +176 -0
- data/Rakefile +2 -0
- data/dummy/config.ru +12 -0
- data/dummy/config/mongoid.yml +6 -0
- data/dummy/dummy.rb +19 -0
- data/dummy/models/admin.rb +6 -0
- data/dummy/models/comment.rb +5 -0
- data/dummy/models/user.rb +11 -0
- data/dummy/views/admin/customs/index.haml +4 -0
- data/dummy/views/admin/users/custom.haml +2 -0
- data/features/admin_login.feature +36 -0
- data/features/admin_logout.feature +14 -0
- data/features/creating_users.feature +44 -0
- data/features/custom_pages.feature +34 -0
- data/features/default_root.feature +43 -0
- data/features/editing_users.feature +46 -0
- data/features/listing_users.feature +46 -0
- data/features/main_menu_resources.feature +41 -0
- data/features/removing_users.feature +34 -0
- data/features/step_definitions/common_steps.rb +59 -0
- data/features/step_definitions/web_steps.rb +212 -0
- data/features/support/database_cleaner.rb +17 -0
- data/features/support/env.rb +18 -0
- data/features/support/paths.rb +30 -0
- data/features/support/sinatra_admin.rb +3 -0
- data/features/support/warden.rb +9 -0
- data/features/user_details.feature +31 -0
- data/lib/sinatra-admin.rb +42 -0
- data/lib/sinatra-admin/app.rb +74 -0
- data/lib/sinatra-admin/config.rb +45 -0
- data/lib/sinatra-admin/helpers/session.rb +24 -0
- data/lib/sinatra-admin/helpers/template_lookup.rb +7 -0
- data/lib/sinatra-admin/models/admin.rb +40 -0
- data/lib/sinatra-admin/register.rb +8 -0
- data/lib/sinatra-admin/register/base.rb +29 -0
- data/lib/sinatra-admin/register/custom.rb +10 -0
- data/lib/sinatra-admin/register/model.rb +75 -0
- data/lib/sinatra-admin/version.rb +3 -0
- data/lib/sinatra-admin/views/auth/login.haml +16 -0
- data/lib/sinatra-admin/views/edit.haml +21 -0
- data/lib/sinatra-admin/views/index.haml +34 -0
- data/lib/sinatra-admin/views/layout.haml +19 -0
- data/lib/sinatra-admin/views/new.haml +19 -0
- data/lib/sinatra-admin/views/show.haml +16 -0
- data/lib/sinatra-admin/warden_strategies/sinatra_admin.rb +27 -0
- data/sinatra-admin.gemspec +36 -0
- data/spec/sinatra-admin/app_spec.rb +15 -0
- data/spec/sinatra-admin/config_spec.rb +111 -0
- data/spec/sinatra-admin/models/admin_spec.rb +33 -0
- data/spec/sinatra-admin/register/base_spec.rb +13 -0
- data/spec/sinatra-admin/register/custom_spec.rb +40 -0
- data/spec/sinatra-admin/register/model_spec.rb +26 -0
- data/spec/sinatra-admin/register_spec.rb +15 -0
- data/spec/sinatra-admin/version_spec.rb +5 -0
- data/spec/sinatra-admin_spec.rb +73 -0
- data/spec/spec_helper.rb +81 -0
- metadata +343 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
.header
|
2
|
+
%h1="Login - SinatraAdmin #{SinatraAdmin::VERSION}"
|
3
|
+
|
4
|
+
.content
|
5
|
+
%div
|
6
|
+
%form{method: 'post', action: "/admin/login"}
|
7
|
+
%fieldset
|
8
|
+
%div
|
9
|
+
%label{for: "email"} Email
|
10
|
+
%input{id: "email", type: "text", value: params['data'].try(:[], 'email'), name: "data[email]"}
|
11
|
+
%div
|
12
|
+
%label{for: "password"} Password
|
13
|
+
%input{id: "password", type: "password", value: params['data'].try(:[], 'password'), name: "data[password]"}
|
14
|
+
=styled_flash
|
15
|
+
%div
|
16
|
+
%button{type: "submit", id: "login"} Login
|
@@ -0,0 +1,21 @@
|
|
1
|
+
.header
|
2
|
+
%h1="#{@model.to_s} - Edit"
|
3
|
+
|
4
|
+
.actions
|
5
|
+
%ul
|
6
|
+
%li
|
7
|
+
%a{href: "/admin/#{@route}"} Index
|
8
|
+
|
9
|
+
.content
|
10
|
+
%div
|
11
|
+
%form{method: 'post', action: "/admin/#{@route}/#{@resource.id}"}
|
12
|
+
%fieldset
|
13
|
+
%div
|
14
|
+
%input{name: "_method", type: "hidden", value: "put"}
|
15
|
+
- (@model.attribute_names - @model.protected_attributes.to_a).each do |attr|
|
16
|
+
%div
|
17
|
+
%label{for: "#{attr}"}= attr
|
18
|
+
%input{id: "#{attr}", type: "text", value: "#{@resource[attr]}", name: "data[#{attr}]"}
|
19
|
+
%span= @resource.errors[attr] if @resource.errors[attr].any?
|
20
|
+
%div
|
21
|
+
%button{type: "submit", id: "update"} Update
|
@@ -0,0 +1,34 @@
|
|
1
|
+
.header
|
2
|
+
%h1="#{@model.to_s.pluralize} - Index"
|
3
|
+
|
4
|
+
.actions
|
5
|
+
%ul
|
6
|
+
%li
|
7
|
+
%a{href: "/admin/#{@route}/new"} New
|
8
|
+
|
9
|
+
.content
|
10
|
+
%table
|
11
|
+
%thead
|
12
|
+
%tr
|
13
|
+
- @model.attribute_names.each do |attr|
|
14
|
+
%th= attr
|
15
|
+
%tbody
|
16
|
+
- if @collection.any?
|
17
|
+
- @collection.each do |record|
|
18
|
+
%tr
|
19
|
+
- @model.attribute_names.each do |attr|
|
20
|
+
- if attr.eql?('_id')
|
21
|
+
%td
|
22
|
+
%a{href: "#{@route}/#{record.send(attr)}"}
|
23
|
+
= record.send(attr)
|
24
|
+
- else
|
25
|
+
%td
|
26
|
+
= record.send(attr)
|
27
|
+
%td
|
28
|
+
%form{method: 'post', action: "/admin/#{@route}/#{record.id}"}
|
29
|
+
%input{name: "_method", type: "hidden", value: "delete"}
|
30
|
+
%button{type: "submit", id: "delete_#{record.id}"} Delete
|
31
|
+
- else
|
32
|
+
%tr
|
33
|
+
%td{colspan: "#{@model.attribute_names.size}"}
|
34
|
+
%h5 There are not records in the database
|
@@ -0,0 +1,19 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head>
|
4
|
+
%meta{charset: 'UTF=8'}
|
5
|
+
%title Sinatra Admin
|
6
|
+
|
7
|
+
%body
|
8
|
+
.top-bar{style: "height:30px;"}
|
9
|
+
.main-menu
|
10
|
+
%ul{style: "list-style-type:none;"}
|
11
|
+
- SinatraAdmin.config.routes.each do |route|
|
12
|
+
%li{style: "float:left; padding-right:15px;"}
|
13
|
+
%a{href: "#{route}"}= route.humanize
|
14
|
+
|
15
|
+
.logout{style: "float:right;"}
|
16
|
+
%a{href: "/admin/logout"} Logout
|
17
|
+
|
18
|
+
.wrapper
|
19
|
+
=yield
|
@@ -0,0 +1,19 @@
|
|
1
|
+
.header
|
2
|
+
%h1="#{@model.to_s} - New"
|
3
|
+
|
4
|
+
.actions
|
5
|
+
%ul
|
6
|
+
%li
|
7
|
+
%a{href: "/admin/#{@route}"} Index
|
8
|
+
|
9
|
+
.content
|
10
|
+
%div
|
11
|
+
%form{method: 'post', action: "/admin/#{@route}/"}
|
12
|
+
%fieldset
|
13
|
+
- (@model.attribute_names - @model.protected_attributes.to_a).each do |attr|
|
14
|
+
%div
|
15
|
+
%label{for: "#{attr}"}= attr
|
16
|
+
%input{id: "#{attr}", type: "text", value: "#{@resource[attr]}", name: "data[#{attr}]"}
|
17
|
+
%span= @resource.errors[attr] if @resource.errors[attr].any?
|
18
|
+
%div
|
19
|
+
%button{type: "submit", id: "create"} Create
|
@@ -0,0 +1,16 @@
|
|
1
|
+
.header
|
2
|
+
%h1="#{@model.to_s} - Show"
|
3
|
+
|
4
|
+
.actions
|
5
|
+
%ul
|
6
|
+
%li
|
7
|
+
%a{href: "/admin/#{@route}"} Index
|
8
|
+
%li
|
9
|
+
%a{href: "/admin/#{@route}/#{@resource.id}/edit"} Edit
|
10
|
+
|
11
|
+
.content
|
12
|
+
%div
|
13
|
+
- @model.attribute_names.each do |attr|
|
14
|
+
%div
|
15
|
+
%span= "#{attr}: "
|
16
|
+
%span= @resource.send(attr)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Warden::Strategies.add(:sinatra_admin) do
|
2
|
+
def valid?
|
3
|
+
email && password
|
4
|
+
end
|
5
|
+
|
6
|
+
def authenticate!
|
7
|
+
admin = SinatraAdmin.config.admin_model.find_by(email: email)
|
8
|
+
|
9
|
+
if admin.nil?
|
10
|
+
fail!("The email you entered does not exist.")
|
11
|
+
elsif admin.authenticate(password)
|
12
|
+
success!(admin)
|
13
|
+
else
|
14
|
+
fail!("You entered an incorrect password")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def email
|
21
|
+
params['data']['email']
|
22
|
+
end
|
23
|
+
|
24
|
+
def password
|
25
|
+
params['data']['password']
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sinatra-admin/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'sinatra-admin'
|
8
|
+
spec.version = SinatraAdmin::VERSION
|
9
|
+
spec.authors = ['Fco. Delgado', 'Carlo Cajucom', 'Vahak Matavosian']
|
10
|
+
spec.email = ['franciscodelgadodev@gmail.com']
|
11
|
+
spec.summary = "Sinatra application that allow us to have an admin dashboard with minimal effort."
|
12
|
+
spec.homepage = 'https://github.com/Herbalifedev/sinatra-admin'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
21
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
22
|
+
spec.add_development_dependency 'rspec', '~> 3.0.0'
|
23
|
+
spec.add_development_dependency 'capybara', '~> 2.4.1'
|
24
|
+
spec.add_development_dependency 'cucumber', '~> 1.3.16'
|
25
|
+
spec.add_development_dependency 'cucumber-sinatra', '~> 0.5.0'
|
26
|
+
spec.add_development_dependency 'database_cleaner'
|
27
|
+
|
28
|
+
spec.add_dependency 'mongoid', '~> 3.1.6'
|
29
|
+
spec.add_dependency 'sinatra', '~> 1.4.5'
|
30
|
+
spec.add_dependency 'sinatra-contrib', '~> 1.4.2'
|
31
|
+
spec.add_dependency 'sinatra-flash', '~> 0.3.0'
|
32
|
+
spec.add_dependency 'haml', '~> 4.0.5'
|
33
|
+
spec.add_dependency 'warden', '~> 1.2.3'
|
34
|
+
spec.add_dependency 'activesupport'
|
35
|
+
spec.add_dependency 'bcrypt'
|
36
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SinatraAdmin::App do
|
4
|
+
it 'inherits from Sinatra::Base' do
|
5
|
+
expect(described_class < Sinatra::Base).to eq(true)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'registers Sinatra::Namespace' do
|
9
|
+
expect(described_class.extensions).to include(Sinatra::Namespace)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'adds Rack::MethodOverride middleware' do
|
13
|
+
expect(described_class.middleware[0]).to include(Rack::MethodOverride)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class User; end
|
4
|
+
|
5
|
+
describe SinatraAdmin::Config do
|
6
|
+
describe ':ATTRIBUTES' do
|
7
|
+
let(:expected_attrs) { [:root, :admin_model] }
|
8
|
+
it { expect(described_class::ATTRIBUTES).to eq(expected_attrs) }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#default_route' do
|
12
|
+
context 'when root is initialized' do
|
13
|
+
before do
|
14
|
+
subject.root = 'User'
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when defined root is not registered' do
|
18
|
+
it 'raises RegistrationException' do
|
19
|
+
expect {
|
20
|
+
subject.default_route
|
21
|
+
}.to raise_error(SinatraAdmin::RegistrationException, 'The resource User was not registered')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when defined root is registered' do
|
26
|
+
before do
|
27
|
+
subject.routes << 'users'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns /admin/users' do
|
31
|
+
expect(subject.default_route).to eq('/admin/users')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when root is not initialized' do
|
37
|
+
context 'when there are not registered routes' do
|
38
|
+
it 'raises RegistrationException' do
|
39
|
+
expect {
|
40
|
+
subject.default_route
|
41
|
+
}.to raise_error(SinatraAdmin::RegistrationException, 'You should register at least one resource')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when there are registered routes' do
|
46
|
+
before do
|
47
|
+
subject.routes << 'tags' << 'users'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns first registered route' do
|
51
|
+
expect(subject.default_route).to eq('/admin/tags')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#admin_model' do
|
58
|
+
context 'when model_name was initialized with User' do
|
59
|
+
before do
|
60
|
+
subject.admin_model = User
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns User' do
|
64
|
+
expect(subject.admin_model).to eq(User)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when model_name was not initialized' do
|
69
|
+
before do
|
70
|
+
subject.admin_model = nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns SinatraAdmin::Admin' do
|
74
|
+
expect(subject.admin_model).to eq(SinatraAdmin::Admin)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#routes' do
|
80
|
+
context 'when there are not registered routes' do
|
81
|
+
it 'returns []' do
|
82
|
+
expect(subject.routes).to eq([])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when there are registered routes' do
|
87
|
+
before do
|
88
|
+
subject.routes << 'users'
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'returns array with routes' do
|
92
|
+
expect(subject.routes).to eq(['users'])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#reset!' do
|
98
|
+
it 'sets nil to ALL config attributes' do
|
99
|
+
described_class::ATTRIBUTES.each do |attr|
|
100
|
+
expect(subject).to receive("#{attr.to_s}=").with(nil)
|
101
|
+
end
|
102
|
+
subject.reset!
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'clears routes array' do
|
106
|
+
subject.routes << 'users'
|
107
|
+
subject.reset!
|
108
|
+
expect(subject.routes).to eq([])
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SinatraAdmin::Admin do
|
4
|
+
subject do
|
5
|
+
SinatraAdmin::Admin.new(email: "admin@mail.com", password: "admin")
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'includes Mongoid::Document' do
|
9
|
+
expect(described_class < Mongoid::Document).to eq(true)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'hashes password' do
|
13
|
+
expect(subject.password).not_to eql('admin')
|
14
|
+
expect(subject.password == 'admin').to eq(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'validations' do
|
18
|
+
[:email, :password_hash].each do |required_attr|
|
19
|
+
it "#{required_attr} is required" do
|
20
|
+
subject.send("#{required_attr}=", nil)
|
21
|
+
subject.valid?
|
22
|
+
expect(subject.errors[required_attr]).to include("can't be blank")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'email should be valid format' do
|
27
|
+
subject.email = 'invalid'
|
28
|
+
subject.valid?
|
29
|
+
expect(subject.errors[:email]).to include("is not an email")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SinatraAdmin::Register::Base do
|
4
|
+
before { SinatraAdmin.config.reset! }
|
5
|
+
|
6
|
+
describe '.add' do
|
7
|
+
it 'raises exception(this is an abstract class)' do
|
8
|
+
expect{
|
9
|
+
described_class.add 'Tag'
|
10
|
+
}.to raise_error(NotImplementedError, "You must implement me!")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SinatraAdmin::Register::Custom do
|
4
|
+
before { SinatraAdmin.config.reset! }
|
5
|
+
|
6
|
+
describe '.add' do
|
7
|
+
context 'when block is given' do
|
8
|
+
context 'when resource has been registered already' do
|
9
|
+
before do
|
10
|
+
described_class.add 'Custom Page' do
|
11
|
+
get '/' do
|
12
|
+
puts "In tag custom page"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'raises RegistrationException' do
|
18
|
+
expect{
|
19
|
+
SinatraAdmin.register 'Custom Page' do
|
20
|
+
get '/' do
|
21
|
+
puts "In tag custom page"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
}.to raise_error(SinatraAdmin::RegistrationException, "The resource Custom Page is already registered")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when resource has not been registered yet' do
|
29
|
+
it 'adds route to config' do
|
30
|
+
described_class.add 'Custom Page' do
|
31
|
+
get '/' do
|
32
|
+
puts "In tag custom page"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
expect(SinatraAdmin.config.routes).to include('custom_pages')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Tag; end
|
4
|
+
|
5
|
+
describe SinatraAdmin::Register::Model do
|
6
|
+
before { SinatraAdmin.config.reset! }
|
7
|
+
|
8
|
+
describe '.add' do
|
9
|
+
context 'when resource has been registered already' do
|
10
|
+
before { described_class.add 'Tag' }
|
11
|
+
|
12
|
+
it 'raises RegistrationException' do
|
13
|
+
expect{
|
14
|
+
SinatraAdmin.register 'Tag'
|
15
|
+
}.to raise_error(SinatraAdmin::RegistrationException, "The resource Tag is already registered")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when resource has not been registered yet' do
|
20
|
+
it 'adds route to config' do
|
21
|
+
described_class.add 'Tag'
|
22
|
+
expect(SinatraAdmin.config.routes).to include('tags')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|