Commit 6c4f6400dbf5daea661eb9eef5d5369573f77f56
1 parent
f078e729
Exists in
federation-webfinger
Makes ExternalProfile respond to all Profile methods to avoid breakage
Showing
4 changed files
with
221 additions
and
131 deletions
Show diff stats
app/models/concerns/profile_entity.rb
... | ... | @@ -12,6 +12,8 @@ module ProfileEntity |
12 | 12 | |
13 | 13 | before_create :set_default_environment |
14 | 14 | |
15 | + scope :recent, -> limit=nil { order('id DESC').limit(limit) } | |
16 | + | |
15 | 17 | end |
16 | 18 | |
17 | 19 | def disable |
... | ... | @@ -65,4 +67,77 @@ module ProfileEntity |
65 | 67 | end |
66 | 68 | end |
67 | 69 | |
70 | + def to_liquid | |
71 | + HashWithIndifferentAccess.new :name => name, :identifier => identifier | |
72 | + end | |
73 | + | |
74 | + # Tells whether a specified profile has members or nor. | |
75 | + # | |
76 | + # On this class, returns <tt>false</tt> by default. | |
77 | + def has_members? | |
78 | + false | |
79 | + end | |
80 | + | |
81 | + def apply_type_specific_template(template) | |
82 | + end | |
83 | + | |
84 | + # Override this method in subclasses of Profile to create a default article | |
85 | + # set upon creation. Note that this method will be called *only* if there is | |
86 | + # no template for the type of profile (i.e. if the template was removed or in | |
87 | + # the creation of the template itself). | |
88 | + # | |
89 | + # This method must return an array of pre-populated articles, which will be | |
90 | + # associated to the profile before being saved. Example: | |
91 | + # | |
92 | + # def default_set_of_articles | |
93 | + # [Blog.new(:name => 'Blog'), Gallery.new(:name => 'Gallery')] | |
94 | + # end | |
95 | + # | |
96 | + # By default, this method returns an empty array. | |
97 | + def default_set_of_articles | |
98 | + [] | |
99 | + end | |
100 | + | |
101 | + def blocks_to_expire_cache | |
102 | + [] | |
103 | + end | |
104 | + | |
105 | + def cache_keys(params = {}) | |
106 | + [] | |
107 | + end | |
108 | + | |
109 | + def members_cache_key(params = {}) | |
110 | + page = params[:npage] || '1' | |
111 | + sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' | |
112 | + cache_key + '-members-page-' + page + '-' + sort | |
113 | + end | |
114 | + | |
115 | + def more_recent_label | |
116 | + _("Since: ") | |
117 | + end | |
118 | + | |
119 | + def control_panel_settings_button | |
120 | + {:title => _('Edit Profile'), :icon => 'edit-profile'} | |
121 | + end | |
122 | + | |
123 | + def control_panel_settings_button | |
124 | + {:title => _('Profile Info and settings'), :icon => 'edit-profile'} | |
125 | + end | |
126 | + | |
127 | + def exclude_verbs_on_activities | |
128 | + %w[] | |
129 | + end | |
130 | + | |
131 | + def allow_invitation_from(person) | |
132 | + false | |
133 | + end | |
134 | + | |
135 | + module ClassMethods | |
136 | + | |
137 | + def identification | |
138 | + name | |
139 | + end | |
140 | + | |
141 | + end | |
142 | + | |
68 | 143 | end | ... | ... |
app/models/external_person.rb
... | ... | @@ -23,87 +23,92 @@ class ExternalPerson < ActiveRecord::Base |
23 | 23 | user |
24 | 24 | end |
25 | 25 | |
26 | - def url | |
27 | - "http://#{self.source}/#{self.identifier}" | |
26 | + def privacy_setting | |
27 | + _('Public profile') | |
28 | 28 | end |
29 | 29 | |
30 | - alias :public_profile_url :url | |
31 | - | |
32 | 30 | def avatar |
33 | 31 | "http://#{self.source}/profile/#{self.identifier}/icon/" |
34 | 32 | end |
35 | 33 | |
34 | + def url | |
35 | + "http://#{self.source}/#{self.identifier}" | |
36 | + end | |
37 | + | |
38 | + alias :public_profile_url :url | |
39 | + | |
36 | 40 | def admin_url |
37 | 41 | "http://#{self.source}/myprofile/#{self.identifier}" |
38 | 42 | end |
39 | 43 | |
40 | - def profile_custom_icon(gravatar_default=nil) | |
41 | - self.avatar | |
44 | + def tasks_url | |
45 | + self.url | |
42 | 46 | end |
43 | - | |
44 | - def preferred_login_redirection | |
45 | - environment.redirection_after_login | |
47 | + def leave_url(reload = false) | |
48 | + self.url | |
46 | 49 | end |
47 | - | |
48 | - def person? | |
49 | - true | |
50 | + def join_url | |
51 | + self.url | |
50 | 52 | end |
51 | - | |
52 | - def is_admin?(environment = nil) | |
53 | - false | |
53 | + def join_not_logged_url | |
54 | + self.url | |
54 | 55 | end |
55 | - | |
56 | - def lat | |
57 | - nil | |
56 | + def check_membership_url | |
57 | + self.url | |
58 | 58 | end |
59 | - def lng | |
60 | - nil | |
59 | + def add_url | |
60 | + self.url | |
61 | 61 | end |
62 | - | |
63 | - def role_assignments | |
64 | - RoleAssignment.none | |
62 | + def check_friendship_url | |
63 | + self.url | |
65 | 64 | end |
66 | - | |
67 | - def favorite_enterprises | |
68 | - Enterprise.none | |
65 | + def people_suggestions_url | |
66 | + self.url | |
69 | 67 | end |
70 | - | |
71 | - def memberships | |
72 | - Profile.none | |
68 | + def communities_suggestions_url | |
69 | + self.url | |
70 | + end | |
71 | + def top_url(scheme = 'http') | |
72 | + "#{scheme}://#{self.source}" | |
73 | 73 | end |
74 | 74 | |
75 | - def friendships | |
76 | - Profile.none | |
75 | + def profile_custom_icon(gravatar_default=nil) | |
76 | + self.avatar | |
77 | 77 | end |
78 | 78 | |
79 | - def tasks | |
80 | - Task.none | |
79 | + def preferred_login_redirection | |
80 | + environment.redirection_after_login | |
81 | 81 | end |
82 | 82 | |
83 | - def suggested_profiles | |
84 | - ProfileSuggestion.none | |
83 | + def location | |
84 | + self.source | |
85 | 85 | end |
86 | - def suggested_people | |
87 | - ProfileSuggestion.none | |
86 | + | |
87 | + def default_hostname | |
88 | + environment.default_hostname | |
88 | 89 | end |
89 | - def suggested_communities | |
90 | - ProfileSuggestion.none | |
90 | + | |
91 | + def possible_domains | |
92 | + environment.domains | |
91 | 93 | end |
92 | 94 | |
93 | - def add_friend(friend, group = nil) | |
94 | - false | |
95 | + def person? | |
96 | + true | |
95 | 97 | end |
96 | 98 | |
97 | - def follows?(profile) | |
98 | - false | |
99 | + def contact_email(*args) | |
100 | + self.email | |
99 | 101 | end |
100 | 102 | |
101 | - def is_a_friend?(person) | |
102 | - false | |
103 | + def notification_emails | |
104 | + [self.contact_email] | |
103 | 105 | end |
104 | 106 | |
105 | - def already_request_friendship?(person) | |
106 | - false | |
107 | + def jid(options = {}) | |
108 | + "#{self.identifier}@#{self.source}" | |
109 | + end | |
110 | + def full_jid(options = {}) | |
111 | + "#{jid(options)}/#{self.name}" | |
107 | 112 | end |
108 | 113 | |
109 | 114 | class ExternalPerson::Image |
... | ... | @@ -126,18 +131,6 @@ class ExternalPerson < ActiveRecord::Base |
126 | 131 | ExternalPerson::Image.new(avatar) |
127 | 132 | end |
128 | 133 | |
129 | - def is_template? | |
130 | - false | |
131 | - end | |
132 | - | |
133 | - def enterprises | |
134 | - [] | |
135 | - end | |
136 | - | |
137 | - def friends | |
138 | - [] | |
139 | - end | |
140 | - | |
141 | 134 | def data_hash(gravatar_default = nil) |
142 | 135 | friends_list = {} |
143 | 136 | { |
... | ... | @@ -155,4 +148,86 @@ class ExternalPerson < ActiveRecord::Base |
155 | 148 | 'chat_enabled' => false |
156 | 149 | } |
157 | 150 | end |
151 | + | |
152 | + # External Person should respond to all methods in Person and Profile | |
153 | + def person_instance_methods | |
154 | + {} | |
155 | + end | |
156 | + | |
157 | + def profile_instance_methods | |
158 | + methods_and_responses = { | |
159 | + role_assignments: RoleAssignment.none, favorite_enterprises: | |
160 | + Enterprise.none, enterprises: Enterprise.none, memberships: Profile.none, | |
161 | + friendships: Profile.none, friends: Profile.none, tasks: Task.none, | |
162 | + suggested_profiles: ProfileSuggestion.none, suggested_people: | |
163 | + ProfileSuggestion.none, suggested_communities: ProfileSuggestion.none, | |
164 | + public_profile: true, nickname: nil, custom_footer: '', custom_header: '', | |
165 | + address: '', zip_code: '', contact_phone: '', image_builder: nil, | |
166 | + description: '', closed: false, template_id: nil, lat: nil, lng: nil, | |
167 | + is_template: false, fields_privacy: {}, preferred_domain_id: nil, | |
168 | + category_ids: [], country: '', city: '', state: '', national_region_code: | |
169 | + '', redirect_l10n: false, notification_time: 0, custom_url_redirection: | |
170 | + nil, email_suggestions: false, allow_members_to_invite: false, | |
171 | + invite_friends_only: false, secret: false, profile_admin_mail_notification: | |
172 | + false, redirection_after_login: nil, profile_activities: | |
173 | + ProfileActivity.none, action_tracker_notifications: | |
174 | + ActionTrackerNotification.none, tracked_notifications: | |
175 | + ActionTracker::Record.none, scraps_received: Scrap.none, template: | |
176 | + Profile.none, comments_received: Comment.none, email_templates: | |
177 | + EmailTemplate.none, members: Profile.none, members_like: Profile.none, | |
178 | + members_by: Profile.none, members_by_role: Profile.none, scraps: | |
179 | + Scrap.none, welcome_page_content: nil, settings: {}, find_in_all_tasks: | |
180 | + nil, top_level_categorization: {}, interests: Category.none, geolocation: | |
181 | + '', country_name: '', pending_categorizations: [], add_category: false, | |
182 | + create_pending_categorizations: false, top_level_articles: Article.none, | |
183 | + valid_identifier: true, valid_template: false, create_default_set_of_boxes: | |
184 | + true, copy_blocks_from: nil, default_template: nil, | |
185 | + template_without_default: nil, template_with_default: nil, apply_template: | |
186 | + false, iframe_whitelist: [], recent_documents: Article.none, last_articles: | |
187 | + Article.none, is_validation_entity?: false, hostname: nil, own_hostname: | |
188 | + nil, article_tags: {}, tagged_with: Article.none, | |
189 | + insert_default_article_set: false, copy_articles_from: true, | |
190 | + copy_article_tree: nil, copy_article?: false, add_member: false, | |
191 | + remove_member: false, add_admin: false, remove_admin: false, add_moderator: | |
192 | + false, display_info_to?: true, update_category_from_region: nil, | |
193 | + accept_category?: false, custom_header_expanded: '', | |
194 | + custom_footer_expanded: '', public?: true, themes: [], find_theme: nil, | |
195 | + blogs: Blog.none, blog: nil, has_blog?: false, forums: Forum.none, forum: | |
196 | + nil, has_forum?: false, admins: [], settings_field: {}, setting_changed: | |
197 | + false, public_content: true, enable_contact?: false, folder_types: [], | |
198 | + folders: Article.none, image_galleries: Article.none, image_valid: true, | |
199 | + update_header_and_footer: nil, update_theme: nil, update_layout_template: | |
200 | + nil, recent_actions: ActionTracker::Record.none, recent_notifications: | |
201 | + ActionTracker::Record.none, more_active_label: _('no activity'), | |
202 | + more_popular_label: _('no members'), profile_custom_image: nil, | |
203 | + is_on_homepage?: false, activities: ProfileActivity.none, | |
204 | + may_display_field_to?: true, may_display_location_to?: true, public_fields: | |
205 | + {}, followed_by?: false, display_private_info_to?: true, can_view_field?: | |
206 | + true, remove_from_suggestion_list: nil, layout_template: 'default', | |
207 | + is_admin?: false, add_friend: false, follows?: false, is_a_friend?: false, | |
208 | + already_request_friendship?: false | |
209 | + } | |
210 | + | |
211 | + derivated_methods = {} | |
212 | + methods_and_responses.keys.each do |method| | |
213 | + derivated_methods[method.to_s.insert(-1, '?').to_sym] = false | |
214 | + derivated_methods[method.to_s.insert(-1, '=').to_sym] = nil | |
215 | + end | |
216 | + derivated_methods.merge(methods_and_responses) | |
217 | + end | |
218 | + | |
219 | + def method_missing(method, *args, &block) | |
220 | + if person_instance_methods.keys.include?(method) | |
221 | + return person_instance_methods[method] | |
222 | + end | |
223 | + if profile_instance_methods.keys.include? method | |
224 | + return profile_instance_methods[method] | |
225 | + end | |
226 | + end | |
227 | + | |
228 | + def respond_to_missing?(method_name, include_private = false) | |
229 | + person_instance_methods.keys.include?(method_name) || | |
230 | + profile_instance_methods.keys.include?(method_name) || | |
231 | + super | |
232 | + end | |
158 | 233 | end | ... | ... |
app/models/profile.rb
... | ... | @@ -116,8 +116,6 @@ class Profile < ApplicationRecord |
116 | 116 | } |
117 | 117 | scope :no_templates, -> { where is_template: false } |
118 | 118 | |
119 | - scope :recent, -> limit=nil { order('id DESC').limit(limit) } | |
120 | - | |
121 | 119 | |
122 | 120 | # Returns a scoped object to select profiles in a given location or in a radius |
123 | 121 | # distance from the given location center. |
... | ... | @@ -483,9 +481,6 @@ class Profile < ApplicationRecord |
483 | 481 | self.save(:validate => false) |
484 | 482 | end |
485 | 483 | |
486 | - def apply_type_specific_template(template) | |
487 | - end | |
488 | - | |
489 | 484 | xss_terminate :only => [ :name, :nickname, :address, :contact_phone, :description ], :on => 'validation' |
490 | 485 | xss_terminate :only => [ :custom_footer, :custom_header ], :with => 'white_list' |
491 | 486 | |
... | ... | @@ -526,10 +521,6 @@ class Profile < ApplicationRecord |
526 | 521 | ).order('articles.published_at desc, articles.id desc') |
527 | 522 | end |
528 | 523 | |
529 | - def to_liquid | |
530 | - HashWithIndifferentAccess.new :name => name, :identifier => identifier | |
531 | - end | |
532 | - | |
533 | 524 | class << self |
534 | 525 | |
535 | 526 | # finds a profile by its identifier. This method is a shortcut to |
... | ... | @@ -653,13 +644,6 @@ private :generate_url, :url_options |
653 | 644 | self.articles.tagged_with(tag) |
654 | 645 | end |
655 | 646 | |
656 | - # Tells whether a specified profile has members or nor. | |
657 | - # | |
658 | - # On this class, returns <tt>false</tt> by default. | |
659 | - def has_members? | |
660 | - false | |
661 | - end | |
662 | - | |
663 | 647 | after_create :insert_default_article_set |
664 | 648 | def insert_default_article_set |
665 | 649 | if template |
... | ... | @@ -674,23 +658,6 @@ private :generate_url, :url_options |
674 | 658 | end |
675 | 659 | end |
676 | 660 | |
677 | - # Override this method in subclasses of Profile to create a default article | |
678 | - # set upon creation. Note that this method will be called *only* if there is | |
679 | - # no template for the type of profile (i.e. if the template was removed or in | |
680 | - # the creation of the template itself). | |
681 | - # | |
682 | - # This method must return an array of pre-populated articles, which will be | |
683 | - # associated to the profile before being saved. Example: | |
684 | - # | |
685 | - # def default_set_of_articles | |
686 | - # [Blog.new(:name => 'Blog'), Gallery.new(:name => 'Gallery')] | |
687 | - # end | |
688 | - # | |
689 | - # By default, this method returns an empty array. | |
690 | - def default_set_of_articles | |
691 | - [] | |
692 | - end | |
693 | - | |
694 | 661 | def copy_articles_from other |
695 | 662 | return false if other.top_level_articles.empty? |
696 | 663 | other.top_level_articles.each do |a| |
... | ... | @@ -891,14 +858,6 @@ private :generate_url, :url_options |
891 | 858 | articles.galleries |
892 | 859 | end |
893 | 860 | |
894 | - def blocks_to_expire_cache | |
895 | - [] | |
896 | - end | |
897 | - | |
898 | - def cache_keys(params = {}) | |
899 | - [] | |
900 | - end | |
901 | - | |
902 | 861 | validate :image_valid |
903 | 862 | |
904 | 863 | def image_valid |
... | ... | @@ -935,16 +894,6 @@ private :generate_url, :url_options |
935 | 894 | self.update_attribute(:layout_template, template) |
936 | 895 | end |
937 | 896 | |
938 | - def members_cache_key(params = {}) | |
939 | - page = params[:npage] || '1' | |
940 | - sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' | |
941 | - cache_key + '-members-page-' + page + '-' + sort | |
942 | - end | |
943 | - | |
944 | - def more_recent_label | |
945 | - _("Since: ") | |
946 | - end | |
947 | - | |
948 | 897 | def recent_actions |
949 | 898 | tracked_actions.recent |
950 | 899 | end |
... | ... | @@ -999,18 +948,6 @@ private :generate_url, :url_options |
999 | 948 | end |
1000 | 949 | end |
1001 | 950 | |
1002 | - def control_panel_settings_button | |
1003 | - {:title => _('Edit Profile'), :icon => 'edit-profile'} | |
1004 | - end | |
1005 | - | |
1006 | - def self.identification | |
1007 | - name | |
1008 | - end | |
1009 | - | |
1010 | - def exclude_verbs_on_activities | |
1011 | - %w[] | |
1012 | - end | |
1013 | - | |
1014 | 951 | # Customize in subclasses |
1015 | 952 | def activities |
1016 | 953 | self.profile_activities.includes(:activity).order('updated_at DESC') |
... | ... | @@ -1045,10 +982,6 @@ private :generate_url, :url_options |
1045 | 982 | self.active_fields |
1046 | 983 | end |
1047 | 984 | |
1048 | - def control_panel_settings_button | |
1049 | - {:title => _('Profile Info and settings'), :icon => 'edit-profile'} | |
1050 | - end | |
1051 | - | |
1052 | 985 | def followed_by?(person) |
1053 | 986 | person.is_member_of?(self) |
1054 | 987 | end |
... | ... | @@ -1076,8 +1009,4 @@ private :generate_url, :url_options |
1076 | 1009 | suggestion.disable if suggestion |
1077 | 1010 | end |
1078 | 1011 | |
1079 | - def allow_invitation_from(person) | |
1080 | - false | |
1081 | - end | |
1082 | - | |
1083 | 1012 | end | ... | ... |
test/unit/external_person_test.rb
1 | 1 | # encoding: UTF-8 |
2 | 2 | require_relative "../test_helper" |
3 | 3 | |
4 | -class PersonTest < ActiveSupport::TestCase | |
4 | +class ExternalPersonTest < ActiveSupport::TestCase | |
5 | 5 | fixtures :environments |
6 | 6 | |
7 | 7 | def setup |
... | ... | @@ -101,4 +101,15 @@ class PersonTest < ActiveSupport::TestCase |
101 | 101 | |
102 | 102 | should 'profile image has public filename and mimetype' do |
103 | 103 | end |
104 | + | |
105 | + should 'respond to all instance methods in Profile' do | |
106 | + methods = Profile.public_instance_methods(false) | |
107 | + methods.each do |method| | |
108 | + # We test if ExternalPerson responds to same methods as Profile, but we | |
109 | + # skip methods generated by plugins, libs and validations, which are | |
110 | + # usually only used internally | |
111 | + assert_respond_to ExternalPerson.new, method.to_sym unless method =~ /type_name|^autosave_.*|^after_.*|^before_.*|validate_.*|^attribute_.*|.*_?tags?_?.*|^custom_value.*|^custom_context.*|^xss.*|bar/ | |
112 | + end | |
113 | + end | |
114 | + | |
104 | 115 | end | ... | ... |