admission 0.2.8 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/Gemfile +2 -1
  4. data/README.md +24 -2
  5. data/examples/rails5_feudalism/.gitignore +19 -0
  6. data/examples/rails5_feudalism/.ruby-version +1 -0
  7. data/examples/rails5_feudalism/Gemfile +52 -0
  8. data/examples/rails5_feudalism/README.md +17 -0
  9. data/examples/rails5_feudalism/Rakefile +6 -0
  10. data/examples/rails5_feudalism/app/assets/config/manifest.js +3 -0
  11. data/examples/rails5_feudalism/app/assets/images/.keep +0 -0
  12. data/examples/rails5_feudalism/app/assets/javascripts/application.js +15 -0
  13. data/examples/rails5_feudalism/app/assets/stylesheets/application.css +15 -0
  14. data/examples/rails5_feudalism/app/assets/stylesheets/scaffolds.scss +84 -0
  15. data/examples/rails5_feudalism/app/controllers/application_controller.rb +13 -0
  16. data/examples/rails5_feudalism/app/controllers/concerns/.keep +0 -0
  17. data/examples/rails5_feudalism/app/controllers/users_controller.rb +75 -0
  18. data/examples/rails5_feudalism/app/helpers/application_helper.rb +2 -0
  19. data/examples/rails5_feudalism/app/jobs/application_job.rb +2 -0
  20. data/examples/rails5_feudalism/app/models/application_record.rb +3 -0
  21. data/examples/rails5_feudalism/app/models/concerns/.keep +0 -0
  22. data/examples/rails5_feudalism/app/models/person.rb +11 -0
  23. data/examples/rails5_feudalism/app/models/possession.rb +7 -0
  24. data/examples/rails5_feudalism/app/models/trait.rb +7 -0
  25. data/examples/rails5_feudalism/app/models/user.rb +17 -0
  26. data/examples/rails5_feudalism/app/models/user_status.rb +140 -0
  27. data/examples/rails5_feudalism/app/views/admission/forbidden.html.erb +14 -0
  28. data/examples/rails5_feudalism/app/views/layouts/application.html.erb +15 -0
  29. data/examples/rails5_feudalism/app/views/users/_form.html.erb +19 -0
  30. data/examples/rails5_feudalism/app/views/users/_privilege_row.html.erb +24 -0
  31. data/examples/rails5_feudalism/app/views/users/_privileges_list.html.erb +51 -0
  32. data/examples/rails5_feudalism/app/views/users/edit.html.erb +6 -0
  33. data/examples/rails5_feudalism/app/views/users/index.html.erb +25 -0
  34. data/examples/rails5_feudalism/app/views/users/new.html.erb +5 -0
  35. data/examples/rails5_feudalism/app/views/users/show.html.erb +4 -0
  36. data/examples/rails5_feudalism/bin/bundle +3 -0
  37. data/examples/rails5_feudalism/bin/rails +9 -0
  38. data/examples/rails5_feudalism/bin/rake +9 -0
  39. data/examples/rails5_feudalism/bin/setup +38 -0
  40. data/examples/rails5_feudalism/bin/spring +17 -0
  41. data/examples/rails5_feudalism/bin/update +29 -0
  42. data/examples/rails5_feudalism/bin/yarn +11 -0
  43. data/examples/rails5_feudalism/config.ru +5 -0
  44. data/examples/rails5_feudalism/config/application.rb +28 -0
  45. data/examples/rails5_feudalism/config/boot.rb +3 -0
  46. data/examples/rails5_feudalism/config/database.yml +85 -0
  47. data/examples/rails5_feudalism/config/environment.rb +5 -0
  48. data/examples/rails5_feudalism/config/environments/development.rb +49 -0
  49. data/examples/rails5_feudalism/config/environments/production.rb +82 -0
  50. data/examples/rails5_feudalism/config/environments/test.rb +36 -0
  51. data/examples/rails5_feudalism/config/initializers/application_controller_renderer.rb +8 -0
  52. data/examples/rails5_feudalism/config/initializers/assets.rb +14 -0
  53. data/examples/rails5_feudalism/config/initializers/backtrace_silencers.rb +7 -0
  54. data/examples/rails5_feudalism/config/initializers/cookies_serializer.rb +5 -0
  55. data/examples/rails5_feudalism/config/initializers/filter_parameter_logging.rb +4 -0
  56. data/examples/rails5_feudalism/config/initializers/inflections.rb +16 -0
  57. data/examples/rails5_feudalism/config/initializers/mime_types.rb +4 -0
  58. data/examples/rails5_feudalism/config/initializers/wrap_parameters.rb +14 -0
  59. data/examples/rails5_feudalism/config/locales/en.yml +33 -0
  60. data/examples/rails5_feudalism/config/puma.rb +56 -0
  61. data/examples/rails5_feudalism/config/routes.rb +8 -0
  62. data/examples/rails5_feudalism/config/secrets.yml +32 -0
  63. data/examples/rails5_feudalism/config/spring.rb +6 -0
  64. data/examples/rails5_feudalism/db/migrate/20171018085629_create_users.rb +9 -0
  65. data/examples/rails5_feudalism/db/migrate/20171019082044_create_people.rb +9 -0
  66. data/examples/rails5_feudalism/db/migrate/20171019082055_create_possessions.rb +9 -0
  67. data/examples/rails5_feudalism/db/migrate/20171019082059_create_traits.rb +9 -0
  68. data/examples/rails5_feudalism/db/schema.rb +49 -0
  69. data/examples/rails5_feudalism/db/seeds.rb +7 -0
  70. data/examples/rails5_feudalism/lib/assets/.keep +0 -0
  71. data/examples/rails5_feudalism/lib/tasks/.keep +0 -0
  72. data/examples/rails5_feudalism/log/.keep +0 -0
  73. data/examples/rails5_feudalism/package.json +7 -0
  74. data/examples/rails5_feudalism/public/404.html +67 -0
  75. data/examples/rails5_feudalism/public/422.html +67 -0
  76. data/examples/rails5_feudalism/public/500.html +66 -0
  77. data/examples/rails5_feudalism/public/apple-touch-icon-precomposed.png +0 -0
  78. data/examples/rails5_feudalism/public/apple-touch-icon.png +0 -0
  79. data/examples/rails5_feudalism/public/favicon.ico +0 -0
  80. data/examples/rails5_feudalism/public/robots.txt +1 -0
  81. data/examples/rails5_feudalism/test/application_system_test_case.rb +5 -0
  82. data/examples/rails5_feudalism/test/controllers/.keep +0 -0
  83. data/examples/rails5_feudalism/test/fixtures/.keep +0 -0
  84. data/examples/rails5_feudalism/test/fixtures/files/.keep +0 -0
  85. data/examples/rails5_feudalism/test/fixtures/people.yml +36 -0
  86. data/examples/rails5_feudalism/test/fixtures/possessions.yml +0 -0
  87. data/examples/rails5_feudalism/test/fixtures/traits.yml +0 -0
  88. data/examples/rails5_feudalism/test/fixtures/users.yml +0 -0
  89. data/examples/rails5_feudalism/test/helpers/.keep +0 -0
  90. data/examples/rails5_feudalism/test/models/.keep +0 -0
  91. data/examples/rails5_feudalism/test/models/user_status/rules_test.rb +152 -0
  92. data/examples/rails5_feudalism/test/models/user_status/user_status_test.rb +50 -0
  93. data/examples/rails5_feudalism/test/system/.keep +0 -0
  94. data/examples/rails5_feudalism/test/test_helper.rb +9 -0
  95. data/examples/rails5_feudalism/tmp/.keep +0 -0
  96. data/examples/rails5_feudalism/vendor/.keep +0 -0
  97. data/examples/rails5_feudalism/yarn.lock +7 -0
  98. data/lib/admission.rb +2 -0
  99. data/lib/admission/admission.rb +8 -2
  100. data/lib/admission/arbitration.rb +5 -0
  101. data/lib/admission/denied.rb +4 -5
  102. data/lib/admission/index.rb +59 -0
  103. data/lib/admission/minitest.rb +41 -0
  104. data/lib/admission/privilege.rb +13 -3
  105. data/lib/admission/rails.rb +8 -94
  106. data/lib/admission/rails/action_admission.rb +73 -0
  107. data/lib/admission/rails/controller_addon.rb +40 -0
  108. data/lib/admission/rails/scope_not_defined.rb +21 -0
  109. data/lib/admission/rails/scope_resolver.rb +46 -0
  110. data/lib/admission/resource_arbitration.rb +14 -9
  111. data/lib/admission/status.rb +11 -2
  112. data/lib/admission/tests.rb +59 -0
  113. data/lib/admission/version.rb +1 -1
  114. data/spec/integration/action_arbitrating_spec.rb +1 -1
  115. data/spec/integration/resource_arbitrating_spec.rb +1 -1
  116. data/spec/rspec_config.rb +13 -13
  117. data/spec/spec_helper.rb +10 -2
  118. data/spec/test_context/index.rb +0 -2
  119. data/spec/unit/arbitration_spec.rb +33 -0
  120. data/spec/unit/index_spec.rb +144 -0
  121. data/spec/unit/privilege/order_definer_spec.rb +1 -1
  122. data/spec/unit/privilege_spec.rb +22 -5
  123. data/spec/unit/rails/action_admission_spec.rb +188 -0
  124. data/spec/unit/rails/controller_addon_spec.rb +68 -0
  125. data/spec/unit/rails/scope_resolver_spec.rb +72 -0
  126. data/spec/unit/resource_arbitration_spec.rb +36 -1
  127. data/spec/unit/status_spec.rb +1 -1
  128. metadata +108 -5
  129. data/spec/integration/_helper.rb +0 -2
  130. data/spec/unit/_helper.rb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cdbe6dd75f329be81da0823bb25211a2c105dc1f
4
- data.tar.gz: 4f77657ad36e58f3a4029fd3734d6c9837882a7b
3
+ metadata.gz: 27226e2614355243e1aba9de00267129fbef0f70
4
+ data.tar.gz: f88d58e66dd6c602dd6ba2fe0ae78d6d951c2a36
5
5
  SHA512:
6
- metadata.gz: d66fd06ba392c274786b71e74b25f171bbf9b419ff5b3c0d1cf7a2c252fb4528827a7ff7bfad329fb62dc30ffbf0f954ca8b50ab738df286e81cb23e6f52b4b9
7
- data.tar.gz: e051486a2089dbcf6bce1fda7d783047d0949434ecb5499cc7bf27b2d8ea421ebea79017f435884676f6aff18242bc34f297a315cbfb91603974d3ac62e423dd
6
+ metadata.gz: 0771d53e94477f7e59def1e84f8652d9e825f4d0bcdacd50be7a52185c82a87b65f7d2465abfaab41df43c1abb114d5d7198199d0dcc10ff74cd80bfea5c63aa
7
+ data.tar.gz: f6755cb896151dbcd63c80d4d101dab2656b2a39e38011632dcd562bc1abcc9ca9a06f374ce6f7cef0266eb255cbb9aa96075dc0a2b9654ff24249ae5b8fb57b
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.3.3
1
+ 2.3.6
data/Gemfile CHANGED
@@ -3,4 +3,5 @@ source "https://rubygems.org"
3
3
 
4
4
  gem 'rspec'
5
5
  gem 'byebug'
6
- gem 'rack'
6
+ gem 'rack'
7
+ gem 'simplecov', require: false
data/README.md CHANGED
@@ -1,2 +1,24 @@
1
- write-me
2
- (sorry, work in progress)
1
+ # Admission
2
+ A system to manage user privileges. Heavily inspired by cancan.
3
+
4
+ ### Is it "cancancancan"?
5
+ Yes, sort of. It's built around the same premise: having an index of rules, which resolve into entitling allowance for an user to a named action. But in Cancan you have to create your own system of privileges. Admission on the other hand is meant for the cases where you need the user to have multiple privileges, while having clear rules to resolve precedences between them.
6
+
7
+ The other thing that always bugged me about cancan (and was proven problematic in production) is that users' ability rules are loaded every time again, for every instance of the user record. I tried to introduce some kind of caching - only ended up making this library.
8
+
9
+ ## Is it any good?
10
+ [yes](https://news.ycombinator.com/item?id=3067434)
11
+
12
+ ## write-me please
13
+ ### status
14
+ * used in production for a rails app
15
+ * tests are only "ok"
16
+ * documentation non-existent
17
+
18
+ ### to-do list
19
+ - [ ] reuse arbitration instance
20
+ - [x] Admission::Denied must be able to tell the requested action and scope
21
+ - [x] minitest helpers
22
+ - [ ] rspec helpers
23
+ - [ ] test guides
24
+ - [ ] rails example
@@ -0,0 +1,19 @@
1
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.bundle
9
+
10
+ # Ignore all logfiles and tempfiles.
11
+ /log/*
12
+ /tmp/*
13
+ !/log/.keep
14
+ !/tmp/.keep
15
+
16
+ /node_modules
17
+ /yarn-error.log
18
+
19
+ .byebug_history
@@ -0,0 +1 @@
1
+ 2.3.3
@@ -0,0 +1,52 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) do |repo_name|
4
+ repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
5
+ "https://github.com/#{repo_name}.git"
6
+ end
7
+
8
+
9
+ # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
10
+ gem 'rails', '~> 5.1.4'
11
+ # Use postgresql as the database for Active Record
12
+ gem 'pg', '~> 0.18'
13
+ # Use Puma as the app server
14
+ gem 'puma', '~> 3.7'
15
+ # Use SCSS for stylesheets
16
+ gem 'sass-rails', '~> 5.0'
17
+ # Use Uglifier as compressor for JavaScript assets
18
+ gem 'uglifier', '>= 1.3.0'
19
+ # See https://github.com/rails/execjs#readme for more supported runtimes
20
+ # gem 'therubyracer', platforms: :ruby
21
+
22
+ # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
23
+ gem 'jbuilder', '~> 2.5'
24
+ # Use ActiveModel has_secure_password
25
+ # gem 'bcrypt', '~> 3.1.7'
26
+
27
+ # Use Capistrano for deployment
28
+ # gem 'capistrano-rails', group: :development
29
+
30
+ group :development, :test do
31
+ # Call 'byebug' anywhere in the code to stop execution and get a debugger console
32
+ gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
33
+ # Adds support for Capybara system testing and selenium driver
34
+ gem 'capybara', '~> 2.13'
35
+ gem 'selenium-webdriver'
36
+ end
37
+
38
+ group :development do
39
+ # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
40
+ gem 'web-console', '>= 3.3.0'
41
+ gem 'listen', '>= 3.0.5', '< 3.2'
42
+ # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
43
+ gem 'spring'
44
+ gem 'spring-watcher-listen', '~> 2.0.0'
45
+ end
46
+
47
+ # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
48
+ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
49
+
50
+
51
+ ########################################################################################################################
52
+ gem 'admission', path: File.expand_path('../../..', __FILE__)
@@ -0,0 +1,17 @@
1
+ # Admission example: Rails app mimicking the mess of feudalism rules
2
+
3
+ ## Goal
4
+ Show how to integrate Admission::ResourceArbitration into a rails app, that uses a complex case of privileges system. Each user (person) can have multiple privileges from multiple areas (countries), resulting in situations where one can do something in one area, but not in the other; where a privilege disallow doing a thing only in a single particular area. European feudalism has these wild and complex rules of inheritance, which is perfect to demonstrate how Admission's privileges one-way inheritance system deals with not that truly one-way real-world privilege inheritance system (you could've became a king -a sovereign- over a man to whom you're a vassal, resulting of insolvable situation: who's the lord to whom?).
5
+
6
+ ## Integration to Rails
7
+ Admission is not meant to be only-rails privilege system. I'd like to include some helpers into the library though. This example then, is actually just a sandbox for me to find out the smoothest integration (controllers helpers, ActiveRecord to save privileges and more).
8
+
9
+ ## to-do list
10
+ - [x] user privileges persistence
11
+ - [x] privileges system (popes, other christian patriarchs, emperors, kings, lords, ...)
12
+ - [ ] controller use of `#request!` and `Admission::Denied` handling
13
+ - [ ] god mode: status modification and transient admission plug-off
14
+ - [ ] nested resources allowance
15
+ - [ ] controllers helper for resources
16
+ - [ ] view usage of `#can?`
17
+ - [ ] model methods and attributes allowance (params permitting?)
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
File without changes
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
5
+ // vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require jquery
15
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
6
+ * vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,84 @@
1
+ body {
2
+ background-color: #fff;
3
+ color: #333;
4
+ margin: 33px;
5
+ font-family: verdana, arial, helvetica, sans-serif;
6
+ font-size: 13px;
7
+ line-height: 18px;
8
+ }
9
+
10
+ p, ol, ul, td {
11
+ font-family: verdana, arial, helvetica, sans-serif;
12
+ font-size: 13px;
13
+ line-height: 18px;
14
+ }
15
+
16
+ pre {
17
+ background-color: #eee;
18
+ padding: 10px;
19
+ font-size: 11px;
20
+ }
21
+
22
+ a {
23
+ color: #000;
24
+
25
+ &:visited {
26
+ color: #666;
27
+ }
28
+
29
+ &:hover {
30
+ color: #fff;
31
+ background-color: #000;
32
+ }
33
+ }
34
+
35
+ th {
36
+ padding-bottom: 5px;
37
+ }
38
+
39
+ td {
40
+ padding: 0 5px 7px;
41
+ }
42
+
43
+ div {
44
+ &.field, &.actions {
45
+ margin-bottom: 10px;
46
+ }
47
+ }
48
+
49
+ #notice {
50
+ color: green;
51
+ }
52
+
53
+ .field_with_errors {
54
+ padding: 2px;
55
+ background-color: red;
56
+ display: table;
57
+ }
58
+
59
+ #error_explanation {
60
+ width: 450px;
61
+ border: 2px solid red;
62
+ padding: 7px 7px 0;
63
+ margin-bottom: 20px;
64
+ background-color: #f0f0f0;
65
+
66
+ h2 {
67
+ text-align: left;
68
+ font-weight: bold;
69
+ padding: 5px 5px 5px 15px;
70
+ font-size: 12px;
71
+ margin: -7px -7px 0;
72
+ background-color: #c00;
73
+ color: #fff;
74
+ }
75
+
76
+ ul li {
77
+ font-size: 12px;
78
+ list-style: square;
79
+ }
80
+ }
81
+
82
+ label {
83
+ display: block;
84
+ }
@@ -0,0 +1,13 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery with: :exception
3
+
4
+ require 'admission/rails'
5
+ include Admission::Rails::ControllerAddon
6
+ Admission::Rails.log_access = true
7
+
8
+ def request_admission! action, scope
9
+ @requested_admission = {action: action, scope: scope}
10
+ puts "ADMISSION: #{action} over #{scope}"
11
+ end
12
+
13
+ end
@@ -0,0 +1,75 @@
1
+ class UsersController < ApplicationController
2
+
3
+ before_action :set_user, only: %i[show edit update destroy]
4
+ before_action :prepare_privilege_params!, only: %i[create update]
5
+
6
+ def index
7
+ @users = User.all
8
+ end
9
+
10
+ def show
11
+ end
12
+
13
+ def new
14
+ @user = User.new
15
+ end
16
+
17
+ def edit
18
+ end
19
+
20
+ def create
21
+ @user = User.new(user_params)
22
+
23
+ if @user.save
24
+ redirect_to @user, notice: 'User was successfully created.'
25
+ else
26
+ render :new
27
+ end
28
+ end
29
+
30
+ def update
31
+ if @user.update(user_params)
32
+ redirect_to @user, notice: 'User was successfully updated.'
33
+ else
34
+ render :edit
35
+ end
36
+ end
37
+
38
+ def destroy
39
+ @user.destroy
40
+ redirect_to users_url, notice: 'User was successfully destroyed.'
41
+ end
42
+
43
+ private
44
+ # Use callbacks to share common setup or constraints between actions.
45
+ def set_user
46
+ @user = User.find(params[:id])
47
+ end
48
+
49
+ # Never trust parameters from the scary internet, only allow the white list through.
50
+ def user_params
51
+ params.fetch(:user, {}).permit privileges: {}
52
+ end
53
+
54
+ def prepare_privilege_params!
55
+ return unless params[:user]
56
+
57
+ privileges = params[:user][:privileges]
58
+ unless privileges
59
+ params[:user][:privileges] = nil
60
+ return
61
+ end
62
+
63
+ countries = (privileges[:country].presence || [])
64
+ names = privileges[:name].presence || []
65
+
66
+ list = countries.zip(names).map do |country, name|
67
+ name, level = name.split '-'
68
+ UserStatus.privilege_for_country name, level.presence, country
69
+ end
70
+
71
+ params[:user][:privileges] = UserStatus.dump_privileges list.compact
72
+ params[:user][:privileges].permit!
73
+ end
74
+
75
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationJob < ActiveJob::Base
2
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
@@ -0,0 +1,11 @@
1
+ class Person < ApplicationRecord
2
+ COUNTRIES = %w[Moravia Bohemia Silesia].freeze
3
+
4
+ has_one :user, dependent: :destroy
5
+ has_many :possessions, dependent: :destroy
6
+ has_many :traits, dependent: :destroy
7
+
8
+ validates_presence_of :name
9
+ validates_inclusion_of :country, in: COUNTRIES
10
+
11
+ end
@@ -0,0 +1,7 @@
1
+ class Possession < ApplicationRecord
2
+
3
+ belongs_to :person
4
+
5
+ validates_presence_of :name
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+ class Trait < ApplicationRecord
2
+
3
+ belongs_to :person
4
+
5
+ validates_presence_of :name
6
+
7
+ end
@@ -0,0 +1,17 @@
1
+ class User < ApplicationRecord
2
+
3
+ belongs_to :person
4
+
5
+ validates_presence_of :person
6
+
7
+ scope :with_privilege, -> (names) {
8
+ names = [names] unless names.is_a? Array
9
+ names = names.map{|name| "'#{name}'"}.join ','
10
+ where.not(privileges: nil).where("\"users\".\"privileges\"->'_all' ?| ARRAY[#{names}]")
11
+ }
12
+
13
+ def status
14
+ @status ||= UserStatus.for_user(self)
15
+ end
16
+
17
+ end