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 | ... | ... |