ditty 0.4.0 → 0.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2fea055fdddd9b21951527617015b2926b064191dfda753fd930037738122c50
4
- data.tar.gz: b8d1cc9f9430ff39d3f345719a0988f51bc03f4a7f718fabe78a69d314e5762a
3
+ metadata.gz: a6c4bdcc080384afbc372c0811697ff421ab6ed3d552ec912cd0a3c0f7ed82da
4
+ data.tar.gz: 1f09c726e251d380cd0b55d8c552b064dae7c6811f3a24b0e16a38e55a0c6408
5
5
  SHA512:
6
- metadata.gz: eafbcf7aaadabc7e9458f403cf2252b3311dc9a716f08884c1651055426864e796866e60f7c3986be4405cc83d3d0552d49fca43e2764e516066884a56e7c4ea
7
- data.tar.gz: f2f3b62750d7711bdd59ee7e0df4630ec89992cda013d5e5e96736aa541a5a2cd55ff096de65b774bef4ab74c90e0983a7a3826d30a498e3a3a474bd1cdfc1cf
6
+ metadata.gz: d0f86ea3db1913ad4c603a6ba96c535705589fd7fbd28ea3fbe3a262d956838fdc2c27e1950e6aae2f6e1bce20e3ffd0dc32e0bde74ae371869c3ac1922a5b03
7
+ data.tar.gz: ad5ea5fe818c8f8d20177082f11ecfeb176b4969b21cb5155410a4f8dbbc581dde05d3cb4c468898a86dd16a8aede7f487f3fd36b60e187df094280f805e1c8e
data/.travis.yml CHANGED
@@ -1,13 +1,15 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.4.0
5
- - 2.3.3
6
- - 2.2.6
4
+ - 2.5.1
5
+ - 2.4.0
6
+ - 2.3.3
7
+ - 2.2.6
7
8
  gemfile: Gemfile.ci
8
9
  env:
9
10
  global:
10
11
  - CC_TEST_REPORTER_ID=289860573c6284a8e277de86848caba84d840be49e35f3601bcd672ab40d1e35
12
+ - DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL=true
11
13
  matrix:
12
14
  - DATABASE_URL="sqlite::memory:" RACK_ENV=test
13
15
  before_install:
data/ditty.gemspec CHANGED
@@ -32,13 +32,14 @@ Gem::Specification.new do |spec|
32
32
  spec.add_dependency 'bcrypt', '~> 3.1'
33
33
  spec.add_dependency 'haml', '~> 5.0'
34
34
  spec.add_dependency 'logger', '~> 1.0'
35
+ spec.add_dependency 'oga', '>= 2.14'
35
36
  spec.add_dependency 'omniauth', '~> 1.0'
36
37
  spec.add_dependency 'omniauth-identity', '~> 1.0'
37
38
  spec.add_dependency 'pundit', '~> 1.0'
38
39
  spec.add_dependency 'rack-contrib', '~> 1.0'
39
40
  spec.add_dependency 'rake', '~> 12.0'
40
- spec.add_dependency 'sequel', '~> 4.0'
41
- spec.add_dependency 'sinatra', '~> 2.0'
41
+ spec.add_dependency 'sequel', '>= 4.0'
42
+ spec.add_dependency 'sinatra', '>= 2.0'
42
43
  spec.add_dependency 'sinatra-contrib', '~> 2.0'
43
44
  spec.add_dependency 'sinatra-flash', '~> 0.3'
44
45
  spec.add_dependency 'tilt', '>= 2'
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'wisper'
4
+ require 'oga'
4
5
  require 'sinatra/base'
5
6
  require 'sinatra/flash'
6
7
  require 'sinatra/respond_with'
@@ -30,10 +31,16 @@ module Ditty
30
31
  use Rack::PostBodyContentTypeParser
31
32
  use Rack::MethodOverride
32
33
 
33
- def view_location
34
- return settings.view_location if settings.view_location
35
- return underscore(pluralize(demodulize(settings.model_class))) if settings.model_class
36
- underscore(demodulize(self.class))
34
+ helpers do
35
+ def base_path
36
+ settings.base_path || "#{settings.map_path}/#{dasherize(view_location)}"
37
+ end
38
+
39
+ def view_location
40
+ return settings.view_location if settings.view_location
41
+ return underscore(pluralize(demodulize(settings.model_class))) if settings.model_class
42
+ underscore(demodulize(self.class))
43
+ end
37
44
  end
38
45
 
39
46
  configure :production do
@@ -54,7 +61,7 @@ module Ditty
54
61
  respond_to do |format|
55
62
  status 404
56
63
  format.html do
57
- haml :'404', locals: { title: '4 oh 4' }
64
+ haml :'404', locals: { title: '4 oh 4' }, layout: layout
58
65
  end
59
66
  format.json do
60
67
  json code: 404, errors: ['Not Found']
@@ -67,7 +74,7 @@ module Ditty
67
74
  status 401
68
75
  format.html do
69
76
  flash[:warning] = 'Please log in first.'
70
- redirect "#{settings.map_path}/auth/identity"
77
+ redirect with_layout("#{settings.map_path}/auth/identity")
71
78
  end
72
79
  format.json do
73
80
  json code: 401, errors: ['Not Authenticated']
@@ -82,10 +89,10 @@ module Ditty
82
89
  status 400
83
90
  format.html do
84
91
  action = entity.id ? :edit : :new
85
- haml :"#{view_location}/#{action}", locals: { entity: entity, title: heading(action) }
92
+ haml :"#{view_location}/#{action}", locals: { entity: entity, title: heading(action) }, layout: layout
86
93
  end
87
94
  format.json do
88
- json code: 400, errors: errors
95
+ json code: 400, errors: errors, full_errors: errors.full_messages
89
96
  end
90
97
  end
91
98
  end
@@ -97,7 +104,7 @@ module Ditty
97
104
  respond_to do |format|
98
105
  status 400
99
106
  format.html do
100
- haml :error, locals: { title: 'Something went wrong', error: error }
107
+ haml :error, locals: { title: 'Something went wrong', error: error }, layout: layout
101
108
  end
102
109
  format.json do
103
110
  json code: 400, errors: ['Invalid Relation Specified']
@@ -112,7 +119,7 @@ module Ditty
112
119
  respond_to do |format|
113
120
  status 500
114
121
  format.html do
115
- haml :error, locals: { title: 'Something went wrong', error: error }
122
+ haml :error, locals: { title: 'Something went wrong', error: error }, layout: layout
116
123
  end
117
124
  format.json do
118
125
  json code: 500, errors: ['Something went wrong']
@@ -124,9 +131,23 @@ module Ditty
124
131
  ::Ditty::Services::Logger.instance.debug "Running with #{self.class}"
125
132
  if request.path =~ /.*\.json\Z/
126
133
  content_type :json
134
+ request.path_info = request.path_info.gsub(/.json$/,'')
127
135
  end
128
136
  # Ensure the accept header is set. People forget to include it in API requests
129
137
  content_type(:json) if request.accept.count.eql?(1) && request.accept.first.to_s.eql?('*/*')
130
138
  end
139
+
140
+ after do
141
+ return if params['layout'].nil?
142
+ response.body = response.body.map do |resp|
143
+ document = Oga.parse_html(resp)
144
+ document.css('a').each do |elm|
145
+ unless (href = elm.get('href')).nil?
146
+ elm.set 'href', with_layout(href)
147
+ end
148
+ end
149
+ document.to_xml
150
+ end
151
+ end
131
152
  end
132
153
  end
@@ -33,7 +33,10 @@ module Ditty
33
33
  authorize settings.model_class, :create
34
34
 
35
35
  entity = settings.model_class.new(permitted_attributes(settings.model_class, :create))
36
- haml :"#{view_location}/new", locals: { entity: entity, title: heading(:new) }
36
+ session[:redirect_to] = request.fullpath
37
+ haml :"#{view_location}/new",
38
+ locals: { entity: entity, title: heading(:new) },
39
+ layout: layout
37
40
  end
38
41
 
39
42
  # Create
@@ -63,7 +66,9 @@ module Ditty
63
66
  halt 404 unless entity
64
67
  authorize entity, :update
65
68
 
66
- haml :"#{view_location}/edit", locals: { entity: entity, title: heading(:edit) }
69
+ haml :"#{view_location}/edit",
70
+ locals: { entity: entity, title: heading(:edit) },
71
+ layout: layout
67
72
  end
68
73
 
69
74
  # Update
@@ -40,7 +40,7 @@ module Ditty
40
40
  self.current_user = user
41
41
  log_action(:identity_login, user: user)
42
42
  flash[:success] = 'Logged In'
43
- redirect "#{settings.map_path}/"
43
+ redirect env['omniauth.origin'] || "#{settings.map_path}/"
44
44
  else
45
45
  # Failed Login
46
46
  broadcast(:identity_failed_login)
@@ -8,6 +8,8 @@ require 'ditty/policies/identity_policy'
8
8
 
9
9
  module Ditty
10
10
  class Users < Ditty::Component
11
+ SEARCHABLE = %i[name surname email].freeze
12
+
11
13
  set model_class: User
12
14
  set track_actions: true
13
15
 
@@ -20,11 +22,7 @@ module Ditty
20
22
  get '/new' do
21
23
  authorize settings.model_class, :create
22
24
 
23
- locals = {
24
- title: heading(:new),
25
- entity: User.new,
26
- identity: Identity.new
27
- }
25
+ locals = { title: heading(:new), entity: User.new, identity: Identity.new }
28
26
  haml :"#{view_location}/new", locals: locals
29
27
  end
30
28
 
@@ -43,9 +41,17 @@ module Ditty
43
41
  identity = locals[:identity] = Identity.new(identity_params)
44
42
 
45
43
  DB.transaction(isolation: :serializable) do
46
- identity.save # Will trigger a Sequel::ValidationFailed exception if the model is incorrect
44
+ begin
45
+ identity.save
46
+ rescue Sequel::ValidationFailed
47
+ raise unless request.accept? 'text/html'
48
+ status 400
49
+ locals = { title: heading(:new), entity: user, identity: identity }
50
+ return haml(:"#{view_location}/new", locals: locals)
51
+ end
47
52
  user.save
48
53
  user.add_identity identity
54
+
49
55
  if roles
50
56
  roles.each do |role_id|
51
57
  user.add_role(role_id) unless user.roles.map(&:id).include? role_id.to_i
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'ditty/models/user'
3
4
  require 'ditty/models/role'
4
5
  require 'ditty/models/identity'
@@ -7,10 +8,8 @@ module Ditty
7
8
  module Helpers
8
9
  module Authentication
9
10
  def current_user
10
- user_id = current_user_id
11
- self.current_user = anonymous_user if user_id.nil?
12
- @users ||= Hash.new { |h, k| h[k] = User[k] }
13
- @users[user_id]
11
+ return anonymous_user if current_user_id.nil?
12
+ User[current_user_id]
14
13
  end
15
14
 
16
15
  def current_user=(user)
@@ -37,25 +36,13 @@ module Ditty
37
36
  end
38
37
 
39
38
  def logout
40
- env['rack.session'].delete('user_id')
41
- end
42
-
43
- def check_basic(request)
44
- auth = Rack::Auth::Basic::Request.new(request.env)
45
- return false unless auth.provided? && auth.basic?
46
-
47
- identity = ::Ditty::Identity.find(username: auth.credentials[0])
48
- identity ||= ::Ditty::Identity.find(username: CGI.unescape(auth.credentials[0]))
49
- return false unless identity
50
- self.current_user = identity.user if identity.authenticate(auth.credentials[1])
39
+ env['rack.session'].delete('user_id') unless env['rack.session'].nil?
40
+ env.delete('omniauth.auth')
51
41
  end
52
42
 
53
43
  def anonymous_user
54
- return @anonymous_user if defined? @anonymous_user
55
- @anonymous_user ||= begin
56
- role = ::Ditty::Role.where(name: 'anonymous').first
57
- ::Ditty::User.where(roles: role).first unless role.nil?
58
- end
44
+ role = ::Ditty::Role.where(name: 'anonymous').first
45
+ ::Ditty::User.where(roles: role).first unless role.nil?
59
46
  end
60
47
  end
61
48
 
@@ -36,10 +36,6 @@ module Ditty
36
36
  settings.dehumanized || underscore(heading)
37
37
  end
38
38
 
39
- def base_path
40
- settings.base_path || "#{settings.map_path}/#{dasherize(view_location)}"
41
- end
42
-
43
39
  def filters
44
40
  self.class.const_defined?('FILTERS') ? self.class::FILTERS : []
45
41
  end
@@ -21,8 +21,9 @@ module Ditty
21
21
  'permitted_attributes'
22
22
  end
23
23
 
24
+ policy_fields = policy.public_send(method_name)
24
25
  request.params.fetch(param_key, {}).select do |key, _value|
25
- policy.public_send(method_name).include? key.to_sym
26
+ policy_fields.include? key.to_sym
26
27
  end
27
28
  end
28
29
 
@@ -9,15 +9,17 @@ module Ditty
9
9
  actions = {}
10
10
  actions["#{base_path}/new"] = "New #{heading}" if policy(settings.model_class).create?
11
11
  haml :"#{view_location}/index",
12
- locals: { list: result, title: heading(:list), actions: actions }
12
+ locals: { list: result, title: heading(:list), actions: actions },
13
+ layout: layout
13
14
  end
14
15
  format.json do
15
16
  # TODO: Add links defined by actions (New #{heading})
17
+ total = result.respond_to?(:pagination_record_count) ? result.pagination_record_count : result.count
16
18
  json(
17
19
  'items' => result.all.map(&:for_json),
18
20
  'page' => (params['page'] || 1).to_i,
19
21
  'count' => result.count,
20
- 'total' => result.pagination_record_count
22
+ 'total' => total
21
23
  )
22
24
  end
23
25
  end
@@ -27,7 +29,7 @@ module Ditty
27
29
  respond_to do |format|
28
30
  format.html do
29
31
  flash[:success] = "#{heading} Created"
30
- redirect "#{base_path}/#{entity.id}"
32
+ redirect with_layout("#{base_path}/#{entity.id}")
31
33
  end
32
34
  format.json do
33
35
  content_type :json
@@ -42,7 +44,9 @@ module Ditty
42
44
  actions = {}
43
45
  actions["#{base_path}/#{entity.id}/edit"] = "Edit #{heading}" if policy(entity).update?
44
46
  title = heading(:read) + (entity.respond_to?(:name) ? ": #{entity.name}" : '')
45
- haml :"#{view_location}/display", locals: { entity: entity, title: title, actions: actions }
47
+ haml :"#{view_location}/display",
48
+ locals: { entity: entity, title: title, actions: actions },
49
+ layout: layout
46
50
  end
47
51
  format.json do
48
52
  # TODO: Add links defined by actions (Edit #{heading})
@@ -56,7 +60,7 @@ module Ditty
56
60
  format.html do
57
61
  # TODO: Ability to customize the return path and message?
58
62
  flash[:success] = "#{heading} Updated"
59
- redirect "#{base_path}/#{entity.id}"
63
+ redirect with_layout("#{base_path}/#{entity.id}")
60
64
  end
61
65
  format.json do
62
66
  headers 'Location' => "#{base_path}/#{entity.id}"
@@ -69,11 +73,11 @@ module Ditty
69
73
  respond_to do |format|
70
74
  format.html do
71
75
  flash[:success] = "#{heading} Deleted"
72
- redirect base_path.to_s
76
+ redirect with_layout(base_path.to_s)
73
77
  end
74
78
  format.json do
75
79
  content_type :json
76
- headers 'Location' => "#{base_path}"
80
+ headers 'Location' => base_path.to_s
77
81
  status 204
78
82
  end
79
83
  end
@@ -3,6 +3,20 @@
3
3
  module Ditty
4
4
  module Helpers
5
5
  module Views
6
+ def layout
7
+ return :embedded if request.params['layout'] == 'embedded'
8
+ :layout
9
+ end
10
+
11
+ def with_layout(url)
12
+ uri = URI.parse(url)
13
+ # Don't set the layout if there's none. Don't set the layout for external URIs
14
+ return url if params['layout'].nil? || uri.host
15
+ qs = { 'layout' => params['layout'] }.merge(uri.query ? CGI.parse(uri.query) : {})
16
+ uri.query = Rack::Utils.build_query qs
17
+ uri.to_s
18
+ end
19
+
6
20
  def form_control(name, model, opts = {})
7
21
  label = opts.delete(:label) || name.to_s.titlecase
8
22
  klass = opts.delete(:class) || 'form-control' unless opts[:type] == 'file'
@@ -41,15 +55,38 @@ module Ditty
41
55
  "<div id='#{id}'>\n" + messages.join + '</div>'
42
56
  end
43
57
 
58
+ def query_string(add = {})
59
+ qs = params.clone.merge(add)
60
+ qs.delete('captures')
61
+ Rack::Utils.build_query qs
62
+ end
63
+
44
64
  def delete_form(entity, label = 'Delete')
45
65
  locals = { delete_label: label, entity: entity }
46
66
  haml :'partials/delete_form', locals: locals
47
67
  end
48
68
 
49
- def query_string(add = {})
50
- qs = params.clone.merge(add)
51
- qs.delete('captures')
52
- Rack::Utils.build_query qs
69
+ def delete_form_tag(url, options = {}, &block)
70
+ options[:form_verb] = :delete
71
+ form_tag(url, options, &block)
72
+ end
73
+
74
+ def edit_form_tag(url, options = {}, &block)
75
+ options[:form_verb] = :put
76
+ form_tag(url, options, &block)
77
+ end
78
+
79
+ def new_form_tag(url, options = {}, &block)
80
+ options[:form_verb] = :post
81
+ form_tag(url, options, &block)
82
+ end
83
+
84
+ def form_tag(url, options = {}, &block)
85
+ options[:form_verb] ||= :post
86
+ options[:attributes] ||= {}
87
+ options[:attributes] = { 'class': 'form-horizontal' }.merge options[:attributes]
88
+ options[:url] = options[:form_verb].to_sym == :get ? url : with_layout(url)
89
+ haml :'partials/form_tag', locals: options.merge(block: block)
53
90
  end
54
91
 
55
92
  def pagination(list, base_path, qp = {})
@@ -6,7 +6,7 @@ module Ditty
6
6
  module Helpers
7
7
  module Wisper
8
8
  def log_action(action, args = {})
9
- args[:user] ||= current_user
9
+ args[:user] = current_user unless args.key? :user
10
10
  broadcast(action, args)
11
11
  end
12
12
  end
@@ -21,6 +21,7 @@ module Ditty
21
21
  end
22
22
 
23
23
  def authenticate(unencrypted)
24
+ return false if crypted_password.blank?
24
25
  self if ::BCrypt::Password.new(crypted_password) == unencrypted
25
26
  end
26
27
 
@@ -17,7 +17,7 @@ module Ditty
17
17
  @loggers = []
18
18
  config.each do |values|
19
19
  klass = values['class'].constantize
20
- opts = values['options'] || nil
20
+ opts = tr(values['options']) || nil
21
21
  logger = klass.new(opts)
22
22
  if values['level']
23
23
  logger.level = klass.const_get(values['level'].to_sym)
@@ -40,6 +40,13 @@ module Ditty
40
40
  @config ||= File.exist?(CONFIG) ? YAML.load_file(CONFIG) : default
41
41
  end
42
42
 
43
+ def tr(val)
44
+ {
45
+ '$stdout' => $stdout,
46
+ '$stderr' => $stderr
47
+ }[val] || val
48
+ end
49
+
43
50
  def default
44
51
  [{ 'name' => 'default', 'class' => 'Logger' }]
45
52
  end
data/lib/ditty/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ditty
4
- VERSION = '0.4.0'.freeze
4
+ VERSION = '0.4.1'.freeze
5
5
  end
@@ -0,0 +1,42 @@
1
+ !!! 5
2
+ %html{ lang: 'en' }
3
+ %head
4
+ %meta{ charset: 'utf-8' }
5
+ %meta{ 'http-equiv' => 'X-UA-Compatible', 'content' => 'IE=edge,chrome=1' }
6
+ %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
7
+ %meta{ name: 'theme-color', content: '#ffffff' }
8
+ %link{ rel: 'manifest', href: '/manifest.json' }
9
+ %link{ rel: 'icon', type: 'image/png', sizes: '32x32', href: '#{request.base_url}/images/favicon-32x32.png' }
10
+ %link{ rel: 'icon', type: 'image/png', sizes: '16x16', href: '#{request.base_url}/images/favicon-16x16.png' }
11
+ %link{ rel: 'apple-touch-icon', sizes: '76x76', href: '/images/apple-icon.png' }
12
+ %link{ rel: 'mask-icon', href: '/safari-pinned-tab.svg', color: '#5bbad5' }
13
+
14
+ %title
15
+ Ditty
16
+ - if defined? title
17
+ = "- #{title}"
18
+
19
+ %meta{ name: 'description', content: '' }
20
+ %meta{ name: 'author', content: '' }
21
+
22
+ / Le styles
23
+ %link{ rel: 'stylesheet', href: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css', media: 'screen' }
24
+ %link{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/startbootstrap-sb-admin-2/3.3.7+1/css/sb-admin-2.min.css', media: 'screen' }
25
+ %link{ rel: 'stylesheet', href: 'https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css', media: 'screen' }
26
+ /[if lt IE 9] <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
27
+ /[if lt IE 9] <script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
28
+
29
+ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js' }
30
+ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/startbootstrap-sb-admin-2/3.3.7+1/js/sb-admin-2.min.js' }
31
+ %body
32
+ .container-fluid
33
+ .row
34
+ .col-md-12
35
+ = haml :'partials/notifications'
36
+
37
+ = yield
38
+
39
+ / Placed at the end of the document so the pages load faster
40
+ %script{ type: 'text/javascript', src: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js' }
41
+ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.min.js' }
42
+ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.bundle.min.js' }
@@ -2,12 +2,10 @@
2
2
  .col-sm-3
3
3
  .col-sm-6
4
4
  .panel.panel-default
5
- .panel-heading
6
- %h4 Login
7
5
  .panel-body
8
6
  %form{ method: 'post', action: "#{settings.map_path}/auth/identity/callback" }
9
7
  .form-group
10
- %label.control-label Username
8
+ %label.control-label Email
11
9
  %input.form-control.border-input{ name: 'username' }
12
10
  .form-group
13
11
  %label.control-label Password
@@ -2,13 +2,20 @@
2
2
  .col-md-2
3
3
  .col-md-8
4
4
  .panel.panel-default
5
- .panel-heading
6
- %h4 Register
7
5
  .panel-body
8
6
  %form.form-horizontal{ method: 'post', action: "#{settings.map_path}/auth/identity/new" }
9
- = form_control(:username, identity, label: 'Username', placeholder: 'Your username')
7
+ = form_control(:username, identity, label: 'Email', placeholder: 'your@email.com')
10
8
  = form_control(:password, identity, label: 'Password', type: :password)
11
9
  = form_control(:password_confirmation, identity, label: 'Confirm Password', type: :password)
12
10
 
13
- %button.btn.btn-primary{ type: 'submit' } Register
11
+ - if identity.errors[:password] && identity.errors[:password].include?('is not strong enough')
12
+ .alert.alert-warning
13
+ %p Make sure your password is at least 8 characters long, and including the following
14
+ %ul
15
+ %li Upper- and lowercase letters
16
+ %li Numbers
17
+ %li Special Characters
18
+
19
+ - if policy(::Ditty::Identity).register?
20
+ %button.btn.btn-primary{ type: 'submit' } Register
14
21
  .col-md-2
data/views/layout.haml CHANGED
@@ -34,10 +34,16 @@
34
34
  #wrapper
35
35
  = haml :'partials/navbar', locals: { title: (defined?(title) ? title : 'Ditty') }
36
36
  #page-wrapper
37
+ -if defined?(title) || defined?(actions)
38
+ .row
39
+ %h1.col-md-9= defined?(title) ? title : '&nbsp'
40
+ .col-md-3.text-left{ style: 'margin-top: 20px' }
41
+ = haml :'partials/actions', locals: { actions: defined?(actions) ? actions : {} }
42
+ -else
43
+ %div{ style: 'padding-top: 20px' }
44
+
37
45
  .row
38
46
  .col-md-12
39
- -if defined? title
40
- %h1.page-header= title
41
47
  = haml :'partials/notifications'
42
48
 
43
49
  = yield
@@ -0,0 +1,12 @@
1
+ - if actions.count > 1
2
+ .dropdown
3
+ %button.btn.btn-default.btn-block.dropdown-toggle{ type: 'button', id: 'actions-toggle', data: { toggle: 'dropdown' } }
4
+ Actions
5
+ %span.caret
6
+ %ul.dropdown-menu{ 'aria-labelledby': 'actions-toggle' }
7
+ -actions.each do |k, v|
8
+ %li
9
+ %a{ href: k }= v
10
+ - elsif actions.count > 0
11
+ -actions.each do |k, v|
12
+ %a.btn.btn-primary.btn-block{ href: k }= v
@@ -1,4 +1,2 @@
1
- <form method="post" action="<%= base_path %>/<%= entity.id %>">
2
- <input type="hidden" name="_method" value="DELETE">
3
- <button type="submit" class="btn btn-danger"><%= delete_label %></button>
4
- </form>
1
+ = delete_form_tag "#{base_path}/#{entity.id}" do
2
+ %button.btn.btn-danger{ type: 'submit' }= delete_label
@@ -2,4 +2,4 @@
2
2
  %hr
3
3
  .copyright
4
4
  :plain
5
- &copy; <script>document.write(new Date().getFullYear())</script>, Automation Exchange
5
+ &copy; <script>document.write(new Date().getFullYear())</script>, Ditty
@@ -0,0 +1,6 @@
1
+ %form{ { method: %i[get post].include?(form_verb.to_sym) ? form_verb : :post, action: url }.merge(attributes) }
2
+ - if form_verb.to_sym == :get && layout
3
+ %input{ name: 'layout', value: layout, type: 'hidden' }
4
+ - if %i[get post].include?(form_verb.to_sym) == false
5
+ %input{ name: '_method', value: form_verb.upcase, type: 'hidden' }
6
+ = capture_haml(&block).chomp
@@ -1,5 +1,5 @@
1
1
  - if self.class.const_defined?(:SEARCHABLE) || self.class.const_defined?(:FILTERS)
2
- %form{ method: 'get', action: base_path }
2
+ = form_tag(base_path, form_verb: :get, attributes: { class: '' }) do
3
3
  - if self.class.const_defined?(:SEARCHABLE)
4
4
  .form-group
5
5
  .input-group
@@ -3,8 +3,7 @@
3
3
  .col-md-8
4
4
  .panel.panel-default
5
5
  .panel-body
6
- %form.form-horizontal{ method: 'post', action: "#{base_path}/#{entity.id}" }
7
- %input{ name: '_method', value: 'PUT', type: 'hidden' }
6
+ = edit_form_tag "#{base_path}/#{entity.id}" do
8
7
  = haml :'roles/form', locals: { entity: entity }
9
8
  %button.btn.btn-primary{ type: 'submit' }
10
9
  Update Role
data/views/roles/new.haml CHANGED
@@ -3,7 +3,7 @@
3
3
  .col-md-8
4
4
  .panel.panel-default
5
5
  .panel-body
6
- %form.form-horizontal{ method: 'post', action: base_path }
6
+ = new_form_tag base_path do
7
7
  = haml :'roles/form', locals: { entity: entity }
8
8
  %button.btn.btn-primary{ type: 'submit' }
9
9
  Create Role
@@ -3,8 +3,7 @@
3
3
  .col-md-8
4
4
  .panel.panel-default
5
5
  .panel-body
6
- %form.form-horizontal{ method: 'post', action: "#{base_path}/#{entity.id}" }
7
- %input{ name: '_method', value: 'PUT', type: 'hidden' }
6
+ = edit_form_tag "#{base_path}/#{entity.id}" do
8
7
  = haml :'users/user', locals: { user: entity }
9
8
  %button.btn.btn-primary{ type: 'submit' }
10
9
  Update User
@@ -1,3 +1,10 @@
1
1
  = form_control(:username, identity, label: 'Email', placeholder: 'Your email address')
2
+ - if identity.errors[:password] && identity.errors[:password].include?('is not strong enough')
3
+ .alert.alert-warning
4
+ %p Make sure your password is at least 8 characters long, and including the following
5
+ %ul
6
+ %li Upper- and lowercase letters
7
+ %li Numbers
8
+ %li Special Characters
2
9
  = form_control(:password, identity, type: 'password', placeholder: 'Your password')
3
10
  = form_control(:password_confirmation, identity, type: 'password', label: 'Confirm Password', placeholder: 'Confirm your password')
@@ -1,6 +1,8 @@
1
1
  .row
2
2
  .col-md-12
3
3
  .panel.panel-default
4
+ .panel-body
5
+ = haml :'partials/search'
4
6
  %table.table.table-striped
5
7
  %thead
6
8
  %tr
data/views/users/new.haml CHANGED
@@ -3,8 +3,8 @@
3
3
  .col-md-8
4
4
  .panel.panel-default
5
5
  .panel-body
6
- %form.form-horizontal{ method: 'post', action: base_path }
7
- = haml :'users/identity', locals: { identity: Ditty::Identity.new }
6
+ = new_form_tag base_path do
7
+ = haml :'users/identity', locals: { identity: identity }
8
8
  = haml :'users/user', locals: { user: entity }
9
9
  %button.btn.btn-primary{ type: 'submit' }
10
10
  Create User
@@ -1,4 +1,4 @@
1
1
  = form_control(:name, user)
2
2
  = form_control(:surname, user)
3
3
  - if policy(user).permitted_attributes.include? :role_id
4
- = form_control(:role_id, user, type: 'select', options: Ditty::Role.as_hash(:id, :name), name: 'user[role_id][]', field: :roles, multiple: true)
4
+ = form_control(:role_id, user, type: 'select', options: Ditty::Role.order(:name).as_hash(:id, :name), name: 'user[role_id][]', field: :roles, multiple: true)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ditty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jurgens du Toit
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-03 00:00:00.000000000 Z
11
+ date: 2018-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: '1.0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: oga
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '2.14'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '2.14'
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: omniauth
169
183
  requirement: !ruby/object:Gem::Requirement
@@ -238,28 +252,28 @@ dependencies:
238
252
  name: sequel
239
253
  requirement: !ruby/object:Gem::Requirement
240
254
  requirements:
241
- - - "~>"
255
+ - - ">="
242
256
  - !ruby/object:Gem::Version
243
257
  version: '4.0'
244
258
  type: :runtime
245
259
  prerelease: false
246
260
  version_requirements: !ruby/object:Gem::Requirement
247
261
  requirements:
248
- - - "~>"
262
+ - - ">="
249
263
  - !ruby/object:Gem::Version
250
264
  version: '4.0'
251
265
  - !ruby/object:Gem::Dependency
252
266
  name: sinatra
253
267
  requirement: !ruby/object:Gem::Requirement
254
268
  requirements:
255
- - - "~>"
269
+ - - ">="
256
270
  - !ruby/object:Gem::Version
257
271
  version: '2.0'
258
272
  type: :runtime
259
273
  prerelease: false
260
274
  version_requirements: !ruby/object:Gem::Requirement
261
275
  requirements:
262
- - - "~>"
276
+ - - ">="
263
277
  - !ruby/object:Gem::Version
264
278
  version: '2.0'
265
279
  - !ruby/object:Gem::Dependency
@@ -384,15 +398,18 @@ files:
384
398
  - public/manifest.json
385
399
  - views/404.haml
386
400
  - views/audit_logs/index.haml
401
+ - views/embedded.haml
387
402
  - views/error.haml
388
403
  - views/identity/login.haml
389
404
  - views/identity/register.haml
390
405
  - views/index.haml
391
406
  - views/layout.haml
407
+ - views/partials/actions.haml
392
408
  - views/partials/delete_form.haml
393
409
  - views/partials/filter_control.haml
394
410
  - views/partials/footer.haml
395
411
  - views/partials/form_control.haml
412
+ - views/partials/form_tag.haml
396
413
  - views/partials/navbar.haml
397
414
  - views/partials/notifications.haml
398
415
  - views/partials/pager.haml
@@ -430,7 +447,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
430
447
  version: '0'
431
448
  requirements: []
432
449
  rubyforge_project:
433
- rubygems_version: 2.7.4
450
+ rubygems_version: 2.7.6
434
451
  signing_key:
435
452
  specification_version: 4
436
453
  summary: Sinatra Based Application Framework