Commit 601cc6bae9f52ea09ac952fee0d14b6492d62e2e
1 parent
e697a141
Exists in
federation_followers
Follow feature views and controller actions
- Follow and Unfollow profile options - Followed profiles categorization - Manage followed profiles page Signed-off-by: Artur Bersan de Faria <arturbersan@gmail.com> Signed-off-by: Gabriel Silva <gabriel93.silva@gmail.com>
Showing
18 changed files
with
316 additions
and
18 deletions
Show diff stats
... | ... | @@ -0,0 +1,16 @@ |
1 | +class FollowersController < MyProfileController | |
2 | + | |
3 | + def index | |
4 | + @followed_people = current_person.following_profiles.paginate(:per_page => 5, :page => params[:npage]) | |
5 | + end | |
6 | + | |
7 | + def set_category | |
8 | + if request.method == "GET" | |
9 | + render :partial => "set_category_modal", :locals => { :followed_profile_id => params[:followed_profile_id] } | |
10 | + elsif request.method == "POST" | |
11 | + follower = ProfileFollower.find_by(follower_id: current_person.id, profile_id: params[:followed_profile_id]) | |
12 | + follower.update_attributes(:group => params[:category_name]) if follower | |
13 | + redirect_to url_for(:controller => "followers", :action => "index") | |
14 | + end | |
15 | + end | |
16 | +end | ... | ... |
app/controllers/public/profile_controller.rb
... | ... | @@ -3,7 +3,7 @@ class ProfileController < PublicController |
3 | 3 | needs_profile |
4 | 4 | before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add] |
5 | 5 | before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail] |
6 | - before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail] | |
6 | + before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail, :follow, :unfollow] | |
7 | 7 | |
8 | 8 | helper TagsHelper |
9 | 9 | helper ActionTrackerHelper |
... | ... | @@ -65,6 +65,10 @@ class ProfileController < PublicController |
65 | 65 | end |
66 | 66 | end |
67 | 67 | |
68 | + def following | |
69 | + @followed_people = [].paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.friends.count) | |
70 | + end | |
71 | + | |
68 | 72 | def members |
69 | 73 | if is_cache_expired?(profile.members_cache_key(params)) |
70 | 74 | sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' |
... | ... | @@ -151,6 +155,22 @@ class ProfileController < PublicController |
151 | 155 | end |
152 | 156 | end |
153 | 157 | |
158 | + def follow | |
159 | + if !current_person.follows?(profile) | |
160 | + group = params['follow'] ? params['follow']['category'] : '' | |
161 | + current_person.follow(profile, group) | |
162 | + end | |
163 | + redirect_to profile.url | |
164 | + end | |
165 | + | |
166 | + def unfollow | |
167 | + if current_person.follows?(profile) | |
168 | + current_person.unfollow(profile) | |
169 | + end | |
170 | + redirect_url = params["redirect_to"] ? params["redirect_to"] : profile.url | |
171 | + redirect_to redirect_url | |
172 | + end | |
173 | + | |
154 | 174 | def check_friendship |
155 | 175 | unless logged_in? |
156 | 176 | render :text => '' | ... | ... |
app/models/person.rb
... | ... | @@ -200,7 +200,7 @@ class Person < Profile |
200 | 200 | end |
201 | 201 | end |
202 | 202 | |
203 | - def follow(profile, group = nil) | |
203 | + def follow(profile, group = "") | |
204 | 204 | unless self.following_profiles.include?(profile) |
205 | 205 | profile_follower = ProfileFollower.new |
206 | 206 | profile_follower.profile = profile |
... | ... | @@ -601,7 +601,7 @@ class Person < Profile |
601 | 601 | protected |
602 | 602 | |
603 | 603 | def followed_by?(profile) |
604 | - self == profile || self.is_a_friend?(profile) || self.followers.include(profile) | |
604 | + self == profile || self.followers.include?(profile) | |
605 | 605 | end |
606 | 606 | |
607 | 607 | end | ... | ... |
app/models/profile.rb
... | ... | @@ -204,7 +204,7 @@ class Profile < ApplicationRecord |
204 | 204 | scope :more_recent, -> { order "created_at DESC" } |
205 | 205 | |
206 | 206 | scope :following_profiles, -> person { |
207 | - distinct.select('profiles.*'). | |
207 | + distinct.select('profiles.*, profile_followers.group'). | |
208 | 208 | joins('join profile_followers ON profile_followers.profile_id = profiles.id'). |
209 | 209 | where('profile_followers.follower_id = ?', person.id) |
210 | 210 | } | ... | ... |
app/models/profile_follower.rb
1 | 1 | class ProfileFollower < ApplicationRecord |
2 | 2 | track_actions :new_follower, :after_create, :keep_params => ["follower.name", "follower.url", "follower.profile_custom_icon"], :custom_user => :profile |
3 | + attr_accessible :group | |
3 | 4 | |
4 | 5 | belongs_to :profile, :foreign_key => :profile_id |
5 | 6 | belongs_to :follower, :class_name => 'Person', :foreign_key => :follower_id | ... | ... |
app/views/blocks/profile_info_actions/_person.html.erb
... | ... | @@ -7,6 +7,20 @@ |
7 | 7 | </li> |
8 | 8 | <% end %> |
9 | 9 | |
10 | + <li> | |
11 | + <% if user.follows?(profile) %> | |
12 | + <%= button(:unfollow, content_tag('span', _('Unfollow')), {:profile => profile.identifier, :controller => 'profile', :action => 'unfollow'}) %> | |
13 | + <% else %> | |
14 | + <form id="follower-container" action="<%= url_for({:profile => profile.identifier, :controller => 'profile', :action => 'follow'}) %>"> | |
15 | + <div id="category-form" style="display: none;"> | |
16 | + <%= labelled_text_field _("Choose a category: "), "follow[category]" %> | |
17 | + </div> | |
18 | + <%= submit_button('follow', _('Follow')) %> | |
19 | + </form> | |
20 | + <% end %> | |
21 | + </li> | |
22 | + | |
23 | + | |
10 | 24 | <% if user.is_a_friend?(profile) && profile.enable_contact? %> |
11 | 25 | <li><%= button(:back, _('Send an e-mail'), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}) %></li> |
12 | 26 | <% end %> | ... | ... |
... | ... | @@ -0,0 +1,18 @@ |
1 | +<ul class="profile-list"> | |
2 | + <% profiles.each do |profile| %> | |
3 | + <li> | |
4 | + <%= link_to_profile profile_image(profile) + tag('br') + profile.short_name, | |
5 | + profile.identifier, :class => 'profile-link' %> | |
6 | + <p class="category-name"> | |
7 | + <%= profile.group %> | |
8 | + </p> | |
9 | + <div class="controll"> | |
10 | + <%= button_without_text :remove, content_tag('span',_('unfollow')), | |
11 | + { :controller => "profile", :profile => profile.identifier , :action => 'unfollow', :redirect_to => url_for({:controller => "followers", :profile => user.identifier}) }, | |
12 | + :title => _('remove') %> | |
13 | + <%= modal_icon_button :change_categoy, content_tag('span',_('change category')), | |
14 | + url_for(:controller => 'followers', :action => 'set_category', :followed_profile_id => profile.id) %> | |
15 | + </div><!-- end class="controll" --> | |
16 | + </li> | |
17 | + <% end %> | |
18 | +</ul> | ... | ... |
... | ... | @@ -0,0 +1,13 @@ |
1 | +<div class='set-category-modal'> | |
2 | + <h2><%= _("Choose a new category") %></h2> | |
3 | + <%= form_for :follower_category, :url => url_for(:controller => 'followers', :action => 'set_category') do |f| %> | |
4 | + <div id="category-name"> | |
5 | + <%= labelled_text_field _("Category: "), "category_name" %> | |
6 | + </div> | |
7 | + <%= hidden_field_tag 'followed_profile_id', followed_profile_id %> | |
8 | + <div id="actions-container"> | |
9 | + <%= submit_button('save', _('Save')) %> | |
10 | + <%= modal_close_button _("Cancel") %> | |
11 | + </div> | |
12 | + <% end %> | |
13 | +</div> | ... | ... |
... | ... | @@ -0,0 +1,25 @@ |
1 | +<div id="manage_followed people"> | |
2 | + | |
3 | +<h1><%= _("%s following") % profile.name %></h1> | |
4 | + | |
5 | +<% cache_timeout(profile.manage_friends_cache_key(params), 4.hours) do %> | |
6 | + <% if @followed_people.empty? %> | |
7 | + <p> | |
8 | + <em> | |
9 | + <%= _("You don't follow anybody yet.") %> | |
10 | + </em> | |
11 | + </p> | |
12 | + <% end %> | |
13 | + | |
14 | + <%= button_bar do %> | |
15 | + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> | |
16 | + <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> | |
17 | + <% end %> | |
18 | + | |
19 | + <%= render :partial => 'profile_list', :locals => { :profiles => @followed_people } %> | |
20 | + | |
21 | + <br style="clear:both" /> | |
22 | + <%= pagination_links @followed_people, :param_name => 'npage' %> | |
23 | +<% end %> | |
24 | + | |
25 | +</div> | ... | ... |
... | ... | @@ -0,0 +1,24 @@ |
1 | +<div class="common-profile-list-block"> | |
2 | + | |
3 | +<h1><%= _("%s is following") % profile.name %></h1> | |
4 | + | |
5 | +<% cache_timeout(profile.friends_cache_key(params), 4.hours) do %> | |
6 | +<ul class='profile-list'> | |
7 | + <% @followed_people.each do |followed_person| %> | |
8 | + <%= profile_image_link(followed_person) %> | |
9 | + <% end%> | |
10 | +</ul> | |
11 | + | |
12 | + <div id='pagination-profiles'> | |
13 | + <%= pagination_links @followed_people, :param_name => 'npage' %> | |
14 | + </div> | |
15 | +<% end %> | |
16 | + | |
17 | +<%= button_bar do %> | |
18 | + <%= button :back, _('Go back'), { :controller => 'profile' } %> | |
19 | + <% if user == profile %> | |
20 | + <%= button :edit, _('Manage followed people'), :controller => 'friends', :action => 'index', :profile => profile.identifier %> | |
21 | + <% end %> | |
22 | +<% end %> | |
23 | + | |
24 | +</div> | ... | ... |
app/views/profile_editor/edit.html.erb
... | ... | @@ -26,6 +26,11 @@ |
26 | 26 | |
27 | 27 | <% if profile.person? %> |
28 | 28 | <div> |
29 | + <!-- TODO: chagen to correct attributes after finishing the backend--> | |
30 | + <%= labelled_check_box _("Allow other users to follow me"), 'profile_data[can_be_followed]', true, profile.secret, :class => "person-can-be-followed" %> | |
31 | + </div> | |
32 | + <br> | |
33 | + <div> | |
29 | 34 | <%= labelled_radio_button _('Public — show my contents to all internet users').html_safe, 'profile_data[public_profile]', true, @profile.public_profile? %> |
30 | 35 | </div> |
31 | 36 | <div> | ... | ... |
app/views/profile_editor/index.html.erb
... | ... | @@ -72,6 +72,8 @@ |
72 | 72 | |
73 | 73 | <%= control_panel_button(_('Email Templates'), 'email-templates', :controller => :profile_email_templates) if profile.organization? %> |
74 | 74 | |
75 | + <%= control_panel_button(_('Manage followed people'), 'manage-followed-people', :controller => :followers) %> | |
76 | + | |
75 | 77 | <% @plugins.dispatch(:control_panel_buttons).each do |button| %> |
76 | 78 | <%= control_panel_button(button[:title], button[:icon], button[:url], button[:html_options]) %> |
77 | 79 | <% end %> | ... | ... |
public/javascripts/application.js
public/stylesheets/blocks/profile-info.scss
... | ... | @@ -99,3 +99,16 @@ |
99 | 99 | margin: 0px 0px 5px 0px; |
100 | 100 | padding: 2px; |
101 | 101 | } |
102 | +#follower-container:hover { | |
103 | + background-color: #eee; | |
104 | + -o-transition:.5s; | |
105 | + -ms-transition:.5s; | |
106 | + -moz-transition:.5s; | |
107 | + -webkit-transition:.5s; | |
108 | + transition:.5s; | |
109 | + padding-top: 5px; | |
110 | + padding-bottom: 5px; | |
111 | +} | |
112 | +#follower-container #category-form { | |
113 | + margin-bottom: 5px; | |
114 | +} | ... | ... |
public/stylesheets/profile-list.scss
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 | } |
24 | 24 | .controller-favorite_enterprises .profile-list a.profile-link, |
25 | 25 | .controller-friends .profile-list a.profile-link, |
26 | +.controller-followers .profile-list a.profile-link, | |
26 | 27 | .list-profile-connections .profile-list a.profile-link, |
27 | 28 | .profiles-suggestions .profile-list a.profile-link { |
28 | 29 | text-decoration: none; |
... | ... | @@ -32,11 +33,13 @@ |
32 | 33 | } |
33 | 34 | .controller-favorite_enterprises .profile-list a.profile-link:hover, |
34 | 35 | .controller-friends .profile-list a.profile-link:hover, |
36 | +.controller-followers .profile-list a.profile-link:hover, | |
35 | 37 | .profiles-suggestions .profile-list a.profile-link:hover { |
36 | 38 | color: #FFF; |
37 | 39 | } |
38 | 40 | .controller-favorite_enterprises .profile-list .profile_link span, |
39 | 41 | .controller-friends .profile-list .profile_link span, |
42 | +.controller-followers .profile-list .profile_link span, | |
40 | 43 | .box-1 .profiles-suggestions .profile-list .profile_link span { |
41 | 44 | width: 80px; |
42 | 45 | display: block; |
... | ... | @@ -44,12 +47,14 @@ |
44 | 47 | } |
45 | 48 | .controller-favorite_enterprises .profile-list, |
46 | 49 | .controller-friends .profile-list, |
50 | +.controller-followers .profile-list, | |
47 | 51 | .profiles-suggestions .profile-list { |
48 | 52 | position: relative; |
49 | 53 | } |
50 | 54 | |
51 | 55 | .controller-favorite_enterprises .profile-list .controll, |
52 | 56 | .controller-friends .profile-list .controll, |
57 | +.controller-followers .profile-list .controll, | |
53 | 58 | .profiles-suggestions .profile-list .controll { |
54 | 59 | position: absolute; |
55 | 60 | top: 7px; |
... | ... | @@ -57,17 +62,20 @@ |
57 | 62 | } |
58 | 63 | .controller-favorite_enterprises .profile-list .controll a, |
59 | 64 | .controller-friends .profile-list .controll a, |
65 | +.controller-followers .profile-list .controll a, | |
60 | 66 | .profiles-suggestions .profile-list .controll a { |
61 | 67 | display: block; |
62 | 68 | margin-bottom: 2px; |
63 | 69 | } |
64 | 70 | .controller-favorite_enterprises .msie6 .profile-list .controll a, |
65 | 71 | .controller-friends .msie6 .profile-list .controll a, |
72 | +.controller-folloed_people .msie6 .profile-list .controll a, | |
66 | 73 | .profiles-suggestions .msie6 .profile-list .controll a { |
67 | 74 | width: 0px; |
68 | 75 | } |
69 | 76 | .controller-favorite_enterprises .button-bar, |
70 | 77 | .controller-friends .button-bar, |
78 | +.controller-followers .button-bar, | |
71 | 79 | .profiles-suggestions .button-bar { |
72 | 80 | clear: both; |
73 | 81 | padding-top: 20px; |
... | ... | @@ -208,22 +216,35 @@ |
208 | 216 | font-size: 12px; |
209 | 217 | } |
210 | 218 | .action-profile-members .profile_link{ |
211 | - position: relative; | |
219 | + position: relative; | |
212 | 220 | } |
213 | 221 | .action-profile-members .profile_link span.new-profile:last-child{ |
214 | - position: absolute; | |
215 | - top: 3px; | |
216 | - right: 2px; | |
217 | - text-transform: uppercase; | |
218 | - color: #FFF; | |
219 | - font-size: 9px; | |
220 | - background: #66CC33; | |
221 | - padding: 2px; | |
222 | - display: block; | |
223 | - width: 35px; | |
224 | - font-weight: 700; | |
222 | + position: absolute; | |
223 | + top: 3px; | |
224 | + right: 2px; | |
225 | + text-transform: uppercase; | |
226 | + color: #FFF; | |
227 | + font-size: 9px; | |
228 | + background: #66CC33; | |
229 | + padding: 2px; | |
230 | + display: block; | |
231 | + width: 35px; | |
232 | + font-weight: 700; | |
225 | 233 | } |
226 | 234 | .action-profile-members .profile_link .fn{ |
227 | - font-style: normal; | |
228 | - color: #000; | |
235 | + font-style: normal; | |
236 | + color: #000; | |
237 | +} | |
238 | +.category-name { | |
239 | + margin-top: 0px; | |
240 | + margin-bottom: 0px; | |
241 | + font-style: italic; | |
242 | + color: #888a85; | |
243 | + text-align: center; | |
244 | +} | |
245 | +.set-category-modal { | |
246 | + width: 250px; | |
247 | +} | |
248 | +.set-category-modal #actions-container { | |
249 | + margin-top: 20px | |
229 | 250 | } | ... | ... |
... | ... | @@ -0,0 +1,48 @@ |
1 | +require_relative "../test_helper" | |
2 | +require 'followers_controller' | |
3 | + | |
4 | +class FollowersControllerTest < ActionController::TestCase | |
5 | + def setup | |
6 | + @profile = create_user('testuser').person | |
7 | + end | |
8 | + | |
9 | + should 'return followed people list' do | |
10 | + login_as(@profile.identifier) | |
11 | + person = fast_create(Person) | |
12 | + fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id) | |
13 | + | |
14 | + get :index, :profile => @profile.identifier | |
15 | + assert_includes assigns(:followed_people), person | |
16 | + end | |
17 | + | |
18 | + should 'redirect to login page if not logged in' do | |
19 | + person = fast_create(Person) | |
20 | + get :index, :profile => @profile.identifier | |
21 | + assert_redirected_to :controller => 'account', :action => 'login' | |
22 | + end | |
23 | + | |
24 | + should 'render set category modal' do | |
25 | + login_as(@profile.identifier) | |
26 | + get :set_category, :profile => @profile.identifier, :followed_profile_id => 3 | |
27 | + assert_tag :tag => "input", :attributes => { :id => "followed_profile_id", :value => 3 } | |
28 | + end | |
29 | + | |
30 | + should 'update followed person category' do | |
31 | + login_as(@profile.identifier) | |
32 | + person = fast_create(Person) | |
33 | + fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id) | |
34 | + | |
35 | + post :set_category, :profile => @profile.identifier, :category_name => "category test", :followed_profile_id => person.id | |
36 | + follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id) | |
37 | + assert_equal follower.group, "category test" | |
38 | + end | |
39 | + | |
40 | + should 'not update category of not followed person' do | |
41 | + login_as(@profile.identifier) | |
42 | + person = fast_create(Person) | |
43 | + | |
44 | + post :set_category, :profile => @profile.identifier, :category_name => "category test", :followed_profile_id => person.id | |
45 | + follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id) | |
46 | + ProfileFollower.any_instance.expects(:update_attributes).times(0) | |
47 | + end | |
48 | +end | ... | ... |
test/functional/profile_controller_test.rb
... | ... | @@ -1932,4 +1932,76 @@ class ProfileControllerTest < ActionController::TestCase |
1932 | 1932 | assert_redirected_to :controller => 'account', :action => 'login' |
1933 | 1933 | end |
1934 | 1934 | |
1935 | + should 'follow a user without defining a group' do | |
1936 | + login_as(@profile.identifier) | |
1937 | + person = fast_create(Person) | |
1938 | + get :follow, :profile => person.identifier | |
1939 | + | |
1940 | + follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id) | |
1941 | + assert_not_nil follower | |
1942 | + end | |
1943 | + | |
1944 | + should "not follow user if not logged" do | |
1945 | + person = fast_create(Person) | |
1946 | + get :follow, :profile => person.identifier | |
1947 | + | |
1948 | + assert_redirected_to :controller => 'account', :action => 'login' | |
1949 | + end | |
1950 | + | |
1951 | + should 'follow a user with a group' do | |
1952 | + login_as(@profile.identifier) | |
1953 | + person = fast_create(Person) | |
1954 | + get :follow, :profile => person.identifier, :follow => { :category => "A Group" } | |
1955 | + | |
1956 | + follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id) | |
1957 | + assert_not_nil follower | |
1958 | + assert_equal "A Group", follower.group | |
1959 | + end | |
1960 | + | |
1961 | + should 'not follow if current_person already follows the person' do | |
1962 | + login_as(@profile.identifier) | |
1963 | + person = fast_create(Person) | |
1964 | + fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id) | |
1965 | + | |
1966 | + assert_no_difference 'ProfileFollower.count' do | |
1967 | + get :follow, :profile => person.identifier, :follow => { :category => "A Group" } | |
1968 | + end | |
1969 | + end | |
1970 | + | |
1971 | + should "not unfollow user if not logged" do | |
1972 | + person = fast_create(Person) | |
1973 | + get :unfollow, :profile => person.identifier | |
1974 | + | |
1975 | + assert_redirected_to :controller => 'account', :action => 'login' | |
1976 | + end | |
1977 | + | |
1978 | + should "unfollow a followed person" do | |
1979 | + login_as(@profile.identifier) | |
1980 | + person = fast_create(Person) | |
1981 | + follower = fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id) | |
1982 | + assert_not_nil follower | |
1983 | + | |
1984 | + get :unfollow, :profile => person.identifier | |
1985 | + follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id) | |
1986 | + assert_nil follower | |
1987 | + end | |
1988 | + | |
1989 | + should "not unfollow a not followed person" do | |
1990 | + login_as(@profile.identifier) | |
1991 | + person = fast_create(Person) | |
1992 | + | |
1993 | + assert_no_difference 'ProfileFollower.count' do | |
1994 | + get :unfollow, :profile => person.identifier | |
1995 | + end | |
1996 | + end | |
1997 | + | |
1998 | + should "redirect to page after unfollow" do | |
1999 | + login_as(@profile.identifier) | |
2000 | + person = fast_create(Person) | |
2001 | + fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id) | |
2002 | + | |
2003 | + get :unfollow, :profile => person.identifier, :redirect_to => "/some/url" | |
2004 | + assert_redirected_to "/some/url" | |
2005 | + end | |
2006 | + | |
1935 | 2007 | end | ... | ... |