social_stream 0.4.3 → 0.4.4
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/app/controllers/api_controller.rb +1 -1
- data/app/controllers/contacts_controller.rb +1 -1
- data/app/controllers/conversations_controller.rb +5 -5
- data/app/controllers/groups_controller.rb +1 -0
- data/app/controllers/likes_controller.rb +17 -5
- data/app/controllers/messages_controller.rb +3 -1
- data/app/controllers/profiles_controller.rb +4 -0
- data/app/controllers/representations_controller.rb +12 -1
- data/app/controllers/tags_controller.rb +15 -0
- data/app/controllers/users_controller.rb +3 -0
- data/app/helpers/activities_helper.rb +13 -6
- data/app/models/activity.rb +53 -52
- data/app/models/activity_object.rb +2 -0
- data/app/models/actor.rb +85 -19
- data/app/models/avatar.rb +2 -1
- data/app/models/like.rb +28 -13
- data/app/models/permission.rb +7 -7
- data/app/models/profile.rb +1 -1
- data/app/models/relation/custom.rb +111 -0
- data/app/models/relation/public.rb +42 -0
- data/app/models/relation.rb +1 -89
- data/app/models/sphere.rb +7 -0
- data/app/models/tie.rb +65 -52
- data/app/models/tie_activity.rb +38 -0
- data/app/views/activities/_new.html.erb +4 -4
- data/app/views/activities/_options.html.erb +2 -2
- data/app/views/actors/_actor.html.erb +0 -0
- data/app/views/avatars/index.html.erb +5 -2
- data/app/views/comments/_new.html.erb +2 -2
- data/app/views/contacts/index.html.erb +5 -1
- data/app/views/conversations/edit.html.erb +4 -0
- data/app/views/conversations/index.html.erb +5 -1
- data/app/views/conversations/show.html.erb +4 -0
- data/app/views/frontpage/index.html.erb +4 -0
- data/app/views/groups/_sidebar_index.html.erb +7 -42
- data/app/views/groups/index.html.erb +3 -0
- data/app/views/groups/new.html.erb +3 -0
- data/app/views/groups/show.html.erb +7 -0
- data/app/views/layouts/_account.html.erb +16 -0
- data/app/views/layouts/_footer.html.erb +1 -1
- data/app/views/layouts/_header.erb +7 -22
- data/app/views/layouts/_representation.html.erb +25 -12
- data/app/views/layouts/application.html.erb +6 -3
- data/app/views/layouts/frontpage.html.erb +1 -1
- data/app/views/likes/create.js.erb +1 -1
- data/app/views/likes/destroy.js.erb +1 -1
- data/app/views/messages/new.html.erb +7 -5
- data/app/views/profiles/_profile.html.erb +20 -0
- data/app/views/profiles/edit.html.erb +42 -0
- data/app/views/profiles/show.html.erb +4 -0
- data/app/views/profiles/update.js.erb +5 -0
- data/app/views/subjects/_toolbar_profile_menu_tie_options.html.erb +3 -1
- data/app/views/ties/_new.html.erb +1 -1
- data/app/views/users/index.html.erb +4 -0
- data/app/views/users/show.html.erb +5 -0
- data/config/locales/en.yml +54 -1
- data/config/routes.rb +3 -1
- data/lib/generators/social_stream/install_generator.rb +2 -1
- data/lib/generators/social_stream/templates/migration.rb +23 -27
- data/lib/generators/social_stream/templates/public/images/btn/error.png +0 -0
- data/lib/generators/social_stream/templates/public/images/btn/info.png +0 -0
- data/lib/generators/social_stream/templates/public/images/btn/like.png +0 -0
- data/lib/generators/social_stream/templates/public/images/btn/nolike.png +0 -0
- data/lib/generators/social_stream/templates/public/images/btn/success.png +0 -0
- data/lib/generators/social_stream/templates/public/images/btn/warning.png +0 -0
- data/lib/generators/social_stream/templates/public/javascripts/ajax.paginate.js +12 -19
- data/lib/generators/social_stream/templates/public/javascripts/jquery.validate.js +1 -1
- data/lib/generators/social_stream/templates/public/javascripts/main.js +20 -10
- data/lib/generators/social_stream/templates/public/stylesheets/default/base.css +21 -4
- data/lib/generators/social_stream/templates/public/stylesheets/default/header.css +8 -3
- data/lib/generators/social_stream/templates/relations.yml +7 -13
- data/lib/social_stream/ability.rb +39 -20
- data/lib/social_stream/controllers/helpers.rb +6 -0
- data/lib/social_stream/models/object.rb +8 -4
- data/lib/social_stream/models/subject.rb +6 -0
- data/lib/social_stream/rails.rb +6 -3
- data/lib/social_stream/version.rb +1 -1
- data/lib/tasks/db/populate.rake +11 -1
- data/social_stream.gemspec +7 -8
- data/spec/controllers/comments_controller_spec.rb +6 -2
- data/spec/controllers/posts_controller_spec.rb +93 -5
- data/spec/controllers/profiles_controller_spec.rb +58 -1
- data/spec/controllers/representations_controller_spec.rb +51 -0
- data/spec/controllers/users_controller_spec.rb +28 -0
- data/spec/dummy/config/relations.yml +7 -13
- data/spec/dummy/db/schema.rb +2 -13
- data/spec/factories/tie.rb +1 -1
- data/spec/models/activity_spec.rb +28 -67
- data/spec/models/profile_spec.rb +38 -0
- data/spec/models/tie_activity_spec.rb +88 -31
- data/spec/models/tie_spec.rb +20 -14
- data/spec/support/db.rb +8 -10
- data/spec/support/migrations.rb +24 -0
- metadata +74 -59
@@ -26,7 +26,7 @@ class ApiController < ApplicationController
|
|
26
26
|
end
|
27
27
|
|
28
28
|
@page = params[:page]
|
29
|
-
@activities = @user.wall(:
|
29
|
+
@activities = @user.wall(:profile).paginate(:page => params[:page], :per_page => 10)
|
30
30
|
respond_to do |format|
|
31
31
|
format.atom
|
32
32
|
end
|
@@ -8,7 +8,7 @@ class ContactsController < ApplicationController
|
|
8
8
|
q.alphabetic.
|
9
9
|
letter(params[:letter]).
|
10
10
|
search(params[:search]).
|
11
|
-
merge(Tie.
|
11
|
+
merge(Tie.related_by(current_subject.relations.find_by_id(params[:relation])))
|
12
12
|
}
|
13
13
|
|
14
14
|
respond_to do |format|
|
@@ -15,9 +15,9 @@ class ConversationsController < ApplicationController
|
|
15
15
|
|
16
16
|
def show
|
17
17
|
if @box.eql? 'trash'
|
18
|
-
@receipts = @
|
18
|
+
@receipts = @mailbox.receipts_for(@conversation).trash
|
19
19
|
else
|
20
|
-
@receipts = @
|
20
|
+
@receipts = @mailbox.receipts_for(@conversation).not_trash
|
21
21
|
end
|
22
22
|
render :action => :show
|
23
23
|
@receipts.mark_as_read
|
@@ -41,14 +41,14 @@ class ConversationsController < ApplicationController
|
|
41
41
|
end
|
42
42
|
|
43
43
|
if params[:reply_all].present?
|
44
|
-
last_receipt = @
|
44
|
+
last_receipt = @mailbox.receipts_for(@conversation).last
|
45
45
|
@receipt = @actor.reply_to_all(last_receipt, params[:body])
|
46
46
|
end
|
47
47
|
|
48
48
|
if @box.eql? 'trash'
|
49
|
-
@receipts = @
|
49
|
+
@receipts = @mailbox.receipts_for(@conversation).trash
|
50
50
|
else
|
51
|
-
@receipts = @
|
51
|
+
@receipts = @mailbox.receipts_for(@conversation).not_trash
|
52
52
|
end
|
53
53
|
render :action => :show
|
54
54
|
@receipts.mark_as_read
|
@@ -1,10 +1,10 @@
|
|
1
1
|
class LikesController < ApplicationController
|
2
|
-
before_filter :authenticate_user
|
2
|
+
before_filter :authenticate_user!, :indirect_object
|
3
3
|
|
4
4
|
# POST /activities/1/like.js
|
5
5
|
def create
|
6
|
-
@like = Like.
|
7
|
-
|
6
|
+
@like = Like.build(current_subject, @indirect_id)
|
7
|
+
|
8
8
|
respond_to do |format|
|
9
9
|
if @like.save
|
10
10
|
format.js
|
@@ -16,8 +16,8 @@ class LikesController < ApplicationController
|
|
16
16
|
|
17
17
|
# DELETE /activities/1/like.js
|
18
18
|
def destroy
|
19
|
-
@like = Like.find!(current_subject,
|
20
|
-
|
19
|
+
@like = Like.find!(current_subject, @indirect_id)
|
20
|
+
|
21
21
|
respond_to do |format|
|
22
22
|
if @like.destroy
|
23
23
|
format.js
|
@@ -26,4 +26,16 @@ class LikesController < ApplicationController
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def indirect_object
|
33
|
+
if params[:activity_id].present?
|
34
|
+
@indirect_id = Activity.find(params[:activity_id])
|
35
|
+
elsif params[:user_id].present?
|
36
|
+
@indirect_id = User.find_by_slug!(params[:user_id])
|
37
|
+
elsif params[:group_id].present?
|
38
|
+
@indirect_id = Group.find_by_slug!(params[:group_id])
|
39
|
+
end
|
40
|
+
end
|
29
41
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
class MessagesController < ApplicationController
|
2
2
|
|
3
|
+
before_filter :authenticate_user!
|
3
4
|
before_filter :get_mailbox, :get_box, :get_actor
|
4
5
|
|
5
6
|
def index
|
@@ -46,6 +47,7 @@ class MessagesController < ApplicationController
|
|
46
47
|
@receipt = @actor.send_message(@recipients, params[:body], params[:subject])
|
47
48
|
if (@receipt.errors.blank?)
|
48
49
|
@conversation = @receipt.conversation
|
50
|
+
flash[:success]="Your message was sent"
|
49
51
|
redirect_to conversation_path(@conversation, :box => :sentbox)
|
50
52
|
else
|
51
53
|
render :action => :new
|
@@ -77,7 +79,7 @@ class MessagesController < ApplicationController
|
|
77
79
|
def get_box
|
78
80
|
if params[:box].blank? or !["inbox","sentbox","trash"].include?params[:box]
|
79
81
|
@box = "inbox"
|
80
|
-
|
82
|
+
return
|
81
83
|
end
|
82
84
|
@box = params[:box]
|
83
85
|
end
|
@@ -1,8 +1,19 @@
|
|
1
1
|
# Changes context for users to represent other subjects
|
2
2
|
class RepresentationsController < ApplicationController
|
3
|
+
before_filter :load_representation
|
4
|
+
|
5
|
+
authorize_resource
|
6
|
+
|
3
7
|
def create
|
4
|
-
self.current_subject =
|
8
|
+
self.current_subject = @representation.subject
|
5
9
|
|
6
10
|
redirect_to(request.referer || home_path)
|
7
11
|
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Build representation from params
|
16
|
+
def load_representation
|
17
|
+
@representation = Representation.new(params[:representation])
|
18
|
+
end
|
8
19
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class TagsController < ApplicationController
|
2
|
+
before_filter :authenticate_user!
|
3
|
+
|
4
|
+
def index
|
5
|
+
@tags = ActsAsTaggableOn::Tag.where('name like ?','%'+params[:tag]+'%').limit(10)
|
6
|
+
response = @tags.map{ |t| { 'key' => t.name, 'value' => t.name } }.to_json
|
7
|
+
if @tags.count == 0
|
8
|
+
response = "[{\"key\":\""+params[:tag]+"\" , \"value\":\""+params[:tag]+"\"}]"
|
9
|
+
end
|
10
|
+
|
11
|
+
respond_to do |format|
|
12
|
+
format.json { render :text => response}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,10 +1,13 @@
|
|
1
1
|
class UsersController < InheritedResources::Base
|
2
|
+
load_and_authorize_resource
|
3
|
+
|
2
4
|
respond_to :html, :xml, :js
|
3
5
|
|
4
6
|
def index
|
5
7
|
@users = User.alphabetic.
|
6
8
|
letter(params[:letter]).
|
7
9
|
search(params[:search]).
|
10
|
+
tagged_with(params[:tag]).
|
8
11
|
paginate(:per_page => 10, :page => params[:page])
|
9
12
|
|
10
13
|
index! do |format|
|
@@ -1,14 +1,21 @@
|
|
1
1
|
module ActivitiesHelper
|
2
|
-
|
2
|
+
|
3
3
|
# Link to 'like' or 'unlike' depending on the like status of the activity to current_subject
|
4
4
|
#
|
5
|
-
# @param [
|
5
|
+
# @param [Object]
|
6
6
|
# @return [String]
|
7
|
-
def link_like(
|
8
|
-
if
|
9
|
-
link_to
|
7
|
+
def link_like(object)
|
8
|
+
if !user_signed_in?
|
9
|
+
link_to image_tag("btn/nolike.png", :class => "menu_icon")+
|
10
|
+
t('activity.like'),new_user_session_path
|
10
11
|
else
|
11
|
-
|
12
|
+
if (object.liked_by?(current_subject))
|
13
|
+
link_to image_tag("btn/like.png", :class => "menu_icon")+
|
14
|
+
t('activity.unlike'), [object, :like], :method => :delete, :remote => true
|
15
|
+
else
|
16
|
+
link_to image_tag("btn/nolike.png", :class => "menu_icon")+
|
17
|
+
t('activity.like'), [object, :like], :method => :post, :remote => true
|
18
|
+
end
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
data/app/models/activity.rb
CHANGED
@@ -10,12 +10,6 @@
|
|
10
10
|
# There are two types of wall, :home and :profile. Check {Actor#wall} for more information
|
11
11
|
#
|
12
12
|
class Activity < ActiveRecord::Base
|
13
|
-
# The direction of the sender and receiver subjects compared with the attached tie
|
14
|
-
SUBJECT_DIRECTIONS = {
|
15
|
-
:direct => %w(follow make-friend),
|
16
|
-
:inverse => %w(like post update)
|
17
|
-
}
|
18
|
-
|
19
13
|
has_ancestry
|
20
14
|
|
21
15
|
belongs_to :activity_verb
|
@@ -34,8 +28,8 @@ class Activity < ActiveRecord::Base
|
|
34
28
|
has_many :activity_objects,
|
35
29
|
:through => :activity_object_activities
|
36
30
|
|
37
|
-
after_create :
|
38
|
-
|
31
|
+
after_create :send_notifications
|
32
|
+
|
39
33
|
scope :wall, lambda { |type, ties|
|
40
34
|
q = select("DISTINCT activities.*").
|
41
35
|
roots.
|
@@ -51,9 +45,9 @@ class Activity < ActiveRecord::Base
|
|
51
45
|
q
|
52
46
|
}
|
53
47
|
|
54
|
-
# After an activity is created, it is
|
48
|
+
# After an activity is created, it is disseminated to follower ties
|
55
49
|
attr_accessor :_tie
|
56
|
-
after_create :
|
50
|
+
after_create :disseminate_to_ties
|
57
51
|
|
58
52
|
# The name of the verb of this activity
|
59
53
|
def verb
|
@@ -70,7 +64,7 @@ class Activity < ActiveRecord::Base
|
|
70
64
|
# This method provides the {Actor}. Use {#sender_subject} for the {SocialStream::Models::Subject Subject}
|
71
65
|
# ({User}, {Group}, etc..)
|
72
66
|
def sender
|
73
|
-
|
67
|
+
tie.sender
|
74
68
|
end
|
75
69
|
|
76
70
|
# The {SocialStream::Models::Subject Subject} author of this activity
|
@@ -78,7 +72,7 @@ class Activity < ActiveRecord::Base
|
|
78
72
|
# This method provides the {SocialStream::Models::Subject Subject} ({User}, {Group}, etc...).
|
79
73
|
# Use {#sender} for the {Actor}.
|
80
74
|
def sender_subject
|
81
|
-
|
75
|
+
tie.sender_subject
|
82
76
|
end
|
83
77
|
|
84
78
|
# The wall where the activity is shown belongs to receiver
|
@@ -86,7 +80,7 @@ class Activity < ActiveRecord::Base
|
|
86
80
|
# This method provides the {Actor}. Use {#receiver_subject} for the {SocialStream::Models::Subject Subject}
|
87
81
|
# ({User}, {Group}, etc..)
|
88
82
|
def receiver
|
89
|
-
|
83
|
+
tie.receiver
|
90
84
|
end
|
91
85
|
|
92
86
|
# The wall where the activity is shown belongs to the receiver
|
@@ -94,7 +88,7 @@ class Activity < ActiveRecord::Base
|
|
94
88
|
# This method provides the {SocialStream::Models::Subject Subject} ({User}, {Group}, etc...).
|
95
89
|
# Use {#receiver} for the {Actor}.
|
96
90
|
def receiver_subject
|
97
|
-
|
91
|
+
tie.receiver_subject
|
98
92
|
end
|
99
93
|
|
100
94
|
# The comments about this activity
|
@@ -108,7 +102,7 @@ class Activity < ActiveRecord::Base
|
|
108
102
|
end
|
109
103
|
|
110
104
|
def liked_by(user) #:nodoc:
|
111
|
-
likes.joins(:ties).where('tie_activities.original' => true).merge(Tie.
|
105
|
+
likes.joins(:ties).where('tie_activities.original' => true).merge(Tie.sent_by(user))
|
112
106
|
end
|
113
107
|
|
114
108
|
# Does user like this activity?
|
@@ -118,9 +112,14 @@ class Activity < ActiveRecord::Base
|
|
118
112
|
|
119
113
|
# Build a new children activity where subject like this
|
120
114
|
def new_like(subject)
|
121
|
-
children.new :verb => "like",
|
122
|
-
|
123
|
-
|
115
|
+
a = children.new :verb => "like",
|
116
|
+
:_tie => subject.sent_ties(:receiver => receiver).first
|
117
|
+
|
118
|
+
if direct_activity_object.present?
|
119
|
+
a.activity_objects << direct_activity_object
|
120
|
+
end
|
121
|
+
|
122
|
+
a
|
124
123
|
end
|
125
124
|
|
126
125
|
# The first activity object of this activity
|
@@ -136,7 +135,7 @@ class Activity < ActiveRecord::Base
|
|
136
135
|
# The title for this activity in the stream
|
137
136
|
def title view
|
138
137
|
case verb
|
139
|
-
when "follow", "make-friend"
|
138
|
+
when "follow", "make-friend", "like"
|
140
139
|
I18n.t "activity.verb.#{ verb }.#{ tie.receiver.subject_type }.title",
|
141
140
|
:subject => view.link_name(sender_subject),
|
142
141
|
:contact => view.link_name(receiver_subject)
|
@@ -144,47 +143,49 @@ class Activity < ActiveRecord::Base
|
|
144
143
|
view.link_name sender_subject
|
145
144
|
end.html_safe
|
146
145
|
end
|
146
|
+
|
147
|
+
def notificable?
|
148
|
+
return true if is_root?
|
149
|
+
return true if ['post','update'].include? root.verb
|
150
|
+
#return false if ['follow','like','make_friend'].include? root.verb #Not necessary
|
151
|
+
return false
|
152
|
+
end
|
153
|
+
|
154
|
+
def notify
|
155
|
+
return nil if !notificable?
|
156
|
+
#Avaible verbs: follow, like, make-friend, post, update
|
157
|
+
case verb
|
158
|
+
when 'like'
|
159
|
+
#Like a SUBJECT
|
160
|
+
|
161
|
+
#Like an OBJECT
|
162
|
+
|
163
|
+
when 'follow','make_friend'
|
164
|
+
#Follow or Make friend with a SUBJECT
|
165
|
+
receipts = _tie.receiver.notify(I18n.t("activity.verb." + verb + "." + _tie.receiver_subject.class.to_s + ".notification.subject", :name => _tie.sender.name),
|
166
|
+
I18n.t("activity.verb." + verb + "." + _tie.receiver_subject.class.to_s + ".notification.body", :name => _tie.sender.name))
|
167
|
+
when 'post','update'
|
168
|
+
#Post or udapte an OBJECT
|
169
|
+
if _tie.sender!=_tie.receiver
|
170
|
+
receipts = _tie.receiver.notify(I18n.t("activity.verb." + verb + "." + _tie.receiver_subject.class.to_s + ".notification.subject", :name => _tie.sender.name, :direct_object => direct_object.class.to_s),
|
171
|
+
I18n.t("activity.verb." + verb + "." + _tie.receiver_subject.class.to_s + ".notification.body", :name => _tie.sender.name, :direct_object => direct_object.class.to_s))
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
147
175
|
|
148
176
|
private
|
149
177
|
|
150
178
|
# Assign to ties of followers
|
151
|
-
def
|
152
|
-
|
153
|
-
|
154
|
-
# All the ties following the activities attached to this tie, allowed to read
|
155
|
-
# this activity
|
156
|
-
Tie.following([_tie.sender_id, _tie.receiver_id]).each do |t|
|
157
|
-
if _tie.allows?(t.sender_id, 'read', 'activity')
|
158
|
-
tie_activities.create!(:tie => t,
|
159
|
-
:original => false)
|
160
|
-
end
|
161
|
-
end
|
179
|
+
def disseminate_to_ties
|
180
|
+
# Create the original sender tie_activity
|
181
|
+
tie_activities.create!(:tie => _tie)
|
162
182
|
end
|
163
183
|
|
164
|
-
# Link like activities with parent direct object
|
165
|
-
def like_direct_object
|
166
|
-
return unless verb == "like"
|
167
|
-
|
168
|
-
return if parent.direct_object.blank?
|
169
|
-
|
170
|
-
activity_objects << parent.direct_activity_object
|
171
|
-
end
|
172
184
|
|
173
185
|
private
|
174
186
|
|
175
|
-
#
|
176
|
-
|
177
|
-
|
178
|
-
# and receiver as their tie. On the other hand, post activities are inverse. The sender of
|
179
|
-
# the activity is the receiver of the tie and the receiver of the activity is the sender of
|
180
|
-
# the tie
|
181
|
-
def direct?
|
182
|
-
if SUBJECT_DIRECTIONS[:direct].include?(verb)
|
183
|
-
true
|
184
|
-
elsif SUBJECT_DIRECTIONS[:inverse].include?(verb)
|
185
|
-
false
|
186
|
-
else
|
187
|
-
raise "Unknown direction for verb #{ verb }"
|
188
|
-
end
|
187
|
+
#Send notifications to actors based on proximity, interest and permissions
|
188
|
+
def send_notifications
|
189
|
+
notify
|
189
190
|
end
|
190
191
|
end
|
@@ -12,6 +12,8 @@ class ActivityObject < ActiveRecord::Base
|
|
12
12
|
@subtypes_name = :object
|
13
13
|
include SocialStream::Models::Supertype
|
14
14
|
|
15
|
+
acts_as_taggable
|
16
|
+
|
15
17
|
has_many :activity_object_activities, :dependent => :destroy
|
16
18
|
has_many :activities, :through => :activity_object_activities
|
17
19
|
has_one :actor
|
data/app/models/actor.rb
CHANGED
@@ -14,16 +14,19 @@ class Actor < ActiveRecord::Base
|
|
14
14
|
@subtypes_name = :subject
|
15
15
|
include SocialStream::Models::Supertype
|
16
16
|
|
17
|
+
delegate :tag_list, :tag_list=, :tagged_with, :tag_counts, :to => :activity_object
|
18
|
+
|
17
19
|
validates_presence_of :name, :subject_type
|
18
20
|
|
19
21
|
acts_as_messageable
|
22
|
+
|
20
23
|
acts_as_url :name, :url_attribute => :slug
|
21
24
|
|
22
25
|
has_one :profile, :dependent => :destroy
|
23
26
|
|
24
27
|
has_many :avatars,
|
25
|
-
|
26
|
-
|
28
|
+
:validate => true,
|
29
|
+
:autosave => true
|
27
30
|
|
28
31
|
has_many :sent_ties,
|
29
32
|
:class_name => "Tie",
|
@@ -43,6 +46,10 @@ class Actor < ActiveRecord::Base
|
|
43
46
|
:through => :sent_ties,
|
44
47
|
:uniq => true
|
45
48
|
|
49
|
+
has_many :spheres
|
50
|
+
|
51
|
+
has_many :relations, :through => :spheres
|
52
|
+
|
46
53
|
scope :alphabetic, order('actors.name')
|
47
54
|
|
48
55
|
scope :letter, lambda { |param|
|
@@ -56,6 +63,12 @@ class Actor < ActiveRecord::Base
|
|
56
63
|
where('actors.name LIKE ?', "%#{ param }%")
|
57
64
|
end
|
58
65
|
}
|
66
|
+
|
67
|
+
scope :tagged_with, lambda { |param|
|
68
|
+
if param.present?
|
69
|
+
joins(:activity_object).merge(ActivityObject.tagged_with(param))
|
70
|
+
end
|
71
|
+
}
|
59
72
|
|
60
73
|
scope :distinct_initials, select('DISTINCT SUBSTR(actors.name,1,1) as initial').order("initial ASC")
|
61
74
|
|
@@ -121,15 +134,15 @@ class Actor < ActiveRecord::Base
|
|
121
134
|
Tie.sent_or_received_by(self)
|
122
135
|
end
|
123
136
|
|
124
|
-
# Relations defined and managed by this actor
|
125
|
-
def relations
|
126
|
-
Relation.includes(:ties).merge(Tie.sent_by(self))
|
127
|
-
end
|
128
|
-
|
129
137
|
# A given relation defined and managed by this actor
|
130
138
|
def relation(name)
|
131
139
|
relations.find_by_name(name)
|
132
140
|
end
|
141
|
+
|
142
|
+
# The {Relation::Public} for this {Actor}
|
143
|
+
def relation_public
|
144
|
+
Relation::Public.of(self)
|
145
|
+
end
|
133
146
|
|
134
147
|
# All the {Actor actors} this one has relation with
|
135
148
|
#
|
@@ -229,18 +242,39 @@ class Actor < ActiveRecord::Base
|
|
229
242
|
|
230
243
|
# Set of ties sent by this actor received by a
|
231
244
|
def ties_to(a)
|
232
|
-
sent_ties.received_by(a)
|
245
|
+
sent_ties.received_by(a)
|
246
|
+
end
|
247
|
+
|
248
|
+
# Get the first of the ties created to a, or create a new one with the {Relation::Public}
|
249
|
+
def ties_to!(a)
|
250
|
+
ties_to(a).present? ?
|
251
|
+
ties_to(a) :
|
252
|
+
Array(sent_ties.create!(:receiver => a,
|
253
|
+
:relation => relation_public))
|
233
254
|
end
|
234
255
|
|
235
256
|
def ties_to?(a)
|
236
257
|
ties_to(a).present?
|
237
258
|
end
|
238
|
-
|
239
|
-
#
|
240
|
-
def
|
259
|
+
|
260
|
+
# The sent {Tie ties} by this {Actor} that grant subject the permission to perform action on object
|
261
|
+
def allow(subject, action, object = nil)
|
241
262
|
return [] if subject.blank?
|
242
|
-
|
243
|
-
sent_ties.allowing(subject, action,
|
263
|
+
|
264
|
+
sent_ties.allowing(subject, action, object)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Does this {Actor} have any {Tie} to subject that grants her the permission of performing action on object
|
268
|
+
def allow?(subject, action, object = nil)
|
269
|
+
allow(subject, action, object).any?
|
270
|
+
end
|
271
|
+
|
272
|
+
# Can this actor be represented by subject. Does she has permissions for it?
|
273
|
+
def represented_by?(subject)
|
274
|
+
return false if subject.blank?
|
275
|
+
|
276
|
+
self.class.normalize(subject) == self ||
|
277
|
+
allow?(subject, 'represent')
|
244
278
|
end
|
245
279
|
|
246
280
|
# The ties that allow attaching an activity to them. This method is used for caching
|
@@ -248,10 +282,17 @@ class Actor < ActiveRecord::Base
|
|
248
282
|
@active_ties ||= {}
|
249
283
|
end
|
250
284
|
|
251
|
-
#
|
252
|
-
def
|
285
|
+
# This {Actor} #allow s subject to create activities and subject has at least one tie to subject
|
286
|
+
def activity_ties_for(subject)
|
253
287
|
active_ties[subject] ||=
|
254
|
-
|
288
|
+
( allow?(subject, 'create', 'activity') ?
|
289
|
+
subject.ties_to!(self) :
|
290
|
+
[] )
|
291
|
+
end
|
292
|
+
|
293
|
+
# Is there any {Tie} for subject to create an activity to this {Actor} ?
|
294
|
+
def activity_ties_for?(subject)
|
295
|
+
activity_ties_for(subject).any?
|
255
296
|
end
|
256
297
|
|
257
298
|
def pending_ties
|
@@ -278,8 +319,7 @@ class Actor < ActiveRecord::Base
|
|
278
319
|
ts = ties
|
279
320
|
|
280
321
|
if type == :profile
|
281
|
-
|
282
|
-
return [] if options[:for].blank?
|
322
|
+
return ties.public_relation if options[:for].blank?
|
283
323
|
|
284
324
|
ts = ts.allowing(options[:for], 'read', 'activity')
|
285
325
|
end
|
@@ -299,10 +339,36 @@ class Actor < ActiveRecord::Base
|
|
299
339
|
avatars.active.first || avatars.build
|
300
340
|
end
|
301
341
|
|
342
|
+
# The 'like' qualifications emmited to this actor
|
343
|
+
def likes
|
344
|
+
Activity.joins(:activity_verb).where('activity_verbs.name' => "like").
|
345
|
+
joins(:activity_objects).where('activity_objects.id' => activity_object_id)
|
346
|
+
end
|
347
|
+
|
348
|
+
def liked_by(subject) #:nodoc:
|
349
|
+
likes.joins(:ties).where('tie_activities.original' => true).merge(Tie.sent_by(subject))
|
350
|
+
end
|
351
|
+
|
352
|
+
# Does subject like this {Actor}?
|
353
|
+
def liked_by?(subject)
|
354
|
+
liked_by(subject).present?
|
355
|
+
end
|
356
|
+
|
357
|
+
# Build a new activity where subject like this
|
358
|
+
def new_like(subject)
|
359
|
+
a = Activity.new :verb => "like",
|
360
|
+
:_tie => subject.ties_to(self).first
|
361
|
+
|
362
|
+
a.activity_objects << activity_object
|
363
|
+
|
364
|
+
a
|
365
|
+
end
|
366
|
+
|
302
367
|
private
|
303
368
|
|
304
369
|
# After create callback
|
305
370
|
def create_initial_relations
|
306
|
-
Relation.defaults_for(self)
|
371
|
+
Relation::Custom.defaults_for(self)
|
372
|
+
Relation::Public.default_for(self)
|
307
373
|
end
|
308
374
|
end
|
data/app/models/avatar.rb
CHANGED
@@ -2,7 +2,8 @@ require 'RMagick'
|
|
2
2
|
|
3
3
|
class Avatar < ActiveRecord::Base
|
4
4
|
has_attached_file :logo,
|
5
|
-
:styles => { :
|
5
|
+
:styles => { :representation => "20x20>",
|
6
|
+
:tie => "30x30>",
|
6
7
|
:actor => '35x35>',
|
7
8
|
:profile => '94x94' },
|
8
9
|
:default_url => "/images/logos/:style/:subtype_class.png"
|
data/app/models/like.rb
CHANGED
@@ -1,34 +1,49 @@
|
|
1
1
|
# Convenience class for managing like activities
|
2
2
|
class Like
|
3
|
-
attr_reader :
|
3
|
+
attr_reader :object
|
4
4
|
|
5
5
|
class << self
|
6
6
|
# Find the children activity of activity_id liked by subject
|
7
|
-
def find(subject,
|
8
|
-
|
7
|
+
def find(subject, object)
|
8
|
+
like = new(object.liked_by(subject).first)
|
9
|
+
# Cache object to make it available before it is destroyed
|
10
|
+
like.object
|
11
|
+
like
|
9
12
|
end
|
10
13
|
|
11
14
|
# Like #find but raises error if not found
|
12
|
-
def find!(subject,
|
13
|
-
find(subject,
|
15
|
+
def find!(subject, object)
|
16
|
+
find(subject, object) ||
|
14
17
|
raise(ActiveRecord::RecordNotFound)
|
15
18
|
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
Activity.find(id) ||
|
20
|
-
raise(ActiveRecord::RecordNotFound)
|
20
|
+
def build(subject, object)
|
21
|
+
new object.new_like(subject)
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
25
|
# Initialize a new like activity
|
25
|
-
def initialize(
|
26
|
-
@
|
27
|
-
@activity = self.class.find_activity(activity_id)
|
28
|
-
@like = @activity.new_like(@subject)
|
26
|
+
def initialize(activity)
|
27
|
+
@like = activity
|
29
28
|
end
|
30
29
|
|
31
30
|
def save
|
32
31
|
@like.save
|
33
32
|
end
|
33
|
+
|
34
|
+
# The object that is liked. It can be an activity
|
35
|
+
def object
|
36
|
+
@object ||=
|
37
|
+
if @like.is_root?
|
38
|
+
obj = @like.direct_object
|
39
|
+
obj = obj.subject if obj.is_a?(Actor)
|
40
|
+
obj
|
41
|
+
else
|
42
|
+
@like.parent
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def destroy
|
47
|
+
@like.destroy
|
48
|
+
end
|
34
49
|
end
|