social_stream 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|