symphonia 4.1.3 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +27 -1
  4. data/app/assets/javascripts/symphonia/application.js +3 -3
  5. data/app/assets/javascripts/symphonia/symphonia_bootstrap_dialog.js +23 -23
  6. data/app/assets/stylesheets/symphonia/_font_awesome.scss +8 -6
  7. data/app/assets/stylesheets/symphonia/_layout.scss +33 -1
  8. data/app/assets/stylesheets/symphonia/basic.scss +3 -99
  9. data/app/assets/stylesheets/symphonia/filters.scss +3 -5
  10. data/app/assets/stylesheets/symphonia/symphonia_bootstrap.scss +1 -1
  11. data/app/controllers/symphonia/accounts_controller.rb +7 -3
  12. data/app/controllers/symphonia/application_controller.rb +2 -1
  13. data/app/controllers/symphonia/users_controller.rb +17 -29
  14. data/app/helpers/symphonia/application_helper.rb +48 -26
  15. data/app/models/symphonia/preference.rb +5 -5
  16. data/app/models/symphonia/user.rb +3 -35
  17. data/app/models/symphonia/user_ability.rb +46 -0
  18. data/app/views/common/403.html.erb +4 -3
  19. data/app/views/layouts/symphonia/application.html.erb +4 -4
  20. data/app/views/symphonia/accounts/_detail.html.erb +21 -18
  21. data/app/views/symphonia/common/_filters.html.erb +15 -15
  22. data/app/views/symphonia/common/_share_links.html.erb +2 -3
  23. data/app/views/symphonia/users/_form.html.erb +1 -6
  24. data/app/views/symphonia/users/show.html.erb +15 -20
  25. data/config/locales/cs.yml +3 -2
  26. data/db/migrate/20130714140500_create_users.rb +0 -2
  27. data/db/seeds.rb +3 -3
  28. data/lib/generators/symphonia/entity_controller/entity_controller_generator.rb +2 -2
  29. data/lib/generators/symphonia/entity_controller/templates/{controller.rb → controller.rb.tt} +0 -0
  30. data/lib/symphonia/admin_constraint.rb +1 -1
  31. data/lib/symphonia/base_controller.rb +9 -17
  32. data/lib/symphonia/controller_extensions.rb +5 -15
  33. data/lib/symphonia/engine.rb +12 -43
  34. data/lib/symphonia/form_builder.rb +17 -16
  35. data/lib/symphonia/menu_manager.rb +15 -11
  36. data/lib/symphonia/model_attributes/attribute.rb +3 -3
  37. data/lib/symphonia/object.rb +9 -9
  38. data/lib/symphonia/spec_helper.rb +8 -4
  39. data/lib/symphonia/user_management.rb +1 -1
  40. data/lib/symphonia/version.rb +1 -1
  41. data/lib/symphonia.rb +12 -9
  42. data/spec/factories/factories.rb +0 -4
  43. data/spec/models/user_spec.rb +39 -2
  44. data/spec/spec_helper.rb +0 -1
  45. data/spec/support/stub_users.rb +7 -7
  46. metadata +41 -140
  47. data/app/controllers/symphonia/roles_controller.rb +0 -39
  48. data/app/models/symphonia/role.rb +0 -55
  49. data/app/views/symphonia/roles/_form.html.erb +0 -26
  50. data/app/views/symphonia/roles/edit.html.erb +0 -5
  51. data/app/views/symphonia/roles/index.html.erb +0 -6
  52. data/app/views/symphonia/roles/new.html.erb +0 -4
  53. data/app/views/symphonia/roles/show.html.erb +0 -11
  54. data/db/migrate/20130714140501_create_roles.rb +0 -18
  55. data/db/migrate/20210509141420_roles_change_permissions_to_json.rb +0 -18
  56. data/db/migrate/20210509180525_roles_change_permissions_to_native_json.rb +0 -7
  57. data/lib/symphonia/permissions.rb +0 -93
  58. data/spec/controllers/roles_controller_spec.rb +0 -12
  59. data/spec/models/role_spec.rb +0 -13
  60. data/spec/requests/roles_spec.rb +0 -10
@@ -4,7 +4,7 @@ module Symphonia
4
4
  def matches?(request)
5
5
  return false if (credentials = request.session["symphonia/user_credentials"]).blank?
6
6
 
7
- user = User.find_by_persistence_token(credentials.split(':')[0])
7
+ user = User.find_by(persistence_token: credentials.split(':')[0])
8
8
  user&.admin?
9
9
  end
10
10
 
@@ -13,16 +13,14 @@ module Symphonia
13
13
  # %i[]
14
14
  # end
15
15
  #
16
- # def swagger_path
17
- # false # => for disable swagger
18
- # "/my-custom-path" # => for custom route
19
- # end
16
+
20
17
  module BaseController
18
+
21
19
  extend ActiveSupport::Concern
22
20
 
23
21
  included do
24
22
  # before_action :authorize
25
- before_action :find_entity, only: [:show, :edit, :update, :destroy]
23
+ before_action :find_entity, only: %i[show edit update destroy]
26
24
 
27
25
  include Rails::Pagination
28
26
  helper Symphonia::BootstrapModalHelper
@@ -30,11 +28,9 @@ module Symphonia
30
28
 
31
29
  # @param [Class] model
32
30
  class_attribute :model
33
-
34
31
  end
35
32
 
36
33
  class_methods do
37
-
38
34
  # def model=(klass)
39
35
  # @model = klass
40
36
  # end
@@ -76,11 +72,11 @@ module Symphonia
76
72
  end
77
73
 
78
74
  def new
79
- @entity ||= instance_variable_set(:"@#{model_name}", model.new(params.fetch(model_name, {}).permit(safe_attributes)))
75
+ @entity ||= instance_variable_set(:"@#{model_name}",
76
+ model.new(params.fetch(model_name, {}).permit(safe_attributes)))
80
77
  end
81
78
 
82
- def edit
83
- end
79
+ def edit; end
84
80
 
85
81
  def create
86
82
  @entity ||= instance_variable_set(:"@#{model_name}", model.new(entity_params))
@@ -119,7 +115,7 @@ module Symphonia
119
115
  end
120
116
 
121
117
  def model_name
122
- model.name.demodulize.underscore.to_sym
118
+ model.name.demodulize.underscore
123
119
  end
124
120
 
125
121
  private
@@ -138,13 +134,9 @@ module Symphonia
138
134
  params.require(model_name).permit(safe_attributes)
139
135
  end
140
136
 
141
- def after_create
142
-
143
- end
137
+ def after_create; end
144
138
 
145
- def after_update
146
-
147
- end
139
+ def after_update; end
148
140
 
149
141
  end
150
142
  end
@@ -17,7 +17,7 @@ module Symphonia
17
17
  add_flash_types :error
18
18
 
19
19
  rescue_from ::ActiveRecord::RecordNotFound, with: :render_404
20
- rescue_from Unauthorized, with: :render_403
20
+ rescue_from Unauthorized, CanCan::AccessDenied, with: :render_403
21
21
 
22
22
  helper_method :current_user, :back_url
23
23
  end
@@ -117,7 +117,7 @@ module Symphonia
117
117
 
118
118
  # Renders a 200 response for successful updates or deletions via the API
119
119
  def render_api_ok
120
- head :ok
120
+ render_api_head :ok
121
121
  end
122
122
 
123
123
  # Renders a head API response
@@ -143,20 +143,10 @@ module Symphonia
143
143
  end
144
144
 
145
145
  def authorize
146
- if Symphonia::User.current.authorize?(controller_name, action_name)
147
- return true
148
- elsif Symphonia::User.current.logged_in?
149
- raise Unauthorized
150
- else
151
- respond_to do |format|
152
- format.html do
153
- return redirect_to(symphonia.login_path(back_url: request.path), error: t(:text_error_login_required))
154
- end
155
- format.any { return head 401 }
156
- end
157
- end
146
+ return true if Symphonia::User.current.admin?
147
+ raise Unauthorized if Symphonia::User.current.logged_in?
158
148
 
159
- raise Unauthorized
149
+ login_require
160
150
  end
161
151
 
162
152
  def handle_unverified_request
@@ -1,54 +1,37 @@
1
1
  require 'symphonia/object'
2
- require 'symphonia/menu_manager'
3
- require 'symphonia/permissions'
4
- require 'symphonia/user_management'
5
2
 
6
- require 'rails-i18n'
7
- require 'turbolinks'
8
3
  require 'authlogic'
4
+ require 'cancancan'
9
5
  require 'scrypt'
10
- require 'bootstrap'
11
6
 
12
7
  require 'will_paginate'
13
8
  require 'api-pagination'
14
- require 'font-awesome-rails'
15
- require 'jquery-rails'
16
- require 'jquery-ui-rails'
9
+
10
+ require 'rails_i18n'
17
11
  require 'rdiscount'
18
12
  require 'sortable-table'
19
- # require 'paperclip'
20
- require 'awesome_nested_set'
21
- # require 'acts_as_list'
22
13
  require 'bootstrap_form'
23
- require 'bootstrap-datepicker-rails'
24
- # require 'wicked_pdf'
25
- # require 'swagger/blocks'
26
14
 
27
15
  module Symphonia
28
16
 
29
17
  class Engine < ::Rails::Engine
30
18
  isolate_namespace Symphonia
31
19
 
20
+ config.autoload_paths << File.expand_path("..", __dir__)
21
+
32
22
  config.generators do |g|
33
23
  g.test_framework :rspec, fixture: false
34
24
  g.fixture_replacement :factory_bot, dir: 'spec/factories'
35
25
  end
36
26
 
37
- # Rails 5
38
- # ActionController::Base.class_eval do
39
- # include Symphonia::ApplicationController
40
- # end
41
-
42
-
43
27
  initializer :symphonia_extensions do
28
+ ActiveSupport.on_load(:action_controller_base) do
29
+ # prepend Symphonia::ApplicationController
30
+ helper Symphonia::ApplicationHelper
31
+ helper Symphonia::BootstrapModalHelper
32
+ end
44
33
  end
45
34
 
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
35
  initializer :symphonia_setup do |_app|
53
36
  Mime::Type.register 'application/pdf', :pdf
54
37
  config.i18n.available_locales ||= %i[cs en]
@@ -72,29 +55,15 @@ module Symphonia
72
55
  end
73
56
  end
74
57
 
75
- # include helpers
76
58
  initializer :load_helper, before: :load_config_initializers do |app|
77
- # config.active_record.raise_in_transactional_callbacks = false
78
59
  if Rails.env.development?
79
60
  config.action_mailer.default_url_options ||= { host: 'symphonia.app' }
80
61
  config.action_mailer.preview_path = "{#{app.root.join('spec/mailers/previews')},#{root.join('spec/mailers/previews')}}"
81
62
  end
82
63
  end
83
64
 
84
- initializer :assets do |_app|
85
- config.assets.precompile << 'symphonia/application.css'
86
- #if defined?(::Ckeditor)
87
- # config.assets.precompile << 'ckeditor/**/*'
88
- # config.assets.precompile << 'symphonia/symphonia_ckeditor.js'
89
- #end
90
- end
91
-
92
- initializer :symphonia_general_permissions do |_app|
93
- Symphonia::Permissions.map do |m|
94
- m.register(:view_users).add(:users, %i[index show])
95
- m.register(:manage_users).add(:users, %i[create update destroy new edit])
96
- end
97
-
65
+ initializer :assets do |app|
66
+ app.config.assets.precompile << 'symphonia/application.css'
98
67
  end
99
68
 
100
69
  # initializer :wicked_pdf do |_app|
@@ -1,26 +1,26 @@
1
1
  module Symphonia
2
2
  class FormBuilder < ::BootstrapForm::FormBuilder
3
3
 
4
+ delegate :tag, :t, to: :@template
5
+
4
6
  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')
7
+ return if !object.respond_to?(:errors) || object.errors.blank?
8
+
9
+ list = tag.p(@template.icon("circle-exclamation", t('activerecord.errors.template.body')))
10
+ list += tag.ul do
11
+ object.errors.full_messages.collect do |error|
12
+ tag.li error
13
+ end.join.html_safe
13
14
  end
15
+ tag.div(list, class: 'alert alert-danger error_explanation')
14
16
  end
15
17
 
16
18
  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
- }))
19
+ options[:type] ||= "date"
20
+ text_field(name, options.merge(
21
+ class: 'form-control datepicker',
22
+ append: @template.icon('calendar'),
23
+ ))
24
24
  end
25
25
 
26
26
  # def form_group_builder(method, options, html_options = nil)
@@ -91,6 +91,7 @@ module Symphonia
91
91
  options[:text]
92
92
  end
93
93
  end
94
+
94
95
  # def generate_label(id, name, options, custom_label_col, group_layout)
95
96
  # return if options.blank?
96
97
  # # id is the caller's options[:id] at the only place this method is called.
@@ -134,4 +135,4 @@ module Symphonia
134
135
  end
135
136
 
136
137
  end
137
- end
138
+ end
@@ -1,23 +1,27 @@
1
1
  module Symphonia
2
- module MenuManager
3
- @@mapper = {}
4
- mattr_accessor :mapper
2
+ # Store in-app menu super-global object for all instances/workers
3
+ class MenuManager
4
+ class << self
5
5
 
6
- def self.menu(name)
7
- return mapper[name.to_sym] || {}
8
- end
6
+ def mapper
7
+ $mapper ||= {}
8
+ end
9
+
10
+ # @param [Symbol] name
11
+ def menu(name)
12
+ mapper[name] || {}
13
+ end
9
14
 
10
- class << self
11
15
  def map(menu_name)
12
16
  mapper[menu_name] ||= {}
13
- if block_given?
14
- yield mapper[menu_name]
15
- end
17
+ yield mapper[menu_name]
16
18
  end
17
19
 
18
20
  def clear(menu_name)
19
- !mapper.delete(menu_name.to_sym).nil?
21
+ !mapper.delete(menu_name).nil?
20
22
  end
23
+
21
24
  end
25
+
22
26
  end
23
27
  end
@@ -106,7 +106,7 @@ module Symphonia
106
106
 
107
107
  # TODO: @klass.name || @klass.base_class.name || entity.class.name
108
108
  def format_value(view, value, _entity)
109
- view.t("#{@klass.name.underscore}.#{name.to_s.pluralize}.#{value}", format_options)
109
+ view.t("#{@klass.name.underscore}.#{name.to_s.pluralize}.#{value}", **format_options)
110
110
  end
111
111
 
112
112
  def input_field
@@ -179,7 +179,7 @@ module Symphonia
179
179
  class DateAttribute < Attribute
180
180
 
181
181
  def format_value(view, value, _entity)
182
- value && view.l(value.to_date, format_options)
182
+ value && view.l(value.to_date, **format_options)
183
183
  end
184
184
 
185
185
  end
@@ -187,7 +187,7 @@ module Symphonia
187
187
  class DateTimeAttribute < Attribute
188
188
 
189
189
  def format_value(view, value, _entity)
190
- value && view.l(value.localtime, format_options)
190
+ value && view.l(value.localtime, **format_options)
191
191
  end
192
192
 
193
193
  end
@@ -1,31 +1,31 @@
1
- class Object
2
- # def to_boolean
3
- # return true if self.is_a?(TrueClass)
4
-
5
- # respond_to?(:downcase) && ['true', 1, '1', 'yes', 't', 'y'].include?(self.downcase)
6
- # end
7
- end
8
-
9
1
  class String
2
+
10
3
  def to_boolean
11
- ['true', 1, '1', 'yes', 't', 'y'].include?(self.downcase)
4
+ ['true', 1, '1', 'yes', 't', 'y'].include?(downcase)
12
5
  end
6
+
13
7
  end
14
8
 
15
9
  class NilClass
10
+
16
11
  def to_boolean
17
12
  false
18
13
  end
14
+
19
15
  end
20
16
 
21
17
  class FalseClass
18
+
22
19
  def to_boolean
23
20
  false
24
21
  end
22
+
25
23
  end
26
24
 
27
25
  class TrueClass
26
+
28
27
  def to_boolean
29
28
  true
30
29
  end
30
+
31
31
  end
@@ -1,6 +1,10 @@
1
- if Rails.env.test?
2
- require File.expand_path('../../../spec/spec_helper', __FILE__)
3
- Dir.glob(File.expand_path('../../../spec/{factories,support}/*.rb', __FILE__)).each do |file|
4
- require file
1
+ module Symphonia
2
+ module SpecHelper
3
+ if Rails.env.test?
4
+ require File.expand_path('../../../spec/spec_helper', __FILE__)
5
+ Dir.glob(File.expand_path('../../../spec/{factories,support}/*.rb', __FILE__)).each do |file|
6
+ require file
7
+ end
8
+ end
5
9
  end
6
10
  end
@@ -29,7 +29,7 @@ module Symphonia
29
29
  end
30
30
 
31
31
  def name=(string)
32
- words = string.split(" ")
32
+ words = string.split
33
33
  self.first_name = words[0..-2].join(" ")
34
34
  self.last_name = words[-1]
35
35
  end
@@ -1,5 +1,5 @@
1
1
  module Symphonia
2
2
 
3
- VERSION = '4.1.3'
3
+ VERSION = '5.0.0'
4
4
 
5
5
  end
data/lib/symphonia.rb CHANGED
@@ -2,15 +2,18 @@ module Symphonia
2
2
 
3
3
  include ::ActiveSupport::Configurable
4
4
 
5
- autoload :BaseController, 'symphonia/base_controller'
6
- autoload :BootstrapLinkRender, 'symphonia/bootstrap_link_render'
7
- autoload :ControllerExtensions, 'symphonia/controller_extensions'
8
- autoload :EntityDecorator, 'symphonia/entity_decorator'
9
- autoload :FormBuilder, 'symphonia/form_builder'
10
- autoload :ModelAttributes, 'symphonia/model_attributes'
11
- autoload :ModelFilters, 'symphonia/model_filters'
12
- autoload :Query, 'symphonia/query'
13
- autoload :QueryColumns, 'symphonia/query_columns'
5
+ # autoload :BaseController, 'symphonia/base_controller'
6
+ # autoload :BootstrapLinkRender, 'symphonia/bootstrap_link_render'
7
+ # autoload :ControllerExtensions, 'symphonia/controller_extensions'
8
+ # autoload :EntityDecorator, 'symphonia/entity_decorator'
9
+ # autoload :FormBuilder, 'symphonia/form_builder'
10
+ # autoload :MenuManager, 'symphonia/menu_manager'
11
+ # autoload :ModelAttributes, 'symphonia/model_attributes'
12
+ # autoload :ModelFilters, 'symphonia/model_filters'
13
+ # autoload :Permissions, 'symphonia/permissions'
14
+ # autoload :Query, 'symphonia/query'
15
+ # autoload :QueryColumns, 'symphonia/query_columns'
16
+ # autoload :UserManagement, 'symphonia/user_management'
14
17
 
15
18
  module ActionCable
16
19
 
@@ -23,10 +23,6 @@ FactoryBot.define do
23
23
  factory :admin_user, traits: [:admin]
24
24
  end
25
25
 
26
- factory :role, class: 'Symphonia::Role' do
27
- sequence(:name) { |n| "#{Faker::Job.title} #{n}" }
28
- end
29
-
30
26
  factory :preference, class: 'Symphonia::Preference' do
31
27
 
32
28
  factory :email_preference, class: 'Symphonia::EmailPreference' do
@@ -1,7 +1,8 @@
1
1
  RSpec.describe Symphonia::User do
2
2
  subject { FactoryBot.create(:user, email: "test@dummy.com") }
3
+
3
4
  it "#like" do
4
- expect(Symphonia::User.like(subject.mail)).to be_all Symphonia::User
5
+ expect(described_class.like(subject.mail)).to be_all described_class
5
6
  end
6
7
 
7
8
  it "#to_s" do
@@ -22,14 +23,50 @@ RSpec.describe Symphonia::User do
22
23
  end
23
24
  end
24
25
 
25
-
26
26
  describe "#required_password" do
27
27
  it "require password for internal" do
28
28
  expect { FactoryBot.create(:user, password: nil) }.to raise_error ActiveRecord::RecordInvalid
29
29
  end
30
+
30
31
  it "do not require password for external_ids" do
31
32
  expect { FactoryBot.create(:user, password: nil, external_id: "ex1") }.not_to raise_error
32
33
  end
33
34
  end
34
35
 
36
+ require "cancan/matchers"
37
+
38
+ describe "abilities" do
39
+ subject(:ability) { Symphonia::UserAbility.new(user) }
40
+
41
+ let(:admin) { create(:admin_user) }
42
+ let(:franta) { create(:user, login: "franta", status: :pending) }
43
+ let(:user) { nil }
44
+
45
+ context "when is an admin" do
46
+ let(:user) { create(:admin_user) }
47
+
48
+ it { is_expected.to be_able_to(:show, admin) }
49
+ it { is_expected.to be_able_to(:edit, admin) }
50
+ it { is_expected.to be_able_to(:edit, user) }
51
+ it { is_expected.not_to be_able_to(:activate, described_class.new(status: :active)) }
52
+ it { is_expected.to be_able_to(:activate, described_class.new(status: :pending)) }
53
+ it { is_expected.not_to be_able_to(:activate, described_class.new(status: :archived)) }
54
+ it { is_expected.to be_able_to(:archive, described_class.new(status: :active)) }
55
+ it { is_expected.not_to be_able_to(:archive, described_class.new(status: :archived)) }
56
+
57
+ end
58
+
59
+ context "regular user" do
60
+ let(:user) { create(:user) }
61
+
62
+ it { is_expected.not_to be_able_to(:show, franta) }
63
+ it { is_expected.to be_able_to(:show, user) }
64
+ it { is_expected.to be_able_to(:edit, user) }
65
+ it { is_expected.not_to be_able_to(:edit, franta) }
66
+ it { is_expected.to be_able_to(:update, user) }
67
+ it { is_expected.not_to be_able_to(:destroy, described_class.new) }
68
+ it { is_expected.not_to be_able_to(:create, described_class.new) }
69
+ it { is_expected.not_to be_able_to(:update, described_class.new) }
70
+ end
71
+ end
35
72
  end
data/spec/spec_helper.rb CHANGED
@@ -3,7 +3,6 @@ require 'pry-rails'
3
3
  require 'faker'
4
4
  require 'factory_bot_rails'
5
5
  require 'database_cleaner'
6
- require 'sass-rails'
7
6
  require 'authlogic/test_case'
8
7
 
9
8
  Dir.glob(File.join(__dir__, 'support', '*.rb')).sort.each { |f| require f }
@@ -6,10 +6,10 @@ def regular_user
6
6
  @regular_user ||= FactoryBot.create :user
7
7
  end
8
8
 
9
- def add_permission *args
10
- @role ||= FactoryBot.build_stubbed :role
11
- @role.permissions = args
12
- regular_user.role = @role
13
- # allow(regular_user).to receive(:role).and_return @role
14
- @role
15
- end
9
+ # def add_permission *args
10
+ # # @role ||= FactoryBot.build_stubbed :role
11
+ # # @role.permissions = args
12
+ # # regular_user.role = @role
13
+ # # # allow(regular_user).to receive(:role).and_return @role
14
+ # # @role
15
+ # end