discretion 0.4.0.pre.alpha → 1.0.0.pre.alpha

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5b39ae6911fe8a0aa3da936ad083d93c346af721
4
- data.tar.gz: 5e34a6059f263690d797e97455777ad7a01cc4ed
3
+ metadata.gz: a56b9cc6109e4904c4c4ffa1569af797b4e043a7
4
+ data.tar.gz: 77a3f57cd1628eee0ed41ca2ae4c71f032309829
5
5
  SHA512:
6
- metadata.gz: b50620eef4fe55b2117695f3aace6a6cb9311d277b7210cc4af07d043947af8b4dbb5b192bc60e505909a433cfce8c5167261c13c778ec7f99b3f70632d87d4e
7
- data.tar.gz: 98118e6239097bad701fd7de80641eec0f3ebccb6f973bd556e40213fee71aba20b4b00e186f3747e493f883de20d63395517e3ab6693495263a5062ed30c5c3
6
+ metadata.gz: 2ec9587ef19c98cd89b9ed107c16907a9a7c3fe1316f58b86b6ac66e38c4bef621c959e1286d2f04466e6b4dea1168e12a8e20959b8b33a5395eaa9816c2bd7a
7
+ data.tar.gz: e3b5fcad23ef87209535356e5ea6d5c4c9d2bc3d60d4cc722c1a772ab05e92a420a6d4cb74fc2d87adcca341b44d61b80d44e2b13fa3db736d3b85ef88f89c01
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .byebug_history
1
2
  /.bundle/
2
3
  /.yardoc
3
4
  /Gemfile.lock
@@ -7,3 +8,4 @@
7
8
  /pkg/
8
9
  /spec/reports/
9
10
  /tmp/
11
+ vendor/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Discretion
2
2
 
3
+ **tldr; Discretion is a simple privacy/authorization framework for Rails projects. You define `can_see?(viewer)` methods in a model class to determine if a given viewer is allowed to view/load/read the model (record). If so, you can query and load the record as you normally would in Rails (e.g. using `find`, `where`, `limit`, ...). If not, then Discretion will throw an exception when you try to fetch the record. Something similar is done for writes as well.**
4
+
3
5
  ## Installation
4
6
 
5
7
  Add this line to your application's Gemfile:
@@ -25,7 +27,7 @@ Or install it yourself as:
25
27
 
26
28
  The idea is simple: we colocate the read and write policies with the model definitions themselves by defining `can_see?(viewer)` and optionally `can_write?(viewer)`. The semantics are straightforward: given a `viewer` (typically a `User` but can be anything you want -- more on this below), can that viewer see the record encapsulated by the model class?
27
29
 
28
- For example, let's say we have a web app for a large non-profit organization which has staff who have to raise money from donors. So we might have models like `Donor`, `Staff`, and `Donation`s. Below we will describe how we would set up authorization/privacy policies for these models using Discretion.
30
+ For example, let's say we have a web app for a large non-profit organization which has staff who have to raise money from donors. So we might have models like `Donor`, `Staff`, and `Donation`. Below we will describe how we would set up authorization/privacy policies for these models using Discretion.
29
31
 
30
32
  ### Opt-In
31
33
 
@@ -185,7 +187,7 @@ Discretion is totally opaque and should not require any changes in how you query
185
187
 
186
188
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
187
189
 
188
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
190
+ To install this gem onto your local machine, run `bundle exec rake install`.
189
191
 
190
192
  ## Contributing
191
193
 
data/Rakefile CHANGED
@@ -1,2 +1,5 @@
1
- require "bundler/gem_tasks"
1
+ require 'rspec/core/rake_task'
2
+ require 'bundler/gem_tasks'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
2
5
  task :default => :spec
data/discretion.gemspec CHANGED
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = 'https://github.com/abeland/discretion'
15
15
  spec.license = 'MIT'
16
16
 
17
+ spec.add_dependency 'activesupport'
17
18
  spec.add_dependency 'rails', '~>5'
18
19
  spec.add_dependency 'request_store', '~>1.3'
19
20
  spec.required_ruby_version = '>= 2.2.2'
@@ -25,6 +26,11 @@ Gem::Specification.new do |spec|
25
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
27
  spec.require_paths = ['lib']
27
28
 
29
+ spec.add_development_dependency 'activerecord'
28
30
  spec.add_development_dependency 'bundler', '~> 1.15'
31
+ spec.add_development_dependency 'factory_bot_rails'
29
32
  spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'rspec'
34
+ spec.add_development_dependency 'rspec-rails'
35
+ spec.add_development_dependency 'sqlite3'
30
36
  end
data/lib/discretion.rb CHANGED
@@ -5,7 +5,7 @@ require 'discretion/errors'
5
5
  require 'discretion/helpers'
6
6
  require 'discretion/meta'
7
7
  require 'discretion/middleware'
8
- require 'discretion/railtie'
8
+ require 'discretion/railtie' if defined?(Rails)
9
9
  require 'discretion/version'
10
10
 
11
11
  ActiveRecord::Base.send(:include, Discretion::Meta) if defined?(ActiveRecord)
@@ -2,6 +2,7 @@ module Discretion
2
2
  class << self
3
3
  def can_see_record?(viewer, record)
4
4
  return true unless record.is_a?(Discretion::DiscreetModel)
5
+ return true if Discretion::OMNISCIENT_VIEWER == viewer || Discretion::OMNIPOTENT_VIEWER == viewer
5
6
 
6
7
  record.send(:can_see?, viewer)
7
8
  end
@@ -10,16 +11,17 @@ module Discretion
10
11
  can_see_record?(Discretion.current_viewer, record)
11
12
  end
12
13
 
13
- def can_write_record?(viewer, record)
14
+ def can_write_record?(viewer, record, changes, new_record)
14
15
  return true unless record.is_a?(Discretion::DiscreetModel)
16
+ return true if Discretion::OMNIPOTENT_VIEWER == viewer
15
17
 
16
18
  record.respond_to?(:can_write?, true) ?
17
- record.send(:can_write?, viewer) :
19
+ record.send(:can_write?, viewer, changes, new_record) :
18
20
  can_see_record?(viewer, record)
19
21
  end
20
22
 
21
- def current_viewer_can_write_record?(record)
22
- can_write_record?(Discretion.current_viewer, record)
23
+ def current_viewer_can_write_record?(record, changes, new_record)
24
+ can_write_record?(Discretion.current_viewer, record, changes, new_record)
23
25
  end
24
26
  end
25
27
  end
@@ -1,4 +1,7 @@
1
1
  module Discretion
2
+ OMNISCIENT_VIEWER = :__discretion_omnisient_viewer_val
3
+ OMNIPOTENT_VIEWER = :__discretion_omnipotent_viewer_val
4
+
2
5
  class << self
3
6
  CURRENT_VIEWER_KEY = :__discretion_current_viewer
4
7
 
@@ -1,3 +1,5 @@
1
+ require 'active_support/concern'
2
+
1
3
  module Discretion
2
4
  module DiscreetModel
3
5
  extend ActiveSupport::Concern
@@ -8,7 +10,9 @@ module Discretion
8
10
  end
9
11
 
10
12
  before_save do |record|
11
- raise Discretion::CannotWriteError unless Discretion.current_viewer_can_write_record?(record)
13
+ unless Discretion.current_viewer_can_write_record?(record, changes, new_record?)
14
+ raise Discretion::CannotWriteError
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -12,8 +12,28 @@ module Discretion
12
12
  records.all? { |record| Discretion.can_see_record?(viewer, record) }
13
13
  end
14
14
 
15
- def can_write_records?(viewer, *records)
16
- records.all? { |record| Discretion.can_write_record?(viewer, record) }
15
+ def omnisciently
16
+ # Calling Proc.new will create a Proc from the implicitly given block to
17
+ # the current method.
18
+ # cf. http://ruby-doc.org/core-2.5.0/Proc.html#method-c-new
19
+ with_viewer(Discretion::OMNISCIENT_VIEWER, &Proc.new)
20
+ end
21
+
22
+ def omnipotently
23
+ # Calling Proc.new will create a Proc from the implicitly given block to
24
+ # the current method.
25
+ # cf. http://ruby-doc.org/core-2.5.0/Proc.html#method-c-new
26
+ with_viewer(Discretion::OMNIPOTENT_VIEWER, &Proc.new)
27
+ end
28
+
29
+ private
30
+
31
+ def with_viewer(viewer)
32
+ orig_viewer = Discretion.current_viewer
33
+ Discretion.set_current_viewer(viewer)
34
+ yield
35
+ ensure
36
+ Discretion.set_current_viewer(orig_viewer)
17
37
  end
18
38
  end
19
39
  end
@@ -1,3 +1,5 @@
1
+ require 'rails'
2
+
1
3
  module Discretion
2
4
  class Railtie < ::Rails::Railtie
3
5
  initializer 'discretion.insert_middleware' do |app|
@@ -1,3 +1,3 @@
1
1
  module Discretion
2
- VERSION = '0.4.0.pre.alpha'.freeze
2
+ VERSION = '1.0.0.pre.alpha'.freeze
3
3
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discretion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0.pre.alpha
4
+ version: 1.0.0.pre.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abe Land
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-26 00:00:00.000000000 Z
11
+ date: 2018-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rails
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activerecord
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: bundler
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +80,20 @@ dependencies:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
82
  version: '1.15'
83
+ - !ruby/object:Gem::Dependency
84
+ name: factory_bot_rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
55
97
  - !ruby/object:Gem::Dependency
56
98
  name: rake
57
99
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +108,48 @@ dependencies:
66
108
  - - "~>"
67
109
  - !ruby/object:Gem::Version
68
110
  version: '10.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec-rails
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: sqlite3
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
69
153
  description: A simple privacy/authorization framework for Rails projects.
70
154
  email:
71
155
  - codeclimbcoffee@gmail.com
@@ -74,6 +158,7 @@ extensions: []
74
158
  extra_rdoc_files: []
75
159
  files:
76
160
  - ".gitignore"
161
+ - ".rspec"
77
162
  - CODE_OF_CONDUCT.md
78
163
  - Gemfile
79
164
  - LICENSE.txt