social_stream-base 0.19.2 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/javascripts/social_stream.follow.js +23 -0
- data/app/assets/javascripts/social_stream.wall.js.erb +3 -3
- data/app/controllers/search_controller.rb +30 -16
- data/app/helpers/location_helper.rb +1 -44
- data/app/helpers/search_helper.rb +7 -7
- data/app/models/activity.rb +0 -21
- data/app/models/activity_action.rb +8 -0
- data/app/models/activity_object.rb +55 -25
- data/app/models/activity_object_audience.rb +8 -0
- data/app/models/actor.rb +9 -0
- data/app/models/comment.rb +1 -3
- data/app/models/group.rb +3 -0
- data/app/models/post.rb +1 -3
- data/app/models/relation.rb +5 -0
- data/app/models/relation/follow.rb +6 -7
- data/app/models/relation/public.rb +5 -0
- data/app/models/relation/single.rb +11 -1
- data/app/views/activities/_new.html.erb +1 -1
- data/app/views/contacts/_link_follow.html.erb +8 -4
- data/app/views/followers/update.js.erb +2 -0
- data/app/views/layouts/_search.html.erb +2 -2
- data/app/views/search/_extended_search.html.erb +17 -17
- data/app/views/search/_form.html.erb +4 -4
- data/app/views/search/_header_search.html.erb +2 -2
- data/app/views/search/index.html.erb +1 -1
- data/app/views/search/index.js.erb +4 -4
- data/db/migrate/20120403175913_create_activity_object_audiences.rb +34 -0
- data/db/migrate/20120411132550_add_visit_count_to_activity_object.rb +9 -0
- data/db/migrate/20120411151413_relation_public_permissions.rb +8 -0
- data/lib/generators/social_stream/base/templates/initializer.rb +3 -0
- data/lib/social_stream-base.rb +2 -1
- data/lib/social_stream/ability/base.rb +14 -8
- data/lib/social_stream/base/dependencies.rb +1 -0
- data/lib/social_stream/base/thinking-sphinx.rb +18 -0
- data/lib/social_stream/base/version.rb +1 -1
- data/lib/social_stream/controllers/objects.rb +6 -0
- data/lib/social_stream/test_helpers/controllers.rb +1 -1
- data/lib/social_stream/views/location.rb +48 -0
- data/lib/tasks/db/populate.rake +1 -1
- data/lib/thinking-sphinx/social_stream.rb +3 -0
- data/spec/controllers/groups_controller_spec.rb +6 -6
- data/spec/controllers/posts_controller_spec.rb +6 -6
- data/spec/controllers/users_controller_spec.rb +4 -4
- data/spec/dummy/config/initializers/social_stream.rb +3 -0
- data/spec/factories/activity.rb +24 -1
- data/spec/factories/post.rb +1 -1
- data/spec/models/activity_authorization_spec.rb +1 -1
- data/spec/models/post_spec.rb +0 -4
- data/spec/models/relation_follow_spec.rb +8 -0
- metadata +73 -64
@@ -0,0 +1,23 @@
|
|
1
|
+
SocialStream.Follow = (function(SS, $, undefined){
|
2
|
+
var initButtons = function(){
|
3
|
+
$(".following-button").mouseenter(function(){
|
4
|
+
$(this).hide();
|
5
|
+
$(this).siblings(".unfollow-button").show();
|
6
|
+
});
|
7
|
+
|
8
|
+
$(".unfollow-button").mouseleave(function(){
|
9
|
+
$(this).hide();
|
10
|
+
$(this).siblings(".following-button").show();
|
11
|
+
});
|
12
|
+
|
13
|
+
$(".unfollow-button").hide();
|
14
|
+
}
|
15
|
+
|
16
|
+
$(function(){
|
17
|
+
SocialStream.Follow.initButtons();
|
18
|
+
});
|
19
|
+
|
20
|
+
return {
|
21
|
+
initButtons: initButtons
|
22
|
+
};
|
23
|
+
})(SocialStream, jQuery);
|
@@ -91,7 +91,7 @@ SocialStream.Wall = (function(SS, $, undefined){
|
|
91
91
|
});
|
92
92
|
$("#masterSubmitButton").val(I18n.t('activity.sending') + '...').attr("disabled", true);
|
93
93
|
|
94
|
-
// Add
|
94
|
+
// Add relation_ids[] parameter from authorization selector
|
95
95
|
$('.liveAdded').remove();
|
96
96
|
|
97
97
|
var currentForm = $(this);
|
@@ -102,7 +102,7 @@ SocialStream.Wall = (function(SS, $, undefined){
|
|
102
102
|
.addClass('liveAdded')
|
103
103
|
.attr('type', 'hidden')
|
104
104
|
.attr('name', currentForm
|
105
|
-
.attr('id').split('_')[1]+'[
|
105
|
+
.attr('id').split('_')[1]+'[relation_ids][]')
|
106
106
|
.val($(this).attr('value')));
|
107
107
|
});
|
108
108
|
return true;
|
@@ -128,7 +128,7 @@ SocialStream.Wall = (function(SS, $, undefined){
|
|
128
128
|
$(this).removeAttr("readonly").val("").blur();
|
129
129
|
});
|
130
130
|
//New comments
|
131
|
-
$('.input_new_comments').each(function() {
|
131
|
+
$('.input_new_comments').each(function() {
|
132
132
|
$(this).removeAttr("readonly").val("");
|
133
133
|
});
|
134
134
|
}
|
@@ -6,20 +6,35 @@ class SearchController < ApplicationController
|
|
6
6
|
RESULTS_SEARCH_PER_PAGE=12
|
7
7
|
MIN_QUERY=2
|
8
8
|
def index
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
@search_result =
|
10
|
+
if params[:q].blank? || too_short_query
|
11
|
+
[]
|
12
|
+
elsif params[:mode].eql? "header_search"
|
13
|
+
search :quick
|
14
|
+
elsif params[:type].present?
|
15
|
+
focus_search
|
16
16
|
else
|
17
|
-
|
18
|
-
@search_result = focus_search
|
19
|
-
else
|
20
|
-
@search_result = search :extended
|
21
|
-
end
|
17
|
+
search :extended
|
22
18
|
end
|
19
|
+
|
20
|
+
respond_to do |format|
|
21
|
+
format.html {
|
22
|
+
if params[:mode] == "header_search"
|
23
|
+
render :partial => "header_search"
|
24
|
+
end
|
25
|
+
}
|
26
|
+
|
27
|
+
format.json {
|
28
|
+
json_obj = (
|
29
|
+
params[:type].present? ?
|
30
|
+
{ params[:type].pluralize => @search_result } :
|
31
|
+
@search_result
|
32
|
+
)
|
33
|
+
|
34
|
+
render :json => json_obj
|
35
|
+
}
|
36
|
+
|
37
|
+
format.js
|
23
38
|
end
|
24
39
|
end
|
25
40
|
|
@@ -43,7 +58,7 @@ class SearchController < ApplicationController
|
|
43
58
|
end
|
44
59
|
|
45
60
|
def focus_search
|
46
|
-
@search_class_sym = params[:
|
61
|
+
@search_class_sym = params[:type].singularize.to_sym unless params[:type].blank?
|
47
62
|
search_class = @search_class_sym.to_s.classify.constantize
|
48
63
|
result = ThinkingSphinx.search(get_search_query, :classes => [search_class])
|
49
64
|
result = authorization_filter result
|
@@ -51,13 +66,13 @@ class SearchController < ApplicationController
|
|
51
66
|
end
|
52
67
|
|
53
68
|
def too_short_query
|
54
|
-
bare_query = strip_tags(params[:
|
69
|
+
bare_query = strip_tags(params[:q]) unless bare_query.html_safe?
|
55
70
|
return bare_query.strip.size < MIN_QUERY
|
56
71
|
end
|
57
72
|
|
58
73
|
def get_search_query
|
59
74
|
search_query = ""
|
60
|
-
param = strip_tags(params[:
|
75
|
+
param = strip_tags(params[:q]) || ""
|
61
76
|
bare_query = param unless bare_query.html_safe?
|
62
77
|
search_query_words = bare_query.strip.split
|
63
78
|
search_query_words.each_index do |i|
|
@@ -70,7 +85,6 @@ class SearchController < ApplicationController
|
|
70
85
|
def authorization_filter results
|
71
86
|
filtered_results = Array.new
|
72
87
|
results.each do |result|
|
73
|
-
puts result
|
74
88
|
if result.is_a? SocialStream::Models::Object
|
75
89
|
filtered_results << result if can? :read, result
|
76
90
|
else
|
@@ -1,46 +1,3 @@
|
|
1
1
|
module LocationHelper
|
2
|
-
|
3
|
-
# Renders the location stack for your view. You can add as many stack levels as you wish.
|
4
|
-
#
|
5
|
-
# Usage:
|
6
|
-
# <%= location(level1,leve2,level3,level4,....) %>
|
7
|
-
#
|
8
|
-
# Output:
|
9
|
-
# base > level1 > level2 > level3 > level 4
|
10
|
-
#
|
11
|
-
# Default configuration:
|
12
|
-
# base => "You are here" ("location.base" on config/locales)
|
13
|
-
# separator => ">" ("location.separator" on config/locales)
|
14
|
-
#
|
15
|
-
# Styles and HTML wrapping:
|
16
|
-
# partial => location/_location.html.erb
|
17
|
-
#
|
18
|
-
# Example:
|
19
|
-
# Render a location with two leves depth:
|
20
|
-
#
|
21
|
-
# <%= location(link_to(leve1.name, level1.url),link_to(leve2.name, level2.url)) %>
|
22
|
-
#
|
23
|
-
def location(*stack)
|
24
|
-
|
25
|
-
location_body = render :partial => "location/location_body", :locals=>{:stack => stack}
|
26
|
-
|
27
|
-
location_div = capture do
|
28
|
-
render :partial => "location/location", :locals=>{:location_body => location_body}
|
29
|
-
end
|
30
|
-
|
31
|
-
case request.format
|
32
|
-
when Mime::JS
|
33
|
-
response = <<-EOJ
|
34
|
-
|
35
|
-
$('#map_location').html("#{ escape_javascript(location_div) }");
|
36
|
-
EOJ
|
37
|
-
|
38
|
-
response.html_safe
|
39
|
-
else
|
40
|
-
content_for(:location) do
|
41
|
-
location_div
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
2
|
+
include SocialStream::Views::Location
|
46
3
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module SearchHelper
|
2
2
|
def too_short_query?
|
3
|
-
return true if params[:
|
4
|
-
bare_query = strip_tags(params[:
|
3
|
+
return true if params[:q].blank?
|
4
|
+
bare_query = strip_tags(params[:q]) unless bare_query.html_safe?
|
5
5
|
return bare_query.strip.size < SearchController::MIN_QUERY
|
6
6
|
end
|
7
7
|
|
@@ -26,15 +26,15 @@ module SearchHelper
|
|
26
26
|
|
27
27
|
def get_search_query_words
|
28
28
|
search_query = ""
|
29
|
-
bare_query = strip_tags(params[:
|
29
|
+
bare_query = strip_tags(params[:q]) unless bare_query.html_safe?
|
30
30
|
return bare_query.strip.split
|
31
31
|
end
|
32
32
|
|
33
33
|
def search_class(type, model_sym)
|
34
34
|
case type
|
35
35
|
when :selected
|
36
|
-
params[:
|
37
|
-
params[:
|
36
|
+
params[:type].present? &&
|
37
|
+
params[:type].eql?(model_sym.to_s) &&
|
38
38
|
'selected' || ''
|
39
39
|
when :disabled
|
40
40
|
search_results?(model_sym) &&
|
@@ -61,8 +61,8 @@ module SearchHelper
|
|
61
61
|
|
62
62
|
link_to_if results,
|
63
63
|
content_tag(:span, t("#{ model_sym }.title.other"), span_options),
|
64
|
-
search_path(:
|
65
|
-
:
|
64
|
+
search_path(:type => model_sym,
|
65
|
+
:q => params[:q]),
|
66
66
|
:remote => true
|
67
67
|
end
|
68
68
|
end
|
data/app/models/activity.rb
CHANGED
@@ -90,8 +90,6 @@ class Activity < ActiveRecord::Base
|
|
90
90
|
order("created_at desc")
|
91
91
|
}
|
92
92
|
|
93
|
-
before_validation :fill_relations
|
94
|
-
|
95
93
|
after_create :increment_like_count
|
96
94
|
after_destroy :decrement_like_count, :delete_notifications
|
97
95
|
|
@@ -325,25 +323,6 @@ class Activity < ActiveRecord::Base
|
|
325
323
|
|
326
324
|
private
|
327
325
|
|
328
|
-
# Before validation callback
|
329
|
-
#
|
330
|
-
# Fill the relations when posting to other subject's wall
|
331
|
-
def fill_relations
|
332
|
-
return if relation_ids.present?
|
333
|
-
|
334
|
-
self.relation_ids =
|
335
|
-
# FIXME: repeated in ActivityObject#_relation_ids
|
336
|
-
if SocialStream.relation_model == :custom
|
337
|
-
if channel.reflexive?
|
338
|
-
receiver.relation_customs.map(&:id)
|
339
|
-
else
|
340
|
-
receiver.relation_customs.allow(channel.author, 'create', 'activity').map(&:id)
|
341
|
-
end
|
342
|
-
else
|
343
|
-
Array.wrap Relation::Public.instance.id
|
344
|
-
end
|
345
|
-
end
|
346
|
-
|
347
326
|
#
|
348
327
|
# Get the email subject for the activity's notification
|
349
328
|
#
|
@@ -19,6 +19,14 @@ class ActivityAction < ActiveRecord::Base
|
|
19
19
|
where(:activity_object_id => ActivityObject.normalize_id(activity_object))
|
20
20
|
}
|
21
21
|
|
22
|
+
scope :authored_or_owned, where(arel_table[:author].eq(true).
|
23
|
+
or(arel_table[:user_author].eq(true)).
|
24
|
+
or(arel_table[:owner].eq(true)))
|
25
|
+
|
26
|
+
scope :authored_or_owned_by, lambda{ |subject|
|
27
|
+
authored_or_owned.sent_by(subject)
|
28
|
+
}
|
29
|
+
|
22
30
|
before_create :follow_by_author_and_owner
|
23
31
|
|
24
32
|
private
|
@@ -9,7 +9,6 @@
|
|
9
9
|
# Objects are added to +config/initializers/social_stream.rb+
|
10
10
|
#
|
11
11
|
class ActivityObject < ActiveRecord::Base
|
12
|
-
attr_writer :_relation_ids
|
13
12
|
attr_reader :_activity_parent_id
|
14
13
|
|
15
14
|
# ActivityObject is a supertype of SocialStream.objects
|
@@ -17,6 +16,9 @@ class ActivityObject < ActiveRecord::Base
|
|
17
16
|
|
18
17
|
acts_as_taggable
|
19
18
|
|
19
|
+
has_many :activity_object_audiences, :dependent => :destroy
|
20
|
+
has_many :relations, :through => :activity_object_audiences
|
21
|
+
|
20
22
|
has_many :activity_object_activities, :dependent => :destroy
|
21
23
|
has_many :activities, :through => :activity_object_activities
|
22
24
|
|
@@ -29,6 +31,11 @@ class ActivityObject < ActiveRecord::Base
|
|
29
31
|
:source => :actor,
|
30
32
|
:conditions => { 'activity_actions.follow' => true }
|
31
33
|
|
34
|
+
# Associations for indexing
|
35
|
+
has_many :author_action,
|
36
|
+
:class_name => "ActivityAction",
|
37
|
+
:conditions => { 'activity_actions.author' => true }
|
38
|
+
|
32
39
|
has_many :activity_object_properties,
|
33
40
|
:dependent => :destroy
|
34
41
|
has_many :object_properties,
|
@@ -42,7 +49,10 @@ class ActivityObject < ActiveRecord::Base
|
|
42
49
|
:through => :activity_object_holders,
|
43
50
|
:source => :activity_object
|
44
51
|
|
52
|
+
before_validation :fill_relation_ids, :if => lambda { |obj| obj.object_type != "Actor" }
|
53
|
+
|
45
54
|
validates_presence_of :object_type
|
55
|
+
validate :allowed_relations, :if => lambda { |obj| obj.object_type != "Actor" }
|
46
56
|
|
47
57
|
# TODO: This is currently defined in lib/social_stream/models/object.rb
|
48
58
|
#
|
@@ -110,6 +120,15 @@ class ActivityObject < ActiveRecord::Base
|
|
110
120
|
class_eval code, __FILE__, __LINE__ - code.lines.count - 2
|
111
121
|
end
|
112
122
|
|
123
|
+
# subject was the author, user author or owner of this {ActivityObject}?
|
124
|
+
def authored_or_owned_by?(subject)
|
125
|
+
return false if subject.blank?
|
126
|
+
|
127
|
+
received_actions.
|
128
|
+
merge(ActivityAction.authored_or_owned_by(subject)).
|
129
|
+
any?
|
130
|
+
end
|
131
|
+
|
113
132
|
# Was the author represented when this {ActivityObject} was created?
|
114
133
|
def represented_author?
|
115
134
|
author_id != user_author_id
|
@@ -146,28 +165,7 @@ class ActivityObject < ActiveRecord::Base
|
|
146
165
|
Activity.new :author => author,
|
147
166
|
:user_author => user_author,
|
148
167
|
:owner => owner,
|
149
|
-
:relation_ids =>
|
150
|
-
end
|
151
|
-
|
152
|
-
def _relation_ids
|
153
|
-
@_relation_ids ||=
|
154
|
-
if author.blank? || owner.blank?
|
155
|
-
nil
|
156
|
-
else
|
157
|
-
# FIXME: repeated in Activity#fill_relations
|
158
|
-
if SocialStream.relation_model == :custom
|
159
|
-
if author == owner
|
160
|
-
owner.relation_customs.map(&:id)
|
161
|
-
else
|
162
|
-
owner.
|
163
|
-
relation_customs.
|
164
|
-
allow(author, 'create', 'activity').
|
165
|
-
map(&:id)
|
166
|
-
end
|
167
|
-
else
|
168
|
-
Array.wrap Relation::Public.instance.id
|
169
|
-
end
|
170
|
-
end
|
168
|
+
:relation_ids => relation_ids
|
171
169
|
end
|
172
170
|
|
173
171
|
def _activity_parent
|
@@ -175,12 +173,44 @@ class ActivityObject < ActiveRecord::Base
|
|
175
173
|
end
|
176
174
|
|
177
175
|
def _activity_parent_id=(id)
|
178
|
-
self.
|
176
|
+
self.relation_ids = Activity.find(id).relation_ids
|
179
177
|
@_activity_parent_id = id
|
180
178
|
end
|
181
179
|
|
182
180
|
private
|
183
181
|
|
182
|
+
def fill_relation_ids
|
183
|
+
return if relation_ids.present? || author.blank? || owner.blank?
|
184
|
+
|
185
|
+
@valid_relations = true
|
186
|
+
|
187
|
+
self.relation_ids =
|
188
|
+
if SocialStream.relation_model == :custom
|
189
|
+
owner.
|
190
|
+
relations.
|
191
|
+
allowing('read', 'activity').
|
192
|
+
map(&:id)
|
193
|
+
else
|
194
|
+
Array.wrap Relation::Public.instance.id
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# validate method
|
199
|
+
#
|
200
|
+
# check relations are included in
|
201
|
+
def allowed_relations
|
202
|
+
return if @valid_relations
|
203
|
+
|
204
|
+
allowed_rels =
|
205
|
+
owner.relations.allowing('read', 'activity') +
|
206
|
+
Relation::Single.allowing('read', 'activity')
|
207
|
+
|
208
|
+
if (relation_ids - allowed_rels.map(&:id)).any?
|
209
|
+
errors.add(:relation_ids, "not allowed")
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
|
184
214
|
def create_post_activity
|
185
215
|
create_activity "post"
|
186
216
|
end
|
@@ -194,7 +224,7 @@ class ActivityObject < ActiveRecord::Base
|
|
194
224
|
:author_id => author_id,
|
195
225
|
:user_author => user_author,
|
196
226
|
:owner => owner,
|
197
|
-
:relation_ids =>
|
227
|
+
:relation_ids => relation_ids,
|
198
228
|
:parent_id => _activity_parent_id
|
199
229
|
|
200
230
|
a.activity_objects << self
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Every {ActivityObject} ({Post}, {Comment}, etc.) is shared with one or more {Relation Relations}.
|
2
|
+
#
|
3
|
+
# Each {Relation} is equivalent to a set {Actor Actors}, which are the ones that have {Tie Ties}
|
4
|
+
# to that {Relation}, in other words, the contacts that were added to that {Relation}
|
5
|
+
class ActivityObjectAudience < ActiveRecord::Base
|
6
|
+
belongs_to :activity_object
|
7
|
+
belongs_to :relation
|
8
|
+
end
|
data/app/models/actor.rb
CHANGED
@@ -57,6 +57,10 @@ class Actor < ActiveRecord::Base
|
|
57
57
|
has_many :received_ties,
|
58
58
|
:through => :received_contacts,
|
59
59
|
:source => :ties
|
60
|
+
|
61
|
+
has_many :received_relations,
|
62
|
+
:through => :received_ties,
|
63
|
+
:source => :relation
|
60
64
|
|
61
65
|
has_many :senders,
|
62
66
|
:through => :received_contacts,
|
@@ -313,6 +317,11 @@ class Actor < ActiveRecord::Base
|
|
313
317
|
map(&:id)
|
314
318
|
end
|
315
319
|
|
320
|
+
# Does this {Actor} allow subject to perform action on object?
|
321
|
+
def allow?(subject, action, object)
|
322
|
+
ties_to(subject).with_permissions(action, object).any?
|
323
|
+
end
|
324
|
+
|
316
325
|
# The {Channel} of this {Actor} to self (totally close!)
|
317
326
|
def self_channel
|
318
327
|
Channel.find_or_create_by_author_id_and_user_author_id_and_owner_id id, id, id
|