sinatra-admin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +176 -0
  6. data/Rakefile +2 -0
  7. data/dummy/config.ru +12 -0
  8. data/dummy/config/mongoid.yml +6 -0
  9. data/dummy/dummy.rb +19 -0
  10. data/dummy/models/admin.rb +6 -0
  11. data/dummy/models/comment.rb +5 -0
  12. data/dummy/models/user.rb +11 -0
  13. data/dummy/views/admin/customs/index.haml +4 -0
  14. data/dummy/views/admin/users/custom.haml +2 -0
  15. data/features/admin_login.feature +36 -0
  16. data/features/admin_logout.feature +14 -0
  17. data/features/creating_users.feature +44 -0
  18. data/features/custom_pages.feature +34 -0
  19. data/features/default_root.feature +43 -0
  20. data/features/editing_users.feature +46 -0
  21. data/features/listing_users.feature +46 -0
  22. data/features/main_menu_resources.feature +41 -0
  23. data/features/removing_users.feature +34 -0
  24. data/features/step_definitions/common_steps.rb +59 -0
  25. data/features/step_definitions/web_steps.rb +212 -0
  26. data/features/support/database_cleaner.rb +17 -0
  27. data/features/support/env.rb +18 -0
  28. data/features/support/paths.rb +30 -0
  29. data/features/support/sinatra_admin.rb +3 -0
  30. data/features/support/warden.rb +9 -0
  31. data/features/user_details.feature +31 -0
  32. data/lib/sinatra-admin.rb +42 -0
  33. data/lib/sinatra-admin/app.rb +74 -0
  34. data/lib/sinatra-admin/config.rb +45 -0
  35. data/lib/sinatra-admin/helpers/session.rb +24 -0
  36. data/lib/sinatra-admin/helpers/template_lookup.rb +7 -0
  37. data/lib/sinatra-admin/models/admin.rb +40 -0
  38. data/lib/sinatra-admin/register.rb +8 -0
  39. data/lib/sinatra-admin/register/base.rb +29 -0
  40. data/lib/sinatra-admin/register/custom.rb +10 -0
  41. data/lib/sinatra-admin/register/model.rb +75 -0
  42. data/lib/sinatra-admin/version.rb +3 -0
  43. data/lib/sinatra-admin/views/auth/login.haml +16 -0
  44. data/lib/sinatra-admin/views/edit.haml +21 -0
  45. data/lib/sinatra-admin/views/index.haml +34 -0
  46. data/lib/sinatra-admin/views/layout.haml +19 -0
  47. data/lib/sinatra-admin/views/new.haml +19 -0
  48. data/lib/sinatra-admin/views/show.haml +16 -0
  49. data/lib/sinatra-admin/warden_strategies/sinatra_admin.rb +27 -0
  50. data/sinatra-admin.gemspec +36 -0
  51. data/spec/sinatra-admin/app_spec.rb +15 -0
  52. data/spec/sinatra-admin/config_spec.rb +111 -0
  53. data/spec/sinatra-admin/models/admin_spec.rb +33 -0
  54. data/spec/sinatra-admin/register/base_spec.rb +13 -0
  55. data/spec/sinatra-admin/register/custom_spec.rb +40 -0
  56. data/spec/sinatra-admin/register/model_spec.rb +26 -0
  57. data/spec/sinatra-admin/register_spec.rb +15 -0
  58. data/spec/sinatra-admin/version_spec.rb +5 -0
  59. data/spec/sinatra-admin_spec.rb +73 -0
  60. data/spec/spec_helper.rb +81 -0
  61. metadata +343 -0
@@ -0,0 +1,3 @@
1
+ module SinatraAdmin
2
+ VERSION = "0.1.0"
3
+ end
@@ -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