private_person 0.4.0 → 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.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +57 -0
- data/.gitignore +13 -0
- data/.rspec +1 -1
- data/.rubocop.yml +28 -0
- data/.rubocop_todo.yml +57 -0
- data/.simplecov +5 -0
- data/CHANGELOG.md +57 -0
- data/CLAUDE.md +5 -0
- data/Gemfile +25 -7
- data/LICENSE.txt +1 -1
- data/README.md +93 -0
- data/Rakefile +5 -23
- data/lib/generators/private_person/install/install_generator.rb +21 -19
- data/lib/generators/private_person/install/templates/migrate/create_permissions_table.rb +7 -14
- data/lib/generators/private_person/utils.rb +2 -7
- data/lib/private_person/extensions/acts_as_permissible.rb +9 -8
- data/lib/private_person/extensions/acts_as_permissor.rb +25 -28
- data/lib/private_person/extensions/acts_as_permitted.rb +21 -31
- data/lib/private_person/models/permission.rb +29 -21
- data/lib/private_person/version.rb +3 -1
- data/lib/private_person.rb +6 -4
- data/private_person.gemspec +35 -124
- data/spec/dummy/.rspec +1 -1
- data/spec/dummy/Rakefile +3 -1
- data/spec/dummy/app/models/application_record.rb +5 -0
- data/spec/dummy/app/models/page.rb +4 -2
- data/spec/dummy/app/models/user.rb +12 -9
- data/spec/dummy/bin/rails +6 -0
- data/spec/dummy/config/application.rb +23 -36
- data/spec/dummy/config/boot.rb +5 -8
- data/spec/dummy/config/database.yml +9 -9
- data/spec/dummy/config/environment.rb +6 -4
- data/spec/dummy/config/environments/development.rb +12 -12
- data/spec/dummy/config/environments/test.rb +20 -12
- data/spec/dummy/db/migrate/20260902000001_create_users_table.rb +9 -0
- data/spec/dummy/db/migrate/20260902000002_create_connections.rb +13 -0
- data/spec/dummy/db/migrate/20260902000003_create_pages_table.rb +11 -0
- data/spec/dummy/db/migrate/20260902000004_create_permissions.rb +11 -0
- data/spec/dummy/db/schema.rb +38 -56
- data/spec/factories/pages.rb +7 -5
- data/spec/factories/permissions.rb +6 -4
- data/spec/factories/users.rb +6 -4
- data/spec/models/page_spec.rb +5 -2
- data/spec/models/permission_spec.rb +58 -39
- data/spec/models/user_spec.rb +83 -40
- data/spec/private_person_spec.rb +4 -2
- data/spec/spec_helper.rb +40 -23
- data/spec/support/permissions_support.rb +41 -18
- data/spec/support/permissor_support.rb +7 -5
- data/spec/support/users_support.rb +9 -7
- metadata +93 -90
- data/.document +0 -5
- data/.idea/scopes/scope_settings.xml +0 -5
- data/README.rdoc +0 -22
- data/VERSION +0 -1
- data/script/rails +0 -6
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/inflections.rb +0 -15
- data/spec/dummy/config/initializers/mime_types.rb +0 -5
- data/spec/dummy/config/initializers/secret_token.rb +0 -7
- data/spec/dummy/config/initializers/session_store.rb +0 -8
- data/spec/dummy/config/locales/devise.en.yml +0 -59
- data/spec/dummy/config/locales/en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -59
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20130906213557_create_users_table.rb +0 -13
- data/spec/dummy/db/migrate/20130906213612_create_pages_table.rb +0 -15
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/script/rails +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: fb0dc73f8b0f56d09feec4fafa8255e374fe6e430361f85ff34806fc5e908e5b
|
|
4
|
+
data.tar.gz: 1add348c75fc0a2a270c0647811e3e4e6af64d92c11ed37380fbbff33d9fdeba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4799c45274e7f19bc7ee3184bfb42f9bb57a2c3228ef5d8d17705deceb92123cd383963be9606471ee6b4cf5dbd9aa4a848c06759522a724e034b7385dcb3dca
|
|
7
|
+
data.tar.gz: 26d4586cbd765cf4018f47ae170d22f22b36212ad1c76cb2721e218821f4ee829a5be02589b104386cd09a9d6d3e3b957d470d5c57f53ed8a3e9d62fbeb115bc
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
pull_request:
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
lint:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
steps:
|
|
10
|
+
- uses: actions/checkout@v4
|
|
11
|
+
- uses: ruby/setup-ruby@v1
|
|
12
|
+
with:
|
|
13
|
+
ruby-version: '3.4'
|
|
14
|
+
bundler-cache: true
|
|
15
|
+
- run: bundle exec rubocop
|
|
16
|
+
|
|
17
|
+
test:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
ruby: ['3.4', '4.0']
|
|
23
|
+
env:
|
|
24
|
+
RAILS_ENV: test
|
|
25
|
+
TZ: America/Denver
|
|
26
|
+
permissions:
|
|
27
|
+
contents: write
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- uses: ruby/setup-ruby@v1
|
|
31
|
+
with:
|
|
32
|
+
ruby-version: ${{ matrix.ruby }}
|
|
33
|
+
bundler-cache: true
|
|
34
|
+
- name: Set up test database
|
|
35
|
+
run: bundle exec rails db:create db:schema:load
|
|
36
|
+
working-directory: spec/dummy
|
|
37
|
+
- run: bundle exec rspec
|
|
38
|
+
- uses: actions/upload-artifact@v4
|
|
39
|
+
if: always()
|
|
40
|
+
with:
|
|
41
|
+
name: coverage-ruby-${{ matrix.ruby }}
|
|
42
|
+
path: coverage/
|
|
43
|
+
# Publishes a self-hosted coverage badge (badges/coverage.json, read by
|
|
44
|
+
# a shields.io endpoint badge in the README) instead of depending on a
|
|
45
|
+
# third-party coverage service like Coveralls/Codecov.
|
|
46
|
+
- name: Update coverage badge
|
|
47
|
+
if: matrix.ruby == '4.0' && github.ref_name == github.event.repository.default_branch && github.event_name == 'push'
|
|
48
|
+
run: |
|
|
49
|
+
pct=$(ruby -rjson -e "r = JSON.parse(File.read('coverage/.last_run.json'))['result']; puts (r['covered_percent'] || r['line']).round(1)")
|
|
50
|
+
color=$(ruby -e "pct = $pct; puts(pct >= 90 ? 'brightgreen' : pct >= 75 ? 'yellow' : 'red')")
|
|
51
|
+
mkdir -p badges
|
|
52
|
+
printf '{"schemaVersion":1,"label":"coverage","message":"%s%%","color":"%s"}\n' "$pct" "$color" > badges/coverage.json
|
|
53
|
+
git config user.name "github-actions[bot]"
|
|
54
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
55
|
+
git add badges/coverage.json
|
|
56
|
+
git diff --staged --quiet || git commit -m "Update coverage badge [skip ci]"
|
|
57
|
+
git push
|
data/.gitignore
ADDED
data/.rspec
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
--color
|
|
1
|
+
--color
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
|
2
|
+
|
|
3
|
+
plugins:
|
|
4
|
+
- rubocop-rails
|
|
5
|
+
- rubocop-rake
|
|
6
|
+
- rubocop-rspec
|
|
7
|
+
|
|
8
|
+
AllCops:
|
|
9
|
+
TargetRubyVersion: 3.2
|
|
10
|
+
DisplayCopNames: true
|
|
11
|
+
NewCops: enable
|
|
12
|
+
SuggestExtensions: false
|
|
13
|
+
Exclude:
|
|
14
|
+
- private_person.gemspec
|
|
15
|
+
- spec/dummy/db/schema.rb
|
|
16
|
+
- spec/dummy/db/migrate/*
|
|
17
|
+
- lib/generators/private_person/install/templates/**/*
|
|
18
|
+
|
|
19
|
+
Metrics/BlockLength:
|
|
20
|
+
Exclude:
|
|
21
|
+
- spec/*
|
|
22
|
+
- spec/*/*
|
|
23
|
+
|
|
24
|
+
# PrivatePerson::Permission is a gem-owned model shipped to consumers -
|
|
25
|
+
# it can't assume a host app's own ApplicationRecord exists.
|
|
26
|
+
Rails/ApplicationRecord:
|
|
27
|
+
Exclude:
|
|
28
|
+
- lib/**/*
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config --no-offense-counts --no-auto-gen-timestamp`
|
|
3
|
+
# using RuboCop version 1.90.0.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros, UseSorbetSigs.
|
|
10
|
+
# NamePrefix: is_, has_, have_, does_
|
|
11
|
+
# ForbiddenPrefixes: is_, has_, have_, does_
|
|
12
|
+
# AllowedMethods: is_a?
|
|
13
|
+
# MethodDefinitionMacros: define_method, define_singleton_method
|
|
14
|
+
Naming/PredicatePrefix:
|
|
15
|
+
Exclude:
|
|
16
|
+
- 'lib/private_person/extensions/acts_as_permissible.rb'
|
|
17
|
+
- 'lib/private_person/extensions/acts_as_permitted.rb'
|
|
18
|
+
|
|
19
|
+
# Configuration parameters: Prefixes, AllowedPatterns.
|
|
20
|
+
# Prefixes: when, with, without
|
|
21
|
+
RSpec/ContextWording:
|
|
22
|
+
Exclude:
|
|
23
|
+
- 'spec/models/user_spec.rb'
|
|
24
|
+
- 'spec/support/permissions_support.rb'
|
|
25
|
+
- 'spec/support/permissor_support.rb'
|
|
26
|
+
- 'spec/support/users_support.rb'
|
|
27
|
+
|
|
28
|
+
RSpec/LetSetup:
|
|
29
|
+
Exclude:
|
|
30
|
+
- 'spec/support/permissions_support.rb'
|
|
31
|
+
- 'spec/support/permissor_support.rb'
|
|
32
|
+
- 'spec/support/users_support.rb'
|
|
33
|
+
|
|
34
|
+
# Configuration parameters: AllowSubject.
|
|
35
|
+
RSpec/MultipleMemoizedHelpers:
|
|
36
|
+
Max: 18
|
|
37
|
+
|
|
38
|
+
# Configuration parameters: EnforcedStyle, IgnoreSharedExamples.
|
|
39
|
+
# SupportedStyles: always, named_only
|
|
40
|
+
RSpec/NamedSubject:
|
|
41
|
+
Exclude:
|
|
42
|
+
- 'spec/models/permission_spec.rb'
|
|
43
|
+
|
|
44
|
+
# Configuration parameters: AllowedGroups.
|
|
45
|
+
RSpec/NestedGroups:
|
|
46
|
+
Max: 5
|
|
47
|
+
|
|
48
|
+
# Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
|
|
49
|
+
# SupportedInflectors: default, active_support
|
|
50
|
+
RSpec/SpecFilePathFormat:
|
|
51
|
+
Exclude:
|
|
52
|
+
- 'spec/models/permission_spec.rb'
|
|
53
|
+
|
|
54
|
+
# Configuration parameters: AllowedConstants.
|
|
55
|
+
# This gem doesn't use top-level documentation comments anywhere.
|
|
56
|
+
Style/Documentation:
|
|
57
|
+
Enabled: false
|
data/.simplecov
ADDED
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
**Breaking change.** From-the-ground-up modernization: Rails 4 support
|
|
6
|
+
is dropped in favor of Rails >= 7.1, < 9, and the packaging/tooling
|
|
7
|
+
stack is fully replaced. There is no data-model migration needed for
|
|
8
|
+
existing installs - the `permissions` table shape is unchanged (see
|
|
9
|
+
below) - but the Ruby/Rails floor bump and the two association fixes
|
|
10
|
+
below are real behavior changes to check against before upgrading.
|
|
11
|
+
|
|
12
|
+
### Breaking
|
|
13
|
+
|
|
14
|
+
- **Ruby >= 3.2, Rails >= 7.1, < 9** required (was Rails >= 4.0, no
|
|
15
|
+
ceiling, developed against Rails 3/4-era conventions).
|
|
16
|
+
- **`user.permissibles` was broken and is now fixed.** The
|
|
17
|
+
`acts_as_permissor`-generated `has_many :permissibles, through:
|
|
18
|
+
:permissions` referenced the wrong association name (should have been
|
|
19
|
+
`:permissions_as_permissor`) and was missing `source_type` for its
|
|
20
|
+
polymorphic source - calling it raised outright on Rails 8's stricter
|
|
21
|
+
association validation. If your code already worked around this
|
|
22
|
+
(e.g. by never calling `.permissibles`), no change needed; if you
|
|
23
|
+
relied on it silently failing, it now actually returns the collection.
|
|
24
|
+
- **`wildcard_permit!`'s de-duplication is now fixed.** It previously
|
|
25
|
+
built its "does this already exist?" check with a malformed `.where`
|
|
26
|
+
call and had its guard commented out, so calling `wildcard_permit!`
|
|
27
|
+
twice with the same arguments always created a duplicate `Permission`
|
|
28
|
+
row. It now correctly creates at most one.
|
|
29
|
+
- **The generator's migration template is rewritten for Rails 8**
|
|
30
|
+
(`ActiveRecord::Migration[8.0]`, `t.references ..., polymorphic:
|
|
31
|
+
true`, `def change`) - the old template used a bare
|
|
32
|
+
`ActiveRecord::Migration` with no version bracket, which doesn't load
|
|
33
|
+
at all on Rails 5+. Column shape is otherwise unchanged: `permissor`
|
|
34
|
+
is required, `permissible` stays nullable (that's the wildcard/
|
|
35
|
+
type-level grant signal), `relationship_type` still defaults to
|
|
36
|
+
`'none'`.
|
|
37
|
+
- **`Permission.permissible_types`** no longer issues an invalid
|
|
38
|
+
`GROUP BY` query (worked on SQLite by accident, would have failed on
|
|
39
|
+
Postgres) and no longer raises when a permissor record has since been
|
|
40
|
+
deleted (it's skipped instead).
|
|
41
|
+
- **`Permission#by_relationship_type`**'s "match nothing" fallback
|
|
42
|
+
changed from the `where(0)` hack to `.none`.
|
|
43
|
+
|
|
44
|
+
### Also changed
|
|
45
|
+
|
|
46
|
+
- Jeweler/Rakefile-based packaging replaced with a hand-written
|
|
47
|
+
gemspec (`s.files` via `git ls-files`); `jeweler` is no longer even a
|
|
48
|
+
runtime dependency of the built gem (it was, by mistake, in 0.5.0).
|
|
49
|
+
- factory_girl -> factory_bot, RSpec `should` syntax -> `expect`/
|
|
50
|
+
`is_expected`, shoulda-matchers bumped to 6.x.
|
|
51
|
+
- Added rubocop (rubocop-rails, rubocop-rspec) - none was configured
|
|
52
|
+
before.
|
|
53
|
+
- Travis CI -> GitHub Actions; Coveralls -> a self-hosted coverage
|
|
54
|
+
badge (same approach as message_train).
|
|
55
|
+
- README rewritten in Markdown; its `is_permitted?` example previously
|
|
56
|
+
passed a **class** (`Page`) where the real method always expects an
|
|
57
|
+
**instance** - fixed.
|
data/CLAUDE.md
ADDED
data/Gemfile
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source 'https://rubygems.org'
|
|
2
4
|
# Add dependencies required to use your gem here.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
gem 'rails', '>= 7.1', '< 9'
|
|
6
|
+
|
|
7
|
+
# Add dependencies to develop your gem here.
|
|
8
|
+
# Include everything needed to run rake, tests, features, etc.
|
|
9
|
+
group :development do
|
|
10
|
+
gem 'rubocop', '~> 1.6', require: false
|
|
11
|
+
gem 'rubocop-rails', '~> 2.25', require: false
|
|
12
|
+
gem 'rubocop-rake', '~> 0.7', require: false
|
|
13
|
+
gem 'rubocop-rspec', '~> 3.0', require: false
|
|
14
|
+
end
|
|
5
15
|
|
|
6
|
-
|
|
7
|
-
gem '
|
|
8
|
-
gem '
|
|
16
|
+
group :development, :test do
|
|
17
|
+
gem 'factory_bot_rails', '~> 6.4'
|
|
18
|
+
gem 'rspec-its', '>= 1', '< 2'
|
|
19
|
+
gem 'rspec-rails', '~> 7.0'
|
|
20
|
+
gem 'sqlite3', '~> 2.1'
|
|
21
|
+
end
|
|
9
22
|
|
|
10
|
-
|
|
23
|
+
group :test do
|
|
24
|
+
gem 'chalk_dust', git: 'https://github.com/krisleech/chalk_dust.git'
|
|
25
|
+
gem 'database_cleaner-active_record', '~> 2.1'
|
|
26
|
+
gem 'shoulda-matchers', '~> 6.0'
|
|
27
|
+
gem 'simplecov', '~> 0.22', require: false
|
|
28
|
+
end
|
data/LICENSE.txt
CHANGED
data/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# PrivatePerson
|
|
2
|
+
|
|
3
|
+
[](https://github.com/gemvein/private_person/actions/workflows/ci.yml)
|
|
4
|
+
[](https://rubygems.org/gems/private_person)
|
|
5
|
+
[](https://github.com/gemvein/private_person/actions/workflows/ci.yml)
|
|
6
|
+
[](http://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
PrivatePerson is an ActiveRecord extension gem that lets a model be given
|
|
9
|
+
privacy settings over arbitrary models and polymorphic relations, putting
|
|
10
|
+
users' accounts in control of their own privacy policies.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Add PrivatePerson to your Gemfile:
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
gem 'private_person'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Then run the install generator, which adds a migration for the
|
|
21
|
+
`permissions` table:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
rails g private_person:install
|
|
25
|
+
rails db:migrate
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
Set up your models. The "permissor" is whoever is granting/checking
|
|
31
|
+
access (typically a `User`); the "permissible" is whatever's being
|
|
32
|
+
protected:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
# app/models/user.rb - using ChalkDust as the subscription model, but any
|
|
36
|
+
# gem or hand-rolled association works, as long as each method below
|
|
37
|
+
# returns the right collection of Users.
|
|
38
|
+
class User < ActiveRecord::Base
|
|
39
|
+
acts_as_permissor of: [:following_users, :user_followers],
|
|
40
|
+
class_name: 'User'
|
|
41
|
+
|
|
42
|
+
def follow(user)
|
|
43
|
+
ChalkDust.subscribe(self, to: user)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def following_users
|
|
47
|
+
ChalkDust.publishers_of(self)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def user_followers
|
|
51
|
+
ChalkDust.subscribers_of(self)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# app/models/page.rb
|
|
56
|
+
class Page < ActiveRecord::Base
|
|
57
|
+
acts_as_permissible by: :user
|
|
58
|
+
belongs_to :user
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then, when you need to know whether someone's permitted to see a
|
|
63
|
+
specific record:
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
@user.is_permitted? friend_user, @page
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Grant or revoke access directly:
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
@user.permit! 'following_users', @page # this specific page
|
|
73
|
+
@user.wildcard_permit! 'public', 'Page' # every Page, by type
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Contributing to PrivatePerson
|
|
77
|
+
|
|
78
|
+
* Check out the latest main to make sure the feature hasn't been
|
|
79
|
+
implemented or the bug hasn't been fixed yet.
|
|
80
|
+
* Check out the issue tracker to make sure someone hasn't already
|
|
81
|
+
requested it and/or contributed it.
|
|
82
|
+
* Fork the project.
|
|
83
|
+
* Start a feature/bugfix branch.
|
|
84
|
+
* Commit and push until you are happy with your contribution.
|
|
85
|
+
* Make sure to add tests for it, so it doesn't break in a future version
|
|
86
|
+
unintentionally.
|
|
87
|
+
* Please try not to mess with the Rakefile, version, or history. If you
|
|
88
|
+
want your own version, or it's otherwise necessary, that's fine, but
|
|
89
|
+
please isolate it to its own commit so it can be cherry-picked around.
|
|
90
|
+
|
|
91
|
+
## Copyright
|
|
92
|
+
|
|
93
|
+
Copyright (c) 2013-2026 Gem Vein. See LICENSE.txt for further details.
|
data/Rakefile
CHANGED
|
@@ -1,39 +1,21 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'rubygems'
|
|
4
4
|
require 'bundler'
|
|
5
5
|
begin
|
|
6
6
|
Bundler.setup(:default, :development)
|
|
7
7
|
rescue Bundler::BundlerError => e
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
warn e.message
|
|
9
|
+
warn 'Run `bundle install` to install missing gems'
|
|
10
10
|
exit e.status_code
|
|
11
11
|
end
|
|
12
|
+
require 'bundler/gem_tasks'
|
|
12
13
|
require 'rake'
|
|
13
14
|
|
|
14
|
-
require 'jeweler'
|
|
15
|
-
Jeweler::Tasks.new do |gem|
|
|
16
|
-
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
|
17
|
-
gem.name = "private_person"
|
|
18
|
-
gem.homepage = "http://www.gemvein.com/museum/cases/private_person"
|
|
19
|
-
gem.license = "MIT"
|
|
20
|
-
gem.summary = %Q{Private person puts your users in control of their own privacy policies.}
|
|
21
|
-
gem.description = %Q{Private person is an active record extension gem that allows a model to be given privacy settings over arbitrary models and polymorphic relations, putting users' accounts in control of their own privacy policies.}
|
|
22
|
-
gem.email = "karen.e.lundgren@gmail.com"
|
|
23
|
-
gem.authors = ["Karen Lundgren"]
|
|
24
|
-
# dependencies defined in Gemfile
|
|
25
|
-
end
|
|
26
|
-
Jeweler::RubygemsDotOrgTasks.new
|
|
27
|
-
|
|
28
15
|
require 'rspec/core'
|
|
29
16
|
require 'rspec/core/rake_task'
|
|
30
17
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
31
18
|
spec.pattern = FileList['spec/**/*_spec.rb']
|
|
32
19
|
end
|
|
33
20
|
|
|
34
|
-
|
|
35
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
|
36
|
-
spec.rcov = false
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
task :default => :spec
|
|
21
|
+
task default: :spec
|
|
@@ -1,31 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module PrivatePerson
|
|
2
4
|
class InstallGenerator < Rails::Generators::Base
|
|
3
|
-
source_root File.expand_path(
|
|
4
|
-
require File.expand_path('
|
|
5
|
+
source_root File.expand_path('templates', __dir__)
|
|
6
|
+
require File.expand_path('../utils', __dir__)
|
|
5
7
|
include Generators::Utils
|
|
6
8
|
include Rails::Generators::Migration
|
|
7
|
-
|
|
9
|
+
|
|
8
10
|
def hello
|
|
9
|
-
output
|
|
11
|
+
output 'With PrivatePerson, you can put your users in control of their own privacy policies.', :magenta
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def add_migrations
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
return if ActiveRecord::Base.connection.table_exists? 'permissions'
|
|
16
|
+
|
|
17
|
+
migration_template 'migrate/create_permissions_table.rb',
|
|
18
|
+
'db/migrate/create_permissions_table.rb'
|
|
19
|
+
rescue StandardError => e
|
|
20
|
+
output e.message
|
|
16
21
|
end
|
|
17
|
-
|
|
22
|
+
|
|
23
|
+
# Rails::Generators::Migration (included above) declares this
|
|
24
|
+
# interface method but only raises NotImplementedError - every
|
|
25
|
+
# generator that ships a migration must supply its own. This mirrors
|
|
26
|
+
# ActiveRecord::Generators::Migration's own implementation, which
|
|
27
|
+
# can't be included directly here without also requiring
|
|
28
|
+
# rails/generators/active_record.rb (not autoloaded by default).
|
|
18
29
|
def self.next_migration_number(dirname)
|
|
19
|
-
|
|
20
|
-
unless @prev_migration_nr
|
|
21
|
-
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
|
22
|
-
else
|
|
23
|
-
@prev_migration_nr += 1
|
|
24
|
-
end
|
|
25
|
-
@prev_migration_nr.to_s
|
|
26
|
-
else
|
|
27
|
-
"%.3d" % (current_migration_number(dirname) + 1)
|
|
28
|
-
end
|
|
30
|
+
ActiveRecord::Migration.next_migration_number(current_migration_number(dirname) + 1)
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
|
-
end
|
|
33
|
+
end
|
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
class CreatePermissionsTable < ActiveRecord::Migration
|
|
2
|
-
def
|
|
1
|
+
class CreatePermissionsTable < ActiveRecord::Migration[8.0]
|
|
2
|
+
def change
|
|
3
3
|
create_table :permissions do |t|
|
|
4
|
-
t.
|
|
5
|
-
t.
|
|
6
|
-
t.string
|
|
7
|
-
|
|
8
|
-
t.string :relationship_type, :default => 'none'
|
|
4
|
+
t.references :permissor, polymorphic: true, null: false
|
|
5
|
+
t.references :permissible, polymorphic: true, null: true
|
|
6
|
+
t.string :relationship_type, default: 'none', null: false
|
|
7
|
+
|
|
9
8
|
t.timestamps
|
|
10
9
|
end
|
|
11
|
-
|
|
12
|
-
add_index :permissions, [:permissor_type, :permissor_id]
|
|
13
|
-
add_index :permissions, [:permissible_type, :permissible_id]
|
|
14
|
-
end
|
|
15
|
-
def self.down
|
|
16
|
-
drop_table :permissions
|
|
17
10
|
end
|
|
18
|
-
end
|
|
11
|
+
end
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module PrivatePerson
|
|
2
4
|
module Generators
|
|
3
5
|
module Utils
|
|
4
6
|
def output(output, color = :green)
|
|
5
7
|
say(" - #{output}", color)
|
|
6
8
|
end
|
|
7
|
-
|
|
8
|
-
def ask_for(wording, default_value = nil, override_if_present_value = nil)
|
|
9
|
-
override_if_present_value.present? ?
|
|
10
|
-
display("Using [#{override_if_present_value}] for question '#{wording}'") && override_if_present_value :
|
|
11
|
-
ask(" ? #{wording} Press <enter> for [#{default_value}] >", :yellow).presence || default_value
|
|
12
|
-
end
|
|
13
9
|
end
|
|
14
10
|
end
|
|
15
11
|
end
|
|
16
|
-
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module PrivatePerson
|
|
2
4
|
module ActsAsPermissible
|
|
3
|
-
|
|
4
5
|
extend ActiveSupport::Concern
|
|
5
6
|
|
|
6
7
|
module ClassMethods
|
|
7
8
|
def acts_as_permissible(params = {})
|
|
8
|
-
if params[:by].nil?
|
|
9
|
-
|
|
10
|
-
end
|
|
9
|
+
raise 'Called acts_as_permissible, but without a :by parameter.' if params[:by].nil?
|
|
10
|
+
|
|
11
11
|
class_attribute :by
|
|
12
12
|
self.by = params[:by]
|
|
13
13
|
|
|
14
|
-
has_many :permissions, :
|
|
15
|
-
has_many :permissors, :
|
|
14
|
+
has_many :permissions, as: :permissible, class_name: 'PrivatePerson::Permission'
|
|
15
|
+
has_many :permissors, through: :permissions, source: :permissor,
|
|
16
|
+
source_type: by.to_s.camelize
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
include InstanceMethods
|
|
18
19
|
end
|
|
19
20
|
end
|
|
20
21
|
|
|
@@ -24,4 +25,4 @@ module PrivatePerson
|
|
|
24
25
|
end
|
|
25
26
|
end
|
|
26
27
|
end
|
|
27
|
-
end
|
|
28
|
+
end
|
|
@@ -1,58 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module PrivatePerson
|
|
2
4
|
module ActsAsPermissor
|
|
3
|
-
|
|
4
5
|
extend ActiveSupport::Concern
|
|
5
6
|
|
|
6
7
|
module ClassMethods
|
|
7
8
|
def acts_as_permissor(params = {})
|
|
8
|
-
if params[:of].nil?
|
|
9
|
-
|
|
10
|
-
end
|
|
9
|
+
raise 'Called acts_as_permissor, but without an :of parameter.' if params[:of].nil?
|
|
10
|
+
|
|
11
11
|
class_attribute :of
|
|
12
12
|
self.of = params[:of]
|
|
13
13
|
class_name = params[:class_name] || params[:of].to_s.classify
|
|
14
14
|
class_name.constantize.acts_as_permitted
|
|
15
15
|
|
|
16
|
-
has_many :permissions_as_permissor, :
|
|
17
|
-
has_many :permissibles, :
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
has_many :permissions_as_permissor, as: :permissor, class_name: 'PrivatePerson::Permission'
|
|
17
|
+
has_many :permissibles, through: :permissions_as_permissor, source: :permissible,
|
|
18
|
+
source_type: class_name
|
|
19
|
+
|
|
20
|
+
include InstanceMethods
|
|
20
21
|
end
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
module InstanceMethods
|
|
24
25
|
def permit!(whom, what)
|
|
25
|
-
existing =
|
|
26
|
+
existing = permissions_as_permissor.by_relationship_type(whom).by_permissible(what)
|
|
26
27
|
|
|
27
|
-
if existing.empty?
|
|
28
|
-
|
|
29
|
-
end
|
|
30
|
-
self.permissions_as_permissor.reload
|
|
28
|
+
permissions_as_permissor.create!(permission_params(whom, what)) if existing.empty?
|
|
29
|
+
permissions_as_permissor.reload
|
|
31
30
|
end
|
|
32
31
|
|
|
33
32
|
def wildcard_permit!(whom, what)
|
|
34
|
-
existing =
|
|
33
|
+
existing = permissions_as_permissor.by_relationship_type(whom).where(permissible_type: what)
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# end
|
|
39
|
-
self.permissions_as_permissor.reload
|
|
35
|
+
permissions_as_permissor.create!(wildcard_permission_params(whom, what)) if existing.empty?
|
|
36
|
+
permissions_as_permissor.reload
|
|
40
37
|
end
|
|
41
38
|
|
|
42
39
|
def permission_params(whom, what)
|
|
43
|
-
|
|
44
|
-
:
|
|
45
|
-
:
|
|
46
|
-
:
|
|
47
|
-
}
|
|
40
|
+
{
|
|
41
|
+
relationship_type: whom,
|
|
42
|
+
permissible_type: what.class.name,
|
|
43
|
+
permissible_id: what.id
|
|
44
|
+
}
|
|
48
45
|
end
|
|
49
46
|
|
|
50
47
|
def wildcard_permission_params(whom, what)
|
|
51
|
-
|
|
52
|
-
:
|
|
53
|
-
:
|
|
54
|
-
}
|
|
48
|
+
{
|
|
49
|
+
relationship_type: whom,
|
|
50
|
+
permissible_type: what
|
|
51
|
+
}
|
|
55
52
|
end
|
|
56
53
|
end
|
|
57
54
|
end
|
|
58
|
-
end
|
|
55
|
+
end
|