symphonia 4.1.3 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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