symphonia 2.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +16 -0
  4. data/Rakefile +44 -0
  5. data/app/assets/images/bg-checker.png +0 -0
  6. data/app/assets/images/bullet.gif +0 -0
  7. data/app/assets/images/close.png +0 -0
  8. data/app/assets/images/loading.gif +0 -0
  9. data/app/assets/images/next.png +0 -0
  10. data/app/assets/images/prev.png +0 -0
  11. data/app/assets/javascripts/ckeditor/plugins/autogrow/plugin.js +232 -0
  12. data/app/assets/javascripts/ckeditor/plugins/autogrow/samples/autogrow.html +102 -0
  13. data/app/assets/javascripts/ckeditor/plugins/image_chooser/icons/addimage.png +0 -0
  14. data/app/assets/javascripts/ckeditor/plugins/image_chooser/plugin.js +15 -0
  15. data/app/assets/javascripts/symphonia/Sortable.js +1249 -0
  16. data/app/assets/javascripts/symphonia/_core.js +45 -0
  17. data/app/assets/javascripts/symphonia/application.js.erb +147 -0
  18. data/app/assets/javascripts/symphonia/filters.js +44 -0
  19. data/app/assets/javascripts/symphonia/symphonia_bootstrap_dialog.js +136 -0
  20. data/app/assets/javascripts/symphonia/symphonia_ckeditor.js +55 -0
  21. data/app/assets/stylesheets/symphonia/application.css +4 -0
  22. data/app/assets/stylesheets/symphonia/basic.scss +218 -0
  23. data/app/assets/stylesheets/symphonia/filters.scss +19 -0
  24. data/app/assets/stylesheets/symphonia/symphonia_bootstrap.scss +56 -0
  25. data/app/channels/application_cable/channel.rb +5 -0
  26. data/app/controllers/symphonia/accounts_controller.rb +169 -0
  27. data/app/controllers/symphonia/admin_controller.rb +22 -0
  28. data/app/controllers/symphonia/api_controller.rb +64 -0
  29. data/app/controllers/symphonia/application_controller.rb +8 -0
  30. data/app/controllers/symphonia/attachments_controller.rb +37 -0
  31. data/app/controllers/symphonia/filters_controller.rb +23 -0
  32. data/app/controllers/symphonia/images_controller.rb +16 -0
  33. data/app/controllers/symphonia/login_controller.rb +80 -0
  34. data/app/controllers/symphonia/roles_controller.rb +100 -0
  35. data/app/controllers/symphonia/user_sessions_controller.rb +16 -0
  36. data/app/controllers/symphonia/users_controller.rb +168 -0
  37. data/app/helpers/symphonia/application_helper.rb +422 -0
  38. data/app/helpers/symphonia/bootstrap_modal_helper.rb +59 -0
  39. data/app/helpers/symphonia/form_helper.rb +50 -0
  40. data/app/helpers/symphonia/renderer_helper.rb +85 -0
  41. data/app/mailers/symphonia/application_mailer.rb +6 -0
  42. data/app/mailers/symphonia/notifier.rb +42 -0
  43. data/app/models/symphonia/admin_module.rb +18 -0
  44. data/app/models/symphonia/application_record.rb +14 -0
  45. data/app/models/symphonia/attachment.rb +16 -0
  46. data/app/models/symphonia/common_file.rb +9 -0
  47. data/app/models/symphonia/email_preference.rb +5 -0
  48. data/app/models/symphonia/image.rb +46 -0
  49. data/app/models/symphonia/preference.rb +12 -0
  50. data/app/models/symphonia/role.rb +55 -0
  51. data/app/models/symphonia/swagger/error_model.rb +19 -0
  52. data/app/models/symphonia/swagger/responses.rb +27 -0
  53. data/app/models/symphonia/user.rb +141 -0
  54. data/app/models/symphonia/user_session.rb +19 -0
  55. data/app/views/common/403.html.erb +5 -0
  56. data/app/views/common/404.html.erb +2 -0
  57. data/app/views/layouts/symphonia/_modal.html.erb +19 -0
  58. data/app/views/layouts/symphonia/_query.html.erb +51 -0
  59. data/app/views/layouts/symphonia/application.html.erb +45 -0
  60. data/app/views/layouts/symphonia/application.pdf.erb +15 -0
  61. data/app/views/layouts/symphonia/mailer.html.erb +13 -0
  62. data/app/views/symphonia/accounts/_detail.html.erb +65 -0
  63. data/app/views/symphonia/accounts/_form.html.erb +14 -0
  64. data/app/views/symphonia/accounts/edit.html.erb +9 -0
  65. data/app/views/symphonia/accounts/edit.js.erb +5 -0
  66. data/app/views/symphonia/accounts/lost_password.html.erb +6 -0
  67. data/app/views/symphonia/accounts/lost_password.js.erb +3 -0
  68. data/app/views/symphonia/accounts/new_activation.html.erb +11 -0
  69. data/app/views/symphonia/accounts/new_activation.js.erb +6 -0
  70. data/app/views/symphonia/accounts/register.html.erb +20 -0
  71. data/app/views/symphonia/accounts/reset_password.html.erb +18 -0
  72. data/app/views/symphonia/accounts/update.js.erb +1 -0
  73. data/app/views/symphonia/admin/index.html.erb +15 -0
  74. data/app/views/symphonia/attachments/destroy.js.erb +1 -0
  75. data/app/views/symphonia/common/_editable_images_grid.html.erb +12 -0
  76. data/app/views/symphonia/common/_filters.html.erb +23 -0
  77. data/app/views/symphonia/common/_locale_chooser.html.erb +16 -0
  78. data/app/views/symphonia/common/_share_links.html.erb +5 -0
  79. data/app/views/symphonia/filters/options.html.erb +36 -0
  80. data/app/views/symphonia/filters/options.js.erb +9 -0
  81. data/app/views/symphonia/filters/table.html.erb +21 -0
  82. data/app/views/symphonia/login/_form.html.erb +19 -0
  83. data/app/views/symphonia/login/new.html.erb +11 -0
  84. data/app/views/symphonia/login_sessions/new.html.erb +1 -0
  85. data/app/views/symphonia/notifier/activation_user.html.erb +7 -0
  86. data/app/views/symphonia/notifier/activation_user.text.erb +3 -0
  87. data/app/views/symphonia/notifier/reset_password_user.html.erb +7 -0
  88. data/app/views/symphonia/notifier/reset_password_user.text.erb +3 -0
  89. data/app/views/symphonia/notifier/test_mail.html.erb +2 -0
  90. data/app/views/symphonia/notifier/test_mail.text.erb +3 -0
  91. data/app/views/symphonia/notifier/user_change_to_active.html.erb +3 -0
  92. data/app/views/symphonia/notifier/user_change_to_active.text.erb +1 -0
  93. data/app/views/symphonia/notifier/user_registered.html.erb +13 -0
  94. data/app/views/symphonia/notifier/user_registered.text.erb +8 -0
  95. data/app/views/symphonia/roles/_form.html.erb +30 -0
  96. data/app/views/symphonia/roles/edit.html.erb +5 -0
  97. data/app/views/symphonia/roles/index.html.erb +6 -0
  98. data/app/views/symphonia/roles/new.html.erb +4 -0
  99. data/app/views/symphonia/roles/show.html.erb +5 -0
  100. data/app/views/symphonia/users/_form.html.erb +13 -0
  101. data/app/views/symphonia/users/edit.html.erb +26 -0
  102. data/app/views/symphonia/users/edit.js.erb +3 -0
  103. data/app/views/symphonia/users/edit_current.html.erb +7 -0
  104. data/app/views/symphonia/users/index.html.erb +5 -0
  105. data/app/views/symphonia/users/new.html.erb +8 -0
  106. data/app/views/symphonia/users/show.html.erb +63 -0
  107. data/config/locales/cs.yml +233 -0
  108. data/config/locales/en.yml +47 -0
  109. data/config/routes.rb +52 -0
  110. data/db/migrate/20130714140500_create_users.rb +49 -0
  111. data/db/migrate/20130714140501_create_roles.rb +16 -0
  112. data/db/migrate/20130714140502_create_preferences.rb +26 -0
  113. data/db/migrate/20130828175114_create_attachments.rb +20 -0
  114. data/db/migrate/20141213204351_create_admin_modules.rb +20 -0
  115. data/db/seeds.rb +12 -0
  116. data/lib/generators/symphonia/entity_controller/entity_controller_generator.rb +48 -0
  117. data/lib/generators/symphonia/entity_controller/templates/controller.rb +100 -0
  118. data/lib/generators/symphonia/query/query_generator.rb +37 -0
  119. data/lib/generators/symphonia/setup/setup_generator.rb +52 -0
  120. data/lib/generators/symphonia/setup/templates/404.html +26 -0
  121. data/lib/generators/symphonia/setup/templates/500.html +37 -0
  122. data/lib/generators/symphonia/setup/templates/Gemfile +18 -0
  123. data/lib/generators/symphonia/setup/templates/base_layout.html.erb +46 -0
  124. data/lib/generators/symphonia/setup/templates/design.scss +4 -0
  125. data/lib/generators/symphonia/setup/templates/settings.rb +65 -0
  126. data/lib/generators/symphonia/setup/templates/spec_helper.rb +18 -0
  127. data/lib/symphonia/action_cable/connection.rb +31 -0
  128. data/lib/symphonia/admin_constraint.rb +9 -0
  129. data/lib/symphonia/attachable.rb +35 -0
  130. data/lib/symphonia/base_controller.rb +96 -0
  131. data/lib/symphonia/bootstrap_link_render.rb +69 -0
  132. data/lib/symphonia/controller_extensions.rb +200 -0
  133. data/lib/symphonia/engine.rb +137 -0
  134. data/lib/symphonia/form_builder.rb +137 -0
  135. data/lib/symphonia/menu_manager.rb +23 -0
  136. data/lib/symphonia/model_attributes/attribute.rb +137 -0
  137. data/lib/symphonia/model_attributes.rb +102 -0
  138. data/lib/symphonia/model_filters/base.rb +82 -0
  139. data/lib/symphonia/model_filters/boolean_filter.rb +26 -0
  140. data/lib/symphonia/model_filters/date_filter.rb +81 -0
  141. data/lib/symphonia/model_filters/integer_filter.rb +18 -0
  142. data/lib/symphonia/model_filters/select_filter.rb +48 -0
  143. data/lib/symphonia/model_filters/string_filter.rb +18 -0
  144. data/lib/symphonia/model_filters.rb +10 -0
  145. data/lib/symphonia/object.rb +31 -0
  146. data/lib/symphonia/permissions.rb +93 -0
  147. data/lib/symphonia/query.rb +275 -0
  148. data/lib/symphonia/query_columns/attribute_column.rb +43 -0
  149. data/lib/symphonia/query_columns/generic_column.rb +165 -0
  150. data/lib/symphonia/query_columns.rb +8 -0
  151. data/lib/symphonia/spec_helper.rb +4 -0
  152. data/lib/symphonia/user_management.rb +58 -0
  153. data/lib/symphonia/version.rb +4 -0
  154. data/lib/symphonia.rb +20 -0
  155. data/spec/controllers/account_controller_spec.rb +90 -0
  156. data/spec/controllers/admin_controller_spec.rb +35 -0
  157. data/spec/controllers/api_controller_spec.rb +9 -0
  158. data/spec/controllers/filters_controller_spec.rb +35 -0
  159. data/spec/controllers/images_controller_spec.rb +5 -0
  160. data/spec/controllers/login_controller_spec.rb +20 -0
  161. data/spec/controllers/roles_controller_spec.rb +12 -0
  162. data/spec/controllers/users_controller_spec.rb +47 -0
  163. data/spec/factories/factories.rb +52 -0
  164. data/spec/helpers/symphonia/application_helper_spec.rb +62 -0
  165. data/spec/mailers/previews/symphonia/notifier_preview.rb +27 -0
  166. data/spec/mailers/symphonia/notifier_spec.rb +76 -0
  167. data/spec/models/attachment_spec.rb +22 -0
  168. data/spec/models/query/attribute_spec.rb +8 -0
  169. data/spec/models/query/symphonia_query_spec.rb +70 -0
  170. data/spec/models/role_spec.rb +13 -0
  171. data/spec/models/user_spec.rb +10 -0
  172. data/spec/rails_helper.rb +13 -0
  173. data/spec/requests/accounts_spec.rb +118 -0
  174. data/spec/requests/attachments_controller_spec.rb +23 -0
  175. data/spec/requests/login_spec.rb +26 -0
  176. data/spec/requests/roles_spec.rb +10 -0
  177. data/spec/requests/users_spec.rb +50 -0
  178. data/spec/spec_helper.rb +101 -0
  179. data/spec/support/common_file.txt +2 -0
  180. data/spec/support/query.rb +36 -0
  181. data/spec/support/shared.rb +62 -0
  182. data/spec/support/shared_controllers.rb +31 -0
  183. data/spec/support/stub_users.rb +32 -0
  184. data/spec/support/symphonia.jpg +0 -0
  185. data/spec/support/wait_for_ajax.rb +15 -0
  186. data/spec/version_spec.rb +5 -0
  187. data/spec/views/filters/options.html.erb_spec.rb +14 -0
  188. metadata +697 -0
@@ -0,0 +1,200 @@
1
+ module Symphonia
2
+ module ControllerExtensions
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+
7
+ included do
8
+ class Unauthorized < Exception; end
9
+
10
+ before_action :current_user, :menu_item
11
+ before_action :set_default_locale
12
+
13
+ # force_ssl if: -> {Rails.env.production? && User.current.ssl?}
14
+
15
+ add_flash_types :warning
16
+ add_flash_types :error
17
+
18
+ rescue_from ::ActiveRecord::RecordNotFound do
19
+ render_404
20
+ end
21
+
22
+ rescue_from Unauthorized do
23
+ render_403
24
+ end
25
+
26
+ helper_method :current_user
27
+
28
+ end
29
+
30
+ def back_url
31
+ url = params[:back_url]
32
+ if url.nil? && (referer = request.env['HTTP_REFERER'])
33
+ url = CGI.unescape(referer.to_s)
34
+ end
35
+ url
36
+ end
37
+
38
+ # def redirect_back_or_default(default, options={})
39
+ # back_url = params[:back_url].to_s
40
+ # if back_url.present?
41
+ # begin
42
+ # uri = URI.parse(back_url)
43
+ # # do not redirect user to another host or to the login or register page
44
+ # if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)})
45
+ # redirect_to(back_url)
46
+ # return
47
+ # end
48
+ # rescue URI::InvalidURIError
49
+ # logger.warn("Could not redirect to invalid URL #{back_url}")
50
+ # # redirect to default
51
+ # end
52
+ # elsif options[:referer]
53
+ # redirect_to_referer_or default
54
+ # return
55
+ # end
56
+ # redirect_to default, options
57
+ # false
58
+ # end
59
+
60
+ # Redirects to the request referer if present, redirects to args or call block otherwise.
61
+ def redirect_to_referer_or(*args, &block)
62
+ redirect_to :back
63
+ rescue ::ActionController::RedirectBackError
64
+ if args.any?
65
+ redirect_to *args
66
+ elsif block_given?
67
+ block.call
68
+ else
69
+ raise "#redirect_to_referer_or takes arguments or a block"
70
+ end
71
+ end
72
+
73
+ # private
74
+
75
+ def set_locale
76
+ client_lang = params.fetch(:locale, nil).presence || session[:locale].presence || request.env['HTTP_ACCEPT_LANGUAGE'].to_s.split(',').collect { |l| l.scan(/^[a-z]{2}/) }.flatten
77
+ @client_lang = Array(client_lang).detect { |l| I18n.available_locales.include?(l.to_sym) }
78
+
79
+ I18n.locale = (@client_lang || I18n.default_locale)
80
+ session[:locale] = I18n.locale
81
+
82
+ logger.debug "* Locale set to '#{I18n.locale}'"
83
+ end
84
+
85
+ def set_default_locale
86
+ if (enforce_default = Symphonia.config.default_locale)
87
+ I18n.locale = enforce_default
88
+ end
89
+ end
90
+
91
+ # protected
92
+
93
+ def login_require(format = nil)
94
+ if current_user.nil? || !current_user.logged_in?
95
+ respond_to do |format|
96
+ format.html do
97
+ store_location
98
+ redirect_to symphonia.login_path, flash: { error: t(:text_login_require) }
99
+ end
100
+ format.json do
101
+ render json: { errors: 'You must be logged in to access this endpoint' }, status: 403
102
+ end
103
+ end
104
+ return false
105
+ end
106
+ true
107
+ end
108
+
109
+ alias_method :require_login, :login_require
110
+ alias_method :require_user, :login_require
111
+
112
+ def admin_require
113
+ return unless login_require
114
+ unless current_user.admin?
115
+ render_403
116
+ return false
117
+ end
118
+ end
119
+
120
+ alias_method :require_admin, :admin_require
121
+
122
+ def render_403
123
+ respond_to do |format|
124
+ format.html { render template: 'common/403', message: :notice_not_authorized, status: 403 }
125
+ format.js { render plain: "alert('#{t :text_access_deny}')", message: :notice_not_authorized, status: 403 }
126
+ format.json { head 403, message: :notice_not_authorized }
127
+ end
128
+ end
129
+
130
+ def render_404
131
+ respond_to do |format|
132
+ format.html { render template: 'common/404', message: :notice_page_not_found, status: 404 }
133
+ format.json { head 404, message: :not_found }
134
+ end
135
+ end
136
+
137
+ # Renders a 200 response for successful updates or deletions via the API
138
+ def render_api_ok
139
+ head :ok
140
+ end
141
+
142
+ # Renders a head API response
143
+ def render_api_head(status)
144
+ head status
145
+ end
146
+
147
+ def menu_item(item = nil)
148
+ @menu_item = (item || controller_name)
149
+ end
150
+
151
+ def current_user_session
152
+ return @current_user_session if defined?(@current_user_session)
153
+ @current_user_session = UserSession.find
154
+ end
155
+
156
+ def current_user
157
+ return (Symphonia::User.current ||= @current_user) if defined?(@current_user)
158
+ @current_user = current_user_session && current_user_session.user
159
+ Symphonia::User.current = @current_user || Symphonia::User::Anonymous.new
160
+ end
161
+
162
+ def authorize
163
+ if Symphonia::User.current.authorize?(controller_name, action_name)
164
+ return true
165
+ else
166
+ if Symphonia::User.current.logged_in?
167
+ raise Unauthorized
168
+ else
169
+ respond_to do |format|
170
+ format.html do
171
+ return redirect_to(symphonia.login_path(back_url: request.path), error: t(:text_error_login_required))
172
+ end
173
+ format.any { return head 401 }
174
+ end
175
+ end
176
+ end
177
+ raise Unauthorized
178
+ end
179
+
180
+ def handle_unverified_request
181
+ # raise an exception
182
+ fail ActionController::InvalidAuthenticityToken
183
+ # or destroy session, redirect
184
+ if current_user_session
185
+ current_user_session.destroy
186
+ end
187
+ redirect_to main_app.root_url
188
+ end
189
+
190
+ def store_location
191
+ session[:return_to] = request.url
192
+ end
193
+
194
+ def redirect_back_or_default(default, options = {})
195
+ options ||= {}
196
+ redirect_to(params[:back_url] || default, options)
197
+ end
198
+
199
+ end
200
+ end
@@ -0,0 +1,137 @@
1
+ require 'symphonia/object'
2
+ require 'symphonia/menu_manager'
3
+ require 'symphonia/permissions'
4
+ require 'symphonia/user_management'
5
+
6
+ require 'rails-i18n'
7
+ require 'turbolinks'
8
+ require 'authlogic'
9
+ require 'bootstrap'
10
+
11
+ require 'will_paginate'
12
+ require 'api-pagination'
13
+ require 'font-awesome-rails'
14
+ require 'jquery-rails'
15
+ require 'jquery-ui-rails'
16
+ require 'rdiscount'
17
+ require 'sortable-table'
18
+ require 'paperclip'
19
+ require 'awesome_nested_set'
20
+ require 'acts_as_list'
21
+ require 'bootstrap_form'
22
+ require 'the_sortable_tree'
23
+ require 'bootstrap-datepicker-rails'
24
+ require 'wicked_pdf'
25
+ require 'swagger/blocks'
26
+
27
+ module Symphonia
28
+
29
+ class Engine < ::Rails::Engine
30
+ isolate_namespace Symphonia
31
+
32
+ config.generators do |g|
33
+ g.test_framework :rspec, fixture: false
34
+ # g.fixture_replacement :factory_girl, dir: 'spec/factories'
35
+ end
36
+
37
+ # Rails 5
38
+ # ActionController::Base.class_eval do
39
+ # include Symphonia::ApplicationController
40
+ # end
41
+
42
+
43
+ initializer :symphonia_extensions do
44
+ end
45
+
46
+ # ActiveSupport::Reloader.to_prepare do
47
+ # ::ApplicationController.send :helper, Symphonia::ApplicationHelper
48
+ # ::ApplicationMailer.send :helper, Symphonia::ApplicationHelper
49
+ # BootstrapForm::FormBuilder.prepend(Symphonia::FormBuilder)
50
+ # end
51
+
52
+ initializer :symphonia_setup do |_app|
53
+ Mime::Type.register 'application/pdf', :pdf
54
+ config.i18n.available_locales ||= %i[cs en]
55
+ config.i18n.default_locale = :cs
56
+
57
+ WillPaginate.per_page = 20
58
+
59
+ Symphonia.configure do |config|
60
+ config.after_login_path = ->(h) { h.symphonia.user_current_path }
61
+ config.allow_registrations = true
62
+ config.default_locale = :cs
63
+ end
64
+
65
+ end
66
+
67
+ initializer :append_migrations do |app|
68
+ if app.root.to_s != root.to_s && app.root != root.join("spec/dummy")
69
+ config.paths['db/migrate'].expanded.each do |expanded_path|
70
+ app.config.paths['db/migrate'] << expanded_path
71
+ end
72
+ end
73
+ end
74
+
75
+ # include helpers
76
+ initializer :load_helper, before: :load_config_initializers do |app|
77
+ # config.active_record.raise_in_transactional_callbacks = false
78
+ if Rails.env.development?
79
+ config.action_mailer.default_url_options ||= { host: 'symphonia.app' }
80
+ config.action_mailer.preview_path = "{#{app.root.join('spec/mailers/previews')},#{root.join('spec/mailers/previews')}}"
81
+ end
82
+ end
83
+
84
+ initializer :assets do |_app|
85
+ if defined?(::Ckeditor)
86
+ config.assets.precompile << 'ckeditor/**/*'
87
+ config.assets.precompile << 'symphonia/symphonia_ckeditor.js'
88
+ end
89
+ end
90
+
91
+ initializer :symphonia_general_permissions do |_app|
92
+ Symphonia::Permissions.map do |m|
93
+ m.register(:view_users).add(:users, %i[index show])
94
+ m.register(:manager_users).add(:users, %i[create update destroy new edit])
95
+ end
96
+
97
+ end
98
+
99
+ initializer :wicked_pdf do |_app|
100
+ WickedPdf.config = {
101
+ layout: 'application.pdf',
102
+ print_media_type: true,
103
+ viewport_size: '1280x800', zoom: 0.7, dpi: 300
104
+ }
105
+ end
106
+
107
+ initializer :api_paginate do
108
+ ApiPagination.configure do |config|
109
+ # If you have both gems included, you can choose a paginator.
110
+ config.paginator = :will_paginate
111
+
112
+ # By default, this is set to 'Total'
113
+ config.total_header = 'X-Total'
114
+
115
+ # By default, this is set to 'Per-Page'
116
+ config.per_page_header = 'X-Per-Page'
117
+
118
+ # Optional: set this to add a header with the current page number.
119
+ config.page_header = 'X-Page'
120
+
121
+ # Optional: what parameter should be used to set the page option
122
+ # config.page_param = :page
123
+ # # or
124
+ # config.page_param do |params|
125
+ # params[:page][:number]
126
+ # end
127
+ #
128
+ # # Optional: what parameter should be used to set the per page option
129
+ # config.per_page_param = :per_page
130
+ # # or
131
+ # config.per_page_param do |params|
132
+ # params[:page][:size]
133
+ # end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,137 @@
1
+ module Symphonia
2
+ class FormBuilder < ::BootstrapForm::FormBuilder
3
+
4
+ def error_messages
5
+ if object.respond_to?(:errors) && object.errors.any?
6
+ list = content_tag(:p, I18n.t('activerecord.errors.template.body')).html_safe
7
+ list += content_tag(:ul) do
8
+ object.errors.full_messages.collect do |error|
9
+ content_tag(:li, error)
10
+ end.join.html_safe
11
+ end
12
+ content_tag(:div, list, class: 'error_explanation')
13
+ end
14
+ end
15
+
16
+ def calendar_field(name, options = {})
17
+ options[:data] ||= {} #{'date-clear-btn': true, 'date-format': 'yyyy-mm-dd'}
18
+ options[:data][:'date-clear-btn'] ||= true
19
+ # options[:data][:'date-format'] ||= 'yyyy-mm-dd'
20
+ text_field(name, options.merge({
21
+ class: 'form-control datepicker',
22
+ append: @template.fa_icon('calendar')
23
+ }))
24
+ end
25
+
26
+ # def form_group_builder(method, options, html_options = nil)
27
+ # options.symbolize_keys!
28
+ # html_options.symbolize_keys! if html_options
29
+ #
30
+ # # Add control_class; allow it to be overridden by :control_class option
31
+ # css_options = html_options || options
32
+ # control_classes = css_options.delete(:control_class) { control_class }
33
+ # css_options[:class] = [control_classes, css_options[:class]].compact.join(" ")
34
+ # css_options[:class] << " is-invalid" if has_error?(method)
35
+ #
36
+ # options = convert_form_tag_options(method, options) if acts_like_form_tag
37
+ #
38
+ # wrapper_class = css_options.delete(:wrapper_class)
39
+ # wrapper_options = css_options.delete(:wrapper)
40
+ # help = options.delete(:help)
41
+ # icon = options.delete(:icon)
42
+ # label_col = options.delete(:label_col)
43
+ # control_col = options.delete(:control_col)
44
+ # layout = get_group_layout(options.delete(:layout))
45
+ # form_group_options = {
46
+ # id: options[:id],
47
+ # help: help,
48
+ # icon: icon,
49
+ # label_col: label_col,
50
+ # control_col: control_col,
51
+ # layout: layout,
52
+ # class: wrapper_class
53
+ # }
54
+ #
55
+ # if wrapper_options.is_a?(Hash)
56
+ # form_group_options.merge!(wrapper_options)
57
+ # end
58
+ #
59
+ # unless options.delete(:skip_label)
60
+ # if options[:label].is_a?(Hash)
61
+ # label_text = options[:label].delete(:text)
62
+ # label_class = options[:label].delete(:class)
63
+ # options.delete(:label)
64
+ # end
65
+ # label_class ||= options.delete(:label_class)
66
+ # label_class = hide_class if options.delete(:hide_label)
67
+ #
68
+ # if options[:label].is_a?(String)
69
+ # label_text ||= options.delete(:label)
70
+ # end
71
+ #
72
+ # form_group_options.merge!(label: {
73
+ # text: label_text,
74
+ # class: label_class,
75
+ # skip_required: options.delete(:skip_required),
76
+ # required: options.delete(:required)
77
+ # })
78
+ # end
79
+ #
80
+ # form_group(method, form_group_options) do
81
+ # yield
82
+ # end
83
+ # end
84
+
85
+ def label_text(name, options)
86
+ name = name.to_s.remove(/_id$/)
87
+
88
+ if label_errors && error?(name)
89
+ (options[:text] || object.class.human_attribute_name(name)).to_s.concat(" #{get_error_messages(name)}")
90
+ else
91
+ options[:text]
92
+ end
93
+ end
94
+ # def generate_label(id, name, options, custom_label_col, group_layout)
95
+ # return if options.blank?
96
+ # # id is the caller's options[:id] at the only place this method is called.
97
+ # # The options argument is a small subset of the options that might have
98
+ # # been passed to generate_label's caller, and definitely doesn't include
99
+ # # :id.
100
+ # options[:for] = id if acts_like_form_tag
101
+ # classes = [options[:class]]
102
+ #
103
+ # if layout_horizontal?(group_layout)
104
+ # classes << "col-form-label"
105
+ # classes << (custom_label_col || label_col)
106
+ # elsif layout_inline?(group_layout)
107
+ # classes << "mr-sm-2"
108
+ # end
109
+ #
110
+ # xname = name.to_s.remove(/_id$/)
111
+ #
112
+ # case options.delete(:required)
113
+ # when true
114
+ # classes << "required"
115
+ # when nil, :default
116
+ # classes << "required" if required_attribute?(object, name)
117
+ # end
118
+ #
119
+ # options[:class] = classes.compact.join(" ").strip
120
+ # options.delete(:class) if options[:class].empty?
121
+ #
122
+ # if label_errors && has_error?(name)
123
+ # error_messages = get_error_messages(name)
124
+ # label_text = (options[:text] || object.class.human_attribute_name(xname)).to_s.concat(" #{error_messages}")
125
+ # options[:class] = [options[:class], "text-danger"].compact.join(" ")
126
+ # label(name, label_text, options.except(:text))
127
+ # else
128
+ # label(name, options[:text], options.except(:text))
129
+ # end
130
+ # end
131
+
132
+ def error_class
133
+ 'is-invalid'
134
+ end
135
+
136
+ end
137
+ end
@@ -0,0 +1,23 @@
1
+ module Symphonia
2
+ module MenuManager
3
+ @@mapper = {}
4
+ mattr_accessor :mapper
5
+
6
+ def self.menu(name)
7
+ return mapper[name.to_sym] || {}
8
+ end
9
+
10
+ class << self
11
+ def map(menu_name)
12
+ mapper[menu_name] ||= {}
13
+ if block_given?
14
+ yield mapper[menu_name]
15
+ end
16
+ end
17
+
18
+ def clear(menu_name)
19
+ !mapper.delete(menu_name.to_sym).nil?
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,137 @@
1
+ module Symphonia
2
+ module ModelAttributes
3
+ class Attribute
4
+
5
+ attr_reader :name, :options
6
+ attr_reader :format_options, :sort_column
7
+ attr_accessor :filter
8
+
9
+ def initialize(name, klass, options, formatter)
10
+ @name = name
11
+ @klass = klass
12
+ @formatter = formatter
13
+ @options = options
14
+ @format_options = {}
15
+ end
16
+
17
+ def title
18
+ @klass.human_attribute_name(@name.to_s.remove(/_id$/), @options[:i18n] || {})
19
+ end
20
+
21
+ def value(entity)
22
+ entity.send(name)
23
+ end
24
+
25
+ def format(view, entity, options={})
26
+ @format_options = options
27
+ if @formatter.is_a?(Proc)
28
+ @formatter.call(view, self, entity).to_s
29
+ else
30
+ format_value(view, value(entity), entity)
31
+ end
32
+ end
33
+
34
+ def sort=(sort_options)
35
+ t = @klass.arel_table
36
+ @sort = true
37
+ case sort_options
38
+ when false
39
+ @sort = false
40
+ when Symbol, Array
41
+ sort = Array(sort_options).collect { |i| t[i] }
42
+ asc_desc = { asc: sort.map { |i| i.asc.to_sql }.join(','), desc: sort.map { |i| i.desc.to_sql }.join(',') }
43
+ @sort_column = SortableTable::SortColumnCustomDefinition.new(@name, asc_desc)
44
+ when String
45
+ asc_desc = { asc: sort_options + ' ASC', desc: sort_options + ' DESC' }
46
+ @sort_column = SortableTable::SortColumnCustomDefinition.new(@name, asc_desc)
47
+ else
48
+ raise "Undefined `sort_options` type: #{sort_options.class.name}"
49
+ end
50
+ end
51
+
52
+ def sort?
53
+ @sort
54
+ end
55
+
56
+ def filter?
57
+ !!filter
58
+ end
59
+
60
+ def default?
61
+ !!@options[:default]
62
+ end
63
+
64
+ private
65
+
66
+ def format_value(_view, value, _entity)
67
+ value.to_s
68
+ end
69
+ end
70
+
71
+
72
+ class DecimalAttribute < Attribute
73
+ def format_value(view, value, entity)
74
+ view.format_price(value)
75
+ end
76
+ end
77
+
78
+ class EnumAttribute < Attribute
79
+ # TODO: @klass.name || @klass.base_class.name || entity.class.name
80
+ def format_value(view, value, entity)
81
+ view.t("#{@klass.name.underscore}.#{name.to_s.pluralize}.#{value}", format_options)
82
+ end
83
+ end
84
+
85
+ class LinkAttribute < Attribute
86
+ def format_value(view, value, entity)
87
+ view.link_to value.to_s, entity, format_options
88
+ end
89
+ end
90
+
91
+ class MailAttribute < Attribute
92
+ def format_value(view, value, entity)
93
+ view.mail_to value.to_s, value.to_s, format_options
94
+ end
95
+ end
96
+
97
+ class ReferenceAttribute < Attribute
98
+
99
+ def initialize(name, klass, options, formatter)
100
+ super
101
+ end
102
+
103
+ def title
104
+ @klass.human_attribute_name(@klass.reflect_on_association(name).foreign_key, @options[:i18n] || {})
105
+ end
106
+
107
+ def format_value(view, value, entity)
108
+ view.link_to value.to_s, value, format_options
109
+ end
110
+ end
111
+
112
+ class BooleanAttribute < Attribute
113
+ def format_value(view, value, entity)
114
+ if value.to_boolean
115
+ view.icon('true', view.t(:true))
116
+ else
117
+ view.icon('false', view.t(:false))
118
+ end
119
+ end
120
+ end
121
+
122
+ class DateAttribute < Attribute
123
+ def format_value(view, value, entity)
124
+ value && view.l(value.to_date, format_options)
125
+ end
126
+ end
127
+
128
+ class DateTimeAttribute < Attribute
129
+ def format_value(view, value, entity)
130
+ value && view.l(value, format_options)
131
+ end
132
+ end
133
+ class DatetimeAttribute < DateTimeAttribute
134
+ # alias
135
+ end
136
+ end
137
+ end