followability 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Gem Version](https://badge.fury.io/rb/
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/followability.svg)](https://badge.fury.io/rb/followability)
|
2
2
|
![test](https://github.com/nejdetkadir/followability/actions/workflows/test.yml/badge.svg?branch=main)
|
3
3
|
![rubocop](https://github.com/nejdetkadir/followability/actions/workflows/rubocop.yml/badge.svg?branch=main)
|
4
4
|
[![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](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
|