symphonia 2.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +16 -0
- data/Rakefile +44 -0
- data/app/assets/images/bg-checker.png +0 -0
- data/app/assets/images/bullet.gif +0 -0
- data/app/assets/images/close.png +0 -0
- data/app/assets/images/loading.gif +0 -0
- data/app/assets/images/next.png +0 -0
- data/app/assets/images/prev.png +0 -0
- data/app/assets/javascripts/ckeditor/plugins/autogrow/plugin.js +232 -0
- data/app/assets/javascripts/ckeditor/plugins/autogrow/samples/autogrow.html +102 -0
- data/app/assets/javascripts/ckeditor/plugins/image_chooser/icons/addimage.png +0 -0
- data/app/assets/javascripts/ckeditor/plugins/image_chooser/plugin.js +15 -0
- data/app/assets/javascripts/symphonia/Sortable.js +1249 -0
- data/app/assets/javascripts/symphonia/_core.js +45 -0
- data/app/assets/javascripts/symphonia/application.js.erb +147 -0
- data/app/assets/javascripts/symphonia/filters.js +44 -0
- data/app/assets/javascripts/symphonia/symphonia_bootstrap_dialog.js +136 -0
- data/app/assets/javascripts/symphonia/symphonia_ckeditor.js +55 -0
- data/app/assets/stylesheets/symphonia/application.css +4 -0
- data/app/assets/stylesheets/symphonia/basic.scss +218 -0
- data/app/assets/stylesheets/symphonia/filters.scss +19 -0
- data/app/assets/stylesheets/symphonia/symphonia_bootstrap.scss +56 -0
- data/app/channels/application_cable/channel.rb +5 -0
- data/app/controllers/symphonia/accounts_controller.rb +169 -0
- data/app/controllers/symphonia/admin_controller.rb +22 -0
- data/app/controllers/symphonia/api_controller.rb +64 -0
- data/app/controllers/symphonia/application_controller.rb +8 -0
- data/app/controllers/symphonia/attachments_controller.rb +37 -0
- data/app/controllers/symphonia/filters_controller.rb +23 -0
- data/app/controllers/symphonia/images_controller.rb +16 -0
- data/app/controllers/symphonia/login_controller.rb +80 -0
- data/app/controllers/symphonia/roles_controller.rb +100 -0
- data/app/controllers/symphonia/user_sessions_controller.rb +16 -0
- data/app/controllers/symphonia/users_controller.rb +168 -0
- data/app/helpers/symphonia/application_helper.rb +422 -0
- data/app/helpers/symphonia/bootstrap_modal_helper.rb +59 -0
- data/app/helpers/symphonia/form_helper.rb +50 -0
- data/app/helpers/symphonia/renderer_helper.rb +85 -0
- data/app/mailers/symphonia/application_mailer.rb +6 -0
- data/app/mailers/symphonia/notifier.rb +42 -0
- data/app/models/symphonia/admin_module.rb +18 -0
- data/app/models/symphonia/application_record.rb +14 -0
- data/app/models/symphonia/attachment.rb +16 -0
- data/app/models/symphonia/common_file.rb +9 -0
- data/app/models/symphonia/email_preference.rb +5 -0
- data/app/models/symphonia/image.rb +46 -0
- data/app/models/symphonia/preference.rb +12 -0
- data/app/models/symphonia/role.rb +55 -0
- data/app/models/symphonia/swagger/error_model.rb +19 -0
- data/app/models/symphonia/swagger/responses.rb +27 -0
- data/app/models/symphonia/user.rb +141 -0
- data/app/models/symphonia/user_session.rb +19 -0
- data/app/views/common/403.html.erb +5 -0
- data/app/views/common/404.html.erb +2 -0
- data/app/views/layouts/symphonia/_modal.html.erb +19 -0
- data/app/views/layouts/symphonia/_query.html.erb +51 -0
- data/app/views/layouts/symphonia/application.html.erb +45 -0
- data/app/views/layouts/symphonia/application.pdf.erb +15 -0
- data/app/views/layouts/symphonia/mailer.html.erb +13 -0
- data/app/views/symphonia/accounts/_detail.html.erb +65 -0
- data/app/views/symphonia/accounts/_form.html.erb +14 -0
- data/app/views/symphonia/accounts/edit.html.erb +9 -0
- data/app/views/symphonia/accounts/edit.js.erb +5 -0
- data/app/views/symphonia/accounts/lost_password.html.erb +6 -0
- data/app/views/symphonia/accounts/lost_password.js.erb +3 -0
- data/app/views/symphonia/accounts/new_activation.html.erb +11 -0
- data/app/views/symphonia/accounts/new_activation.js.erb +6 -0
- data/app/views/symphonia/accounts/register.html.erb +20 -0
- data/app/views/symphonia/accounts/reset_password.html.erb +18 -0
- data/app/views/symphonia/accounts/update.js.erb +1 -0
- data/app/views/symphonia/admin/index.html.erb +15 -0
- data/app/views/symphonia/attachments/destroy.js.erb +1 -0
- data/app/views/symphonia/common/_editable_images_grid.html.erb +12 -0
- data/app/views/symphonia/common/_filters.html.erb +23 -0
- data/app/views/symphonia/common/_locale_chooser.html.erb +16 -0
- data/app/views/symphonia/common/_share_links.html.erb +5 -0
- data/app/views/symphonia/filters/options.html.erb +36 -0
- data/app/views/symphonia/filters/options.js.erb +9 -0
- data/app/views/symphonia/filters/table.html.erb +21 -0
- data/app/views/symphonia/login/_form.html.erb +19 -0
- data/app/views/symphonia/login/new.html.erb +11 -0
- data/app/views/symphonia/login_sessions/new.html.erb +1 -0
- data/app/views/symphonia/notifier/activation_user.html.erb +7 -0
- data/app/views/symphonia/notifier/activation_user.text.erb +3 -0
- data/app/views/symphonia/notifier/reset_password_user.html.erb +7 -0
- data/app/views/symphonia/notifier/reset_password_user.text.erb +3 -0
- data/app/views/symphonia/notifier/test_mail.html.erb +2 -0
- data/app/views/symphonia/notifier/test_mail.text.erb +3 -0
- data/app/views/symphonia/notifier/user_change_to_active.html.erb +3 -0
- data/app/views/symphonia/notifier/user_change_to_active.text.erb +1 -0
- data/app/views/symphonia/notifier/user_registered.html.erb +13 -0
- data/app/views/symphonia/notifier/user_registered.text.erb +8 -0
- data/app/views/symphonia/roles/_form.html.erb +30 -0
- data/app/views/symphonia/roles/edit.html.erb +5 -0
- data/app/views/symphonia/roles/index.html.erb +6 -0
- data/app/views/symphonia/roles/new.html.erb +4 -0
- data/app/views/symphonia/roles/show.html.erb +5 -0
- data/app/views/symphonia/users/_form.html.erb +13 -0
- data/app/views/symphonia/users/edit.html.erb +26 -0
- data/app/views/symphonia/users/edit.js.erb +3 -0
- data/app/views/symphonia/users/edit_current.html.erb +7 -0
- data/app/views/symphonia/users/index.html.erb +5 -0
- data/app/views/symphonia/users/new.html.erb +8 -0
- data/app/views/symphonia/users/show.html.erb +63 -0
- data/config/locales/cs.yml +233 -0
- data/config/locales/en.yml +47 -0
- data/config/routes.rb +52 -0
- data/db/migrate/20130714140500_create_users.rb +49 -0
- data/db/migrate/20130714140501_create_roles.rb +16 -0
- data/db/migrate/20130714140502_create_preferences.rb +26 -0
- data/db/migrate/20130828175114_create_attachments.rb +20 -0
- data/db/migrate/20141213204351_create_admin_modules.rb +20 -0
- data/db/seeds.rb +12 -0
- data/lib/generators/symphonia/entity_controller/entity_controller_generator.rb +48 -0
- data/lib/generators/symphonia/entity_controller/templates/controller.rb +100 -0
- data/lib/generators/symphonia/query/query_generator.rb +37 -0
- data/lib/generators/symphonia/setup/setup_generator.rb +52 -0
- data/lib/generators/symphonia/setup/templates/404.html +26 -0
- data/lib/generators/symphonia/setup/templates/500.html +37 -0
- data/lib/generators/symphonia/setup/templates/Gemfile +18 -0
- data/lib/generators/symphonia/setup/templates/base_layout.html.erb +46 -0
- data/lib/generators/symphonia/setup/templates/design.scss +4 -0
- data/lib/generators/symphonia/setup/templates/settings.rb +65 -0
- data/lib/generators/symphonia/setup/templates/spec_helper.rb +18 -0
- data/lib/symphonia/action_cable/connection.rb +31 -0
- data/lib/symphonia/admin_constraint.rb +9 -0
- data/lib/symphonia/attachable.rb +35 -0
- data/lib/symphonia/base_controller.rb +96 -0
- data/lib/symphonia/bootstrap_link_render.rb +69 -0
- data/lib/symphonia/controller_extensions.rb +200 -0
- data/lib/symphonia/engine.rb +137 -0
- data/lib/symphonia/form_builder.rb +137 -0
- data/lib/symphonia/menu_manager.rb +23 -0
- data/lib/symphonia/model_attributes/attribute.rb +137 -0
- data/lib/symphonia/model_attributes.rb +102 -0
- data/lib/symphonia/model_filters/base.rb +82 -0
- data/lib/symphonia/model_filters/boolean_filter.rb +26 -0
- data/lib/symphonia/model_filters/date_filter.rb +81 -0
- data/lib/symphonia/model_filters/integer_filter.rb +18 -0
- data/lib/symphonia/model_filters/select_filter.rb +48 -0
- data/lib/symphonia/model_filters/string_filter.rb +18 -0
- data/lib/symphonia/model_filters.rb +10 -0
- data/lib/symphonia/object.rb +31 -0
- data/lib/symphonia/permissions.rb +93 -0
- data/lib/symphonia/query.rb +275 -0
- data/lib/symphonia/query_columns/attribute_column.rb +43 -0
- data/lib/symphonia/query_columns/generic_column.rb +165 -0
- data/lib/symphonia/query_columns.rb +8 -0
- data/lib/symphonia/spec_helper.rb +4 -0
- data/lib/symphonia/user_management.rb +58 -0
- data/lib/symphonia/version.rb +4 -0
- data/lib/symphonia.rb +20 -0
- data/spec/controllers/account_controller_spec.rb +90 -0
- data/spec/controllers/admin_controller_spec.rb +35 -0
- data/spec/controllers/api_controller_spec.rb +9 -0
- data/spec/controllers/filters_controller_spec.rb +35 -0
- data/spec/controllers/images_controller_spec.rb +5 -0
- data/spec/controllers/login_controller_spec.rb +20 -0
- data/spec/controllers/roles_controller_spec.rb +12 -0
- data/spec/controllers/users_controller_spec.rb +47 -0
- data/spec/factories/factories.rb +52 -0
- data/spec/helpers/symphonia/application_helper_spec.rb +62 -0
- data/spec/mailers/previews/symphonia/notifier_preview.rb +27 -0
- data/spec/mailers/symphonia/notifier_spec.rb +76 -0
- data/spec/models/attachment_spec.rb +22 -0
- data/spec/models/query/attribute_spec.rb +8 -0
- data/spec/models/query/symphonia_query_spec.rb +70 -0
- data/spec/models/role_spec.rb +13 -0
- data/spec/models/user_spec.rb +10 -0
- data/spec/rails_helper.rb +13 -0
- data/spec/requests/accounts_spec.rb +118 -0
- data/spec/requests/attachments_controller_spec.rb +23 -0
- data/spec/requests/login_spec.rb +26 -0
- data/spec/requests/roles_spec.rb +10 -0
- data/spec/requests/users_spec.rb +50 -0
- data/spec/spec_helper.rb +101 -0
- data/spec/support/common_file.txt +2 -0
- data/spec/support/query.rb +36 -0
- data/spec/support/shared.rb +62 -0
- data/spec/support/shared_controllers.rb +31 -0
- data/spec/support/stub_users.rb +32 -0
- data/spec/support/symphonia.jpg +0 -0
- data/spec/support/wait_for_ajax.rb +15 -0
- data/spec/version_spec.rb +5 -0
- data/spec/views/filters/options.html.erb_spec.rb +14 -0
- 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
|