anoubis 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +38 -0
  5. data/app/controllers/anoubis/application_controller.rb +78 -0
  6. data/app/controllers/anoubis/core/application_controller.rb +343 -0
  7. data/app/controllers/anoubis/core/data/actions.rb +962 -0
  8. data/app/controllers/anoubis/core/data/callbacks.rb +68 -0
  9. data/app/controllers/anoubis/core/data/convert.rb +407 -0
  10. data/app/controllers/anoubis/core/data/defaults.rb +217 -0
  11. data/app/controllers/anoubis/core/data/get.rb +531 -0
  12. data/app/controllers/anoubis/core/data/load.rb +89 -0
  13. data/app/controllers/anoubis/core/data/set.rb +49 -0
  14. data/app/controllers/anoubis/core/data/setup.rb +104 -0
  15. data/app/controllers/anoubis/core/data_controller.rb +28 -0
  16. data/app/controllers/anoubis/core/index/actions.rb +53 -0
  17. data/app/controllers/anoubis/core/index/callbacks.rb +23 -0
  18. data/app/controllers/anoubis/core/index_controller.rb +36 -0
  19. data/app/controllers/anoubis/etc/base.rb +52 -0
  20. data/app/controllers/anoubis/etc/data.rb +89 -0
  21. data/app/controllers/anoubis/etc/field.rb +468 -0
  22. data/app/controllers/anoubis/etc/field_options.rb +83 -0
  23. data/app/controllers/anoubis/etc/field_order.rb +51 -0
  24. data/app/controllers/anoubis/etc/filter.rb +251 -0
  25. data/app/controllers/anoubis/etc/menu.rb +101 -0
  26. data/app/controllers/anoubis/etc/model.rb +67 -0
  27. data/app/controllers/anoubis/etc/tab_item.rb +91 -0
  28. data/app/controllers/anoubis/etc.rb +8 -0
  29. data/app/controllers/anoubis/export.rb +47 -0
  30. data/app/controllers/anoubis/output/autocomplete.rb +30 -0
  31. data/app/controllers/anoubis/output/basic.rb +86 -0
  32. data/app/controllers/anoubis/output/data.rb +101 -0
  33. data/app/controllers/anoubis/output/delete.rb +41 -0
  34. data/app/controllers/anoubis/output/edit.rb +55 -0
  35. data/app/controllers/anoubis/output/frame.rb +227 -0
  36. data/app/controllers/anoubis/output/login.rb +71 -0
  37. data/app/controllers/anoubis/output/menu.rb +220 -0
  38. data/app/controllers/anoubis/output/update.rb +43 -0
  39. data/app/controllers/anoubis/sso/client/application_controller.rb +139 -0
  40. data/app/controllers/anoubis/sso/client/data/actions.rb +5 -0
  41. data/app/controllers/anoubis/sso/client/data/callbacks.rb +5 -0
  42. data/app/controllers/anoubis/sso/client/data/convert.rb +5 -0
  43. data/app/controllers/anoubis/sso/client/data/defaults.rb +5 -0
  44. data/app/controllers/anoubis/sso/client/data/get.rb +5 -0
  45. data/app/controllers/anoubis/sso/client/data/load.rb +26 -0
  46. data/app/controllers/anoubis/sso/client/data/set.rb +5 -0
  47. data/app/controllers/anoubis/sso/client/data/setup.rb +5 -0
  48. data/app/controllers/anoubis/sso/client/data_controller.rb +21 -0
  49. data/app/controllers/anoubis/sso/client/index/actions.rb +79 -0
  50. data/app/controllers/anoubis/sso/client/index/callbacks.rb +13 -0
  51. data/app/controllers/anoubis/sso/client/index_controller.rb +18 -0
  52. data/app/controllers/anoubis/sso/server/application_controller.rb +49 -0
  53. data/app/controllers/anoubis/sso/server/login_controller.rb +342 -0
  54. data/app/controllers/anoubis/sso/server/user_controller.rb +142 -0
  55. data/app/controllers/anoubis/tenant/application_controller.rb +54 -0
  56. data/app/controllers/anoubis/tenant/data/actions.rb +11 -0
  57. data/app/controllers/anoubis/tenant/data/callbacks.rb +11 -0
  58. data/app/controllers/anoubis/tenant/data/convert.rb +11 -0
  59. data/app/controllers/anoubis/tenant/data/defaults.rb +11 -0
  60. data/app/controllers/anoubis/tenant/data/get.rb +11 -0
  61. data/app/controllers/anoubis/tenant/data/load.rb +52 -0
  62. data/app/controllers/anoubis/tenant/data/set.rb +11 -0
  63. data/app/controllers/anoubis/tenant/data/setup.rb +11 -0
  64. data/app/controllers/anoubis/tenant/data_controller.rb +28 -0
  65. data/app/controllers/anoubis/tenant/index/actions.rb +191 -0
  66. data/app/controllers/anoubis/tenant/index/callbacks.rb +11 -0
  67. data/app/controllers/anoubis/tenant/index_controller.rb +38 -0
  68. data/app/controllers/anoubis/tenants_controller.rb +7 -0
  69. data/app/controllers/anoubis/users_controller.rb +7 -0
  70. data/app/jobs/anoubis/application_job.rb +6 -0
  71. data/app/mailers/anoubis/application_mailer.rb +8 -0
  72. data/app/models/anoubis/application_record.rb +45 -0
  73. data/app/models/anoubis/core/application_record.rb +250 -0
  74. data/app/models/anoubis/core/locales.rb +27 -0
  75. data/app/models/anoubis/sso/client/application_record.rb +3 -0
  76. data/app/models/anoubis/sso/client/group.rb +19 -0
  77. data/app/models/anoubis/sso/client/group_menu.rb +109 -0
  78. data/app/models/anoubis/sso/client/menu.rb +145 -0
  79. data/app/models/anoubis/sso/client/user.rb +81 -0
  80. data/app/models/anoubis/sso/client/user_group.rb +32 -0
  81. data/app/models/anoubis/sso/server/system.rb +36 -0
  82. data/app/models/anoubis/sso/server/user.rb +79 -0
  83. data/app/models/anoubis/tenant/application_record.rb +41 -0
  84. data/app/models/anoubis/tenant/group.rb +95 -0
  85. data/app/models/anoubis/tenant/group_locale.rb +19 -0
  86. data/app/models/anoubis/tenant/group_menu.rb +84 -0
  87. data/app/models/anoubis/tenant/menu.rb +156 -0
  88. data/app/models/anoubis/tenant/menu_locale.rb +27 -0
  89. data/app/models/anoubis/tenant/system.rb +127 -0
  90. data/app/models/anoubis/tenant/system_locale.rb +19 -0
  91. data/app/models/anoubis/tenant/system_menu.rb +51 -0
  92. data/app/models/anoubis/tenant/tenant.rb +107 -0
  93. data/app/models/anoubis/tenant/tenant_system.rb +19 -0
  94. data/app/models/anoubis/tenant/user.rb +225 -0
  95. data/app/models/anoubis/tenant/user_group.rb +32 -0
  96. data/app/services/anoubis/core_service.rb +16 -0
  97. data/app/services/anoubis/session_service.rb +17 -0
  98. data/app/validators/presence_in_tenant_validator.rb +20 -0
  99. data/config/initializers/mime_type.rb +1 -0
  100. data/config/locales/en.yml +120 -0
  101. data/config/locales/ru.yml +245 -0
  102. data/config/routes.rb +74 -0
  103. data/db/migrate/20181018085843_create_tenants.rb +13 -0
  104. data/db/migrate/20181018111217_create_systems.rb +10 -0
  105. data/db/migrate/20181018111713_create_tenant_systems.rb +11 -0
  106. data/db/migrate/20181018111925_create_groups.rb +13 -0
  107. data/db/migrate/20181018112151_create_users.rb +25 -0
  108. data/db/migrate/20181018115737_add_title_to_users.rb +10 -0
  109. data/db/migrate/20181022060211_create_menus.rb +18 -0
  110. data/db/migrate/20181115055245_create_group_menus.rb +12 -0
  111. data/db/migrate/20181115060830_create_system_menus.rb +11 -0
  112. data/db/migrate/20181122062131_create_user_groups.rb +11 -0
  113. data/db/migrate/20181221060727_create_menu_locales.rb +14 -0
  114. data/db/migrate/20181225062303_create_system_locales.rb +11 -0
  115. data/db/migrate/20181225062339_create_group_locales.rb +11 -0
  116. data/db/seeds.rb +268 -0
  117. data/lib/anoubis/engine.rb +13 -0
  118. data/lib/anoubis/version.rb +5 -0
  119. data/lib/anoubis.rb +213 -0
  120. data/lib/tasks/anubis_tasks.rake +10 -0
  121. data/lib/tasks/sessions/clear_sessions.rake +10 -0
  122. data/spec/anubis_spec.rb +5 -0
  123. data/spec/controllers/anoubis/index_controller_spec.rb +77 -0
  124. data/spec/dummy/Rakefile +3 -0
  125. data/spec/dummy/app/assets/config/manifest.js +2 -0
  126. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  127. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  128. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  129. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  130. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  131. data/spec/dummy/app/jobs/application_job.rb +2 -0
  132. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  133. data/spec/dummy/app/models/application_record.rb +3 -0
  134. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  135. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  136. data/spec/dummy/bin/bundle +3 -0
  137. data/spec/dummy/bin/rails +4 -0
  138. data/spec/dummy/bin/rake +4 -0
  139. data/spec/dummy/bin/setup +33 -0
  140. data/spec/dummy/bin/update +28 -0
  141. data/spec/dummy/config/application.rb +14 -0
  142. data/spec/dummy/config/boot.rb +5 -0
  143. data/spec/dummy/config/cable.yml +10 -0
  144. data/spec/dummy/config/database.yml +54 -0
  145. data/spec/dummy/config/environment.rb +5 -0
  146. data/spec/dummy/config/environments/development.rb +54 -0
  147. data/spec/dummy/config/environments/production.rb +85 -0
  148. data/spec/dummy/config/environments/test.rb +46 -0
  149. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  150. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  151. data/spec/dummy/config/initializers/cors.rb +16 -0
  152. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  153. data/spec/dummy/config/initializers/inflections.rb +16 -0
  154. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  155. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  156. data/spec/dummy/config/locales/en.yml +33 -0
  157. data/spec/dummy/config/puma.rb +34 -0
  158. data/spec/dummy/config/routes.rb +3 -0
  159. data/spec/dummy/config/spring.rb +6 -0
  160. data/spec/dummy/config/storage.yml +34 -0
  161. data/spec/dummy/config.ru +5 -0
  162. data/spec/dummy/db/schema.rb +167 -0
  163. data/spec/dummy/db/seeds.rb +1 -0
  164. data/spec/factories/anubis_group_locales.rb +7 -0
  165. data/spec/factories/anubis_group_menus.rb +7 -0
  166. data/spec/factories/anubis_groups.rb +6 -0
  167. data/spec/factories/anubis_menu_locales.rb +9 -0
  168. data/spec/factories/anubis_menus.rb +6 -0
  169. data/spec/factories/anubis_system_locales.rb +7 -0
  170. data/spec/factories/anubis_system_menus.rb +6 -0
  171. data/spec/factories/anubis_systems.rb +5 -0
  172. data/spec/factories/anubis_tenants.rb +7 -0
  173. data/spec/factories/anubis_users.rb +10 -0
  174. data/spec/integration/navigation_test.rb +7 -0
  175. data/spec/models/anoubis/group_locale_spec.rb +25 -0
  176. data/spec/models/anoubis/group_menu_spec.rb +50 -0
  177. data/spec/models/anoubis/group_spec.rb +52 -0
  178. data/spec/models/anoubis/menu_locale_spec.rb +31 -0
  179. data/spec/models/anoubis/menu_spec.rb +48 -0
  180. data/spec/models/anoubis/system_locale_spec.rb +20 -0
  181. data/spec/models/anoubis/system_menu_spec.rb +49 -0
  182. data/spec/models/anoubis/system_spec.rb +53 -0
  183. data/spec/models/anoubis/tenant_spec.rb +67 -0
  184. data/spec/models/anoubis/user_spec.rb +57 -0
  185. data/spec/rails_helper.rb +32 -0
  186. data/spec/requests/anoubis/users_request_spec.rb +5 -0
  187. data/spec/spec_helper.rb +13 -0
  188. 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