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.
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