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

Sign up to get free protection for your applications and to get access to all the features.
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