social_stream-base 0.19.1 → 0.19.2
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/conversations_controller.rb +15 -10
- data/app/controllers/followers_controller.rb +4 -9
- data/app/helpers/permissions_helper.rb +4 -0
- data/app/models/activity_action.rb +4 -0
- data/app/models/activity_object.rb +9 -0
- data/app/models/actor.rb +19 -0
- data/app/models/group.rb +5 -0
- data/app/models/relation/single.rb +2 -1
- data/app/models/user.rb +1 -1
- data/app/views/conversations/destroy.js.erb +2 -0
- data/app/views/followers/index.html.erb +26 -5
- data/app/views/permissions/_index.html.erb +7 -2
- data/app/views/profiles/update.js.erb +4 -9
- data/app/views/relation/customs/_list.html.erb +4 -0
- data/config/locales/en.yml +4 -0
- data/config/locales/es.yml +5 -1
- data/config/routes.rb +31 -32
- data/lib/generators/social_stream/base/templates/initializer.rb +5 -1
- data/lib/social_stream-base.rb +12 -1
- data/lib/social_stream/base/version.rb +1 -1
- data/lib/social_stream/models/object.rb +5 -0
- data/lib/social_stream/models/supertype.rb +1 -1
- data/lib/social_stream/routing/constraints/custom.rb +11 -0
- data/lib/social_stream/routing/constraints/follow.rb +11 -0
- data/lib/social_stream/routing/constraints/resque.rb +11 -0
- data/spec/controllers/followers_controller_spec.rb +37 -0
- data/spec/controllers/posts_controller_spec.rb +196 -163
- data/spec/dummy/config/initializers/social_stream.rb +5 -1
- data/spec/factories/tie.rb +4 -0
- data/spec/integration/resque_access_spec.rb +30 -0
- data/spec/models/post_spec.rb +66 -17
- metadata +70 -64
@@ -59,17 +59,22 @@ class ConversationsController < ApplicationController
|
|
59
59
|
|
60
60
|
@conversation.move_to_trash(@actor)
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
62
|
+
respond_to do |format|
|
63
|
+
format.html {
|
64
|
+
if params[:location].present? and params[:location] == 'conversation'
|
65
|
+
redirect_to conversations_path(:box => :trash)
|
66
|
+
else
|
67
|
+
redirect_to conversations_path(:box => @box,:page => params[:page])
|
68
|
+
end
|
69
|
+
}
|
70
|
+
format.js {
|
71
|
+
if params[:location].present? and params[:location] == 'conversation'
|
72
|
+
render :js => "window.location = '#{conversations_path(:box => @box,:page => params[:page])}';"
|
73
|
+
else
|
74
|
+
render 'conversations/destroy'
|
75
|
+
end
|
76
|
+
}
|
71
77
|
end
|
72
|
-
redirect_to conversations_path(:box => @box,:page => params[:page])
|
73
78
|
end
|
74
79
|
|
75
80
|
private
|
@@ -4,17 +4,12 @@ class FollowersController < ApplicationController
|
|
4
4
|
respond_to :html, :js
|
5
5
|
|
6
6
|
def index
|
7
|
-
@
|
8
|
-
|
9
|
-
current_subject.sent_contacts
|
10
|
-
else
|
11
|
-
current_subject.received_contacts
|
12
|
-
end
|
7
|
+
@followings = current_subject.following_actor_objects.includes(:actor)
|
8
|
+
@followers = current_subject.followers
|
13
9
|
|
14
10
|
respond_to do |format|
|
15
|
-
format.html
|
16
|
-
format.
|
17
|
-
format.json { render :text => to_json(@contacts) }
|
11
|
+
format.html
|
12
|
+
format.json { render :text => to_json(@followers) }
|
18
13
|
end
|
19
14
|
end
|
20
15
|
|
@@ -14,4 +14,8 @@ module PermissionsHelper
|
|
14
14
|
Permission.find_or_create_by_action_and_object *p
|
15
15
|
}
|
16
16
|
end
|
17
|
+
|
18
|
+
def disable_permission_edit? perm
|
19
|
+
(perm.action == 'represent') and (@relation.ties.size > 0) and perm.relations.include?(@relation) and (perm.relations.where(:actor_id => @relation.actor_id).find_all{|r| r.ties.size > 0}.size <= 1)
|
20
|
+
end
|
17
21
|
end
|
@@ -11,6 +11,10 @@ class ActivityAction < ActiveRecord::Base
|
|
11
11
|
where(:actor_id => Actor.normalize_id(actor))
|
12
12
|
}
|
13
13
|
|
14
|
+
scope :not_sent_by, lambda{ |actor|
|
15
|
+
where(arel_table[:actor_id].not_in(Actor.normalize_id(actor)))
|
16
|
+
}
|
17
|
+
|
14
18
|
scope :received_by, lambda{ |activity_object|
|
15
19
|
where(:activity_object_id => ActivityObject.normalize_id(activity_object))
|
16
20
|
}
|
@@ -56,6 +56,11 @@ class ActivityObject < ActiveRecord::Base
|
|
56
56
|
merge(ActivityAction.sent_by(subject).where(:author => true))
|
57
57
|
}
|
58
58
|
|
59
|
+
scope :not_authored_by, lambda { |subject|
|
60
|
+
joins(:received_actions).
|
61
|
+
merge(ActivityAction.not_sent_by(subject).where(:author => true))
|
62
|
+
}
|
63
|
+
|
59
64
|
scope :followed, order("activity_objects.follower_count DESC")
|
60
65
|
|
61
66
|
def received_role_action(role)
|
@@ -122,6 +127,10 @@ class ActivityObject < ActiveRecord::Base
|
|
122
127
|
object_type == "Actor"
|
123
128
|
end
|
124
129
|
|
130
|
+
def actor!
|
131
|
+
actor || raise("Unknown Actor for ActivityObject: #{ inspect }")
|
132
|
+
end
|
133
|
+
|
125
134
|
# Return the {Action} model to an {Actor}
|
126
135
|
def action_from(actor)
|
127
136
|
received_actions.sent_by(actor).first
|
data/app/models/actor.rb
CHANGED
@@ -82,6 +82,10 @@ class Actor < ActiveRecord::Base
|
|
82
82
|
has_many :sent_actions,
|
83
83
|
:class_name => "ActivityAction",
|
84
84
|
:dependent => :destroy
|
85
|
+
has_many :followings,
|
86
|
+
:through => :sent_actions,
|
87
|
+
:source => :activity_object,
|
88
|
+
:conditions => { 'activity_actions.follow' => true }
|
85
89
|
|
86
90
|
scope :alphabetic, order('actors.name')
|
87
91
|
|
@@ -294,6 +298,21 @@ class Actor < ActiveRecord::Base
|
|
294
298
|
|
295
299
|
alias_method :ego_contact, :self_contact
|
296
300
|
|
301
|
+
# The {ActivityObject ActivityObjects} followed by this {Actor}
|
302
|
+
# that are {Actor Actors}
|
303
|
+
def following_actor_objects
|
304
|
+
followings.
|
305
|
+
where('activity_objects.object_type' => "Actor")
|
306
|
+
end
|
307
|
+
|
308
|
+
# An array with the ids of {Actor Actors} followed by this {Actor}
|
309
|
+
def following_actor_ids
|
310
|
+
following_actor_objects.
|
311
|
+
includes(:actor).
|
312
|
+
map(&:actor).
|
313
|
+
map(&:id)
|
314
|
+
end
|
315
|
+
|
297
316
|
# The {Channel} of this {Actor} to self (totally close!)
|
298
317
|
def self_channel
|
299
318
|
Channel.find_or_create_by_author_id_and_user_author_id_and_owner_id id, id, id
|
data/app/models/group.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# {Group Groups} are the other kind of social entities supported in SocialStream::Base
|
2
|
+
#
|
3
|
+
# As with {User}, almost all the interaction with other classes in Social Stream is done
|
4
|
+
# through {Actor}. The glue between {Group} and {Actor} is in {SocialStream::Models::Subject}
|
5
|
+
#
|
1
6
|
class Group < ActiveRecord::Base
|
2
7
|
include SocialStream::Models::Subject
|
3
8
|
|
data/app/models/user.rb
CHANGED
@@ -6,7 +6,7 @@ require 'devise/orm/active_record'
|
|
6
6
|
# for managing authentication
|
7
7
|
#
|
8
8
|
# Almost all the logic of the interaction between {User} and the rest of classes in Social Stream
|
9
|
-
# is done through {
|
9
|
+
# is done through {Actor}. The glue between {User} and {Actor} is in {SocialStream::Models::Subject}
|
10
10
|
#
|
11
11
|
class User < ActiveRecord::Base
|
12
12
|
include SocialStream::Models::Subject
|
@@ -1,5 +1,26 @@
|
|
1
|
-
<%
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
<% sidebar %>
|
2
|
+
<% toolbar :profile, :subject => current_subject %>
|
3
|
+
<div class="followers tabbable">
|
4
|
+
<ul class="nav nav-tabs">
|
5
|
+
<li class="active">
|
6
|
+
<a data-toggle="tab" href="#following"><%=t('follow.followings')%></a>
|
7
|
+
</li>
|
8
|
+
<li class="">
|
9
|
+
<a data-toggle="tab" href="#follower"><%=t('follow.followers')%></a>
|
10
|
+
</li>
|
11
|
+
</ul>
|
12
|
+
<div class="tab-content">
|
13
|
+
<div id="following" class="tab-pane active offset1">
|
14
|
+
<%= render @followings.
|
15
|
+
page(params[:page]).
|
16
|
+
per(20).
|
17
|
+
map { |f| current_subject.contact_to!(f) } %>
|
18
|
+
</div>
|
19
|
+
<div id="follower" class="tab-pane offset1 ">
|
20
|
+
<%= render @followers.
|
21
|
+
page(params[:page]).
|
22
|
+
per(20).
|
23
|
+
map { |f| current_subject.contact_to!(f) } %>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
</div>
|
@@ -9,8 +9,13 @@
|
|
9
9
|
<tr>
|
10
10
|
<td>
|
11
11
|
<div contain=<%= dom_id p %> class="checkboxPermissionOptionLeft">
|
12
|
-
|
13
|
-
|
12
|
+
<% if disable_permission_edit? p %>
|
13
|
+
<input id=<%= dom_id p %> class="permission" type="checkbox" disabled="disabled"/>
|
14
|
+
<label for=<%= dom_id p %>><%= p.description(:brief, :subject => current_subject) %></label>
|
15
|
+
<% else %>
|
16
|
+
<input id=<%= dom_id p %> class="permission" type="checkbox"/>
|
17
|
+
<label for=<%= dom_id p %>><%= p.description(:brief, :subject => current_subject) %></label>
|
18
|
+
<% end %>
|
14
19
|
<div class="clearfloat"></div>
|
15
20
|
</div>
|
16
21
|
</td>
|
@@ -1,15 +1,10 @@
|
|
1
|
-
|
1
|
+
<% if @profile.valid? %>
|
2
|
+
<% flash[:notice] = t('profile.update.success') %>
|
3
|
+
document.location.href="<%= resource_path(@profile) %>";
|
4
|
+
<% else %>
|
2
5
|
if ($("#profile_notice").length == 0){
|
3
6
|
$("#profile_form").prepend('<div id="profile_notice" class="notice"></div>');
|
4
7
|
}
|
5
|
-
|
6
|
-
<% if @profile.valid? %>
|
7
|
-
|
8
|
-
$("#profile_notice").html("<%= t('profile.update.success')%>");
|
9
|
-
$("#profile_notice").removeClass('error');
|
10
|
-
$("#profile_notice").addClass('success');
|
11
|
-
|
12
|
-
<% else %>
|
13
8
|
$("#profile_notice").html("<h2><%= pluralize(@profile.errors.count, "error") %> <%= t('profile.update.error')%></h2>"
|
14
9
|
+"<ul><% @profile.errors.full_messages.each do |msg| %><li><%= msg %></li><% end %></ul>");
|
15
10
|
$("#profile_notice").removeClass('success');
|
@@ -39,6 +39,8 @@
|
|
39
39
|
<%= javascript_tag do %>
|
40
40
|
$(function(){
|
41
41
|
$('#relation_customs_list :radio').change(function(){
|
42
|
+
$("#new_relation_custom_title_block").show();
|
43
|
+
$("#new_relation_custom_input_block").hide();
|
42
44
|
selectRelation(this);
|
43
45
|
});
|
44
46
|
|
@@ -56,6 +58,8 @@
|
|
56
58
|
});
|
57
59
|
|
58
60
|
$("#new_relation_custom_title").click(function() {
|
61
|
+
$("#permissions_list").hide();
|
62
|
+
$("#privacy_rules").hide();
|
59
63
|
$("#new_relation_custom_title_block").hide();
|
60
64
|
$("#new_relation_custom_input_block").show();
|
61
65
|
});
|
data/config/locales/en.yml
CHANGED
@@ -191,6 +191,10 @@ en:
|
|
191
191
|
instructions: "Type the email address bound to your account and we will sent you instructions to change it:"
|
192
192
|
update: "Change your password"
|
193
193
|
follower:
|
194
|
+
follower:
|
195
|
+
title: "Followers"
|
196
|
+
following:
|
197
|
+
title: "Followings"
|
194
198
|
n:
|
195
199
|
one: "1 follower"
|
196
200
|
other: "%{count} followers"
|
data/config/locales/es.yml
CHANGED
@@ -190,7 +190,11 @@ es:
|
|
190
190
|
instructions: "Introduce el correo electrónico y te mandaremos instrucciones para cambiarlo"
|
191
191
|
update: "Cambiar contraseña"
|
192
192
|
follower:
|
193
|
-
|
193
|
+
follower:
|
194
|
+
title: "Seguidores"
|
195
|
+
following:
|
196
|
+
title: "Siguiendo"
|
197
|
+
n:
|
194
198
|
one: "1 seguidor/a"
|
195
199
|
other: "%{count} seguidores"
|
196
200
|
forgot_password: "¿Olvidaste tu contraseña?"
|
data/config/routes.rb
CHANGED
@@ -1,22 +1,11 @@
|
|
1
1
|
Rails.application.routes.draw do
|
2
|
-
#Background tasks
|
3
|
-
resque_constraint = lambda do |request|
|
4
|
-
#request.env['warden'].authenticate? and request.env['warden'].user.admin?
|
5
|
-
true
|
6
|
-
end
|
7
|
-
|
8
|
-
constraints resque_constraint do
|
9
|
-
mount Resque::Server, :at => "/resque"
|
10
|
-
end
|
11
|
-
|
12
2
|
root :to => "frontpage#index"
|
13
3
|
|
14
4
|
match 'home' => 'home#index', :as => :home
|
15
5
|
match 'home' => 'home#index', :as => :user_root # devise after_sign_in_path_for
|
16
|
-
|
17
|
-
#
|
18
|
-
|
19
|
-
|
6
|
+
|
7
|
+
match 'search' => 'search#index', :as => :search
|
8
|
+
|
20
9
|
# Social Stream subjects configured in config/initializers/social_stream.rb
|
21
10
|
SocialStream.subjects.each do |actor|
|
22
11
|
resources actor.to_s.pluralize do
|
@@ -40,15 +29,9 @@ Rails.application.routes.draw do
|
|
40
29
|
resources object.to_s.pluralize
|
41
30
|
end
|
42
31
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
resources :contacts do
|
47
|
-
collection do
|
48
|
-
get 'pending'
|
49
|
-
end
|
50
|
-
end
|
51
|
-
when :custom
|
32
|
+
resources :comments
|
33
|
+
|
34
|
+
constraints SocialStream::Routing::Constraints::Custom.new do
|
52
35
|
resources :contacts do
|
53
36
|
collection do
|
54
37
|
get 'pending'
|
@@ -62,13 +45,20 @@ Rails.application.routes.draw do
|
|
62
45
|
resources :permissions
|
63
46
|
end
|
64
47
|
|
48
|
+
constraints SocialStream::Routing::Constraints::Follow.new do
|
49
|
+
match 'followings' => 'followers#index', :as => :followings, :defaults => { :direction => 'sent' }
|
50
|
+
match 'followers' => 'followers#index', :as => :followers, :defaults => { :direction => 'received' }
|
51
|
+
resources :followers
|
52
|
+
|
53
|
+
resources :contacts do
|
54
|
+
collection do
|
55
|
+
get 'pending'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
65
60
|
resources :activity_actions
|
66
61
|
|
67
|
-
match 'tags' => 'tags#index', :as => 'tags'
|
68
|
-
|
69
|
-
# Find subjects by slug
|
70
|
-
match 'subjects/lrdd/:id' => 'subjects#lrdd', :as => 'subject_lrdd'
|
71
|
-
|
72
62
|
resource :representation
|
73
63
|
|
74
64
|
resources :settings do
|
@@ -89,19 +79,16 @@ Rails.application.routes.draw do
|
|
89
79
|
end
|
90
80
|
end
|
91
81
|
|
92
|
-
resources :comments
|
93
|
-
|
94
82
|
resources :activities do
|
95
83
|
resource :like
|
96
84
|
end
|
97
85
|
|
98
|
-
match 'search' => 'search#index', :as => :search
|
99
|
-
|
100
86
|
match 'cheesecake' => 'cheesecake#index', :as => :cheesecake
|
101
87
|
match 'update_cheesecake' => 'cheesecake#update', :as => :update_cheesecake
|
102
88
|
|
103
89
|
match 'ties' => 'ties#index', :as => :ties
|
104
90
|
|
91
|
+
match 'tags' => 'tags#index', :as => 'tags'
|
105
92
|
|
106
93
|
##API###
|
107
94
|
match 'api/keygen' => 'api#create_key', :as => :api_keygen
|
@@ -113,4 +100,16 @@ Rails.application.routes.draw do
|
|
113
100
|
match 'api/me/contacts' => 'contacts#index', :format => 'json', :as => :api_contacts
|
114
101
|
match 'api/subjects/:s/contacts' => 'contacts#index', :format => 'json', :as => :api_subject_contacts
|
115
102
|
##/API##
|
103
|
+
|
104
|
+
|
105
|
+
#Background tasks
|
106
|
+
constraints SocialStream::Routing::Constraints::Resque.new do
|
107
|
+
mount Resque::Server, :at => "/resque"
|
108
|
+
end
|
109
|
+
|
110
|
+
# Webfinger
|
111
|
+
match '.well-known/host-meta',:to => 'frontpage#host_meta'
|
112
|
+
|
113
|
+
# Find subjects by slug
|
114
|
+
match 'subjects/lrdd/:id' => 'subjects#lrdd', :as => 'subject_lrdd'
|
116
115
|
end
|
@@ -27,7 +27,11 @@ SocialStream.setup do |config|
|
|
27
27
|
# :follow - user just follow other users, like Twitter
|
28
28
|
#
|
29
29
|
# config.relation_model = :custom
|
30
|
-
|
30
|
+
|
31
|
+
# Expose resque interface to manage background tasks at /resque
|
32
|
+
#
|
33
|
+
# config.resque_access = true
|
34
|
+
|
31
35
|
# Quick search (header) and Extended search models and its order. Remember to create
|
32
36
|
# the indexes with thinking-sphinx if you are using customized models.
|
33
37
|
#
|
data/lib/social_stream-base.rb
CHANGED
@@ -26,6 +26,14 @@ module SocialStream
|
|
26
26
|
autoload :Supertype, 'social_stream/models/supertype'
|
27
27
|
end
|
28
28
|
|
29
|
+
module Routing
|
30
|
+
module Constraints
|
31
|
+
autoload :Custom, 'social_stream/routing/constraints/custom'
|
32
|
+
autoload :Follow, 'social_stream/routing/constraints/follow'
|
33
|
+
autoload :Resque, 'social_stream/routing/constraints/resque'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
29
37
|
module Views
|
30
38
|
autoload :List, 'social_stream/views/list'
|
31
39
|
|
@@ -62,7 +70,10 @@ module SocialStream
|
|
62
70
|
|
63
71
|
mattr_accessor :relation_model
|
64
72
|
@@relation_model = :custom
|
65
|
-
|
73
|
+
|
74
|
+
mattr_accessor :resque_access
|
75
|
+
@@resque_access = true
|
76
|
+
|
66
77
|
mattr_accessor :quick_search_models
|
67
78
|
@@quick_search_models = [ :user, :group, :post ]
|
68
79
|
|