amistad 0.7.5 → 0.9.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.
- data/.gitignore +4 -1
- data/Gemfile.lock +56 -39
- data/README.markdown +29 -126
- data/Rakefile +35 -1
- data/amistad.gemspec +8 -3
- data/lib/amistad.rb +14 -9
- data/lib/amistad/active_record_friend_model.rb +157 -0
- data/lib/amistad/active_record_friendship_model.rb +52 -0
- data/lib/amistad/config.rb +21 -0
- data/lib/amistad/friend_model.rb +10 -4
- data/lib/amistad/friendship_model.rb +2 -2
- data/lib/amistad/friendships.rb +19 -0
- data/lib/amistad/mongo_friend_model.rb +168 -0
- data/lib/amistad/mongo_mapper_friend_model.rb +58 -0
- data/lib/amistad/mongoid_friend_model.rb +58 -0
- data/lib/amistad/version.rb +1 -1
- data/lib/generators/amistad/install/install_generator.rb +0 -1
- data/lib/generators/amistad/install/templates/create_friendships.rb +2 -2
- data/spec/activerecord/activerecord_spec_helper.rb +11 -24
- data/spec/activerecord/friend_custom_model_spec.rb +17 -0
- data/spec/activerecord/friend_spec.rb +16 -0
- data/spec/activerecord/friendship_spec.rb +13 -0
- data/spec/activerecord/friendship_with_custom_friend_model_spec.rb +18 -0
- data/spec/mongo_mapper/friend_custom_model_spec.rb +27 -0
- data/spec/mongo_mapper/friend_spec.rb +17 -0
- data/spec/mongo_mapper/mongo_mapper_spec_helper.rb +9 -0
- data/spec/mongoid/friend_custom_model_spec.rb +27 -0
- data/spec/mongoid/friend_spec.rb +17 -0
- data/spec/mongoid/mongoid_spec_helper.rb +8 -7
- data/spec/spec_helper.rb +33 -4
- data/spec/{activerecord/activerecord_friendship_model_spec.rb → support/activerecord/friendship_examples.rb} +11 -23
- data/spec/support/activerecord/schema.rb +40 -0
- data/spec/support/friend_examples.rb +2 -12
- data/spec/support/parameterized_models.rb +19 -0
- metadata +177 -36
- data/lib/amistad/active_record/friend_model.rb +0 -146
- data/lib/amistad/active_record/friendship_model.rb +0 -50
- data/lib/amistad/mongoid/friend_model.rb +0 -195
- data/lib/generators/amistad/install/templates/friendship.rb +0 -3
- data/spec/activerecord/activerecord_friend_model_spec.rb +0 -13
- data/spec/mongoid/mongoid_friend_model_spec.rb +0 -47
@@ -0,0 +1,52 @@
|
|
1
|
+
module Amistad
|
2
|
+
module ActiveRecordFriendshipModel
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
belongs_to :friendable,
|
7
|
+
:class_name => Amistad.friend_model,
|
8
|
+
:foreign_key => "friendable_id"
|
9
|
+
|
10
|
+
belongs_to :friend,
|
11
|
+
:class_name => Amistad.friend_model,
|
12
|
+
:foreign_key => "friend_id"
|
13
|
+
|
14
|
+
belongs_to :blocker,
|
15
|
+
:class_name => Amistad.friend_model,
|
16
|
+
:foreign_key => "blocker_id"
|
17
|
+
|
18
|
+
validates_presence_of :friendable_id, :friend_id
|
19
|
+
validates_uniqueness_of :friend_id, :scope => :friendable_id
|
20
|
+
end
|
21
|
+
|
22
|
+
# returns true if a friendship has been approved, else false
|
23
|
+
def approved?
|
24
|
+
!self.pending
|
25
|
+
end
|
26
|
+
|
27
|
+
# returns true if a friendship has not been approved, else false
|
28
|
+
def pending?
|
29
|
+
self.pending
|
30
|
+
end
|
31
|
+
|
32
|
+
# returns true if a friendship has been blocked, else false
|
33
|
+
def blocked?
|
34
|
+
self.blocker_id.present?
|
35
|
+
end
|
36
|
+
|
37
|
+
# returns true if a friendship has not beed blocked, else false
|
38
|
+
def active?
|
39
|
+
self.blocker_id.nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
# returns true if a friendship can be blocked by given friendable
|
43
|
+
def can_block?(friendable)
|
44
|
+
active? && (approved? || (pending? && self.friend_id == friendable.id && friendable.class.to_s == Amistad.friend_model))
|
45
|
+
end
|
46
|
+
|
47
|
+
# returns true if a friendship can be unblocked by given friendable
|
48
|
+
def can_unblock?(friendable)
|
49
|
+
blocked? && self.blocker_id == friendable.id && friendable.class.to_s == Amistad.friend_model
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Amistad
|
2
|
+
class << self
|
3
|
+
attr_accessor :friend_model
|
4
|
+
|
5
|
+
def configure
|
6
|
+
yield self
|
7
|
+
end
|
8
|
+
|
9
|
+
def friend_model
|
10
|
+
@friend_model || 'User'
|
11
|
+
end
|
12
|
+
|
13
|
+
def friendship_model
|
14
|
+
"#{self.friend_model}Friendship"
|
15
|
+
end
|
16
|
+
|
17
|
+
def friendship_class
|
18
|
+
Amistad::Friendships.const_get(self.friendship_model)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/amistad/friend_model.rb
CHANGED
@@ -3,15 +3,21 @@ module Amistad
|
|
3
3
|
def self.included(receiver)
|
4
4
|
if receiver.ancestors.map(&:to_s).include?("ActiveRecord::Base")
|
5
5
|
receiver.class_exec do
|
6
|
-
include Amistad::
|
6
|
+
include Amistad::ActiveRecordFriendModel
|
7
7
|
end
|
8
8
|
elsif receiver.ancestors.map(&:to_s).include?("Mongoid::Document")
|
9
9
|
receiver.class_exec do
|
10
|
-
include Amistad::
|
10
|
+
include Amistad::MongoidFriendModel
|
11
|
+
include Amistad::MongoFriendModel
|
12
|
+
end
|
13
|
+
elsif receiver.ancestors.map(&:to_s).include?("MongoMapper::Document")
|
14
|
+
receiver.class_exec do
|
15
|
+
include Amistad::MongoMapperFriendModel
|
16
|
+
include Amistad::MongoFriendModel
|
11
17
|
end
|
12
18
|
else
|
13
|
-
raise "Amistad only supports ActiveRecord and
|
19
|
+
raise "Amistad only supports ActiveRecord, Mongoid and MongoMapper"
|
14
20
|
end
|
15
21
|
end
|
16
22
|
end
|
17
|
-
end
|
23
|
+
end
|
@@ -3,11 +3,11 @@ module Amistad
|
|
3
3
|
def self.included(receiver)
|
4
4
|
if receiver.ancestors.map(&:to_s).include?("ActiveRecord::Base")
|
5
5
|
receiver.class_exec do
|
6
|
-
include Amistad::
|
6
|
+
include Amistad::ActiveRecordFriendshipModel
|
7
7
|
end
|
8
8
|
else
|
9
9
|
raise "Amistad only supports ActiveRecord and Mongoid"
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
|
-
end
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Amistad
|
2
|
+
module Friendships
|
3
|
+
if Object.const_defined? :ActiveRecord
|
4
|
+
const_set Amistad.friendship_model, Class.new(ActiveRecord::Base)
|
5
|
+
const_get(Amistad.friendship_model.to_sym).class_exec do
|
6
|
+
include Amistad::FriendshipModel
|
7
|
+
self.table_name = 'friendships'
|
8
|
+
end
|
9
|
+
elsif Object.const_defined? :Mongoid
|
10
|
+
Friendship = Class.new
|
11
|
+
Friendship.class_exec do
|
12
|
+
include Mongoid::Document
|
13
|
+
include Amistad::FriendshipModel
|
14
|
+
end
|
15
|
+
else
|
16
|
+
raise "Amistad only supports ActiveRecord and Mongoid"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Amistad
|
2
|
+
module MongoFriendModel
|
3
|
+
# suggest a user to become a friend. If the operation succeeds, the method returns true, else false
|
4
|
+
def invite(user)
|
5
|
+
return false if friendshiped_with?(user) or user == self or blocked?(user)
|
6
|
+
pending_friend_ids << user.id
|
7
|
+
user.pending_inverse_friend_ids << self.id
|
8
|
+
self.save && user.save
|
9
|
+
end
|
10
|
+
|
11
|
+
# approve a friendship invitation. If the operation succeeds, the method returns true, else false
|
12
|
+
def approve(user)
|
13
|
+
return false unless pending_inverse_friend_ids.include?(user.id) && user.pending_friend_ids.include?(self.id)
|
14
|
+
pending_inverse_friend_ids.delete(user.id)
|
15
|
+
user.pending_friend_ids.delete(self.id)
|
16
|
+
inverse_friend_ids << user.id
|
17
|
+
user.friend_ids << self.id
|
18
|
+
self.save && user.save
|
19
|
+
end
|
20
|
+
|
21
|
+
# returns the list of approved friends
|
22
|
+
def friends
|
23
|
+
self.invited + self.invited_by
|
24
|
+
end
|
25
|
+
|
26
|
+
# total # of invited and invited_by without association loading
|
27
|
+
def total_friends
|
28
|
+
(friend_ids + inverse_friend_ids).count
|
29
|
+
end
|
30
|
+
|
31
|
+
# return the list of invited friends
|
32
|
+
def invited
|
33
|
+
self.class.find(friend_ids)
|
34
|
+
end
|
35
|
+
|
36
|
+
# return the list of friends who invited
|
37
|
+
def invited_by
|
38
|
+
self.class.find(inverse_friend_ids)
|
39
|
+
end
|
40
|
+
|
41
|
+
# return the list of pending invited friends
|
42
|
+
def pending_invited
|
43
|
+
self.class.find(pending_friend_ids)
|
44
|
+
end
|
45
|
+
|
46
|
+
# return the list of pending friends who invited
|
47
|
+
def pending_invited_by
|
48
|
+
self.class.find(pending_inverse_friend_ids)
|
49
|
+
end
|
50
|
+
|
51
|
+
# return the list of the ones among its friends which are also friend with the given use
|
52
|
+
def common_friends_with(user)
|
53
|
+
self.friends & user.friends
|
54
|
+
end
|
55
|
+
|
56
|
+
# checks if a user is a friend
|
57
|
+
def friend_with?(user)
|
58
|
+
return false if user == self
|
59
|
+
(friend_ids + inverse_friend_ids).include?(user.id)
|
60
|
+
end
|
61
|
+
|
62
|
+
# checks if a current user is connected to given user
|
63
|
+
def connected_with?(user)
|
64
|
+
friendshiped_with?(user)
|
65
|
+
end
|
66
|
+
|
67
|
+
# checks if a current user received invitation from given user
|
68
|
+
def invited_by?(user)
|
69
|
+
user.friend_ids.include?(self.id) or user.pending_friend_ids.include?(self.id)
|
70
|
+
end
|
71
|
+
|
72
|
+
# checks if a current user invited given user
|
73
|
+
def invited?(user)
|
74
|
+
self.friend_ids.include?(user.id) or self.pending_friend_ids.include?(user.id)
|
75
|
+
end
|
76
|
+
|
77
|
+
# deletes a friendship
|
78
|
+
def remove_friendship(user)
|
79
|
+
friend_ids.delete(user.id)
|
80
|
+
user.inverse_friend_ids.delete(self.id)
|
81
|
+
inverse_friend_ids.delete(user.id)
|
82
|
+
user.friend_ids.delete(self.id)
|
83
|
+
pending_friend_ids.delete(user.id)
|
84
|
+
user.pending_inverse_friend_ids.delete(self.id)
|
85
|
+
pending_inverse_friend_ids.delete(user.id)
|
86
|
+
user.pending_friend_ids.delete(self.id)
|
87
|
+
self.save && user.save
|
88
|
+
end
|
89
|
+
|
90
|
+
# blocks a friendship
|
91
|
+
def block(user)
|
92
|
+
if inverse_friend_ids.include?(user.id)
|
93
|
+
inverse_friend_ids.delete(user.id)
|
94
|
+
user.friend_ids.delete(self.id)
|
95
|
+
blocked_inverse_friend_ids << user.id
|
96
|
+
elsif pending_inverse_friend_ids.include?(user.id)
|
97
|
+
pending_inverse_friend_ids.delete(user.id)
|
98
|
+
user.pending_friend_ids.delete(self.id)
|
99
|
+
blocked_pending_inverse_friend_ids << user.id
|
100
|
+
elsif friend_ids.include?(user.id)
|
101
|
+
friend_ids.delete(user.id)
|
102
|
+
user.inverse_friend_ids.delete(user.id)
|
103
|
+
blocked_friend_ids << user.id
|
104
|
+
else
|
105
|
+
return false
|
106
|
+
end
|
107
|
+
|
108
|
+
self.save
|
109
|
+
end
|
110
|
+
|
111
|
+
# unblocks a friendship
|
112
|
+
def unblock(user)
|
113
|
+
if blocked_inverse_friend_ids.include?(user.id)
|
114
|
+
blocked_inverse_friend_ids.delete(user.id)
|
115
|
+
user.blocked_friend_ids.delete(self.id)
|
116
|
+
inverse_friend_ids << user.id
|
117
|
+
user.friend_ids << self.id
|
118
|
+
elsif blocked_pending_inverse_friend_ids.include?(user.id)
|
119
|
+
blocked_pending_inverse_friend_ids.delete(user.id)
|
120
|
+
pending_inverse_friend_ids << user.id
|
121
|
+
user.pending_friend_ids << self.id
|
122
|
+
elsif blocked_friend_ids.include?(user.id)
|
123
|
+
blocked_friend_ids.delete(user.id)
|
124
|
+
user.blocked_inverse_friend_ids.delete(self.id)
|
125
|
+
friend_ids << user.id
|
126
|
+
user.inverse_friend_ids << self.id
|
127
|
+
else
|
128
|
+
return false
|
129
|
+
end
|
130
|
+
|
131
|
+
self.save && user.save
|
132
|
+
end
|
133
|
+
|
134
|
+
# returns the list of blocked friends
|
135
|
+
def blocked
|
136
|
+
blocked_ids = blocked_friend_ids + blocked_inverse_friend_ids + blocked_pending_inverse_friend_ids
|
137
|
+
self.class.find(blocked_ids)
|
138
|
+
end
|
139
|
+
|
140
|
+
# total # of blockades and blockedes_by without association loading
|
141
|
+
def total_blocked
|
142
|
+
(blocked_friend_ids + blocked_inverse_friend_ids + blocked_pending_inverse_friend_ids).count
|
143
|
+
end
|
144
|
+
|
145
|
+
# checks if a user is blocked
|
146
|
+
def blocked?(user)
|
147
|
+
(blocked_friend_ids + blocked_inverse_friend_ids + blocked_pending_inverse_friend_ids).include?(user.id) or user.blocked_pending_inverse_friend_ids.include?(self.id)
|
148
|
+
end
|
149
|
+
|
150
|
+
# check if any friendship exists with another user
|
151
|
+
def friendshiped_with?(user)
|
152
|
+
(friend_ids + inverse_friend_ids + pending_friend_ids + pending_inverse_friend_ids + blocked_friend_ids).include?(user.id)
|
153
|
+
end
|
154
|
+
|
155
|
+
# deletes all the friendships
|
156
|
+
def delete_all_friendships
|
157
|
+
friend_ids.clear
|
158
|
+
inverse_friend_ids.clear
|
159
|
+
pending_friend_ids.clear
|
160
|
+
pending_inverse_friend_ids.clear
|
161
|
+
blocked_friend_ids.clear
|
162
|
+
blocked_inverse_friend_ids.clear
|
163
|
+
blocked_pending_friend_ids.clear
|
164
|
+
blocked_pending_inverse_friend_ids.clear
|
165
|
+
self.save
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Amistad
|
2
|
+
module MongoMapperFriendModel
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
key :friend_ids,
|
7
|
+
Array,
|
8
|
+
:default => []
|
9
|
+
|
10
|
+
key :inverse_friend_ids,
|
11
|
+
Array,
|
12
|
+
:default => []
|
13
|
+
|
14
|
+
key :pending_friend_ids,
|
15
|
+
Array,
|
16
|
+
:default => []
|
17
|
+
|
18
|
+
key :pending_inverse_friend_ids,
|
19
|
+
Array,
|
20
|
+
:default => []
|
21
|
+
|
22
|
+
key :blocked_friend_ids,
|
23
|
+
Array,
|
24
|
+
:default => []
|
25
|
+
|
26
|
+
key :blocked_inverse_friend_ids,
|
27
|
+
Array,
|
28
|
+
:default => []
|
29
|
+
|
30
|
+
key :blocked_pending_friend_ids,
|
31
|
+
Array,
|
32
|
+
:default => []
|
33
|
+
|
34
|
+
key :blocked_pending_inverse_friend_ids,
|
35
|
+
Array,
|
36
|
+
:default => []
|
37
|
+
|
38
|
+
attr_accessible(
|
39
|
+
:friend_ids,
|
40
|
+
:inverse_friend_ids,
|
41
|
+
:pending_friend_ids,
|
42
|
+
:pending_inverse_friend_ids,
|
43
|
+
:blocked_friend_ids,
|
44
|
+
:blocked_inverse_friend_ids,
|
45
|
+
:blocked_pending_friend_ids,
|
46
|
+
:blocked_pending_inverse_friend_ids,
|
47
|
+
)
|
48
|
+
|
49
|
+
%w(friend_ids inverse_friend_ids pending_friend_ids pending_inverse_friend_ids blocked_friend_ids blocked_inverse_friend_ids blocked_pending_friend_ids blocked_pending_inverse_friend_ids).each do |attribute|
|
50
|
+
define_method(attribute.to_sym) do
|
51
|
+
value = read_attribute(attribute)
|
52
|
+
write_attribute(attribute, value = []) if value.nil?
|
53
|
+
value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Amistad
|
2
|
+
module MongoidFriendModel
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
field :friend_ids,
|
7
|
+
:type => Array,
|
8
|
+
:default => []
|
9
|
+
|
10
|
+
field :inverse_friend_ids,
|
11
|
+
:type => Array,
|
12
|
+
:default => []
|
13
|
+
|
14
|
+
field :pending_friend_ids,
|
15
|
+
:type => Array,
|
16
|
+
:default => []
|
17
|
+
|
18
|
+
field :pending_inverse_friend_ids,
|
19
|
+
:type => Array,
|
20
|
+
:default => []
|
21
|
+
|
22
|
+
field :blocked_friend_ids,
|
23
|
+
:type => Array,
|
24
|
+
:default => []
|
25
|
+
|
26
|
+
field :blocked_inverse_friend_ids,
|
27
|
+
:type => Array,
|
28
|
+
:default => []
|
29
|
+
|
30
|
+
field :blocked_pending_friend_ids,
|
31
|
+
:type => Array,
|
32
|
+
:default => []
|
33
|
+
|
34
|
+
field :blocked_pending_inverse_friend_ids,
|
35
|
+
:type => Array,
|
36
|
+
:default => []
|
37
|
+
|
38
|
+
attr_accessible(
|
39
|
+
:friend_ids,
|
40
|
+
:inverse_friend_ids,
|
41
|
+
:pending_friend_ids,
|
42
|
+
:pending_inverse_friend_ids,
|
43
|
+
:blocked_friend_ids,
|
44
|
+
:blocked_inverse_friend_ids,
|
45
|
+
:blocked_pending_friend_ids,
|
46
|
+
:blocked_pending_inverse_friend_ids,
|
47
|
+
)
|
48
|
+
|
49
|
+
%w(friend_ids inverse_friend_ids pending_friend_ids pending_inverse_friend_ids blocked_friend_ids blocked_inverse_friend_ids blocked_pending_friend_ids blocked_pending_inverse_friend_ids).each do |attribute|
|
50
|
+
define_method(attribute.to_sym) do
|
51
|
+
value = read_attribute(attribute)
|
52
|
+
write_attribute(attribute, value = []) if value.nil?
|
53
|
+
value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/amistad/version.rb
CHANGED
@@ -16,7 +16,6 @@ module Amistad
|
|
16
16
|
|
17
17
|
desc "This generator creates a friendship model and its migration file"
|
18
18
|
def create_friendship_model_files
|
19
|
-
template 'friendship.rb', 'app/models/friendship.rb'
|
20
19
|
template 'create_friendships.rb', "db/migrate/#{self.class.next_migration_number}_create_friendships.rb"
|
21
20
|
end
|
22
21
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
class CreateFriendships < ActiveRecord::Migration
|
2
2
|
def self.up
|
3
3
|
create_table :friendships do |t|
|
4
|
-
t.integer :
|
4
|
+
t.integer :friendable_id
|
5
5
|
t.integer :friend_id
|
6
6
|
t.integer :blocker_id
|
7
7
|
t.boolean :pending, :default => true
|
8
8
|
end
|
9
9
|
|
10
|
-
add_index :friendships, [:
|
10
|
+
add_index :friendships, [:friendable_id, :friend_id], :unique => true
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.down
|