social_stream 0.2.3 → 0.3.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 +1 -0
- data/README.rdoc +2 -3
- data/app/controllers/likes_controller.rb +2 -2
- data/app/controllers/messages_controller.rb +3 -0
- data/app/controllers/representations_controller.rb +8 -0
- data/app/controllers/ties_controller.rb +1 -1
- data/app/helpers/activities_helper.rb +2 -2
- data/app/helpers/ties_helper.rb +19 -16
- data/app/models/activity.rb +42 -7
- data/app/models/activity_object.rb +1 -0
- data/app/models/activity_verb.rb +5 -1
- data/app/models/actor.rb +113 -68
- data/app/models/group.rb +15 -1
- data/app/models/message.rb +2 -0
- data/app/models/permission.rb +20 -41
- data/app/models/profile.rb +1 -1
- data/app/models/relation.rb +34 -26
- data/app/models/representation.rb +35 -0
- data/app/models/tie.rb +47 -100
- data/app/models/user.rb +12 -17
- data/app/views/activities/_activities.html.erb +2 -2
- data/app/views/activities/_new.html.erb +6 -3
- data/app/views/activities/_options.html.erb +1 -1
- data/app/views/comments/_new.html.erb +2 -2
- data/app/views/frontpage/index.html.erb +0 -2
- data/app/views/groups/_group.html.erb +3 -3
- data/app/views/groups/_index.html.erb +3 -4
- data/app/views/groups/_middle_show.html.erb +7 -4
- data/app/views/groups/_new.html.erb +25 -0
- data/app/views/groups/_right_show.html.erb +4 -2
- data/app/views/groups/new.html.erb +1 -0
- data/app/views/groups/show.html.erb +1 -1
- data/app/views/home/_groups.html.erb +7 -5
- data/app/views/home/_location.html.erb +1 -1
- data/app/views/home/_options.html.erb +2 -2
- data/app/views/home/_right.html.erb +2 -2
- data/app/views/home/index.html.erb +6 -2
- data/app/views/layouts/_footer.html.erb +1 -1
- data/app/views/layouts/_header.erb +4 -1
- data/app/views/layouts/_representation.html.erb +20 -0
- data/app/views/{private_messages → messages}/_form.html.erb +4 -4
- data/app/views/{private_messages → messages}/_index.html.erb +1 -1
- data/app/views/{private_messages → messages}/_location.html.erb +1 -1
- data/app/views/messages/_message.html.erb +17 -0
- data/app/views/messages/_messages.html.erb +2 -0
- data/app/views/messages/edit.html.erb +6 -0
- data/app/views/{private_messages → messages}/index.html.erb +0 -0
- data/app/views/{private_messages → messages}/index.js.erb +0 -0
- data/app/views/{private_messages → messages}/new.html.erb +2 -2
- data/app/views/messages/show.html.erb +21 -0
- data/app/views/subjects/_contacts.html.erb +20 -0
- data/app/views/ties/_new.html.erb +6 -6
- data/app/views/ties/_pendings.html.erb +3 -3
- data/app/views/ties/_suggestions.html.erb +3 -3
- data/app/views/ties/_tie.html.erb +1 -1
- data/app/views/ties/create.js.erb +4 -5
- data/app/views/ties/new.js.erb +1 -1
- data/app/views/users/_groups.html.erb +5 -5
- data/app/views/users/_index.html.erb +3 -1
- data/app/views/users/_options.html.erb +1 -1
- data/app/views/users/_right_show.html.erb +3 -3
- data/app/views/users/show.html.erb +5 -3
- data/config/locales/en.yml +13 -19
- data/config/routes.rb +11 -4
- data/lib/generators/social_stream/install_generator.rb +2 -10
- data/lib/generators/social_stream/templates/initializer.rb +1 -1
- data/lib/generators/social_stream/templates/migration.rb +19 -24
- data/lib/generators/social_stream/templates/public/javascripts/jquery.js +6883 -0
- data/lib/generators/social_stream/templates/public/javascripts/rails.js +146 -0
- data/lib/generators/social_stream/templates/public/javascripts/ui.dropdownchecklist.js +3 -13
- data/lib/generators/social_stream/templates/public/stylesheets/header.css +5 -1
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-icons_222222_256x240.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-icons_454545_256x240.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-icons_888888_256x240.png +0 -0
- data/lib/generators/social_stream/templates/public/{images → stylesheets/images}/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/generators/social_stream/templates/relations.yml +42 -0
- data/lib/social_stream/ability.rb +7 -6
- data/lib/social_stream/controllers/helpers.rb +35 -0
- data/lib/social_stream/models/{activity_object.rb → object.rb} +1 -1
- data/lib/social_stream/models/{actor.rb → subject.rb} +10 -30
- data/lib/social_stream/models/supertype.rb +5 -2
- data/lib/social_stream/rails.rb +25 -6
- data/lib/social_stream/relations.rb +46 -0
- data/lib/social_stream/version.rb +1 -1
- data/lib/social_stream.rb +13 -13
- data/lib/tasks/db/populate.rake +23 -29
- data/spec/controllers/groups_controller_spec.rb +2 -6
- data/spec/controllers/ties_controller_spec.rb +19 -0
- data/spec/controllers/users_controller_spec.rb +0 -2
- data/spec/dummy/config/application.rb +0 -1
- data/spec/dummy/config/initializers/social_stream.rb +14 -2
- data/spec/dummy/config/relations.yml +42 -0
- data/spec/dummy/db/schema.rb +9 -0
- data/spec/dummy/db/seeds.rb +0 -1
- data/spec/factories/activity.rb +2 -2
- data/spec/factories/actor.rb +2 -1
- data/spec/factories/group.rb +1 -0
- data/spec/factories/post.rb +1 -1
- data/spec/factories/tie.rb +16 -22
- data/spec/models/activity_spec.rb +27 -24
- data/spec/models/actor_spec.rb +3 -0
- data/spec/models/representation_spec.rb +16 -0
- data/spec/models/tie_spec.rb +49 -57
- data/spec/models/user_spec.rb +22 -0
- data/spec/support/db.rb +1 -1
- metadata +47 -45
- data/Gemfile.lock +0 -171
- data/app/controllers/private_messages_controller.rb +0 -3
- data/app/models/private_message.rb +0 -6
- data/app/views/groups/_follow.html.erb +0 -9
- data/app/views/groups/_followers.html.erb +0 -16
- data/app/views/home/_contacts.html.erb +0 -17
- data/app/views/private_messages/_messages.html.erb +0 -2
- data/app/views/private_messages/_private_message.html.erb +0 -17
- data/app/views/private_messages/edit.html.erb +0 -6
- data/app/views/private_messages/show.html.erb +0 -21
- data/app/views/ties/_pending.html.erb +0 -21
- data/app/views/users/_contacts.html.erb +0 -19
- data/init.rb +0 -3
- data/lib/generators/social_stream/templates/seeds.yml +0 -64
- data/lib/social_stream/rails/common.rb +0 -36
- data/lib/social_stream/rails/engine.rb +0 -9
- data/lib/social_stream/rails/railtie.rb +0 -9
- data/lib/social_stream/seed.rb +0 -49
- data/spec/dummy/db/seeds/social_stream.yml +0 -64
- data/spec/models/user_space.rb +0 -10
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
|
@@ -43,14 +43,13 @@ This will generate the following:
|
|
|
43
43
|
* A jquery:install generation for jQuery support
|
|
44
44
|
* A devise:install generation for authentication support
|
|
45
45
|
* An initializer file with configuration for Social Stream.
|
|
46
|
-
* A
|
|
46
|
+
* A configuration file for defining custom Social Stream relations. You can define your application default relations at <tt>config/relations.yml</tt>
|
|
47
47
|
* A new application layout
|
|
48
48
|
* A migration providing the database schema
|
|
49
49
|
|
|
50
|
-
Do not forget to migrate
|
|
50
|
+
Do not forget to migrate your database
|
|
51
51
|
|
|
52
52
|
rake db:migrate
|
|
53
|
-
rake db:seed
|
|
54
53
|
|
|
55
54
|
== Actors and Activity Objects
|
|
56
55
|
|
|
@@ -17,7 +17,7 @@ class LikesController < ApplicationController
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def destroy
|
|
20
|
-
if (@like = activity!.liked_by(
|
|
20
|
+
if (@like = activity!.liked_by(current_subject).first)
|
|
21
21
|
@like.destroy
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -37,7 +37,7 @@ class LikesController < ApplicationController
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def tie
|
|
40
|
-
@tie ||=
|
|
40
|
+
@tie ||= current_subject.sent_ties(:receiver => activity!.receiver,
|
|
41
41
|
:relation => activity!.relation).first
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module ActivitiesHelper
|
|
2
2
|
|
|
3
|
-
# Link to 'like' or 'unlike' depending on the like status of the activity to
|
|
3
|
+
# Link to 'like' or 'unlike' depending on the like status of the activity to current_subject
|
|
4
4
|
#
|
|
5
5
|
# @param [Activity]
|
|
6
6
|
# @return [String]
|
|
7
7
|
def link_like(activity)
|
|
8
|
-
if (activity.liked_by?(
|
|
8
|
+
if (activity.liked_by?(current_subject))
|
|
9
9
|
link_to t('activity.unlike'), activity_like_path(activity), :method => :delete, :remote => true
|
|
10
10
|
else
|
|
11
11
|
link_to t('activity.like'), activity_like_path(activity), :method => :post, :remote => true
|
data/app/helpers/ties_helper.rb
CHANGED
|
@@ -3,26 +3,29 @@ module TiesHelper
|
|
|
3
3
|
"N contacts in common"
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
:title => t("#{ tie.relation.name }.confirm_new",
|
|
16
|
-
:name => tie.receiver_subject.name),
|
|
17
|
-
:remote => true
|
|
18
|
-
|
|
6
|
+
# Show current ties from current user to actor, if they exist, or provide a link
|
|
7
|
+
# to create a new tie to actor
|
|
8
|
+
def ties_to(a)
|
|
9
|
+
if user_signed_in?
|
|
10
|
+
if current_subject.ties_to(a).present?
|
|
11
|
+
current_subject.ties_to(a).first.relation_name
|
|
12
|
+
else
|
|
13
|
+
new_tie_link(current_subject.sent_ties.build :receiver_id => Actor.normalize_id(a))
|
|
14
|
+
end
|
|
19
15
|
else
|
|
20
|
-
|
|
21
|
-
render :partial => 'ties/form',
|
|
22
|
-
:locals => { :tie => tie }
|
|
16
|
+
link_to t("contact.new.link"), new_user_session_path
|
|
23
17
|
end
|
|
24
18
|
end
|
|
25
19
|
|
|
20
|
+
def new_tie_link(tie)
|
|
21
|
+
link_to t("contact.new.link"),
|
|
22
|
+
new_tie_path("tie[sender_id]" => tie.sender.id,
|
|
23
|
+
"tie[receiver_id]" => tie.receiver.id),
|
|
24
|
+
:title => t("contact.new.title",
|
|
25
|
+
:name => tie.receiver_subject.name),
|
|
26
|
+
:remote => true
|
|
27
|
+
end
|
|
28
|
+
|
|
26
29
|
def link_follow_state
|
|
27
30
|
link_to("Unfollow", home_path)
|
|
28
31
|
end
|
data/app/models/activity.rb
CHANGED
|
@@ -17,19 +17,16 @@ class Activity < ActiveRecord::Base
|
|
|
17
17
|
|
|
18
18
|
has_one :tie,
|
|
19
19
|
:through => :tie_activities,
|
|
20
|
-
:conditions => { 'tie_activities.original' => true }
|
|
21
|
-
:include => [ :sender ]
|
|
20
|
+
:conditions => { 'tie_activities.original' => true }
|
|
22
21
|
|
|
23
|
-
delegate :
|
|
24
|
-
:sender_subject, :receiver_subject,
|
|
25
|
-
:to => :tie
|
|
22
|
+
delegate :relation, :to => :tie
|
|
26
23
|
|
|
27
24
|
has_many :activity_object_activities,
|
|
28
25
|
:dependent => :destroy
|
|
29
26
|
has_many :activity_objects,
|
|
30
27
|
:through => :activity_object_activities
|
|
31
28
|
|
|
32
|
-
scope :
|
|
29
|
+
scope :home_wall, lambda { |ties|
|
|
33
30
|
select("DISTINCT activities.*").
|
|
34
31
|
roots.
|
|
35
32
|
joins(:tie_activities).
|
|
@@ -37,6 +34,15 @@ class Activity < ActiveRecord::Base
|
|
|
37
34
|
order("created_at desc")
|
|
38
35
|
}
|
|
39
36
|
|
|
37
|
+
scope :profile_wall, lambda { |ties|
|
|
38
|
+
select("DISTINCT activities.*").
|
|
39
|
+
roots.
|
|
40
|
+
joins(:tie_activities).
|
|
41
|
+
where('tie_activities.tie_id' => ties).
|
|
42
|
+
where('tie_activities.original' => true).
|
|
43
|
+
order("created_at desc")
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
# After an activity is created, it is associated to ties
|
|
41
47
|
attr_accessor :_tie
|
|
42
48
|
after_create :assign_to_ties
|
|
@@ -51,6 +57,34 @@ class Activity < ActiveRecord::Base
|
|
|
51
57
|
self.activity_verb = ActivityVerb[name]
|
|
52
58
|
end
|
|
53
59
|
|
|
60
|
+
# The author of the activity is the receiver of the tie
|
|
61
|
+
#
|
|
62
|
+
# This method provides the actor. Use sender_subject for the subject (user, group, etc..)
|
|
63
|
+
def sender
|
|
64
|
+
tie.receiver
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# The author of the activity is the receiver of the tie
|
|
68
|
+
#
|
|
69
|
+
# This method provides the subject (user, group, etc...). Use sender for the actor.
|
|
70
|
+
def sender_subject
|
|
71
|
+
tie.receiver_subject
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The wall where the activity is shown belongs to the sender of the tie
|
|
75
|
+
#
|
|
76
|
+
# This method provides the actor. Use sender_subject for the subject (user, group, etc..)
|
|
77
|
+
def receiver
|
|
78
|
+
tie.sender
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# The wall where the activity is shown belongs to the sender of the tie
|
|
82
|
+
#
|
|
83
|
+
# This method provides the subject (user, group, etc...). Use sender for the actor.
|
|
84
|
+
def receiver_subject
|
|
85
|
+
tie.sender_subject
|
|
86
|
+
end
|
|
87
|
+
|
|
54
88
|
# The comments about this activity
|
|
55
89
|
def comments
|
|
56
90
|
children.includes(:activity_objects).where('activity_objects.object_type' => "Comment")
|
|
@@ -62,7 +96,7 @@ class Activity < ActiveRecord::Base
|
|
|
62
96
|
end
|
|
63
97
|
|
|
64
98
|
def liked_by(user) #:nodoc:
|
|
65
|
-
likes.joins(:ties).where('tie_activities.original' => true) & Tie.
|
|
99
|
+
likes.joins(:ties).where('tie_activities.original' => true) & Tie.received_by(user)
|
|
66
100
|
end
|
|
67
101
|
|
|
68
102
|
# Does user like this activity?
|
|
@@ -77,6 +111,7 @@ class Activity < ActiveRecord::Base
|
|
|
77
111
|
|
|
78
112
|
private
|
|
79
113
|
|
|
114
|
+
# Assign to ties of followers
|
|
80
115
|
def assign_to_ties
|
|
81
116
|
original = tie_activities.create!(:tie => _tie)
|
|
82
117
|
_tie.activity_receivers.each do |t|
|
data/app/models/activity_verb.rb
CHANGED
data/app/models/actor.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# An actor is a social entity. This includes individuals, but also groups, departments, organizations even nations or states. Actors are linked by ties.
|
|
2
2
|
class Actor < ActiveRecord::Base
|
|
3
|
+
@subtypes_name = :subject
|
|
3
4
|
include SocialStream::Models::Supertype
|
|
4
5
|
|
|
5
6
|
validates_presence_of :name, :subject_type
|
|
@@ -12,24 +13,46 @@ class Actor < ActiveRecord::Base
|
|
|
12
13
|
:profile => '94x94' },
|
|
13
14
|
:default_url => "/images/:attachment/:style/:subtype_class.png"
|
|
14
15
|
|
|
16
|
+
has_one :profile, :dependent => :destroy
|
|
17
|
+
|
|
15
18
|
has_many :sent_ties,
|
|
16
19
|
:class_name => "Tie",
|
|
17
20
|
:foreign_key => 'sender_id',
|
|
18
21
|
:dependent => :destroy
|
|
19
22
|
|
|
20
|
-
has_many :senders,
|
|
21
|
-
:through => :received_ties,
|
|
22
|
-
:uniq => true
|
|
23
|
-
|
|
24
23
|
has_many :received_ties,
|
|
25
24
|
:class_name => "Tie",
|
|
26
25
|
:foreign_key => 'receiver_id',
|
|
27
26
|
:dependent => :destroy
|
|
28
27
|
|
|
28
|
+
has_many :senders,
|
|
29
|
+
:through => :received_ties,
|
|
30
|
+
:uniq => true
|
|
31
|
+
|
|
29
32
|
has_many :receivers,
|
|
30
33
|
:through => :sent_ties,
|
|
31
34
|
:uniq => true
|
|
32
35
|
|
|
36
|
+
after_create :initialize_ties
|
|
37
|
+
|
|
38
|
+
after_create :create_profile
|
|
39
|
+
|
|
40
|
+
class << self
|
|
41
|
+
# Get actor's id from an object, if possible
|
|
42
|
+
def normalize_id(a)
|
|
43
|
+
case a
|
|
44
|
+
when Integer
|
|
45
|
+
a
|
|
46
|
+
when Array
|
|
47
|
+
a.map{ |e| normalize_id(e) }
|
|
48
|
+
when Actor
|
|
49
|
+
a.id
|
|
50
|
+
else
|
|
51
|
+
a.actor.id
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
33
56
|
# The subject instance for this actor
|
|
34
57
|
def subject
|
|
35
58
|
subtype_instance ||
|
|
@@ -41,68 +64,71 @@ class Actor < ActiveRecord::Base
|
|
|
41
64
|
Tie.sent_or_received_by(self)
|
|
42
65
|
end
|
|
43
66
|
|
|
44
|
-
#
|
|
45
|
-
|
|
67
|
+
# Relations defined and managed by this actor
|
|
68
|
+
def relations
|
|
69
|
+
Relation.includes(:ties) & Tie.sent_by(self)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# A given relation defined and managed by this actor
|
|
73
|
+
def relation(name)
|
|
74
|
+
relations.find_by_name(name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# All the actors this one has relation with
|
|
46
78
|
#
|
|
47
|
-
# Options
|
|
79
|
+
# Options:
|
|
80
|
+
# * subject_type: Filter by the class of the subjects.
|
|
81
|
+
# * direction: senders or receivers
|
|
48
82
|
# * relations: Restrict the relations of considered ties
|
|
49
|
-
# * include_self: False by default, don't include this actor as subject even they
|
|
50
|
-
#
|
|
51
|
-
def
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
83
|
+
# * include_self: False by default, don't include this actor as subject even they have ties with themselves.
|
|
84
|
+
#
|
|
85
|
+
def actors(options = {})
|
|
86
|
+
subject_types = Array(options[:subject_type] || self.class.subtypes)
|
|
87
|
+
subject_classes = subject_types.map{ |s| s.to_s.classify }
|
|
88
|
+
|
|
89
|
+
as = Actor.select("DISTINCT actors.*").
|
|
90
|
+
where('actors.subject_type' => subject_classes).
|
|
91
|
+
includes(subject_types)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
case options[:direction]
|
|
95
|
+
when :senders
|
|
96
|
+
as = as.joins(:sent_ties) & Tie.received_by(self)
|
|
97
|
+
when :receivers
|
|
98
|
+
as = as.joins(:received_ties) & Tie.sent_by(self)
|
|
99
|
+
else
|
|
100
|
+
raise "actors in both directions is not supported yet"
|
|
101
|
+
end
|
|
59
102
|
|
|
60
103
|
if options[:include_self].blank?
|
|
61
|
-
|
|
104
|
+
as = as.where("actors.id != ?", self.id)
|
|
62
105
|
end
|
|
63
106
|
|
|
64
107
|
if options[:relations].present?
|
|
65
|
-
|
|
66
|
-
Tie.related_by(Tie.Relation(options[:relations], :mode => [ subject_class, self.subject.class ]))
|
|
108
|
+
as &= Tie.related_by(options[:relations])
|
|
67
109
|
end
|
|
68
110
|
|
|
69
|
-
|
|
111
|
+
as
|
|
70
112
|
end
|
|
71
113
|
|
|
72
|
-
# All the subject actors
|
|
73
|
-
# from this actor
|
|
114
|
+
# All the subject actors that send or receive at least one tie to this actor
|
|
74
115
|
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
def
|
|
80
|
-
|
|
81
|
-
subject_class = subject_type.to_s.classify.constantize
|
|
82
|
-
|
|
83
|
-
cs = subject_class.
|
|
84
|
-
select("DISTINCT #{ subject_class.quoted_table_name }.*").
|
|
85
|
-
with_received_ties &
|
|
86
|
-
Tie.sent_by(self)
|
|
87
|
-
|
|
88
|
-
if options[:include_self].blank?
|
|
89
|
-
cs = cs.where("#{ self.class.quoted_table_name }.id != ?", self.id)
|
|
90
|
-
end
|
|
116
|
+
# When passing a block, it will be evaluated for the actors query, allowing to add
|
|
117
|
+
# options before the mapping to subjects
|
|
118
|
+
#
|
|
119
|
+
# See actors for options
|
|
120
|
+
def subjects(options = {})
|
|
121
|
+
as = actors(options)
|
|
91
122
|
|
|
92
|
-
if
|
|
93
|
-
|
|
94
|
-
Tie.related_by(Tie.Relation(options[:relations], :mode => [ subject.class, subject_class ]))
|
|
123
|
+
if block_given?
|
|
124
|
+
as = yield(as)
|
|
95
125
|
end
|
|
96
126
|
|
|
97
|
-
|
|
127
|
+
as.map(&:subject)
|
|
98
128
|
end
|
|
99
129
|
|
|
100
130
|
# This is an scaffold for a recomendations engine
|
|
101
131
|
#
|
|
102
|
-
SuggestedRelations = {
|
|
103
|
-
'User' => 'friend_request',
|
|
104
|
-
'Group' => 'follower'
|
|
105
|
-
}
|
|
106
132
|
|
|
107
133
|
# Make n suggestions
|
|
108
134
|
# TODO: make more
|
|
@@ -118,16 +144,17 @@ class Actor < ActiveRecord::Base
|
|
|
118
144
|
#
|
|
119
145
|
# @return [Tie]
|
|
120
146
|
def suggestion(options = {})
|
|
121
|
-
candidates_types =
|
|
122
|
-
|
|
123
|
-
|
|
147
|
+
candidates_types =
|
|
148
|
+
options[:type].present? ?
|
|
149
|
+
Array(options[:type]) :
|
|
150
|
+
self.class.subtypes
|
|
124
151
|
|
|
125
|
-
candidates_classes = candidates_types.map
|
|
152
|
+
candidates_classes = candidates_types.map{ |t| t.to_s.classify.constantize }
|
|
126
153
|
|
|
127
154
|
# Candidates are all the instance of "type" minus all the subjects
|
|
128
155
|
# that are receiving any tie from this actor
|
|
129
156
|
candidates = candidates_classes.inject([]) do |cs, klass|
|
|
130
|
-
cs += klass.all -
|
|
157
|
+
cs += klass.all - subjects(:subject_type => klass, :direction => :receivers)
|
|
131
158
|
cs -= Array(subject) if subject.is_a?(klass)
|
|
132
159
|
cs
|
|
133
160
|
end
|
|
@@ -136,38 +163,56 @@ class Actor < ActiveRecord::Base
|
|
|
136
163
|
|
|
137
164
|
return nil unless candidate.present?
|
|
138
165
|
|
|
139
|
-
sent_ties
|
|
140
|
-
|
|
166
|
+
# Building ties with sent_ties catches them and excludes them from pending ties.
|
|
167
|
+
# An useful side effect for excluding this ones from pending, but can be weird!
|
|
168
|
+
# Maybe we must use:
|
|
169
|
+
# Tie.sent_by(self).build :receiver_id => candidate.actor.id
|
|
170
|
+
sent_ties.build :receiver_id => candidate.actor.id
|
|
141
171
|
end
|
|
142
172
|
|
|
143
|
-
#
|
|
144
|
-
def
|
|
145
|
-
sent_ties.received_by(
|
|
173
|
+
# Set of ties sent by this actor received by a
|
|
174
|
+
def ties_to(a)
|
|
175
|
+
sent_ties.received_by(a)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# All the ties this actor has with subject that support permission
|
|
179
|
+
def sent_ties_allowing(subject, action, objective)
|
|
180
|
+
return [] if subject.blank?
|
|
181
|
+
|
|
182
|
+
sent_ties.allowing(subject, action, objective)
|
|
146
183
|
end
|
|
147
184
|
|
|
148
185
|
def pending_ties
|
|
149
|
-
#TODO: optimize by SQL
|
|
150
186
|
@pending_ties ||=
|
|
151
|
-
received_ties.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
:receiver_id => u.sender_id,
|
|
155
|
-
:relation_id => u.relation.granted_id
|
|
156
|
-
}
|
|
187
|
+
received_ties.where('ties.sender_id NOT IN (?)', sent_ties.map(&:receiver_id).uniq).map(&:sender_id).uniq.
|
|
188
|
+
map{ |i| Tie.new :sender => self,
|
|
189
|
+
:receiver_id => i }
|
|
157
190
|
end
|
|
158
191
|
|
|
159
192
|
# The set of activities in the wall of this actor, includes all the activities
|
|
160
193
|
# from the ties the actor has access to
|
|
161
194
|
#
|
|
162
|
-
def
|
|
163
|
-
Activity.
|
|
195
|
+
def home_wall
|
|
196
|
+
Activity.home_wall ties
|
|
164
197
|
end
|
|
165
198
|
|
|
166
199
|
# The set of activities in the wall profile of this actor, includes the activities
|
|
167
200
|
# from the ties of this actor that can be read by user
|
|
168
201
|
#
|
|
169
|
-
def
|
|
170
|
-
|
|
202
|
+
def profile_wall(user)
|
|
203
|
+
# FIXME: show public activities
|
|
204
|
+
return [] if user.blank?
|
|
205
|
+
|
|
206
|
+
Activity.profile_wall ties.allowing(user, 'read', 'activity')
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
private
|
|
210
|
+
|
|
211
|
+
def initialize_ties
|
|
212
|
+
::SocialStream::Relations.create(subject_type).each do |r|
|
|
213
|
+
sent_ties.create! :receiver => self,
|
|
214
|
+
:relation => r
|
|
215
|
+
end
|
|
171
216
|
end
|
|
172
217
|
end
|
|
173
218
|
|
data/app/models/group.rb
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
class Group < ActiveRecord::Base
|
|
2
|
+
attr_accessor :_founder
|
|
3
|
+
|
|
2
4
|
def followers
|
|
3
|
-
|
|
5
|
+
subjects(:subject_type => :user, :direction => :senders)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
after_create :create_founder
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def create_founder
|
|
13
|
+
founder =
|
|
14
|
+
Actor.find_by_permalink(_founder) || raise("Cannot create group without founder")
|
|
15
|
+
|
|
16
|
+
sent_ties.create! :receiver => founder,
|
|
17
|
+
:relation => relations.sort.first
|
|
4
18
|
end
|
|
5
19
|
end
|
data/app/models/permission.rb
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
# SocialStream provides a sophisticated and powerful system of permissions based on the relations
|
|
2
2
|
# and ties of the social network.
|
|
3
3
|
#
|
|
4
|
-
# Permissions are composed by action, objective and
|
|
4
|
+
# Permissions are composed by action, objective and function. Action and objective are classical
|
|
5
5
|
# in content management systems, e.g. "create" "activity", "update" "tie", "read" "post"
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
# This set of ties changes with the formation of ties in your website.
|
|
7
|
+
# function is a novel feature. It supports applying the permission to certain set of ties.
|
|
8
|
+
# This set of ties changes along with the formation of ties in your website.
|
|
9
9
|
#
|
|
10
|
-
# Permissions
|
|
11
|
-
# When a sender establishes a tie with a receiver, she
|
|
10
|
+
# Permissions are assigned to relations, and through relations, to ties.
|
|
11
|
+
# When a sender establishes a tie with a receiver, she is granting to the receiver the permissions assigned
|
|
12
12
|
# to relation of the tie she has just established. For example, when Alice establishes a "friend" tie
|
|
13
13
|
# to Bob, she is granting him the permissions associated with "friend" relation.
|
|
14
14
|
#
|
|
15
|
-
# One of this permissions can be "read" "activity" "
|
|
16
|
-
# to read the activities attached to ties inside the "
|
|
17
|
-
# the "friends" of Alice to Alice herself.
|
|
15
|
+
# One of this permissions can be "read" "activity" "star_set". This way, Bob will have access
|
|
16
|
+
# to read the activities attached to ties inside the "star_set", which are the ties from Alice to her "friends"
|
|
18
17
|
#
|
|
19
18
|
class Permission < ActiveRecord::Base
|
|
20
19
|
has_many :relation_permissions, :dependent => :destroy
|
|
21
20
|
has_many :relations, :through => :relation_permissions
|
|
22
21
|
|
|
22
|
+
scope :represent, where(:action => 'represent')
|
|
23
|
+
|
|
23
24
|
# The SQL and ARel conditions for permission queries
|
|
24
25
|
ParameterConditions = {
|
|
25
26
|
:table => {
|
|
@@ -27,16 +28,10 @@ class Permission < ActiveRecord::Base
|
|
|
27
28
|
"ties_as.sender_id = ties.sender_id AND ties_as.receiver_id = ties.receiver_id AND ties_as.relation_id = ties.relation_id",
|
|
28
29
|
'weak_set' =>
|
|
29
30
|
"ties_as.sender_id = ties.sender_id AND ties_as.receiver_id = ties.receiver_id AND relations.lft BETWEEN relations_as.lft AND relations_as.rgt",
|
|
30
|
-
'
|
|
31
|
-
"ties_as.sender_id = ties.
|
|
32
|
-
'
|
|
33
|
-
"ties_as.
|
|
34
|
-
'inverse_group_set' =>
|
|
35
|
-
"ties_as.sender_id = ties.receiver_id AND ties_as.relation_id = relations.inverse_id",
|
|
36
|
-
'weak_group_set' =>
|
|
37
|
-
"ties_as.receiver_id = ties.receiver_id AND relations.lft BETWEEN relations_as.lft AND relations_as.rgt",
|
|
38
|
-
'inverse_weak_group_set' =>
|
|
39
|
-
"ties_as.sender_id = ties.receiver_id AND relations.inverse_id = relations_inverse.id AND relations_inverse.lft BETWEEN relations_as.lft AND relations_as.rgt"
|
|
31
|
+
'star_set' =>
|
|
32
|
+
"ties_as.sender_id = ties.sender_id AND ties_as.relation_id = ties.relation_id",
|
|
33
|
+
'weak_star_set' =>
|
|
34
|
+
"ties_as.sender_id = ties.sender_id AND relations.lft BETWEEN relations_as.lft AND relations_as.rgt"
|
|
40
35
|
},
|
|
41
36
|
:arel => {
|
|
42
37
|
'tie' => lambda { |as, t|
|
|
@@ -51,31 +46,15 @@ class Permission < ActiveRecord::Base
|
|
|
51
46
|
as[:receiver_id].eq(t.receiver_id)).and(
|
|
52
47
|
as[:relation_id].in(t.relation.stronger_or_equal.map(&:id)))
|
|
53
48
|
},
|
|
54
|
-
'
|
|
55
|
-
# Senders and receivers interchanged, with a stronger or equal relation of the inverse
|
|
56
|
-
as[:sender_id].eq(t.receiver_id).and(
|
|
57
|
-
as[:receiver_id].eq(t.sender_id)).and(
|
|
58
|
-
as[:relation_id].in(Array(t.relation.inverse.try(:stronger_or_equal)).map(&:id)))
|
|
59
|
-
},
|
|
60
|
-
'group_set' => lambda { |as, t|
|
|
49
|
+
'star_set' => lambda { |as, t|
|
|
61
50
|
# The same receiver and relation
|
|
62
|
-
as[:
|
|
51
|
+
as[:sender_id].eq(t.sender_id).and(
|
|
63
52
|
as[:relation_id].eq(t.relation_id))
|
|
64
53
|
},
|
|
65
|
-
'
|
|
66
|
-
# Senders to the common receiver in the same relation
|
|
67
|
-
as[:sender_id].eq(t.receiver_id).and(
|
|
68
|
-
as[:relation_id].eq(t.relation.inverse_id))
|
|
69
|
-
},
|
|
70
|
-
'weak_group_set' => lambda { |as, t|
|
|
54
|
+
'weak_star_set' => lambda { |as, t|
|
|
71
55
|
# The same receiver with stronger or equal relations
|
|
72
|
-
as[:
|
|
56
|
+
as[:sender_id].eq(t.sender_id).and(
|
|
73
57
|
as[:relation_id].in(t.relation.stronger_or_equal.map(&:id)))
|
|
74
|
-
},
|
|
75
|
-
'inverse_weak_group_set' => lambda { |as, t|
|
|
76
|
-
# Senders to the common receiver with stronger or equal relations
|
|
77
|
-
as[:sender_id].eq(t.receiver_id).and(
|
|
78
|
-
as[:relation_id].in(Array(t.relation.inverse.try(:stronger_or_equal)).map(&:id)))
|
|
79
58
|
}
|
|
80
59
|
}
|
|
81
60
|
}
|
|
@@ -84,10 +63,10 @@ class Permission < ActiveRecord::Base
|
|
|
84
63
|
def parameter_conditions(tie = nil)
|
|
85
64
|
if tie.present?
|
|
86
65
|
ParameterConditions[:arel].inject([]) { |conditions, h|
|
|
87
|
-
# Add the condition 'permissions.
|
|
66
|
+
# Add the condition 'permissions.function = key'
|
|
88
67
|
# to all arel ParameterConditions
|
|
89
68
|
conditions <<
|
|
90
|
-
h.last.call(Tie.arel_table, tie).and(arel_table[:
|
|
69
|
+
h.last.call(Tie.arel_table, tie).and(arel_table[:function].eq(h.first))
|
|
91
70
|
}.inject(nil){ |result, pc|
|
|
92
71
|
# Join all ParameterConditions with OR
|
|
93
72
|
result.nil? ? pc : result.or(pc)
|
|
@@ -95,7 +74,7 @@ class Permission < ActiveRecord::Base
|
|
|
95
74
|
else
|
|
96
75
|
ParameterConditions[:table].inject([]){ |result, pc|
|
|
97
76
|
result <<
|
|
98
|
-
sanitize_sql([ "#{ pc.last } AND permissions.
|
|
77
|
+
sanitize_sql([ "#{ pc.last } AND permissions.function = ?", pc.first ])
|
|
99
78
|
}.join(" OR ")
|
|
100
79
|
end
|
|
101
80
|
end
|
data/app/models/profile.rb
CHANGED