tramway 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/MIT-LICENSE +20 -0
- data/README.md +889 -15
- data/Rakefile +8 -8
- data/app/assets/config/tramway_core_manifest.js +2 -0
- data/app/assets/images/tramway/mona_lisa_from_prado.jpg +0 -0
- data/app/assets/images/tramway/mona_lisa_from_prado_square.jpg +0 -0
- data/app/assets/javascripts/bootstrap-datepicker-1.8.0.js +2035 -0
- data/app/assets/javascripts/bootstrap-datepicker-1.8.0.ru.min.js +64 -0
- data/app/assets/javascripts/ckeditor/config.js +30 -0
- data/app/assets/javascripts/ckeditor/plugins/image/dialogs/image.js +1259 -0
- data/app/assets/javascripts/ckeditor/plugins/image/icons/hidpi/image.png +0 -0
- data/app/assets/javascripts/ckeditor/plugins/image/icons/image.png +0 -0
- data/app/assets/javascripts/ckeditor/plugins/image/images/noimage.png +0 -0
- data/app/assets/javascripts/ckeditor/plugins/image/lang/en.js +25 -0
- data/app/assets/javascripts/ckeditor/plugins/image/lang/ru.js +25 -0
- data/app/assets/javascripts/ckeditor/plugins/image/plugin.js +184 -0
- data/app/assets/javascripts/ckeditor/plugins/youtube/images/icon-hdpi.png +0 -0
- data/app/assets/javascripts/ckeditor/plugins/youtube/images/icon.png +0 -0
- data/app/assets/javascripts/ckeditor/plugins/youtube/lang/en.js +25 -0
- data/app/assets/javascripts/ckeditor/plugins/youtube/lang/ru.js +25 -0
- data/app/assets/javascripts/ckeditor/plugins/youtube/plugin.js +449 -0
- data/app/assets/javascripts/tramway/application.js +60 -0
- data/app/assets/stylesheets/tramway/application.sass +60 -0
- data/app/assets/stylesheets/tramway/bootstrap-datepicker-1.8.0.css +477 -0
- data/app/controllers/concerns/auth_management.rb +26 -0
- data/app/controllers/concerns/filtering.rb +43 -0
- data/app/controllers/tramway/application_controller.rb +142 -0
- data/app/controllers/tramway/export/application_controller.rb +5 -0
- data/app/controllers/tramway/has_and_belongs_to_many_records_controller.rb +26 -0
- data/app/controllers/tramway/records_controller.rb +86 -0
- data/app/controllers/tramway/sessions_controller.rb +49 -0
- data/app/controllers/tramway/singletons_controller.rb +48 -0
- data/app/controllers/tramway/welcome_controller.rb +17 -0
- data/app/decorators/tramway/application_decorated_collection.rb +15 -0
- data/app/decorators/tramway/application_decorator.rb +124 -0
- data/app/decorators/tramway/associations/class_helper.rb +45 -0
- data/app/decorators/tramway/associations/object_helper.rb +58 -0
- data/app/decorators/tramway/attributes/view_helper.rb +30 -0
- data/app/decorators/tramway/concerns/attributes_decorator_helper.rb +97 -0
- data/app/decorators/tramway/concerns/table_builder.rb +33 -0
- data/app/decorators/tramway/default/values_helper.rb +23 -0
- data/app/decorators/tramway/delegating/class_helper.rb +9 -0
- data/app/decorators/tramway/user_decorator.rb +49 -0
- data/app/forms/admin/tramway/user_form.rb +24 -0
- data/app/forms/tramway/application_form.rb +124 -0
- data/app/forms/tramway/application_forms/association_class_helpers.rb +7 -0
- data/app/forms/tramway/application_forms/association_object_helpers.rb +36 -0
- data/app/forms/tramway/application_forms/constant_class_actions.rb +7 -0
- data/app/forms/tramway/application_forms/constant_object_actions.rb +20 -0
- data/app/forms/tramway/application_forms/frontend.rb +12 -0
- data/app/forms/tramway/application_forms/object_helpers.rb +15 -0
- data/app/forms/tramway/application_forms/properties_object_helper.rb +16 -0
- data/app/forms/tramway/application_forms/submit_helper.rb +26 -0
- data/app/forms/tramway/extendable_form.rb +15 -0
- data/app/forms/tramway/extendable_forms_helpers/class_builder.rb +34 -0
- data/app/forms/tramway/extendable_forms_helpers/ignored_properties_helper.rb +11 -0
- data/app/forms/tramway/extendable_forms_helpers/more_properties_helper.rb +31 -0
- data/app/forms/tramway/extendable_forms_helpers/properties_helper.rb +16 -0
- data/app/forms/tramway/extendable_forms_helpers/submit/class_helpers.rb +18 -0
- data/app/forms/tramway/extendable_forms_helpers/submit/object_helpers.rb +21 -0
- data/app/forms/tramway/extendable_forms_helpers/validators.rb +40 -0
- data/app/forms/tramway/extended_application_form.rb +23 -0
- data/app/forms/tramway/form_creator.rb +7 -0
- data/app/forms/tramway/session_form.rb +26 -0
- data/app/helpers/tramway/actions_helper.rb +45 -0
- data/app/helpers/tramway/additional_buttons_builder.rb +12 -0
- data/app/helpers/tramway/application_helper.rb +27 -0
- data/app/helpers/tramway/cases_helper.rb +13 -0
- data/app/helpers/tramway/copy_to_clipboard_helper.rb +11 -0
- data/app/helpers/tramway/focus_generator_helper.rb +10 -0
- data/app/helpers/tramway/frontend_helper.rb +26 -0
- data/app/helpers/tramway/inputs/associations_helper.rb +30 -0
- data/app/helpers/tramway/inputs/polymorphic_associations_helper.rb +24 -0
- data/app/helpers/tramway/inputs_helper.rb +96 -0
- data/app/helpers/tramway/model_helper.rb +7 -0
- data/app/helpers/tramway/navbar_helper.rb +11 -0
- data/app/helpers/tramway/records_helper.rb +120 -0
- data/app/helpers/tramway/russian_cases_helper.rb +26 -0
- data/app/helpers/tramway/singleton_helper.rb +12 -0
- data/app/helpers/tramway/state_machine_buttons_helper.rb +61 -0
- data/app/helpers/tramway/title_helper.rb +25 -0
- data/app/inputs/date_picker_input.rb +4 -0
- data/app/inputs/multiple_file_input.rb +7 -0
- data/app/models/tramway/application_record.rb +60 -0
- data/app/models/tramway/user.rb +23 -0
- data/app/uploaders/application_uploader.rb +22 -0
- data/app/uploaders/file_uploader.rb +4 -0
- data/app/uploaders/ico_uploader.rb +7 -0
- data/app/uploaders/image_defaults.rb +14 -0
- data/app/uploaders/photo_uploader.rb +54 -0
- data/app/views/layouts/tramway/application.html.haml +32 -0
- data/app/views/layouts/tramway/shared/_navbar.html.haml +46 -0
- data/app/views/tramway/404.haml +1 -0
- data/app/views/tramway/records/_form.html.haml +22 -0
- data/app/views/tramway/records/_list.html.haml +38 -0
- data/app/views/tramway/records/_search.html.haml +34 -0
- data/app/views/tramway/records/edit.html.haml +1 -0
- data/app/views/tramway/records/index.html.haml +31 -0
- data/app/views/tramway/records/new.html.haml +1 -0
- data/app/views/tramway/records/show.html.haml +1 -0
- data/app/views/tramway/sessions/new.html.haml +9 -0
- data/app/views/tramway/shared/_input.html.haml +34 -0
- data/app/views/tramway/shared/_input_extended.html.haml +14 -0
- data/app/views/tramway/shared/_messages.html.haml +10 -0
- data/app/views/tramway/shared/_show.html.haml +35 -0
- data/app/views/tramway/shared/errors/server_error.html.haml +12 -0
- data/app/views/tramway/shared/input_extended_types/_checkbox.html.haml +1 -0
- data/app/views/tramway/shared/input_extended_types/_select.html.haml +16 -0
- data/app/views/tramway/shared/input_extended_types/_simple.html.haml +4 -0
- data/app/views/tramway/shared/input_extended_types/_yes_no.html.haml +4 -0
- data/app/views/tramway/shared/show/_attribute_tr.html.haml +9 -0
- data/app/views/tramway/shared/show/associations/_habtm_row.html.haml +14 -0
- data/app/views/tramway/shared/show/associations/_list.html.haml +21 -0
- data/app/views/tramway/shared/show/associations/_row.html.haml +19 -0
- data/app/views/tramway/shared/show/associations/_table_row.html.haml +21 -0
- data/app/views/tramway/singletons/_form.html.haml +15 -0
- data/app/views/tramway/singletons/edit.html.haml +1 -0
- data/app/views/tramway/singletons/new.html.haml +1 -0
- data/app/views/tramway/singletons/show.html.haml +1 -0
- data/app/views/tramway/welcome/index.html.haml +4 -0
- data/config/initializers/assets.rb +7 -0
- data/config/initializers/carrierwave.rb +5 -0
- data/config/initializers/ckeditor.rb +9 -0
- data/config/initializers/plurals.rb +25 -0
- data/config/locales/en/collections.yml +4 -0
- data/config/locales/en/date.yml +16 -0
- data/config/locales/en/dates.yml +10 -0
- data/config/locales/en/helpers.yml +26 -0
- data/config/locales/en/locale.yml +11 -0
- data/config/locales/en/messages.yml +7 -0
- data/config/locales/en/models.yml +9 -0
- data/config/locales/en/simple_form_extension.yml +8 -0
- data/config/locales/en/state_machines.yml +8 -0
- data/config/locales/ru/collections.yml +4 -0
- data/config/locales/ru/date.yml +16 -0
- data/config/locales/ru/dates.yml +10 -0
- data/config/locales/ru/helpers.yml +30 -0
- data/config/locales/ru/locale.yml +6 -0
- data/config/locales/ru/messages.yml +7 -0
- data/config/locales/ru/models.yml +21 -0
- data/config/locales/ru/simple_form_extension.yml +8 -0
- data/config/locales/ru/state_machines.yml +8 -0
- data/config/routes.rb +13 -0
- data/lib/string.rb +18 -0
- data/lib/tramway/application.rb +10 -0
- data/lib/tramway/class_name_helpers.rb +15 -0
- data/lib/tramway/collection.rb +9 -0
- data/lib/tramway/collections/helper.rb +21 -0
- data/lib/tramway/collections.rb +4 -0
- data/lib/tramway/engine.rb +14 -0
- data/lib/tramway/error.rb +32 -0
- data/lib/tramway/forms.rb +5 -0
- data/lib/tramway/generators/install_generator.rb +49 -0
- data/lib/tramway/generators/model_generator.rb +105 -0
- data/lib/tramway/generators/templates/create_tramway_users.rb +18 -0
- data/lib/tramway/generators/templates/decorator.rb.erb +56 -0
- data/lib/tramway/generators/templates/form.rb.erb +22 -0
- data/lib/tramway/generators/templates/initializers/simple_form.rb +23 -0
- data/lib/tramway/generators/templates/initializers/simple_form_bootstrap.rb +133 -0
- data/lib/tramway/generators.rb +4 -0
- data/lib/tramway/navbar.rb +44 -0
- data/lib/tramway/notifications.rb +12 -0
- data/lib/tramway/record_routes_helper.rb +23 -0
- data/lib/tramway/records_models.rb +52 -0
- data/lib/tramway/singleton_models.rb +32 -0
- data/lib/tramway/spec/helpers/navbar_helper.rb +7 -0
- data/lib/tramway/spec/helpers/tramway_helpers.rb +47 -0
- data/lib/tramway/version.rb +3 -1
- data/lib/tramway/welcome_page_actions.rb +5 -0
- data/lib/tramway/yaml/errors.yml +49 -0
- data/lib/tramway.rb +143 -2
- data/lib/validators/presence_validator.rb +9 -0
- metadata +582 -25
- data/.gitignore +0 -9
- data/.travis.yml +0 -5
- data/Gemfile +0 -6
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/tramway.gemspec +0 -26
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::ApplicationHelper
|
4
|
+
include FontAwesome5::Rails::IconHelper
|
5
|
+
include SmartButtons
|
6
|
+
include Tramway::AuthManagement
|
7
|
+
|
8
|
+
helpers = Dir["#{Tramway.root}/app/helpers/tramway/*_helper.rb"]
|
9
|
+
helpers.each do |helper|
|
10
|
+
module_name = helper.split('/')[-2..].join('/')[0..-4].camelize.constantize
|
11
|
+
|
12
|
+
include module_name unless Tramway::ApplicationHelper
|
13
|
+
end
|
14
|
+
|
15
|
+
def object_type(object)
|
16
|
+
object_class_name = if object.class.ancestors.include? ::Tramway::ApplicationDecorator
|
17
|
+
object.class.model_class.name
|
18
|
+
else
|
19
|
+
object.class.name
|
20
|
+
end
|
21
|
+
if Tramway.available_models_for(@application_engine || @application.name).map(&:to_s).include?(object_class_name)
|
22
|
+
:record
|
23
|
+
else
|
24
|
+
:singleton
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::CasesHelper
|
4
|
+
def plural(word)
|
5
|
+
if I18n.locale == :ru
|
6
|
+
russian_plural word
|
7
|
+
elsif word.respond_to?(:model_name)
|
8
|
+
word.model_name.human.pluralize(I18n.locale)
|
9
|
+
else
|
10
|
+
word.human.pluralize(I18n.locale)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::CopyToClipboardHelper
|
4
|
+
def copy_to_clipboard(id)
|
5
|
+
button_tag class: 'btn btn-info clipboard-btn',
|
6
|
+
data: { clipboard_action: 'copy', clipboard_target: "##{id}" },
|
7
|
+
style: 'margin-left: 15px' do
|
8
|
+
fa_icon 'copy'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::FrontendHelper
|
4
|
+
def react_params(form, action, method)
|
5
|
+
form.properties.each_with_object({ action: react_params_url(form, action), method: method,
|
6
|
+
authenticity_token: form_authenticity_token }) do |property, hash|
|
7
|
+
case property[1]
|
8
|
+
when :association
|
9
|
+
hash.merge!(
|
10
|
+
property[0] => {
|
11
|
+
collection: build_collection_for_association(form, property[0])
|
12
|
+
}
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end.merge model: form.model.attributes
|
16
|
+
end
|
17
|
+
|
18
|
+
def react_params_url(form, action)
|
19
|
+
case action
|
20
|
+
when :create
|
21
|
+
Tramway::Engine.routes.url_helpers.records_path(model: form.model.class)
|
22
|
+
else
|
23
|
+
Tramway::Engine.routes.url_helpers.record_path(form.model.id, model: form.model.class)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Inputs::AssociationsHelper
|
4
|
+
def build_collection_for_association(form_object, property)
|
5
|
+
full_class_name_association = form_object.class.full_class_name_association(property)
|
6
|
+
check_valid_association full_class_name_association
|
7
|
+
full_class_name_association.send("#{current_user.role}_scope", current_user.id).map do |obj|
|
8
|
+
decorator_class(full_class_name_association).decorate obj
|
9
|
+
end.sort_by do |association|
|
10
|
+
association.name || "#{association.class.name} ##{association.id}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_value_for_association(form_object, property, value)
|
15
|
+
form_object.send(property) || form_object.model.send("#{property}_id") || value
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_valid_association(full_class_name_association)
|
19
|
+
unless full_class_name_association
|
20
|
+
Tramway::Error.raise_error(
|
21
|
+
:tramway, :inputs_helpers, :association_params, :defined_with_property_method, property: property
|
22
|
+
)
|
23
|
+
end
|
24
|
+
return unless full_class_name_association.is_a? Array
|
25
|
+
|
26
|
+
Tramway::Error.raise_error(
|
27
|
+
:tramway, :inputs_helpers, :association_params, :used_polymorphic_association, property: property
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::Inputs::PolymorphicAssociationsHelper
|
4
|
+
def build_collection_for_polymorphic_association(form_object, property)
|
5
|
+
object_names = full_class_names(form_object, property).map do |class_name|
|
6
|
+
class_name.send("#{current_user.role}_scope", current_user.id).map do |obj|
|
7
|
+
decorator_class(class_name).decorate obj
|
8
|
+
end
|
9
|
+
end.flatten
|
10
|
+
object_names.sort_by { |obj| obj.name.to_s }
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_value_for_polymorphic_association(form_object, property, value)
|
14
|
+
if form_object.send(property).present?
|
15
|
+
"#{form_object.send(property).class.to_s.underscore}_#{form_object.send(property).id}"
|
16
|
+
elsif value[:type].present? && value[:id].present?
|
17
|
+
"#{value[:type]&.underscore}_#{value[:id]}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def full_class_names(form_object, property)
|
22
|
+
form_object.model.class.send("#{property}_type").values.map(&:constantize)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::InputsHelper
|
4
|
+
include Tramway::Inputs::AssociationsHelper
|
5
|
+
include Tramway::Inputs::PolymorphicAssociationsHelper
|
6
|
+
|
7
|
+
def association_params(form_object:, property:, value:, object:, options: {})
|
8
|
+
full_class_name_association = form_object.class.full_class_name_association(property)
|
9
|
+
|
10
|
+
value = current_user&.id if full_class_name_association.to_s == 'Tramway::User'
|
11
|
+
|
12
|
+
build_input_attributes(object: object, property: property, options: options,
|
13
|
+
value: build_value_for_association(form_object, property, value),
|
14
|
+
collection: build_collection_for_association(form_object, property),
|
15
|
+
include_blank: true,
|
16
|
+
selected: form_object.model.send("#{property}_id") || value)
|
17
|
+
end
|
18
|
+
|
19
|
+
def polymorphic_association_params(object:, form_object:, property:, value:, options: {})
|
20
|
+
build_input_attributes object: object, property: property,
|
21
|
+
selected: build_value_for_polymorphic_association(form_object, property, value),
|
22
|
+
value: build_value_for_polymorphic_association(form_object, property, value),
|
23
|
+
collection: build_collection_for_polymorphic_association(form_object, property),
|
24
|
+
options: options.merge(
|
25
|
+
as: :select,
|
26
|
+
include_blank: true,
|
27
|
+
label_method: ->(obj) { "#{obj.class.model_name.human} | #{obj.name}" },
|
28
|
+
value_method: lambda { |obj|
|
29
|
+
"#{obj.class.to_s.underscore.sub(/_decorator$/, '')}_#{obj.id}"
|
30
|
+
}
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_input_attributes(**options)
|
35
|
+
{
|
36
|
+
label: false,
|
37
|
+
input_html: {
|
38
|
+
name: "#{options[:object]}[#{options[:property]}]",
|
39
|
+
id: "#{options[:object]}_#{options[:property]}",
|
40
|
+
value: options[:value]
|
41
|
+
},
|
42
|
+
selected: options[:selected],
|
43
|
+
collection: options[:collection]
|
44
|
+
}.merge options[:options]
|
45
|
+
end
|
46
|
+
|
47
|
+
def value_from_params(model_class:, property:, type:)
|
48
|
+
case type
|
49
|
+
when :polymorphic_association, 'polymorphic_association'
|
50
|
+
{
|
51
|
+
id: params.dig(model_class.to_s.underscore, property.to_s),
|
52
|
+
type: params.dig(model_class.to_s.underscore, "#{property}_type")
|
53
|
+
}
|
54
|
+
else
|
55
|
+
params.dig(model_class.to_s.underscore, property.to_s)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_params(property:, object:, form_object:, value:, options: {})
|
60
|
+
{
|
61
|
+
label: false,
|
62
|
+
input_html: {
|
63
|
+
name: "#{object}[#{property}]",
|
64
|
+
id: "#{object}_#{property}",
|
65
|
+
value: (form_object.send(property) || form_object.model.send(property) || value)
|
66
|
+
},
|
67
|
+
selected: (form_object.model.send(property) || value)
|
68
|
+
}.merge options
|
69
|
+
end
|
70
|
+
|
71
|
+
def simple_params(**options)
|
72
|
+
builded_options = { as: options[:type], label: false,
|
73
|
+
input_html: {
|
74
|
+
name: "#{options[:object]}[#{options[:property]}]",
|
75
|
+
id: "#{options[:object]}_#{options[:property]}",
|
76
|
+
value: build_simple_value(
|
77
|
+
*options.values_at(:form_object, :property, :value),
|
78
|
+
options.dig(:options, :input_html, :value)
|
79
|
+
)
|
80
|
+
} }
|
81
|
+
merge_with_user_options builded_options, options
|
82
|
+
end
|
83
|
+
|
84
|
+
def build_simple_value(form_object, property, value, input_html_value)
|
85
|
+
value_to_add = input_html_value || value
|
86
|
+
value_to_add || form_object.send(property)
|
87
|
+
end
|
88
|
+
|
89
|
+
def merge_with_user_options(builded_options, options)
|
90
|
+
if options[:options].present?
|
91
|
+
options[:options][:input_html]&.delete(:value)
|
92
|
+
builded_options.merge!(options) || {}
|
93
|
+
end
|
94
|
+
builded_options
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::RecordsHelper
|
4
|
+
# FIXME: replace to module
|
5
|
+
def current_model_record_path(*args, **options)
|
6
|
+
record_path args, options.merge(model: params[:model])
|
7
|
+
end
|
8
|
+
|
9
|
+
def edit_current_model_record_path(*args, **options)
|
10
|
+
edit_record_path args, options.merge(model: params[:model])
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_current_model_record_path(*args, **options)
|
14
|
+
new_record_path args, options.merge(model: params[:model])
|
15
|
+
end
|
16
|
+
|
17
|
+
def current_model_records_path(*args, **options)
|
18
|
+
records_path args, options.merge(model: params[:model])
|
19
|
+
end
|
20
|
+
|
21
|
+
def public_path(record)
|
22
|
+
record.public_path || try("#{record.class.name.underscore.gsub('/', '_')}_path", record)
|
23
|
+
end
|
24
|
+
|
25
|
+
def model_class
|
26
|
+
params[:model].constantize
|
27
|
+
end
|
28
|
+
|
29
|
+
def decorator_class(model_name = nil)
|
30
|
+
"#{model_name || model_class}Decorator".constantize
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_path(constant)
|
34
|
+
constant.name.underscore.gsub '/', '_'
|
35
|
+
end
|
36
|
+
|
37
|
+
def search_tab_title(count)
|
38
|
+
"#{t('helpers.scope.found')} / #{count}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def searchable_model?(model_class)
|
42
|
+
model_class.methods.include? :full_text_search
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_options_for_select(name, collection)
|
46
|
+
selected_value = params[:list_filters].present? ? params[:list_filters][name] : nil
|
47
|
+
options_for_select(collection, selected_value)
|
48
|
+
end
|
49
|
+
|
50
|
+
def index_path_of_model(model_class, tab, filter)
|
51
|
+
if tab
|
52
|
+
records_path model: model_class, filter: filter, scope: tab
|
53
|
+
else
|
54
|
+
records_path model: model_class, filter: filter
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def collection_human_name(model_name:, collection_name:)
|
59
|
+
if t("default.collections.#{collection_name}").include?('<span')
|
60
|
+
t("collections.#{model_name}.#{collection_name}").pluralize(:ru)
|
61
|
+
else
|
62
|
+
t("default.collections.#{collection_name}")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def tab_title(model_class, tab, count, _state_method = :state)
|
67
|
+
model = model_class.name.underscore
|
68
|
+
name = collection_human_name model_name: model, collection_name: tab
|
69
|
+
"#{name} / #{count}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def active_tab(tab, index)
|
73
|
+
return :active if params[:scope].nil? && index.zero?
|
74
|
+
return :active if params[:search].nil? && params[:scope].to_s == tab.to_s
|
75
|
+
end
|
76
|
+
|
77
|
+
def new_associated_record_path(object:, association:, as:)
|
78
|
+
unless association.options[:class_name].present?
|
79
|
+
raise "You should set `class_name` for #{association.name} association"
|
80
|
+
end
|
81
|
+
|
82
|
+
new_record_path(**new_record_path_options(object, association, as))
|
83
|
+
end
|
84
|
+
|
85
|
+
def new_record_path_options(object, association, as)
|
86
|
+
hash = {
|
87
|
+
model: association.class_name,
|
88
|
+
redirect: current_model_record_path(object.model)
|
89
|
+
}
|
90
|
+
|
91
|
+
if association.options[:as].present? # polymorphic? conditiion
|
92
|
+
hash.merge! options_for_polymorphic_link object, association
|
93
|
+
else
|
94
|
+
hash.merge! options_for_isomorphic_link object, association, as
|
95
|
+
end
|
96
|
+
|
97
|
+
hash
|
98
|
+
end
|
99
|
+
|
100
|
+
def options_for_polymorphic_link(object, association)
|
101
|
+
{
|
102
|
+
association.options[:class_name].underscore => {
|
103
|
+
association.options[:as] => object.id,
|
104
|
+
association.type => object.class.model_name
|
105
|
+
}
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
def options_for_isomorphic_link(object, association, as)
|
110
|
+
{
|
111
|
+
association.options[:class_name].underscore => {
|
112
|
+
as || object.model.class.name.underscore.gsub('/', '_') => object.id
|
113
|
+
}
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def there_any_filters?(model_class)
|
118
|
+
decorator_class(model_class).list_filters&.any?
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::RussianCasesHelper
|
4
|
+
def case_word(model_name, case_name)
|
5
|
+
word_case = I18n.t("cases.#{model_name.name.underscore}.#{case_name}")
|
6
|
+
return word_case if word_case.present?
|
7
|
+
|
8
|
+
raise "There is not #{case_name} implementation for \"#{model_name}\""
|
9
|
+
end
|
10
|
+
|
11
|
+
def genitive(word)
|
12
|
+
case_word word, :genitive
|
13
|
+
end
|
14
|
+
|
15
|
+
def instrumental(word)
|
16
|
+
case_word word, :instrumental
|
17
|
+
end
|
18
|
+
|
19
|
+
def dative(word)
|
20
|
+
case_word word, :dative
|
21
|
+
end
|
22
|
+
|
23
|
+
def russian_plural(word)
|
24
|
+
case_word word, :plural
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::SingletonHelper
|
4
|
+
# FIXME: replace to module
|
5
|
+
def current_model_singleton_path(*args, **options)
|
6
|
+
singleton_path args, options.merge(model: params[:model])
|
7
|
+
end
|
8
|
+
|
9
|
+
def edit_current_model_singleton_path(*args, **options)
|
10
|
+
edit_singleton_path args, options.merge(model: params[:model])
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::StateMachineButtonsHelper
|
4
|
+
def state_events_buttons(object, **options)
|
5
|
+
options.each do |(key, value)|
|
6
|
+
define_singleton_method(key) { value }
|
7
|
+
end
|
8
|
+
content_tag(:div, class: 'btn-group-vertical') do
|
9
|
+
transitions(object, state_method, options[:without]).each do |event|
|
10
|
+
button(
|
11
|
+
object,
|
12
|
+
event: event[:event],
|
13
|
+
model_name: object.class.model_name.name.underscore,
|
14
|
+
form_options: button_options,
|
15
|
+
**options
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def excepted_actions(without)
|
24
|
+
return unless without
|
25
|
+
|
26
|
+
without.is_a?(Array) ? without.map(&:to_sym) : [without.to_sym]
|
27
|
+
end
|
28
|
+
|
29
|
+
def transitions(object, state_method, without)
|
30
|
+
object.model.aasm(state_method).permitted_transitions.reject do |t|
|
31
|
+
excepted_actions(without).present? && excepted_actions(without).include?(t[:event])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def button(object, **options)
|
36
|
+
event = options[:event]
|
37
|
+
|
38
|
+
concat(
|
39
|
+
patch_button(patch_button_options(object, event, options)) do
|
40
|
+
model = object.model
|
41
|
+
class_name = model.class.name.underscore
|
42
|
+
actual_event = model.aasm(options[:state_method]).events.select { |ev| ev.name == event }.first.name
|
43
|
+
I18n.t("state_machines.#{class_name}.#{options[:state_method]}.events.#{actual_event}")
|
44
|
+
end
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def patch_button_options(object, event, options)
|
49
|
+
attributes = { aasm_event: event }
|
50
|
+
css_class = "btn btn-sm btn-xs btn-#{object.public_send("#{options[:state_method]}_button_color", event)}"
|
51
|
+
|
52
|
+
{
|
53
|
+
record: object.model,
|
54
|
+
attributes: attributes,
|
55
|
+
model_name: options[:model_name],
|
56
|
+
button_options: { class: css_class },
|
57
|
+
form_options: options[:form_options],
|
58
|
+
url: Tramway::Engine.routes.url_helpers.record_path(object.id, options[:parameters])
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tramway::TitleHelper
|
4
|
+
def title(page_title = default_title)
|
5
|
+
@application ||= Tramway.application&.model_class&.first || Tramway.application
|
6
|
+
if @application.present?
|
7
|
+
title_text = "#{page_title} | #{@application.try(:title) || @application.public_name}"
|
8
|
+
content_for(:title) { title_text }
|
9
|
+
else
|
10
|
+
Tramway::Error.raise_error(:tramway, :title_helper, :title, :you_should_set_tramway_core_application)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def default_title
|
15
|
+
t('.title')
|
16
|
+
end
|
17
|
+
|
18
|
+
def page_title(action, model_name)
|
19
|
+
if I18n.locale == :ru
|
20
|
+
"#{t("helpers.actions.#{action}")} #{genitive(model_name)}"
|
21
|
+
else
|
22
|
+
"#{t("helpers.actions.#{action}")} #{model_name.model_name.human.downcase}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'carrierwave/orm/activerecord' if defined?(CarrierWave::Mount)
|
4
|
+
|
5
|
+
class Tramway::ApplicationRecord < ActiveRecord::Base
|
6
|
+
self.abstract_class = true
|
7
|
+
audited
|
8
|
+
extend ::Enumerize
|
9
|
+
include AASM
|
10
|
+
acts_as_paranoid
|
11
|
+
|
12
|
+
scope :created_by_user, lambda { |user_id|
|
13
|
+
joins(:audits).where('audits.action = \'create\' AND audits.user_id = ?', user_id)
|
14
|
+
}
|
15
|
+
scope :admin_scope, ->(_arg) { all }
|
16
|
+
|
17
|
+
include ::PgSearch::Model
|
18
|
+
|
19
|
+
def creator
|
20
|
+
creation_event = audits.where(action: :create).first
|
21
|
+
creation_event.user if creation_event.user_id.present?
|
22
|
+
end
|
23
|
+
|
24
|
+
# FIXME: detect inhertited locales
|
25
|
+
class << self
|
26
|
+
def human_attribute_name(attribute_name, *_args)
|
27
|
+
excepted_attributes = %w[created_at updated_at]
|
28
|
+
if attribute_name.to_s.in? excepted_attributes
|
29
|
+
I18n.t "activerecord.attributes.tramway/application_record.#{attribute_name}"
|
30
|
+
else
|
31
|
+
super attribute_name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def search_by(*attributes, **associations)
|
36
|
+
pg_search_scope :full_text_search,
|
37
|
+
against: attributes,
|
38
|
+
associated_against: associations,
|
39
|
+
using: %i[tsearch trigram]
|
40
|
+
end
|
41
|
+
|
42
|
+
def uploader(attribute_name, uploader_name, **options)
|
43
|
+
mount_uploader attribute_name, "#{uploader_name.to_s.camelize}Uploader".constantize
|
44
|
+
@versions = options[:versions] if uploader_name == :photo
|
45
|
+
@extensions = options[:extensions]
|
46
|
+
end
|
47
|
+
|
48
|
+
def photo_versions
|
49
|
+
@versions
|
50
|
+
end
|
51
|
+
|
52
|
+
def file_extensions
|
53
|
+
@extensions
|
54
|
+
end
|
55
|
+
|
56
|
+
def state_machines_names
|
57
|
+
AASM::StateMachineStore.fetch(self).machine_names
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Tramway::User < ::Tramway::ApplicationRecord
|
4
|
+
has_secure_password
|
5
|
+
|
6
|
+
if defined? Tramway::Conference
|
7
|
+
has_many :social_networks, as: :record,
|
8
|
+
class_name: 'Tramway::Profiles::SocialNetwork'
|
9
|
+
end
|
10
|
+
|
11
|
+
scope :admins, -> { where role: :admin }
|
12
|
+
scope :simple_users, -> { where role: :user }
|
13
|
+
|
14
|
+
enumerize :role, in: %i[user admin], default: :admin
|
15
|
+
|
16
|
+
def admin?
|
17
|
+
role.admin?
|
18
|
+
end
|
19
|
+
|
20
|
+
def full_name
|
21
|
+
"#{first_name} #{last_name}"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'carrierwave'
|
4
|
+
|
5
|
+
class ApplicationUploader < CarrierWave::Uploader::Base
|
6
|
+
storage :file
|
7
|
+
|
8
|
+
def store_dir
|
9
|
+
"system/uploads/#{model.class.model_name.to_s.underscore}/#{mounted_as}/#{id_directory}"
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def id_directory
|
15
|
+
if model.respond_to?(:uuid)
|
16
|
+
model.reload unless model.uuid.present?
|
17
|
+
model.uuid
|
18
|
+
else
|
19
|
+
model.id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ImageDefaults
|
4
|
+
include CarrierWave::MiniMagick
|
5
|
+
|
6
|
+
def default_url
|
7
|
+
"/images/fallback/#{model.class.model_name.to_s.underscore}/" <<
|
8
|
+
[mounted_as, version_name].compact.join('_') << '.gif'
|
9
|
+
end
|
10
|
+
|
11
|
+
def extension_allowlist
|
12
|
+
model.class.file_extensions || %w[jpg jpeg gif png]
|
13
|
+
end
|
14
|
+
end
|