incline 0.1.5

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 (303) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +186 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +208 -0
  7. data/Rakefile +37 -0
  8. data/app/assets/fonts/incline/.keep +0 -0
  9. data/app/assets/images/incline/.keep +0 -0
  10. data/app/assets/images/incline/barcode-B.svg +181 -0
  11. data/app/assets/javascripts/incline/activate_classed_items.js +11 -0
  12. data/app/assets/javascripts/incline/application.js +30 -0
  13. data/app/assets/javascripts/incline/bootstrap-datepicker.js +1800 -0
  14. data/app/assets/javascripts/incline/datatables.js +22193 -0
  15. data/app/assets/javascripts/incline/escapeHtml.js +10 -0
  16. data/app/assets/javascripts/incline/inline_actions.js +479 -0
  17. data/app/assets/javascripts/incline/jquery.doubleScroll.js +112 -0
  18. data/app/assets/javascripts/incline/jquery.number.js +764 -0
  19. data/app/assets/javascripts/incline/regexMask.js +27 -0
  20. data/app/assets/javascripts/incline/select2/i18n/en.js +3 -0
  21. data/app/assets/javascripts/incline/select2/select2.full.js +6436 -0
  22. data/app/assets/stylesheets/incline/application.css +18 -0
  23. data/app/assets/stylesheets/incline/bootstrap-theme.min.css +5 -0
  24. data/app/assets/stylesheets/incline/custom.scss +279 -0
  25. data/app/assets/stylesheets/incline/datatables.css +494 -0
  26. data/app/assets/stylesheets/incline/datepicker3.css +790 -0
  27. data/app/assets/stylesheets/incline/select2.css +484 -0
  28. data/app/controllers/incline/access_groups_controller.rb +127 -0
  29. data/app/controllers/incline/access_test_controller.rb +30 -0
  30. data/app/controllers/incline/account_activations_controller.rb +28 -0
  31. data/app/controllers/incline/application_controller.rb +11 -0
  32. data/app/controllers/incline/contact_controller.rb +34 -0
  33. data/app/controllers/incline/password_resets_controller.rb +113 -0
  34. data/app/controllers/incline/security_controller.rb +100 -0
  35. data/app/controllers/incline/sessions_controller.rb +50 -0
  36. data/app/controllers/incline/users_controller.rb +304 -0
  37. data/app/controllers/incline/welcome_controller.rb +19 -0
  38. data/app/helpers/incline/.keep +0 -0
  39. data/app/mailers/incline/application_mailer_base.rb +11 -0
  40. data/app/mailers/incline/contact_form.rb +19 -0
  41. data/app/mailers/incline/user_mailer.rb +45 -0
  42. data/app/models/incline/access_group.rb +121 -0
  43. data/app/models/incline/access_group_group_member.rb +12 -0
  44. data/app/models/incline/access_group_user_member.rb +10 -0
  45. data/app/models/incline/action_group.rb +12 -0
  46. data/app/models/incline/action_security.rb +222 -0
  47. data/app/models/incline/contact_message.rb +37 -0
  48. data/app/models/incline/disable_info.rb +20 -0
  49. data/app/models/incline/password_reset.rb +14 -0
  50. data/app/models/incline/password_reset_request.rb +14 -0
  51. data/app/models/incline/user.rb +437 -0
  52. data/app/models/incline/user_login_history.rb +30 -0
  53. data/app/views/incline/access_groups/_details.json.jbuilder +10 -0
  54. data/app/views/incline/access_groups/_form.html.erb +19 -0
  55. data/app/views/incline/access_groups/_list.html.erb +60 -0
  56. data/app/views/incline/access_groups/_messages.json.jbuilder +6 -0
  57. data/app/views/incline/access_groups/edit.html.erb +2 -0
  58. data/app/views/incline/access_groups/index.html.erb +6 -0
  59. data/app/views/incline/access_groups/index.json.jbuilder +16 -0
  60. data/app/views/incline/access_groups/new.html.erb +2 -0
  61. data/app/views/incline/access_groups/show.html.erb +9 -0
  62. data/app/views/incline/access_groups/show.json.jbuilder +11 -0
  63. data/app/views/incline/contact/new.html.erb +22 -0
  64. data/app/views/incline/contact_form/contact.html.erb +16 -0
  65. data/app/views/incline/contact_form/contact.text.erb +13 -0
  66. data/app/views/incline/password_resets/edit.html.erb +16 -0
  67. data/app/views/incline/password_resets/new.html.erb +12 -0
  68. data/app/views/incline/security/_details.json.jbuilder +7 -0
  69. data/app/views/incline/security/_form.html.erb +20 -0
  70. data/app/views/incline/security/_list.html.erb +89 -0
  71. data/app/views/incline/security/_messages.json.jbuilder +6 -0
  72. data/app/views/incline/security/edit.html.erb +2 -0
  73. data/app/views/incline/security/index.html.erb +6 -0
  74. data/app/views/incline/security/index.json.jbuilder +16 -0
  75. data/app/views/incline/security/show.html.erb +31 -0
  76. data/app/views/incline/security/show.json.jbuilder +11 -0
  77. data/app/views/incline/sessions/new.html.erb +26 -0
  78. data/app/views/incline/user_mailer/account_activation.html.erb +7 -0
  79. data/app/views/incline/user_mailer/account_activation.text.erb +6 -0
  80. data/app/views/incline/user_mailer/invalid_password_reset.html.erb +3 -0
  81. data/app/views/incline/user_mailer/invalid_password_reset.text.erb +5 -0
  82. data/app/views/incline/user_mailer/password_reset.html.erb +8 -0
  83. data/app/views/incline/user_mailer/password_reset.text.erb +7 -0
  84. data/app/views/incline/users/_details.json.jbuilder +32 -0
  85. data/app/views/incline/users/_form.html.erb +21 -0
  86. data/app/views/incline/users/_list.html.erb +102 -0
  87. data/app/views/incline/users/_messages.json.jbuilder +6 -0
  88. data/app/views/incline/users/disable_confirm.html.erb +19 -0
  89. data/app/views/incline/users/edit.html.erb +5 -0
  90. data/app/views/incline/users/index.html.erb +6 -0
  91. data/app/views/incline/users/index.json.jbuilder +16 -0
  92. data/app/views/incline/users/new.html.erb +5 -0
  93. data/app/views/incline/users/show.html.erb +12 -0
  94. data/app/views/incline/users/show.json.jbuilder +11 -0
  95. data/app/views/incline/welcome/home.html.erb +5 -0
  96. data/app/views/layouts/application.html.erb +1 -0
  97. data/app/views/layouts/incline/_account_menu.html.erb +18 -0
  98. data/app/views/layouts/incline/_app_menu_anon.html.erb +1 -0
  99. data/app/views/layouts/incline/_app_menu_authenticated.html.erb +1 -0
  100. data/app/views/layouts/incline/_footer.html.erb +13 -0
  101. data/app/views/layouts/incline/_header.html.erb +21 -0
  102. data/app/views/layouts/incline/_html_mailer.html.erb +5 -0
  103. data/app/views/layouts/incline/_incline_app.html.erb +25 -0
  104. data/app/views/layouts/incline/_messages.html.erb +3 -0
  105. data/app/views/layouts/incline/_shim.html.erb +3 -0
  106. data/app/views/layouts/incline/_text_mailer.text.erb +1 -0
  107. data/app/views/layouts/incline/application.html.erb +1 -0
  108. data/app/views/layouts/mailer.html.erb +2 -0
  109. data/app/views/layouts/mailer.text.erb +2 -0
  110. data/bin/rails +12 -0
  111. data/bin/test_scaffold.sh +10 -0
  112. data/config/routes.rb +61 -0
  113. data/db/migrate/20170511230126_create_incline_users.rb +26 -0
  114. data/db/migrate/20170515003052_create_incline_access_groups.rb +10 -0
  115. data/db/migrate/20170515003221_create_incline_user_login_histories.rb +12 -0
  116. data/db/migrate/20170515150908_create_incline_access_group_user_members.rb +11 -0
  117. data/db/migrate/20170515151058_create_incline_access_group_group_members.rb +11 -0
  118. data/db/migrate/20170517193432_add_comments_to_incline_user.rb +5 -0
  119. data/db/migrate/20170622132700_create_incline_action_securities.rb +16 -0
  120. data/db/migrate/20170622172712_create_incline_action_groups.rb +11 -0
  121. data/db/migrate/20170622195742_add_non_standard_to_action_security.rb +5 -0
  122. data/db/migrate/20170622230422_add_visible_to_action_security.rb +5 -0
  123. data/db/seeds.rb +81 -0
  124. data/exe/new_incline_app +42 -0
  125. data/lib/generators/incline/install_generator.rb +259 -0
  126. data/lib/generators/incline/templates/_app_menu_anon.html.erb +1 -0
  127. data/lib/generators/incline/templates/_app_menu_authenticated.html.erb +1 -0
  128. data/lib/generators/incline/templates/incline_application.css +17 -0
  129. data/lib/generators/incline/templates/incline_application.html.erb +1 -0
  130. data/lib/generators/incline/templates/incline_application.js +12 -0
  131. data/lib/generators/incline/templates/incline_database.yml +25 -0
  132. data/lib/generators/incline/templates/incline_email.yml +20 -0
  133. data/lib/generators/incline/templates/incline_mailer.html.erb +2 -0
  134. data/lib/generators/incline/templates/incline_mailer.text.erb +2 -0
  135. data/lib/generators/incline/templates/incline_users.yml +64 -0
  136. data/lib/generators/incline/templates/incline_version.rb +3 -0
  137. data/lib/incline/auth_engine_base.rb +52 -0
  138. data/lib/incline/data_tables_request.rb +336 -0
  139. data/lib/incline/date_time_formats.rb +6 -0
  140. data/lib/incline/engine.rb +212 -0
  141. data/lib/incline/errors.rb +15 -0
  142. data/lib/incline/extensions/action_controller_base.rb +526 -0
  143. data/lib/incline/extensions/action_mailer_base.rb +66 -0
  144. data/lib/incline/extensions/action_view_base.rb +489 -0
  145. data/lib/incline/extensions/active_record_base.rb +308 -0
  146. data/lib/incline/extensions/application.rb +137 -0
  147. data/lib/incline/extensions/application_configuration.rb +50 -0
  148. data/lib/incline/extensions/connection_adapter.rb +55 -0
  149. data/lib/incline/extensions/date_time_value.rb +123 -0
  150. data/lib/incline/extensions/date_value.rb +77 -0
  151. data/lib/incline/extensions/decimal_value.rb +55 -0
  152. data/lib/incline/extensions/erb_scaffold_generator.rb +31 -0
  153. data/lib/incline/extensions/float_value.rb +59 -0
  154. data/lib/incline/extensions/form_builder.rb +617 -0
  155. data/lib/incline/extensions/integer_value.rb +54 -0
  156. data/lib/incline/extensions/jbuilder_generator.rb +38 -0
  157. data/lib/incline/extensions/jbuilder_template.rb +39 -0
  158. data/lib/incline/extensions/main_app.rb +40 -0
  159. data/lib/incline/extensions/numeric.rb +63 -0
  160. data/lib/incline/extensions/object.rb +31 -0
  161. data/lib/incline/extensions/resource_route_generator.rb +53 -0
  162. data/lib/incline/extensions/session.rb +113 -0
  163. data/lib/incline/extensions/string.rb +50 -0
  164. data/lib/incline/extensions/test_case.rb +764 -0
  165. data/lib/incline/extensions/time_zone_converter.rb +40 -0
  166. data/lib/incline/global_status.rb +236 -0
  167. data/lib/incline/helpers/route_hash_formatter.rb +46 -0
  168. data/lib/incline/json_log_formatter.rb +96 -0
  169. data/lib/incline/json_logger.rb +17 -0
  170. data/lib/incline/log.rb +153 -0
  171. data/lib/incline/number_formats.rb +17 -0
  172. data/lib/incline/recaptcha.rb +346 -0
  173. data/lib/incline/user_manager.rb +212 -0
  174. data/lib/incline/validators/email_validator.rb +45 -0
  175. data/lib/incline/validators/ip_address_validator.rb +32 -0
  176. data/lib/incline/validators/recaptcha_validator.rb +37 -0
  177. data/lib/incline/validators/safe_name_validator.rb +31 -0
  178. data/lib/incline/version.rb +3 -0
  179. data/lib/incline/work_path.rb +75 -0
  180. data/lib/incline.rb +197 -0
  181. data/lib/tasks/incline_tasks.rake +4 -0
  182. data/lib/templates/erb/scaffold/_form.html.erb +43 -0
  183. data/lib/templates/erb/scaffold/_list.html.erb +81 -0
  184. data/lib/templates/erb/scaffold/edit.html.erb +1 -0
  185. data/lib/templates/erb/scaffold/index.html.erb +6 -0
  186. data/lib/templates/erb/scaffold/new.html.erb +1 -0
  187. data/lib/templates/erb/scaffold/show.html.erb +34 -0
  188. data/lib/templates/jbuilder/scaffold/_details.json.jbuilder +20 -0
  189. data/lib/templates/jbuilder/scaffold/index.json.jbuilder +16 -0
  190. data/lib/templates/jbuilder/scaffold/show.json.jbuilder +16 -0
  191. data/lib/templates/rails/scaffold_controller/controller.rb +128 -0
  192. data/test/controllers/incline/access_groups_controller_test.rb +65 -0
  193. data/test/controllers/incline/access_test_controller_test.rb +53 -0
  194. data/test/controllers/incline/contact_controller_test.rb +32 -0
  195. data/test/controllers/incline/security_controller_test.rb +39 -0
  196. data/test/controllers/incline/welcome_controller_test.rb +16 -0
  197. data/test/dummy/README.rdoc +28 -0
  198. data/test/dummy/Rakefile +6 -0
  199. data/test/dummy/app/assets/images/.keep +0 -0
  200. data/test/dummy/app/assets/javascripts/application.js +12 -0
  201. data/test/dummy/app/assets/stylesheets/application.css +17 -0
  202. data/test/dummy/app/controllers/application_controller.rb +5 -0
  203. data/test/dummy/app/controllers/concerns/.keep +0 -0
  204. data/test/dummy/app/helpers/application_helper.rb +2 -0
  205. data/test/dummy/app/mailers/.keep +0 -0
  206. data/test/dummy/app/models/.keep +0 -0
  207. data/test/dummy/app/models/concerns/.keep +0 -0
  208. data/test/dummy/app/views/layouts/application.html.erb +1 -0
  209. data/test/dummy/app/views/layouts/incline/_app_menu_anon.html.erb +1 -0
  210. data/test/dummy/app/views/layouts/incline/_app_menu_authenticated.html.erb +1 -0
  211. data/test/dummy/app/views/layouts/mailer.html.erb +2 -0
  212. data/test/dummy/app/views/layouts/mailer.text.erb +2 -0
  213. data/test/dummy/bin/bundle +3 -0
  214. data/test/dummy/bin/rails +4 -0
  215. data/test/dummy/bin/rake +4 -0
  216. data/test/dummy/bin/setup +29 -0
  217. data/test/dummy/config/application.rb +38 -0
  218. data/test/dummy/config/boot.rb +5 -0
  219. data/test/dummy/config/database.yml +34 -0
  220. data/test/dummy/config/email.yml +24 -0
  221. data/test/dummy/config/environment.rb +5 -0
  222. data/test/dummy/config/environments/development.rb +45 -0
  223. data/test/dummy/config/environments/production.rb +85 -0
  224. data/test/dummy/config/environments/test.rb +44 -0
  225. data/test/dummy/config/initializers/assets.rb +11 -0
  226. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  227. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  228. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  229. data/test/dummy/config/initializers/inflections.rb +16 -0
  230. data/test/dummy/config/initializers/mime_types.rb +4 -0
  231. data/test/dummy/config/initializers/session_store.rb +3 -0
  232. data/test/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  233. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  234. data/test/dummy/config/locales/en.yml +23 -0
  235. data/test/dummy/config/routes.rb +6 -0
  236. data/test/dummy/config.ru +4 -0
  237. data/test/dummy/db/schema.rb +108 -0
  238. data/test/dummy/lib/assets/.keep +0 -0
  239. data/test/dummy/log/.keep +0 -0
  240. data/test/dummy/public/404.html +67 -0
  241. data/test/dummy/public/422.html +67 -0
  242. data/test/dummy/public/500.html +66 -0
  243. data/test/dummy/public/favicon.ico +0 -0
  244. data/test/extensions/action_controller_base_extensions_test.rb +21 -0
  245. data/test/extensions/action_mailer_base_extensions_test.rb +20 -0
  246. data/test/extensions/action_view_base_extensions_test.rb +267 -0
  247. data/test/extensions/active_record_extensions_test.rb +173 -0
  248. data/test/extensions/application_configuration_extensions_test.rb +46 -0
  249. data/test/extensions/application_extensions_test.rb +23 -0
  250. data/test/extensions/connection_adapter_extensions_test.rb +54 -0
  251. data/test/extensions/date_time_value_extensions_test.rb +104 -0
  252. data/test/extensions/date_value_extensions_test.rb +102 -0
  253. data/test/extensions/decimal_value_extensions_test.rb +85 -0
  254. data/test/extensions/erb_scaffold_generator_extensions_test.rb +17 -0
  255. data/test/extensions/float_value_extensions_test.rb +78 -0
  256. data/test/extensions/form_builder_extensions_test.rb +28 -0
  257. data/test/extensions/integer_value_extensions_test.rb +78 -0
  258. data/test/extensions/jbuilder_generator_extensions_test.rb +21 -0
  259. data/test/extensions/jbuilder_template_extensions_test.rb +47 -0
  260. data/test/extensions/main_app_extensions_test.rb +55 -0
  261. data/test/extensions/numeric_extensions_test.rb +76 -0
  262. data/test/extensions/object_extensions_test.rb +104 -0
  263. data/test/extensions/session_extensions_test.rb +69 -0
  264. data/test/extensions/string_extensions_test.rb +32 -0
  265. data/test/extensions/test_case_extensions_test.rb +538 -0
  266. data/test/extensions/time_zone_converter_extensions_test.rb +10 -0
  267. data/test/fixtures/incline/access_group_group_members.yml +1 -0
  268. data/test/fixtures/incline/access_group_user_members.yml +1 -0
  269. data/test/fixtures/incline/access_groups.yml +13 -0
  270. data/test/fixtures/incline/action_groups.yml +6 -0
  271. data/test/fixtures/incline/action_securities.yml +18 -0
  272. data/test/fixtures/incline/user_login_histories.yml +1 -0
  273. data/test/fixtures/incline/users.yml +64 -0
  274. data/test/incline_test.rb +63 -0
  275. data/test/integration/incline/users_edit_test.rb +180 -0
  276. data/test/integration/incline/users_login_test.rb +105 -0
  277. data/test/integration/incline/users_signup_test.rb +147 -0
  278. data/test/integration/navigation_test.rb +11 -0
  279. data/test/lib/data_tables_request_test.rb +245 -0
  280. data/test/lib/date_time_formats_test.rb +111 -0
  281. data/test/lib/global_status_test.rb +89 -0
  282. data/test/lib/json_log_formatter_test.rb +43 -0
  283. data/test/lib/log_test.rb +36 -0
  284. data/test/lib/recaptcha_test.rb +75 -0
  285. data/test/lib/user_manager_test.rb +47 -0
  286. data/test/lib/work_path_test.rb +18 -0
  287. data/test/models/incline/access_group_group_member_test.rb +30 -0
  288. data/test/models/incline/access_group_test.rb +60 -0
  289. data/test/models/incline/access_group_user_member_test.rb +29 -0
  290. data/test/models/incline/action_group_test.rb +27 -0
  291. data/test/models/incline/action_security_test.rb +176 -0
  292. data/test/models/incline/contact_message_test.rb +66 -0
  293. data/test/models/incline/disable_info_test.rb +29 -0
  294. data/test/models/incline/password_reset_request_test.rb +35 -0
  295. data/test/models/incline/password_reset_test.rb +51 -0
  296. data/test/models/incline/user_login_history_test.rb +31 -0
  297. data/test/models/incline/user_test.rb +91 -0
  298. data/test/test_helper.rb +42 -0
  299. data/test/validators/email_validator_test.rb +102 -0
  300. data/test/validators/ip_address_validator_test.rb +107 -0
  301. data/test/validators/recaptcha_validator_test.rb +57 -0
  302. data/test/validators/safe_name_validator_test.rb +101 -0
  303. metadata +584 -0
@@ -0,0 +1,121 @@
1
+ require_relative './access_group_group_member'
2
+ require_relative './access_group_user_member'
3
+
4
+ module Incline
5
+ class AccessGroup < ActiveRecord::Base
6
+
7
+ # hide the Groups<=>Users relationship association
8
+ has_many :access_group_user_members, class_name: 'Incline::AccessGroupUserMember', foreign_key: 'group_id', dependent: :delete_all
9
+ private :access_group_user_members, :access_group_user_members=
10
+
11
+ # and expose the users instead.
12
+ has_many :users, class_name: 'Incline::User', through: :access_group_user_members, source: :member
13
+
14
+ # hide the Groups<=>Groups relationship association
15
+ has_many :access_group_group_members, class_name: 'Incline::AccessGroupGroupMember', foreign_key: 'group_id', dependent: :delete_all
16
+ private :access_group_group_members, :access_group_group_members=
17
+
18
+ # and expose the groups instead.
19
+ has_many :groups, class_name: 'Incline::AccessGroup', through: :access_group_group_members, source: :member
20
+
21
+ ##
22
+ # Gets a list of memberships for this group. (Read-only)
23
+ def memberships(refresh = false)
24
+ @memberships = nil if refresh
25
+ @memberships ||= AccessGroupGroupMember.where(member_id: id).includes(:group).map{|v| v.group}.to_a.freeze
26
+ end
27
+
28
+ ##
29
+ # Gets a list of all of the member users for this group. (Read-only)
30
+ def members(refresh = false)
31
+ @members = nil if refresh
32
+ @members ||= safe_members.sort{|a,b| a.to_s <=> b.to_s}
33
+ end
34
+
35
+ validates :name,
36
+ presence: true,
37
+ length: { maximum: 100 },
38
+ uniqueness: { case_sensitive: false }
39
+
40
+ scope :sorted, ->{ order(:name) }
41
+
42
+ ##
43
+ # Determines if this group belongs to the specified group.
44
+ def belongs_to?(group)
45
+ group = AccessGroup.get(group) unless group.is_a?(::Incline::AccessGroup)
46
+ return false unless group
47
+ safe_belongs_to?(group)
48
+ end
49
+
50
+ ##
51
+ # Gets a list of all the groups this group provides effective membership to.
52
+ def effective_groups
53
+ ret = [ self ]
54
+ memberships.each do |m|
55
+ unless ret.include?(m) # prevent infinite recursion
56
+ tmp = m.effective_groups
57
+ tmp.each do |g|
58
+ ret << g unless ret.include?(g)
59
+ end
60
+ end
61
+ end
62
+ ret.sort{|a,b| a.name <=> b.name}
63
+ end
64
+
65
+ ##
66
+ # Gets the user IDs for the members of this group.
67
+ def user_ids
68
+ users.pluck(:id)
69
+ end
70
+
71
+ ##
72
+ # Gets the group IDs for the members of this group.
73
+ def group_ids
74
+ groups.pluck(:id)
75
+ end
76
+
77
+ ##
78
+ # Sets the user IDs for the members of this group.
79
+ def user_ids=(values)
80
+ values ||= []
81
+ values = [ values ] unless values.is_a?(::Array)
82
+ values = values.reject{|v| v.blank?}.map{|v| v.to_i}
83
+ self.users = Incline::User.where(id: values).to_a
84
+ end
85
+
86
+ ##
87
+ # Sets the group IDs for the members of this group.
88
+ def group_ids=(values)
89
+ values ||= []
90
+ values = [ values ] unless values.is_a?(::Array)
91
+ values = values.reject{|v| v.blank?}.map{|v| v.to_i}
92
+ self.groups = Incline::AccessGroup.where(id: values).to_a
93
+ end
94
+
95
+ protected
96
+
97
+ def safe_belongs_to?(group, already_tried = [])
98
+ return true if self == group
99
+ already_tried << self
100
+ memberships.each do |parent|
101
+ unless already_tried.include?(parent)
102
+ return true if parent.safe_belongs_to?(group, already_tried)
103
+ end
104
+ end
105
+ false
106
+ end
107
+
108
+ def safe_members(already_tried = [])
109
+ return [] if already_tried.include?(self)
110
+ already_tried << self
111
+ ret = users.to_a
112
+ groups.each do |g|
113
+ g.send(:safe_members, already_tried).each do |u|
114
+ ret << u unless ret.include?(u)
115
+ end
116
+ end
117
+ ret
118
+ end
119
+
120
+ end
121
+ end
@@ -0,0 +1,12 @@
1
+ module Incline
2
+ class AccessGroupGroupMember < ActiveRecord::Base
3
+ belongs_to :group, class_name: 'Incline::AccessGroup'
4
+ belongs_to :member, class_name: 'Incline::AccessGroup'
5
+
6
+ validates :group_id, presence: true
7
+ validates :member_id, presence: true, uniqueness: { scope: :group_id }
8
+
9
+ # member_id should not equal group_id or cause infinite recursion.
10
+ # these two issues are addressed in the AccessGroup model.
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Incline
2
+ class AccessGroupUserMember < ActiveRecord::Base
3
+
4
+ belongs_to :group, class_name: 'Incline::AccessGroup'
5
+ belongs_to :member, class_name: 'Incline::User'
6
+
7
+ validates :group_id, presence: true
8
+ validates :member_id, presence: true, uniqueness: { scope: :group_id }
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ require_relative './access_group'
2
+
3
+ module Incline
4
+ class ActionGroup < ActiveRecord::Base
5
+ belongs_to :action_security
6
+ belongs_to :access_group
7
+
8
+ validates :action_security, presence: true
9
+ validates :access_group, presence: true, uniqueness: { scope: :action_security }
10
+
11
+ end
12
+ end
@@ -0,0 +1,222 @@
1
+ require_relative './action_group'
2
+
3
+ module Incline
4
+ class ActionSecurity < ActiveRecord::Base
5
+
6
+ SHORT_PERMITTED_FILTERS = {
7
+ '- Editable -' => 'users|custom',
8
+ 'Admins' => 'admins',
9
+ 'Anon' => 'anon',
10
+ 'Custom' => 'custom',
11
+ 'Everyone' => 'everyone',
12
+ 'Users' => 'users'
13
+ }.freeze
14
+
15
+ has_many :action_groups
16
+ private :action_groups, :action_groups=
17
+
18
+ has_many :groups, through: :action_groups, class_name: 'Incline::AccessGroup', source: :access_group
19
+
20
+ validates :controller_name, presence: true, length: { maximum: 200 }
21
+ validates :action_name, presence: true, length: { maximum: 200 }, uniqueness: { scope: :controller_name, case_sensitive: false }
22
+ validates :path, presence: true
23
+
24
+ before_save :downcase_names
25
+
26
+ scope :visible, ->{ where(visible: true) }
27
+
28
+ ##
29
+ # Updates the flags based on the controller configuration.
30
+ def update_flags
31
+ self.allow_anon = self.require_anon = self.require_admin = self.unknown_controller = self.non_standard = false
32
+
33
+ self.unknown_controller = true
34
+ klass =
35
+ begin
36
+ (controller_name + '_controller').classify.constantize
37
+ rescue NameError
38
+ nil
39
+ end
40
+
41
+ unless klass
42
+ options =
43
+ if controller_name.include?('/')
44
+ ns = controller_name.rpartition('/')[0]
45
+ ctrl = controller_name.rpartition('/')[2]
46
+ options = [
47
+ "#{ns}/app/controllers/#{ns}/#{ctrl}_controller",
48
+ "app/controllers/#{ns}/#{ctrl}_controller",
49
+ "#{ns}/app/controllers/#{ctrl}_controller",
50
+ "#{ns}/#{ctrl}_controller"
51
+ ]
52
+ else
53
+ options = [
54
+ "app/controllers/#{controller_name}_controller",
55
+ "#{controller_name}_controller"
56
+ ]
57
+ end
58
+
59
+ while (file = options.shift)
60
+ begin
61
+ require file
62
+ klass = (controller_name + '_controller').classify.constantize
63
+ break
64
+ rescue LoadError, NameError
65
+ # just preventing the error from bubbling up.
66
+ end
67
+ end
68
+ end
69
+
70
+ if klass
71
+ self.unknown_controller = false
72
+ if klass.require_admin_for?(action_name)
73
+ self.require_admin = true
74
+ elsif klass.require_anon_for?(action_name)
75
+ self.require_anon = true
76
+ elsif klass.allow_anon_for?(action_name)
77
+ self.allow_anon = true
78
+ end
79
+
80
+ # if the authentication methods are overridden, set a flag to alert the user that standard security may not be honored.
81
+ unless klass.instance_method(:valid_user?).owner == Incline::Extensions::ActionControllerBase &&
82
+ klass.instance_method(:authorize!).owner == Incline::Extensions::ActionControllerBase
83
+ self.non_standard = true
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ ##
91
+ # Determines if the action allows custom security settings.
92
+ def allow_custom?
93
+ !(require_admin? || require_anon? || allow_anon?)
94
+ end
95
+
96
+ ##
97
+ # Generates a list of security items related to all of the current routes in the application.
98
+ #
99
+ # If "refresh" is true, the list will be rebuilt.
100
+ # If "update_flags" is true, the individual controllers will be loaded to regenerate the flags for the security.
101
+ #
102
+ # The returned list can be indexed two ways. The normal way with a numeric index and also by specifying the
103
+ # controller_name and action_name.
104
+ #
105
+ # Incline::ActionSecurity.valid_items[0]
106
+ # Incline::ActionSecurity.valid_items['incline/welcome','home']
107
+ #
108
+ def self.valid_items(refresh = false, update_flags = true)
109
+ @valid_items = nil if refresh
110
+ @valid_items ||=
111
+ begin
112
+ Incline::ActionSecurity.update_all(visible: false)
113
+
114
+ ret = Incline
115
+ .route_list
116
+ .reject{|r| r[:action] == 'api'}
117
+ .map do |r|
118
+ item = ActionSecurity.find_or_initialize_by(controller_name: r[:controller], action_name: r[:action])
119
+ item.path = "#{r[:path]} [#{r[:verb]}]"
120
+ item.visible = true
121
+ item.update_flags if update_flags
122
+ item.save!
123
+ item
124
+ end
125
+ .sort{|a,b| a.controller_name == b.controller_name ? a.action_name <=> b.action_name : a.controller_name <=> b.controller_name}
126
+
127
+ def ret.[](*args)
128
+ if args.length == 2
129
+ controller = args[0].to_s
130
+ action = args[1].to_s
131
+ find{|item| item.controller_name == controller && item.action_name == action}
132
+ else
133
+ super(*args)
134
+ end
135
+ end
136
+
137
+ ret.freeze
138
+ end
139
+ end
140
+
141
+ ##
142
+ # Gets a string describing who is permitted to execute the action.
143
+ def permitted(refresh = false)
144
+ @permitted = nil if refresh
145
+ @permitted ||=
146
+ if require_admin?
147
+ 'Administrators Only'
148
+ elsif require_anon?
149
+ 'Anonymous Only'
150
+ elsif allow_anon?
151
+ 'Everyone'
152
+ elsif groups.any?
153
+ names = groups.pluck(:name).map{|v| "\"#{v}\""}
154
+ 'Members of ' +
155
+ if names.count == 1
156
+ names.first
157
+ elsif names.count == 2
158
+ names.join(' or ')
159
+ else
160
+ names[0...-1].join(', ') + ', or ' + names.last
161
+ end
162
+ else
163
+ 'All Users'
164
+ end +
165
+ if non_standard
166
+ ' (Non-Standard)'
167
+ else
168
+ ''
169
+ end
170
+ end
171
+
172
+ ##
173
+ # Gets a short string describing who is permitted to execute the action.
174
+ def short_permitted
175
+ if require_admin?
176
+ 'Admins'
177
+ elsif require_anon?
178
+ 'Anon'
179
+ elsif allow_anon?
180
+ 'Everyone'
181
+ elsif groups.any?
182
+ 'Custom'
183
+ else
184
+ 'Users'
185
+ end +
186
+ if non_standard
187
+ '*'
188
+ else
189
+ ''
190
+ end
191
+ end
192
+
193
+ ##
194
+ # Description of action.
195
+ def to_s
196
+ @to_s ||= "#{controller_name}:#{action_name} [#{permitted}]"
197
+ end
198
+
199
+ ##
200
+ # Gets the group IDs accepted by this action.
201
+ def group_ids
202
+ groups.pluck(:id)
203
+ end
204
+
205
+ ##
206
+ # Sets the group IDs accepted by this action.
207
+ def group_ids=(values)
208
+ values ||= []
209
+ values = [ values ] unless values.is_a?(::Array)
210
+ values = values.reject{|v| v.blank?}.map{|v| v.to_i}
211
+ self.groups = Incline::AccessGroup.where(id: values).to_a
212
+ end
213
+
214
+ private
215
+
216
+ def downcase_names
217
+ controller_name.downcase!
218
+ action_name.downcase!
219
+ end
220
+
221
+ end
222
+ end
@@ -0,0 +1,37 @@
1
+ module Incline
2
+ ##
3
+ # Defines the message generated by the generic contact form.
4
+ class ContactMessage
5
+ include ActiveModel::Model
6
+ include ActiveModel::Validations
7
+
8
+ attr_accessor :your_name, :your_email, :related_to, :subject, :body, :remote_ip, :recaptcha
9
+
10
+ validates :your_name, presence: true
11
+ validates :your_email, presence: true, 'incline/email' => true
12
+ validates :related_to, presence: true
13
+ validates :subject, presence: true, if: :need_subject?
14
+ validates :body, presence: true
15
+ validates :recaptcha, presence: true, 'incline/recaptcha' => true
16
+
17
+ ##
18
+ # Gets the full subject for the message.
19
+ def full_subject
20
+ return related_to if subject.blank?
21
+ "#{related_to}: #{subject}"
22
+ end
23
+
24
+ ##
25
+ # Sends the message.
26
+ def send_message
27
+ Incline::ContactForm.contact(self).deliver_now
28
+ end
29
+
30
+ private
31
+
32
+ def need_subject?
33
+ related_to.to_s.downcase == 'other'
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,20 @@
1
+ module Incline
2
+ ##
3
+ # This model is used to disable a user with a reason for the disabling.
4
+ class DisableInfo
5
+ include ActiveModel::Model
6
+ include ActiveModel::Validations
7
+
8
+ attr_accessor :reason, :user
9
+
10
+ validates :reason, presence: true
11
+ validate do
12
+ if user && user.is_a?(::Incline::User)
13
+ errors.add(:user, 'must be enabled') unless user.enabled?
14
+ else
15
+ errors.add(:user, 'must be provided')
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module Incline
2
+ class PasswordReset
3
+ include ActiveModel::Model
4
+ include ActiveModel::Validations
5
+
6
+ attr_accessor :password
7
+ attr_accessor :recaptcha
8
+
9
+ validates :password, presence: true, length: { minimum: 8 }, confirmation: true
10
+ validates :password_confirmation, presence: true
11
+ validates :recaptcha, presence: true, 'incline/recaptcha' => true
12
+
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+
2
+ module Incline
3
+ class PasswordResetRequest
4
+ include ActiveModel::Model
5
+ include ActiveModel::Validations
6
+
7
+ attr_accessor :email
8
+ attr_accessor :recaptcha
9
+
10
+ validates :email, presence: true, 'incline/email' => true
11
+ validates :recaptcha, presence: true, 'incline/recaptcha' => true
12
+ end
13
+
14
+ end