Commit 8b945809d1d522c39798b10d96ecca9eccd13328
Committed by
Larissa Reis
1 parent
fceeac68
Exists in
profile_api_improvements
and in
1 other branch
Profile followers feature
Signed-off-by: Alessandro Caetano <alessandro.caetanob@gmail.com> Signed-off-by: Artur Bersan de Faria <arturbersan@gmail.com> Signed-off-by: Gabriel Silva <gabriel93.silva@gmail.com> Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com> Signed-off-by: Matheus Miranda <matheusmirandalacerda@gmail.com> Signed-off-by: Sabryna Sousa <sabryna.sousa1323@gmail.com> Signed-off-by: Victor Matias Navarro <victor.matias.navarro@gmail.com> Signed-off-by: Vitor Barbosa <vitormga15@gmail.com>
Showing
58 changed files
with
1448 additions
and
92 deletions
Show diff stats
app/controllers/application_controller.rb
@@ -115,6 +115,10 @@ class ApplicationController < ActionController::Base | @@ -115,6 +115,10 @@ class ApplicationController < ActionController::Base | ||
115 | 115 | ||
116 | protected | 116 | protected |
117 | 117 | ||
118 | + def accept_only_post | ||
119 | + return render_not_found if !request.post? | ||
120 | + end | ||
121 | + | ||
118 | def verified_request? | 122 | def verified_request? |
119 | super || form_authenticity_token == request.headers['X-XSRF-TOKEN'] | 123 | super || form_authenticity_token == request.headers['X-XSRF-TOKEN'] |
120 | end | 124 | end |
@@ -0,0 +1,58 @@ | @@ -0,0 +1,58 @@ | ||
1 | +class CirclesController < MyProfileController | ||
2 | + | ||
3 | + before_action :accept_only_post, :only => [:create, :update, :destroy] | ||
4 | + | ||
5 | + def index | ||
6 | + @circles = current_person.circles | ||
7 | + end | ||
8 | + | ||
9 | + def new | ||
10 | + @circle = Circle.new | ||
11 | + end | ||
12 | + | ||
13 | + def create | ||
14 | + @circle = Circle.new(params[:circle].merge({ :person => current_person })) | ||
15 | + if @circle.save | ||
16 | + redirect_to :action => 'index' | ||
17 | + else | ||
18 | + render :action => 'new' | ||
19 | + end | ||
20 | + end | ||
21 | + | ||
22 | + def xhr_create | ||
23 | + if request.xhr? | ||
24 | + circle = Circle.new(params[:circle].merge({:person => current_person })) | ||
25 | + if circle.save | ||
26 | + render :partial => "circle_checkbox", :locals => { :circle => circle }, | ||
27 | + :status => 201 | ||
28 | + else | ||
29 | + render :text => _('The circle could not be saved'), :status => 400 | ||
30 | + end | ||
31 | + else | ||
32 | + render_not_found | ||
33 | + end | ||
34 | + end | ||
35 | + | ||
36 | + def edit | ||
37 | + @circle = Circle.find_by_id(params[:id]) | ||
38 | + render_not_found if @circle.nil? | ||
39 | + end | ||
40 | + | ||
41 | + def update | ||
42 | + @circle = Circle.find_by_id(params[:id]) | ||
43 | + return render_not_found if @circle.nil? | ||
44 | + | ||
45 | + if @circle.update(params[:circle]) | ||
46 | + redirect_to :action => 'index' | ||
47 | + else | ||
48 | + render :action => 'edit' | ||
49 | + end | ||
50 | + end | ||
51 | + | ||
52 | + def destroy | ||
53 | + @circle = Circle.find_by_id(params[:id]) | ||
54 | + return render_not_found if @circle.nil? | ||
55 | + @circle.destroy | ||
56 | + redirect_to :action => 'index' | ||
57 | + end | ||
58 | +end |
@@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
1 | +class FollowersController < MyProfileController | ||
2 | + | ||
3 | + before_action :only_for_person, :only => :index | ||
4 | + before_action :accept_only_post, :only => [:update_category] | ||
5 | + | ||
6 | + def index | ||
7 | + @followed_people = current_person.followed_profiles.order(:type) | ||
8 | + @profile_types = {_('All profiles') => nil}.merge(Circle.profile_types).to_a | ||
9 | + | ||
10 | + if params['filter'].present? | ||
11 | + @followed_people = @followed_people.where(:type => params['filter']) | ||
12 | + @active_filter = params['filter'] | ||
13 | + end | ||
14 | + | ||
15 | + @followed_people = @followed_people.paginate(:per_page => 15, :page => params[:npage]) | ||
16 | + end | ||
17 | + | ||
18 | + def set_category_modal | ||
19 | + profile = Profile.find(params[:followed_profile_id]) | ||
20 | + circles = Circle.where(:person => current_person, :profile_type => profile.class.name) | ||
21 | + render :partial => 'followers/edit_circles_modal', :locals => { :circles => circles, :profile => profile } | ||
22 | + end | ||
23 | + | ||
24 | + def update_category | ||
25 | + followed_profile = Profile.find_by(:id => params["followed_profile_id"]) | ||
26 | + | ||
27 | + selected_circles = params[:circles].map{|circle_name, circle_id| Circle.find_by(:id => circle_id)}.select{|c|not c.nil?} | ||
28 | + | ||
29 | + if followed_profile | ||
30 | + current_person.update_profile_circles(followed_profile, selected_circles) | ||
31 | + render :text => _("Circles of %s updated successfully") % followed_profile.name, :status => 200 | ||
32 | + else | ||
33 | + render :text => _("Error: No profile to follow."), :status => 400 | ||
34 | + end | ||
35 | + end | ||
36 | + | ||
37 | + protected | ||
38 | + | ||
39 | + def only_for_person | ||
40 | + render_not_found unless profile.person? | ||
41 | + end | ||
42 | + | ||
43 | +end |
app/controllers/public/content_viewer_controller.rb
@@ -128,9 +128,9 @@ class ContentViewerController < ApplicationController | @@ -128,9 +128,9 @@ class ContentViewerController < ApplicationController | ||
128 | end | 128 | end |
129 | 129 | ||
130 | unless @page.display_to?(user) | 130 | unless @page.display_to?(user) |
131 | - if !profile.visible? || profile.secret? || (user && user.follows?(profile)) || user.blank? | 131 | + if !profile.visible? || profile.secret? || (user && profile.in_social_circle?(user)) || user.blank? |
132 | render_access_denied | 132 | render_access_denied |
133 | - else #!profile.public? | 133 | + else |
134 | private_profile_partial_parameters | 134 | private_profile_partial_parameters |
135 | render :template => 'profile/_private_profile', :status => 403, :formats => [:html] | 135 | render :template => 'profile/_private_profile', :status => 403, :formats => [:html] |
136 | end | 136 | end |
app/controllers/public/profile_controller.rb
@@ -3,7 +3,8 @@ class ProfileController < PublicController | @@ -3,7 +3,8 @@ class ProfileController < PublicController | ||
3 | needs_profile | 3 | needs_profile |
4 | before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add] | 4 | before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add] |
5 | before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail] | 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 | + before_filter :allow_followers?, :only => [:follow, :unfollow] | ||
7 | 8 | ||
8 | helper TagsHelper | 9 | helper TagsHelper |
9 | helper ActionTrackerHelper | 10 | helper ActionTrackerHelper |
@@ -65,6 +66,14 @@ class ProfileController < PublicController | @@ -65,6 +66,14 @@ class ProfileController < PublicController | ||
65 | end | 66 | end |
66 | end | 67 | end |
67 | 68 | ||
69 | + def following | ||
70 | + @followed_people = profile.followed_profiles.paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.followed_profiles.count) | ||
71 | + end | ||
72 | + | ||
73 | + def followed | ||
74 | + @followed_by = profile.followers.paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.followers.count) | ||
75 | + end | ||
76 | + | ||
68 | def members | 77 | def members |
69 | if is_cache_expired?(profile.members_cache_key(params)) | 78 | if is_cache_expired?(profile.members_cache_key(params)) |
70 | sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' | 79 | sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' |
@@ -151,6 +160,37 @@ class ProfileController < PublicController | @@ -151,6 +160,37 @@ class ProfileController < PublicController | ||
151 | end | 160 | end |
152 | end | 161 | end |
153 | 162 | ||
163 | + def follow | ||
164 | + if request.post? | ||
165 | + if profile.followed_by?(current_person) | ||
166 | + render :text => _("You are already following %s.") % profile.name, :status => 400 | ||
167 | + else | ||
168 | + selected_circles = params[:circles].map{|circle_name, circle_id| Circle.find_by(:id => circle_id)}.select{|c|not c.nil?} | ||
169 | + if selected_circles.present? | ||
170 | + current_person.follow(profile, selected_circles) | ||
171 | + render :text => _("You are now following %s") % profile.name, :status => 200 | ||
172 | + else | ||
173 | + render :text => _("Select at least one circle to follow %s.") % profile.name, :status => 400 | ||
174 | + end | ||
175 | + end | ||
176 | + else | ||
177 | + render_not_found | ||
178 | + end | ||
179 | + end | ||
180 | + | ||
181 | + def find_profile_circles | ||
182 | + circles = Circle.where(:person => current_person, :profile_type => profile.class.name) | ||
183 | + render :partial => 'blocks/profile_info_actions/circles', :locals => { :circles => circles, :profile_types => Circle.profile_types.to_a } | ||
184 | + end | ||
185 | + | ||
186 | + def unfollow | ||
187 | + if current_person.follows?(profile) | ||
188 | + current_person.unfollow(profile) | ||
189 | + end | ||
190 | + redirect_url = params["redirect_to"] ? params["redirect_to"] : profile.url | ||
191 | + redirect_to redirect_url | ||
192 | + end | ||
193 | + | ||
154 | def check_friendship | 194 | def check_friendship |
155 | unless logged_in? | 195 | unless logged_in? |
156 | render :text => '' | 196 | render :text => '' |
@@ -437,4 +477,8 @@ class ProfileController < PublicController | @@ -437,4 +477,8 @@ class ProfileController < PublicController | ||
437 | [:image, :domains, :preferred_domain, :environment] | 477 | [:image, :domains, :preferred_domain, :environment] |
438 | end | 478 | end |
439 | 479 | ||
480 | + def allow_followers? | ||
481 | + render_not_found unless profile.allow_followers? | ||
482 | + end | ||
483 | + | ||
440 | end | 484 | end |
app/helpers/action_tracker_helper.rb
@@ -14,13 +14,23 @@ module ActionTrackerHelper | @@ -14,13 +14,23 @@ module ActionTrackerHelper | ||
14 | } | 14 | } |
15 | end | 15 | end |
16 | 16 | ||
17 | + def new_follower_description ta | ||
18 | + n_('has 1 new follower:<br />%{name}', 'has %{num} new followers:<br />%{name}', ta.get_follower_name.size).html_safe % { | ||
19 | + num: ta.get_follower_name.size, | ||
20 | + name: safe_join(ta.collect_group_with_index(:follower_name) do |n,i| | ||
21 | + link_to image_tag(ta.get_follower_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/person-icon.png")), | ||
22 | + ta.get_follower_url[i], title: n | ||
23 | + end) | ||
24 | + } | ||
25 | + end | ||
26 | + | ||
17 | def join_community_description ta | 27 | def join_community_description ta |
18 | n_('has joined 1 community:<br />%{name}', 'has joined %{num} communities:<br />%{name}', ta.get_resource_name.size).html_safe % { | 28 | n_('has joined 1 community:<br />%{name}', 'has joined %{num} communities:<br />%{name}', ta.get_resource_name.size).html_safe % { |
19 | num: ta.get_resource_name.size, | 29 | num: ta.get_resource_name.size, |
20 | - name: ta.collect_group_with_index(:resource_name) do |n,i| | 30 | + name: safe_join(ta.collect_group_with_index(:resource_name) do |n,i| |
21 | link = link_to image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")), | 31 | link = link_to image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")), |
22 | ta.get_resource_url[i], title: n | 32 | ta.get_resource_url[i], title: n |
23 | - end.join.html_safe | 33 | + end) |
24 | } | 34 | } |
25 | end | 35 | end |
26 | 36 | ||
@@ -68,9 +78,9 @@ module ActionTrackerHelper | @@ -68,9 +78,9 @@ module ActionTrackerHelper | ||
68 | end | 78 | end |
69 | 79 | ||
70 | def favorite_enterprise_description ta | 80 | def favorite_enterprise_description ta |
71 | - _('favorited enterprise %{title}') % { | 81 | + (_('favorited enterprise %{title}') % { |
72 | title: link_to(truncate(ta.get_enterprise_name), ta.get_enterprise_url), | 82 | title: link_to(truncate(ta.get_enterprise_name), ta.get_enterprise_url), |
73 | - } | 83 | + }).html_safe |
74 | end | 84 | end |
75 | 85 | ||
76 | end | 86 | end |
app/helpers/profile_helper.rb
@@ -11,7 +11,7 @@ module ProfileHelper | @@ -11,7 +11,7 @@ module ProfileHelper | ||
11 | PERSON_CATEGORIES[:location] = [:address, :address_reference, :zip_code, :city, :state, :district, :country, :nationality] | 11 | PERSON_CATEGORIES[:location] = [:address, :address_reference, :zip_code, :city, :state, :district, :country, :nationality] |
12 | PERSON_CATEGORIES[:work] = [:organization, :organization_website, :professional_activity] | 12 | PERSON_CATEGORIES[:work] = [:organization, :organization_website, :professional_activity] |
13 | PERSON_CATEGORIES[:study] = [:schooling, :formation, :area_of_study] | 13 | PERSON_CATEGORIES[:study] = [:schooling, :formation, :area_of_study] |
14 | - PERSON_CATEGORIES[:network] = [:friends, :communities, :enterprises] | 14 | + PERSON_CATEGORIES[:network] = [:friends, :followers, :followed_profiles, :communities, :enterprises] |
15 | PERSON_CATEGORIES.merge!(COMMON_CATEGORIES) | 15 | PERSON_CATEGORIES.merge!(COMMON_CATEGORIES) |
16 | 16 | ||
17 | ORGANIZATION_CATEGORIES = {} | 17 | ORGANIZATION_CATEGORIES = {} |
@@ -42,7 +42,8 @@ module ProfileHelper | @@ -42,7 +42,8 @@ module ProfileHelper | ||
42 | :created_at => _('Profile created at'), | 42 | :created_at => _('Profile created at'), |
43 | :members_count => _('Members'), | 43 | :members_count => _('Members'), |
44 | :privacy_setting => _('Privacy setting'), | 44 | :privacy_setting => _('Privacy setting'), |
45 | - :article_tags => _('Tags') | 45 | + :article_tags => _('Tags'), |
46 | + :followed_profiles => _('Following') | ||
46 | } | 47 | } |
47 | 48 | ||
48 | EXCEPTION = { | 49 | EXCEPTION = { |
@@ -144,6 +145,14 @@ module ProfileHelper | @@ -144,6 +145,14 @@ module ProfileHelper | ||
144 | link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url) | 145 | link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url) |
145 | end | 146 | end |
146 | 147 | ||
148 | + def treat_followers(followers) | ||
149 | + link_to(profile.followers.count, {:action=>"followed", :controller=>"profile", :profile=>"#{profile.identifier}"}) | ||
150 | + end | ||
151 | + | ||
152 | + def treat_followed_profiles(followed_profiles) | ||
153 | + link_to(profile.followed_profiles.count, {:action=>"following", :controller=>"profile", :profile=>"#{profile.identifier}"}) | ||
154 | + end | ||
155 | + | ||
147 | def treat_events(events) | 156 | def treat_events(events) |
148 | link_to events.published.count, :controller => 'events', :action => 'events' | 157 | link_to events.published.count, :controller => 'events', :action => 'events' |
149 | end | 158 | end |
app/jobs/notify_activity_to_profiles_job.rb
@@ -19,8 +19,8 @@ class NotifyActivityToProfilesJob < Struct.new(:tracked_action_id) | @@ -19,8 +19,8 @@ class NotifyActivityToProfilesJob < Struct.new(:tracked_action_id) | ||
19 | # Notify the user | 19 | # Notify the user |
20 | ActionTrackerNotification.create(:profile_id => tracked_action.user.id, :action_tracker_id => tracked_action.id) | 20 | ActionTrackerNotification.create(:profile_id => tracked_action.user.id, :action_tracker_id => tracked_action.id) |
21 | 21 | ||
22 | - # Notify all friends | ||
23 | - ActionTrackerNotification.connection.execute("insert into action_tracker_notifications(profile_id, action_tracker_id) select f.friend_id, #{tracked_action.id} from friendships as f where person_id=#{tracked_action.user.id} and f.friend_id not in (select atn.profile_id from action_tracker_notifications as atn where atn.action_tracker_id = #{tracked_action.id})") | 22 | + # Notify all followers |
23 | + ActionTrackerNotification.connection.execute("INSERT INTO action_tracker_notifications(profile_id, action_tracker_id) SELECT DISTINCT c.person_id, #{tracked_action.id} FROM profiles_circles AS p JOIN circles as c ON c.id = p.circle_id WHERE p.profile_id = #{tracked_action.user.id} AND (c.person_id NOT IN (SELECT atn.profile_id FROM action_tracker_notifications AS atn WHERE atn.action_tracker_id = #{tracked_action.id}))") | ||
24 | 24 | ||
25 | if tracked_action.user.is_a? Organization | 25 | if tracked_action.user.is_a? Organization |
26 | ActionTrackerNotification.connection.execute "insert into action_tracker_notifications(profile_id, action_tracker_id) " + | 26 | ActionTrackerNotification.connection.execute "insert into action_tracker_notifications(profile_id, action_tracker_id) " + |
app/models/add_member.rb
@@ -22,6 +22,7 @@ class AddMember < Task | @@ -22,6 +22,7 @@ class AddMember < Task | ||
22 | self.roles = [Profile::Roles.member(organization.environment.id).id] | 22 | self.roles = [Profile::Roles.member(organization.environment.id).id] |
23 | end | 23 | end |
24 | target.affiliate(requestor, self.roles.select{|r| !r.to_i.zero? }.map{|i| Role.find(i)}) | 24 | target.affiliate(requestor, self.roles.select{|r| !r.to_i.zero? }.map{|i| Role.find(i)}) |
25 | + person.follow(organization, Circle.find_or_create_by(:person => person, :name =>_('memberships'), :profile_type => 'Community')) | ||
25 | end | 26 | end |
26 | 27 | ||
27 | def title | 28 | def title |
app/models/article.rb
@@ -538,13 +538,13 @@ class Article < ApplicationRecord | @@ -538,13 +538,13 @@ class Article < ApplicationRecord | ||
538 | 538 | ||
539 | scope :display_filter, lambda {|user, profile| | 539 | scope :display_filter, lambda {|user, profile| |
540 | return published if (user.nil? && profile && profile.public?) | 540 | return published if (user.nil? && profile && profile.public?) |
541 | - return [] if user.nil? || (profile && !profile.public? && !user.follows?(profile)) | 541 | + return [] if user.nil? || (profile && !profile.public? && !profile.in_social_circle?(user)) |
542 | where( | 542 | where( |
543 | [ | 543 | [ |
544 | "published = ? OR last_changed_by_id = ? OR profile_id = ? OR ? | 544 | "published = ? OR last_changed_by_id = ? OR profile_id = ? OR ? |
545 | OR (show_to_followers = ? AND ? AND profile_id IN (?))", true, user.id, user.id, | 545 | OR (show_to_followers = ? AND ? AND profile_id IN (?))", true, user.id, user.id, |
546 | profile.nil? ? false : user.has_permission?(:view_private_content, profile), | 546 | profile.nil? ? false : user.has_permission?(:view_private_content, profile), |
547 | - true, (profile.nil? ? true : user.follows?(profile)), ( profile.nil? ? (user.friends.select('profiles.id')) : [profile.id]) | 547 | + true, (profile.nil? ? true : profile.in_social_circle?(user)), ( profile.nil? ? (user.friends.select('profiles.id')) : [profile.id]) |
548 | ] | 548 | ] |
549 | ) | 549 | ) |
550 | } | 550 | } |
app/models/block.rb
@@ -89,7 +89,7 @@ class Block < ApplicationRecord | @@ -89,7 +89,7 @@ class Block < ApplicationRecord | ||
89 | end | 89 | end |
90 | 90 | ||
91 | def display_to_user?(user) | 91 | def display_to_user?(user) |
92 | - display_user == 'all' || (user.nil? && display_user == 'not_logged') || (user && display_user == 'logged') || (user && display_user == 'followers' && user.follows?(owner)) | 92 | + display_user == 'all' || (user.nil? && display_user == 'not_logged') || (user && display_user == 'logged') || (user && display_user == 'followers' && owner.in_social_circle?(user)) |
93 | end | 93 | end |
94 | 94 | ||
95 | def display_always(context) | 95 | def display_always(context) |
@@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
1 | +class Circle < ApplicationRecord | ||
2 | + has_many :profile_followers | ||
3 | + belongs_to :person | ||
4 | + | ||
5 | + attr_accessible :name, :person, :profile_type | ||
6 | + | ||
7 | + validates :name, presence: true | ||
8 | + validates :person_id, presence: true | ||
9 | + validates :profile_type, presence: true | ||
10 | + validates :person_id, :uniqueness => {:scope => :name, :message => "can't add two circles with the same name"} | ||
11 | + | ||
12 | + validate :profile_type_must_be_in_list | ||
13 | + | ||
14 | + scope :by_owner, -> person{ | ||
15 | + where(:person => person) | ||
16 | + } | ||
17 | + | ||
18 | + scope :with_name, -> name{ | ||
19 | + where(:name => name) | ||
20 | + } | ||
21 | + | ||
22 | + def self.profile_types | ||
23 | + { | ||
24 | + _("Person") => Person.name, | ||
25 | + _("Community") => Community.name, | ||
26 | + _("Enterprise") => Enterprise.name | ||
27 | + } | ||
28 | + end | ||
29 | + | ||
30 | + def profile_type_must_be_in_list | ||
31 | + valid_profile_types = Circle.profile_types.values | ||
32 | + unless self.profile_type.in? valid_profile_types | ||
33 | + self.errors.add(:profile_type, "invalid profile type") | ||
34 | + end | ||
35 | + end | ||
36 | + | ||
37 | +end |
app/models/enterprise.rb
app/models/favorite_enterprise_person.rb
@@ -7,6 +7,10 @@ class FavoriteEnterprisePerson < ApplicationRecord | @@ -7,6 +7,10 @@ class FavoriteEnterprisePerson < ApplicationRecord | ||
7 | belongs_to :enterprise | 7 | belongs_to :enterprise |
8 | belongs_to :person | 8 | belongs_to :person |
9 | 9 | ||
10 | + after_create do |favorite| | ||
11 | + favorite.person.follow(favorite.enterprise, Circle.find_or_create_by(:person => favorite.person, :name =>_('favorites'), :profile_type => 'Enterprise')) | ||
12 | + end | ||
13 | + | ||
10 | protected | 14 | protected |
11 | 15 | ||
12 | def is_trackable? | 16 | def is_trackable? |
app/models/friendship.rb
@@ -9,11 +9,15 @@ class Friendship < ApplicationRecord | @@ -9,11 +9,15 @@ class Friendship < ApplicationRecord | ||
9 | after_create do |friendship| | 9 | after_create do |friendship| |
10 | Friendship.update_cache_counter(:friends_count, friendship.person, 1) | 10 | Friendship.update_cache_counter(:friends_count, friendship.person, 1) |
11 | Friendship.update_cache_counter(:friends_count, friendship.friend, 1) | 11 | Friendship.update_cache_counter(:friends_count, friendship.friend, 1) |
12 | + friendship.person.follow(friendship.friend, Circle.find_or_create_by(:person => friendship.person, :name => (friendship.group.blank? ? 'friendships': friendship.group), :profile_type => 'Person')) | ||
12 | end | 13 | end |
13 | 14 | ||
14 | after_destroy do |friendship| | 15 | after_destroy do |friendship| |
15 | Friendship.update_cache_counter(:friends_count, friendship.person, -1) | 16 | Friendship.update_cache_counter(:friends_count, friendship.person, -1) |
16 | Friendship.update_cache_counter(:friends_count, friendship.friend, -1) | 17 | Friendship.update_cache_counter(:friends_count, friendship.friend, -1) |
18 | + | ||
19 | + circle = Circle.find_by(:person => friendship.person, :name => (friendship.group.blank? ? 'friendships': friendship.group) ) | ||
20 | + friendship.person.remove_profile_from_circle(friendship.friend, circle) if circle | ||
17 | end | 21 | end |
18 | 22 | ||
19 | def self.remove_friendship(person1, person2) | 23 | def self.remove_friendship(person1, person2) |
app/models/person.rb
@@ -8,7 +8,6 @@ class Person < Profile | @@ -8,7 +8,6 @@ class Person < Profile | ||
8 | :display => %w[compact] | 8 | :display => %w[compact] |
9 | } | 9 | } |
10 | 10 | ||
11 | - | ||
12 | def self.type_name | 11 | def self.type_name |
13 | _('Person') | 12 | _('Person') |
14 | end | 13 | end |
@@ -93,6 +92,7 @@ class Person < Profile | @@ -93,6 +92,7 @@ class Person < Profile | ||
93 | has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article | 92 | has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article |
94 | has_many :friendships, :dependent => :destroy | 93 | has_many :friendships, :dependent => :destroy |
95 | has_many :friends, :class_name => 'Person', :through => :friendships | 94 | has_many :friends, :class_name => 'Person', :through => :friendships |
95 | + has_many :circles | ||
96 | 96 | ||
97 | scope :online, -> { | 97 | scope :online, -> { |
98 | joins(:user).where("users.chat_status != '' AND users.chat_status_at >= ?", DateTime.now - User.expires_chat_status_every.minutes) | 98 | joins(:user).where("users.chat_status != '' AND users.chat_status_at >= ?", DateTime.now - User.expires_chat_status_every.minutes) |
@@ -200,6 +200,33 @@ class Person < Profile | @@ -200,6 +200,33 @@ class Person < Profile | ||
200 | end | 200 | end |
201 | end | 201 | end |
202 | 202 | ||
203 | + def follow (profile, circles) | ||
204 | + circles = [circles] unless circles.is_a?(Array) | ||
205 | + circles.each do |new_circle| | ||
206 | + ProfileFollower.create(profile: profile, circle: new_circle) | ||
207 | + end | ||
208 | + end | ||
209 | + | ||
210 | + def update_profile_circles (profile, new_circles) | ||
211 | + profile_circles = ProfileFollower.with_profile(profile).with_follower(self).map(&:circle) | ||
212 | + circles_to_add = new_circles - profile_circles | ||
213 | + circles_to_remove = profile_circles - new_circles | ||
214 | + circles_to_add.each do |new_circle| | ||
215 | + ProfileFollower.create(profile: profile, circle: new_circle) | ||
216 | + end | ||
217 | + | ||
218 | + ProfileFollower.where('circle_id IN (?) AND profile_id = ?', | ||
219 | + circles_to_remove.map(&:id), profile.id).destroy_all | ||
220 | + end | ||
221 | + | ||
222 | + def unfollow(profile) | ||
223 | + ProfileFollower.with_follower(self).with_profile(profile).destroy_all | ||
224 | + end | ||
225 | + | ||
226 | + def remove_profile_from_circle(profile, circle) | ||
227 | + ProfileFollower.with_profile(profile).with_circle(circle).destroy_all | ||
228 | + end | ||
229 | + | ||
203 | def already_request_friendship?(person) | 230 | def already_request_friendship?(person) |
204 | person.tasks.where(requestor_id: self.id, type: 'AddFriend', status: Task::Status::ACTIVE).first | 231 | person.tasks.where(requestor_id: self.id, type: 'AddFriend', status: Task::Status::ACTIVE).first |
205 | end | 232 | end |
@@ -580,9 +607,12 @@ class Person < Profile | @@ -580,9 +607,12 @@ class Person < Profile | ||
580 | person.has_permission?(:manage_friends, self) | 607 | person.has_permission?(:manage_friends, self) |
581 | end | 608 | end |
582 | 609 | ||
583 | - protected | 610 | + def followed_profiles |
611 | + Profile.followed_by self | ||
612 | + end | ||
584 | 613 | ||
585 | - def followed_by?(profile) | ||
586 | - self == profile || self.is_a_friend?(profile) | 614 | + def in_social_circle?(person) |
615 | + self.is_a_friend?(person) || super | ||
587 | end | 616 | end |
617 | + | ||
588 | end | 618 | end |
app/models/profile.rb
@@ -5,7 +5,7 @@ class Profile < ApplicationRecord | @@ -5,7 +5,7 @@ class Profile < ApplicationRecord | ||
5 | 5 | ||
6 | attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, | 6 | attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, |
7 | :redirection_after_login, :custom_url_redirection, | 7 | :redirection_after_login, :custom_url_redirection, |
8 | - :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :profile_admin_mail_notification | 8 | + :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :profile_admin_mail_notification, :allow_followers |
9 | 9 | ||
10 | # use for internationalizable human type names in search facets | 10 | # use for internationalizable human type names in search facets |
11 | # reimplement on subclasses | 11 | # reimplement on subclasses |
@@ -206,6 +206,23 @@ class Profile < ApplicationRecord | @@ -206,6 +206,23 @@ class Profile < ApplicationRecord | ||
206 | scope :more_active, -> { order 'activities_count DESC' } | 206 | scope :more_active, -> { order 'activities_count DESC' } |
207 | scope :more_recent, -> { order "created_at DESC" } | 207 | scope :more_recent, -> { order "created_at DESC" } |
208 | 208 | ||
209 | + scope :followed_by, -> person{ | ||
210 | + distinct.select('profiles.*'). | ||
211 | + joins('left join profiles_circles ON profiles_circles.profile_id = profiles.id'). | ||
212 | + joins('left join circles ON circles.id = profiles_circles.circle_id'). | ||
213 | + where('circles.person_id = ?', person.id) | ||
214 | + } | ||
215 | + | ||
216 | + scope :in_circle, -> circle{ | ||
217 | + distinct.select('profiles.*'). | ||
218 | + joins('left join profiles_circles ON profiles_circles.profile_id = profiles.id'). | ||
219 | + joins('left join circles ON circles.id = profiles_circles.circle_id'). | ||
220 | + where('circles.id = ?', circle.id) | ||
221 | + } | ||
222 | + | ||
223 | + settings_items :allow_followers, :type => :boolean, :default => true | ||
224 | + alias_method :allow_followers?, :allow_followers | ||
225 | + | ||
209 | acts_as_trackable :dependent => :destroy | 226 | acts_as_trackable :dependent => :destroy |
210 | 227 | ||
211 | has_many :profile_activities | 228 | has_many :profile_activities |
@@ -218,6 +235,9 @@ class Profile < ApplicationRecord | @@ -218,6 +235,9 @@ class Profile < ApplicationRecord | ||
218 | 235 | ||
219 | has_many :email_templates, :foreign_key => :owner_id | 236 | has_many :email_templates, :foreign_key => :owner_id |
220 | 237 | ||
238 | + has_many :profile_followers | ||
239 | + has_many :followers, :class_name => 'Person', :through => :profile_followers, :source => :person | ||
240 | + | ||
221 | # Although this should be a has_one relation, there are no non-silly names for | 241 | # Although this should be a has_one relation, there are no non-silly names for |
222 | # a foreign key on article to reference the template to which it is | 242 | # a foreign key on article to reference the template to which it is |
223 | # welcome_page... =P | 243 | # welcome_page... =P |
@@ -769,6 +789,7 @@ private :generate_url, :url_options | @@ -769,6 +789,7 @@ private :generate_url, :url_options | ||
769 | else | 789 | else |
770 | self.affiliate(person, Profile::Roles.admin(environment.id), attributes) if members.count == 0 | 790 | self.affiliate(person, Profile::Roles.admin(environment.id), attributes) if members.count == 0 |
771 | self.affiliate(person, Profile::Roles.member(environment.id), attributes) | 791 | self.affiliate(person, Profile::Roles.member(environment.id), attributes) |
792 | + person.follow(self, Circle.find_or_create_by(:person => person, :name =>_('memberships'), :profile_type => 'Community')) | ||
772 | end | 793 | end |
773 | person.tasks.pending.of("InviteMember").select { |t| t.data[:community_id] == self.id }.each { |invite| invite.cancel } | 794 | person.tasks.pending.of("InviteMember").select { |t| t.data[:community_id] == self.id }.each { |invite| invite.cancel } |
774 | remove_from_suggestion_list person | 795 | remove_from_suggestion_list person |
@@ -1112,7 +1133,11 @@ private :generate_url, :url_options | @@ -1112,7 +1133,11 @@ private :generate_url, :url_options | ||
1112 | end | 1133 | end |
1113 | 1134 | ||
1114 | def followed_by?(person) | 1135 | def followed_by?(person) |
1115 | - person.is_member_of?(self) | 1136 | + (person == self) || (person.in? self.followers) |
1137 | + end | ||
1138 | + | ||
1139 | + def in_social_circle?(person) | ||
1140 | + (person == self) || (person.is_member_of?(self)) | ||
1116 | end | 1141 | end |
1117 | 1142 | ||
1118 | def display_private_info_to?(user) | 1143 | def display_private_info_to?(user) |
@@ -1153,4 +1178,8 @@ private :generate_url, :url_options | @@ -1153,4 +1178,8 @@ private :generate_url, :url_options | ||
1153 | def allow_destroy?(person = nil) | 1178 | def allow_destroy?(person = nil) |
1154 | person.kind_of?(Profile) && person.has_permission?('destroy_profile', self) | 1179 | person.kind_of?(Profile) && person.has_permission?('destroy_profile', self) |
1155 | end | 1180 | end |
1181 | + | ||
1182 | + def in_circle?(circle, follower) | ||
1183 | + ProfileFollower.with_follower(follower).with_circle(circle).with_profile(self).present? | ||
1184 | + end | ||
1156 | end | 1185 | end |
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +class ProfileFollower < ApplicationRecord | ||
2 | + self.table_name = :profiles_circles | ||
3 | + track_actions :new_follower, :after_create, :keep_params => ["follower.name", "follower.url", "follower.profile_custom_icon"], :custom_user => :profile | ||
4 | + | ||
5 | + attr_accessible :profile, :circle | ||
6 | + | ||
7 | + belongs_to :profile | ||
8 | + belongs_to :circle | ||
9 | + | ||
10 | + has_one :person, through: :circle | ||
11 | + alias follower person | ||
12 | + | ||
13 | + validates_presence_of :profile_id, :circle_id | ||
14 | + validates :profile_id, :uniqueness => {:scope => :circle_id, :message => "can't put a profile in the same circle twice"} | ||
15 | + | ||
16 | + scope :with_follower, -> person{ | ||
17 | + joins(:circle).where('circles.person_id = ?', person.id) | ||
18 | + } | ||
19 | + | ||
20 | + scope :with_profile, -> profile{ | ||
21 | + where(:profile => profile) | ||
22 | + } | ||
23 | + | ||
24 | + scope :with_circle, -> circle{ | ||
25 | + where(:circle => circle) | ||
26 | + } | ||
27 | + | ||
28 | +end |
@@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +<div class="circles" id='circles-list'> | ||
2 | + | ||
3 | + <%= form_for :circles, :url => {:controller => 'profile', :action => 'follow'}, :html => {:id => "follow-circles-form"} do |f|%> | ||
4 | + <%= render partial: "blocks/profile_info_actions/select_circles", :locals => {:circles => circles} %> | ||
5 | + | ||
6 | + <div id="circle-actions"> | ||
7 | + <%= submit_button :ok, _("Follow") %> | ||
8 | + <input type="button" value="<%= _("Cancel") %>" id="cancel-set-circle" class="button with-text icon-cancel"/> | ||
9 | + </div> | ||
10 | + <% end %> | ||
11 | +</div> |
app/views/blocks/profile_info_actions/_common.html.erb
1 | <li><%= report_abuse(profile, :button) %></li> | 1 | <li><%= report_abuse(profile, :button) %></li> |
2 | +<%if logged_in? && (user != profile) && profile.allow_followers?%> | ||
3 | +<li> | ||
4 | + <% follow = user.follows?(profile) %> | ||
5 | + <%= button(:unfollow, content_tag('span', _('Unfollow')), {:profile => profile.identifier, :controller => 'profile', :action => 'unfollow'}, :id => 'action-unfollow', :title => _("Unfollow"), :style => follow ? "" : "display: none;") %> | ||
6 | + <%= button(:ok, content_tag('span', _('Follow')), {:profile => profile.identifier, :controller => 'profile', :action => 'find_profile_circles'}, :id => 'action-follow', :title => _("Follow"), :style => follow ? "display: none;" : "") %> | ||
7 | + <div id="circles-container" style="display: none;"> | ||
8 | + </div> | ||
9 | +</li> | ||
10 | +<%end%> | ||
2 | <%= render_environment_features(:profile_actions) %> | 11 | <%= render_environment_features(:profile_actions) %> |
app/views/blocks/profile_info_actions/_select_circles.html.erb
0 → 100644
@@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
1 | +<div class="circles" id='circles-list'> | ||
2 | + <p><%= _("Select the circles for %s") % profile.name %></p> | ||
3 | + <div id="circles-checkboxes"> | ||
4 | + <% circles.each do |circle| %> | ||
5 | + <div class="circle"> | ||
6 | + <%= labelled_check_box circle.name, "circles[#{circle.name}]", circle.id, profile.in_circle?(circle, current_person) %> | ||
7 | + </div> | ||
8 | + <% end %> | ||
9 | + </div> | ||
10 | + | ||
11 | + <a href="#" id="new-circle"> | ||
12 | + <span><%= _("New Circle") %></span> | ||
13 | + </a> | ||
14 | + | ||
15 | + <div id="new-circle-form" style="display: none;"> | ||
16 | + <%= labelled_text_field _('Circle name') , 'circle[name]', "",:id => 'text-field-name-new-circle'%> | ||
17 | + <%= hidden_field_tag('circle[profile_type]', profile.class.name) %> | ||
18 | + | ||
19 | + <%= button_bar do %> | ||
20 | + <%= button(:save, _('Create'), {:profile => profile.identifier, :controller => 'circles', :action => 'xhr_create'}, :id => "new-circle-submit") %> | ||
21 | + <%= button(:cancel, _('Cancel'), '#', :id => "new-circle-cancel") %> | ||
22 | + <% end %> | ||
23 | + </div> | ||
24 | +</div> |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +<%= error_messages_for :circle %> | ||
2 | + | ||
3 | +<%= labelled_form_for :circle, :url => (mode == :edit) ? {:action => 'update', :id => circle} : {:action => 'create'} do |f| %> | ||
4 | + | ||
5 | + <%= required_fields_message %> | ||
6 | + | ||
7 | + <%= required f.text_field(:name) %> | ||
8 | + | ||
9 | + <%= required labelled_form_field _("Profile type"), f.select(:profile_type, Circle.profile_types.to_a) %> | ||
10 | + | ||
11 | + <%= button_bar do %> | ||
12 | + <%= submit_button('save', (mode == :edit) ? _('Save changes') : _('Create circle'), :cancel => {:action => 'index'} ) %> | ||
13 | + <% end %> | ||
14 | +<% end %> |
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +<h1><%= _('Manage circles') %></h1> | ||
2 | + | ||
3 | +<table> | ||
4 | + <tr> | ||
5 | + <th><%= _('Circle name') %></th> | ||
6 | + <th><%= _('Profile type') %></th> | ||
7 | + <th><%= _('Actions') %></th> | ||
8 | + </tr> | ||
9 | + <% @circles.each do |circle| %> | ||
10 | + <tr> | ||
11 | + <td> | ||
12 | + <%= circle.name %> | ||
13 | + </td> | ||
14 | + <td> | ||
15 | + <%= _(circle.profile_type) %> | ||
16 | + </td> | ||
17 | + <td> | ||
18 | + <div style="text-align: center;"> | ||
19 | + <%= button_without_text :edit, _('Edit'), :action => 'edit', :id => circle %> | ||
20 | + <%= button_without_text :delete, _('Delete'), { :action => 'destroy', :id => circle }, { "data-method" => "POST" } %> | ||
21 | + </div> | ||
22 | + </td> | ||
23 | + </tr> | ||
24 | + <% end %> | ||
25 | +</table> | ||
26 | + | ||
27 | +<%= button_bar do %> | ||
28 | + <%= button :add, _('Create a new circle'), :action => 'new' %> | ||
29 | + <%= button :back, _('Back to control panel'), :controller => 'profile_editor' %> | ||
30 | +<% end %> |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +<div class="circles" id='circles-list'> | ||
2 | + <%= form_for :circles, :url => {:controller => 'followers', :action => 'update_category'}, :html => {:id => "follow-circles-form"} do |f|%> | ||
3 | + <%= render partial: "blocks/profile_info_actions/select_circles", :locals => {:circles => circles, :profile => profile} %> | ||
4 | + | ||
5 | + <%= hidden_field_tag('followed_profile_id', profile.id) %> | ||
6 | + | ||
7 | + <div id="circle-actions"> | ||
8 | + <div id="actions-container"> | ||
9 | + <%= submit_button('save', _('Save')) %> | ||
10 | + <%= modal_close_button _("Cancel") %> | ||
11 | + </div> | ||
12 | + </div> | ||
13 | + <% end %> | ||
14 | +</div> |
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
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 | + <div class="controll"> | ||
7 | + <%= button_without_text :remove, content_tag('span',_('unfollow')), | ||
8 | + { :controller => "profile", :profile => profile.identifier , :action => 'unfollow', :redirect_to => url_for({:controller => "followers", :profile => user.identifier}) }, | ||
9 | + :title => _('remove') %> | ||
10 | + <%= modal_icon_button :edit, _('change category'), | ||
11 | + url_for(:controller => 'followers', :action => 'set_category_modal', | ||
12 | + :followed_profile_id => profile.id) %> | ||
13 | + </div><!-- end class="controll" --> | ||
14 | + </li> | ||
15 | + <% end %> | ||
16 | +</ul> |
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
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 | + <%= labelled_select(_('Profile type')+': ', :filter_profile_type, :last, :first, @active_filter, @profile_types, :id => "profile-type-filter") %> | ||
20 | + | ||
21 | + <%= render :partial => 'profile_list', :locals => { :profiles => @followed_people } %> | ||
22 | + | ||
23 | + <br style="clear:both" /> | ||
24 | + <%= pagination_links @followed_people, :param_name => 'npage' %> | ||
25 | +<% end %> | ||
26 | + | ||
27 | +</div> |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +<%= render :partial => 'default_activity', :locals => { :activity => activity } %> |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +<% cache_timeout(profile.friends_cache_key(params), 4.hours) do %> | ||
2 | + <ul class='profile-list'> | ||
3 | + <% follow.each do |follower| %> | ||
4 | + <%= profile_image_link(follower) %> | ||
5 | + <% end%> | ||
6 | + </ul> | ||
7 | + | ||
8 | + <div id='pagination-profiles'> | ||
9 | + <%= pagination_links follow, :param_name => 'npage' %> | ||
10 | + </div> | ||
11 | +<% end %> | ||
12 | + | ||
13 | +<%= button_bar do %> | ||
14 | + <%= button :back, _('Go back'), { :controller => 'profile' } %> | ||
15 | + <% if user == profile %> | ||
16 | + <%= button :edit, _('Manage followed people'), :controller => 'friends', :action => 'index', :profile => profile.identifier %> | ||
17 | + <% end %> | ||
18 | +<% end %> |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +<%= render :partial => 'default_activity', :locals => { :activity => activity, :tab_action => tab_action } %> |
app/views/profile_editor/edit.html.erb
@@ -23,9 +23,11 @@ | @@ -23,9 +23,11 @@ | ||
23 | </div> | 23 | </div> |
24 | 24 | ||
25 | <h2><%= _('Privacy options') %></h2> | 25 | <h2><%= _('Privacy options') %></h2> |
26 | - | 26 | + <div> |
27 | + <%= labelled_check_box _("Allow other users to follow me"), 'profile_data[allow_followers]', true, @profile.allow_followers?, :class => "person-can-be-followed" %> | ||
28 | + </div> | ||
27 | <% if profile.person? %> | 29 | <% if profile.person? %> |
28 | - <div> | 30 | + <div id="profile_allow_follows"> |
29 | <%= labelled_radio_button _('Public — show my contents to all internet users').html_safe, 'profile_data[public_profile]', true, @profile.public_profile? %> | 31 | <%= labelled_radio_button _('Public — show my contents to all internet users').html_safe, 'profile_data[public_profile]', true, @profile.public_profile? %> |
30 | </div> | 32 | </div> |
31 | <div> | 33 | <div> |
app/views/profile_editor/index.html.erb
@@ -72,6 +72,11 @@ | @@ -72,6 +72,11 @@ | ||
72 | 72 | ||
73 | <%= control_panel_button(_('Email Templates'), 'email-templates', :controller => :profile_email_templates) if profile.organization? %> | 73 | <%= control_panel_button(_('Email Templates'), 'email-templates', :controller => :profile_email_templates) if profile.organization? %> |
74 | 74 | ||
75 | + <% if profile.person? %> | ||
76 | + <%= control_panel_button(_('Manage followed profiles'), 'edit-profile', :controller => :followers) %> | ||
77 | + <%= control_panel_button(_('Manage circles'), 'edit-profile-group', :controller => :circles) %> | ||
78 | + <% end %> | ||
79 | + | ||
75 | <% @plugins.dispatch(:control_panel_buttons).each do |button| %> | 80 | <% @plugins.dispatch(:control_panel_buttons).each do |button| %> |
76 | <%= control_panel_button(button[:title], button[:icon], button[:url], button[:html_options]) %> | 81 | <%= control_panel_button(button[:title], button[:icon], button[:url], button[:html_options]) %> |
77 | <% end %> | 82 | <% end %> |
config/initializers/action_tracker.rb
@@ -12,6 +12,10 @@ ActionTrackerConfig.verbs = { | @@ -12,6 +12,10 @@ ActionTrackerConfig.verbs = { | ||
12 | type: :groupable | 12 | type: :groupable |
13 | }, | 13 | }, |
14 | 14 | ||
15 | + new_follower: { | ||
16 | + type: :groupable | ||
17 | + }, | ||
18 | + | ||
15 | join_community: { | 19 | join_community: { |
16 | type: :groupable | 20 | type: :groupable |
17 | }, | 21 | }, |
db/migrate/20160608123748_create_profile_followers_table.rb
0 → 100644
@@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
1 | +class CreateProfileFollowersTable < ActiveRecord::Migration | ||
2 | + def up | ||
3 | + create_table :profiles_circles do |t| | ||
4 | + t.column :profile_id, :integer | ||
5 | + t.column :circle_id, :integer | ||
6 | + t.timestamps | ||
7 | + end | ||
8 | + | ||
9 | + create_table :circles do |t| | ||
10 | + t.column :name, :string | ||
11 | + t.belongs_to :person | ||
12 | + t.column :profile_type, :string, :null => false | ||
13 | + end | ||
14 | + | ||
15 | + add_foreign_key :profiles_circles, :circles, :on_delete => :nullify | ||
16 | + | ||
17 | + add_index :profiles_circles, [:profile_id, :circle_id], :name => "profiles_circles_composite_key_index", :unique => true | ||
18 | + add_index :circles, [:person_id, :name], :name => "circles_composite_key_index", :unique => true | ||
19 | + | ||
20 | + #insert one category for each friend group a person has | ||
21 | + execute("INSERT INTO circles(name, person_id, profile_type) SELECT DISTINCT (CASE WHEN (f.group IS NULL OR f.group = '') THEN 'friendships' ELSE f.group END), f.person_id, 'Person' FROM friendships as f") | ||
22 | + #insert 'memberships' category if a person is in a community as a member, moderator or profile admin | ||
23 | + execute("INSERT INTO circles(name, person_id, profile_type) SELECT DISTINCT 'memberships', ra.accessor_id, 'Community' FROM role_assignments as ra JOIN roles ON ra.role_id = roles.id WHERE roles.name IN ('Member','Moderator','Profile Administrator')") | ||
24 | + #insert 'favorites' category if a person has any favorited enterprise | ||
25 | + execute("INSERT INTO circles(name, person_id, profile_type) SELECT DISTINCT 'favorites', person_id, 'Enterprise' FROM favorite_enterprise_people") | ||
26 | + | ||
27 | + #insert a follower entry for each friend, with the category the same as the friendship group or equals 'friendships' | ||
28 | + execute("INSERT INTO profiles_circles(profile_id, circle_id) SELECT DISTINCT f.friend_id, c.id FROM friendships as f JOIN circles as c ON f.person_id = c.person_id WHERE c.name = f.group OR c.name = 'friendships'") | ||
29 | + #insert a follower entry for each favorited enterprise, with the category 'favorites' | ||
30 | + execute("INSERT INTO profiles_circles(profile_id, circle_id) SELECT DISTINCT f.enterprise_id, c.id FROM favorite_enterprise_people AS f JOIN circles as c ON f.person_id = c.person_id WHERE c.name = 'favorites' ") | ||
31 | + #insert a follower entry for each community a person participates as a member, moderator or admininstrator | ||
32 | + execute("INSERT INTO profiles_circles(profile_id, circle_id) SELECT DISTINCT ra.resource_id, c.id FROM role_assignments as ra JOIN roles ON ra.role_id = roles.id JOIN circles as c ON ra.accessor_id = c.person_id WHERE roles.name IN ('Member','Moderator','Profile Administrator') AND c.name = 'memberships'") | ||
33 | + end | ||
34 | + | ||
35 | + def down | ||
36 | + remove_foreign_key :profiles_circles, :circles | ||
37 | + remove_index :profiles_circles, :name => "profiles_circles_composite_key_index" | ||
38 | + remove_index :circles, :name => "circles_composite_key_index" | ||
39 | + drop_table :circles | ||
40 | + drop_table :profiles_circles | ||
41 | + end | ||
42 | +end |
@@ -0,0 +1,114 @@ | @@ -0,0 +1,114 @@ | ||
1 | +Feature: follow profile | ||
2 | + As a noosfero user | ||
3 | + I want to follow a profile | ||
4 | + So I can receive notifications from it | ||
5 | + | ||
6 | + Background: | ||
7 | + Given the following community | ||
8 | + | identifier | name | | ||
9 | + | nightswatch | Nights Watch | | ||
10 | + And the following users | ||
11 | + | login | | ||
12 | + | johnsnow | | ||
13 | + And the user "johnsnow" has the following circles | ||
14 | + | name | profile_type | | ||
15 | + | Family | Person | | ||
16 | + | Work | Community | | ||
17 | + | Favorites | Community | | ||
18 | + | ||
19 | + @selenium | ||
20 | + Scenario: Common noofero user follow a community | ||
21 | + Given I am logged in as "johnsnow" | ||
22 | + When I go to nightswatch's homepage | ||
23 | + When I follow "Follow" | ||
24 | + When I check "Work" | ||
25 | + When I press "Follow" | ||
26 | + And I wait 1 second | ||
27 | + Then "johnsnow" should be a follower of "nightswatch" in circle "Work" | ||
28 | + | ||
29 | + @selenium | ||
30 | + Scenario: Common noofero user follow a community in more than one circle | ||
31 | + Given I am logged in as "johnsnow" | ||
32 | + When I go to nightswatch's homepage | ||
33 | + When I follow "Follow" | ||
34 | + When I check "Work" | ||
35 | + When I check "Favorites" | ||
36 | + When I press "Follow" | ||
37 | + And I wait 1 second | ||
38 | + Then "johnsnow" should be a follower of "nightswatch" in circle "Work" | ||
39 | + And "johnsnow" should be a follower of "nightswatch" in circle "Favorites" | ||
40 | + | ||
41 | + @selenium | ||
42 | + Scenario: No see another profile type circle when following a community | ||
43 | + Given I am logged in as "johnsnow" | ||
44 | + When I go to nightswatch's homepage | ||
45 | + When I follow "Follow" | ||
46 | + Then I should not see "Family" | ||
47 | + And I should see "Favorites" | ||
48 | + And I should see "Work" | ||
49 | + | ||
50 | + @selenium | ||
51 | + Scenario: Common noofero user follow a community then cancel the action | ||
52 | + Given I am logged in as "johnsnow" | ||
53 | + When I go to nightswatch's homepage | ||
54 | + When I follow "Follow" | ||
55 | + When I press "Cancel" | ||
56 | + And I wait 1 second | ||
57 | + Then I should not see "Family" | ||
58 | + And I should not see "Favorites" | ||
59 | + And I should not see "Work" | ||
60 | + And I should not see "New Circle" | ||
61 | + Then "johnsnow" should not be a follower of "nightswatch" | ||
62 | + | ||
63 | + @selenium | ||
64 | + Scenario: Common noofero user cancel the circle creation action | ||
65 | + Given I am logged in as "johnsnow" | ||
66 | + When I go to nightswatch's homepage | ||
67 | + When I follow "Follow" | ||
68 | + When I follow "New Circle" | ||
69 | + When I press "Cancel" | ||
70 | + And I wait 1 second | ||
71 | + Then I should not see "Circle name" | ||
72 | + And I should not see "Create" | ||
73 | + | ||
74 | + @selenium | ||
75 | + Scenario: Noosfero user see new circle option when following a community | ||
76 | + Given I am logged in as "johnsnow" | ||
77 | + When I go to nightswatch's homepage | ||
78 | + When I follow "Follow" | ||
79 | + Then I should see "New Circle" | ||
80 | + | ||
81 | + @selenium | ||
82 | + Scenario: Common noofero user follow a community with a new circle | ||
83 | + Given I am logged in as "johnsnow" | ||
84 | + When I go to nightswatch's homepage | ||
85 | + When I follow "Follow" | ||
86 | + When I follow "New Circle" | ||
87 | + And I fill in "text-field-name-new-circle" with "Winterfell" | ||
88 | + When I follow "Create" | ||
89 | + When I check "Winterfell" | ||
90 | + When I press "Follow" | ||
91 | + And I wait 1 second | ||
92 | + Then "johnsnow" should be a follower of "nightswatch" in circle "Winterfell" | ||
93 | + | ||
94 | + @selenium | ||
95 | + Scenario: Common noofero user create a new circle when following a community | ||
96 | + Given I am logged in as "johnsnow" | ||
97 | + When I go to nightswatch's homepage | ||
98 | + When I follow "Follow" | ||
99 | + When I follow "New Circle" | ||
100 | + And I fill in "text-field-name-new-circle" with "Winterfell" | ||
101 | + When I follow "Create" | ||
102 | + And I wait 1 second | ||
103 | + Then "johnsnow" should have the circle "Winterfell" with profile type "Community" | ||
104 | + Then I should not see "Circle name" | ||
105 | + Then I should not see "Create" | ||
106 | + | ||
107 | + @selenium | ||
108 | + Scenario: Common noofero user unfollow a community | ||
109 | + Given "johnsnow" is a follower of "nightswatch" in circle "Work" | ||
110 | + And I am logged in as "johnsnow" | ||
111 | + When I go to nightswatch's homepage | ||
112 | + When I follow "Unfollow" | ||
113 | + Then "johnsnow" should not be a follower of "nightswatch" | ||
114 | + |
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +Given /^the user "(.+)" has the following circles$/ do |user_name,table| | ||
2 | + person = User.find_by(:login => user_name).person | ||
3 | + table.hashes.each do |circle| | ||
4 | + Circle.create!(:person => person, :name => circle[:name], :profile_type => circle[:profile_type]) | ||
5 | + end | ||
6 | +end | ||
7 | + | ||
8 | +Then /^"(.+)" should be a follower of "(.+)" in circle "(.+)"$/ do |person, profile, circle| | ||
9 | + profile = Profile.find_by(identifier: profile) | ||
10 | + followers = profile.followers | ||
11 | + person = Person.find_by(identifier: person) | ||
12 | + followers.should include(person) | ||
13 | + | ||
14 | + circle = Circle.find_by(:name => circle, :person => person) | ||
15 | + ProfileFollower.find_by(:circle => circle, :profile => profile).should_not == nil | ||
16 | +end | ||
17 | + | ||
18 | +Then /^"(.+)" should not be a follower of "(.+)"$/ do |person, profile| | ||
19 | + profile = Profile.find_by(identifier: profile) | ||
20 | + followers = profile.followers | ||
21 | + person = Person.find_by(identifier: person) | ||
22 | + followers.should_not include(person) | ||
23 | +end | ||
24 | + | ||
25 | +Given /^"(.+)" is a follower of "(.+)" in circle "(.+)"$/ do |person, profile, circle| | ||
26 | + profile = Profile.find_by(identifier: profile) | ||
27 | + person = Person.find_by(identifier: person) | ||
28 | + circle = Circle.find_by(:name => circle, :person => person) | ||
29 | + ProfileFollower.create!(:circle => circle, :profile => profile) | ||
30 | +end | ||
31 | + | ||
32 | +Then /^"(.+)" should have the circle "(.+)" with profile type "(.+)"$/ do |user_name, circle, profile_type| | ||
33 | + person = User.find_by(:login => user_name).person | ||
34 | + Circle.find_by(:name => circle, :person => person, :profile_type => profile_type).should_not == nil | ||
35 | +end |
public/javascripts/application.js
@@ -26,6 +26,8 @@ | @@ -26,6 +26,8 @@ | ||
26 | *= require pagination.js | 26 | *= require pagination.js |
27 | * views speficics | 27 | * views speficics |
28 | *= require add-and-join.js | 28 | *= require add-and-join.js |
29 | +*= require followers.js | ||
30 | +*= require manage-followers.js | ||
29 | *= require report-abuse.js | 31 | *= require report-abuse.js |
30 | *= require autogrow.js | 32 | *= require autogrow.js |
31 | *= require require_login.js | 33 | *= require require_login.js |
@@ -550,6 +552,11 @@ function loading_for_button(selector) { | @@ -550,6 +552,11 @@ function loading_for_button(selector) { | ||
550 | jQuery(selector).css('cursor', 'progress'); | 552 | jQuery(selector).css('cursor', 'progress'); |
551 | } | 553 | } |
552 | 554 | ||
555 | +function hide_loading_for_button(selector) { | ||
556 | + selector.css("cursor",""); | ||
557 | + $(".small-loading").remove(); | ||
558 | +} | ||
559 | + | ||
553 | function new_qualifier_row(selector, select_qualifiers, delete_button) { | 560 | function new_qualifier_row(selector, select_qualifiers, delete_button) { |
554 | index = jQuery(selector + ' tr').size() - 1; | 561 | index = jQuery(selector + ' tr').size() - 1; |
555 | jQuery(selector).append("<tr><td>" + select_qualifiers + "</td><td id='certifier-area-" + index + "'><select></select>" + delete_button + "</td></tr>"); | 562 | jQuery(selector).append("<tr><td>" + select_qualifiers + "</td><td id='certifier-area-" + index + "'><select></select>" + delete_button + "</td></tr>"); |
@@ -0,0 +1,81 @@ | @@ -0,0 +1,81 @@ | ||
1 | +$("#action-follow").live("click", function() { | ||
2 | + var button = $(this); | ||
3 | + var url = button.attr("href"); | ||
4 | + loading_for_button(button); | ||
5 | + | ||
6 | + $.post(url, function(data) { | ||
7 | + button.fadeOut("fast", function() { | ||
8 | + $("#circles-container").html(data); | ||
9 | + $("#circles-container").fadeIn(); | ||
10 | + }); | ||
11 | + }).always(function() { | ||
12 | + hide_loading_for_button(button); | ||
13 | + }); | ||
14 | + return false; | ||
15 | +}); | ||
16 | + | ||
17 | +$("#cancel-set-circle").live("click", function() { | ||
18 | + $("#circles-container").fadeOut("fast", function() { | ||
19 | + $("#action-follow").fadeIn(); | ||
20 | + }); | ||
21 | + return false; | ||
22 | +}); | ||
23 | + | ||
24 | +$("#new-circle").live("click", function() { | ||
25 | + $(this).fadeOut(); | ||
26 | + $("#circle-actions").fadeOut("fast", function() { | ||
27 | + $("#new-circle-form").fadeIn(); | ||
28 | + }); | ||
29 | + return false; | ||
30 | +}); | ||
31 | + | ||
32 | +$("#new-circle-cancel").live("click", function() { | ||
33 | + $("#new-circle-form").fadeOut("fast", function() { | ||
34 | + $("#circle-actions").fadeIn(); | ||
35 | + $("#new-circle").fadeIn(); | ||
36 | + $("#text-field-name-new-circle").val('') | ||
37 | + }); | ||
38 | + return false; | ||
39 | +}); | ||
40 | + | ||
41 | +$('#follow-circles-form').live("submit", function() { | ||
42 | + var valuesToSubmit = $(this).serialize(); | ||
43 | + $.ajax({ | ||
44 | + type: "POST", | ||
45 | + url: $(this).attr('action'), | ||
46 | + data: valuesToSubmit, | ||
47 | + dataType: "JSON", | ||
48 | + statusCode: { | ||
49 | + 200: function(response){ | ||
50 | + $("#circles-container").fadeOut(); | ||
51 | + $("#action-unfollow").fadeIn(); | ||
52 | + $.colorbox.close(); | ||
53 | + display_notice(response.responseText); | ||
54 | + }, | ||
55 | + 400: function(response) { | ||
56 | + display_notice(response.responseText); | ||
57 | + } | ||
58 | + } | ||
59 | + }) | ||
60 | + return false; | ||
61 | +}); | ||
62 | + | ||
63 | +$("#new-circle-submit").live("click", function() { | ||
64 | + $.ajax({ | ||
65 | + method: 'POST', | ||
66 | + url: $(this).attr("href"), | ||
67 | + data: {'circle[name]': $("#text-field-name-new-circle").val(), | ||
68 | + 'circle[profile_type]': $("#circle_profile_type").val()}, | ||
69 | + success: function(response) { | ||
70 | + $('#circles-checkboxes').append(response); | ||
71 | + }, | ||
72 | + error: function(response) { | ||
73 | + display_notice(response.responseText); | ||
74 | + }, | ||
75 | + complete: function(response) { | ||
76 | + $("#text-field-name-new-circle").val('') | ||
77 | + $("#new-circle-cancel").trigger("click"); | ||
78 | + } | ||
79 | + }) | ||
80 | + return false; | ||
81 | +}); |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +$('#profile-type-filter').live('change', function() { | ||
2 | + var filter_type = $(this).val(); | ||
3 | + $(".profile-list").addClass("fetching"); | ||
4 | + $.get(window.location.pathname, {filter: filter_type}, function(data) { | ||
5 | + $(".main-content").html(data); | ||
6 | + }).fail(function(data) { | ||
7 | + $(".profile-list").removeClass("fetching"); | ||
8 | + }); | ||
9 | +}); |
public/stylesheets/blocks/profile-info.scss
@@ -99,3 +99,44 @@ | @@ -99,3 +99,44 @@ | ||
99 | margin: 0px 0px 5px 0px; | 99 | margin: 0px 0px 5px 0px; |
100 | padding: 2px; | 100 | padding: 2px; |
101 | } | 101 | } |
102 | +#circles-container { | ||
103 | + background-color: #eee; | ||
104 | + padding: 5px; | ||
105 | + display: flex; | ||
106 | +} | ||
107 | +#circles-container p { | ||
108 | + font-size: 12px; | ||
109 | + margin-bottom: 5px; | ||
110 | +} | ||
111 | +#circle-actions { | ||
112 | + margin-top: 15px; | ||
113 | +} | ||
114 | +#new-category-field-actions-block { | ||
115 | + float: left; | ||
116 | + width: 80%; | ||
117 | + margin-bottom: 10px; | ||
118 | +} | ||
119 | +#new-circle-form { | ||
120 | + margin-top: 10px; | ||
121 | +} | ||
122 | +#new-circle-form input { | ||
123 | + width: 90px; | ||
124 | +} | ||
125 | +#new-circle-form select { | ||
126 | + margin-top: 2px; | ||
127 | + width: 95px; | ||
128 | +} | ||
129 | +#new-circle-form label { | ||
130 | + font-size: 10px; | ||
131 | + margin-right: 5px; | ||
132 | +} | ||
133 | +#new-circle-form .button-bar { | ||
134 | + padding-top: 0px; | ||
135 | +} | ||
136 | +#new-circle-form .button { | ||
137 | + width: 60px; | ||
138 | +} | ||
139 | +#new-circle-form .button-bar .button { | ||
140 | + width: 40px; | ||
141 | + font-size: 10px; | ||
142 | +} |
public/stylesheets/profile-activity.scss
@@ -167,7 +167,9 @@ li.profile-activity-item.upload_image .activity-gallery-images-count-1 img { | @@ -167,7 +167,9 @@ li.profile-activity-item.upload_image .activity-gallery-images-count-1 img { | ||
167 | 167 | ||
168 | #profile-wall li.profile-activity-item.join_community .profile-activity-text a img, | 168 | #profile-wall li.profile-activity-item.join_community .profile-activity-text a img, |
169 | #profile-wall li.profile-activity-item.new_friendship .profile-activity-text a img, | 169 | #profile-wall li.profile-activity-item.new_friendship .profile-activity-text a img, |
170 | +#profile-wall li.profile-activity-item.new_follower .profile-activity-text a img, | ||
170 | #profile-network li.profile-activity-item.join_community .profile-activity-text a img, | 171 | #profile-network li.profile-activity-item.join_community .profile-activity-text a img, |
172 | +#profile-network li.profile-activity-item.new_follower .profile-activity-text a img, | ||
171 | #profile-network li.profile-activity-item.new_friendship .profile-activity-text a img { | 173 | #profile-network li.profile-activity-item.new_friendship .profile-activity-text a img { |
172 | margin: 5px 5px 0 0; | 174 | margin: 5px 5px 0 0; |
173 | padding: 1px; | 175 | padding: 1px; |
public/stylesheets/profile-editor.scss
public/stylesheets/profile-list.scss
@@ -23,6 +23,7 @@ | @@ -23,6 +23,7 @@ | ||
23 | } | 23 | } |
24 | .controller-favorite_enterprises .profile-list a.profile-link, | 24 | .controller-favorite_enterprises .profile-list a.profile-link, |
25 | .controller-friends .profile-list a.profile-link, | 25 | .controller-friends .profile-list a.profile-link, |
26 | +.controller-followers .profile-list a.profile-link, | ||
26 | .list-profile-connections .profile-list a.profile-link, | 27 | .list-profile-connections .profile-list a.profile-link, |
27 | .profiles-suggestions .profile-list a.profile-link { | 28 | .profiles-suggestions .profile-list a.profile-link { |
28 | text-decoration: none; | 29 | text-decoration: none; |
@@ -32,11 +33,13 @@ | @@ -32,11 +33,13 @@ | ||
32 | } | 33 | } |
33 | .controller-favorite_enterprises .profile-list a.profile-link:hover, | 34 | .controller-favorite_enterprises .profile-list a.profile-link:hover, |
34 | .controller-friends .profile-list a.profile-link:hover, | 35 | .controller-friends .profile-list a.profile-link:hover, |
36 | +.controller-followers .profile-list a.profile-link:hover, | ||
35 | .profiles-suggestions .profile-list a.profile-link:hover { | 37 | .profiles-suggestions .profile-list a.profile-link:hover { |
36 | color: #FFF; | 38 | color: #FFF; |
37 | } | 39 | } |
38 | .controller-favorite_enterprises .profile-list .profile_link span, | 40 | .controller-favorite_enterprises .profile-list .profile_link span, |
39 | .controller-friends .profile-list .profile_link span, | 41 | .controller-friends .profile-list .profile_link span, |
42 | +.controller-followers .profile-list .profile_link span, | ||
40 | .box-1 .profiles-suggestions .profile-list .profile_link span { | 43 | .box-1 .profiles-suggestions .profile-list .profile_link span { |
41 | width: 80px; | 44 | width: 80px; |
42 | display: block; | 45 | display: block; |
@@ -44,12 +47,14 @@ | @@ -44,12 +47,14 @@ | ||
44 | } | 47 | } |
45 | .controller-favorite_enterprises .profile-list, | 48 | .controller-favorite_enterprises .profile-list, |
46 | .controller-friends .profile-list, | 49 | .controller-friends .profile-list, |
50 | +.controller-followers .profile-list, | ||
47 | .profiles-suggestions .profile-list { | 51 | .profiles-suggestions .profile-list { |
48 | position: relative; | 52 | position: relative; |
49 | } | 53 | } |
50 | 54 | ||
51 | .controller-favorite_enterprises .profile-list .controll, | 55 | .controller-favorite_enterprises .profile-list .controll, |
52 | .controller-friends .profile-list .controll, | 56 | .controller-friends .profile-list .controll, |
57 | +.controller-followers .profile-list .controll, | ||
53 | .profiles-suggestions .profile-list .controll { | 58 | .profiles-suggestions .profile-list .controll { |
54 | position: absolute; | 59 | position: absolute; |
55 | top: 7px; | 60 | top: 7px; |
@@ -57,17 +62,20 @@ | @@ -57,17 +62,20 @@ | ||
57 | } | 62 | } |
58 | .controller-favorite_enterprises .profile-list .controll a, | 63 | .controller-favorite_enterprises .profile-list .controll a, |
59 | .controller-friends .profile-list .controll a, | 64 | .controller-friends .profile-list .controll a, |
65 | +.controller-followers .profile-list .controll a, | ||
60 | .profiles-suggestions .profile-list .controll a { | 66 | .profiles-suggestions .profile-list .controll a { |
61 | display: block; | 67 | display: block; |
62 | margin-bottom: 2px; | 68 | margin-bottom: 2px; |
63 | } | 69 | } |
64 | .controller-favorite_enterprises .msie6 .profile-list .controll a, | 70 | .controller-favorite_enterprises .msie6 .profile-list .controll a, |
65 | .controller-friends .msie6 .profile-list .controll a, | 71 | .controller-friends .msie6 .profile-list .controll a, |
72 | +.controller-folloed_people .msie6 .profile-list .controll a, | ||
66 | .profiles-suggestions .msie6 .profile-list .controll a { | 73 | .profiles-suggestions .msie6 .profile-list .controll a { |
67 | width: 0px; | 74 | width: 0px; |
68 | } | 75 | } |
69 | .controller-favorite_enterprises .button-bar, | 76 | .controller-favorite_enterprises .button-bar, |
70 | .controller-friends .button-bar, | 77 | .controller-friends .button-bar, |
78 | +.controller-followers .button-bar, | ||
71 | .profiles-suggestions .button-bar { | 79 | .profiles-suggestions .button-bar { |
72 | clear: both; | 80 | clear: both; |
73 | padding-top: 20px; | 81 | padding-top: 20px; |
@@ -208,22 +216,35 @@ | @@ -208,22 +216,35 @@ | ||
208 | font-size: 12px; | 216 | font-size: 12px; |
209 | } | 217 | } |
210 | .action-profile-members .profile_link{ | 218 | .action-profile-members .profile_link{ |
211 | - position: relative; | 219 | + position: relative; |
212 | } | 220 | } |
213 | .action-profile-members .profile_link span.new-profile:last-child{ | 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 | .action-profile-members .profile_link .fn{ | 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 | } |
public/stylesheets/profile.scss
@@ -0,0 +1,129 @@ | @@ -0,0 +1,129 @@ | ||
1 | +require_relative "../test_helper" | ||
2 | +require 'circles_controller' | ||
3 | + | ||
4 | +class CirclesControllerTest < ActionController::TestCase | ||
5 | + | ||
6 | + def setup | ||
7 | + @controller = CirclesController.new | ||
8 | + @person = create_user('person').person | ||
9 | + login_as(@person.identifier) | ||
10 | + end | ||
11 | + | ||
12 | + should 'return all circles of a profile' do | ||
13 | + circle1 = Circle.create!(:name => "circle1", :person => @person, :profile_type => 'Person') | ||
14 | + circle2 = Circle.create!(:name => "circle2", :person => @person, :profile_type => 'Person') | ||
15 | + get :index, :profile => @person.identifier | ||
16 | + | ||
17 | + assert_equivalent [circle1, circle2], assigns[:circles] | ||
18 | + end | ||
19 | + | ||
20 | + should 'initialize an empty circle for creation' do | ||
21 | + get :new, :profile => @person.identifier | ||
22 | + assert_nil assigns[:circle].id | ||
23 | + assert_nil assigns[:circle].name | ||
24 | + end | ||
25 | + | ||
26 | + should 'create a new circle' do | ||
27 | + assert_difference '@person.circles.count' do | ||
28 | + post :create, :profile => @person.identifier, | ||
29 | + :circle => { :name => 'circle' , :profile_type => Person.name} | ||
30 | + end | ||
31 | + assert_redirected_to :action => :index | ||
32 | + end | ||
33 | + | ||
34 | + should 'not create a circle without a name' do | ||
35 | + assert_no_difference '@person.circles.count' do | ||
36 | + post :create, :profile => @person.identifier, :circle => { :name => nil } | ||
37 | + end | ||
38 | + assert_template :new | ||
39 | + end | ||
40 | + | ||
41 | + should 'retrieve an existing circle when editing' do | ||
42 | + circle = Circle.create!(:name => "circle", :person => @person, :profile_type => 'Person') | ||
43 | + get :edit, :profile => @person.identifier, :id => circle.id | ||
44 | + assert_equal circle.name, assigns[:circle].name | ||
45 | + end | ||
46 | + | ||
47 | + should 'return 404 when editing a circle that does not exist' do | ||
48 | + get :edit, :profile => @person.identifier, :id => "nope" | ||
49 | + assert_response 404 | ||
50 | + end | ||
51 | + | ||
52 | + should 'update an existing circle' do | ||
53 | + circle = Circle.create!(:name => "circle", :person => @person, :profile_type => 'Person') | ||
54 | + post :update, :profile => @person.identifier, :id => circle.id, | ||
55 | + :circle => { :name => "new name" } | ||
56 | + | ||
57 | + circle.reload | ||
58 | + assert_equal "new name", circle.name | ||
59 | + assert_redirected_to :action => :index | ||
60 | + end | ||
61 | + | ||
62 | + should 'not update an existing circle without a name' do | ||
63 | + circle = Circle.create!(:name => "circle", :person => @person, :profile_type => 'Person') | ||
64 | + post :update, :profile => @person.identifier, :id => circle.id, | ||
65 | + :circle => { :name => nil } | ||
66 | + | ||
67 | + circle.reload | ||
68 | + assert_equal "circle", circle.name | ||
69 | + assert_template :edit | ||
70 | + end | ||
71 | + | ||
72 | + should 'return 404 when updating a circle that does not exist' do | ||
73 | + post :update, :profile => @person.identifier, :id => "nope", :name => "new name" | ||
74 | + assert_response 404 | ||
75 | + end | ||
76 | + | ||
77 | + should 'destroy an existing circle and update related profiles' do | ||
78 | + circle = Circle.create!(:name => "circle", :person => @person, :profile_type => 'Person') | ||
79 | + follower = fast_create(ProfileFollower, :profile_id => fast_create(Person).id, | ||
80 | + :circle_id => circle.id) | ||
81 | + | ||
82 | + assert_difference "@person.circles.count", -1 do | ||
83 | + post :destroy, :profile => @person.identifier, :id => circle.id | ||
84 | + end | ||
85 | + | ||
86 | + follower.reload | ||
87 | + assert_nil follower.circle | ||
88 | + end | ||
89 | + | ||
90 | + should 'not destroy an existing circle if action is not post' do | ||
91 | + circle = Circle.create!(:name => "circle", :person => @person, :profile_type => 'Person') | ||
92 | + | ||
93 | + assert_no_difference "@person.circles.count" do | ||
94 | + get :destroy, :profile => @person.identifier, :id => circle.id | ||
95 | + end | ||
96 | + assert_response 404 | ||
97 | + end | ||
98 | + | ||
99 | + should 'return 404 when deleting and circle that does not exist' do | ||
100 | + get :destroy, :profile => @person.identifier, :id => "nope" | ||
101 | + assert_response 404 | ||
102 | + end | ||
103 | + | ||
104 | + should 'return 404 for xhr_create if request is not xhr' do | ||
105 | + post :xhr_create, :profile => @person.identifier | ||
106 | + assert_response 404 | ||
107 | + end | ||
108 | + | ||
109 | + should 'return 400 if not possible to create circle via xhr' do | ||
110 | + xhr :post, :xhr_create, :profile => @person.identifier, | ||
111 | + :circle => { :name => 'Invalid Circle' } | ||
112 | + assert_response 400 | ||
113 | + end | ||
114 | + | ||
115 | + should 'create a new circle via xhr' do | ||
116 | + xhr :post, :xhr_create, :profile => @person.identifier, | ||
117 | + :circle => { :name => 'A Brand New Circle', | ||
118 | + :profile_type => Person.name } | ||
119 | + assert_response 201 | ||
120 | + assert_match /A Brand New Circle/, response.body | ||
121 | + end | ||
122 | + | ||
123 | + should 'not create a new circle via xhr with an invalid profile_type' do | ||
124 | + xhr :post, :xhr_create, :profile => @person.identifier, | ||
125 | + :circle => { :name => 'A Brand New Circle', | ||
126 | + :profile_type => '__invalid__' } | ||
127 | + assert_response 400 | ||
128 | + end | ||
129 | +end |
@@ -0,0 +1,58 @@ | @@ -0,0 +1,58 @@ | ||
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 | + circle = Circle.create!(:person=> @profile, :name => "Zombies", :profile_type => 'Person') | ||
13 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle.id) | ||
14 | + | ||
15 | + get :index, :profile => @profile.identifier | ||
16 | + assert_includes assigns(:followed_people), person | ||
17 | + end | ||
18 | + | ||
19 | + should 'return filtered followed people list' do | ||
20 | + login_as(@profile.identifier) | ||
21 | + person = fast_create(Person) | ||
22 | + community = fast_create(Community) | ||
23 | + circle = Circle.create!(:person=> @profile, :name => "Zombies", :profile_type => 'Person') | ||
24 | + circle2 = Circle.create!(:person=> @profile, :name => "Teams", :profile_type => 'Community') | ||
25 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle.id) | ||
26 | + fast_create(ProfileFollower, :profile_id => community.id, :circle_id => circle2.id) | ||
27 | + | ||
28 | + get :index, :profile => @profile.identifier, :filter => "Community" | ||
29 | + assert_equal assigns(:followed_people), [community] | ||
30 | + | ||
31 | + get :index, :profile => @profile.identifier, :filter => "Person" | ||
32 | + assert_equal assigns(:followed_people), [person] | ||
33 | + end | ||
34 | + | ||
35 | + should 'redirect to login page if not logged in' do | ||
36 | + get :index, :profile => @profile.identifier | ||
37 | + assert_redirected_to :controller => 'account', :action => 'login' | ||
38 | + end | ||
39 | + | ||
40 | + should 'render set category modal' do | ||
41 | + login_as(@profile.identifier) | ||
42 | + person = fast_create(Person) | ||
43 | + get :set_category_modal, :profile => @profile.identifier, :followed_profile_id => person.id | ||
44 | + assert_tag :tag => "input", :attributes => { :id => "followed_profile_id", :value => person.id } | ||
45 | + end | ||
46 | + | ||
47 | + should 'update followed person category' do | ||
48 | + login_as(@profile.identifier) | ||
49 | + person = fast_create(Person) | ||
50 | + circle = Circle.create!(:person=> @profile, :name => "Zombies", :profile_type => 'Person') | ||
51 | + circle2 = Circle.create!(:person=> @profile, :name => "DotA", :profile_type => 'Person') | ||
52 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle.id) | ||
53 | + | ||
54 | + post :update_category, :profile => @profile.identifier, :circles => {"DotA"=> circle2.id}, :followed_profile_id => person.id | ||
55 | + assert_equivalent ProfileFollower.with_profile(person).with_follower(@profile).map(&:circle), [circle2] | ||
56 | + end | ||
57 | + | ||
58 | +end |
test/functional/profile_controller_test.rb
@@ -771,12 +771,15 @@ class ProfileControllerTest < ActionController::TestCase | @@ -771,12 +771,15 @@ class ProfileControllerTest < ActionController::TestCase | ||
771 | assert_equal 15, assigns(:activities).size | 771 | assert_equal 15, assigns(:activities).size |
772 | end | 772 | end |
773 | 773 | ||
774 | - should 'not see the friends activities in the current profile' do | 774 | + should 'not see the followers activities in the current profile' do |
775 | + circle = Circle.create!(:person=> profile, :name => "Zombies", :profile_type => 'Person') | ||
776 | + | ||
775 | p2 = create_user.person | 777 | p2 = create_user.person |
776 | - refute profile.is_a_friend?(p2) | 778 | + refute profile.follows?(p2) |
777 | p3 = create_user.person | 779 | p3 = create_user.person |
778 | - p3.add_friend(profile) | ||
779 | - assert p3.is_a_friend?(profile) | 780 | + profile.follow(p3, circle) |
781 | + assert profile.follows?(p3) | ||
782 | + | ||
780 | ActionTracker::Record.destroy_all | 783 | ActionTracker::Record.destroy_all |
781 | 784 | ||
782 | scrap1 = create(Scrap, defaults_for_scrap(:sender => p2, :receiver => p3)) | 785 | scrap1 = create(Scrap, defaults_for_scrap(:sender => p2, :receiver => p3)) |
@@ -964,7 +967,11 @@ class ProfileControllerTest < ActionController::TestCase | @@ -964,7 +967,11 @@ class ProfileControllerTest < ActionController::TestCase | ||
964 | should 'have activities defined if logged in and is following profile' do | 967 | should 'have activities defined if logged in and is following profile' do |
965 | login_as(profile.identifier) | 968 | login_as(profile.identifier) |
966 | p1= fast_create(Person) | 969 | p1= fast_create(Person) |
967 | - p1.add_friend(profile) | 970 | + |
971 | + circle = Circle.create!(:person=> profile, :name => "Zombies", :profile_type => 'Person') | ||
972 | + | ||
973 | + profile.follow(p1, circle) | ||
974 | + | ||
968 | ActionTracker::Record.destroy_all | 975 | ActionTracker::Record.destroy_all |
969 | get :index, :profile => p1.identifier | 976 | get :index, :profile => p1.identifier |
970 | assert_equal [], assigns(:activities) | 977 | assert_equal [], assigns(:activities) |
@@ -1932,4 +1939,110 @@ class ProfileControllerTest < ActionController::TestCase | @@ -1932,4 +1939,110 @@ class ProfileControllerTest < ActionController::TestCase | ||
1932 | assert_redirected_to :controller => 'account', :action => 'login' | 1939 | assert_redirected_to :controller => 'account', :action => 'login' |
1933 | end | 1940 | end |
1934 | 1941 | ||
1942 | + should 'not follow a user without defining a circle' do | ||
1943 | + login_as(@profile.identifier) | ||
1944 | + person = fast_create(Person) | ||
1945 | + assert_no_difference 'ProfileFollower.count' do | ||
1946 | + post :follow, :profile => person.identifier, :circles => {} | ||
1947 | + end | ||
1948 | + end | ||
1949 | + | ||
1950 | + should "not follow user if not logged" do | ||
1951 | + person = fast_create(Person) | ||
1952 | + get :follow, :profile => person.identifier | ||
1953 | + | ||
1954 | + assert_redirected_to :controller => 'account', :action => 'login' | ||
1955 | + end | ||
1956 | + | ||
1957 | + should 'follow a user with a circle' do | ||
1958 | + login_as(@profile.identifier) | ||
1959 | + person = fast_create(Person) | ||
1960 | + | ||
1961 | + circle = Circle.create!(:person=> @profile, :name => "Zombies", :profile_type => 'Person') | ||
1962 | + | ||
1963 | + assert_difference 'ProfileFollower.count' do | ||
1964 | + post :follow, :profile => person.identifier, :circles => {"Zombies" => circle.id} | ||
1965 | + end | ||
1966 | + end | ||
1967 | + | ||
1968 | + should 'follow a user with more than one circle' do | ||
1969 | + login_as(@profile.identifier) | ||
1970 | + person = fast_create(Person) | ||
1971 | + | ||
1972 | + circle = Circle.create!(:person=> @profile, :name => "Zombies", :profile_type => 'Person') | ||
1973 | + circle2 = Circle.create!(:person=> @profile, :name => "Brainsss", :profile_type => 'Person') | ||
1974 | + | ||
1975 | + assert_difference 'ProfileFollower.count', 2 do | ||
1976 | + post :follow, :profile => person.identifier, :circles => {"Zombies" => circle.id, "Brainsss"=> circle2.id} | ||
1977 | + end | ||
1978 | + end | ||
1979 | + | ||
1980 | + should 'not follow a user with no circle selected' do | ||
1981 | + login_as(@profile.identifier) | ||
1982 | + person = fast_create(Person) | ||
1983 | + | ||
1984 | + circle = Circle.create!(:person=> @profile, :name => "Zombies", :profile_type => 'Person') | ||
1985 | + circle2 = Circle.create!(:person=> @profile, :name => "Brainsss", :profile_type => 'Person') | ||
1986 | + | ||
1987 | + assert_no_difference 'ProfileFollower.count' do | ||
1988 | + post :follow, :profile => person.identifier, :circles => {"Zombies" => "0", "Brainsss" => "0"} | ||
1989 | + end | ||
1990 | + | ||
1991 | + assert_match /Select at least one circle to follow/, response.body | ||
1992 | + end | ||
1993 | + | ||
1994 | + should 'not follow if current_person already follows the person' do | ||
1995 | + login_as(@profile.identifier) | ||
1996 | + person = fast_create(Person) | ||
1997 | + | ||
1998 | + circle = Circle.create!(:person=> @profile, :name => "Zombies", :profile_type => 'Person') | ||
1999 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle.id) | ||
2000 | + | ||
2001 | + assert_no_difference 'ProfileFollower.count' do | ||
2002 | + post :follow, :profile => person.identifier, :follow => { :circles => {"Zombies" => circle.id} } | ||
2003 | + end | ||
2004 | + assert_response 400 | ||
2005 | + end | ||
2006 | + | ||
2007 | + should "not unfollow user if not logged" do | ||
2008 | + person = fast_create(Person) | ||
2009 | + get :unfollow, :profile => person.identifier | ||
2010 | + | ||
2011 | + assert_redirected_to :controller => 'account', :action => 'login' | ||
2012 | + end | ||
2013 | + | ||
2014 | + should "unfollow a followed person" do | ||
2015 | + login_as(@profile.identifier) | ||
2016 | + person = fast_create(Person) | ||
2017 | + | ||
2018 | + circle = Circle.create!(:person=> @profile, :name => "Zombies", :profile_type => 'Person') | ||
2019 | + follower = fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle.id) | ||
2020 | + | ||
2021 | + assert_not_nil follower | ||
2022 | + | ||
2023 | + get :unfollow, :profile => person.identifier | ||
2024 | + follower = ProfileFollower.find_by(:profile_id => person.id, :circle_id => circle.id) | ||
2025 | + assert_nil follower | ||
2026 | + end | ||
2027 | + | ||
2028 | + should "not unfollow a not followed person" do | ||
2029 | + login_as(@profile.identifier) | ||
2030 | + person = fast_create(Person) | ||
2031 | + | ||
2032 | + assert_no_difference 'ProfileFollower.count' do | ||
2033 | + get :unfollow, :profile => person.identifier | ||
2034 | + end | ||
2035 | + end | ||
2036 | + | ||
2037 | + should "redirect to page after unfollow" do | ||
2038 | + login_as(@profile.identifier) | ||
2039 | + person = fast_create(Person) | ||
2040 | + | ||
2041 | + circle = Circle.create!(:person=> @profile, :name => "Zombies", :profile_type => 'Person') | ||
2042 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle.id) | ||
2043 | + | ||
2044 | + get :unfollow, :profile => person.identifier, :redirect_to => "/some/url" | ||
2045 | + assert_redirected_to "/some/url" | ||
2046 | + end | ||
2047 | + | ||
1935 | end | 2048 | end |
test/unit/article_test.rb
@@ -1099,9 +1099,10 @@ class ArticleTest < ActiveSupport::TestCase | @@ -1099,9 +1099,10 @@ class ArticleTest < ActiveSupport::TestCase | ||
1099 | assert_equal 3, ActionTrackerNotification.where(action_tracker_id: second_activity.id).count | 1099 | assert_equal 3, ActionTrackerNotification.where(action_tracker_id: second_activity.id).count |
1100 | end | 1100 | end |
1101 | 1101 | ||
1102 | - should 'create notifications to friends when creating an article' do | 1102 | + should 'create notifications to followers when creating an article' do |
1103 | friend = fast_create(Person) | 1103 | friend = fast_create(Person) |
1104 | - profile.add_friend(friend) | 1104 | + circle = Circle.create!(:person=> friend, :name => "Zombies", :profile_type => 'Person') |
1105 | + friend.follow(profile, circle) | ||
1105 | Article.destroy_all | 1106 | Article.destroy_all |
1106 | ActionTracker::Record.destroy_all | 1107 | ActionTracker::Record.destroy_all |
1107 | ActionTrackerNotification.destroy_all | 1108 | ActionTrackerNotification.destroy_all |
@@ -1112,9 +1113,10 @@ class ArticleTest < ActiveSupport::TestCase | @@ -1112,9 +1113,10 @@ class ArticleTest < ActiveSupport::TestCase | ||
1112 | assert_equal friend, ActionTrackerNotification.last.profile | 1113 | assert_equal friend, ActionTrackerNotification.last.profile |
1113 | end | 1114 | end |
1114 | 1115 | ||
1115 | - should 'create the notification to the friend when one friend has the notification and the other no' do | 1116 | + should 'create the notification to the follower when one follower has the notification and the other no' do |
1116 | f1 = fast_create(Person) | 1117 | f1 = fast_create(Person) |
1117 | - profile.add_friend(f1) | 1118 | + circle = Circle.create!(:person=> f1, :name => "Zombies", :profile_type => 'Person') |
1119 | + f1.follow(profile, circle) | ||
1118 | 1120 | ||
1119 | User.current = profile.user | 1121 | User.current = profile.user |
1120 | article = create TinyMceArticle, :name => 'Tracked Article 1', :profile_id => profile.id | 1122 | article = create TinyMceArticle, :name => 'Tracked Article 1', :profile_id => profile.id |
@@ -1123,16 +1125,22 @@ class ArticleTest < ActiveSupport::TestCase | @@ -1123,16 +1125,22 @@ class ArticleTest < ActiveSupport::TestCase | ||
1123 | assert_equal 2, ActionTrackerNotification.where(action_tracker_id: article.activity.id).count | 1125 | assert_equal 2, ActionTrackerNotification.where(action_tracker_id: article.activity.id).count |
1124 | 1126 | ||
1125 | f2 = fast_create(Person) | 1127 | f2 = fast_create(Person) |
1126 | - profile.add_friend(f2) | 1128 | + circle2 = Circle.create!(:person=> f2, :name => "Zombies", :profile_type => 'Person') |
1129 | + f2.follow(profile, circle2) | ||
1130 | + | ||
1127 | article2 = create TinyMceArticle, :name => 'Tracked Article 2', :profile_id => profile.id | 1131 | article2 = create TinyMceArticle, :name => 'Tracked Article 2', :profile_id => profile.id |
1128 | assert_equal 2, ActionTracker::Record.where(verb: 'create_article').count | 1132 | assert_equal 2, ActionTracker::Record.where(verb: 'create_article').count |
1129 | process_delayed_job_queue | 1133 | process_delayed_job_queue |
1130 | assert_equal 3, ActionTrackerNotification.where(action_tracker_id: article2.activity.id).count | 1134 | assert_equal 3, ActionTrackerNotification.where(action_tracker_id: article2.activity.id).count |
1131 | end | 1135 | end |
1132 | 1136 | ||
1133 | - should 'destroy activity and notifications of friends when destroying an article' do | 1137 | + should 'destroy activity and notifications of followers when destroying an article' do |
1134 | friend = fast_create(Person) | 1138 | friend = fast_create(Person) |
1135 | - profile.add_friend(friend) | 1139 | + |
1140 | + circle = Circle.create!(:person=> friend, :name => "Zombies", :profile_type => 'Person') | ||
1141 | + | ||
1142 | + friend.follow(profile, circle) | ||
1143 | + | ||
1136 | Article.destroy_all | 1144 | Article.destroy_all |
1137 | ActionTracker::Record.destroy_all | 1145 | ActionTracker::Record.destroy_all |
1138 | ActionTrackerNotification.destroy_all | 1146 | ActionTrackerNotification.destroy_all |
test/unit/friendship_test.rb
@@ -28,14 +28,14 @@ class FriendshipTest < ActiveSupport::TestCase | @@ -28,14 +28,14 @@ class FriendshipTest < ActiveSupport::TestCase | ||
28 | f.person = a | 28 | f.person = a |
29 | f.friend = b | 29 | f.friend = b |
30 | f.save! | 30 | f.save! |
31 | - ta = ActionTracker::Record.last | 31 | + ta = ActionTracker::Record.where(:target_type => "Friendship").last |
32 | assert_equal a, ta.user | 32 | assert_equal a, ta.user |
33 | assert_equal 'b', ta.get_friend_name[0] | 33 | assert_equal 'b', ta.get_friend_name[0] |
34 | f = Friendship.new | 34 | f = Friendship.new |
35 | f.person = a | 35 | f.person = a |
36 | f.friend = c | 36 | f.friend = c |
37 | f.save! | 37 | f.save! |
38 | - ta = ActionTracker::Record.last | 38 | + ta = ActionTracker::Record.where(:target_type => "Friendship").last |
39 | assert_equal a, ta.user | 39 | assert_equal a, ta.user |
40 | assert_equal 'c', ta.get_friend_name[1] | 40 | assert_equal 'c', ta.get_friend_name[1] |
41 | end | 41 | end |
@@ -46,14 +46,14 @@ class FriendshipTest < ActiveSupport::TestCase | @@ -46,14 +46,14 @@ class FriendshipTest < ActiveSupport::TestCase | ||
46 | f.person = a | 46 | f.person = a |
47 | f.friend = b | 47 | f.friend = b |
48 | f.save! | 48 | f.save! |
49 | - ta = ActionTracker::Record.last | 49 | + ta = ActionTracker::Record.where(:target_type => "Friendship").last |
50 | assert_equal a, ta.user | 50 | assert_equal a, ta.user |
51 | assert_equal ['b'], ta.get_friend_name | 51 | assert_equal ['b'], ta.get_friend_name |
52 | f = Friendship.new | 52 | f = Friendship.new |
53 | f.person = b | 53 | f.person = b |
54 | f.friend = a | 54 | f.friend = a |
55 | f.save! | 55 | f.save! |
56 | - ta = ActionTracker::Record.last | 56 | + ta = ActionTracker::Record.where(:target_type => "Friendship").last |
57 | assert_equal b, ta.user | 57 | assert_equal b, ta.user |
58 | assert_equal ['a'], ta.get_friend_name | 58 | assert_equal ['a'], ta.get_friend_name |
59 | end | 59 | end |
@@ -72,4 +72,55 @@ class FriendshipTest < ActiveSupport::TestCase | @@ -72,4 +72,55 @@ class FriendshipTest < ActiveSupport::TestCase | ||
72 | assert_not_includes p2.friends(true), p1 | 72 | assert_not_includes p2.friends(true), p1 |
73 | end | 73 | end |
74 | 74 | ||
75 | + should 'add follower when adding friend' do | ||
76 | + p1 = create_user('testuser1').person | ||
77 | + p2 = create_user('testuser2').person | ||
78 | + | ||
79 | + assert_difference 'ProfileFollower.count', 2 do | ||
80 | + p1.add_friend(p2, 'friends') | ||
81 | + p2.add_friend(p1, 'friends') | ||
82 | + end | ||
83 | + | ||
84 | + assert_includes p1.followers(true), p2 | ||
85 | + assert_includes p2.followers(true), p1 | ||
86 | + end | ||
87 | + | ||
88 | + should 'remove follower when a friend removal occurs' do | ||
89 | + p1 = create_user('testuser1').person | ||
90 | + p2 = create_user('testuser2').person | ||
91 | + | ||
92 | + p1.add_friend(p2, 'friends') | ||
93 | + p2.add_friend(p1, 'friends') | ||
94 | + | ||
95 | + Friendship.remove_friendship(p1, p2) | ||
96 | + | ||
97 | + assert_not_includes p1.followers(true), p2 | ||
98 | + assert_not_includes p2.followers(true), p1 | ||
99 | + end | ||
100 | + | ||
101 | + should 'keep friendship intact when stop following' do | ||
102 | + p1 = create_user('testuser1').person | ||
103 | + p2 = create_user('testuser2').person | ||
104 | + | ||
105 | + p1.add_friend(p2, 'friends') | ||
106 | + p2.add_friend(p1, 'friends') | ||
107 | + | ||
108 | + p1.unfollow(p2) | ||
109 | + | ||
110 | + assert_includes p1.friends(true), p2 | ||
111 | + assert_includes p2.friends(true), p1 | ||
112 | + end | ||
113 | + | ||
114 | + should 'do not add friendship when start following' do | ||
115 | + p1 = create_user('testuser1').person | ||
116 | + p2 = create_user('testuser2').person | ||
117 | + | ||
118 | + circle1 = Circle.create!(:person=> p1, :name => "Zombies", :profile_type => 'Person') | ||
119 | + circle2 = Circle.create!(:person=> p2, :name => "Zombies", :profile_type => 'Person') | ||
120 | + p1.follow(p2, circle1) | ||
121 | + p2.follow(p1, circle2) | ||
122 | + | ||
123 | + assert_not_includes p1.friends(true), p2 | ||
124 | + assert_not_includes p2.friends(true), p1 | ||
125 | + end | ||
75 | end | 126 | end |
test/unit/notify_activity_to_profiles_job_test.rb
@@ -24,15 +24,21 @@ class NotifyActivityToProfilesJobTest < ActiveSupport::TestCase | @@ -24,15 +24,21 @@ class NotifyActivityToProfilesJobTest < ActiveSupport::TestCase | ||
24 | end | 24 | end |
25 | end | 25 | end |
26 | 26 | ||
27 | - should 'notify just the users and his friends tracking user actions' do | 27 | + should 'notify just the users and his followers tracking user actions' do |
28 | person = fast_create(Person) | 28 | person = fast_create(Person) |
29 | community = fast_create(Community) | 29 | community = fast_create(Community) |
30 | action_tracker = fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person.id, :target_type => 'Profile', :verb => 'create_article') | 30 | action_tracker = fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person.id, :target_type => 'Profile', :verb => 'create_article') |
31 | refute NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY.include?(action_tracker.verb) | 31 | refute NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY.include?(action_tracker.verb) |
32 | p1, p2, m1, m2 = fast_create(Person), fast_create(Person), fast_create(Person), fast_create(Person) | 32 | p1, p2, m1, m2 = fast_create(Person), fast_create(Person), fast_create(Person), fast_create(Person) |
33 | - fast_create(Friendship, :person_id => person.id, :friend_id => p1.id) | ||
34 | - fast_create(Friendship, :person_id => person.id, :friend_id => p2.id) | ||
35 | - fast_create(Friendship, :person_id => p1.id, :friend_id => m1.id) | 33 | + |
34 | + circle1 = Circle.create!(:person=> p1, :name => "Zombies", :profile_type => 'Person') | ||
35 | + circle2 = Circle.create!(:person=> p2, :name => "Zombies", :profile_type => 'Person') | ||
36 | + circle = Circle.create!(:person=> person, :name => "Zombies", :profile_type => 'Person') | ||
37 | + | ||
38 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle1.id) | ||
39 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle2.id) | ||
40 | + fast_create(ProfileFollower, :profile_id => m1.id, :circle_id => circle.id) | ||
41 | + | ||
36 | fast_create(RoleAssignment, :accessor_id => m2.id, :role_id => 3, :resource_id => community.id) | 42 | fast_create(RoleAssignment, :accessor_id => m2.id, :role_id => 3, :resource_id => community.id) |
37 | ActionTrackerNotification.delete_all | 43 | ActionTrackerNotification.delete_all |
38 | job = NotifyActivityToProfilesJob.new(action_tracker.id) | 44 | job = NotifyActivityToProfilesJob.new(action_tracker.id) |
@@ -66,23 +72,24 @@ class NotifyActivityToProfilesJobTest < ActiveSupport::TestCase | @@ -66,23 +72,24 @@ class NotifyActivityToProfilesJobTest < ActiveSupport::TestCase | ||
66 | end | 72 | end |
67 | end | 73 | end |
68 | 74 | ||
69 | - should 'notify users its friends, the community and its members' do | 75 | + should 'notify users its followers, the community and its members' do |
70 | person = fast_create(Person) | 76 | person = fast_create(Person) |
71 | community = fast_create(Community) | 77 | community = fast_create(Community) |
72 | action_tracker = fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person.id, :target_type => 'Profile', :target_id => community.id, :verb => 'create_article') | 78 | action_tracker = fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person.id, :target_type => 'Profile', :target_id => community.id, :verb => 'create_article') |
73 | refute NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY.include?(action_tracker.verb) | 79 | refute NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY.include?(action_tracker.verb) |
74 | p1, p2, m1, m2 = fast_create(Person), fast_create(Person), fast_create(Person), fast_create(Person) | 80 | p1, p2, m1, m2 = fast_create(Person), fast_create(Person), fast_create(Person), fast_create(Person) |
75 | - fast_create(Friendship, :person_id => person.id, :friend_id => p1.id) | ||
76 | - fast_create(Friendship, :person_id => person.id, :friend_id => p2.id) | 81 | + |
82 | + circle1 = Circle.create!(:person=> p1, :name => "Zombies", :profile_type => 'Person') | ||
83 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle1.id) | ||
84 | + | ||
77 | fast_create(RoleAssignment, :accessor_id => m1.id, :role_id => 3, :resource_id => community.id) | 85 | fast_create(RoleAssignment, :accessor_id => m1.id, :role_id => 3, :resource_id => community.id) |
78 | fast_create(RoleAssignment, :accessor_id => m2.id, :role_id => 3, :resource_id => community.id) | 86 | fast_create(RoleAssignment, :accessor_id => m2.id, :role_id => 3, :resource_id => community.id) |
79 | ActionTrackerNotification.delete_all | 87 | ActionTrackerNotification.delete_all |
80 | job = NotifyActivityToProfilesJob.new(action_tracker.id) | 88 | job = NotifyActivityToProfilesJob.new(action_tracker.id) |
81 | job.perform | 89 | job.perform |
82 | process_delayed_job_queue | 90 | process_delayed_job_queue |
83 | - | ||
84 | - assert_equal 6, ActionTrackerNotification.count | ||
85 | - [person, community, p1, p2, m1, m2].each do |profile| | 91 | + assert_equal 5, ActionTrackerNotification.count |
92 | + [person, community, p1, m1, m2].each do |profile| | ||
86 | notification = ActionTrackerNotification.find_by profile_id: profile.id | 93 | notification = ActionTrackerNotification.find_by profile_id: profile.id |
87 | assert_equal action_tracker, notification.action_tracker | 94 | assert_equal action_tracker, notification.action_tracker |
88 | end | 95 | end |
@@ -119,8 +126,13 @@ class NotifyActivityToProfilesJobTest < ActiveSupport::TestCase | @@ -119,8 +126,13 @@ class NotifyActivityToProfilesJobTest < ActiveSupport::TestCase | ||
119 | action_tracker = fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person.id, :target_type => 'Profile', :target_id => community.id, :verb => 'join_community') | 126 | action_tracker = fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person.id, :target_type => 'Profile', :target_id => community.id, :verb => 'join_community') |
120 | refute NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY.include?(action_tracker.verb) | 127 | refute NotifyActivityToProfilesJob::NOTIFY_ONLY_COMMUNITY.include?(action_tracker.verb) |
121 | p1, p2, m1, m2 = fast_create(Person), fast_create(Person), fast_create(Person), fast_create(Person) | 128 | p1, p2, m1, m2 = fast_create(Person), fast_create(Person), fast_create(Person), fast_create(Person) |
122 | - fast_create(Friendship, :person_id => person.id, :friend_id => p1.id) | ||
123 | - fast_create(Friendship, :person_id => person.id, :friend_id => p2.id) | 129 | + |
130 | + circle1 = Circle.create!(:person=> p1, :name => "Zombies", :profile_type => 'Person') | ||
131 | + circle2 = Circle.create!(:person=> p2, :name => "Zombies", :profile_type => 'Person') | ||
132 | + | ||
133 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle1.id) | ||
134 | + fast_create(ProfileFollower, :profile_id => person.id, :circle_id => circle2.id) | ||
135 | + | ||
124 | fast_create(RoleAssignment, :accessor_id => m1.id, :role_id => 3, :resource_id => community.id) | 136 | fast_create(RoleAssignment, :accessor_id => m1.id, :role_id => 3, :resource_id => community.id) |
125 | fast_create(RoleAssignment, :accessor_id => m2.id, :role_id => 3, :resource_id => community.id) | 137 | fast_create(RoleAssignment, :accessor_id => m2.id, :role_id => 3, :resource_id => community.id) |
126 | ActionTrackerNotification.delete_all | 138 | ActionTrackerNotification.delete_all |
test/unit/person_notifier_test.rb
@@ -178,6 +178,7 @@ class PersonNotifierTest < ActiveSupport::TestCase | @@ -178,6 +178,7 @@ class PersonNotifierTest < ActiveSupport::TestCase | ||
178 | update_product: -> { create Product, profile: @profile, product_category: create(ProductCategory, environment: Environment.default) }, | 178 | update_product: -> { create Product, profile: @profile, product_category: create(ProductCategory, environment: Environment.default) }, |
179 | remove_product: -> { create Product, profile: @profile, product_category: create(ProductCategory, environment: Environment.default) }, | 179 | remove_product: -> { create Product, profile: @profile, product_category: create(ProductCategory, environment: Environment.default) }, |
180 | favorite_enterprise: -> { create FavoriteEnterprisePerson, enterprise: create(Enterprise), person: @member }, | 180 | favorite_enterprise: -> { create FavoriteEnterprisePerson, enterprise: create(Enterprise), person: @member }, |
181 | + new_follower: -> { @member } | ||
181 | } | 182 | } |
182 | 183 | ||
183 | ActionTrackerConfig.verb_names.each do |verb| | 184 | ActionTrackerConfig.verb_names.each do |verb| |
@@ -197,6 +198,7 @@ class PersonNotifierTest < ActiveSupport::TestCase | @@ -197,6 +198,7 @@ class PersonNotifierTest < ActiveSupport::TestCase | ||
197 | 'friend_url' => '/', 'friend_profile_custom_icon' => [], 'friend_name' => ['joe'], | 198 | 'friend_url' => '/', 'friend_profile_custom_icon' => [], 'friend_name' => ['joe'], |
198 | 'resource_name' => ['resource'], 'resource_profile_custom_icon' => [], 'resource_url' => ['/'], | 199 | 'resource_name' => ['resource'], 'resource_profile_custom_icon' => [], 'resource_url' => ['/'], |
199 | 'enterprise_name' => 'coop', 'enterprise_url' => '/coop', | 200 | 'enterprise_name' => 'coop', 'enterprise_url' => '/coop', |
201 | + 'follower_url' => '/', 'follower_profile_custom_icon' => [], 'follower_name' => ['joe'], | ||
200 | 'view_url'=> ['/'], 'thumbnail_path' => ['1'], | 202 | 'view_url'=> ['/'], 'thumbnail_path' => ['1'], |
201 | } | 203 | } |
202 | a.get_url = '' | 204 | a.get_url = '' |
test/unit/person_test.rb
@@ -728,7 +728,7 @@ class PersonTest < ActiveSupport::TestCase | @@ -728,7 +728,7 @@ class PersonTest < ActiveSupport::TestCase | ||
728 | assert_equal [s4], p2.scraps_received.not_replies | 728 | assert_equal [s4], p2.scraps_received.not_replies |
729 | end | 729 | end |
730 | 730 | ||
731 | - should "the followed_by method be protected and true to the person friends and herself by default" do | 731 | + should "the followed_by method return true to the person friends and herself by default" do |
732 | p1 = fast_create(Person) | 732 | p1 = fast_create(Person) |
733 | p2 = fast_create(Person) | 733 | p2 = fast_create(Person) |
734 | p3 = fast_create(Person) | 734 | p3 = fast_create(Person) |
@@ -740,9 +740,9 @@ class PersonTest < ActiveSupport::TestCase | @@ -740,9 +740,9 @@ class PersonTest < ActiveSupport::TestCase | ||
740 | assert p1.is_a_friend?(p4) | 740 | assert p1.is_a_friend?(p4) |
741 | 741 | ||
742 | assert_equal true, p1.send(:followed_by?,p1) | 742 | assert_equal true, p1.send(:followed_by?,p1) |
743 | - assert_equal true, p1.send(:followed_by?,p2) | ||
744 | - assert_equal true, p1.send(:followed_by?,p4) | ||
745 | - assert_equal false, p1.send(:followed_by?,p3) | 743 | + assert_equal true, p2.send(:followed_by?,p1) |
744 | + assert_equal true, p4.send(:followed_by?,p1) | ||
745 | + assert_equal false, p3.send(:followed_by?,p1) | ||
746 | end | 746 | end |
747 | 747 | ||
748 | should "the person follows her friends and herself by default" do | 748 | should "the person follows her friends and herself by default" do |
@@ -757,9 +757,9 @@ class PersonTest < ActiveSupport::TestCase | @@ -757,9 +757,9 @@ class PersonTest < ActiveSupport::TestCase | ||
757 | assert p4.is_a_friend?(p1) | 757 | assert p4.is_a_friend?(p1) |
758 | 758 | ||
759 | assert_equal true, p1.follows?(p1) | 759 | assert_equal true, p1.follows?(p1) |
760 | - assert_equal true, p1.follows?(p2) | ||
761 | - assert_equal true, p1.follows?(p4) | ||
762 | - assert_equal false, p1.follows?(p3) | 760 | + assert_equal true, p2.follows?(p1) |
761 | + assert_equal true, p4.follows?(p1) | ||
762 | + assert_equal false, p3.follows?(p1) | ||
763 | end | 763 | end |
764 | 764 | ||
765 | should "a person member of a community follows the community" do | 765 | should "a person member of a community follows the community" do |
@@ -836,18 +836,21 @@ class PersonTest < ActiveSupport::TestCase | @@ -836,18 +836,21 @@ class PersonTest < ActiveSupport::TestCase | ||
836 | assert_nil Scrap.find_by(id: scrap.id) | 836 | assert_nil Scrap.find_by(id: scrap.id) |
837 | end | 837 | end |
838 | 838 | ||
839 | - should "the tracked action be notified to person friends and herself" do | 839 | + should "the tracked action be notified to person followers and herself" do |
840 | Person.destroy_all | 840 | Person.destroy_all |
841 | p1 = fast_create(Person) | 841 | p1 = fast_create(Person) |
842 | p2 = fast_create(Person) | 842 | p2 = fast_create(Person) |
843 | p3 = fast_create(Person) | 843 | p3 = fast_create(Person) |
844 | p4 = fast_create(Person) | 844 | p4 = fast_create(Person) |
845 | 845 | ||
846 | - p1.add_friend(p2) | ||
847 | - assert p1.is_a_friend?(p2) | ||
848 | - refute p1.is_a_friend?(p3) | ||
849 | - p1.add_friend(p4) | ||
850 | - assert p1.is_a_friend?(p4) | 846 | + circle2 = Circle.create!(:person=> p2, :name => "Zombies", :profile_type => 'Person') |
847 | + circle4 = Circle.create!(:person=> p4, :name => "Zombies", :profile_type => 'Person') | ||
848 | + | ||
849 | + p2.follow(p1, circle2) | ||
850 | + assert p2.follows?(p1) | ||
851 | + refute p3.follows?(p1) | ||
852 | + p4.follow(p1, circle4) | ||
853 | + assert p4.follows?(p1) | ||
851 | 854 | ||
852 | action_tracker = fast_create(ActionTracker::Record, :user_id => p1.id) | 855 | action_tracker = fast_create(ActionTracker::Record, :user_id => p1.id) |
853 | ActionTrackerNotification.delete_all | 856 | ActionTrackerNotification.delete_all |
@@ -880,17 +883,19 @@ class PersonTest < ActiveSupport::TestCase | @@ -880,17 +883,19 @@ class PersonTest < ActiveSupport::TestCase | ||
880 | end | 883 | end |
881 | end | 884 | end |
882 | 885 | ||
883 | - should "the tracked action notify friends with one delayed job process" do | 886 | + should "the tracked action notify followers with one delayed job process" do |
884 | p1 = fast_create(Person) | 887 | p1 = fast_create(Person) |
885 | p2 = fast_create(Person) | 888 | p2 = fast_create(Person) |
886 | p3 = fast_create(Person) | 889 | p3 = fast_create(Person) |
887 | p4 = fast_create(Person) | 890 | p4 = fast_create(Person) |
888 | 891 | ||
889 | - p1.add_friend(p2) | ||
890 | - assert p1.is_a_friend?(p2) | ||
891 | - refute p1.is_a_friend?(p3) | ||
892 | - p1.add_friend(p4) | ||
893 | - assert p1.is_a_friend?(p4) | 892 | + circle2 = Circle.create!(:person=> p2, :name => "Zombies", :profile_type => 'Person') |
893 | + circle4 = Circle.create!(:person=> p4, :name => "Zombies", :profile_type => 'Person') | ||
894 | + p2.follow(p1, circle2) | ||
895 | + assert p2.follows?(p1) | ||
896 | + refute p3.follows?(p1) | ||
897 | + p4.follow(p1, circle4) | ||
898 | + assert p4.follows?(p1) | ||
894 | 899 | ||
895 | action_tracker = fast_create(ActionTracker::Record, :user_id => p1.id) | 900 | action_tracker = fast_create(ActionTracker::Record, :user_id => p1.id) |
896 | 901 | ||
@@ -1035,11 +1040,13 @@ class PersonTest < ActiveSupport::TestCase | @@ -1035,11 +1040,13 @@ class PersonTest < ActiveSupport::TestCase | ||
1035 | p2 = create_user('p2').person | 1040 | p2 = create_user('p2').person |
1036 | p3 = create_user('p3').person | 1041 | p3 = create_user('p3').person |
1037 | c = fast_create(Community, :name => "Foo") | 1042 | c = fast_create(Community, :name => "Foo") |
1043 | + | ||
1038 | c.add_member(p1) | 1044 | c.add_member(p1) |
1039 | process_delayed_job_queue | 1045 | process_delayed_job_queue |
1040 | c.add_member(p3) | 1046 | c.add_member(p3) |
1041 | process_delayed_job_queue | 1047 | process_delayed_job_queue |
1042 | - assert_equal 4, ActionTracker::Record.count | 1048 | + |
1049 | + assert_equal 5, ActionTracker::Record.count | ||
1043 | assert_equal 5, ActionTrackerNotification.count | 1050 | assert_equal 5, ActionTrackerNotification.count |
1044 | has_add_member_notification = false | 1051 | has_add_member_notification = false |
1045 | ActionTrackerNotification.all.map do |notification| | 1052 | ActionTrackerNotification.all.map do |notification| |
@@ -1951,4 +1958,51 @@ class PersonTest < ActiveSupport::TestCase | @@ -1951,4 +1958,51 @@ class PersonTest < ActiveSupport::TestCase | ||
1951 | person.save! | 1958 | person.save! |
1952 | end | 1959 | end |
1953 | 1960 | ||
1961 | + should 'update profile circles for a person' do | ||
1962 | + person = create_user('testuser').person | ||
1963 | + community = fast_create(Community) | ||
1964 | + circle = Circle.create!(:person=> person, :name => "Zombies", :profile_type => 'Community') | ||
1965 | + circle2 = Circle.create!(:person=> person, :name => "Dota", :profile_type => 'Community') | ||
1966 | + circle3 = Circle.create!(:person=> person, :name => "Quadrado", :profile_type => 'Community') | ||
1967 | + person.follow(community, [circle, circle2]) | ||
1968 | + person.update_profile_circles(community, [circle2, circle3]) | ||
1969 | + assert_equivalent [circle2, circle3], ProfileFollower.with_profile(community).with_follower(person).map(&:circle) | ||
1970 | + end | ||
1971 | + | ||
1972 | + should 'a person follow a profile' do | ||
1973 | + person = create_user('testuser').person | ||
1974 | + community = fast_create(Community) | ||
1975 | + circle = Circle.create!(:person=> person, :name => "Zombies", :profile_type => 'Community') | ||
1976 | + person.follow(community, circle) | ||
1977 | + assert_includes person.followed_profiles, community | ||
1978 | + end | ||
1979 | + | ||
1980 | + should 'a person follow a profile with more than one circle' do | ||
1981 | + person = create_user('testuser').person | ||
1982 | + community = fast_create(Community) | ||
1983 | + circle = Circle.create!(:person=> person, :name => "Zombies", :profile_type => 'Community') | ||
1984 | + circle2 = Circle.create!(:person=> person, :name => "Dota", :profile_type => 'Community') | ||
1985 | + person.follow(community, [circle, circle2]) | ||
1986 | + assert_includes person.followed_profiles, community | ||
1987 | + assert_equivalent [circle, circle2], ProfileFollower.with_profile(community).with_follower(person).map(&:circle) | ||
1988 | + end | ||
1989 | + | ||
1990 | + should 'a person unfollow a profile' do | ||
1991 | + person = create_user('testuser').person | ||
1992 | + community = fast_create(Community) | ||
1993 | + circle = Circle.create!(:person=> person, :name => "Zombies", :profile_type => 'Community') | ||
1994 | + person.follow(community, circle) | ||
1995 | + person.unfollow(community) | ||
1996 | + assert_not_includes person.followed_profiles, community | ||
1997 | + end | ||
1998 | + | ||
1999 | + should 'a person remove a profile from a circle' do | ||
2000 | + person = create_user('testuser').person | ||
2001 | + community = fast_create(Community) | ||
2002 | + circle = Circle.create!(:person=> person, :name => "Zombies", :profile_type => 'Community') | ||
2003 | + circle2 = Circle.create!(:person=> person, :name => "Dota", :profile_type => 'Community') | ||
2004 | + person.follow(community, [circle, circle2]) | ||
2005 | + person.remove_profile_from_circle(community, circle) | ||
2006 | + assert_equivalent [circle2], ProfileFollower.with_profile(community).with_follower(person).map(&:circle) | ||
2007 | + end | ||
1954 | end | 2008 | end |
@@ -0,0 +1,73 @@ | @@ -0,0 +1,73 @@ | ||
1 | +require_relative "../test_helper" | ||
2 | + | ||
3 | +class ProfileFollowersTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + should 'a person follow another' do | ||
6 | + p1 = create_user('person_test').person | ||
7 | + p2 = create_user('person_test_2').person | ||
8 | + circle = Circle.create!(:person=> p1, :name => "Zombies", :profile_type => 'Person') | ||
9 | + | ||
10 | + assert_difference 'ProfileFollower.count' do | ||
11 | + p1.follow(p2, circle) | ||
12 | + end | ||
13 | + | ||
14 | + assert_includes p2.followers(true), p1 | ||
15 | + assert_not_includes p1.followers(true), p2 | ||
16 | + end | ||
17 | + | ||
18 | + should 'a person unfollow another person' do | ||
19 | + p1 = create_user('person_test').person | ||
20 | + p2 = create_user('person_test_2').person | ||
21 | + circle = Circle.create!(:person=> p1, :name => "Zombies", :profile_type => 'Person') | ||
22 | + | ||
23 | + p1.follow(p2,circle) | ||
24 | + | ||
25 | + assert_difference 'ProfileFollower.count', -1 do | ||
26 | + p1.unfollow(p2) | ||
27 | + end | ||
28 | + | ||
29 | + assert_not_includes p2.followers(true), p1 | ||
30 | + end | ||
31 | + | ||
32 | + should 'get the followed persons for a profile' do | ||
33 | + p1 = create_user('person_test').person | ||
34 | + p2 = create_user('person_test_2').person | ||
35 | + p3 = create_user('person_test_3').person | ||
36 | + circle = Circle.create!(:person=> p1, :name => "Zombies", :profile_type => 'Person') | ||
37 | + | ||
38 | + p1.follow(p2, circle) | ||
39 | + p1.follow(p3, circle) | ||
40 | + | ||
41 | + assert_equivalent p1.followed_profiles, [p2,p3] | ||
42 | + assert_equivalent Profile.followed_by(p1), [p2,p3] | ||
43 | + end | ||
44 | + | ||
45 | + should 'not follow same person twice' do | ||
46 | + p1 = create_user('person_test').person | ||
47 | + p2 = create_user('person_test_2').person | ||
48 | + circle = Circle.create!(:person=> p1, :name => "Zombies", :profile_type => 'Person') | ||
49 | + | ||
50 | + assert_difference 'ProfileFollower.count' do | ||
51 | + p1.follow(p2, circle) | ||
52 | + p1.follow(p2, circle) | ||
53 | + end | ||
54 | + | ||
55 | + assert_equivalent p1.followed_profiles, [p2] | ||
56 | + assert_equivalent p2.followers, [p1] | ||
57 | + end | ||
58 | + | ||
59 | + should 'show the correct message when a profile is followed by the same person' do | ||
60 | + p1 = create_user('person_test').person | ||
61 | + p2 = create_user('person_test_2').person | ||
62 | + circle = Circle.create!(:person=> p1, :name => "Zombies", :profile_type => 'Person') | ||
63 | + | ||
64 | + p1.follow(p2, circle) | ||
65 | + profile_follower = ProfileFollower.new | ||
66 | + profile_follower.circle = circle | ||
67 | + profile_follower.profile = p2 | ||
68 | + profile_follower.valid? | ||
69 | + | ||
70 | + assert_includes profile_follower.errors.messages[:profile_id], | ||
71 | + "can't put a profile in the same circle twice" | ||
72 | + end | ||
73 | +end |
test/unit/scrap_test.rb
@@ -125,11 +125,11 @@ class ScrapTest < ActiveSupport::TestCase | @@ -125,11 +125,11 @@ class ScrapTest < ActiveSupport::TestCase | ||
125 | assert_equal c, ta.target | 125 | assert_equal c, ta.target |
126 | end | 126 | end |
127 | 127 | ||
128 | - should "notify leave_scrap action tracker verb to friends and itself" do | 128 | + should "notify leave_scrap action tracker verb to followers and itself" do |
129 | User.current = create_user | 129 | User.current = create_user |
130 | p1 = User.current.person | 130 | p1 = User.current.person |
131 | p2 = create_user.person | 131 | p2 = create_user.person |
132 | - p1.add_friend(p2) | 132 | + p2.add_friend(p1) |
133 | process_delayed_job_queue | 133 | process_delayed_job_queue |
134 | s = Scrap.new | 134 | s = Scrap.new |
135 | s.sender= p1 | 135 | s.sender= p1 |
@@ -180,11 +180,11 @@ class ScrapTest < ActiveSupport::TestCase | @@ -180,11 +180,11 @@ class ScrapTest < ActiveSupport::TestCase | ||
180 | assert_equal p, ta.user | 180 | assert_equal p, ta.user |
181 | end | 181 | end |
182 | 182 | ||
183 | - should "notify leave_scrap_to_self action tracker verb to friends and itself" do | 183 | + should "notify leave_scrap_to_self action tracker verb to followers and itself" do |
184 | User.current = create_user | 184 | User.current = create_user |
185 | p1 = User.current.person | 185 | p1 = User.current.person |
186 | p2 = create_user.person | 186 | p2 = create_user.person |
187 | - p1.add_friend(p2) | 187 | + p2.add_friend(p1) |
188 | ActionTrackerNotification.delete_all | 188 | ActionTrackerNotification.delete_all |
189 | Delayed::Job.delete_all | 189 | Delayed::Job.delete_all |
190 | s = Scrap.new | 190 | s = Scrap.new |