diff --git a/app/controllers/my_profile/followers_controller.rb b/app/controllers/my_profile/followers_controller.rb
new file mode 100644
index 0000000..1be40ae
--- /dev/null
+++ b/app/controllers/my_profile/followers_controller.rb
@@ -0,0 +1,16 @@
+class FollowersController < MyProfileController
+
+ def index
+ @followed_people = current_person.following_profiles.paginate(:per_page => 5, :page => params[:npage])
+ end
+
+ def set_category
+ if request.method == "GET"
+ render :partial => "set_category_modal", :locals => { :followed_profile_id => params[:followed_profile_id] }
+ elsif request.method == "POST"
+ follower = ProfileFollower.find_by(follower_id: current_person.id, profile_id: params[:followed_profile_id])
+ follower.update_attributes(:group => params[:category_name]) if follower
+ redirect_to url_for(:controller => "followers", :action => "index")
+ end
+ end
+end
diff --git a/app/controllers/public/profile_controller.rb b/app/controllers/public/profile_controller.rb
index cccc352..50e8a1c 100644
--- a/app/controllers/public/profile_controller.rb
+++ b/app/controllers/public/profile_controller.rb
@@ -3,7 +3,7 @@ class ProfileController < PublicController
needs_profile
before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add]
before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail]
- 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]
+ 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]
helper TagsHelper
helper ActionTrackerHelper
@@ -65,6 +65,10 @@ class ProfileController < PublicController
end
end
+ def following
+ @followed_people = [].paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.friends.count)
+ end
+
def members
if is_cache_expired?(profile.members_cache_key(params))
sort = (params[:sort] == 'desc') ? params[:sort] : 'asc'
@@ -151,6 +155,22 @@ class ProfileController < PublicController
end
end
+ def follow
+ if !current_person.follows?(profile)
+ group = params['follow'] ? params['follow']['category'] : ''
+ current_person.follow(profile, group)
+ end
+ redirect_to profile.url
+ end
+
+ def unfollow
+ if current_person.follows?(profile)
+ current_person.unfollow(profile)
+ end
+ redirect_url = params["redirect_to"] ? params["redirect_to"] : profile.url
+ redirect_to redirect_url
+ end
+
def check_friendship
unless logged_in?
render :text => ''
diff --git a/app/models/person.rb b/app/models/person.rb
index 8a6d98e..255bc7b 100644
--- a/app/models/person.rb
+++ b/app/models/person.rb
@@ -200,7 +200,7 @@ class Person < Profile
end
end
- def follow(profile, group = nil)
+ def follow(profile, group = "")
unless self.following_profiles.include?(profile)
profile_follower = ProfileFollower.new
profile_follower.profile = profile
@@ -601,7 +601,7 @@ class Person < Profile
protected
def followed_by?(profile)
- self == profile || self.is_a_friend?(profile) || self.followers.include(profile)
+ self == profile || self.followers.include?(profile)
end
end
diff --git a/app/models/profile.rb b/app/models/profile.rb
index 499291c..2e11755 100644
--- a/app/models/profile.rb
+++ b/app/models/profile.rb
@@ -204,7 +204,7 @@ class Profile < ApplicationRecord
scope :more_recent, -> { order "created_at DESC" }
scope :following_profiles, -> person {
- distinct.select('profiles.*').
+ distinct.select('profiles.*, profile_followers.group').
joins('join profile_followers ON profile_followers.profile_id = profiles.id').
where('profile_followers.follower_id = ?', person.id)
}
diff --git a/app/models/profile_follower.rb b/app/models/profile_follower.rb
index d389bdd..c91e769 100644
--- a/app/models/profile_follower.rb
+++ b/app/models/profile_follower.rb
@@ -1,5 +1,6 @@
class ProfileFollower < ApplicationRecord
track_actions :new_follower, :after_create, :keep_params => ["follower.name", "follower.url", "follower.profile_custom_icon"], :custom_user => :profile
+ attr_accessible :group
belongs_to :profile, :foreign_key => :profile_id
belongs_to :follower, :class_name => 'Person', :foreign_key => :follower_id
diff --git a/app/views/blocks/profile_info_actions/_person.html.erb b/app/views/blocks/profile_info_actions/_person.html.erb
index c655b4e..b523369 100644
--- a/app/views/blocks/profile_info_actions/_person.html.erb
+++ b/app/views/blocks/profile_info_actions/_person.html.erb
@@ -7,6 +7,20 @@
<% end %>
+
+ <% if user.follows?(profile) %>
+ <%= button(:unfollow, content_tag('span', _('Unfollow')), {:profile => profile.identifier, :controller => 'profile', :action => 'unfollow'}) %>
+ <% else %>
+
+ <% end %>
+
+
+
<% if user.is_a_friend?(profile) && profile.enable_contact? %>
<%= button(:back, _('Send an e-mail'), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}) %>
<% end %>
diff --git a/app/views/followers/_profile_list.html.erb b/app/views/followers/_profile_list.html.erb
new file mode 100644
index 0000000..5143323
--- /dev/null
+++ b/app/views/followers/_profile_list.html.erb
@@ -0,0 +1,18 @@
+
+ <% profiles.each do |profile| %>
+ -
+ <%= link_to_profile profile_image(profile) + tag('br') + profile.short_name,
+ profile.identifier, :class => 'profile-link' %>
+
+ <%= profile.group %>
+
+
+ <%= button_without_text :remove, content_tag('span',_('unfollow')),
+ { :controller => "profile", :profile => profile.identifier , :action => 'unfollow', :redirect_to => url_for({:controller => "followers", :profile => user.identifier}) },
+ :title => _('remove') %>
+ <%= modal_icon_button :change_categoy, content_tag('span',_('change category')),
+ url_for(:controller => 'followers', :action => 'set_category', :followed_profile_id => profile.id) %>
+
+
+ <% end %>
+
diff --git a/app/views/followers/_set_category_modal.html.erb b/app/views/followers/_set_category_modal.html.erb
new file mode 100644
index 0000000..b63507f
--- /dev/null
+++ b/app/views/followers/_set_category_modal.html.erb
@@ -0,0 +1,13 @@
+
+
<%= _("Choose a new category") %>
+ <%= form_for :follower_category, :url => url_for(:controller => 'followers', :action => 'set_category') do |f| %>
+
+ <%= labelled_text_field _("Category: "), "category_name" %>
+
+ <%= hidden_field_tag 'followed_profile_id', followed_profile_id %>
+
+ <%= submit_button('save', _('Save')) %>
+ <%= modal_close_button _("Cancel") %>
+
+ <% end %>
+
diff --git a/app/views/followers/index.html.erb b/app/views/followers/index.html.erb
new file mode 100644
index 0000000..c496b67
--- /dev/null
+++ b/app/views/followers/index.html.erb
@@ -0,0 +1,25 @@
+
+
+
<%= _("%s following") % profile.name %>
+
+<% cache_timeout(profile.manage_friends_cache_key(params), 4.hours) do %>
+ <% if @followed_people.empty? %>
+
+
+ <%= _("You don't follow anybody yet.") %>
+
+
+ <% end %>
+
+ <%= button_bar do %>
+ <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
+ <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %>
+ <% end %>
+
+ <%= render :partial => 'profile_list', :locals => { :profiles => @followed_people } %>
+
+
+ <%= pagination_links @followed_people, :param_name => 'npage' %>
+<% end %>
+
+
diff --git a/app/views/profile/following.html.erb b/app/views/profile/following.html.erb
new file mode 100644
index 0000000..3492e78
--- /dev/null
+++ b/app/views/profile/following.html.erb
@@ -0,0 +1,24 @@
+
+
+
<%= _("%s is following") % profile.name %>
+
+<% cache_timeout(profile.friends_cache_key(params), 4.hours) do %>
+
+ <% @followed_people.each do |followed_person| %>
+ <%= profile_image_link(followed_person) %>
+ <% end%>
+
+
+
+<% end %>
+
+<%= button_bar do %>
+ <%= button :back, _('Go back'), { :controller => 'profile' } %>
+ <% if user == profile %>
+ <%= button :edit, _('Manage followed people'), :controller => 'friends', :action => 'index', :profile => profile.identifier %>
+ <% end %>
+<% end %>
+
+
diff --git a/app/views/profile_editor/edit.html.erb b/app/views/profile_editor/edit.html.erb
index 2bc3c45..f6e4d0e 100644
--- a/app/views/profile_editor/edit.html.erb
+++ b/app/views/profile_editor/edit.html.erb
@@ -26,6 +26,11 @@
<% if profile.person? %>
+
+ <%= labelled_check_box _("Allow other users to follow me"), 'profile_data[can_be_followed]', true, profile.secret, :class => "person-can-be-followed" %>
+
+
+
<%= labelled_radio_button _('Public — show my contents to all internet users').html_safe, 'profile_data[public_profile]', true, @profile.public_profile? %>
diff --git a/app/views/profile_editor/index.html.erb b/app/views/profile_editor/index.html.erb
index 9c99687..4874b04 100644
--- a/app/views/profile_editor/index.html.erb
+++ b/app/views/profile_editor/index.html.erb
@@ -72,6 +72,8 @@
<%= control_panel_button(_('Email Templates'), 'email-templates', :controller => :profile_email_templates) if profile.organization? %>
+ <%= control_panel_button(_('Manage followed people'), 'manage-followed-people', :controller => :followers) %>
+
<% @plugins.dispatch(:control_panel_buttons).each do |button| %>
<%= control_panel_button(button[:title], button[:icon], button[:url], button[:html_options]) %>
<% end %>
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index fff7e9b..25d00c6 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -26,6 +26,7 @@
*= require pagination.js
* views speficics
*= require add-and-join.js
+*= require followers.js
*= require report-abuse.js
*= require autogrow.js
*= require require_login.js
diff --git a/public/javascripts/followers.js b/public/javascripts/followers.js
new file mode 100644
index 0000000..d7fcece
--- /dev/null
+++ b/public/javascripts/followers.js
@@ -0,0 +1,5 @@
+$("#follower-container").live("mouseenter", function() {
+ $("#category-form").fadeIn();
+}).live("mouseleave", function() {
+ $("#category-form").fadeOut();
+});
diff --git a/public/stylesheets/blocks/profile-info.scss b/public/stylesheets/blocks/profile-info.scss
index 80fd7f0..b1d8611 100644
--- a/public/stylesheets/blocks/profile-info.scss
+++ b/public/stylesheets/blocks/profile-info.scss
@@ -99,3 +99,16 @@
margin: 0px 0px 5px 0px;
padding: 2px;
}
+#follower-container:hover {
+ background-color: #eee;
+ -o-transition:.5s;
+ -ms-transition:.5s;
+ -moz-transition:.5s;
+ -webkit-transition:.5s;
+ transition:.5s;
+ padding-top: 5px;
+ padding-bottom: 5px;
+}
+#follower-container #category-form {
+ margin-bottom: 5px;
+}
diff --git a/public/stylesheets/profile-list.scss b/public/stylesheets/profile-list.scss
index cbd9bc1..3458bb9 100644
--- a/public/stylesheets/profile-list.scss
+++ b/public/stylesheets/profile-list.scss
@@ -23,6 +23,7 @@
}
.controller-favorite_enterprises .profile-list a.profile-link,
.controller-friends .profile-list a.profile-link,
+.controller-followers .profile-list a.profile-link,
.list-profile-connections .profile-list a.profile-link,
.profiles-suggestions .profile-list a.profile-link {
text-decoration: none;
@@ -32,11 +33,13 @@
}
.controller-favorite_enterprises .profile-list a.profile-link:hover,
.controller-friends .profile-list a.profile-link:hover,
+.controller-followers .profile-list a.profile-link:hover,
.profiles-suggestions .profile-list a.profile-link:hover {
color: #FFF;
}
.controller-favorite_enterprises .profile-list .profile_link span,
.controller-friends .profile-list .profile_link span,
+.controller-followers .profile-list .profile_link span,
.box-1 .profiles-suggestions .profile-list .profile_link span {
width: 80px;
display: block;
@@ -44,12 +47,14 @@
}
.controller-favorite_enterprises .profile-list,
.controller-friends .profile-list,
+.controller-followers .profile-list,
.profiles-suggestions .profile-list {
position: relative;
}
.controller-favorite_enterprises .profile-list .controll,
.controller-friends .profile-list .controll,
+.controller-followers .profile-list .controll,
.profiles-suggestions .profile-list .controll {
position: absolute;
top: 7px;
@@ -57,17 +62,20 @@
}
.controller-favorite_enterprises .profile-list .controll a,
.controller-friends .profile-list .controll a,
+.controller-followers .profile-list .controll a,
.profiles-suggestions .profile-list .controll a {
display: block;
margin-bottom: 2px;
}
.controller-favorite_enterprises .msie6 .profile-list .controll a,
.controller-friends .msie6 .profile-list .controll a,
+.controller-folloed_people .msie6 .profile-list .controll a,
.profiles-suggestions .msie6 .profile-list .controll a {
width: 0px;
}
.controller-favorite_enterprises .button-bar,
.controller-friends .button-bar,
+.controller-followers .button-bar,
.profiles-suggestions .button-bar {
clear: both;
padding-top: 20px;
@@ -208,22 +216,35 @@
font-size: 12px;
}
.action-profile-members .profile_link{
- position: relative;
+ position: relative;
}
.action-profile-members .profile_link span.new-profile:last-child{
- position: absolute;
- top: 3px;
- right: 2px;
- text-transform: uppercase;
- color: #FFF;
- font-size: 9px;
- background: #66CC33;
- padding: 2px;
- display: block;
- width: 35px;
- font-weight: 700;
+ position: absolute;
+ top: 3px;
+ right: 2px;
+ text-transform: uppercase;
+ color: #FFF;
+ font-size: 9px;
+ background: #66CC33;
+ padding: 2px;
+ display: block;
+ width: 35px;
+ font-weight: 700;
}
.action-profile-members .profile_link .fn{
- font-style: normal;
- color: #000;
+ font-style: normal;
+ color: #000;
+}
+.category-name {
+ margin-top: 0px;
+ margin-bottom: 0px;
+ font-style: italic;
+ color: #888a85;
+ text-align: center;
+}
+.set-category-modal {
+ width: 250px;
+}
+.set-category-modal #actions-container {
+ margin-top: 20px
}
diff --git a/test/functional/followers_controller_test.rb b/test/functional/followers_controller_test.rb
new file mode 100644
index 0000000..30f9076
--- /dev/null
+++ b/test/functional/followers_controller_test.rb
@@ -0,0 +1,48 @@
+require_relative "../test_helper"
+require 'followers_controller'
+
+class FollowersControllerTest < ActionController::TestCase
+ def setup
+ @profile = create_user('testuser').person
+ end
+
+ should 'return followed people list' do
+ login_as(@profile.identifier)
+ person = fast_create(Person)
+ fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id)
+
+ get :index, :profile => @profile.identifier
+ assert_includes assigns(:followed_people), person
+ end
+
+ should 'redirect to login page if not logged in' do
+ person = fast_create(Person)
+ get :index, :profile => @profile.identifier
+ assert_redirected_to :controller => 'account', :action => 'login'
+ end
+
+ should 'render set category modal' do
+ login_as(@profile.identifier)
+ get :set_category, :profile => @profile.identifier, :followed_profile_id => 3
+ assert_tag :tag => "input", :attributes => { :id => "followed_profile_id", :value => 3 }
+ end
+
+ should 'update followed person category' do
+ login_as(@profile.identifier)
+ person = fast_create(Person)
+ fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id)
+
+ post :set_category, :profile => @profile.identifier, :category_name => "category test", :followed_profile_id => person.id
+ follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id)
+ assert_equal follower.group, "category test"
+ end
+
+ should 'not update category of not followed person' do
+ login_as(@profile.identifier)
+ person = fast_create(Person)
+
+ post :set_category, :profile => @profile.identifier, :category_name => "category test", :followed_profile_id => person.id
+ follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id)
+ ProfileFollower.any_instance.expects(:update_attributes).times(0)
+ end
+end
diff --git a/test/functional/profile_controller_test.rb b/test/functional/profile_controller_test.rb
index 57da6e0..6d78980 100644
--- a/test/functional/profile_controller_test.rb
+++ b/test/functional/profile_controller_test.rb
@@ -1932,4 +1932,76 @@ class ProfileControllerTest < ActionController::TestCase
assert_redirected_to :controller => 'account', :action => 'login'
end
+ should 'follow a user without defining a group' do
+ login_as(@profile.identifier)
+ person = fast_create(Person)
+ get :follow, :profile => person.identifier
+
+ follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id)
+ assert_not_nil follower
+ end
+
+ should "not follow user if not logged" do
+ person = fast_create(Person)
+ get :follow, :profile => person.identifier
+
+ assert_redirected_to :controller => 'account', :action => 'login'
+ end
+
+ should 'follow a user with a group' do
+ login_as(@profile.identifier)
+ person = fast_create(Person)
+ get :follow, :profile => person.identifier, :follow => { :category => "A Group" }
+
+ follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id)
+ assert_not_nil follower
+ assert_equal "A Group", follower.group
+ end
+
+ should 'not follow if current_person already follows the person' do
+ login_as(@profile.identifier)
+ person = fast_create(Person)
+ fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id)
+
+ assert_no_difference 'ProfileFollower.count' do
+ get :follow, :profile => person.identifier, :follow => { :category => "A Group" }
+ end
+ end
+
+ should "not unfollow user if not logged" do
+ person = fast_create(Person)
+ get :unfollow, :profile => person.identifier
+
+ assert_redirected_to :controller => 'account', :action => 'login'
+ end
+
+ should "unfollow a followed person" do
+ login_as(@profile.identifier)
+ person = fast_create(Person)
+ follower = fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id)
+ assert_not_nil follower
+
+ get :unfollow, :profile => person.identifier
+ follower = ProfileFollower.find_by(:profile_id => person.id, :follower_id => @profile.id)
+ assert_nil follower
+ end
+
+ should "not unfollow a not followed person" do
+ login_as(@profile.identifier)
+ person = fast_create(Person)
+
+ assert_no_difference 'ProfileFollower.count' do
+ get :unfollow, :profile => person.identifier
+ end
+ end
+
+ should "redirect to page after unfollow" do
+ login_as(@profile.identifier)
+ person = fast_create(Person)
+ fast_create(ProfileFollower, :profile_id => person.id, :follower_id => @profile.id)
+
+ get :unfollow, :profile => person.identifier, :redirect_to => "/some/url"
+ assert_redirected_to "/some/url"
+ end
+
end
--
libgit2 0.21.2