anoubis 1.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +38 -0
- data/app/controllers/anoubis/application_controller.rb +78 -0
- data/app/controllers/anoubis/core/application_controller.rb +343 -0
- data/app/controllers/anoubis/core/data/actions.rb +962 -0
- data/app/controllers/anoubis/core/data/callbacks.rb +68 -0
- data/app/controllers/anoubis/core/data/convert.rb +407 -0
- data/app/controllers/anoubis/core/data/defaults.rb +217 -0
- data/app/controllers/anoubis/core/data/get.rb +531 -0
- data/app/controllers/anoubis/core/data/load.rb +89 -0
- data/app/controllers/anoubis/core/data/set.rb +49 -0
- data/app/controllers/anoubis/core/data/setup.rb +104 -0
- data/app/controllers/anoubis/core/data_controller.rb +28 -0
- data/app/controllers/anoubis/core/index/actions.rb +53 -0
- data/app/controllers/anoubis/core/index/callbacks.rb +23 -0
- data/app/controllers/anoubis/core/index_controller.rb +36 -0
- data/app/controllers/anoubis/etc/base.rb +52 -0
- data/app/controllers/anoubis/etc/data.rb +89 -0
- data/app/controllers/anoubis/etc/field.rb +468 -0
- data/app/controllers/anoubis/etc/field_options.rb +83 -0
- data/app/controllers/anoubis/etc/field_order.rb +51 -0
- data/app/controllers/anoubis/etc/filter.rb +251 -0
- data/app/controllers/anoubis/etc/menu.rb +101 -0
- data/app/controllers/anoubis/etc/model.rb +67 -0
- data/app/controllers/anoubis/etc/tab_item.rb +91 -0
- data/app/controllers/anoubis/etc.rb +8 -0
- data/app/controllers/anoubis/export.rb +47 -0
- data/app/controllers/anoubis/output/autocomplete.rb +30 -0
- data/app/controllers/anoubis/output/basic.rb +86 -0
- data/app/controllers/anoubis/output/data.rb +101 -0
- data/app/controllers/anoubis/output/delete.rb +41 -0
- data/app/controllers/anoubis/output/edit.rb +55 -0
- data/app/controllers/anoubis/output/frame.rb +227 -0
- data/app/controllers/anoubis/output/login.rb +71 -0
- data/app/controllers/anoubis/output/menu.rb +220 -0
- data/app/controllers/anoubis/output/update.rb +43 -0
- data/app/controllers/anoubis/sso/client/application_controller.rb +139 -0
- data/app/controllers/anoubis/sso/client/data/actions.rb +5 -0
- data/app/controllers/anoubis/sso/client/data/callbacks.rb +5 -0
- data/app/controllers/anoubis/sso/client/data/convert.rb +5 -0
- data/app/controllers/anoubis/sso/client/data/defaults.rb +5 -0
- data/app/controllers/anoubis/sso/client/data/get.rb +5 -0
- data/app/controllers/anoubis/sso/client/data/load.rb +26 -0
- data/app/controllers/anoubis/sso/client/data/set.rb +5 -0
- data/app/controllers/anoubis/sso/client/data/setup.rb +5 -0
- data/app/controllers/anoubis/sso/client/data_controller.rb +21 -0
- data/app/controllers/anoubis/sso/client/index/actions.rb +79 -0
- data/app/controllers/anoubis/sso/client/index/callbacks.rb +13 -0
- data/app/controllers/anoubis/sso/client/index_controller.rb +18 -0
- data/app/controllers/anoubis/sso/server/application_controller.rb +49 -0
- data/app/controllers/anoubis/sso/server/login_controller.rb +342 -0
- data/app/controllers/anoubis/sso/server/user_controller.rb +142 -0
- data/app/controllers/anoubis/tenant/application_controller.rb +54 -0
- data/app/controllers/anoubis/tenant/data/actions.rb +11 -0
- data/app/controllers/anoubis/tenant/data/callbacks.rb +11 -0
- data/app/controllers/anoubis/tenant/data/convert.rb +11 -0
- data/app/controllers/anoubis/tenant/data/defaults.rb +11 -0
- data/app/controllers/anoubis/tenant/data/get.rb +11 -0
- data/app/controllers/anoubis/tenant/data/load.rb +52 -0
- data/app/controllers/anoubis/tenant/data/set.rb +11 -0
- data/app/controllers/anoubis/tenant/data/setup.rb +11 -0
- data/app/controllers/anoubis/tenant/data_controller.rb +28 -0
- data/app/controllers/anoubis/tenant/index/actions.rb +191 -0
- data/app/controllers/anoubis/tenant/index/callbacks.rb +11 -0
- data/app/controllers/anoubis/tenant/index_controller.rb +38 -0
- data/app/controllers/anoubis/tenants_controller.rb +7 -0
- data/app/controllers/anoubis/users_controller.rb +7 -0
- data/app/jobs/anoubis/application_job.rb +6 -0
- data/app/mailers/anoubis/application_mailer.rb +8 -0
- data/app/models/anoubis/application_record.rb +45 -0
- data/app/models/anoubis/core/application_record.rb +250 -0
- data/app/models/anoubis/core/locales.rb +27 -0
- data/app/models/anoubis/sso/client/application_record.rb +3 -0
- data/app/models/anoubis/sso/client/group.rb +19 -0
- data/app/models/anoubis/sso/client/group_menu.rb +109 -0
- data/app/models/anoubis/sso/client/menu.rb +145 -0
- data/app/models/anoubis/sso/client/user.rb +81 -0
- data/app/models/anoubis/sso/client/user_group.rb +32 -0
- data/app/models/anoubis/sso/server/system.rb +36 -0
- data/app/models/anoubis/sso/server/user.rb +79 -0
- data/app/models/anoubis/tenant/application_record.rb +41 -0
- data/app/models/anoubis/tenant/group.rb +95 -0
- data/app/models/anoubis/tenant/group_locale.rb +19 -0
- data/app/models/anoubis/tenant/group_menu.rb +84 -0
- data/app/models/anoubis/tenant/menu.rb +156 -0
- data/app/models/anoubis/tenant/menu_locale.rb +27 -0
- data/app/models/anoubis/tenant/system.rb +127 -0
- data/app/models/anoubis/tenant/system_locale.rb +19 -0
- data/app/models/anoubis/tenant/system_menu.rb +51 -0
- data/app/models/anoubis/tenant/tenant.rb +107 -0
- data/app/models/anoubis/tenant/tenant_system.rb +19 -0
- data/app/models/anoubis/tenant/user.rb +225 -0
- data/app/models/anoubis/tenant/user_group.rb +32 -0
- data/app/services/anoubis/core_service.rb +16 -0
- data/app/services/anoubis/session_service.rb +17 -0
- data/app/validators/presence_in_tenant_validator.rb +20 -0
- data/config/initializers/mime_type.rb +1 -0
- data/config/locales/en.yml +120 -0
- data/config/locales/ru.yml +245 -0
- data/config/routes.rb +74 -0
- data/db/migrate/20181018085843_create_tenants.rb +13 -0
- data/db/migrate/20181018111217_create_systems.rb +10 -0
- data/db/migrate/20181018111713_create_tenant_systems.rb +11 -0
- data/db/migrate/20181018111925_create_groups.rb +13 -0
- data/db/migrate/20181018112151_create_users.rb +25 -0
- data/db/migrate/20181018115737_add_title_to_users.rb +10 -0
- data/db/migrate/20181022060211_create_menus.rb +18 -0
- data/db/migrate/20181115055245_create_group_menus.rb +12 -0
- data/db/migrate/20181115060830_create_system_menus.rb +11 -0
- data/db/migrate/20181122062131_create_user_groups.rb +11 -0
- data/db/migrate/20181221060727_create_menu_locales.rb +14 -0
- data/db/migrate/20181225062303_create_system_locales.rb +11 -0
- data/db/migrate/20181225062339_create_group_locales.rb +11 -0
- data/db/seeds.rb +268 -0
- data/lib/anoubis/engine.rb +13 -0
- data/lib/anoubis/version.rb +5 -0
- data/lib/anoubis.rb +213 -0
- data/lib/tasks/anubis_tasks.rake +10 -0
- data/lib/tasks/sessions/clear_sessions.rake +10 -0
- data/spec/anubis_spec.rb +5 -0
- data/spec/controllers/anoubis/index_controller_spec.rb +77 -0
- data/spec/dummy/Rakefile +3 -0
- data/spec/dummy/app/assets/config/manifest.js +2 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +33 -0
- data/spec/dummy/bin/update +28 -0
- data/spec/dummy/config/application.rb +14 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/database.yml +54 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +54 -0
- data/spec/dummy/config/environments/production.rb +85 -0
- data/spec/dummy/config/environments/test.rb +46 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cors.rb +16 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/puma.rb +34 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/config/storage.yml +34 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/db/schema.rb +167 -0
- data/spec/dummy/db/seeds.rb +1 -0
- data/spec/factories/anubis_group_locales.rb +7 -0
- data/spec/factories/anubis_group_menus.rb +7 -0
- data/spec/factories/anubis_groups.rb +6 -0
- data/spec/factories/anubis_menu_locales.rb +9 -0
- data/spec/factories/anubis_menus.rb +6 -0
- data/spec/factories/anubis_system_locales.rb +7 -0
- data/spec/factories/anubis_system_menus.rb +6 -0
- data/spec/factories/anubis_systems.rb +5 -0
- data/spec/factories/anubis_tenants.rb +7 -0
- data/spec/factories/anubis_users.rb +10 -0
- data/spec/integration/navigation_test.rb +7 -0
- data/spec/models/anoubis/group_locale_spec.rb +25 -0
- data/spec/models/anoubis/group_menu_spec.rb +50 -0
- data/spec/models/anoubis/group_spec.rb +52 -0
- data/spec/models/anoubis/menu_locale_spec.rb +31 -0
- data/spec/models/anoubis/menu_spec.rb +48 -0
- data/spec/models/anoubis/system_locale_spec.rb +20 -0
- data/spec/models/anoubis/system_menu_spec.rb +49 -0
- data/spec/models/anoubis/system_spec.rb +53 -0
- data/spec/models/anoubis/tenant_spec.rb +67 -0
- data/spec/models/anoubis/user_spec.rb +57 -0
- data/spec/rails_helper.rb +32 -0
- data/spec/requests/anoubis/users_request_spec.rb +5 -0
- data/spec/spec_helper.rb +13 -0
- metadata +408 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Model links {Menu} and {Group}. Describes group access to menu.
|
|
3
|
+
class Anubis::Sso::Client::GroupMenu < Anubis::Sso::Client::ApplicationRecord
|
|
4
|
+
# Redefines default table name
|
|
5
|
+
self.table_name = 'group_menus'
|
|
6
|
+
|
|
7
|
+
before_validation :before_validation_sso_client_group_menu
|
|
8
|
+
after_create :after_create_sso_client_group_menu
|
|
9
|
+
before_update :before_update_sso_client_group_menu
|
|
10
|
+
after_destroy :after_destroy_sso_client_group_menu
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# @!attribute group
|
|
14
|
+
# @return [Group] reference to the {Group} model
|
|
15
|
+
belongs_to :group, :class_name => 'Anubis::Sso::Client::Group'
|
|
16
|
+
validates :group, presence: true, uniqueness: { scope: [:menu_id] }
|
|
17
|
+
|
|
18
|
+
# @!attribute menu
|
|
19
|
+
# @return [Menu] reference to the {Menu} model
|
|
20
|
+
belongs_to :menu, :class_name => 'Anubis::Sso::Client::Menu'
|
|
21
|
+
validates :menu, presence: true, uniqueness: { scope: [:group_id] }
|
|
22
|
+
|
|
23
|
+
# @!attribute access
|
|
24
|
+
# @return ['not', 'read', 'write', 'disable'] group access to menu element.
|
|
25
|
+
# - 'not' --- menu element doesn't available for this group
|
|
26
|
+
# - 'read' --- group has access to menu element only for read data
|
|
27
|
+
# - 'write' --- group has access to menu element for read and write data
|
|
28
|
+
# - 'disable' --- group hasn't access to menu element
|
|
29
|
+
enum access: { not: 0, read: 20, write: 40, disable: 60 }
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Is called before validation when the link between menu and group is being created or updated.
|
|
33
|
+
# Procedure checks if group belongs a system that has access to this menu element. If {#access} doesn't
|
|
34
|
+
# defined then {#access} sets to 'read'
|
|
35
|
+
def before_validation_sso_client_group_menu
|
|
36
|
+
self.access = 'read' if !self.access
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# Is called after new link between menu and group was created. If new element has parent with link that
|
|
41
|
+
# doesn't present in database then adds this link to database with {#access} defined as 'read'.
|
|
42
|
+
def after_create_sso_client_group_menu
|
|
43
|
+
if self.menu.menu_id != nil
|
|
44
|
+
Anubis::Sso::Client::GroupMenu.find_or_create_by(menu_id: self.menu.menu_id, group_id: self.group_id) do |menu|
|
|
45
|
+
menu.access = 'read'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
self.after_modify_sso_client_group_menu
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
##
|
|
52
|
+
# Is called before link between menu and group will be updated. Procedure prevents changing {#menu}
|
|
53
|
+
# and {#group} value.
|
|
54
|
+
def before_update_sso_client_group_menu
|
|
55
|
+
self.menu_id = self.menu_id_was if self.menu_id_changed?
|
|
56
|
+
self.group_id = self.group_id_was if self.group_id_changed?
|
|
57
|
+
self.after_modify_sso_client_group_menu
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
##
|
|
61
|
+
# Is called after link between menu and group had been deleted from database. It also deletes all child links.
|
|
62
|
+
def after_destroy_sso_client_group_menu
|
|
63
|
+
Anubis::Sso::Client::Menu.select(:id).where(menu_id: self.menu_id).each do |menu|
|
|
64
|
+
Anubis::Sso::Client::GroupMenu.where(menu_id: menu.id, group_id: self.group_id).each do |group_menu|
|
|
65
|
+
group_menu.destroy
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
self.after_modify_sso_client_group_menu
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
# Deletes all user's keys that belong this menu element in Redis database.
|
|
73
|
+
def after_modify_sso_client_group_menu
|
|
74
|
+
if self.redis
|
|
75
|
+
self.redis.keys(self.redis_prefix + '*_' + self.menu.mode).each do |data|
|
|
76
|
+
self.redis.del data
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def title
|
|
82
|
+
self.get_localized_menu 'title'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def page_title
|
|
86
|
+
self.get_localized_menu 'page_title'
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def short_title
|
|
90
|
+
self.get_localized_menu 'short_title'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def get_localized_menu(field)
|
|
94
|
+
loc_field = (field.to_s + '_locale').to_sym
|
|
95
|
+
begin
|
|
96
|
+
self[loc_field] = JSON.parse(self[loc_field]) if self[loc_field]
|
|
97
|
+
rescue
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
begin
|
|
102
|
+
result = self.get_locale_field loc_field.to_s
|
|
103
|
+
rescue
|
|
104
|
+
result = eval('self.menu.' + field.to_s)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
result
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
class Anubis::Sso::Client::Menu < Anubis::Sso::Client::ApplicationRecord
|
|
2
|
+
self.table_name = 'menus'
|
|
3
|
+
|
|
4
|
+
before_create :before_create_sso_client_menu
|
|
5
|
+
before_update :before_update_sso_client_menu
|
|
6
|
+
before_save :before_save_sso_client_menu
|
|
7
|
+
before_destroy :before_destroy_sso_client_menu
|
|
8
|
+
after_destroy :after_destroy_sso_client_menu
|
|
9
|
+
|
|
10
|
+
VALID_IDENT_REGEX = /\A[a-z_\/0-9]*\z/i
|
|
11
|
+
|
|
12
|
+
# @!attribute mode
|
|
13
|
+
# @return [String] the controller path for menu element.
|
|
14
|
+
validates :mode, length: { minimum: 3, maximum: 100 }, uniqueness: { case_sensitive: false }, format: { with: VALID_IDENT_REGEX }
|
|
15
|
+
|
|
16
|
+
# @!attribute action
|
|
17
|
+
# @return [String] the default action of menu element ('data', 'menu', etc.).
|
|
18
|
+
validates :action, presence: true
|
|
19
|
+
|
|
20
|
+
# @!attribute tab
|
|
21
|
+
# @return [Integer] the nesting level of menu element
|
|
22
|
+
validates :tab, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
|
23
|
+
|
|
24
|
+
# @!attribute position
|
|
25
|
+
# @return [Integer] the order position of menu element in current level.
|
|
26
|
+
validates :position, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
|
27
|
+
|
|
28
|
+
# @!attribute page_size
|
|
29
|
+
# @return [Integer] the default page size for table of data frame.
|
|
30
|
+
validates :page_size, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
|
31
|
+
|
|
32
|
+
# @!attribute menu
|
|
33
|
+
# @return [Menu, nil] the parent menu for element menu (if exists).
|
|
34
|
+
belongs_to :menu, class_name: 'Anubis::Sso::Client::Menu', optional: true
|
|
35
|
+
has_many :menus, class_name: 'Anubis::Sso::Client::Menu'
|
|
36
|
+
|
|
37
|
+
# @!attribute title
|
|
38
|
+
# @return [String] the menu's localized title.
|
|
39
|
+
validates :title, presence: true, length: { maximum: 100 }
|
|
40
|
+
|
|
41
|
+
def title
|
|
42
|
+
get_locale_field 'title_locale'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def title=(value)
|
|
46
|
+
self.set_locale_field 'title_locale', value
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @!attribute page_title
|
|
50
|
+
# @return [String] the menu's localized page title. Uses in frontend application.
|
|
51
|
+
validates :page_title, presence: true, length: { minimum: 3, maximum: 200 }
|
|
52
|
+
|
|
53
|
+
def page_title
|
|
54
|
+
get_locale_field 'page_title_locale'
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def page_title=(value)
|
|
58
|
+
self.set_locale_field 'page_title_locale', value
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @!attribute short_title
|
|
62
|
+
# @return [String] the menu's localized short title. Uses in frontend application.
|
|
63
|
+
validates :short_title, length: { maximum: 200 }
|
|
64
|
+
|
|
65
|
+
def short_title
|
|
66
|
+
get_locale_field 'short_title_locale'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def short_title=(value)
|
|
70
|
+
self.set_locale_field 'short_title_locale', value
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @!attribute status
|
|
74
|
+
# @return ['enabled', 'disabled'] the status of menu element.
|
|
75
|
+
# - 'enabled' --- element is enabled and is used by the system.
|
|
76
|
+
# - 'disabled' --- element is disabled and isn't used by the system.
|
|
77
|
+
enum status: { enabled: 0, disabled: 1 }
|
|
78
|
+
|
|
79
|
+
# @!attribute state
|
|
80
|
+
# @return ['visible', 'hidden'] the visibility of menu element. Attribute is used in fronted application.
|
|
81
|
+
# - 'visible' --- element is visible.
|
|
82
|
+
# - 'hidden' --- element is hidden.
|
|
83
|
+
enum state: { visible: 0, hidden: 1 }
|
|
84
|
+
|
|
85
|
+
has_many :group_menus, class_name: 'Anubis::Sso::Client::GroupMenu'
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
# Is called before menu will be created in database. Sets {#position} as last {#position} + 1 on current {#tab}.
|
|
89
|
+
# After this calls {#before_update_menu} for additional modification.
|
|
90
|
+
def before_create_sso_client_menu
|
|
91
|
+
data = Anubis::Sso::Client::Menu.where(menu_id: self.menu_id).maximum(:position)
|
|
92
|
+
self.position = if data then data + 1 else 0 end
|
|
93
|
+
|
|
94
|
+
self.before_update_sso_client_menu
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
##
|
|
98
|
+
# Is called before menu will be stored in database. Sets {#mode} and {#action} in lowercase. If {#page_size}
|
|
99
|
+
# doesn't defined then sets it to 20. If defined parent menu element then sets {#tab} based on {#tab} of
|
|
100
|
+
# parent menu element + 1.
|
|
101
|
+
def before_update_sso_client_menu
|
|
102
|
+
self.mode = mode.downcase
|
|
103
|
+
self.action = self.action.downcase
|
|
104
|
+
self.page_size = 20 if self.page_size == 0
|
|
105
|
+
self.page_size = self.page_size.to_i
|
|
106
|
+
|
|
107
|
+
parent_menu = Anubis::Sso::Client::Menu.where(id: self.menu_id).first
|
|
108
|
+
if parent_menu
|
|
109
|
+
self.tab = parent_menu.tab + 1
|
|
110
|
+
else
|
|
111
|
+
self.tab = 0
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
##
|
|
116
|
+
# Is called right before menu will be stored in database (after {#before_create_menu} and {#before_update_menu}).
|
|
117
|
+
# Deletes cache data for this menu in Redis database.
|
|
118
|
+
def before_save_sso_client_menu
|
|
119
|
+
self.redis.del(self.redis_prefix + 'menu:' + self.mode) if self.redis
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
##
|
|
123
|
+
# Is called before menu will be deleted from database. Checks the ability to destroy a menu. Delete
|
|
124
|
+
# all translations for menu model from {MenuLocale}.
|
|
125
|
+
def before_destroy_sso_client_menu
|
|
126
|
+
if !self.can_destroy?
|
|
127
|
+
errors.add(:base, I18n.t('anubis.menus.errors.has_childs'))
|
|
128
|
+
throw(:abort, __method__)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
##
|
|
133
|
+
# Is called after menu was deleted from database. Procedure recalculates position of other menu elements.
|
|
134
|
+
def after_destroy_sso_client_menu
|
|
135
|
+
query = <<-SQL
|
|
136
|
+
UPDATE menus
|
|
137
|
+
SET menus.position = menus.position - 1
|
|
138
|
+
WHERE menus.tab = #{self.tab} AND menus.position > #{self.position}
|
|
139
|
+
SQL
|
|
140
|
+
Anubis::Sso::Client::Menu.connection.execute query
|
|
141
|
+
Anubis::Sso::Client::Menu.where(menu_id: self.id).find_each do |menu|
|
|
142
|
+
menu.destroy
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
class Anubis::Sso::Client::User < Anubis::Sso::Client::ApplicationRecord
|
|
2
|
+
self.table_name = 'users'
|
|
3
|
+
|
|
4
|
+
after_destroy :after_destroy_anubis_sso_client_user
|
|
5
|
+
after_save :after_save_anubis_sso_client_user
|
|
6
|
+
|
|
7
|
+
attr_accessor :name
|
|
8
|
+
attr_accessor :surname
|
|
9
|
+
attr_accessor :locale
|
|
10
|
+
attr_accessor :timeout
|
|
11
|
+
attr_accessor :timezone
|
|
12
|
+
attr_accessor :menus
|
|
13
|
+
|
|
14
|
+
def save_cache(sso_data)
|
|
15
|
+
if sso_data
|
|
16
|
+
self.name = sso_data[:name] if sso_data.key? :name
|
|
17
|
+
self.surname = sso_data[:surname] if sso_data.key? :surname
|
|
18
|
+
self.locale = sso_data[:locale] if sso_data.key? :locale
|
|
19
|
+
self.timeout = sso_data[:timeout] if sso_data.key? :timeout
|
|
20
|
+
self.timezone = sso_data[:timezone] if sso_data.key? :timezone
|
|
21
|
+
end
|
|
22
|
+
self.redis.set(self.redis_prefix + 'user:' + self.uuid, self.to_json) if self.redis
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def clear_cache
|
|
26
|
+
self.redis.del(self.redis_prefix + 'user:' + self.uuid) if self.redis
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.load_cache(redis, uuid)
|
|
30
|
+
begin
|
|
31
|
+
data = JSON.parse redis.get(User.redis_prefix + 'user:' + uuid), { symbolize_names: true }
|
|
32
|
+
rescue
|
|
33
|
+
data = nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
unless data
|
|
37
|
+
user = self.where(uuid: uuid).first
|
|
38
|
+
if user
|
|
39
|
+
return JSON.parse(user.to_json(except: [:password_digest]), { symbolize_names: true })
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
data
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def attributes
|
|
47
|
+
super.merge({
|
|
48
|
+
name: self.name,
|
|
49
|
+
surname: self.surname,
|
|
50
|
+
locale: self.locale,
|
|
51
|
+
timeout: self.timeout,
|
|
52
|
+
timezone: self.timezone,
|
|
53
|
+
menus: self.get_menus
|
|
54
|
+
})
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def after_save_anubis_sso_client_user
|
|
58
|
+
self.clear_cache
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def after_destroy_anubis_sso_client_user
|
|
62
|
+
self.clear_cache
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def get_menus
|
|
66
|
+
self.menus = {}
|
|
67
|
+
access = Anubis::Sso::Client::GroupMenu.accesses[:read].to_s+','+Anubis::Sso::Client::GroupMenu.accesses[:write].to_s
|
|
68
|
+
query = <<-SQL
|
|
69
|
+
SELECT `menus`.`id`, `menus`.`mode`, MAX(`group_menus`.`access`) AS `access`
|
|
70
|
+
FROM (`menus`, `group_menus`, `groups`, `user_groups`)
|
|
71
|
+
WHERE `menus`.`status` = 0 AND `menus`.`id` = `group_menus`.`menu_id` AND `group_menus`.`access` IN (#{access}) AND `group_menus`.`group_id` = `groups`.`id` AND
|
|
72
|
+
`groups`.`id` = `user_groups`.`group_id` AND `user_groups`.`user_id` = #{self.id}
|
|
73
|
+
GROUP BY `menus`.`id`, `menus`.`mode`
|
|
74
|
+
SQL
|
|
75
|
+
Anubis::Sso::Client::GroupMenu.find_by_sql(query).each do |data|
|
|
76
|
+
self.menus[data[:mode]] = data.access
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
self.menus
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
##
|
|
2
|
+
# UserGroup model. It links User and Group models.
|
|
3
|
+
class Anoubis::Sso::Client::UserGroup < Anoubis::Sso::Client::ApplicationRecord
|
|
4
|
+
self.table_name = 'user_groups'
|
|
5
|
+
|
|
6
|
+
before_update :before_update_sso_client_user_group
|
|
7
|
+
after_create :after_modify_sso_client_user_group
|
|
8
|
+
after_destroy :after_modify_sso_client_user_group
|
|
9
|
+
|
|
10
|
+
belongs_to :group, class_name: 'Anoubis::Sso::Client::Group'
|
|
11
|
+
validates :group, presence: true, uniqueness: { scope: [:user_id] }
|
|
12
|
+
belongs_to :user, class_name: 'Anoubis::Sso::Client::User'
|
|
13
|
+
validates :user, presence: true, uniqueness: { scope: [:group_id] }
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Can't change elements
|
|
17
|
+
def before_update_sso_client_user_group
|
|
18
|
+
self.user_id = self.user_id_was if self.user_id_changed?
|
|
19
|
+
self.group_id = self.group_id_was if self.group_id_changed?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Delete all redis keys of menu for defined user
|
|
24
|
+
def after_modify_sso_client_user_group
|
|
25
|
+
if self.redis
|
|
26
|
+
self.redis.keys(self.redis_prefix + self.user.uuid.to_s + '_*').each do |data|
|
|
27
|
+
self.redis.del data
|
|
28
|
+
end
|
|
29
|
+
self.redis.del self.redis_prefix + 'user:' + self.user.uuid.to_s
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class Anoubis::Sso::Server::System < Anoubis::Core::ApplicationRecord
|
|
2
|
+
self.table_name = 'systems'
|
|
3
|
+
|
|
4
|
+
before_validation :before_validation_anoubis_sso_server_system_on_create, on: :create
|
|
5
|
+
after_save :after_save_anoubis_sso_server_system
|
|
6
|
+
after_destroy :after_destroy_anoubis_sso_server_system
|
|
7
|
+
|
|
8
|
+
#VALID_HTTP_REGEX = /\A(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w\.-]*)*\/?\Z/i
|
|
9
|
+
|
|
10
|
+
validates :title, presence: true, length: { maximum: 100 }
|
|
11
|
+
validates :host, presence: true, length: { maximum: 200 }#, format: { with: VALID_HTTP_REGEX }
|
|
12
|
+
validates :uuid, presence: true, length: { maximum: 40 }, uniqueness: { case_sensitive: true }
|
|
13
|
+
|
|
14
|
+
enum status: { enabled: 0, disabled: 1 }
|
|
15
|
+
|
|
16
|
+
def before_validation_anoubis_sso_server_system_on_create
|
|
17
|
+
self.uuid = SecureRandom.uuid unless self.uuid
|
|
18
|
+
self.secret_key = SecureRandom.uuid unless self.secret_key
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def after_save_anoubis_sso_server_system
|
|
22
|
+
if self.status == 'enabled'
|
|
23
|
+
self.redis.set self.redis_cache_name, { host: self.host, secret_key: self.secret_key, callback: self.callback, silent: self.silent }.to_json
|
|
24
|
+
else
|
|
25
|
+
self.after_destroy_system
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def after_destroy_anubis_sso_server_system
|
|
30
|
+
self.redis.del self.redis_cache_name
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def redis_cache_name
|
|
34
|
+
self.redis_prefix + 'system:' + self.uuid
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
class Anubis::Sso::Server::User < Anubis::Core::ApplicationRecord
|
|
2
|
+
has_secure_password
|
|
3
|
+
|
|
4
|
+
self.table_name = 'users'
|
|
5
|
+
|
|
6
|
+
before_validation :before_validation_anubis_sso_server_user_on_create, on: :create
|
|
7
|
+
before_save :before_save_anubis_sso_server_user
|
|
8
|
+
after_destroy :after_destroy_anubis_sso_server_user
|
|
9
|
+
|
|
10
|
+
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
|
|
11
|
+
|
|
12
|
+
validates :login, presence: true, length: { maximum: 50 },
|
|
13
|
+
format: { with: VALID_EMAIL_REGEX },
|
|
14
|
+
uniqueness: { case_sensitive: true }
|
|
15
|
+
|
|
16
|
+
validates :name, presence: true, length: { maximum: 100 }
|
|
17
|
+
validates :surname, presence: true, length: { maximum: 100 }
|
|
18
|
+
|
|
19
|
+
validates :password, length: { in: 5..30 }, on: [:create]
|
|
20
|
+
validates :password, length: { in: 5..30 }, on: [:update], if: :password_changed?
|
|
21
|
+
validates :password_confirmation, length: { in: 5..30 }, on: [:create]
|
|
22
|
+
validates :password_confirmation, length: { in: 5..30 }, on: [:update], if: :password_changed?
|
|
23
|
+
|
|
24
|
+
validates :auth_key, length: { maximum: 32 }
|
|
25
|
+
|
|
26
|
+
validates :timeout, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 300 }
|
|
27
|
+
|
|
28
|
+
validates :uuid, presence: true, length: { maximum: 40 }, uniqueness: { case_sensitive: true }
|
|
29
|
+
|
|
30
|
+
enum status: { pending: 0, enabled: 1, disabled: 100 }
|
|
31
|
+
validates :status, inclusion: { in: self.statuses }
|
|
32
|
+
|
|
33
|
+
enum role: { user_role: 0, admin_role: 100 }
|
|
34
|
+
validates :role, inclusion: { in: self.roles }
|
|
35
|
+
|
|
36
|
+
def before_validation_anubis_sso_server_user_on_create
|
|
37
|
+
self.uuid = SecureRandom.uuid
|
|
38
|
+
self.timezone = 'GMT' if !self.timezone
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def before_save_anubis_sso_server_user
|
|
42
|
+
self.timezone = 'GMT' if !self.timezone
|
|
43
|
+
self.login = self.login.downcase
|
|
44
|
+
self.clear_cache
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def after_destroy_anubis_sso_server_user
|
|
48
|
+
self.clear_cache
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def save_cache
|
|
52
|
+
self.redis.set(self.redis_prefix + 'user:' + self.uuid, self.to_json(except: [:password_digest])) if self.redis
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def clear_cache
|
|
56
|
+
self.redis.del(self.redis_prefix + 'user:' + self.uuid) if self.redis
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def password_changed?
|
|
60
|
+
!password.blank?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.load_cache(redis, uuid)
|
|
64
|
+
begin
|
|
65
|
+
data = JSON.parse redis.get(User.redis_prefix + 'user:' + uuid), { symbolize_names: true }
|
|
66
|
+
rescue
|
|
67
|
+
data = nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
unless data
|
|
71
|
+
user = self.where(uuid: uuid).first
|
|
72
|
+
if user
|
|
73
|
+
return JSON.parse(user.to_json(except: [:password_digest]), { symbolize_names: true })
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
data
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Default ApplicationRecord for Anoubis::Core library.
|
|
3
|
+
class Anoubis::Tenant::ApplicationRecord < Anoubis::Core::ApplicationRecord
|
|
4
|
+
self.abstract_class = true
|
|
5
|
+
|
|
6
|
+
before_update :before_update_tenant_anoubis_model
|
|
7
|
+
before_create :before_create_tenant_anoubis_model
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Returns the default ActiveRecord 'where' for defined model.
|
|
11
|
+
# @param object [ApplicationController] pointer to used Application controller
|
|
12
|
+
# @param pid [Integer] parent model id if present (default: 0). Variable doesn't necessary
|
|
13
|
+
# @return [Hash] ActiveRecord 'where' definition
|
|
14
|
+
def self.get_where(object, pid = 0)
|
|
15
|
+
if self.has_attribute? :tenant_id
|
|
16
|
+
return { tenant_id: object.current_user.tenant_id }
|
|
17
|
+
else
|
|
18
|
+
return {}
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Is called before data will be updated in database. Prevents changing tenant
|
|
24
|
+
def before_update_tenant_anoubis_model
|
|
25
|
+
begin
|
|
26
|
+
self.tenant_id = self.tenant_id_was
|
|
27
|
+
rescue
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# Is called before data will be created in database. Sets tenant according by current user
|
|
34
|
+
def before_create_tenant_anoubis_model
|
|
35
|
+
begin
|
|
36
|
+
self.tenant_id = self.current_user.tenant_id
|
|
37
|
+
rescue
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Group model. Stores information about usser's groups
|
|
3
|
+
class Anoubis::Tenant::Group < Anoubis::Core::ApplicationRecord
|
|
4
|
+
# Redefines default table name
|
|
5
|
+
self.table_name = 'groups'
|
|
6
|
+
|
|
7
|
+
before_validation :before_validation_group_create, on: :create
|
|
8
|
+
before_validation :before_validation_group_update, on: :update
|
|
9
|
+
before_save :before_save_group
|
|
10
|
+
before_destroy :before_destroy_group
|
|
11
|
+
|
|
12
|
+
# Group's identifier consists of lowercase alphabetic symbols.
|
|
13
|
+
VALID_IDENT_REGEX = /[a-z]\z/i
|
|
14
|
+
|
|
15
|
+
# @!attribute ident
|
|
16
|
+
# @return [String] the group's identifier. Identifier consists of lowercase alphabetical symbols.
|
|
17
|
+
validates :ident, length: { minimum: 3, maximum: 50 }, uniqueness: { scope: [:system_id], case_sensitive: false }, format: { with: VALID_IDENT_REGEX }
|
|
18
|
+
|
|
19
|
+
# @!attribute full_ident
|
|
20
|
+
# @return [String] the calculated group's identification. This identification based on {System#ident} and {#ident}
|
|
21
|
+
|
|
22
|
+
# @!attribute system
|
|
23
|
+
# @return [System] reference to system that owns this group
|
|
24
|
+
belongs_to :system, class_name: 'Anoubis::Tenant::System'
|
|
25
|
+
|
|
26
|
+
has_many :group_menus, class_name: 'Anoubis::Tenant::GroupMenu'
|
|
27
|
+
has_many :user_groups, class_name: 'Anoubis::Tenant::UserGroup'
|
|
28
|
+
has_many :group_locales, class_name: 'Anoubis::Tenant::GroupLocale'
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Is called before validation when new group is being created. Sets {#ident} value as 'admin' and {#system}
|
|
32
|
+
# value to main system with id 1 if this is a first group.
|
|
33
|
+
def before_validation_group_create
|
|
34
|
+
if self.id
|
|
35
|
+
if self.id == 1
|
|
36
|
+
self.ident = 'admin'
|
|
37
|
+
self.system_id = 1
|
|
38
|
+
return true
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
##
|
|
44
|
+
# Is called before validation when group is being updated. Prevents changing {#ident} value when {#ident}
|
|
45
|
+
# value is 'admin'
|
|
46
|
+
def before_validation_group_update
|
|
47
|
+
if self.ident != self.ident_was && self.ident_was == 'admin'
|
|
48
|
+
errors.add(:ident, I18n.t('tims.groups.errors.cant_change_admin_ident'))
|
|
49
|
+
throw(:abort, __method__)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Is called before group will be stored in database. Changes {#ident} value to lower case.
|
|
55
|
+
def before_save_group
|
|
56
|
+
self.full_ident = self.system.ident+'.'+self.ident
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# Is called before group will be deleted from database. Checks the ability to destroy a group. Prevents deleting
|
|
61
|
+
# group with id 1. Also destroys all associated links to {User} and {Menu}
|
|
62
|
+
def before_destroy_group
|
|
63
|
+
# Can't destroy admin group of main system
|
|
64
|
+
if self.ident == 'admin' && self.system_id == 1
|
|
65
|
+
errors.add(:base, I18n.t('anubis.groups.errors.cant_destroy_admin_group'))
|
|
66
|
+
throw(:abort, __method__)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
Anoubis::Tenant::GroupLocale.where(group_id: self.id).each do |group_locale|
|
|
70
|
+
group_locale.destroy
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
unless user_groups.empty?
|
|
74
|
+
errors.add(:base, I18n.t('anubis.groups.errors.cant_destroy_group_with_users'))
|
|
75
|
+
throw(:abort, __method__)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Before destroy group delete all associated links to users and menus
|
|
79
|
+
Anoubis::Tenant::GroupMenu.where(group_id: self.id).delete_all
|
|
80
|
+
#Anoubis::Tenant::UserGroup.where(group_id: self.id).delete_all
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
# Returns model localization data from {GroupLocale}.
|
|
85
|
+
# @return [GroupLocale] localization for current group
|
|
86
|
+
def model_locale
|
|
87
|
+
@model_locale ||= self.group_locales.where(locale: Anoubis::Tenant::GroupLocale.locales[self.current_locale.to_sym]).first
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @!attribute title
|
|
91
|
+
# @return [String] the group's title. Title loads from {GroupLocale#title} based on {#current_locale}
|
|
92
|
+
def title
|
|
93
|
+
self.model_locale.title if self.model_locale
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Localization for {Group} model. Model stores all translations for {Group} model.
|
|
3
|
+
class Anoubis::Tenant::GroupLocale < Anoubis::Core::ApplicationRecord
|
|
4
|
+
# Redefines default table name
|
|
5
|
+
self.table_name = 'group_locales'
|
|
6
|
+
|
|
7
|
+
# @!attribute title
|
|
8
|
+
# @return [String] the group's localized title
|
|
9
|
+
validates :title, length: { minimum: 3, maximum: 100 }
|
|
10
|
+
|
|
11
|
+
# @!attribute menu
|
|
12
|
+
# @return [Group] reference to the {Group} model
|
|
13
|
+
belongs_to :group, :class_name => 'Anoubis::Tenant::Group'
|
|
14
|
+
validates :group, presence: true, uniqueness: { scope: [:locale] }
|
|
15
|
+
|
|
16
|
+
# @!attribute locale
|
|
17
|
+
# @return [Locales] reference to locale
|
|
18
|
+
enum locale: Anoubis::Core::Locales.enums
|
|
19
|
+
end
|