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