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.
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,84 @@
1
+ ##
2
+ # Model links {Menu} and {Group}. Describes group access to menu.
3
+ class Anoubis::Tenant::GroupMenu < Anoubis::Core::ApplicationRecord
4
+ # Redefines default table name
5
+ self.table_name = 'group_menus'
6
+
7
+ before_validation :before_validation_group_menu
8
+ after_create :after_create_group_menu
9
+ before_update :before_update_group_menu
10
+ after_destroy :after_destroy_group_menu
11
+
12
+
13
+ # @!attribute group
14
+ # @return [Group] reference to the {Group} model
15
+ belongs_to :group, :class_name => 'Anoubis::Tenant::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 => 'Anoubis::Tenant::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_group_menu
36
+ if !Anoubis::Tenant::SystemMenu.where(system_id: self.group.system_id, menu_id: self.menu_id).first
37
+ errors.add(:base, I18n.t('anubis.group_menus.errors.no_access'))
38
+ throw(:abort, __method__)
39
+ end
40
+ self.access = Anubis::Tenant::GroupMenu.accesses[:read] if !self.access
41
+ end
42
+
43
+ ##
44
+ # Is called after new link between menu and group was created. If new element has parent with link that
45
+ # doesn't present in database then adds this link to database with {#access} defined as 'read'.
46
+ def after_create_group_menu
47
+ if self.menu.menu_id != nil
48
+ Anubis::Tenant::GroupMenu.find_or_create_by(menu_id: self.menu.menu_id, group_id: self.group_id) do |menu|
49
+ menu.access = Anubis::Tenant::GroupMenu.accesses[:read]
50
+ end
51
+ end
52
+ self.after_modify_group_menu
53
+ end
54
+
55
+ ##
56
+ # Is called before link between menu and group will be updated. Procedure prevents changing {#menu}
57
+ # and {#group} value.
58
+ def before_update_group_menu
59
+ self.menu_id = self.menu_id_was if self.menu_id_changed?
60
+ self.group_id = self.group_id_was if self.group_id_changed?
61
+ self.after_modify_group_menu
62
+ end
63
+
64
+ ##
65
+ # Is called after link between menu and group had been deleted from database. It also deletes all child links.
66
+ def after_destroy_group_menu
67
+ Anubis::Tenant::Menu.select(:id).where(menu_id: self.menu_id).each do |menu|
68
+ Anubis::Tenant::GroupMenu.where(menu_id: menu.id, group_id: self.group_id).each do |group_menu|
69
+ group_menu.destroy
70
+ end
71
+ end
72
+ self.after_modify_group_menu
73
+ end
74
+
75
+ ##
76
+ # Deletes all user's keys that belong this menu element in Redis database.
77
+ def after_modify_group_menu
78
+ if self.redis
79
+ self.redis.keys(self.redis_prefix + '*_'+self.menu.mode).each do |data|
80
+ self.redis.del data
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,156 @@
1
+ ##
2
+ # Menu model. Stores information about all menu elements of the portal. Menu model defines the dependence
3
+ # between controller and user access.
4
+ class Anubis::Tenant::Menu < ApplicationRecord
5
+ # Redefines default table name
6
+ self.table_name = 'menus'
7
+
8
+ before_create :before_create_menu
9
+ before_update :before_update_menu
10
+ before_save :before_save_menu
11
+ before_destroy :before_destroy_menu
12
+ after_destroy :after_destroy_menu
13
+
14
+ # @!attribute mode
15
+ # @return [String] the controller path for menu element.
16
+ validates :mode, presence: true, uniqueness: true
17
+
18
+ # @!attribute action
19
+ # @return [String] the default action of menu element ('data', 'menu', etc.).
20
+ validates :action, presence: true
21
+
22
+ # @!attribute tab
23
+ # @return [Integer] the nesting level of menu element
24
+ validates :tab, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
25
+
26
+ # @!attribute position
27
+ # @return [Integer] the order position of menu element in current level.
28
+ validates :position, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
29
+
30
+ # @!attribute page_size
31
+ # @return [Integer] the default page size for table of data frame.
32
+ validates :page_size, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
33
+
34
+ # @!attribute menu
35
+ # @return [Menu, nil] the parent menu for element menu (if exists).
36
+ belongs_to :menu, class_name: 'Anubis::Tenant::Menu', optional: true
37
+ has_many :menus, class_name: 'Anubis::Tenant::Menu'
38
+
39
+ has_many :group_menus, class_name: 'Anubis::Tenant::GroupMenu'
40
+ has_many :system_menus, class_name: 'Anubis::Tenant::SystemMenu'
41
+ has_many :menu_locales, class_name: 'Anubis::Tenant::MenuLocale'
42
+
43
+ # @!attribute status
44
+ # @return ['enabled', 'disabled'] the status of menu element.
45
+ # - 'enabled' --- element is enabled and is used by the system.
46
+ # - 'disabled' --- element is disabled and isn't used by the system.
47
+ enum status: { enabled: 0, disabled: 1 }
48
+
49
+ # @!attribute state
50
+ # @return ['visible', 'hidden'] the visibility of menu element. Attribute is used in fronted application.
51
+ # - 'visible' --- element is visible.
52
+ # - 'hidden' --- element is hidden.
53
+ enum state: { visible: 0, hidden: 1 }
54
+
55
+ ##
56
+ # Is called before menu will be created in database. Sets {#position} as last {#position} + 1 on current {#tab}.
57
+ # After this calls {#before_update_menu} for additional modification.
58
+ def before_create_menu
59
+ data = Anubis::Tenant::Menu.where(menu_id: self.menu_id).maximum(:position)
60
+ self.position = if data then data + 1 else 0 end
61
+
62
+ self.before_update_menu
63
+ end
64
+
65
+ ##
66
+ # Is called before menu will be stored in database. Sets {#mode} and {#action} in lowercase. If {#page_size}
67
+ # doesn't defined then sets it to 20. If defined parent menu element then sets {#tab} based on {#tab} of
68
+ # parent menu element + 1.
69
+ def before_update_menu
70
+ self.mode = mode.downcase
71
+ self.action = self.action.downcase
72
+ self.page_size = 20 if !self.page_size
73
+ self.page_size = self.page_size.to_i
74
+
75
+ parent_menu = Anubis::Tenant::Menu.where(id: self.menu_id).first
76
+ if parent_menu
77
+ self.tab = parent_menu.tab + 1
78
+ else
79
+ self.tab = 0
80
+ end
81
+ end
82
+
83
+ ##
84
+ # Is called right before menu will be stored in database (after {#before_create_menu} and {#before_update_menu}).
85
+ # Deletes cache data for this menu in Redis database.
86
+ def before_save_menu
87
+ self.redis.del(self.redis_prefix + 'menu_' + self.mode) if self.redis
88
+ end
89
+
90
+ ##
91
+ # Is called before menu will be deleted from database. Checks the ability to destroy a menu. Delete
92
+ # all translations for menu model from {MenuLocale}.
93
+ def before_destroy_menu
94
+ Anubis::Tenant::MenuLocale.where(menu_id: self.id).each do |menu_locale|
95
+ menu_locale.destroy
96
+ end
97
+
98
+ if !can_destroy?
99
+ errors.add(:base, I18n.t('anubis.menus.errors.has_childs'))
100
+ throw(:abort, __method__)
101
+ end
102
+ #childs = !self.menus.empty?
103
+ #childs = !self.group_menus.empty? if !childs
104
+ #childs = !self.system_menus.empty? if !childs
105
+
106
+ #return if !childs
107
+
108
+ #errors.add(:base, I18n.t('menus.errors.has_childs'))
109
+ #throw(:abort, __method__)
110
+ end
111
+
112
+ ##
113
+ # Is called after menu was deleted from database. Procedure recalculates position of other menu elements.
114
+ def after_destroy_menu
115
+ query = <<-SQL
116
+ UPDATE menus
117
+ SET menus.position = menus.position - 1
118
+ WHERE menus.tab = #{self.tab} AND menus.position > #{self.position}
119
+ SQL
120
+ Anubis::Tenant::Menu.connection.execute query
121
+ #i = self.position
122
+ #Anubis::Tenant::Menu.where(menu_id: self.menu_id, position: (self.position+1..Float::INFINITY)).find_each do |menu|
123
+ # menu.position = i
124
+ # menu.save
125
+ # i += 1
126
+ # end
127
+ Anubis::Tenant::Menu.where(menu_id: self.id).find_each do |menu|
128
+ menu.destroy
129
+ end
130
+ end
131
+
132
+ ##
133
+ # Returns model localization data from {MenuLocale}.
134
+ # @return [MenuLocale] localization for current menu
135
+ def model_locale
136
+ @model_locale ||= self.menu_locales.where(locale: Anubis::Tenant::MenuLocale.locales[self.current_locale.to_sym]).first
137
+ end
138
+
139
+ # @!attribute title
140
+ # @return [String] the menu's title. Title loads from {MenuLocale#title} based on {#current_locale}
141
+ def title
142
+ self.model_locale.title if self.model_locale
143
+ end
144
+
145
+ # @!attribute page_title
146
+ # @return [String] the menu's page title. Page title loads from {MenuLocale#page_title} based on {#current_locale}
147
+ def page_title
148
+ self.model_locale.page_title if self.model_locale
149
+ end
150
+
151
+ # @!attribute short_title
152
+ # @return [String] the menu's short title. Short title loads from {MenuLocale#short_title} based on {#current_locale}
153
+ def short_title
154
+ self.model_locale.short_title if self.model_locale
155
+ end
156
+ end
@@ -0,0 +1,27 @@
1
+ ##
2
+ # Localization for {Menu} model. Model stores all translations for {Menu} model.
3
+ class Anoubis::Tenant::MenuLocale < Anoubis::Core::ApplicationRecord
4
+ # Redefines default table name
5
+ self.table_name = 'menu_locales'
6
+
7
+ # @!attribute menu
8
+ # @return [Menu] reference to the {Menu} model
9
+ belongs_to :menu, :class_name => 'Anoubis::Tenant::Menu'
10
+ validates :menu, presence: true, uniqueness: { scope: [:locale] }
11
+
12
+ # @!attribute title
13
+ # @return [String] the menu's localized title
14
+ validates :title, presence: true, length: { minimum: 3, maximum: 100 }
15
+
16
+ # @!attribute page_title
17
+ # @return [String] the menu's localized page title. Uses in frontend application.
18
+ validates :page_title, presence: true, length: { minimum: 3, maximum: 200 }
19
+
20
+ # @!attribute short_title
21
+ # @return [String] the menu's localized short title. Uses in frontend application.
22
+ validates :short_title, length: { maximum: 200 }
23
+
24
+ # @!attribute locale
25
+ # @return [Locales] reference to locale
26
+ enum locale: Anoubis::Core::Locales.enums
27
+ end
@@ -0,0 +1,127 @@
1
+ ##
2
+ # System model. Stores information about all portal's systems.
3
+ class Anoubis::Tenant::System < Anoubis::Core::ApplicationRecord
4
+ # Redefines default table name
5
+ self.table_name = 'systems'
6
+
7
+ before_validation :before_validation_system_create, on: :create
8
+ before_validation :before_validation_system_update, on: :update
9
+ after_create :after_create_system
10
+ before_save :before_save_system
11
+ after_update :after_update_system
12
+ before_destroy :before_destroy_system
13
+
14
+ # System's identifier consists of lowercase alphabetic symbols.
15
+ VALID_SYSTEM_REGEX = /[a-z]\z/i
16
+
17
+ # @!attribute ident
18
+ # @return [String] the system's identifier. Identifier consists of lowercase alphabetical symbols.
19
+ validates :ident, length: { minimum: 3, maximum: 15 }, uniqueness: true, format: { with: VALID_SYSTEM_REGEX }
20
+
21
+ has_many :tenant_systems, class_name: 'Anoubis::Tenant::TenantSystem'
22
+ has_many :groups, class_name: 'Anoubis::Tenant::Group'
23
+ has_many :system_menus, class_name: 'Anoubis::Tenant::SystemMenu'
24
+ has_many :system_locales, class_name: 'Anoubis::Tenant::SystemLocale'
25
+
26
+ ##
27
+ # Is called before validation when new system is being created. If it's a first system then it sets {#ident}
28
+ # value to 'sys'
29
+ def before_validation_system_create
30
+ if self.id
31
+ if self.id == 1
32
+ self.ident = 'sys'
33
+ return true
34
+ end
35
+ end
36
+ end
37
+
38
+ ##
39
+ # Is called before validation when system is being updated. Prevents the changing {#ident} value for
40
+ # system with id 1.
41
+ def before_validation_system_update
42
+ if self.id == 1 && self.ident_was != self.ident
43
+ errors.add(:ident, I18n.t('anubis.systems.errors.cant_change_ident'))
44
+ throw(:abort, __method__)
45
+ end
46
+ end
47
+
48
+ ##
49
+ # Is called after new system was created. Creates administration group for new system.
50
+ def after_create_system
51
+ if self.id == 1
52
+ data = Anoubis::Tenant::Group.create(id: 1)
53
+ I18n.available_locales.each do |locale|
54
+ I18n.locale = locale
55
+ Anoubis::Tenant::GroupLocale.find_or_create_by(group_id: data.id, locale: Anoubis::Tenant::MenuLocale.locales[locale.to_s.to_sym]) do |system_locale|
56
+ system_locale.title = I18n.t('anubis.install.admins_group')
57
+ end
58
+ end
59
+ else
60
+ data = Anoubis::Tenant::Group.find_or_create_by(ident: 'admin', system_id: self.id)
61
+ I18n.available_locales.each do |locale|
62
+ I18n.locale = locale
63
+ Anubis::Tenant::GroupLocale.find_or_create_by(group_id: data.id, locale: Anubis::Tenant::MenuLocale.locales[locale.to_s.to_sym]) do |system_locale|
64
+ system_locale.title = I18n.t('anubis.install.admins_group')
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Is called before system will be stored in database. Changes {#ident} value to lower case.
72
+ def before_save_system
73
+ self.ident = self.ident.downcase if self.ident
74
+ end
75
+
76
+ ##
77
+ # Is called after system had been updated. If {#ident} value had been changed then procedure updates
78
+ # every {Anubis::Group#full_ident} value.
79
+ def after_update_system
80
+ if self.ident_was != self.ident
81
+ update_groups_full_ident self.id, self.ident
82
+ end
83
+ end
84
+
85
+ ##
86
+ # Is called before system will be deleted from database. Checks the ability to destroy a system. Delete
87
+ # all translations for system model from {GroupLocale}.
88
+ def before_destroy_system
89
+ if self.id == 1
90
+ errors.add(:base, I18n.t('anubis.tenants.errors.cant_destroy'))
91
+ throw(:abort, __method__)
92
+ end
93
+
94
+ Anubis::Tenant::SystemLocale.where(system_id: self.id).each do |system_locale|
95
+ system_locale.destroy
96
+ end
97
+
98
+ if !can_destroy?
99
+ errors.add(:base, I18n.t('anubis.tenants.errors.has_childs'))
100
+ throw(:abort, __method__)
101
+ end
102
+ end
103
+
104
+ ##
105
+ # Updates {Group#full_ident} when changed system's identifier.
106
+ # @param id [Integer] group unique identifier
107
+ # @param ident [String] new system identifier
108
+ def update_groups_full_ident (id, ident)
109
+ query = <<-SQL
110
+ UPDATE groups SET groups.full_ident = CONCAT('#{ident}.', groups.ident) WHERE groups.system_id = #{id}
111
+ SQL
112
+ Anubis::Tenant::Group.connection.execute query
113
+ end
114
+
115
+ ##
116
+ # Returns model localization data from {SystemLocale}.
117
+ # @return [SystemLocale] localization for current system
118
+ def model_locale
119
+ @model_locale ||= self.system_locales.where(locale: Anubis::Tenant::SystemLocale.locales[self.current_locale.to_sym]).first
120
+ end
121
+
122
+ # @!attribute title
123
+ # @return [String] the system's title. Title loads from {SystemLocale#title} based on {#current_locale}
124
+ def title
125
+ self.model_locale.title if self.model_locale
126
+ end
127
+ end
@@ -0,0 +1,19 @@
1
+ ##
2
+ # Localization for {System} model. Model stores all translations for {System} model.
3
+ class Anoubis::Tenant::SystemLocale < Anoubis::Core::ApplicationRecord
4
+ # Redefines default table name
5
+ self.table_name = 'system_locales'
6
+
7
+ # @!attribute title
8
+ # @return [String] the system's localized title
9
+ validates :title, length: { minimum: 3, maximum: 100 }, uniqueness: { scope: [:system_id, :locale] }
10
+
11
+ # @!attribute system
12
+ # @return [System] reference to the {System} model
13
+ belongs_to :system, :class_name => 'Anoubis::Tenant::System'
14
+ validates :system, presence: true, uniqueness: { scope: [:locale] }
15
+
16
+ # @!attribute locale
17
+ # @return [Locales] reference to locale
18
+ enum locale: Anoubis::Core::Locales.enums
19
+ end
@@ -0,0 +1,51 @@
1
+ ##
2
+ # Model links menu and systems. Describes if system has access to menu.
3
+ class Anoubis::Tenant::SystemMenu < Anoubis::Core::ApplicationRecord
4
+ # Redefines default table name
5
+ self.table_name = 'system_menus'
6
+
7
+ after_create :after_create_system_menu
8
+ after_destroy :after_destroy_system_menu
9
+
10
+ # @!attribute system
11
+ # @return [System] reference to the {System} model
12
+ belongs_to :system, class_name: 'Anoubis::Tenant::System'
13
+ validates :system, presence: true, uniqueness: { scope: [:menu_id] }
14
+
15
+ # @!attribute menu
16
+ # @return [Menu] reference to the {Menu} model
17
+ belongs_to :menu, class_name: 'Anoubis::Tenant::Menu'
18
+ validates :menu, presence: true, uniqueness: { scope: [:system_id] }
19
+
20
+ ##
21
+ # Is called after create new link between system and menu. If created element has parent element and
22
+ # link to this parent element doesn't present in database then adds this link too.
23
+ def after_create_system_menu
24
+ if self.menu.menu_id != nil
25
+ Anoubis::Tenant::SystemMenu.find_or_create_by(menu: self.menu.menu, system: self.system)
26
+ end
27
+ end
28
+
29
+ ##
30
+ # Is called after link between system and menu was deleted from database. It also deletes all child links.
31
+ def after_destroy_system_menu
32
+ ids = []
33
+
34
+ Anoubis::Tenant::Menu.where(menu_id: self.menu_id).each do |data|
35
+ ids.push data.id
36
+ end
37
+
38
+ Anoubis::Tenant::SystemMenu.where(menu_id: ids, system_id: self.system_id).each do |data|
39
+ data.destroy
40
+ end
41
+
42
+ ids = []
43
+ Anoubis::Tenant::Group.where(system_id: self.system_id).each do |data|
44
+ ids.push data.id
45
+ end
46
+
47
+ Anoubis::Tenant::GroupMenu.where(menu_id: self.menu_id, group_id: ids).each do |data|
48
+ data.destroy
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,107 @@
1
+ ##
2
+ # Tenant model. Stores information about all portal's tenants.
3
+ class Anoubis::Tenant::Tenant < Anoubis::Core::ApplicationRecord
4
+ # Redefines default table name
5
+ self.table_name = 'tenants'
6
+
7
+ before_validation :before_validation_tenant_create, on: :create
8
+ before_validation :before_validation_tenant_update, on: :update
9
+ before_save :before_save_tenant
10
+ after_create :after_create_tenant
11
+ after_update :after_update_tenant
12
+ before_destroy :before_destroy_tenant
13
+
14
+ # Tenant's identifier consists of lowercase alphabetic symbols.
15
+ VALID_TENANT_REGEX = /[a-z]\z/i
16
+
17
+ # @!attribute ident
18
+ # @return [String] the tenant's identifier. Identifier consists of lowercase alphabetical symbols.
19
+ validates :ident, length: { minimum: 3, maximum: 10 }, uniqueness: true, format: { with: VALID_TENANT_REGEX }
20
+
21
+ # @!attribute title
22
+ # @return [String] the tenant's title
23
+ validates :title, length: { minimum: 5, maximum: 100 }, uniqueness: true
24
+
25
+ # @!attribute state
26
+ # @return ['standard', 'default'] the tenant's status.
27
+ # - 'default' --- tenant is marked as default (only one tenant may be default)
28
+ # - 'standard' --- tenant is marked as standard
29
+ enum state: { standard: 0, default: 1 }
30
+
31
+ has_many :tenant_systems, class_name: 'Anoubis::Tenant::TenantSystem'
32
+
33
+ ##
34
+ # Is called before validation when new tenant is being created. If it's a first tenant then it sets {#ident}
35
+ # value to 'sys'
36
+ def before_validation_tenant_create
37
+ if self.id
38
+ if self.id == 1
39
+ self.ident = 'sys'
40
+ return true
41
+ end
42
+ end
43
+ end
44
+
45
+ ##
46
+ # Is called before validation when tenant is being updated. Prevents the changing {#ident} value.
47
+ def before_validation_tenant_update
48
+ if self.id == 1 && self.ident != self.ident_was
49
+ errors.add(:ident, I18n.t('anubis.tenants.errors.cant_change_ident'))
50
+ throw(:abort, __method__)
51
+ end
52
+ end
53
+
54
+ ##
55
+ # Is called after new tenant was created. Adds access for this tenant to main system with id 1.
56
+ def after_create_tenant
57
+ Anoubis::Tenant::TenantSystem.find_or_create_by(tenant_id: self.id, system_id: 1) if self.id != 1
58
+ end
59
+
60
+ ##
61
+ # Is called after tenant had been updated. If {#ident} value had been changed then procedure updates
62
+ # every {Anoubis::User#login} value.
63
+ # Also if current tenant {#state} value had been set as 'default', then procedure sets {#state}
64
+ # value of all other tenants as 'standard'.
65
+ def after_update_tenant
66
+ if self.ident_was != self.ident
67
+ self.update_users_login self.id, self.ident
68
+ end
69
+
70
+ # If current tenant had been set as 'default', then sets all other tenants as 'standard'.
71
+ if self.state != self.state_was && self.state = 'default'
72
+ Anoubis::Tenant::Tenant.where(state: Anoubis::Tenant::Tenant.states[:default]).update_all(state: Anoubis::Tenant::Tenant.states[:standard])
73
+ end
74
+ end
75
+
76
+ ##
77
+ # Is called before tenant will be stored in database. Changes {#ident} value to lower case.
78
+ def before_save_tenant
79
+ self.ident = self.ident.downcase if self.ident
80
+ end
81
+
82
+ ##
83
+ # Is called before tenant will be deleted from database. Checks the ability to destroy a tenant.
84
+ def before_destroy_tenant
85
+ if self.id == 1
86
+ errors.add(:base, I18n.t('anubis.tenants.errors.cant_destroy'))
87
+ throw(:abort, __method__)
88
+ end
89
+
90
+ if !can_destroy?
91
+ errors.add(:base, I18n.t('anubis.tenants.errors.has_childs'))
92
+ throw(:abort, __method__)
93
+ end
94
+ end
95
+
96
+ ##
97
+ # Changes every {User#login} value based on {#ident} value. Procedure makes direct update
98
+ # in database and doesn't call any callbacks of {Anoubis::Tenant::User} model.
99
+ # @param id [Integer] user unique identifier
100
+ # @param ident [String] new tenant identifier
101
+ def update_users_login (id, ident)
102
+ query = <<-SQL
103
+ UPDATE users SET users.login = CONCAT(users.email, '.#{ident}') WHERE users.tenant_id = #{id}
104
+ SQL
105
+ Anoubis::Tenant::User.connection.execute query
106
+ end
107
+ end
@@ -0,0 +1,19 @@
1
+ ##
2
+ # Model for links Tenant and System models
3
+ class Anoubis::Tenant::TenantSystem < ApplicationRecord
4
+ self.table_name = 'tenant_systems'
5
+
6
+ before_update :before_update_tenant_system
7
+
8
+ belongs_to :tenant, class_name: 'Anoubis::Tenant::Tenant'
9
+ validates :tenant, presence: true, uniqueness: { scope: [:system_id] }
10
+ belongs_to :system, class_name: 'Anoubis::Tenant::System'
11
+ validates :system, presence: true, uniqueness: { scope: [:tenant_id] }
12
+
13
+ ##
14
+ # Checks before update data in model. Prevents from changing element data
15
+ def before_update_tenant_system
16
+ self.tenant_id = self.tenant_id_was if self.tenant_id_changed?
17
+ self.system_id = self.system_id_was if self.system_id_changed?
18
+ end
19
+ end