chaltron 0.3.2 → 1.0.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 +5 -5
- data/README.md +2 -1
- data/app/assets/javascripts/chaltron.js +7 -5
- data/app/assets/javascripts/chaltron/datatables.js.coffee +2 -2
- data/app/assets/javascripts/chaltron/navbar.js.coffee +46 -0
- data/app/assets/javascripts/dataTables/dataTables.bootstrap4.min.js +8 -0
- data/app/assets/stylesheets/chaltron.scss +9 -9
- data/app/assets/stylesheets/chaltron/layout.scss +3 -29
- data/app/assets/stylesheets/chaltron/logs.scss +5 -0
- data/app/controllers/chaltron/ldap_controller.rb +5 -5
- data/app/controllers/chaltron/omniauth_callbacks_controller.rb +0 -1
- data/app/controllers/chaltron/sessions_controller.rb +0 -3
- data/app/controllers/chaltron/users_controller.rb +1 -3
- data/app/datatables/log_datatable.rb +3 -2
- data/app/helpers/chaltron/ldap_helper.rb +3 -3
- data/app/helpers/chaltron/logs_helper.rb +4 -13
- data/app/helpers/chaltron/users_helper.rb +20 -2
- data/app/helpers/chaltron_helper.rb +0 -16
- data/app/models/authorizable.rb +1 -1
- data/app/models/log.rb +10 -12
- data/app/models/user.rb +1 -5
- data/app/views/chaltron/ldap/multi_create.html.erb +39 -35
- data/app/views/chaltron/ldap/multi_new.html.erb +36 -30
- data/app/views/chaltron/ldap/search.html.erb +13 -10
- data/app/views/chaltron/logs/index.html.erb +22 -28
- data/app/views/chaltron/logs/show.html.erb +6 -6
- data/app/views/chaltron/users/_form.html.erb +8 -5
- data/app/views/chaltron/users/_side_filters.html.erb +10 -26
- data/app/views/chaltron/users/edit.html.erb +1 -1
- data/app/views/chaltron/users/index.html.erb +29 -31
- data/app/views/chaltron/users/new.html.erb +1 -1
- data/app/views/chaltron/users/self_edit.html.erb +27 -20
- data/app/views/chaltron/users/self_show.html.erb +8 -8
- data/app/views/chaltron/users/show.html.erb +10 -10
- data/app/views/devise/passwords/edit.html.erb +8 -7
- data/app/views/devise/passwords/new.html.erb +10 -7
- data/app/views/devise/sessions/_new_ldap.html.erb +17 -14
- data/app/views/devise/sessions/_new_local.html.erb +10 -7
- data/app/views/devise/sessions/new.html.erb +30 -25
- data/app/views/locales/en.yml +4 -4
- data/app/views/locales/it.yml +2 -2
- data/config/chaltron_navigation.rb +15 -23
- data/config/locales/en.yml +1 -6
- data/config/locales/it.yml +1 -6
- data/config/routes.rb +4 -5
- data/lib/chaltron.rb +1 -24
- data/lib/chaltron/bootstrap_form.rb +1 -1
- data/lib/chaltron/engine.rb +2 -3
- data/lib/chaltron/ldap/connection.rb +34 -93
- data/lib/chaltron/ldap/person.rb +3 -13
- data/lib/chaltron/ldap/user.rb +1 -5
- data/lib/chaltron/version.rb +1 -1
- data/lib/generators/chaltron/install_generator.rb +9 -3
- data/lib/generators/chaltron/templates/app/assets/stylesheets/home.scss +2 -20
- data/lib/generators/chaltron/templates/app/views/home/_carousel.html.erb +18 -18
- data/lib/generators/chaltron/templates/app/views/home/_faq.html.erb +10 -8
- data/lib/generators/chaltron/templates/app/views/home/_panel.html.erb +5 -7
- data/lib/generators/chaltron/templates/app/views/home/index.html.erb +12 -10
- data/lib/generators/chaltron/templates/app/views/home/test.html.erb +3 -5
- data/lib/generators/chaltron/templates/app/views/layouts/_footer.html.erb +7 -9
- data/lib/generators/chaltron/templates/app/views/layouts/_navbar.html.erb +8 -15
- data/lib/generators/chaltron/templates/config/initializers/chaltron.rb +4 -57
- data/lib/generators/chaltron/templates/config/navigation.rb +11 -10
- data/lib/templates/erb/scaffold/_form.html.erb +8 -5
- data/lib/templates/erb/scaffold/edit.html.erb +8 -8
- data/lib/templates/erb/scaffold/index.html.erb +15 -21
- data/lib/templates/erb/scaffold/new.html.erb +2 -6
- data/lib/templates/erb/scaffold/show.html.erb +9 -9
- metadata +24 -25
- data/app/assets/javascripts/dataTables/extras/dataTables.select.min.js +0 -23
- data/app/assets/stylesheets/dataTables/dataTables.bootstrap.css +0 -167
- data/app/assets/stylesheets/dataTables/extras/select.dataTables.css +0 -100
- data/app/models/application_record.rb +0 -3
- data/app/views/chaltron/logs/_log.html.erb +0 -14
data/lib/chaltron/engine.rb
CHANGED
@@ -2,7 +2,7 @@ require 'devise'
|
|
2
2
|
require 'cancancan'
|
3
3
|
require 'omniauth'
|
4
4
|
require 'omniauth-ldap'
|
5
|
-
require 'bootstrap
|
5
|
+
require 'bootstrap'
|
6
6
|
require 'autoprefixer-rails'
|
7
7
|
require 'font-awesome-sass'
|
8
8
|
require 'simple-navigation'
|
@@ -11,9 +11,8 @@ require 'bootstrap_form'
|
|
11
11
|
require 'nprogress-rails'
|
12
12
|
require 'rails-i18n'
|
13
13
|
require 'jquery-rails'
|
14
|
-
require 'jquery-datatables
|
14
|
+
require 'jquery-datatables'
|
15
15
|
|
16
|
-
require 'simple_navigation_bootstrap'
|
17
16
|
SimpleNavigation.config_file_paths << File.expand_path('../../../config', __FILE__)
|
18
17
|
|
19
18
|
module Chaltron
|
@@ -4,12 +4,6 @@ require 'chaltron/ldap/person'
|
|
4
4
|
module Chaltron
|
5
5
|
module LDAP
|
6
6
|
class Connection
|
7
|
-
NET_LDAP_ENCRYPTION_METHOD = {
|
8
|
-
simple_tls: :simple_tls,
|
9
|
-
start_tls: :start_tls,
|
10
|
-
plain: nil
|
11
|
-
}.freeze
|
12
|
-
|
13
7
|
attr_reader :ldap
|
14
8
|
|
15
9
|
def initialize(params = {})
|
@@ -22,9 +16,7 @@ module Chaltron
|
|
22
16
|
end
|
23
17
|
|
24
18
|
def find_by_uid(id)
|
25
|
-
|
26
|
-
opts[uid.to_sym] = id
|
27
|
-
ret = find_user(opts)
|
19
|
+
find_user(uid: id)
|
28
20
|
end
|
29
21
|
|
30
22
|
def find_user(*args)
|
@@ -55,31 +47,35 @@ module Chaltron
|
|
55
47
|
scope: Net::LDAP::SearchScope_BaseObject
|
56
48
|
}
|
57
49
|
else
|
58
|
-
filters =
|
59
|
-
|
60
|
-
Net::LDAP::Filter.eq(
|
50
|
+
filters = []
|
51
|
+
fields.each do |field|
|
52
|
+
filters << Net::LDAP::Filter.eq(field, args[field])
|
61
53
|
end
|
62
54
|
options = {
|
63
55
|
base: base,
|
64
56
|
filter: filters.inject { |sum, n| Net::LDAP::Filter.join(sum, n) }
|
65
57
|
}
|
66
58
|
end
|
67
|
-
options.merge!(size: limit) unless limit.nil?
|
68
|
-
ldap_search(options).map do |entry|
|
69
|
-
Chaltron::LDAP::Person.new(entry, uid) if entry.respond_to? uid
|
70
|
-
end.compact
|
71
|
-
end
|
72
59
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
filter:
|
77
|
-
|
78
|
-
|
79
|
-
|
60
|
+
# if config.user_filter.present?
|
61
|
+
# user_filter = Net::LDAP::Filter.construct(config.user_filter)
|
62
|
+
|
63
|
+
# options[:filter] = if options[:filter]
|
64
|
+
# Net::LDAP::Filter.join(options[:filter], user_filter)
|
65
|
+
# else
|
66
|
+
# user_filter
|
67
|
+
# end
|
68
|
+
# end
|
80
69
|
|
81
|
-
|
82
|
-
|
70
|
+
options.merge!(size: limit) if limit.present?
|
71
|
+
|
72
|
+
entries = ldap_search(options).select do |entry|
|
73
|
+
entry.respond_to? uid
|
74
|
+
end
|
75
|
+
|
76
|
+
entries.map do |entry|
|
77
|
+
Chaltron::LDAP::Person.new(entry, uid)
|
78
|
+
end
|
83
79
|
end
|
84
80
|
|
85
81
|
private
|
@@ -88,21 +84,15 @@ module Chaltron
|
|
88
84
|
Devise.omniauth_configs[:ldap].options
|
89
85
|
end
|
90
86
|
|
91
|
-
def translate_field field
|
92
|
-
return uid if field.to_sym == :uid
|
93
|
-
return Chaltron.ldap_field_mappings[field.to_sym] unless Chaltron.ldap_field_mappings[field.to_sym].nil?
|
94
|
-
field
|
95
|
-
end
|
96
|
-
|
97
87
|
def adapter_options
|
98
|
-
|
88
|
+
{
|
99
89
|
host: options[:host],
|
100
90
|
port: options[:port],
|
101
|
-
encryption:
|
91
|
+
encryption: encryption,
|
102
92
|
verbose: true
|
103
|
-
}
|
104
|
-
|
105
|
-
|
93
|
+
}.tap do |options|
|
94
|
+
options.merge!(auth_options) if has_auth?
|
95
|
+
end
|
106
96
|
end
|
107
97
|
|
108
98
|
def base
|
@@ -113,64 +103,15 @@ module Chaltron
|
|
113
103
|
options[:uid]
|
114
104
|
end
|
115
105
|
|
116
|
-
def
|
117
|
-
method
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
}
|
123
|
-
end
|
124
|
-
|
125
|
-
def translate_method
|
126
|
-
NET_LDAP_ENCRYPTION_METHOD[options[:encryption]&.to_sym]
|
127
|
-
end
|
128
|
-
|
129
|
-
def tls_options
|
130
|
-
return @tls_options if defined?(@tls_options)
|
131
|
-
|
132
|
-
method = translate_method
|
133
|
-
return unless method
|
134
|
-
|
135
|
-
opts = if options[:disable_verify_certificates]
|
136
|
-
# It is important to explicitly set verify_mode for two reasons:
|
137
|
-
# 1. The behavior of OpenSSL is undefined when verify_mode is not set.
|
138
|
-
# 2. The net-ldap gem implementation verifies the certificate hostname
|
139
|
-
# unless verify_mode is set to VERIFY_NONE.
|
140
|
-
{ verify_mode: OpenSSL::SSL::VERIFY_NONE }
|
106
|
+
def encryption
|
107
|
+
case options[:method].to_s
|
108
|
+
when 'ssl'
|
109
|
+
:simple_tls
|
110
|
+
when 'tls'
|
111
|
+
:start_tls
|
141
112
|
else
|
142
|
-
|
143
|
-
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.dup
|
144
|
-
end
|
145
|
-
|
146
|
-
opts.merge!(custom_tls_options)
|
147
|
-
|
148
|
-
@tls_options = opts
|
149
|
-
end
|
150
|
-
|
151
|
-
def custom_tls_options
|
152
|
-
return {} unless options['tls_options']
|
153
|
-
|
154
|
-
# Dup so we don't overwrite the original value
|
155
|
-
custom_options = options['tls_options'].dup.delete_if { |_, value| value.nil? || value.blank? }
|
156
|
-
custom_options.symbolize_keys!
|
157
|
-
|
158
|
-
if custom_options[:cert]
|
159
|
-
begin
|
160
|
-
custom_options[:cert] = OpenSSL::X509::Certificate.new(custom_options[:cert])
|
161
|
-
rescue OpenSSL::X509::CertificateError => e
|
162
|
-
Rails.logger.error "LDAP TLS Options 'cert' is invalid for provider #{provider}: #{e.message}"
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
if custom_options[:key]
|
167
|
-
begin
|
168
|
-
custom_options[:key] = OpenSSL::PKey.read(custom_options[:key])
|
169
|
-
rescue OpenSSL::PKey::PKeyError => e
|
170
|
-
Rails.logger.error "LDAP TLS Options 'key' is invalid for provider #{provider}: #{e.message}"
|
171
|
-
end
|
113
|
+
nil
|
172
114
|
end
|
173
|
-
custom_options
|
174
115
|
end
|
175
116
|
|
176
117
|
def auth_options
|
data/lib/chaltron/ldap/person.rb
CHANGED
@@ -44,17 +44,11 @@ module Chaltron
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def department
|
47
|
-
entry.
|
47
|
+
entry.department.first rescue nil
|
48
48
|
end
|
49
49
|
|
50
50
|
def name
|
51
|
-
|
52
|
-
first_name = entry.send(Chaltron.ldap_field_mappings[:first_name]).first
|
53
|
-
last_name = entry.send(Chaltron.ldap_field_mappings[:last_name]).first
|
54
|
-
"#{first_name} #{last_name}"
|
55
|
-
else
|
56
|
-
entry.send(Chaltron.ldap_field_mappings[:full_name]).first
|
57
|
-
end
|
51
|
+
entry.cn.first
|
58
52
|
end
|
59
53
|
|
60
54
|
def uid
|
@@ -66,7 +60,7 @@ module Chaltron
|
|
66
60
|
end
|
67
61
|
|
68
62
|
def email
|
69
|
-
entry.
|
63
|
+
entry.mail.first rescue nil
|
70
64
|
end
|
71
65
|
|
72
66
|
def dn
|
@@ -77,10 +71,6 @@ module Chaltron
|
|
77
71
|
'ldap'
|
78
72
|
end
|
79
73
|
|
80
|
-
def ldap_groups
|
81
|
-
self.class.ldap.find_groups_by_member(self)
|
82
|
-
end
|
83
|
-
|
84
74
|
private
|
85
75
|
|
86
76
|
def self.ldap
|
data/lib/chaltron/ldap/user.rb
CHANGED
@@ -20,11 +20,7 @@ module Chaltron
|
|
20
20
|
entry = Chaltron::LDAP::Person.find_by_uid(username)
|
21
21
|
if user.nil? and create
|
22
22
|
# create user
|
23
|
-
|
24
|
-
roles = entry.ldap_groups.map do |e|
|
25
|
-
Chaltron.ldap_role_mappings[e.dn]
|
26
|
-
end.compact if !Chaltron.ldap_role_mappings.blank?
|
27
|
-
user = entry.create_user(roles)
|
23
|
+
user = entry.create_user Chaltron.default_roles
|
28
24
|
end
|
29
25
|
update_ldap_attributes(user, entry) unless user.nil?
|
30
26
|
user
|
data/lib/chaltron/version.rb
CHANGED
@@ -15,6 +15,15 @@ module Chaltron
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
def gemfile
|
19
|
+
gem 'bootstrap_form',
|
20
|
+
git: 'https://github.com/bootstrap-ruby/rails-bootstrap-forms.git',
|
21
|
+
branch: 'master'
|
22
|
+
Bundler.with_clean_env do
|
23
|
+
run 'bundle install'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
18
27
|
def db_migrations
|
19
28
|
rake 'chaltron_engine:install:migrations'
|
20
29
|
end
|
@@ -42,9 +51,6 @@ RUBY
|
|
42
51
|
# javascript
|
43
52
|
inject_into_file 'app/assets/javascripts/application.js',
|
44
53
|
"//= require chaltron\n", before: '//= require_tree .'
|
45
|
-
# css
|
46
|
-
inject_into_file 'app/assets/stylesheets/application.css',
|
47
|
-
" *= require chaltron\n", before: ' *= require_self'
|
48
54
|
end
|
49
55
|
|
50
56
|
def create_index_controller
|
@@ -2,29 +2,11 @@
|
|
2
2
|
// They will automatically be included in application.css.
|
3
3
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
4
4
|
|
5
|
+
@import 'chaltron';
|
6
|
+
|
5
7
|
#main-carousel {
|
6
8
|
img {
|
7
9
|
height: 400px;
|
8
10
|
width: 100%;
|
9
11
|
}
|
10
|
-
margin-bottom: 60px;
|
11
|
-
}
|
12
|
-
|
13
|
-
.marketing {
|
14
|
-
img.img-circle {
|
15
|
-
height: 140px;
|
16
|
-
width: 140px;
|
17
|
-
}
|
18
|
-
.col-lg-4 {
|
19
|
-
margin-bottom: 20px;
|
20
|
-
text-align: center;
|
21
|
-
}
|
22
|
-
}
|
23
|
-
|
24
|
-
.featurette-divider {
|
25
|
-
margin: 80px 0;
|
26
|
-
}
|
27
|
-
|
28
|
-
.featurette-heading {
|
29
|
-
font-size: 50px;
|
30
12
|
}
|
@@ -1,39 +1,39 @@
|
|
1
|
-
<div id='main-carousel' class='carousel slide' data-ride='carousel'>
|
2
|
-
|
3
|
-
<ol class=
|
4
|
-
<li data-target=
|
5
|
-
<li data-target=
|
6
|
-
<li data-target=
|
1
|
+
<div id='main-carousel' class='carousel slide border-bottom border-primary' data-ride='carousel'>
|
2
|
+
|
3
|
+
<ol class="carousel-indicators">
|
4
|
+
<li data-target="#main-carousel" data-slide-to="0" class="active"></li>
|
5
|
+
<li data-target="#main-carousel" data-slide-to="1"></li>
|
6
|
+
<li data-target="#main-carousel" data-slide-to="2"></li>
|
7
7
|
</ol>
|
8
8
|
|
9
|
-
<!-- Wrapper for slides -->
|
10
9
|
<div class='carousel-inner'>
|
11
|
-
<div class='item active'>
|
10
|
+
<div class='carousel-item active'>
|
12
11
|
<%= image_tag('slide1.gif') %>
|
13
|
-
<div class='carousel-caption'>
|
12
|
+
<div class='carousel-caption d-none d-md-block'>
|
14
13
|
<h1>Chaltron rulez!</h1>
|
15
14
|
</div>
|
16
15
|
</div>
|
17
|
-
<div class='item'>
|
16
|
+
<div class='carousel-item'>
|
18
17
|
<%= image_tag('slide2.gif') %>
|
19
|
-
<div class='carousel-caption'>
|
18
|
+
<div class='carousel-caption d-none d-md-block'>
|
20
19
|
<h1>Wow!</h1>
|
21
20
|
<p>Looking good</p>
|
22
21
|
</div>
|
23
22
|
</div>
|
24
|
-
<div class='item'>
|
23
|
+
<div class='carousel-item'>
|
25
24
|
<%= image_tag('slide3.gif') %>
|
26
|
-
<div class='carousel-caption'>
|
25
|
+
<div class='carousel-caption d-none d-md-block'>
|
27
26
|
<h1>Not bad!</h1>
|
28
27
|
</div>
|
29
28
|
</div>
|
30
29
|
</div>
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
<span class=
|
31
|
+
<a class="carousel-control-prev" href="#main-carousel" role="button" data-slide="prev">
|
32
|
+
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
33
|
+
<span class="sr-only">Previous</span>
|
35
34
|
</a>
|
36
|
-
<a class=
|
37
|
-
<span class=
|
35
|
+
<a class="carousel-control-next" href="#main-carousel" role="button" data-slide="next">
|
36
|
+
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
37
|
+
<span class="sr-only">Next</span>
|
38
38
|
</a>
|
39
39
|
</div>
|
@@ -1,11 +1,13 @@
|
|
1
|
-
<div class=
|
2
|
-
|
3
|
-
<
|
4
|
-
<%= link_to raw(faq[:question]), "#collapse#{faq_counter}", data: {toggle: 'collapse'
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
<div class='card'>
|
2
|
+
<%= content_tag :div, id: "heading#{faq_counter}", class: 'card-header', role: 'tab' do %>
|
3
|
+
<h5 class='mb-0'>
|
4
|
+
<%= link_to raw(faq[:question]), "#collapse#{faq_counter}", data: {toggle: 'collapse'},
|
5
|
+
role: 'button', aria: {expanded: false, controls: "collapse#{faq_counter}"}, class: 'collapsed' %>
|
6
|
+
</h5>
|
7
|
+
<% end %>
|
8
|
+
<%= content_tag :div, id: "collapse#{faq_counter}", class: 'collapse', role: 'tabpanel',
|
9
|
+
data: { parent: '#accordion'}, aria: {labelledby: "heading#{faq_counter}"} do %>
|
10
|
+
<div class="card-body">
|
9
11
|
<%= raw faq[:answer] %>
|
10
12
|
</div>
|
11
13
|
<% end %>
|
@@ -4,15 +4,13 @@
|
|
4
4
|
link_text ||= 'Learn more'
|
5
5
|
%>
|
6
6
|
|
7
|
-
<div class=
|
8
|
-
<div class=
|
9
|
-
<
|
10
|
-
<h4>
|
7
|
+
<div class='col-md-4'>
|
8
|
+
<div class='card'>
|
9
|
+
<h5 class='card-header text-white bg-primary'>
|
11
10
|
<%= icon(icon) %>
|
12
11
|
<%= title %>
|
13
|
-
|
14
|
-
|
15
|
-
<div class="panel-body">
|
12
|
+
</h5>
|
13
|
+
<div class='card-body'>
|
16
14
|
<p><%= raw body %> </p>
|
17
15
|
<%= link_to link_text, link, class: 'btn btn-primary' %>
|
18
16
|
</div>
|
@@ -1,13 +1,12 @@
|
|
1
1
|
<%= render 'carousel' %>
|
2
|
-
|
3
2
|
<div class='container-fluid'>
|
4
3
|
<div class='row'>
|
5
4
|
<div class='col-lg-12'>
|
6
|
-
<h1 class='
|
5
|
+
<h1 class='pt-4'>
|
7
6
|
Welcome to Chaltron! <small> aka Muffaster reloaded</small>
|
8
7
|
</h1>
|
9
8
|
</div>
|
10
|
-
<%= render 'panel', title: 'Bootstrap
|
9
|
+
<%= render 'panel', title: 'Bootstrap v4',
|
11
10
|
link: 'http://getbootstrap.com', icon: 'check',
|
12
11
|
body: 'Bootstrap rocks! And there are lots of good template ready to ' \
|
13
12
|
'use, and free. Just as this one ;-)'
|
@@ -23,9 +22,11 @@
|
|
23
22
|
%>
|
24
23
|
</div>
|
25
24
|
|
25
|
+
<hr>
|
26
|
+
|
26
27
|
<div class='row'>
|
27
28
|
<div class='col-lg-12'>
|
28
|
-
<h2 class='
|
29
|
+
<h2 class='pt-4'>Main features</h2>
|
29
30
|
</div>
|
30
31
|
<div class='col-md-6'>
|
31
32
|
<p>Chaltron provides:</p>
|
@@ -33,7 +34,7 @@
|
|
33
34
|
<li>
|
34
35
|
<%= icon('check-square', '', class: 'fa-li') %>
|
35
36
|
Compatibility with
|
36
|
-
<strong><%= link_to 'Bootstrap
|
37
|
+
<strong><%= link_to 'Bootstrap v4', 'http://getbootstrap.com' %></strong> and
|
37
38
|
<strong><%= link_to 'Font Awesome v4', 'http://fortawesome.github.io/Font-Awesome/' %></strong>
|
38
39
|
</li>
|
39
40
|
<li>
|
@@ -54,13 +55,15 @@
|
|
54
55
|
taste <strong>L</strong>ight <strong>S</strong>peed <strong>A</strong>pplication <strong>D</strong>evelopment!</p>
|
55
56
|
</div>
|
56
57
|
<div class='col-md-6'>
|
57
|
-
<%= image_tag('700x300.gif', class: 'img-responsive img-thumbnail') %>
|
58
|
+
<%= image_tag('700x300.gif', class: 'img-responsive img-thumbnail border border-primary') %>
|
58
59
|
</div>
|
59
60
|
</div>
|
60
61
|
|
62
|
+
<hr>
|
63
|
+
|
61
64
|
<div class='row'%>
|
62
65
|
<div class='col-lg-12'>
|
63
|
-
<h2 class='
|
66
|
+
<h2 class='pt-4'>FAQ</h2>
|
64
67
|
</div>
|
65
68
|
</div>
|
66
69
|
|
@@ -85,11 +88,10 @@
|
|
85
88
|
}
|
86
89
|
%>
|
87
90
|
|
88
|
-
<div class='row'
|
91
|
+
<div class='row'>
|
89
92
|
<div class='col-lg-12'>
|
90
|
-
<div
|
93
|
+
<div id='accordion' role='tablist'>
|
91
94
|
<%= render partial: 'faq', collection: faqs %>
|
92
|
-
</div>
|
93
95
|
</div>
|
94
96
|
</div>
|
95
97
|
|