followability 0.1.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 +4 -4
- data/.rubocop.yml +7 -1
- data/CHANGELOG.md +13 -1
- data/Gemfile +12 -0
- data/Gemfile.lock +132 -0
- data/README.md +218 -5
- data/config/locales/en.yml +28 -0
- data/lib/followability/followable/actions/block.rb +80 -0
- data/lib/followability/followable/actions/common.rb +13 -0
- data/lib/followability/followable/actions/follow.rb +154 -0
- data/lib/followability/followable/associations.rb +15 -0
- data/lib/followability/followable/callbacks.rb +31 -0
- data/lib/followability/followable.rb +56 -0
- data/lib/followability/generators/install_generator.rb +40 -0
- data/lib/followability/relationship.rb +18 -0
- data/lib/followability/version.rb +1 -1
- data/lib/followability.rb +17 -2
- metadata +11 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 74981f3a807c733f78c36f78ebec08e18f9469415ca5fe500ba902a244f2490a
|
|
4
|
+
data.tar.gz: 49109e4a45692f73f206b3847610d0c725a8837b7a561d5f99b5641e6e53e89c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd0716f68c519a24544e47d9d88c21a1eb006485c99b92419cd166dcd847c9876e2b3fa3df968afd061e8ce3a13ff481893e8dd09f331aad47e045a505b5ab4b
|
|
7
|
+
data.tar.gz: 29b0bda4d267f4d8b34a1a5f438e64eb5135e775af9cb283815570e417fd35eb322e7e1b612062b3a2972fc58904b70c41bfe353d9f66cd12758f24277170fe2
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
## [
|
|
1
|
+
## [1.0.0] - 2022-10-15
|
|
2
|
+
- Added belowing methods
|
|
3
|
+
- decline_follow_request_of
|
|
4
|
+
- remove_follow_request_for
|
|
5
|
+
- send_follow_request_to
|
|
6
|
+
- following?
|
|
7
|
+
- mutual_following_with?
|
|
8
|
+
- sent_follow_request_to?
|
|
9
|
+
- block_to
|
|
10
|
+
- unblock_to
|
|
11
|
+
- blocked?
|
|
12
|
+
- blocked_by?
|
|
13
|
+
- myself?
|
|
2
14
|
|
|
3
15
|
## [0.1.0] - 2022-10-14
|
|
4
16
|
|
data/Gemfile
CHANGED
|
@@ -25,3 +25,15 @@ gem 'dry-configurable', '~> 0.15.0'
|
|
|
25
25
|
|
|
26
26
|
# Pry is a runtime developer console and IRB alternative with powerful introspection capabilities [https://github.com/pry/pry]
|
|
27
27
|
gem 'pry', '~> 0.14.1'
|
|
28
|
+
|
|
29
|
+
# A toolkit of support libraries and Ruby core extensions extracted from the Rails framework [https://github.com/rails/rails]
|
|
30
|
+
gem 'activesupport', '>= 5.0', '>= 7.0.4'
|
|
31
|
+
|
|
32
|
+
# A toolkit for building modeling frameworks like Active Record [https://github.com/rails/rails]
|
|
33
|
+
gem 'activemodel', '>= 5.0', '>= 7.0.4'
|
|
34
|
+
|
|
35
|
+
# Databases on Rails. Build a persistent domain model by mapping database tables to Ruby classes [https://github.com/rails/rails]
|
|
36
|
+
gem 'activerecord', '>= 5.0', '>= 7.0.4'
|
|
37
|
+
|
|
38
|
+
# Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity [https://github.com/rails/rails]
|
|
39
|
+
gem 'rails', '>= 5.0', '>= 7.0.4'
|
data/Gemfile.lock
CHANGED
|
@@ -6,10 +6,77 @@ PATH
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
+
actioncable (7.0.4)
|
|
10
|
+
actionpack (= 7.0.4)
|
|
11
|
+
activesupport (= 7.0.4)
|
|
12
|
+
nio4r (~> 2.0)
|
|
13
|
+
websocket-driver (>= 0.6.1)
|
|
14
|
+
actionmailbox (7.0.4)
|
|
15
|
+
actionpack (= 7.0.4)
|
|
16
|
+
activejob (= 7.0.4)
|
|
17
|
+
activerecord (= 7.0.4)
|
|
18
|
+
activestorage (= 7.0.4)
|
|
19
|
+
activesupport (= 7.0.4)
|
|
20
|
+
mail (>= 2.7.1)
|
|
21
|
+
net-imap
|
|
22
|
+
net-pop
|
|
23
|
+
net-smtp
|
|
24
|
+
actionmailer (7.0.4)
|
|
25
|
+
actionpack (= 7.0.4)
|
|
26
|
+
actionview (= 7.0.4)
|
|
27
|
+
activejob (= 7.0.4)
|
|
28
|
+
activesupport (= 7.0.4)
|
|
29
|
+
mail (~> 2.5, >= 2.5.4)
|
|
30
|
+
net-imap
|
|
31
|
+
net-pop
|
|
32
|
+
net-smtp
|
|
33
|
+
rails-dom-testing (~> 2.0)
|
|
34
|
+
actionpack (7.0.4)
|
|
35
|
+
actionview (= 7.0.4)
|
|
36
|
+
activesupport (= 7.0.4)
|
|
37
|
+
rack (~> 2.0, >= 2.2.0)
|
|
38
|
+
rack-test (>= 0.6.3)
|
|
39
|
+
rails-dom-testing (~> 2.0)
|
|
40
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
41
|
+
actiontext (7.0.4)
|
|
42
|
+
actionpack (= 7.0.4)
|
|
43
|
+
activerecord (= 7.0.4)
|
|
44
|
+
activestorage (= 7.0.4)
|
|
45
|
+
activesupport (= 7.0.4)
|
|
46
|
+
globalid (>= 0.6.0)
|
|
47
|
+
nokogiri (>= 1.8.5)
|
|
48
|
+
actionview (7.0.4)
|
|
49
|
+
activesupport (= 7.0.4)
|
|
50
|
+
builder (~> 3.1)
|
|
51
|
+
erubi (~> 1.4)
|
|
52
|
+
rails-dom-testing (~> 2.0)
|
|
53
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
54
|
+
activejob (7.0.4)
|
|
55
|
+
activesupport (= 7.0.4)
|
|
56
|
+
globalid (>= 0.3.6)
|
|
57
|
+
activemodel (7.0.4)
|
|
58
|
+
activesupport (= 7.0.4)
|
|
59
|
+
activerecord (7.0.4)
|
|
60
|
+
activemodel (= 7.0.4)
|
|
61
|
+
activesupport (= 7.0.4)
|
|
62
|
+
activestorage (7.0.4)
|
|
63
|
+
actionpack (= 7.0.4)
|
|
64
|
+
activejob (= 7.0.4)
|
|
65
|
+
activerecord (= 7.0.4)
|
|
66
|
+
activesupport (= 7.0.4)
|
|
67
|
+
marcel (~> 1.0)
|
|
68
|
+
mini_mime (>= 1.1.0)
|
|
69
|
+
activesupport (7.0.4)
|
|
70
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
71
|
+
i18n (>= 1.6, < 2)
|
|
72
|
+
minitest (>= 5.1)
|
|
73
|
+
tzinfo (~> 2.0)
|
|
9
74
|
ast (2.4.2)
|
|
10
75
|
awesome_print (1.9.2)
|
|
76
|
+
builder (3.2.4)
|
|
11
77
|
coderay (1.1.3)
|
|
12
78
|
concurrent-ruby (1.1.10)
|
|
79
|
+
crass (1.0.6)
|
|
13
80
|
dry-configurable (0.15.0)
|
|
14
81
|
concurrent-ruby (~> 1.0)
|
|
15
82
|
dry-core (~> 0.6)
|
|
@@ -18,15 +85,68 @@ GEM
|
|
|
18
85
|
dry-monads (1.4.0)
|
|
19
86
|
concurrent-ruby (~> 1.0)
|
|
20
87
|
dry-core (~> 0.7)
|
|
88
|
+
erubi (1.11.0)
|
|
89
|
+
globalid (1.0.0)
|
|
90
|
+
activesupport (>= 5.0)
|
|
91
|
+
i18n (1.12.0)
|
|
92
|
+
concurrent-ruby (~> 1.0)
|
|
21
93
|
json (2.6.2)
|
|
94
|
+
loofah (2.19.0)
|
|
95
|
+
crass (~> 1.0.2)
|
|
96
|
+
nokogiri (>= 1.5.9)
|
|
97
|
+
mail (2.7.1)
|
|
98
|
+
mini_mime (>= 0.1.1)
|
|
99
|
+
marcel (1.0.2)
|
|
22
100
|
method_source (1.0.0)
|
|
101
|
+
mini_mime (1.1.2)
|
|
23
102
|
minitest (5.16.3)
|
|
103
|
+
net-imap (0.3.1)
|
|
104
|
+
net-protocol
|
|
105
|
+
net-pop (0.1.2)
|
|
106
|
+
net-protocol
|
|
107
|
+
net-protocol (0.1.3)
|
|
108
|
+
timeout
|
|
109
|
+
net-smtp (0.3.2)
|
|
110
|
+
net-protocol
|
|
111
|
+
nio4r (2.5.8)
|
|
112
|
+
nokogiri (1.13.8-arm64-darwin)
|
|
113
|
+
racc (~> 1.4)
|
|
24
114
|
parallel (1.22.1)
|
|
25
115
|
parser (3.1.2.1)
|
|
26
116
|
ast (~> 2.4.1)
|
|
27
117
|
pry (0.14.1)
|
|
28
118
|
coderay (~> 1.1)
|
|
29
119
|
method_source (~> 1.0)
|
|
120
|
+
racc (1.6.0)
|
|
121
|
+
rack (2.2.4)
|
|
122
|
+
rack-test (2.0.2)
|
|
123
|
+
rack (>= 1.3)
|
|
124
|
+
rails (7.0.4)
|
|
125
|
+
actioncable (= 7.0.4)
|
|
126
|
+
actionmailbox (= 7.0.4)
|
|
127
|
+
actionmailer (= 7.0.4)
|
|
128
|
+
actionpack (= 7.0.4)
|
|
129
|
+
actiontext (= 7.0.4)
|
|
130
|
+
actionview (= 7.0.4)
|
|
131
|
+
activejob (= 7.0.4)
|
|
132
|
+
activemodel (= 7.0.4)
|
|
133
|
+
activerecord (= 7.0.4)
|
|
134
|
+
activestorage (= 7.0.4)
|
|
135
|
+
activesupport (= 7.0.4)
|
|
136
|
+
bundler (>= 1.15.0)
|
|
137
|
+
railties (= 7.0.4)
|
|
138
|
+
rails-dom-testing (2.0.3)
|
|
139
|
+
activesupport (>= 4.2.0)
|
|
140
|
+
nokogiri (>= 1.6)
|
|
141
|
+
rails-html-sanitizer (1.4.3)
|
|
142
|
+
loofah (~> 2.3)
|
|
143
|
+
railties (7.0.4)
|
|
144
|
+
actionpack (= 7.0.4)
|
|
145
|
+
activesupport (= 7.0.4)
|
|
146
|
+
method_source
|
|
147
|
+
rake (>= 12.2)
|
|
148
|
+
thor (~> 1.0)
|
|
149
|
+
zeitwerk (~> 2.5)
|
|
30
150
|
rainbow (3.1.1)
|
|
31
151
|
rake (13.0.6)
|
|
32
152
|
regexp_parser (2.6.0)
|
|
@@ -44,18 +164,30 @@ GEM
|
|
|
44
164
|
rubocop-ast (1.21.0)
|
|
45
165
|
parser (>= 3.1.1.0)
|
|
46
166
|
ruby-progressbar (1.11.0)
|
|
167
|
+
thor (1.2.1)
|
|
168
|
+
timeout (0.3.0)
|
|
169
|
+
tzinfo (2.0.5)
|
|
170
|
+
concurrent-ruby (~> 1.0)
|
|
47
171
|
unicode-display_width (2.3.0)
|
|
172
|
+
websocket-driver (0.7.5)
|
|
173
|
+
websocket-extensions (>= 0.1.0)
|
|
174
|
+
websocket-extensions (0.1.5)
|
|
175
|
+
zeitwerk (2.6.1)
|
|
48
176
|
|
|
49
177
|
PLATFORMS
|
|
50
178
|
arm64-darwin-21
|
|
51
179
|
|
|
52
180
|
DEPENDENCIES
|
|
181
|
+
activemodel (>= 7.0.4, >= 5.0)
|
|
182
|
+
activerecord (>= 7.0.4, >= 5.0)
|
|
183
|
+
activesupport (>= 7.0.4, >= 5.0)
|
|
53
184
|
awesome_print
|
|
54
185
|
dry-configurable (~> 0.15.0)
|
|
55
186
|
dry-monads (~> 1.4)
|
|
56
187
|
followability!
|
|
57
188
|
minitest (~> 5.0)
|
|
58
189
|
pry (~> 0.14.1)
|
|
190
|
+
rails (>= 7.0.4, >= 5.0)
|
|
59
191
|
rake (~> 13.0)
|
|
60
192
|
rubocop (~> 1.21)
|
|
61
193
|
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://badge.fury.io/rb/followability)
|
|
2
2
|

|
|
3
3
|

|
|
4
4
|
[](https://github.com/rubocop/rubocop)
|
|
@@ -13,15 +13,228 @@ gem 'followability', github: 'nejdetkadir/followability', branch: 'main'
|
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Install the gem and add to the application's Gemfile by executing:
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
```bash
|
|
17
|
+
$ bundle add followability
|
|
18
|
+
```
|
|
18
19
|
|
|
19
20
|
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
21
|
+
```bash
|
|
22
|
+
$ gem install followability
|
|
23
|
+
```
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
Run the generator for creating database migration and copying localization files.
|
|
26
|
+
```bash
|
|
27
|
+
$ rails g followability:install
|
|
28
|
+
```
|
|
22
29
|
|
|
23
30
|
## Usage
|
|
24
|
-
|
|
31
|
+
Simply drop in `followability` to a model:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
class User < ActiveRecord::Base
|
|
35
|
+
followability
|
|
36
|
+
end
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Now, instances of `User` have followability.
|
|
40
|
+
```ruby
|
|
41
|
+
User.followability?
|
|
42
|
+
# => true
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Following actions
|
|
46
|
+
Avaiable methods:
|
|
47
|
+
- decline_follow_request_of
|
|
48
|
+
- remove_follow_request_for
|
|
49
|
+
- send_follow_request_to
|
|
50
|
+
- following?
|
|
51
|
+
- mutual_following_with?
|
|
52
|
+
- sent_follow_request_to?
|
|
53
|
+
|
|
54
|
+
### Usage
|
|
55
|
+
```ruby
|
|
56
|
+
@foo = User.first
|
|
57
|
+
@bar = User.last
|
|
58
|
+
|
|
59
|
+
@foo.send_follow_request_to(@bar)
|
|
60
|
+
# => true
|
|
61
|
+
|
|
62
|
+
@foo.sent_follow_request_to?(@bar)
|
|
63
|
+
# => true
|
|
64
|
+
|
|
65
|
+
@bar.decline_follow_request_of(@foo)
|
|
66
|
+
# => true
|
|
67
|
+
|
|
68
|
+
@bar.accept_follow_request_of(@foo)
|
|
69
|
+
# => false
|
|
70
|
+
|
|
71
|
+
@bar.errors.full_messages
|
|
72
|
+
# => [...]
|
|
73
|
+
|
|
74
|
+
@foo.remove_follow_request_for(@bar)
|
|
75
|
+
# => false
|
|
76
|
+
|
|
77
|
+
@foo.errors.full_messages
|
|
78
|
+
# => [...]
|
|
79
|
+
|
|
80
|
+
@foo.mutual_following_with?(@bar)
|
|
81
|
+
# => false
|
|
82
|
+
|
|
83
|
+
@foo.errors.full_messages
|
|
84
|
+
# => [...]
|
|
85
|
+
|
|
86
|
+
@bar.following?(@foo)
|
|
87
|
+
# => false
|
|
88
|
+
|
|
89
|
+
@foo.errors.full_messages
|
|
90
|
+
# => [...]
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Blocking actions
|
|
95
|
+
Avaiable methods:
|
|
96
|
+
- block_to
|
|
97
|
+
- unblock_to
|
|
98
|
+
- blocked?
|
|
99
|
+
- blocked_by?
|
|
100
|
+
|
|
101
|
+
### Usage
|
|
102
|
+
```ruby
|
|
103
|
+
@foo.block_to(@bar)
|
|
104
|
+
# => true
|
|
105
|
+
|
|
106
|
+
@foo.blocked?(@bar)
|
|
107
|
+
# => true
|
|
108
|
+
|
|
109
|
+
@bar.blocked_by?(@foo)
|
|
110
|
+
# => true
|
|
111
|
+
|
|
112
|
+
@foo.unblock_to(@bar)
|
|
113
|
+
# => true
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Common
|
|
117
|
+
Avaiable methods:
|
|
118
|
+
- myself?
|
|
119
|
+
|
|
120
|
+
### Usage
|
|
121
|
+
```ruby
|
|
122
|
+
class User < ActiveRecord::Base
|
|
123
|
+
followability
|
|
124
|
+
|
|
125
|
+
def follow_request_removed_by_someone(record)
|
|
126
|
+
unless myself?(record)
|
|
127
|
+
# Do something
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Relations
|
|
134
|
+
Avaiable methods:
|
|
135
|
+
- follow_requests
|
|
136
|
+
- pending_requests
|
|
137
|
+
- followerable_relationships
|
|
138
|
+
- followable_relationships
|
|
139
|
+
- followers
|
|
140
|
+
- following
|
|
141
|
+
- blocks
|
|
142
|
+
|
|
143
|
+
### Usage
|
|
144
|
+
```ruby
|
|
145
|
+
@foo.follow_requests
|
|
146
|
+
# => [#<Followability::Relationship ...>]
|
|
147
|
+
|
|
148
|
+
@foo.pending_requests
|
|
149
|
+
# => [#<Followability::Relationship ...>]
|
|
150
|
+
|
|
151
|
+
@foo.followerable_relationships
|
|
152
|
+
# => [#<Followability::Relationship ...>]
|
|
153
|
+
|
|
154
|
+
@foo.followable_relationships
|
|
155
|
+
# => [#<Followability::Relationship ...>]
|
|
156
|
+
|
|
157
|
+
@foo.followers
|
|
158
|
+
# => [#<User ...>]
|
|
159
|
+
|
|
160
|
+
@foo.following
|
|
161
|
+
# => [#<User ...>]
|
|
162
|
+
|
|
163
|
+
@foo.blocks
|
|
164
|
+
# => [#<User ...>]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Callback Methods
|
|
168
|
+
Available methods:
|
|
169
|
+
- follow_request_sent_to_me
|
|
170
|
+
- follow_request_sent_to_someone
|
|
171
|
+
- follow_request_accepted_by_me
|
|
172
|
+
- follow_request_accepted_by_someone
|
|
173
|
+
- follow_request_declined_by_me
|
|
174
|
+
- follow_request_declined_by_someone
|
|
175
|
+
- follow_request_removed_by_me
|
|
176
|
+
- follow_request_removed_by_someone
|
|
177
|
+
- followable_blocked_by_me
|
|
178
|
+
- followable_blocked_by_someone
|
|
179
|
+
- followable_unblocked_by_me
|
|
180
|
+
- followable_unblocked_by_someone
|
|
181
|
+
- followability_triggered
|
|
182
|
+
|
|
183
|
+
### Usage
|
|
184
|
+
```ruby
|
|
185
|
+
class User < ActiveRecord::Base
|
|
186
|
+
followability
|
|
187
|
+
|
|
188
|
+
def follow_request_sent_to_me(record)
|
|
189
|
+
Notifications::FollowRequestSentToMeJob.perform_later(from_id: record.id)
|
|
190
|
+
end
|
|
191
|
+
def follow_request_sent_to_someone(record); end
|
|
192
|
+
def follow_request_accepted_by_me(record); end
|
|
193
|
+
def follow_request_accepted_by_someone(record); end
|
|
194
|
+
def follow_request_declined_by_me(record); end
|
|
195
|
+
def follow_request_declined_by_someone(record); end
|
|
196
|
+
def follow_request_removed_by_me(record); end
|
|
197
|
+
def follow_request_removed_by_someone(record); end
|
|
198
|
+
def followable_blocked_by_me(record); end
|
|
199
|
+
def followable_blocked_by_someone(record); end
|
|
200
|
+
def followable_unblocked_by_me(record); end
|
|
201
|
+
def followable_unblocked_by_someone(record); end
|
|
202
|
+
def followability_triggered(record, callback_name); end
|
|
203
|
+
end
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## I18n
|
|
207
|
+
```yml
|
|
208
|
+
---
|
|
209
|
+
---
|
|
210
|
+
en:
|
|
211
|
+
followability:
|
|
212
|
+
errors:
|
|
213
|
+
block:
|
|
214
|
+
unblock_to:
|
|
215
|
+
myself: 'You can not run this action for yourself'
|
|
216
|
+
block_to:
|
|
217
|
+
myself: 'You can not run this action for yourself'
|
|
218
|
+
blocked_by: 'You can not block to who blocked to you'
|
|
219
|
+
already_blocked: '%{klass} already blocked'
|
|
220
|
+
not_blocked_for_blocking: 'You can not unblock to %{klass} because was not blocked'
|
|
221
|
+
follow:
|
|
222
|
+
decline_follow_request_of:
|
|
223
|
+
myself: 'You can not run this action for yourself'
|
|
224
|
+
empty_relation: 'You can not decline follow request of %{klass} because was not sent'
|
|
225
|
+
accept_follow_request_of:
|
|
226
|
+
myself: 'You can not run this action for yourself'
|
|
227
|
+
empty_relation: 'You can not accept follow request of %{klass} because was not sent'
|
|
228
|
+
remove_follow_request_for:
|
|
229
|
+
empty_relation: 'You can not remove follow request of %{klass} because was not sent'
|
|
230
|
+
myself: 'You can not run this action for yourself'
|
|
231
|
+
send_follow_request_to:
|
|
232
|
+
myself: 'You can not run this action for yourself'
|
|
233
|
+
blocked_by: 'You can not send follow request to who blocked to you'
|
|
234
|
+
following: 'You are already following to %{klass}'
|
|
235
|
+
already_sent: 'You are already sent follow request'
|
|
236
|
+
blocked: 'You can not send follow request to blocked %{klass}'
|
|
237
|
+
```
|
|
25
238
|
|
|
26
239
|
## Development
|
|
27
240
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
en:
|
|
3
|
+
followability:
|
|
4
|
+
errors:
|
|
5
|
+
block:
|
|
6
|
+
unblock_to:
|
|
7
|
+
myself: 'You can not run this action for yourself'
|
|
8
|
+
block_to:
|
|
9
|
+
myself: 'You can not run this action for yourself'
|
|
10
|
+
blocked_by: 'You can not block to who blocked to you'
|
|
11
|
+
already_blocked: '%{klass} already blocked'
|
|
12
|
+
not_blocked_for_blocking: 'You can not unblock to %{klass} because was not blocked'
|
|
13
|
+
follow:
|
|
14
|
+
decline_follow_request_of:
|
|
15
|
+
myself: 'You can not run this action for yourself'
|
|
16
|
+
empty_relation: 'You can not decline follow request of %{klass} because was not sent'
|
|
17
|
+
accept_follow_request_of:
|
|
18
|
+
myself: 'You can not run this action for yourself'
|
|
19
|
+
empty_relation: 'You can not accept follow request of %{klass} because was not sent'
|
|
20
|
+
remove_follow_request_for:
|
|
21
|
+
empty_relation: 'You can not remove follow request of %{klass} because was not sent'
|
|
22
|
+
myself: 'You can not run this action for yourself'
|
|
23
|
+
send_follow_request_to:
|
|
24
|
+
myself: 'You can not run this action for yourself'
|
|
25
|
+
blocked_by: 'You can not send follow request to who blocked to you'
|
|
26
|
+
following: 'You are already following to %{klass}'
|
|
27
|
+
already_sent: 'You are already sent follow request'
|
|
28
|
+
blocked: 'You can not send follow request to blocked %{klass}'
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Followability
|
|
4
|
+
module Followable
|
|
5
|
+
module Actions
|
|
6
|
+
module Block
|
|
7
|
+
I18N_SCOPE = 'followability.errors.block'
|
|
8
|
+
|
|
9
|
+
def block_to(record)
|
|
10
|
+
if myself?(record)
|
|
11
|
+
errors.add(:base, I18n.t('block_to.myself', scope: I18N_SCOPE, klass: record.class))
|
|
12
|
+
|
|
13
|
+
return false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if blocked_by?(record)
|
|
17
|
+
errors.add(:base, I18n.t('block_to.blocked_by', scope: I18N_SCOPE, klass: record.class))
|
|
18
|
+
|
|
19
|
+
return false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if blocked?(record)
|
|
23
|
+
errors.add(:base, I18n.t('block.already_blocked', scope: I18N_SCOPE, klass: record.class))
|
|
24
|
+
|
|
25
|
+
return false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
relation = followerable_relationships.blocked.new(followable: record,
|
|
29
|
+
status: Followability::Relationship.statuses[:blocked])
|
|
30
|
+
|
|
31
|
+
if relation.save
|
|
32
|
+
run_callback(self, affected: record, callback: :followable_blocked_by_me)
|
|
33
|
+
run_callback(record, affected: self, callback: :followable_blocked_by_someone)
|
|
34
|
+
|
|
35
|
+
true
|
|
36
|
+
else
|
|
37
|
+
errors.add(:base, relation.errors.full_messages.to_sentence)
|
|
38
|
+
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def unblock_to(record)
|
|
44
|
+
if myself?(record)
|
|
45
|
+
errors.add(:base, I18n.t('unblock_to.myself', scope: I18N_SCOPE, klass: record.class))
|
|
46
|
+
|
|
47
|
+
return false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
unless blocked?(record)
|
|
51
|
+
errors.add(:base, I18n.t(:not_blocked_for_blocking, scope: I18N_SCOPE, klass: record.class))
|
|
52
|
+
|
|
53
|
+
return false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
relation = followerable_relationships.blocked.find_by(followable: record)
|
|
57
|
+
|
|
58
|
+
if relation.destroy
|
|
59
|
+
run_callback(self, affected: record, callback: :followable_unblocked_by_me)
|
|
60
|
+
run_callback(record, affected: self, callback: :followable_unblocked_by_someone)
|
|
61
|
+
|
|
62
|
+
true
|
|
63
|
+
else
|
|
64
|
+
errors.add(:base, relation.errors.full_messages.to_sentence)
|
|
65
|
+
|
|
66
|
+
false
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def blocked?(record)
|
|
71
|
+
followerable_relationships.blocked.exists?(followable: record)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def blocked_by?(record)
|
|
75
|
+
record.followerable_relationships.blocked.exists?(followable: self)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/ModuleLength
|
|
4
|
+
module Followability
|
|
5
|
+
module Followable
|
|
6
|
+
module Actions
|
|
7
|
+
module Follow
|
|
8
|
+
I18N_SCOPE = 'followability.errors.follow'
|
|
9
|
+
|
|
10
|
+
def decline_follow_request_of(record)
|
|
11
|
+
if myself?(record)
|
|
12
|
+
errors.add(:base, I18n.t('decline_follow_request_of.myself', scope: I18N_SCOPE, klass: record.class))
|
|
13
|
+
|
|
14
|
+
return false
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
relation = follow_requests.find_by(followerable_id: record.id, followerable_type: record.class.name)
|
|
18
|
+
|
|
19
|
+
if relation.blank?
|
|
20
|
+
errors.add(:base,
|
|
21
|
+
I18n.t('decline_follow_request_of.empty_relation', scope: I18N_SCOPE, klass: record.class.name))
|
|
22
|
+
|
|
23
|
+
false
|
|
24
|
+
elsif relation.destroy
|
|
25
|
+
run_callback(self, affected: record, callback: :follow_request_declined_by_me)
|
|
26
|
+
run_callback(record, affected: self, callback: :follow_request_declined_by_someone)
|
|
27
|
+
|
|
28
|
+
true
|
|
29
|
+
else
|
|
30
|
+
errors.add(:base, relation.errors.full_messages.to_sentence)
|
|
31
|
+
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def accept_follow_request_of(record)
|
|
37
|
+
if myself?(record)
|
|
38
|
+
errors.add(:base, I18n.t('accept_follow_request_of.myself', scope: I18N_SCOPE, klass: record.class))
|
|
39
|
+
|
|
40
|
+
return false
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
relation = follow_requests.find_by(followerable_id: record.id, followerable_type: record.class.name)
|
|
44
|
+
|
|
45
|
+
if relation.blank?
|
|
46
|
+
errors.add(:base,
|
|
47
|
+
I18n.t('accept_follow_request_of.empty_relation', scope: I18N_SCOPE, klass: record.class.name))
|
|
48
|
+
|
|
49
|
+
false
|
|
50
|
+
elsif relation.update(status: Followability::Relationship.statuses[:following])
|
|
51
|
+
run_callback(record, affected: record, callback: :follow_request_accepted_by_someone)
|
|
52
|
+
run_callback(self, affected: self, callback: :follow_request_accepted_by_me)
|
|
53
|
+
|
|
54
|
+
true
|
|
55
|
+
else
|
|
56
|
+
errors.add(:base, relation.errors.full_messages.to_sentence)
|
|
57
|
+
|
|
58
|
+
false
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def remove_follow_request_for(record)
|
|
63
|
+
if myself?(record)
|
|
64
|
+
errors.add(:base, I18n.t('remove_follow_request_for.myself', scope: I18N_SCOPE, klass: record.class))
|
|
65
|
+
|
|
66
|
+
return false
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
relation = pending_requests.find_by(followable_id: record.id, followable_type: record.class.name)
|
|
70
|
+
|
|
71
|
+
if relation.blank?
|
|
72
|
+
errors.add(:base,
|
|
73
|
+
I18n.t('remove_follow_request_for.empty_relation', scope: I18N_SCOPE, klass: record.class.name))
|
|
74
|
+
|
|
75
|
+
false
|
|
76
|
+
elsif relation.destroy
|
|
77
|
+
run_callback(self, affected: record, callback: :follow_request_removed_by_me)
|
|
78
|
+
run_callback(record, affected: self, callback: :follow_request_removed_by_someone)
|
|
79
|
+
|
|
80
|
+
true
|
|
81
|
+
else
|
|
82
|
+
errors.add(:base, relation.errors.full_messages.to_sentence)
|
|
83
|
+
|
|
84
|
+
false
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
89
|
+
def send_follow_request_to(record)
|
|
90
|
+
if myself?(record)
|
|
91
|
+
errors.add(:base, I18n.t('send_follow_request_to.myself', scope: I18N_SCOPE, klass: record.class))
|
|
92
|
+
|
|
93
|
+
return false
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
if blocked_by?(record)
|
|
97
|
+
errors.add(:base, I18n.t('send_follow_request_to.blocked_by', scope: I18N_SCOPE, klass: record.class.name))
|
|
98
|
+
|
|
99
|
+
return false
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if following?(record)
|
|
103
|
+
errors.add(:base,
|
|
104
|
+
I18n.t('send_follow_request_to.following', scope: I18N_SCOPE,
|
|
105
|
+
klass: pluralize(record.class.name)))
|
|
106
|
+
|
|
107
|
+
return false
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if sent_follow_request_to?(record)
|
|
111
|
+
errors.add(:base,
|
|
112
|
+
I18n.t('send_follow_request_to.already_sent', scope: I18N_SCOPE, klass: record.class.name))
|
|
113
|
+
|
|
114
|
+
return false
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
if blocked?(record)
|
|
118
|
+
errors.add(:base, I18n.t('send_follow_request_to.blocked', scope: I18N_SCOPE, klass: record.class.name))
|
|
119
|
+
|
|
120
|
+
return false
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
relation = pending_requests.new(followable: record,
|
|
124
|
+
status: Followability::Relationship.statuses[:requested])
|
|
125
|
+
|
|
126
|
+
if relation.save
|
|
127
|
+
run_callback(self, affected: record, callback: :follow_request_sent_to_someone)
|
|
128
|
+
run_callback(record, affected: self, callback: :follow_request_sent_to_me)
|
|
129
|
+
|
|
130
|
+
true
|
|
131
|
+
else
|
|
132
|
+
errors.add(:base, relation.errors.full_messages.to_sentence)
|
|
133
|
+
|
|
134
|
+
false
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
138
|
+
|
|
139
|
+
def following?(record)
|
|
140
|
+
following.exists?(id: record.id)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def mutual_following_with?(record)
|
|
144
|
+
following.exists?(id: record.id) && followers.exists?(id: record.id)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def sent_follow_request_to?(record)
|
|
148
|
+
record.follow_requests.exists?(followerable_id: id, followerable_type: self.class.name)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
# rubocop:enable Metrics/ModuleLength
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Followability
|
|
4
|
+
module Followable
|
|
5
|
+
module Associations
|
|
6
|
+
def follow_requests
|
|
7
|
+
followable_relationships.requested
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def pending_requests
|
|
11
|
+
followerable_relationships.requested
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Followability
|
|
4
|
+
module Followable
|
|
5
|
+
module Callbacks
|
|
6
|
+
METHOD_NAMES = %i[
|
|
7
|
+
follow_request_sent_to_someone
|
|
8
|
+
follow_request_sent_to_me
|
|
9
|
+
follow_request_accepted_by_me
|
|
10
|
+
follow_request_accepted_by_someone
|
|
11
|
+
follow_request_declined_by_me
|
|
12
|
+
follow_request_declined_by_someone
|
|
13
|
+
follow_request_removed_by_me
|
|
14
|
+
follow_request_removed_by_someone
|
|
15
|
+
followable_blocked_by_me
|
|
16
|
+
followable_blocked_by_someone
|
|
17
|
+
followable_unblocked_by_me
|
|
18
|
+
followable_unblocked_by_someone
|
|
19
|
+
followability_triggered
|
|
20
|
+
].freeze
|
|
21
|
+
|
|
22
|
+
def run_callback(record, callback:, affected:)
|
|
23
|
+
raise ArgumentError if METHOD_NAMES.exclude?(callback) || callback.eql?(:followability_triggered)
|
|
24
|
+
|
|
25
|
+
[callback, :followability_triggered].each do |cb_name|
|
|
26
|
+
record.send(cb_name, affected, cb_name) if record.respond_to?(cb_name)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Followability
|
|
4
|
+
module Followable
|
|
5
|
+
def followability?
|
|
6
|
+
false
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# rubocop:disable Metrics/MethodLength
|
|
10
|
+
def followability
|
|
11
|
+
class_eval do
|
|
12
|
+
def self.followability?
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
has_many :followerable_relationships,
|
|
17
|
+
as: :followerable,
|
|
18
|
+
class_name: 'Followability::Relationship',
|
|
19
|
+
dependent: :destroy
|
|
20
|
+
|
|
21
|
+
has_many :followable_relationships,
|
|
22
|
+
as: :followable,
|
|
23
|
+
class_name: 'Followability::Relationship',
|
|
24
|
+
dependent: :destroy
|
|
25
|
+
|
|
26
|
+
has_many :followers,
|
|
27
|
+
-> { Followability::Relationship.following },
|
|
28
|
+
through: :followable_relationships,
|
|
29
|
+
source: :followerable,
|
|
30
|
+
class_name: name,
|
|
31
|
+
source_type: name
|
|
32
|
+
|
|
33
|
+
has_many :following,
|
|
34
|
+
-> { Followability::Relationship.following },
|
|
35
|
+
through: :followerable_relationships,
|
|
36
|
+
source: :followable,
|
|
37
|
+
class_name: name,
|
|
38
|
+
source_type: name
|
|
39
|
+
|
|
40
|
+
has_many :blocks,
|
|
41
|
+
-> { Followability::Relationship.blocked },
|
|
42
|
+
through: :followerable_relationships,
|
|
43
|
+
source: :followable,
|
|
44
|
+
class_name: name,
|
|
45
|
+
source_type: name
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
include Followability::Followable::Associations
|
|
49
|
+
include Followability::Followable::Callbacks
|
|
50
|
+
include Followability::Followable::Actions::Common
|
|
51
|
+
include Followability::Followable::Actions::Follow
|
|
52
|
+
include Followability::Followable::Actions::Block
|
|
53
|
+
end
|
|
54
|
+
# rubocop:enable Metrics/MethodLength
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
|
|
5
|
+
module Followability
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
|
9
|
+
|
|
10
|
+
def create_migration
|
|
11
|
+
invoke 'migration', migration_args
|
|
12
|
+
copy_file locale_source, locale_destination
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def fields_command
|
|
16
|
+
%w[
|
|
17
|
+
followerable:belongs_to{polymorphic}
|
|
18
|
+
followable:belongs_to{polymorphic}
|
|
19
|
+
status:integer
|
|
20
|
+
]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def locale_source
|
|
24
|
+
File.expand_path('../../../config/locales/en.yml', __dir__)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def locale_destination
|
|
28
|
+
'config/locales/followability.en.yml'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def migration_name
|
|
32
|
+
'CreateFollowabilityRelationships'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def migration_args
|
|
36
|
+
[migration_name].concat(fields_command)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Followability
|
|
4
|
+
class Relationship < ActiveRecord::Base
|
|
5
|
+
STATUSES = %i[requested blocked following].freeze
|
|
6
|
+
|
|
7
|
+
enum status: STATUSES
|
|
8
|
+
|
|
9
|
+
validates :status, presence: true
|
|
10
|
+
|
|
11
|
+
belongs_to :followerable, polymorphic: true, optional: false
|
|
12
|
+
belongs_to :followable, polymorphic: true, optional: false
|
|
13
|
+
|
|
14
|
+
def self.table_name_prefix
|
|
15
|
+
'followability_'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/followability.rb
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'followability/version'
|
|
4
|
+
require 'active_support'
|
|
5
|
+
require 'active_record'
|
|
6
|
+
require 'active_model'
|
|
4
7
|
|
|
5
8
|
module Followability
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
extend ActiveSupport::Autoload
|
|
10
|
+
|
|
11
|
+
require_relative 'followability/followable/associations'
|
|
12
|
+
require_relative 'followability/followable/callbacks'
|
|
13
|
+
require_relative 'followability/followable/actions/common'
|
|
14
|
+
require_relative 'followability/followable/actions/follow'
|
|
15
|
+
require_relative 'followability/followable/actions/block'
|
|
16
|
+
require_relative 'followability/followable'
|
|
17
|
+
require_relative 'followability/relationship'
|
|
18
|
+
require_relative 'followability/generators/install_generator'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
ActiveSupport.on_load(:active_record) do
|
|
22
|
+
extend Followability::Followable
|
|
8
23
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: followability
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- nejdetkadir
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-10-
|
|
11
|
+
date: 2022-10-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Implements the social network followable functionality for your Active
|
|
14
14
|
Record models.
|
|
@@ -27,8 +27,17 @@ files:
|
|
|
27
27
|
- LICENSE
|
|
28
28
|
- README.md
|
|
29
29
|
- Rakefile
|
|
30
|
+
- config/locales/en.yml
|
|
30
31
|
- followability.gemspec
|
|
31
32
|
- lib/followability.rb
|
|
33
|
+
- lib/followability/followable.rb
|
|
34
|
+
- lib/followability/followable/actions/block.rb
|
|
35
|
+
- lib/followability/followable/actions/common.rb
|
|
36
|
+
- lib/followability/followable/actions/follow.rb
|
|
37
|
+
- lib/followability/followable/associations.rb
|
|
38
|
+
- lib/followability/followable/callbacks.rb
|
|
39
|
+
- lib/followability/generators/install_generator.rb
|
|
40
|
+
- lib/followability/relationship.rb
|
|
32
41
|
- lib/followability/version.rb
|
|
33
42
|
- sig/followability.rbs
|
|
34
43
|
homepage: https://github.com/nejdetkadir/followability
|