social_stream-base 0.20.0 → 0.20.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +2 -2
- data/app/assets/stylesheets/base.css.scss +1 -1
- data/app/controllers/activities_controller.rb +1 -2
- data/app/controllers/profiles_controller.rb +40 -8
- data/app/controllers/search_controller.rb +6 -49
- data/app/helpers/search_helper.rb +4 -34
- data/app/models/activity_object.rb +37 -4
- data/app/models/actor.rb +6 -0
- data/app/models/relation.rb +15 -0
- data/app/models/tie.rb +6 -0
- data/app/views/comments/create.js.erb +12 -7
- data/app/views/messages/_form.html.erb +1 -1
- data/app/views/posts/create.js.erb +8 -3
- data/app/views/search/_extended_search.html.erb +1 -1
- data/app/views/search/_extended_tab.html.erb +5 -0
- data/app/views/search/_form.html.erb +3 -3
- data/app/views/search/index.js.erb +3 -3
- data/config/routes.rb +6 -2
- data/lib/logos/groups/1.jpg +0 -0
- data/lib/logos/groups/10.jpg +0 -0
- data/lib/logos/groups/11.jpg +0 -0
- data/lib/logos/groups/12.jpg +0 -0
- data/lib/logos/groups/2.jpg +0 -0
- data/lib/logos/groups/3.jpg +0 -0
- data/lib/logos/groups/4.jpg +0 -0
- data/lib/logos/groups/5.jpg +0 -0
- data/lib/logos/groups/6.jpg +0 -0
- data/lib/logos/groups/7.jpg +0 -0
- data/lib/logos/groups/8.jpg +0 -0
- data/lib/logos/groups/9.jpg +0 -0
- data/lib/logos/partners/1.jpg +0 -0
- data/lib/logos/partners/1.png +0 -0
- data/lib/logos/partners/2.jpg +0 -0
- data/lib/logos/partners/2.png +0 -0
- data/lib/logos/users/1.jpg +0 -0
- data/lib/logos/users/10.jpg +0 -0
- data/lib/logos/users/11.jpg +0 -0
- data/lib/logos/users/12.jpg +0 -0
- data/lib/logos/users/2.jpg +0 -0
- data/lib/logos/users/3.jpg +0 -0
- data/lib/logos/users/4.jpg +0 -0
- data/lib/logos/users/5.jpg +0 -0
- data/lib/logos/users/6.jpg +0 -0
- data/lib/logos/users/7.jpg +0 -0
- data/lib/logos/users/8.jpg +0 -0
- data/lib/logos/users/9.jpg +0 -0
- data/lib/social_stream-base.rb +8 -0
- data/lib/social_stream/base/dependencies.rb +3 -1
- data/lib/social_stream/base/thinking-sphinx.rb +3 -1
- data/lib/social_stream/base/version.rb +1 -1
- data/lib/social_stream/controllers/helpers.rb +36 -30
- data/lib/social_stream/controllers/objects.rb +89 -1
- data/lib/social_stream/controllers/subjects.rb +3 -1
- data/lib/social_stream/models/object.rb +18 -0
- data/lib/social_stream/models/subject.rb +2 -0
- data/lib/social_stream/population/activity_object.rb +55 -0
- data/lib/social_stream/{populate.rb → population/power_law.rb} +3 -4
- data/lib/social_stream/population/timestamps.rb +12 -0
- data/lib/social_stream/search.rb +107 -0
- data/lib/tasks/db/populate.rake +13 -26
- data/social_stream-base.gemspec +3 -1
- data/spec/models/post_spec.rb +14 -0
- metadata +110 -68
data/README.rdoc
CHANGED
@@ -7,8 +7,8 @@ network environment see https://github.com/ging/social_stream
|
|
7
7
|
|
8
8
|
== Features
|
9
9
|
|
10
|
-
* Social network
|
11
|
-
* Activity streams
|
10
|
+
* Social network infrastructure
|
11
|
+
* Activity streams infrastructure
|
12
12
|
* Subjects: {User} and {Group}
|
13
13
|
* Objects: {Post} and {Comment}
|
14
14
|
* Private messages and notifications, by {Mailboxer}[https://github.com/ging/mailboxer]
|
@@ -240,7 +240,7 @@ div.chzn-container ul.chzn-choices li.search-field input{ cursor:pointer;}
|
|
240
240
|
padding: 5px 7px;
|
241
241
|
background-color: $secondary-color;
|
242
242
|
}
|
243
|
-
.menu_plain_list li span.selected {
|
243
|
+
.menu_plain_list li span.selected, .menu_plain_list li span.active {
|
244
244
|
border: solid 1px $main-color;
|
245
245
|
}
|
246
246
|
.menu_plain_list li span.disabled {
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class ActivitiesController < InheritedResources::Base
|
2
|
-
belongs_to_subjects
|
3
2
|
actions :index
|
4
3
|
|
5
4
|
respond_to :js
|
@@ -10,7 +9,7 @@ class ActivitiesController < InheritedResources::Base
|
|
10
9
|
rel = params[:section].to_i if params[:section].present?
|
11
10
|
|
12
11
|
# should be activities.page(params[:page], :count => { :select => 'activity.id', :distinct => true }) but it is not working in Rails 3.0.3
|
13
|
-
@activities ||=
|
12
|
+
@activities ||= profile_subject.
|
14
13
|
wall(:profile,
|
15
14
|
:for => current_subject,
|
16
15
|
:relation => rel).
|
@@ -1,9 +1,41 @@
|
|
1
|
-
class ProfilesController <
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
class ProfilesController < ApplicationController
|
2
|
+
before_filter :authenticate_user!, :except => [ :show ]
|
3
|
+
|
4
|
+
respond_to :html, :js
|
5
|
+
|
6
|
+
def show
|
7
|
+
subject_profile
|
8
|
+
end
|
9
|
+
|
10
|
+
def edit
|
11
|
+
current_profile
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
current_profile.update_attributes params[:profile]
|
16
|
+
|
17
|
+
respond_to do |format|
|
18
|
+
format.html{ redirect_to [profile_subject, :profile] }
|
19
|
+
format.js
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def subject_profile
|
26
|
+
@profile ||=
|
27
|
+
profile_subject!.profile
|
28
|
+
end
|
29
|
+
|
30
|
+
def current_profile
|
31
|
+
@profile ||= find_current_profile
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_current_profile
|
35
|
+
unless profile_subject!.represented_by?(current_subject)
|
36
|
+
raise CanCan::AccessDenied
|
37
|
+
end
|
38
|
+
|
39
|
+
current_subject.profile
|
40
|
+
end
|
9
41
|
end
|
@@ -1,18 +1,14 @@
|
|
1
1
|
class SearchController < ApplicationController
|
2
2
|
include ActionView::Helpers::SanitizeHelper
|
3
3
|
|
4
|
-
helper_method :get_search_query
|
5
|
-
|
6
4
|
RESULTS_SEARCH_PER_PAGE=12
|
7
5
|
MIN_QUERY=2
|
8
6
|
def index
|
9
7
|
@search_result =
|
10
|
-
if params[:q].blank? ||
|
8
|
+
if params[:q].blank? || params[:q].strip.size < MIN_QUERY
|
11
9
|
[]
|
12
10
|
elsif params[:mode].eql? "header_search"
|
13
11
|
search :quick
|
14
|
-
elsif params[:type].present?
|
15
|
-
focus_search
|
16
12
|
else
|
17
13
|
search :extended
|
18
14
|
end
|
@@ -41,56 +37,17 @@ class SearchController < ApplicationController
|
|
41
37
|
private
|
42
38
|
|
43
39
|
def search mode
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
result = SocialStream::Search.search(params[:q],
|
41
|
+
current_subject,
|
42
|
+
:mode => mode,
|
43
|
+
:key => params[:type])
|
48
44
|
|
49
|
-
models.map! {|model_sym| model_sym.to_s.classify.constantize}
|
50
|
-
result = ThinkingSphinx.search(get_search_query, :classes => models)
|
51
|
-
result = authorization_filter result
|
52
45
|
if mode.to_s.eql? "quick"
|
53
46
|
result = Kaminari.paginate_array(result).page(1).per(7)
|
54
47
|
else
|
55
48
|
result = Kaminari.paginate_array(result).page(params[:page]).per(RESULTS_SEARCH_PER_PAGE)
|
56
49
|
end
|
57
|
-
return result
|
58
|
-
end
|
59
|
-
|
60
|
-
def focus_search
|
61
|
-
@search_class_sym = params[:type].singularize.to_sym unless params[:type].blank?
|
62
|
-
search_class = @search_class_sym.to_s.classify.constantize
|
63
|
-
result = ThinkingSphinx.search(get_search_query, :classes => [search_class])
|
64
|
-
result = authorization_filter result
|
65
|
-
return Kaminari.paginate_array(result).page(params[:page]).per(RESULTS_SEARCH_PER_PAGE)
|
66
|
-
end
|
67
|
-
|
68
|
-
def too_short_query
|
69
|
-
bare_query = strip_tags(params[:q]) unless bare_query.html_safe?
|
70
|
-
return bare_query.strip.size < MIN_QUERY
|
71
|
-
end
|
72
|
-
|
73
|
-
def get_search_query
|
74
|
-
search_query = ""
|
75
|
-
param = strip_tags(params[:q]) || ""
|
76
|
-
bare_query = param unless bare_query.html_safe?
|
77
|
-
search_query_words = bare_query.strip.split
|
78
|
-
search_query_words.each_index do |i|
|
79
|
-
search_query+= search_query_words[i] + " " if i < (search_query_words.size - 1)
|
80
|
-
search_query+= "*" + search_query_words[i] + "* " if i == (search_query_words.size - 1)
|
81
|
-
end
|
82
|
-
return search_query.strip
|
83
|
-
end
|
84
50
|
|
85
|
-
|
86
|
-
filtered_results = Array.new
|
87
|
-
results.each do |result|
|
88
|
-
if result.is_a? SocialStream::Models::Object
|
89
|
-
filtered_results << result if can? :read, result
|
90
|
-
else
|
91
|
-
filtered_results << result
|
92
|
-
end
|
93
|
-
end
|
94
|
-
return filtered_results
|
51
|
+
result
|
95
52
|
end
|
96
53
|
end
|
@@ -30,39 +30,9 @@ module SearchHelper
|
|
30
30
|
return bare_query.strip.split
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
params[:type].eql?(model_sym.to_s) &&
|
38
|
-
'selected' || ''
|
39
|
-
when :disabled
|
40
|
-
search_results?(model_sym) &&
|
41
|
-
'' || 'disabled'
|
42
|
-
else
|
43
|
-
raise "Unknown select search class type"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def search_results?(model_sym)
|
48
|
-
ThinkingSphinx.count(get_search_query,
|
49
|
-
:classes => [model_sym.to_s.classify.constantize]) > 0
|
50
|
-
end
|
51
|
-
|
52
|
-
def search_tab(model_sym)
|
53
|
-
span_options = {}
|
54
|
-
span_options[:class] = "#{ search_class(:selected, model_sym) } #{ search_class(:disabled, model_sym) } #{ model_sym.to_s.pluralize.downcase }"
|
55
|
-
|
56
|
-
results = search_results?(model_sym)
|
57
|
-
|
58
|
-
unless results
|
59
|
-
span_options[:title] = t('search.no_subject_found', :subject => model_sym.to_s)
|
60
|
-
end
|
61
|
-
|
62
|
-
link_to_if results,
|
63
|
-
content_tag(:span, t("#{ model_sym }.title.other"), span_options),
|
64
|
-
search_path(:type => model_sym,
|
65
|
-
:q => params[:q]),
|
66
|
-
:remote => true
|
33
|
+
def search_results?(key)
|
34
|
+
SocialStream::Search.count(params[:q],
|
35
|
+
current_subject,
|
36
|
+
:key => key) > 0
|
67
37
|
end
|
68
38
|
end
|
@@ -32,9 +32,12 @@ class ActivityObject < ActiveRecord::Base
|
|
32
32
|
:conditions => { 'activity_actions.follow' => true }
|
33
33
|
|
34
34
|
# Associations for indexing
|
35
|
-
has_many :
|
35
|
+
has_many :author_actions,
|
36
36
|
:class_name => "ActivityAction",
|
37
|
-
:conditions => {
|
37
|
+
:conditions => { :author => true }
|
38
|
+
has_many :owner_actions,
|
39
|
+
:class_name => "ActivityAction",
|
40
|
+
:conditions => { :owner => true }
|
38
41
|
|
39
42
|
has_many :activity_object_properties,
|
40
43
|
:dependent => :destroy
|
@@ -49,7 +52,8 @@ class ActivityObject < ActiveRecord::Base
|
|
49
52
|
:through => :activity_object_holders,
|
50
53
|
:source => :activity_object
|
51
54
|
|
52
|
-
|
55
|
+
|
56
|
+
before_validation :fill_owner_id, :fill_user_author_id, :fill_relation_ids, :if => lambda { |obj| obj.object_type != "Actor" }
|
53
57
|
|
54
58
|
validates_presence_of :object_type
|
55
59
|
validate :allowed_relations, :if => lambda { |obj| obj.object_type != "Actor" }
|
@@ -71,8 +75,23 @@ class ActivityObject < ActiveRecord::Base
|
|
71
75
|
merge(ActivityAction.not_sent_by(subject).where(:author => true))
|
72
76
|
}
|
73
77
|
|
78
|
+
scope :owned_by, lambda { |subject|
|
79
|
+
joins(:received_actions).
|
80
|
+
merge(ActivityAction.sent_by(subject).where(:owner => true))
|
81
|
+
}
|
82
|
+
|
74
83
|
scope :followed, order("activity_objects.follower_count DESC")
|
75
84
|
|
85
|
+
scope :followed_by, lambda { |subject|
|
86
|
+
joins(:received_actions).
|
87
|
+
merge(ActivityAction.sent_by(subject).where(:follow => true))
|
88
|
+
}
|
89
|
+
|
90
|
+
scope :shared_with, lambda { |subject|
|
91
|
+
joins(:activity_object_audiences).
|
92
|
+
merge(ActivityObjectAudience.where(:relation_id => Relation.ids_shared_with(subject)))
|
93
|
+
}
|
94
|
+
|
76
95
|
def received_role_action(role)
|
77
96
|
received_actions.
|
78
97
|
find{ |a| a.__send__ "#{ role }?" }
|
@@ -179,6 +198,20 @@ class ActivityObject < ActiveRecord::Base
|
|
179
198
|
|
180
199
|
private
|
181
200
|
|
201
|
+
def fill_owner_id
|
202
|
+
return if owner_id.present? || author_id.blank?
|
203
|
+
|
204
|
+
self.owner_id = author_id
|
205
|
+
end
|
206
|
+
|
207
|
+
def fill_user_author_id
|
208
|
+
return if user_author_id.present? ||
|
209
|
+
author_id.blank? ||
|
210
|
+
author.subject_type != "User"
|
211
|
+
|
212
|
+
self.user_author_id = author_id
|
213
|
+
end
|
214
|
+
|
182
215
|
def fill_relation_ids
|
183
216
|
return if relation_ids.present? || author.blank? || owner.blank?
|
184
217
|
|
@@ -206,7 +239,7 @@ class ActivityObject < ActiveRecord::Base
|
|
206
239
|
Relation::Single.allowing('read', 'activity')
|
207
240
|
|
208
241
|
if (relation_ids - allowed_rels.map(&:id)).any?
|
209
|
-
errors.add(:relation_ids, "not allowed")
|
242
|
+
errors.add(:relation_ids, "not allowed: #{ relation_ids }, author_id: #{ author_id }, owner_id: #{ owner_id }")
|
210
243
|
end
|
211
244
|
end
|
212
245
|
|
data/app/models/actor.rb
CHANGED
@@ -317,6 +317,12 @@ class Actor < ActiveRecord::Base
|
|
317
317
|
map(&:id)
|
318
318
|
end
|
319
319
|
|
320
|
+
# An array with the ids of {Actor Actors} followed by this {Actor}
|
321
|
+
# plus the id from this {Actor}
|
322
|
+
def following_actor_and_self_ids
|
323
|
+
following_actor_ids + [ id ]
|
324
|
+
end
|
325
|
+
|
320
326
|
# Does this {Actor} allow subject to perform action on object?
|
321
327
|
def allow?(subject, action, object)
|
322
328
|
ties_to(subject).with_permissions(action, object).any?
|
data/app/models/relation.rb
CHANGED
@@ -152,6 +152,21 @@ class Relation < ActiveRecord::Base
|
|
152
152
|
def allow?(*args)
|
153
153
|
allow(*args).to_a.any?
|
154
154
|
end
|
155
|
+
|
156
|
+
# All the {Relation} ids in {Tie Ties} this subject has received
|
157
|
+
# plus the one from {Relation::Public}
|
158
|
+
def ids_shared_with(subject)
|
159
|
+
ids = [Relation::Public.instance.id]
|
160
|
+
|
161
|
+
if SocialStream.relation_model == :custom && subject.present?
|
162
|
+
# Subject own defined custom relations
|
163
|
+
ids += subject.relation_ids
|
164
|
+
# From Ties sent by other subject
|
165
|
+
ids += subject.received_relation_ids
|
166
|
+
end
|
167
|
+
|
168
|
+
ids
|
169
|
+
end
|
155
170
|
end
|
156
171
|
|
157
172
|
# Relation class scoped in the same mode that this relation
|
data/app/models/tie.rb
CHANGED
@@ -28,6 +28,12 @@ class Tie < ActiveRecord::Base
|
|
28
28
|
has_one :receiver, :through => :contact
|
29
29
|
|
30
30
|
belongs_to :relation
|
31
|
+
has_many :permissions, :through => :relation
|
32
|
+
|
33
|
+
scope :allowing, lambda { |action, object|
|
34
|
+
joins(:relation).
|
35
|
+
merge(Relation.allowing(action, object))
|
36
|
+
}
|
31
37
|
|
32
38
|
scope :recent, order("ties.created_at DESC")
|
33
39
|
|
@@ -1,8 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
$(".
|
4
|
-
$(".
|
5
|
-
$(
|
6
|
-
|
1
|
+
<% if @comment.valid? %>
|
2
|
+
//Display the new comment
|
3
|
+
$("#comments_activity_<%= @comment.post_activity.parent.id %>").append("<%= escape_javascript(render @comment.post_activity) %>");
|
4
|
+
$(".activities_comment_btn").hide();
|
5
|
+
$(".input_new_comments").each(function() {
|
6
|
+
$(this).focus().val("").blur();
|
7
|
+
});
|
7
8
|
|
8
|
-
SocialStream.Timeline.create("<%= escape_javascript dom_id(@comment.post_activity) %>");
|
9
|
+
SocialStream.Timeline.create("<%= escape_javascript dom_id(@comment.post_activity) %>");
|
10
|
+
<% else %>
|
11
|
+
SocialStream.Timeline.create();
|
12
|
+
alert('<%= j @comment.errors.full_messages.to_sentence %>');
|
13
|
+
<% end %>
|
@@ -1,4 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
<% if @post.valid? %>
|
2
|
+
//Display the new post
|
3
|
+
$("#wall").prepend("<%= escape_javascript(render @post.post_activity) %>");
|
3
4
|
|
4
|
-
SocialStream.Timeline.create("<%= escape_javascript dom_id(@post.post_activity) %>");
|
5
|
+
SocialStream.Timeline.create("<%= escape_javascript dom_id(@post.post_activity) %>");
|
6
|
+
<% else %>
|
7
|
+
SocialStream.Timeline.create();
|
8
|
+
alert('<%= j @post.errors.full_messages.to_sentence %>');
|
9
|
+
<% end %>
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<%= link_to (search_results?(key) ? search_path(:type => key, :q => params[:q]) : '#') do %>
|
2
|
+
<span class="<%= key %><%= " active" if params[:type] == key.to_s %><%= " disabled" unless search_results?(key) %>" <%= "title=\"#{ t 'search.no_subject_found', :subject => key.to_s }\"" %>>
|
3
|
+
<%= t("#{ key }.title.other") %>
|
4
|
+
</span>
|
5
|
+
<% end %>
|
@@ -13,12 +13,12 @@
|
|
13
13
|
<ul class="menu_plain_list">
|
14
14
|
<li><%= link_to content_tag(:span,
|
15
15
|
t('search.show_all'),
|
16
|
-
:class => "global #{ params[:type].blank? && '
|
16
|
+
:class => "global #{ params[:type].blank? && 'active' }"),
|
17
17
|
search_path(:q => params[:q]),
|
18
18
|
:remote => true %></li>
|
19
|
-
<% SocialStream.
|
19
|
+
<% SocialStream::Search.keys(:extended).each do |model_sym| %>
|
20
20
|
<li>
|
21
|
-
<%=
|
21
|
+
<%= render :partial => 'extended_tab', :locals => { :key => model_sym } %>
|
22
22
|
</li>
|
23
23
|
<% end %>
|
24
24
|
</ul>
|
@@ -1,12 +1,12 @@
|
|
1
1
|
$('#search_results').html("<%= escape_javascript render :partial => 'extended_search' %>");
|
2
2
|
$('#search_form_div').html("<%= escape_javascript render :partial => 'form' %>");
|
3
3
|
|
4
|
-
$('#focus_options ul li a span').removeClass('
|
4
|
+
$('#focus_options ul li a span').removeClass('active');
|
5
5
|
|
6
6
|
<% if params[:type].present? %>
|
7
|
-
$('#focus_options ul li a span.<%= params[:type].pluralize.downcase %>').addClass('
|
7
|
+
$('#focus_options ul li a span.<%= params[:type].pluralize.downcase %>').addClass('active');
|
8
8
|
<% else %>
|
9
|
-
$('#focus_options ul li a span.global').addClass('
|
9
|
+
$('#focus_options ul li a span.global').addClass('active');
|
10
10
|
<% end %>
|
11
11
|
|
12
12
|
$('title').text('<%= t('search.name')%> <%= escape_javascript(params[:q].present? ? ": #{params[:q]}" : "")%>');
|
data/config/routes.rb
CHANGED
@@ -17,7 +17,9 @@ Rails.application.routes.draw do
|
|
17
17
|
#
|
18
18
|
# /users/demo/posts
|
19
19
|
(SocialStream.objects - [ :actor ]).each do |object|
|
20
|
-
resources object.to_s.pluralize
|
20
|
+
resources object.to_s.pluralize do
|
21
|
+
get 'search', :on => :collection
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
@@ -26,7 +28,9 @@ Rails.application.routes.draw do
|
|
26
28
|
#
|
27
29
|
# /posts
|
28
30
|
(SocialStream.objects - [ :actor ]).each do |object|
|
29
|
-
resources object.to_s.pluralize
|
31
|
+
resources object.to_s.pluralize do
|
32
|
+
get 'search', :on => :collection
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
32
36
|
resources :comments
|