Commit fa46a8f5fc858a9410e0f3b20753f5ea9e9710f2
Exists in
oauth_external_login
and in
1 other branch
Merge branch 'external-person' into 'federation'
External person Allow external users to login in a network that is federated with the user's network. See merge request !951
Showing
53 changed files
with
1289 additions
and
275 deletions
Show diff stats
app/api/app.rb
1 | 1 | require_dependency 'api/helpers' |
2 | 2 | |
3 | 3 | module Api |
4 | + class NoosferoFederation < Grape::API | |
5 | + use Rack::JSONP | |
6 | + helpers Helpers | |
7 | + before { detect_stuff_by_domain } | |
8 | + format :json | |
9 | + content_type :json, "application/jrd+json" | |
10 | + prefix [ENV['RAILS_RELATIVE_URL_ROOT'], ".well-known"].compact.join('/') | |
11 | + mount Federation::Webfinger | |
12 | + end | |
13 | + | |
4 | 14 | class App < Grape::API |
5 | 15 | use Rack::JSONP |
6 | 16 | |
... | ... | @@ -23,6 +33,8 @@ module Api |
23 | 33 | end |
24 | 34 | end |
25 | 35 | |
36 | + mount NoosferoFederation | |
37 | + | |
26 | 38 | before { set_locale } |
27 | 39 | before { setup_multitenancy } |
28 | 40 | before { detect_stuff_by_domain } | ... | ... |
... | ... | @@ -0,0 +1,108 @@ |
1 | +require 'rails/commands/server' | |
2 | + | |
3 | +module Api | |
4 | + module Federation | |
5 | + class Webfinger < Grape::API | |
6 | + get 'webfinger' do | |
7 | + result = generate_jrd | |
8 | + present result, with: Grape::Presenters::Presenter | |
9 | + end | |
10 | + end | |
11 | + end | |
12 | +end | |
13 | + | |
14 | +def generate_jrd | |
15 | + unless valid_domain? | |
16 | + not_found! | |
17 | + Rails.logger.error 'Domain Not Found' | |
18 | + end | |
19 | + if request_acct? | |
20 | + acct_hash | |
21 | + elsif valid_uri?(params[:resource]) | |
22 | + uri_hash | |
23 | + end | |
24 | +end | |
25 | + | |
26 | +def domain | |
27 | + if request_acct? | |
28 | + params[:resource].split('@')[1] | |
29 | + else | |
30 | + params[:resource].split('/')[2] | |
31 | + end | |
32 | +end | |
33 | + | |
34 | +def valid_domain? | |
35 | + environment.domains.map(&:name).include? domain | |
36 | +end | |
37 | + | |
38 | +def request_acct? | |
39 | + params[:resource].include? 'acct:' | |
40 | +end | |
41 | + | |
42 | +def acct_hash | |
43 | + rails = Rails::Server.new | |
44 | + acct = Hash.new{|hash, key| hash[key] = Hash.new{|hash, key| hash[key] = Array.new}} | |
45 | + url = rails.options[:Host] + ':' + rails.options[:Port].to_s + '/' | |
46 | + person = Person.find_by_identifier(extract_person_identifier) | |
47 | + | |
48 | + if person.nil? | |
49 | + Rails.logger.error 'Person not found' | |
50 | + not_found! | |
51 | + else | |
52 | + acct[:subject] = params[:resource] | |
53 | + acct[:alias] = url + person.identifier | |
54 | + acct[:properties][:identifier] = person.identifier | |
55 | + acct[:properties][:created_at] = person.created_at | |
56 | + for blog in person.blogs do | |
57 | + acct[:links][:rel] << url + 'rel/' + blog.path | |
58 | + acct[:links][:href] << url + person.identifier + '/' + blog.path | |
59 | + end | |
60 | + | |
61 | + for galleries in person.articles.galleries do | |
62 | + acct[:links][:rel] << url + 'rel/' + galleries.path | |
63 | + acct[:links][:href] << url + person.identifier + '/' + galleries.path | |
64 | + end | |
65 | + | |
66 | + acct[:titles][:name] = person.name | |
67 | + end | |
68 | + acct | |
69 | +end | |
70 | + | |
71 | +def extract_person_identifier | |
72 | + params[:resource].split('@')[0].split(':')[1] | |
73 | +end | |
74 | + | |
75 | +def valid_uri?(url) | |
76 | + uri = URI.parse(url) | |
77 | + if uri.is_a?(URI::HTTP) | |
78 | + true | |
79 | + else | |
80 | + Rails.logger.error 'Bad URI Error' | |
81 | + not_found! | |
82 | + end | |
83 | +end | |
84 | + | |
85 | +def uri_hash | |
86 | + uri = {} | |
87 | + uri[:subject] = params[:resource] | |
88 | + entity = find_entity(params[:resource]) | |
89 | + id = params[:resource].split('/').last.to_i | |
90 | + begin | |
91 | + uri[:properties] = entity.classify.constantize.find(id) | |
92 | + rescue ActiveRecord::RecordNotFound | |
93 | + Rails.logger.error "Entity: #{entity} with id: #{id} not found" | |
94 | + not_found! | |
95 | + end | |
96 | + uri | |
97 | +end | |
98 | + | |
99 | +def find_entity(uri) | |
100 | + possible_entity = uri.split('/') | |
101 | + possible_entity.map! { |entity| "#{entity}s" } | |
102 | + entity = (ActiveRecord::Base.connection.tables & possible_entity).first | |
103 | + unless entity | |
104 | + Rails.logger.error 'Entity not found on records' | |
105 | + not_found! | |
106 | + end | |
107 | + entity | |
108 | +end | ... | ... |
app/api/helpers.rb
... | ... | @@ -10,6 +10,9 @@ module Api |
10 | 10 | include Noosfero::Plugin::HotSpot |
11 | 11 | include ForgotPasswordHelper |
12 | 12 | include SearchTermHelper |
13 | + include ProfileImageHelper | |
14 | + include Noosfero::Gravatar | |
15 | + include ThemeLoaderHelper | |
13 | 16 | |
14 | 17 | def set_locale |
15 | 18 | I18n.locale = (params[:lang] || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en') |
... | ... | @@ -412,7 +415,7 @@ module Api |
412 | 415 | content_type == 'TextArticle' ? Article.text_article_types : content_type |
413 | 416 | end |
414 | 417 | content_types.flatten.uniq |
415 | - end | |
418 | + end | |
416 | 419 | |
417 | 420 | def period(from_date, until_date) |
418 | 421 | begin_period = from_date.nil? ? Time.at(0).to_datetime : from_date | ... | ... |
app/api/v1/articles.rb
... | ... | @@ -62,7 +62,7 @@ module Api |
62 | 62 | { :success => true } |
63 | 63 | rescue Exception => exception |
64 | 64 | render_api_error!(_('The article couldn\'t be removed due to some problem. Please contact the administrator.'), 400) |
65 | - end | |
65 | + end | |
66 | 66 | end |
67 | 67 | |
68 | 68 | desc 'Report a abuse and/or violent content in a article by id' do | ... | ... |
app/api/v1/people.rb
... | ... | @@ -108,6 +108,23 @@ module Api |
108 | 108 | end |
109 | 109 | present output |
110 | 110 | end |
111 | + | |
112 | + desc "Return the person profile picture (you can optionally pass a 'size' parameter)" | |
113 | + get ":id/icon" do | |
114 | + person = environment.people.find(params[:id]) | |
115 | + | |
116 | + size = params[:size] || :portrait | |
117 | + image = profile_icon(person, size.to_sym) | |
118 | + output = {} | |
119 | + | |
120 | + unless image.match(/^\/\/www\.gravatar\.com/).nil? | |
121 | + output[:icon] = 'https:' + image | |
122 | + else | |
123 | + output[:icon] = request.url.gsub(/\/api\/.*/, '') + image | |
124 | + end | |
125 | + | |
126 | + present output | |
127 | + end | |
111 | 128 | end |
112 | 129 | |
113 | 130 | resource :profiles do | ... | ... |
app/concerns/authenticated_system.rb
... | ... | @@ -25,7 +25,19 @@ module AuthenticatedSystem |
25 | 25 | # Accesses the current user from the session. |
26 | 26 | def current_user user_id = session[:user] |
27 | 27 | @current_user ||= begin |
28 | - user = User.find_by id: user_id if user_id | |
28 | + user = nil | |
29 | + if session[:external] | |
30 | + user = User.new | |
31 | + external_person = ExternalPerson.find_by(id: session[:external]) | |
32 | + if external_person | |
33 | + user.external_person_id = external_person.id | |
34 | + user.email = external_person.email | |
35 | + else | |
36 | + session[:external] = nil | |
37 | + end | |
38 | + else | |
39 | + user = User.find_by(id: user_id) if user_id | |
40 | + end | |
29 | 41 | user.session = session if user |
30 | 42 | User.current = user |
31 | 43 | user |
... | ... | @@ -37,9 +49,13 @@ module AuthenticatedSystem |
37 | 49 | if new_user.nil? |
38 | 50 | session.delete(:user) |
39 | 51 | else |
40 | - session[:user] = new_user.id | |
52 | + if new_user.id | |
53 | + session[:user] = new_user.id | |
54 | + else | |
55 | + session[:external] = new_user.external_person_id | |
56 | + end | |
41 | 57 | new_user.session = session |
42 | - new_user.register_login | |
58 | + new_user.register_login if new_user.id | |
43 | 59 | end |
44 | 60 | @current_user = User.current = new_user |
45 | 61 | end | ... | ... |
app/controllers/application_controller.rb
... | ... | @@ -8,6 +8,7 @@ class ApplicationController < ActionController::Base |
8 | 8 | before_filter :allow_cross_domain_access |
9 | 9 | |
10 | 10 | include AuthenticatedSystem |
11 | + | |
11 | 12 | before_filter :require_login_for_environment, :if => :private_environment? |
12 | 13 | |
13 | 14 | before_filter :verify_members_whitelist, :if => [:private_environment?, :user] |
... | ... | @@ -120,7 +121,9 @@ class ApplicationController < ActionController::Base |
120 | 121 | end |
121 | 122 | |
122 | 123 | def user |
123 | - current_user.person if logged_in? | |
124 | + if logged_in? | |
125 | + current_user.person || current_user.external_person | |
126 | + end | |
124 | 127 | end |
125 | 128 | |
126 | 129 | alias :current_person :user | ... | ... |
app/controllers/my_profile/email_templates_controller.rb
... | ... | @@ -64,7 +64,7 @@ class EmailTemplatesController < ApplicationController |
64 | 64 | private |
65 | 65 | |
66 | 66 | def template_params |
67 | - {:profile_name => current_user.name, :environment_name => environment.name } | |
67 | + {:profile_name => current_person.name, :environment_name => environment.name } | |
68 | 68 | end |
69 | 69 | |
70 | 70 | def template_params_allowed params | ... | ... |
app/controllers/public/profile_controller.rb
... | ... | @@ -176,7 +176,7 @@ class ProfileController < PublicController |
176 | 176 | end |
177 | 177 | |
178 | 178 | def unblock |
179 | - if current_user.person.is_admin?(profile.environment) | |
179 | + if current_person.is_admin?(profile.environment) | |
180 | 180 | profile.unblock |
181 | 181 | session[:notice] = _("You have unblocked %s successfully. ") % profile.name |
182 | 182 | redirect_to :controller => 'profile', :action => 'index' |
... | ... | @@ -187,7 +187,7 @@ class ProfileController < PublicController |
187 | 187 | end |
188 | 188 | |
189 | 189 | def leave_scrap |
190 | - sender = params[:sender_id].nil? ? current_user.person : Person.find(params[:sender_id]) | |
190 | + sender = params[:sender_id].nil? ? current_person : Person.find(params[:sender_id]) | |
191 | 191 | receiver = params[:receiver_id].nil? ? @profile : Person.find(params[:receiver_id]) |
192 | 192 | @scrap = Scrap.new(params[:scrap]) |
193 | 193 | @scrap.sender= sender |
... | ... | @@ -270,7 +270,7 @@ class ProfileController < PublicController |
270 | 270 | |
271 | 271 | def remove_scrap |
272 | 272 | begin |
273 | - scrap = current_user.person.scraps(params[:scrap_id]) | |
273 | + scrap = current_person.scraps(params[:scrap_id]) | |
274 | 274 | scrap.destroy |
275 | 275 | finish_successful_removal 'Scrap successfully removed.' |
276 | 276 | rescue |
... | ... | @@ -395,6 +395,17 @@ class ProfileController < PublicController |
395 | 395 | end |
396 | 396 | end |
397 | 397 | |
398 | + def icon | |
399 | + size = params[:size] || :portrait | |
400 | + image, mime = profile_icon(profile, size.to_sym, true) | |
401 | + | |
402 | + unless image.match(/^\/\/www\.gravatar\.com/).nil? | |
403 | + redirect_to 'https:' + image | |
404 | + else | |
405 | + @file = File.join(Rails.root, 'public', image) | |
406 | + send_file @file, type: mime, disposition: 'inline' | |
407 | + end | |
408 | + end | |
398 | 409 | |
399 | 410 | protected |
400 | 411 | ... | ... |
app/controllers/public/search_controller.rb
... | ... | @@ -247,7 +247,7 @@ class SearchController < PublicController |
247 | 247 | def visible_profiles(klass, *extra_relations) |
248 | 248 | relations = [:image, :domains, :environment, :preferred_domain] |
249 | 249 | relations += extra_relations |
250 | - if current_user && current_user.person.is_admin? | |
250 | + if current_user && current_person.is_admin? | |
251 | 251 | @environment.send(klass.name.underscore.pluralize).includes(relations) |
252 | 252 | else |
253 | 253 | @environment.send(klass.name.underscore.pluralize).visible.includes(relations) | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -146,12 +146,12 @@ module ApplicationHelper |
146 | 146 | end |
147 | 147 | |
148 | 148 | def link_to_cms(text, profile = nil, options = {}) |
149 | - profile ||= current_user.login | |
149 | + profile ||= current_person.identifier | |
150 | 150 | link_to text, myprofile_path(:controller => 'cms', :profile => profile), options |
151 | 151 | end |
152 | 152 | |
153 | 153 | def link_to_profile(text, profile = nil, options = {}) |
154 | - profile ||= current_user.login | |
154 | + profile ||= current_person.identifier | |
155 | 155 | link_to text, profile_path(:profile => profile) , options |
156 | 156 | end |
157 | 157 | |
... | ... | @@ -160,7 +160,7 @@ module ApplicationHelper |
160 | 160 | end |
161 | 161 | |
162 | 162 | def link_if_permitted(link, permission = nil, target = nil) |
163 | - if permission.nil? || current_user.person.has_permission?(permission, target) | |
163 | + if permission.nil? || current_person.has_permission?(permission, target) | |
164 | 164 | link |
165 | 165 | else |
166 | 166 | nil |
... | ... | @@ -814,7 +814,7 @@ module ApplicationHelper |
814 | 814 | {s_('contents|Most commented') => {href: url_for({host: host, controller: 'search', action: 'contents', filter: 'more_comments'})}} |
815 | 815 | ] |
816 | 816 | if logged_in? |
817 | - links.push(_('New content') => modal_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})})) | |
817 | + links.push(_('New content') => modal_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_person.identifier, :cms => true})})) | |
818 | 818 | end |
819 | 819 | |
820 | 820 | link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => nil}, :id => 'submenu-contents') + |
... | ... | @@ -830,8 +830,8 @@ module ApplicationHelper |
830 | 830 | {s_('people|More popular') => {href: url_for({host: host, controller: 'search', action: 'people', filter: 'more_popular'})}} |
831 | 831 | ] |
832 | 832 | if logged_in? |
833 | - links.push(_('My friends') => {:href => url_for({:profile => current_user.login, :controller => 'friends'})}) | |
834 | - links.push(_('Invite friends') => {:href => url_for({:profile => current_user.login, :controller => 'invite', :action => 'friends'})}) | |
833 | + links.push(_('My friends') => {:href => url_for({:profile => current_person.identifier, :controller => 'friends'})}) | |
834 | + links.push(_('Invite friends') => {:href => url_for({:profile => current_person.identifier, :controller => 'invite', :action => 'friends'})}) | |
835 | 835 | end |
836 | 836 | |
837 | 837 | link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "search", :action => 'people', :category_path => ''}, :id => 'submenu-people') + |
... | ... | @@ -847,8 +847,8 @@ module ApplicationHelper |
847 | 847 | {s_('communities|More popular') => {href: url_for({host: host, controller: 'search', action: 'communities', filter: 'more_popular'})}} |
848 | 848 | ] |
849 | 849 | if logged_in? |
850 | - links.push(_('My communities') => {:href => url_for({:profile => current_user.login, :controller => 'memberships'})}) | |
851 | - links.push(_('New community') => {:href => url_for({:profile => current_user.login, :controller => 'memberships', :action => 'new_community'})}) | |
850 | + links.push(_('My communities') => {:href => url_for({:profile => current_person.identifier, :controller => 'memberships'})}) | |
851 | + links.push(_('New community') => {:href => url_for({:profile => current_person.identifier, :controller => 'memberships', :action => 'new_community'})}) | |
852 | 852 | end |
853 | 853 | |
854 | 854 | link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "search", :action => 'communities'}, :id => 'submenu-communities') + | ... | ... |
app/helpers/theme_loader_helper.rb
... | ... | @@ -2,7 +2,7 @@ module ThemeLoaderHelper |
2 | 2 | def current_theme |
3 | 3 | @current_theme ||= |
4 | 4 | begin |
5 | - if session[:user_theme] | |
5 | + if defined?(session).present? && session[:user_theme] | |
6 | 6 | session[:user_theme] |
7 | 7 | else |
8 | 8 | # utility for developers: set the theme to 'random' in development mode and |
... | ... | @@ -14,7 +14,7 @@ module ThemeLoaderHelper |
14 | 14 | elsif Rails.env.development? && respond_to?(:params) && params[:user_theme] && File.exists?(Rails.root.join('public/designs/themes', params[:user_theme])) |
15 | 15 | params[:user_theme] |
16 | 16 | else |
17 | - if profile && !profile.theme.nil? | |
17 | + if defined?(profile) && profile && !profile.theme.nil? | |
18 | 18 | profile.theme |
19 | 19 | elsif environment |
20 | 20 | environment.theme |
... | ... | @@ -34,9 +34,9 @@ module ThemeLoaderHelper |
34 | 34 | end |
35 | 35 | |
36 | 36 | def theme_path |
37 | - if session[:user_theme] | |
37 | + if defined?(session).present? && session[:user_theme] | |
38 | 38 | '/user_themes/' + current_theme |
39 | - elsif session[:theme] | |
39 | + elsif defined?(session).present? && session[:theme] | |
40 | 40 | '/designs/themes/' + session[:theme] |
41 | 41 | else |
42 | 42 | '/designs/themes/' + current_theme | ... | ... |
app/models/abuse_complaint.rb
1 | 1 | class AbuseComplaint < Task |
2 | 2 | has_many :abuse_reports, :dependent => :destroy |
3 | - belongs_to :reported, :class_name => "Profile", :foreign_key => "requestor_id" | |
3 | + belongs_to :reported, :polymorphic => true, :foreign_key => "requestor_id" | |
4 | 4 | |
5 | 5 | validates_presence_of :reported |
6 | 6 | alias :requestor :reported | ... | ... |
app/models/abuse_report.rb
... | ... | @@ -2,7 +2,7 @@ class AbuseReport < ApplicationRecord |
2 | 2 | |
3 | 3 | attr_accessible :content, :reason |
4 | 4 | |
5 | - belongs_to :reporter, :class_name => 'Person' | |
5 | + belongs_to :reporter, :polymorphic => true | |
6 | 6 | belongs_to :abuse_complaint |
7 | 7 | has_many :reported_images, :dependent => :destroy |
8 | 8 | ... | ... |
app/models/comment.rb
... | ... | @@ -15,7 +15,7 @@ class Comment < ApplicationRecord |
15 | 15 | alias :article= :source= |
16 | 16 | attr_accessor :follow_article |
17 | 17 | |
18 | - belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id' | |
18 | + belongs_to :author, :polymorphic => true, :foreign_key => 'author_id' | |
19 | 19 | has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy |
20 | 20 | belongs_to :reply_of, :class_name => 'Comment', :foreign_key => 'reply_of_id' |
21 | 21 | ... | ... |
... | ... | @@ -0,0 +1,100 @@ |
1 | +require 'ostruct' | |
2 | + | |
3 | +module ExternalUser | |
4 | + extend ActiveSupport::Concern | |
5 | + | |
6 | + included do | |
7 | + attr_accessor :external_person_id | |
8 | + end | |
9 | + | |
10 | + def external_person | |
11 | + ExternalPerson.where(id: self.external_person_id).first | |
12 | + end | |
13 | + | |
14 | + def person_with_external | |
15 | + self.external_person || self.person_without_external | |
16 | + end | |
17 | + | |
18 | + module ClassMethods | |
19 | + def webfinger_lookup(login, domain, environment) | |
20 | + if login && domain && environment.has_federated_network?(domain) | |
21 | + external_environment = environment.external_environments.find_by_url(domain) | |
22 | + scheme = "http#{external_environment.uses_ssl? ? 's' : ''}" | |
23 | + url = URI.parse(scheme+"://"+ domain +'/.well-known/webfinger?resource=acct:'+ | |
24 | + login+'@'+domain) | |
25 | + http = build_request(url) | |
26 | + req = Net::HTTP::Get.new(url.to_s) | |
27 | + res = http.request(req) | |
28 | + JSON.parse(res.body) | |
29 | + else | |
30 | + nil | |
31 | + end | |
32 | + end | |
33 | + | |
34 | + def build_request(uri) | |
35 | + request = Net::HTTP.new(uri.host, uri.port) | |
36 | + if uri.scheme == "https" # enable SSL/TLS | |
37 | + request.use_ssl = true | |
38 | + #TODO There may be self-signed certificates that we would not be able | |
39 | + #to verify, so we'll not verify the ssl certificate for now. Since | |
40 | + #this requests will go only towards trusted federated networks the admin | |
41 | + #configured we consider this not to be a big deal. Nonetheless we may be | |
42 | + #able in the future to require/provide the CA Files on the federation | |
43 | + #process which would allow us to verify the certificate. | |
44 | + request.verify_mode = OpenSSL::SSL::VERIFY_NONE | |
45 | + end | |
46 | + request | |
47 | + end | |
48 | + | |
49 | + def external_login(login, password, domain) | |
50 | + # Call Noosfero /api/login | |
51 | + result = nil | |
52 | + response = nil | |
53 | + redirections_allowed = 3 | |
54 | + external_environment = ExternalEnvironment.find_by_url(domain) | |
55 | + scheme = "http#{external_environment.uses_ssl? ? 's' : ''}" | |
56 | + location = scheme + '://' + domain + '/api/v1/login' | |
57 | + request_params = CGI.unescape({ login: login, password: password }.to_query) | |
58 | + begin | |
59 | + while redirections_allowed > 0 && (response.blank? || response.code == '301') | |
60 | + uri = URI.parse(location) | |
61 | + request = build_request(uri) | |
62 | + response = request.post(uri.to_s, request_params) | |
63 | + location = response.header['location'] | |
64 | + redirections_allowed -= 1 | |
65 | + end | |
66 | + result = response.code.to_i / 100 === 2 ? JSON.parse(response.body) : nil | |
67 | + rescue | |
68 | + # Could not make request | |
69 | + end | |
70 | + result | |
71 | + end | |
72 | + | |
73 | + # Authenticates a user from an external social network | |
74 | + def external_authenticate(username, password, environment) | |
75 | + if username && username.include?('@') | |
76 | + login, domain = username.split('@') | |
77 | + webfinger = User.webfinger_lookup(login, domain, environment) | |
78 | + if webfinger | |
79 | + user = User.external_login(login, password, domain) | |
80 | + if user | |
81 | + u = User.new | |
82 | + u.email = user['user']['email'] | |
83 | + u.login = login | |
84 | + webfinger = OpenStruct.new( | |
85 | + identifier: webfinger['properties']['identifier'], | |
86 | + name: webfinger['titles']['name'], | |
87 | + created_at: webfinger['properties']['created_at'], | |
88 | + domain: domain, | |
89 | + email: user['user']['email'] | |
90 | + ) | |
91 | + u.external_person_id = ExternalPerson.get_or_create(webfinger).id | |
92 | + return u | |
93 | + end | |
94 | + end | |
95 | + end | |
96 | + nil | |
97 | + end | |
98 | + | |
99 | + end | |
100 | +end | ... | ... |
... | ... | @@ -0,0 +1,42 @@ |
1 | +module Human | |
2 | + extend ActiveSupport::Concern | |
3 | + | |
4 | + included do | |
5 | + has_many :comments, :as => :author, :foreign_key => :author_id | |
6 | + has_many :abuse_reports, :as => :reporter, :foreign_key => 'reporter_id', :dependent => :destroy | |
7 | + | |
8 | + scope :abusers, -> { | |
9 | + joins(:abuse_complaints).where('tasks.status = 3').distinct.select("#{self.table_name}.*") | |
10 | + } | |
11 | + scope :non_abusers, -> { | |
12 | + distinct.select("#{self.table_name}.*"). | |
13 | + joins("LEFT JOIN tasks ON #{self.table_name}.id = tasks.requestor_id AND tasks.type='AbuseComplaint'"). | |
14 | + where("tasks.status != 3 OR tasks.id is NULL") | |
15 | + } | |
16 | + end | |
17 | + | |
18 | + def already_reported?(profile) | |
19 | + abuse_reports.any? { |report| report.abuse_complaint.reported == profile && report.abuse_complaint.opened? } | |
20 | + end | |
21 | + | |
22 | + def register_report(abuse_report, profile) | |
23 | + AbuseComplaint.create!(:reported => profile, :target => profile.environment) if !profile.opened_abuse_complaint | |
24 | + abuse_report.abuse_complaint = profile.opened_abuse_complaint | |
25 | + abuse_report.reporter = self | |
26 | + abuse_report.save! | |
27 | + end | |
28 | + | |
29 | + def abuser? | |
30 | + AbuseComplaint.finished.where(:requestor_id => self).count > 0 | |
31 | + end | |
32 | + | |
33 | + # Sets the identifier for this person. Raises an exception when called on a | |
34 | + # existing person (since peoples' identifiers cannot be changed) | |
35 | + def identifier=(value) | |
36 | + unless self.new_record? | |
37 | + raise ArgumentError.new(_('An existing person cannot be renamed.')) | |
38 | + end | |
39 | + self[:identifier] = value | |
40 | + end | |
41 | + | |
42 | +end | ... | ... |
... | ... | @@ -0,0 +1,155 @@ |
1 | +module ProfileEntity | |
2 | + extend ActiveSupport::Concern | |
3 | + | |
4 | + included do | |
5 | + attr_accessible :name, :identifier, :environment | |
6 | + | |
7 | + validates_presence_of :identifier, :name | |
8 | + | |
9 | + belongs_to :environment | |
10 | + has_many :search_terms, :as => :context | |
11 | + has_many :abuse_complaints, :as => :reported, :foreign_key => 'requestor_id', :dependent => :destroy | |
12 | + | |
13 | + before_create :set_default_environment | |
14 | + | |
15 | + scope :recent, -> limit=nil { order('id DESC').limit(limit) } | |
16 | + | |
17 | + end | |
18 | + | |
19 | + def disable | |
20 | + self.visible = false | |
21 | + self.save | |
22 | + end | |
23 | + | |
24 | + def enable | |
25 | + self.visible = true | |
26 | + self.save | |
27 | + end | |
28 | + | |
29 | + def opened_abuse_complaint | |
30 | + abuse_complaints.opened.first | |
31 | + end | |
32 | + | |
33 | + def set_default_environment | |
34 | + if self.environment.nil? | |
35 | + self.environment = Environment.default | |
36 | + end | |
37 | + true | |
38 | + end | |
39 | + | |
40 | + # returns +false+ | |
41 | + def person? | |
42 | + self.kind_of?(Person) | |
43 | + end | |
44 | + | |
45 | + def enterprise? | |
46 | + self.kind_of?(Enterprise) | |
47 | + end | |
48 | + | |
49 | + def organization? | |
50 | + self.kind_of?(Organization) | |
51 | + end | |
52 | + | |
53 | + def community? | |
54 | + self.kind_of?(Community) | |
55 | + end | |
56 | + | |
57 | + include ActionView::Helpers::TextHelper | |
58 | + def short_name(chars = 40) | |
59 | + if self[:nickname].blank? | |
60 | + if chars | |
61 | + truncate self.name, length: chars, omission: '...' | |
62 | + else | |
63 | + self.name | |
64 | + end | |
65 | + else | |
66 | + self[:nickname] | |
67 | + end | |
68 | + end | |
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 | + def allow_post_content?(person = nil) | |
136 | + person.kind_of?(Profile) && person.has_permission?('post_content', self) | |
137 | + end | |
138 | + | |
139 | + def allow_edit?(person = nil) | |
140 | + person.kind_of?(Profile) && person.has_permission?('edit_profile', self) | |
141 | + end | |
142 | + | |
143 | + def allow_destroy?(person = nil) | |
144 | + person.kind_of?(Profile) && person.has_permission?('destroy_profile', self) | |
145 | + end | |
146 | + | |
147 | + module ClassMethods | |
148 | + | |
149 | + def identification | |
150 | + name | |
151 | + end | |
152 | + | |
153 | + end | |
154 | + | |
155 | +end | ... | ... |
app/models/environment.rb
... | ... | @@ -1009,6 +1009,10 @@ class Environment < ApplicationRecord |
1009 | 1009 | HashWithIndifferentAccess.new :name => name |
1010 | 1010 | end |
1011 | 1011 | |
1012 | + def has_federated_network?(domain) | |
1013 | + self.external_environments.map(&:url).any? { |url| /http[s]?:\/\/#{domain}\/?/ =~ url } | |
1014 | + end | |
1015 | + | |
1012 | 1016 | private |
1013 | 1017 | |
1014 | 1018 | def default_language_available | ... | ... |
app/models/external_environment.rb
... | ... | @@ -6,4 +6,9 @@ class ExternalEnvironment < ActiveRecord::Base |
6 | 6 | |
7 | 7 | has_many :environment_external_environments, dependent: :destroy |
8 | 8 | has_many :environments, through: :environment_external_environments |
9 | + | |
10 | + def uses_ssl? | |
11 | + url.starts_with? 'https' | |
12 | + end | |
13 | + | |
9 | 14 | end | ... | ... |
... | ... | @@ -0,0 +1,290 @@ |
1 | +# A pseudo profile is a person from a remote network | |
2 | +class ExternalPerson < ActiveRecord::Base | |
3 | + | |
4 | + include Human | |
5 | + include ProfileEntity | |
6 | + | |
7 | + validates_uniqueness_of :identifier, scope: :source | |
8 | + | |
9 | + validates_presence_of :source, :email, :created_at | |
10 | + | |
11 | + attr_accessible :source, :email, :created_at | |
12 | + | |
13 | + def self.get_or_create(webfinger) | |
14 | + user = ExternalPerson.find_by(identifier: webfinger.identifier, source: webfinger.domain) | |
15 | + if user.nil? | |
16 | + user = ExternalPerson.create!(identifier: webfinger.identifier, | |
17 | + name: webfinger.name, | |
18 | + source: webfinger.domain, | |
19 | + email: webfinger.email, | |
20 | + created_at: webfinger.created_at | |
21 | + ) | |
22 | + end | |
23 | + user | |
24 | + end | |
25 | + | |
26 | + def privacy_setting | |
27 | + _('Public profile') | |
28 | + end | |
29 | + | |
30 | + def avatar | |
31 | + "http://#{self.source}/profile/#{self.identifier}/icon/" | |
32 | + end | |
33 | + | |
34 | + def url | |
35 | + "http://#{self.source}/profile/#{self.identifier}" | |
36 | + end | |
37 | + | |
38 | + alias :public_profile_url :url | |
39 | + | |
40 | + def admin_url | |
41 | + "http://#{self.source}/myprofile/#{self.identifier}" | |
42 | + end | |
43 | + | |
44 | + def wall_url | |
45 | + self.url | |
46 | + end | |
47 | + def tasks_url | |
48 | + self.url | |
49 | + end | |
50 | + def leave_url(reload = false) | |
51 | + self.url | |
52 | + end | |
53 | + def join_url | |
54 | + self.url | |
55 | + end | |
56 | + def join_not_logged_url | |
57 | + self.url | |
58 | + end | |
59 | + def check_membership_url | |
60 | + self.url | |
61 | + end | |
62 | + def add_url | |
63 | + self.url | |
64 | + end | |
65 | + def check_friendship_url | |
66 | + self.url | |
67 | + end | |
68 | + def people_suggestions_url | |
69 | + self.url | |
70 | + end | |
71 | + def communities_suggestions_url | |
72 | + self.url | |
73 | + end | |
74 | + def top_url(scheme = 'http') | |
75 | + "#{scheme}://#{self.source}" | |
76 | + end | |
77 | + | |
78 | + def profile_custom_icon(gravatar_default=nil) | |
79 | + self.avatar | |
80 | + end | |
81 | + | |
82 | + def preferred_login_redirection | |
83 | + environment.redirection_after_login | |
84 | + end | |
85 | + | |
86 | + def location | |
87 | + self.source | |
88 | + end | |
89 | + | |
90 | + def default_hostname | |
91 | + environment.default_hostname | |
92 | + end | |
93 | + | |
94 | + def possible_domains | |
95 | + environment.domains | |
96 | + end | |
97 | + | |
98 | + def person? | |
99 | + true | |
100 | + end | |
101 | + | |
102 | + def contact_email(*args) | |
103 | + self.email | |
104 | + end | |
105 | + | |
106 | + def notification_emails | |
107 | + [self.contact_email] | |
108 | + end | |
109 | + | |
110 | + def email_domain | |
111 | + self.source | |
112 | + end | |
113 | + | |
114 | + def email_addresses | |
115 | + ['%s@%s' % [self.identifier, self.source] ] | |
116 | + end | |
117 | + | |
118 | + def jid(options = {}) | |
119 | + "#{self.identifier}@#{self.source}" | |
120 | + end | |
121 | + def full_jid(options = {}) | |
122 | + "#{jid(options)}/#{self.name}" | |
123 | + end | |
124 | + | |
125 | + class ExternalPerson::Image | |
126 | + def initialize(path) | |
127 | + @path = path | |
128 | + end | |
129 | + | |
130 | + def public_filename(size = nil) | |
131 | + URI.join(@path, size.to_s) | |
132 | + end | |
133 | + | |
134 | + def content_type | |
135 | + # This is not really going to be used anywhere that matters | |
136 | + # so we are hardcodding it here. | |
137 | + 'image/png' | |
138 | + end | |
139 | + end | |
140 | + | |
141 | + def image | |
142 | + ExternalPerson::Image.new(avatar) | |
143 | + end | |
144 | + | |
145 | + def data_hash(gravatar_default = nil) | |
146 | + friends_list = {} | |
147 | + { | |
148 | + 'login' => self.identifier, | |
149 | + 'name' => self.name, | |
150 | + 'email' => self.email, | |
151 | + 'avatar' => self.profile_custom_icon(gravatar_default), | |
152 | + 'is_admin' => self.is_admin?, | |
153 | + 'since_month' => self.created_at.month, | |
154 | + 'since_year' => self.created_at.year, | |
155 | + 'email_domain' => self.source, | |
156 | + 'friends_list' => friends_list, | |
157 | + 'enterprises' => [], | |
158 | + 'amount_of_friends' => friends_list.count, | |
159 | + 'chat_enabled' => false | |
160 | + } | |
161 | + end | |
162 | + | |
163 | + # External Person should respond to all methods in Person and Profile | |
164 | + def person_instance_methods | |
165 | + methods_and_responses = { | |
166 | + enterprises: Enterprise.none, communities: Community.none, friends: | |
167 | + Person.none, memberships: Profile.none, friendships: Person.none, | |
168 | + following_articles: Article.none, article_followers: ArticleFollower.none, | |
169 | + requested_tasks: Task.none, mailings: Mailing.none, scraps_sent: | |
170 | + Scrap.none, favorite_enterprise_people: FavoriteEnterprisePerson.none, | |
171 | + favorite_enterprises: Enterprise.none, acepted_forums: Forum.none, | |
172 | + articles_with_access: Article.none, suggested_profiles: | |
173 | + ProfileSuggestion.none, suggested_people: ProfileSuggestion.none, | |
174 | + suggested_communities: ProfileSuggestion.none, user: nil, | |
175 | + refused_communities: Community.none, has_permission?: false, | |
176 | + has_permission_with_admin?: false, has_permission_without_admin?: false, | |
177 | + has_permission_with_plugins?: false, has_permission_without_plugins?: | |
178 | + false, memberships_by_role: Person.none, can_change_homepage?: false, | |
179 | + can_control_scrap?: false, receives_scrap_notification?: false, | |
180 | + can_control_activity?: false, can_post_content?: false, | |
181 | + suggested_friend_groups: [], friend_groups: [], add_friend: nil, | |
182 | + already_request_friendship?: false, remove_friend: nil, | |
183 | + presence_of_required_fields: nil, active_fields: [], required_fields: [], | |
184 | + signup_fields: [], default_set_of_blocks: [], default_set_of_boxes: [], | |
185 | + default_set_of_articles: [], cell_phone: nil, comercial_phone: nil, | |
186 | + nationality: nil, schooling: nil, contact_information: nil, sex: nil, | |
187 | + birth_date: nil, jabber_id: nil, personal_website: nil, address_reference: | |
188 | + nil, district: nil, schooling_status: nil, formation: nil, | |
189 | + custom_formation: nil, area_of_study: nil, custom_area_of_study: nil, | |
190 | + professional_activity: nil, organization_website: nil, organization: nil, | |
191 | + photo: nil, city: nil, state: nil, country: nil, zip_code: nil, | |
192 | + address_line2: nil, copy_communities_from: nil, | |
193 | + has_organization_pending_tasks?: false, organizations_with_pending_tasks: | |
194 | + Organization.none, pending_tasks_for_organization: Task.none, | |
195 | + build_contact: nil, is_a_friend?: false, ask_to_join?: false, refuse_join: | |
196 | + nil, blocks_to_expire_cache: [], cache_keys: [], communities_cache_key: '', | |
197 | + friends_cache_key: '', manage_friends_cache_key: '', | |
198 | + relationships_cache_key: '', is_member_of?: false, follows?: false, | |
199 | + each_friend: nil, is_last_admin?: false, is_last_admin_leaving?: false, | |
200 | + leave: nil, last_notification: nil, notification_time: 0, notifier: nil, | |
201 | + remove_suggestion: nil, allow_invitation_from?: false | |
202 | + } | |
203 | + | |
204 | + derivated_methods = generate_derivated_methods(methods_and_responses) | |
205 | + derivated_methods.merge(methods_and_responses) | |
206 | + end | |
207 | + | |
208 | + def profile_instance_methods | |
209 | + methods_and_responses = { | |
210 | + role_assignments: RoleAssignment.none, favorite_enterprises: | |
211 | + Enterprise.none, memberships: Profile.none, friendships: Profile.none, | |
212 | + tasks: Task.none, suggested_profiles: ProfileSuggestion.none, | |
213 | + suggested_people: ProfileSuggestion.none, suggested_communities: | |
214 | + ProfileSuggestion.none, public_profile: true, nickname: nil, custom_footer: | |
215 | + '', custom_header: '', address: '', zip_code: '', contact_phone: '', | |
216 | + image_builder: nil, description: '', closed: false, template_id: nil, lat: | |
217 | + nil, lng: nil, is_template: false, fields_privacy: {}, preferred_domain_id: | |
218 | + nil, category_ids: [], country: '', city: '', state: '', | |
219 | + national_region_code: '', redirect_l10n: false, notification_time: 0, | |
220 | + custom_url_redirection: nil, email_suggestions: false, | |
221 | + allow_members_to_invite: false, invite_friends_only: false, secret: false, | |
222 | + profile_admin_mail_notification: false, redirection_after_login: nil, | |
223 | + profile_activities: ProfileActivity.none, action_tracker_notifications: | |
224 | + ActionTrackerNotification.none, tracked_notifications: | |
225 | + ActionTracker::Record.none, scraps_received: Scrap.none, template: | |
226 | + Profile.none, comments_received: Comment.none, email_templates: | |
227 | + EmailTemplate.none, members: Profile.none, members_like: Profile.none, | |
228 | + members_by: Profile.none, members_by_role: Profile.none, scraps: | |
229 | + Scrap.none, welcome_page_content: nil, settings: {}, find_in_all_tasks: | |
230 | + nil, top_level_categorization: {}, interests: Category.none, geolocation: | |
231 | + '', country_name: '', pending_categorizations: [], add_category: false, | |
232 | + create_pending_categorizations: false, top_level_articles: Article.none, | |
233 | + valid_identifier: true, valid_template: false, create_default_set_of_boxes: | |
234 | + true, copy_blocks_from: nil, default_template: nil, | |
235 | + template_without_default: nil, template_with_default: nil, apply_template: | |
236 | + false, iframe_whitelist: [], recent_documents: Article.none, last_articles: | |
237 | + Article.none, is_validation_entity?: false, hostname: nil, own_hostname: | |
238 | + nil, article_tags: {}, tagged_with: Article.none, | |
239 | + insert_default_article_set: false, copy_articles_from: true, | |
240 | + copy_article_tree: nil, copy_article?: false, add_member: false, | |
241 | + remove_member: false, add_admin: false, remove_admin: false, add_moderator: | |
242 | + false, display_info_to?: true, update_category_from_region: nil, | |
243 | + accept_category?: false, custom_header_expanded: '', | |
244 | + custom_footer_expanded: '', public?: true, themes: [], find_theme: nil, | |
245 | + blogs: Blog.none, blog: nil, has_blog?: false, forums: Forum.none, forum: | |
246 | + nil, has_forum?: false, admins: [], settings_field: {}, setting_changed: | |
247 | + false, public_content: true, enable_contact?: false, folder_types: [], | |
248 | + folders: Article.none, image_galleries: Article.none, image_valid: true, | |
249 | + update_header_and_footer: nil, update_theme: nil, update_layout_template: | |
250 | + nil, recent_actions: ActionTracker::Record.none, recent_notifications: | |
251 | + ActionTracker::Record.none, more_active_label: _('no activity'), | |
252 | + more_popular_label: _('no members'), profile_custom_image: nil, | |
253 | + is_on_homepage?: false, activities: ProfileActivity.none, | |
254 | + may_display_field_to?: true, may_display_location_to?: true, public_fields: | |
255 | + {}, followed_by?: false, display_private_info_to?: true, can_view_field?: | |
256 | + true, remove_from_suggestion_list: nil, layout_template: 'default', | |
257 | + is_admin?: false, add_friend: false, follows?: false, is_a_friend?: false, | |
258 | + already_request_friendship?: false | |
259 | + } | |
260 | + | |
261 | + derivated_methods = generate_derivated_methods(methods_and_responses) | |
262 | + derivated_methods.merge(methods_and_responses) | |
263 | + end | |
264 | + | |
265 | + def method_missing(method, *args, &block) | |
266 | + if person_instance_methods.keys.include?(method) | |
267 | + return person_instance_methods[method] | |
268 | + end | |
269 | + if profile_instance_methods.keys.include? method | |
270 | + return profile_instance_methods[method] | |
271 | + end | |
272 | + end | |
273 | + | |
274 | + def respond_to_missing?(method_name, include_private = false) | |
275 | + person_instance_methods.keys.include?(method_name) || | |
276 | + profile_instance_methods.keys.include?(method_name) || | |
277 | + super | |
278 | + end | |
279 | + | |
280 | + private | |
281 | + | |
282 | + def generate_derivated_methods(methods) | |
283 | + derivated_methods = {} | |
284 | + methods.keys.each do |method| | |
285 | + derivated_methods[method.to_s.insert(-1, '?').to_sym] = false | |
286 | + derivated_methods[method.to_s.insert(-1, '=').to_sym] = nil | |
287 | + end | |
288 | + derivated_methods | |
289 | + end | |
290 | +end | ... | ... |
app/models/person.rb
1 | 1 | # A person is the profile of an user holding all relationships with the rest of the system |
2 | 2 | class Person < Profile |
3 | 3 | |
4 | + include Human | |
5 | + | |
4 | 6 | attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization_website, :following_articles |
5 | 7 | |
6 | 8 | SEARCH_FILTERS = { |
... | ... | @@ -88,7 +90,6 @@ class Person < Profile |
88 | 90 | memberships.where('role_assignments.role_id = ?', role.id) |
89 | 91 | end |
90 | 92 | |
91 | - has_many :comments, :foreign_key => :author_id | |
92 | 93 | has_many :article_followers, :dependent => :destroy |
93 | 94 | has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article |
94 | 95 | has_many :friendships, :dependent => :destroy |
... | ... | @@ -100,8 +101,6 @@ class Person < Profile |
100 | 101 | |
101 | 102 | has_many :requested_tasks, :class_name => 'Task', :foreign_key => :requestor_id, :dependent => :destroy |
102 | 103 | |
103 | - has_many :abuse_reports, :foreign_key => 'reporter_id', :dependent => :destroy | |
104 | - | |
105 | 104 | has_many :mailings |
106 | 105 | |
107 | 106 | has_many :scraps_sent, :class_name => 'Scrap', :foreign_key => :sender_id, :dependent => :destroy |
... | ... | @@ -123,15 +122,6 @@ class Person < Profile |
123 | 122 | |
124 | 123 | scope :more_popular, -> { order 'friends_count DESC' } |
125 | 124 | |
126 | - scope :abusers, -> { | |
127 | - joins(:abuse_complaints).where('tasks.status = 3').distinct.select('profiles.*') | |
128 | - } | |
129 | - scope :non_abusers, -> { | |
130 | - distinct.select("profiles.*"). | |
131 | - joins("LEFT JOIN tasks ON profiles.id = tasks.requestor_id AND tasks.type='AbuseComplaint'"). | |
132 | - where("tasks.status != 3 OR tasks.id is NULL") | |
133 | - } | |
134 | - | |
135 | 125 | scope :admins, -> { joins(:role_assignments => :role).where('roles.key = ?', 'environment_administrator') } |
136 | 126 | scope :activated, -> { joins(:user).where('users.activation_code IS NULL AND users.activated_at IS NOT NULL') } |
137 | 127 | scope :deactivated, -> { joins(:user).where('NOT (users.activation_code IS NULL AND users.activated_at IS NOT NULL)') } |
... | ... | @@ -174,15 +164,6 @@ class Person < Profile |
174 | 164 | (self.has_permission?('post_content', profile) || self.has_permission?('publish_content', profile)) |
175 | 165 | end |
176 | 166 | |
177 | - # Sets the identifier for this person. Raises an exception when called on a | |
178 | - # existing person (since peoples' identifiers cannot be changed) | |
179 | - def identifier=(value) | |
180 | - unless self.new_record? | |
181 | - raise ArgumentError.new(_('An existing person cannot be renamed.')) | |
182 | - end | |
183 | - self[:identifier] = value | |
184 | - end | |
185 | - | |
186 | 167 | def suggested_friend_groups |
187 | 168 | (friend_groups.compact + [ _('friends'), _('work'), _('school'), _('family') ]).map {|i| i if !i.empty?}.compact.uniq |
188 | 169 | end |
... | ... | @@ -192,7 +173,7 @@ class Person < Profile |
192 | 173 | end |
193 | 174 | |
194 | 175 | def add_friend(friend, group = nil) |
195 | - unless self.is_a_friend?(friend) | |
176 | + unless self.is_a_friend?(friend) || friend.is_a?(ExternalPerson) | |
196 | 177 | friendship = self.friendships.build |
197 | 178 | friendship.friend = friend |
198 | 179 | friendship.group = group |
... | ... | @@ -517,21 +498,6 @@ class Person < Profile |
517 | 498 | leave_hash.to_json |
518 | 499 | end |
519 | 500 | |
520 | - def already_reported?(profile) | |
521 | - abuse_reports.any? { |report| report.abuse_complaint.reported == profile && report.abuse_complaint.opened? } | |
522 | - end | |
523 | - | |
524 | - def register_report(abuse_report, profile) | |
525 | - AbuseComplaint.create!(:reported => profile, :target => profile.environment) if !profile.opened_abuse_complaint | |
526 | - abuse_report.abuse_complaint = profile.opened_abuse_complaint | |
527 | - abuse_report.reporter = self | |
528 | - abuse_report.save! | |
529 | - end | |
530 | - | |
531 | - def abuser? | |
532 | - AbuseComplaint.finished.where(:requestor_id => self).count > 0 | |
533 | - end | |
534 | - | |
535 | 501 | def control_panel_settings_button |
536 | 502 | {:title => _('Edit Profile'), :icon => 'edit-profile'} |
537 | 503 | end |
... | ... | @@ -580,6 +546,34 @@ class Person < Profile |
580 | 546 | person.has_permission?(:manage_friends, self) |
581 | 547 | end |
582 | 548 | |
549 | + def data_hash(gravatar_default = nil) | |
550 | + friends_list = {} | |
551 | + enterprises = self.enterprises.map { |e| { 'name' => e.short_name, 'identifier' => e.identifier } } | |
552 | + self.friends.online.map do |person| | |
553 | + friends_list[person.identifier] = { | |
554 | + 'avatar' => person.profile_custom_icon(gravatar_default), | |
555 | + 'name' => person.short_name, | |
556 | + 'jid' => person.full_jid, | |
557 | + 'status' => person.user.chat_status, | |
558 | + } | |
559 | + end | |
560 | + | |
561 | + { | |
562 | + 'login' => self.identifier, | |
563 | + 'name' => self.name, | |
564 | + 'email' => self.email, | |
565 | + 'avatar' => self.profile_custom_icon(gravatar_default), | |
566 | + 'is_admin' => self.is_admin?, | |
567 | + 'since_month' => self.created_at.month, | |
568 | + 'since_year' => self.created_at.year, | |
569 | + 'email_domain' => self.user.enable_email ? self.user.email_domain : nil, | |
570 | + 'friends_list' => friends_list, | |
571 | + 'enterprises' => enterprises, | |
572 | + 'amount_of_friends' => friends_list.count, | |
573 | + 'chat_enabled' => self.environment.enabled?('xmpp_chat') | |
574 | + } | |
575 | + end | |
576 | + | |
583 | 577 | protected |
584 | 578 | |
585 | 579 | def followed_by?(profile) | ... | ... |
app/models/profile.rb
... | ... | @@ -3,9 +3,10 @@ |
3 | 3 | # which by default is the one returned by Environment:default. |
4 | 4 | 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, | |
7 | - :redirection_after_login, :custom_url_redirection, | |
8 | - :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :profile_admin_mail_notification | |
6 | + include ProfileEntity | |
7 | + | |
8 | + attr_accessible :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, | |
9 | + :custom_url_redirection, :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :profile_admin_mail_notification, :redirection_after_login | |
9 | 10 | |
10 | 11 | # use for internationalizable human type names in search facets |
11 | 12 | # reimplement on subclasses |
... | ... | @@ -115,8 +116,6 @@ class Profile < ApplicationRecord |
115 | 116 | } |
116 | 117 | scope :no_templates, -> { where is_template: false } |
117 | 118 | |
118 | - scope :recent, -> limit=nil { order('id DESC').limit(limit) } | |
119 | - | |
120 | 119 | |
121 | 120 | # Returns a scoped object to select profiles in a given location or in a radius |
122 | 121 | # distance from the given location center. |
... | ... | @@ -224,8 +223,6 @@ class Profile < ApplicationRecord |
224 | 223 | welcome_page && welcome_page.published ? welcome_page.body : nil |
225 | 224 | end |
226 | 225 | |
227 | - has_many :search_terms, :as => :context | |
228 | - | |
229 | 226 | def scraps(scrap=nil) |
230 | 227 | scrap = scrap.is_a?(Scrap) ? scrap.id : scrap |
231 | 228 | scrap.nil? ? Scrap.all_scraps(self) : Scrap.all_scraps(self).find(scrap) |
... | ... | @@ -278,7 +275,6 @@ class Profile < ApplicationRecord |
278 | 275 | |
279 | 276 | has_many :domains, :as => :owner |
280 | 277 | belongs_to :preferred_domain, :class_name => 'Domain', :foreign_key => 'preferred_domain_id' |
281 | - belongs_to :environment | |
282 | 278 | |
283 | 279 | has_many :articles, :dependent => :destroy |
284 | 280 | belongs_to :home_page, :class_name => Article.name, :foreign_key => 'home_page_id' |
... | ... | @@ -305,8 +301,6 @@ class Profile < ApplicationRecord |
305 | 301 | has_many :profile_categorizations_including_virtual, :class_name => 'ProfileCategorization' |
306 | 302 | has_many :categories_including_virtual, :through => :profile_categorizations_including_virtual, :source => :category |
307 | 303 | |
308 | - has_many :abuse_complaints, :foreign_key => 'requestor_id', :dependent => :destroy | |
309 | - | |
310 | 304 | has_many :profile_suggestions, :foreign_key => :suggestion_id, :dependent => :destroy |
311 | 305 | |
312 | 306 | def top_level_categorization |
... | ... | @@ -401,7 +395,6 @@ class Profile < ApplicationRecord |
401 | 395 | self.all |
402 | 396 | end |
403 | 397 | |
404 | - validates_presence_of :identifier, :name | |
405 | 398 | validates_length_of :nickname, :maximum => 16, :allow_nil => true |
406 | 399 | validate :valid_template |
407 | 400 | validate :valid_identifier |
... | ... | @@ -416,14 +409,6 @@ class Profile < ApplicationRecord |
416 | 409 | end |
417 | 410 | end |
418 | 411 | |
419 | - before_create :set_default_environment | |
420 | - def set_default_environment | |
421 | - if self.environment.nil? | |
422 | - self.environment = Environment.default | |
423 | - end | |
424 | - true | |
425 | - end | |
426 | - | |
427 | 412 | # registar callback for creating boxes after the object is created. |
428 | 413 | after_create :create_default_set_of_boxes |
429 | 414 | |
... | ... | @@ -496,9 +481,6 @@ class Profile < ApplicationRecord |
496 | 481 | self.save(:validate => false) |
497 | 482 | end |
498 | 483 | |
499 | - def apply_type_specific_template(template) | |
500 | - end | |
501 | - | |
502 | 484 | xss_terminate :only => [ :name, :nickname, :address, :contact_phone, :description ], :on => 'validation' |
503 | 485 | xss_terminate :only => [ :custom_footer, :custom_header ], :with => 'white_list' |
504 | 486 | |
... | ... | @@ -539,10 +521,6 @@ class Profile < ApplicationRecord |
539 | 521 | ).order('articles.published_at desc, articles.id desc') |
540 | 522 | end |
541 | 523 | |
542 | - def to_liquid | |
543 | - HashWithIndifferentAccess.new :name => name, :identifier => identifier | |
544 | - end | |
545 | - | |
546 | 524 | class << self |
547 | 525 | |
548 | 526 | # finds a profile by its identifier. This method is a shortcut to |
... | ... | @@ -562,23 +540,6 @@ class Profile < ApplicationRecord |
562 | 540 | environment |
563 | 541 | end |
564 | 542 | |
565 | - # returns +false+ | |
566 | - def person? | |
567 | - self.kind_of?(Person) | |
568 | - end | |
569 | - | |
570 | - def enterprise? | |
571 | - self.kind_of?(Enterprise) | |
572 | - end | |
573 | - | |
574 | - def organization? | |
575 | - self.kind_of?(Organization) | |
576 | - end | |
577 | - | |
578 | - def community? | |
579 | - self.kind_of?(Community) | |
580 | - end | |
581 | - | |
582 | 543 | # returns false. |
583 | 544 | def is_validation_entity? |
584 | 545 | false |
... | ... | @@ -683,13 +644,6 @@ private :generate_url, :url_options |
683 | 644 | self.articles.tagged_with(tag) |
684 | 645 | end |
685 | 646 | |
686 | - # Tells whether a specified profile has members or nor. | |
687 | - # | |
688 | - # On this class, returns <tt>false</tt> by default. | |
689 | - def has_members? | |
690 | - false | |
691 | - end | |
692 | - | |
693 | 647 | after_create :insert_default_article_set |
694 | 648 | def insert_default_article_set |
695 | 649 | if template |
... | ... | @@ -704,23 +658,6 @@ private :generate_url, :url_options |
704 | 658 | end |
705 | 659 | end |
706 | 660 | |
707 | - # Override this method in subclasses of Profile to create a default article | |
708 | - # set upon creation. Note that this method will be called *only* if there is | |
709 | - # no template for the type of profile (i.e. if the template was removed or in | |
710 | - # the creation of the template itself). | |
711 | - # | |
712 | - # This method must return an array of pre-populated articles, which will be | |
713 | - # associated to the profile before being saved. Example: | |
714 | - # | |
715 | - # def default_set_of_articles | |
716 | - # [Blog.new(:name => 'Blog'), Gallery.new(:name => 'Gallery')] | |
717 | - # end | |
718 | - # | |
719 | - # By default, this method returns an empty array. | |
720 | - def default_set_of_articles | |
721 | - [] | |
722 | - end | |
723 | - | |
724 | 661 | def copy_articles_from other |
725 | 662 | return false if other.top_level_articles.empty? |
726 | 663 | other.top_level_articles.each do |a| |
... | ... | @@ -816,19 +753,6 @@ private :generate_url, :url_options |
816 | 753 | !forbidden.include?(cat.class) |
817 | 754 | end |
818 | 755 | |
819 | - include ActionView::Helpers::TextHelper | |
820 | - def short_name(chars = 40) | |
821 | - if self[:nickname].blank? | |
822 | - if chars | |
823 | - truncate self.name, length: chars, omission: '...' | |
824 | - else | |
825 | - self.name | |
826 | - end | |
827 | - else | |
828 | - self[:nickname] | |
829 | - end | |
830 | - end | |
831 | - | |
832 | 756 | def custom_header |
833 | 757 | self[:custom_header] || environment && environment.custom_header |
834 | 758 | end |
... | ... | @@ -934,14 +858,6 @@ private :generate_url, :url_options |
934 | 858 | articles.galleries |
935 | 859 | end |
936 | 860 | |
937 | - def blocks_to_expire_cache | |
938 | - [] | |
939 | - end | |
940 | - | |
941 | - def cache_keys(params = {}) | |
942 | - [] | |
943 | - end | |
944 | - | |
945 | 861 | validate :image_valid |
946 | 862 | |
947 | 863 | def image_valid |
... | ... | @@ -978,16 +894,6 @@ private :generate_url, :url_options |
978 | 894 | self.update_attribute(:layout_template, template) |
979 | 895 | end |
980 | 896 | |
981 | - def members_cache_key(params = {}) | |
982 | - page = params[:npage] || '1' | |
983 | - sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' | |
984 | - cache_key + '-members-page-' + page + '-' + sort | |
985 | - end | |
986 | - | |
987 | - def more_recent_label | |
988 | - _("Since: ") | |
989 | - end | |
990 | - | |
991 | 897 | def recent_actions |
992 | 898 | tracked_actions.recent |
993 | 899 | end |
... | ... | @@ -1042,32 +948,6 @@ private :generate_url, :url_options |
1042 | 948 | end |
1043 | 949 | end |
1044 | 950 | |
1045 | - def opened_abuse_complaint | |
1046 | - abuse_complaints.opened.first | |
1047 | - end | |
1048 | - | |
1049 | - def disable | |
1050 | - self.visible = false | |
1051 | - self.save | |
1052 | - end | |
1053 | - | |
1054 | - def enable | |
1055 | - self.visible = true | |
1056 | - self.save | |
1057 | - end | |
1058 | - | |
1059 | - def control_panel_settings_button | |
1060 | - {:title => _('Edit Profile'), :icon => 'edit-profile'} | |
1061 | - end | |
1062 | - | |
1063 | - def self.identification | |
1064 | - name | |
1065 | - end | |
1066 | - | |
1067 | - def exclude_verbs_on_activities | |
1068 | - %w[] | |
1069 | - end | |
1070 | - | |
1071 | 951 | # Customize in subclasses |
1072 | 952 | def activities |
1073 | 953 | self.profile_activities.includes(:activity).order('updated_at DESC') |
... | ... | @@ -1102,10 +982,6 @@ private :generate_url, :url_options |
1102 | 982 | self.active_fields |
1103 | 983 | end |
1104 | 984 | |
1105 | - def control_panel_settings_button | |
1106 | - {:title => _('Profile Info and settings'), :icon => 'edit-profile'} | |
1107 | - end | |
1108 | - | |
1109 | 985 | def followed_by?(person) |
1110 | 986 | person.is_member_of?(self) |
1111 | 987 | end |
... | ... | @@ -1133,19 +1009,4 @@ private :generate_url, :url_options |
1133 | 1009 | suggestion.disable if suggestion |
1134 | 1010 | end |
1135 | 1011 | |
1136 | - def allow_invitation_from(person) | |
1137 | - false | |
1138 | - end | |
1139 | - | |
1140 | - def allow_post_content?(person = nil) | |
1141 | - person.kind_of?(Profile) && person.has_permission?('post_content', self) | |
1142 | - end | |
1143 | - | |
1144 | - def allow_edit?(person = nil) | |
1145 | - person.kind_of?(Profile) && person.has_permission?('edit_profile', self) | |
1146 | - end | |
1147 | - | |
1148 | - def allow_destroy?(person = nil) | |
1149 | - person.kind_of?(Profile) && person.has_permission?('destroy_profile', self) | |
1150 | - end | |
1151 | 1012 | end | ... | ... |
app/models/user.rb
... | ... | @@ -7,6 +7,8 @@ class User < ApplicationRecord |
7 | 7 | |
8 | 8 | attr_accessible :login, :email, :password, :password_confirmation, :activated_at |
9 | 9 | |
10 | + include ExternalUser | |
11 | + | |
10 | 12 | N_('Password') |
11 | 13 | N_('Password confirmation') |
12 | 14 | N_('Terms accepted') |
... | ... | @@ -105,6 +107,8 @@ class User < ApplicationRecord |
105 | 107 | has_one :person, dependent: :destroy, autosave: false |
106 | 108 | belongs_to :environment |
107 | 109 | |
110 | + alias_method_chain :person, :external | |
111 | + | |
108 | 112 | has_many :sessions, dependent: :destroy |
109 | 113 | # holds the current session, see lib/authenticated_system.rb |
110 | 114 | attr_accessor :session |
... | ... | @@ -146,7 +150,8 @@ class User < ApplicationRecord |
146 | 150 | u.generate_private_token_if_not_exist |
147 | 151 | return u |
148 | 152 | end |
149 | - return nil | |
153 | + | |
154 | + return User.external_authenticate(login, password, environment) | |
150 | 155 | end |
151 | 156 | |
152 | 157 | def register_login |
... | ... | @@ -380,31 +385,7 @@ class User < ApplicationRecord |
380 | 385 | end |
381 | 386 | |
382 | 387 | def data_hash(gravatar_default = nil) |
383 | - friends_list = {} | |
384 | - enterprises = person.enterprises.map { |e| { 'name' => e.short_name, 'identifier' => e.identifier } } | |
385 | - self.person.friends.online.map do |person| | |
386 | - friends_list[person.identifier] = { | |
387 | - 'avatar' => person.profile_custom_icon(gravatar_default), | |
388 | - 'name' => person.short_name, | |
389 | - 'jid' => person.full_jid, | |
390 | - 'status' => person.user.chat_status, | |
391 | - } | |
392 | - end | |
393 | - | |
394 | - { | |
395 | - 'login' => self.login, | |
396 | - 'name' => self.person.name, | |
397 | - 'email' => self.email, | |
398 | - 'avatar' => self.person.profile_custom_icon(gravatar_default), | |
399 | - 'is_admin' => self.person.is_admin?, | |
400 | - 'since_month' => self.person.created_at.month, | |
401 | - 'since_year' => self.person.created_at.year, | |
402 | - 'email_domain' => self.enable_email ? self.email_domain : nil, | |
403 | - 'friends_list' => friends_list, | |
404 | - 'enterprises' => enterprises, | |
405 | - 'amount_of_friends' => friends_list.count, | |
406 | - 'chat_enabled' => person.environment.enabled?('xmpp_chat') | |
407 | - } | |
388 | + self.person.data_hash(gravatar_default) | |
408 | 389 | end |
409 | 390 | |
410 | 391 | def self.expires_chat_status_every | ... | ... |
app/views/account/welcome.html.erb
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 | <%= _('%s was successfuly activated. Now you may go to your control panel or to the control panel of your enterprise') % @enterprise.name %> |
5 | 5 | |
6 | 6 | <%= button_bar do %> |
7 | - <%= button 'forward', _('Go to my control panel'), :action => 'index', :controller => 'profile_editor', :profile => current_user.person.identifier %> | |
7 | + <%= button 'forward', _('Go to my control panel'), :action => 'index', :controller => 'profile_editor', :profile => current_person.identifier %> | |
8 | 8 | <%= button 'forward', _('Go to my enterprise control panel') % @enterprise.name, :action => 'index', :controller => 'profile_editor', :profile => @enterprise.identifier %> |
9 | 9 | <% end %> |
10 | 10 | <% end %> | ... | ... |
app/views/enterprise_registration/basic_information.html.erb
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | </div> |
10 | 10 | |
11 | 11 | <%= button_bar do %> |
12 | - <%= button :back, _('Go back'), { :profile => current_user.person.identifier, :action=>"enterprises", :controller=>"profile" }%> | |
12 | + <%= button :back, _('Go back'), { :profile => current_person.identifier, :action=>"enterprises", :controller=>"profile" }%> | |
13 | 13 | <% end %> |
14 | 14 | <% else %> |
15 | 15 | <div class='atention'> |
... | ... | @@ -37,7 +37,7 @@ |
37 | 37 | <%= template_options(:enterprises, 'create_enterprise')%> |
38 | 38 | |
39 | 39 | <%= button_bar do %> |
40 | - <%= submit_button('next', _('Next'), :cancel => {:profile => current_user.person.identifier, :action=>"enterprises", :controller=>"profile"}) %> | |
40 | + <%= submit_button('next', _('Next'), :cancel => {:profile => current_person.identifier, :action=>"enterprises", :controller=>"profile"}) %> | |
41 | 41 | <% end %> |
42 | 42 | <% end %> |
43 | 43 | <% end %> | ... | ... |
app/views/environment_role_manager/affiliate.html.erb
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | |
3 | 3 | <%= form_tag( {:action => 'give_role'}, {:method => :post}) do %> |
4 | 4 | <%= select_tag 'role', options_for_select(@roles.map{|r|[r.name,r.id]}) %> |
5 | - <%= hidden_field_tag 'person', current_user.person.id %> | |
5 | + <%= hidden_field_tag 'person', current_person.id %> | |
6 | 6 | <%= button_bar do %> |
7 | 7 | <%= submit_button('affiliate', _('Affiliate', :cancel => {:action => 'index'}) %> |
8 | 8 | <% end %> | ... | ... |
app/views/layouts/_user.html.erb
app/views/profile_members/affiliate.html.erb
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | |
3 | 3 | <%= form_tag( {:action => 'give_role'}, {:method => :post}) do %> |
4 | 4 | <%= select_tag 'role', options_for_select(@roles.map{|r|[r.name,r.id]}) %> |
5 | - <%= hidden_field_tag 'person', current_user.person.id %> | |
5 | + <%= hidden_field_tag 'person', current_person.id %> | |
6 | 6 | <%= button_bar do %> |
7 | 7 | <%= submit_button('affiliate', _('Affiliate'), :cancel => {:action => 'index'}) %> |
8 | 8 | <% end %> | ... | ... |
config/routes.rb
... | ... | @@ -87,6 +87,9 @@ Noosfero::Application.routes.draw do |
87 | 87 | # comments |
88 | 88 | match 'profile/:profile/comment/:action/:id', controller: 'comment', profile: /#{Noosfero.identifier_format_in_url}/i, via: :all |
89 | 89 | |
90 | + # icon | |
91 | + match 'profile/:profile/icon(/:size)', controller: 'profile', action: 'icon', size: /(big|minor|thumb|portrait|icon)/, profile: /#{Noosfero.identifier_format_in_url}/i, via: :get | |
92 | + | |
90 | 93 | # public profile information |
91 | 94 | match 'profile/:profile(/:action(/:id))', controller: 'profile', action: 'index', id: /[^\/]*/, profile: /#{Noosfero.identifier_format_in_url}/i, as: :profile, via: :all |
92 | 95 | ... | ... |
db/migrate/20160420125236_add_type_to_polymorphic_profile_associations.rb
0 → 100644
... | ... | @@ -0,0 +1,17 @@ |
1 | +class AddTypeToPolymorphicProfileAssociations < ActiveRecord::Migration | |
2 | + def up | |
3 | + add_column :tasks, :reported_type, :string | |
4 | + add_column :abuse_reports, :reporter_type, :string | |
5 | + add_column :comments, :author_type, :string | |
6 | + | |
7 | + update("UPDATE tasks SET reported_type='Profile'") | |
8 | + update("UPDATE abuse_reports SET reporter_type='Person'") | |
9 | + update("UPDATE comments SET author_type='Person'") | |
10 | + end | |
11 | + | |
12 | + def down | |
13 | + remove_column :abuse_complaints, :reported_type | |
14 | + remove_column :abuse_reports, :reporter_type | |
15 | + remove_column :comments, :author_type | |
16 | + end | |
17 | +end | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +class CreateExternalPerson < ActiveRecord::Migration | |
2 | + def change | |
3 | + create_table :external_people do |t| | |
4 | + t.string :name | |
5 | + t.string :identifier | |
6 | + t.string :source | |
7 | + t.string :email | |
8 | + t.integer :environment_id | |
9 | + t.boolean :visible, default: true | |
10 | + t.datetime :created_at | |
11 | + t.datetime :updated_at | |
12 | + end | |
13 | + end | |
14 | +end | ... | ... |
db/schema.rb
... | ... | @@ -23,6 +23,7 @@ ActiveRecord::Schema.define(version: 20160422163123) do |
23 | 23 | t.text "reason" |
24 | 24 | t.datetime "created_at" |
25 | 25 | t.datetime "updated_at" |
26 | + t.string "reporter_type" | |
26 | 27 | end |
27 | 28 | |
28 | 29 | create_table "action_tracker", force: :cascade do |t| |
... | ... | @@ -289,6 +290,7 @@ ActiveRecord::Schema.define(version: 20160422163123) do |
289 | 290 | t.string "user_agent" |
290 | 291 | t.string "referrer" |
291 | 292 | t.text "settings" |
293 | + t.string "author_type" | |
292 | 294 | end |
293 | 295 | |
294 | 296 | add_index "comments", ["source_id", "spam"], name: "index_comments_on_source_id_and_spam", using: :btree |
... | ... | @@ -404,6 +406,14 @@ ActiveRecord::Schema.define(version: 20160422163123) do |
404 | 406 | t.boolean "disable_feed_ssl", default: false |
405 | 407 | end |
406 | 408 | |
409 | + create_table "external_environments", force: :cascade do |t| | |
410 | + t.string "name" | |
411 | + t.string "url" | |
412 | + t.string "identifier" | |
413 | + t.string "screenshot" | |
414 | + t.string "thumbnail" | |
415 | + end | |
416 | + | |
407 | 417 | create_table "external_feeds", force: :cascade do |t| |
408 | 418 | t.string "feed_title" |
409 | 419 | t.datetime "fetched_at" |
... | ... | @@ -421,6 +431,17 @@ ActiveRecord::Schema.define(version: 20160422163123) do |
421 | 431 | add_index "external_feeds", ["enabled"], name: "index_external_feeds_on_enabled", using: :btree |
422 | 432 | add_index "external_feeds", ["fetched_at"], name: "index_external_feeds_on_fetched_at", using: :btree |
423 | 433 | |
434 | + create_table "external_people", force: :cascade do |t| | |
435 | + t.string "name" | |
436 | + t.string "identifier" | |
437 | + t.string "source" | |
438 | + t.string "email" | |
439 | + t.integer "environment_id" | |
440 | + t.boolean "visible", default: true | |
441 | + t.datetime "created_at" | |
442 | + t.datetime "updated_at" | |
443 | + end | |
444 | + | |
424 | 445 | create_table "favorite_enterprise_people", force: :cascade do |t| |
425 | 446 | t.integer "person_id" |
426 | 447 | t.integer "enterprise_id" |
... | ... | @@ -432,14 +453,6 @@ ActiveRecord::Schema.define(version: 20160422163123) do |
432 | 453 | add_index "favorite_enterprise_people", ["person_id", "enterprise_id"], name: "index_favorite_enterprise_people_on_person_id_and_enterprise_id", using: :btree |
433 | 454 | add_index "favorite_enterprise_people", ["person_id"], name: "index_favorite_enterprise_people_on_person_id", using: :btree |
434 | 455 | |
435 | - create_table "external_environments", force: :cascade do |t| | |
436 | - t.string "name" | |
437 | - t.string "url" | |
438 | - t.string "identifier" | |
439 | - t.string "screenshot" | |
440 | - t.string "thumbnail" | |
441 | - end | |
442 | - | |
443 | 456 | create_table "friendships", force: :cascade do |t| |
444 | 457 | t.integer "person_id" |
445 | 458 | t.integer "friend_id" |
... | ... | @@ -797,6 +810,7 @@ ActiveRecord::Schema.define(version: 20160422163123) do |
797 | 810 | t.boolean "spam", default: false |
798 | 811 | t.integer "responsible_id" |
799 | 812 | t.integer "closed_by_id" |
813 | + t.string "reported_type" | |
800 | 814 | end |
801 | 815 | |
802 | 816 | add_index "tasks", ["requestor_id"], name: "index_tasks_on_requestor_id", using: :btree | ... | ... |
... | ... | @@ -0,0 +1,55 @@ |
1 | +Feature: external login | |
2 | + As a user | |
3 | + I want to login using an account from a federated network | |
4 | + In order to view pages logged in | |
5 | + | |
6 | + @selenium | |
7 | + Scenario: login from portal homepage | |
8 | + Given feature "allow_change_of_redirection_after_login" is disabled on environment | |
9 | + And the following external environments | |
10 | + | identifier | name | url | | |
11 | + | test | Test | http://federated.noosfero.org | | |
12 | + And the following external users | |
13 | + | login | | |
14 | + | joaosilva@federated.noosfero.org | | |
15 | + And I am not logged in | |
16 | + And I go to the homepage | |
17 | + And I follow "Login" | |
18 | + And I fill in the following: | |
19 | + | Username / Email | joaosilva@federated.noosfero.org | | |
20 | + | Password | 123456 | | |
21 | + When I press "Log in" | |
22 | + Then I should be on the homepage | |
23 | + And I should be externally logged in as "joaosilva@federated.noosfero.org" | |
24 | + | |
25 | + @selenium | |
26 | + Scenario: not login from portal homepage | |
27 | + Given feature "allow_change_of_redirection_after_login" is disabled on environment | |
28 | + And the following external environments | |
29 | + | identifier | name | url | | |
30 | + | test | Test | http://federated.noosfero.org | | |
31 | + And I am not logged in | |
32 | + And I go to the homepage | |
33 | + And I follow "Login" | |
34 | + And I fill in the following: | |
35 | + | Username / Email | joaosilva@federated.noosfero.org | | |
36 | + | Password | 123456 | | |
37 | + When I press "Log in" | |
38 | + Then I should be on /account/login | |
39 | + And I should not be externally logged in as "joaosilva@federated.noosfero.org" | |
40 | + | |
41 | + @selenium | |
42 | + Scenario: not login if network is not whitelisted | |
43 | + Given feature "allow_change_of_redirection_after_login" is disabled on environment | |
44 | + And the following external users | |
45 | + | login | | |
46 | + | joaosilva@federated.noosfero.org | | |
47 | + And I am not logged in | |
48 | + And I go to the homepage | |
49 | + And I follow "Login" | |
50 | + And I fill in the following: | |
51 | + | Username / Email | joaosilva@federated.noosfero.org | | |
52 | + | Password | 123456 | | |
53 | + When I press "Log in" | |
54 | + Then I should be on /account/login | |
55 | + And I should not be externally logged in as "joaosilva@federated.noosfero.org" | ... | ... |
features/step_definitions/noosfero_steps.rb
... | ... | @@ -679,3 +679,36 @@ Given /^the field (.*) is public for all users$/ do |field| |
679 | 679 | person.save! |
680 | 680 | end |
681 | 681 | end |
682 | + | |
683 | +Given /^the following external users?$/ do |table| | |
684 | + table.hashes.each do |item| | |
685 | + person_data = item.dup | |
686 | + username, domain = person_data['login'].split('@') | |
687 | + response = OpenStruct.new( | |
688 | + code: '200', | |
689 | + body: { | |
690 | + user: { | |
691 | + email: username + '@ema.il', | |
692 | + person: { | |
693 | + identifier: username, | |
694 | + name: username, | |
695 | + created_at: Time.now, | |
696 | + } | |
697 | + } | |
698 | + }.to_json | |
699 | + ) | |
700 | + Net::HTTP.stub(:post_form).and_return(response) | |
701 | + end | |
702 | +end | |
703 | + | |
704 | +Then /^I should be externally logged in as "([^@]+)@(.+)"$/ do |username, domain| | |
705 | + visit '/' | |
706 | + url = 'http://' + domain + '/' + username | |
707 | + page.should have_xpath("//a[@href=\"#{url}\"]") | |
708 | +end | |
709 | + | |
710 | +Then /^I should not be externally logged in as "([^@]+)@(.+)"$/ do |username, domain| | |
711 | + visit '/' | |
712 | + url = 'http://' + domain + '/' + username | |
713 | + page.should_not have_xpath("//a[@href=\"#{url}\"]") | |
714 | +end | ... | ... |
features/support/env.rb
plugins/organization_ratings/controllers/organization_ratings_plugin_profile_controller.rb
... | ... | @@ -38,7 +38,7 @@ class OrganizationRatingsPluginProfileController < ProfileController |
38 | 38 | |
39 | 39 | def create_new_rate |
40 | 40 | @rating = OrganizationRating.new(params[:organization_rating]) |
41 | - @rating.person = current_user.person | |
41 | + @rating.person = current_person | |
42 | 42 | @rating.organization = profile |
43 | 43 | @rating.value = params[:organization_rating_value] if params[:organization_rating_value] |
44 | 44 | ... | ... |
plugins/organization_ratings/test/functional/organization_ratings_plugin_profile_controller_test.rb
... | ... | @@ -173,6 +173,7 @@ class OrganizationRatingsPluginProfileControllerTest < ActionController::TestCas |
173 | 173 | |
174 | 174 | logout |
175 | 175 | @controller.stubs(:logged_in?).returns(false) |
176 | + @controller.stubs(:current_user).returns(nil) | |
176 | 177 | |
177 | 178 | get :new_rating, profile: @community.identifier |
178 | 179 | assert_no_tag :tag => 'p', :content => /Report waiting for approval/, :attributes => {:class =>/comment-rejected-msg/} | ... | ... |
plugins/organization_ratings/views/organization_ratings_plugin_profile/_new_rating_fields.html.erb
... | ... | @@ -5,11 +5,11 @@ |
5 | 5 | |
6 | 6 | <div class="star-profile-information"> |
7 | 7 | <div class="star-profile-image"> |
8 | - <%= link_to profile_image(current_user.person, :portrait), current_user.person.url %> | |
8 | + <%= link_to profile_image(current_person, :portrait), current_person.url %> | |
9 | 9 | </div> |
10 | 10 | |
11 | 11 | <div class="star-profile-name"> |
12 | - <%= link_to current_user.person.name, current_user.person.url %> | |
12 | + <%= link_to current_person.name, current_person.url %> | |
13 | 13 | </div> |
14 | 14 | </div> |
15 | 15 | |
... | ... | @@ -55,14 +55,14 @@ |
55 | 55 | </div> |
56 | 56 | <% elsif env_organization_ratings_config.vote_once %> |
57 | 57 | <div class="star-rate-form rating-vote-once"> |
58 | - <%= _("Hi, %s! The administrators set that you can vote") % current_user.name %> | |
58 | + <%= _("Hi, %s! The administrators set that you can vote") % current_person.name %> | |
59 | 59 | <strong><%= _("only once") %></strong> |
60 | 60 | <%= _("for this %s.") % profile.class.name.downcase %> |
61 | 61 | <%= render :partial => 'shared/rating_button', :locals => { :disabled => true } %> |
62 | 62 | </div> |
63 | 63 | <% else %> |
64 | 64 | <div class="star-rate-form rating-cooldown"> |
65 | - <%= _("Hi, %s! The administrators set the minimum time of") % current_user.name %> | |
65 | + <%= _("Hi, %s! The administrators set the minimum time of") % current_person.name %> | |
66 | 66 | <strong><%= _("%d hour(s)") % env_organization_ratings_config.cooldown %></strong> |
67 | 67 | <%= _("between each evaluation.") %> |
68 | 68 | ... | ... |
plugins/organization_ratings/views/shared/_make_report_block.html.erb
1 | -<% logged_in_image = link_to profile_image(current_user.person, :portrait), current_user.person.url if current_user %> | |
2 | -<% logged_in_name = link_to current_user.person.name, current_user.person.url if current_user %> | |
3 | -<% logged_out_image = image_tag('plugins/organization_ratings/images/user-not-logged.png') %> | |
1 | +<% logged_in_image = link_to profile_image(current_person, :portrait), current_person.url if current_user %> | |
2 | +<% logged_in_name = link_to current_person.name, current_person.url if current_user %> | |
3 | +<% logged_out_image = image_tag('plugins/organization_ratings/public/images/user-not-logged.png') %> | |
4 | 4 | |
5 | 5 | <div class="make-report-block"> |
6 | 6 | <div class="star-profile-information"> |
... | ... | @@ -26,4 +26,4 @@ |
26 | 26 | </div> |
27 | 27 | <% end %> |
28 | 28 | </div> |
29 | -</div> | |
30 | 29 | \ No newline at end of file |
30 | +</div> | ... | ... |
plugins/responsive/lib/ext/application_helper.rb
... | ... | @@ -140,7 +140,7 @@ module ApplicationHelper |
140 | 140 | [s_('contents|Most commented'), {host: host, controller: :search, action: :contents, filter: 'more_comments'}], |
141 | 141 | ] |
142 | 142 | if logged_in? |
143 | - links.push [_('New content'), '', modal_options({href: url_for({controller: 'cms', action: 'new', profile: current_user.login, cms: true})})] | |
143 | + links.push [_('New content'), '', modal_options({href: url_for({controller: 'cms', action: 'new', profile: current_person.identifier, cms: true})})] | |
144 | 144 | end |
145 | 145 | |
146 | 146 | content_tag :li, class: 'dropdown' do |
... | ... | @@ -170,8 +170,8 @@ module ApplicationHelper |
170 | 170 | [s_('people|More popular'), {host: host, controller: :search, action: :people, filter: 'more_popular'}], |
171 | 171 | ] |
172 | 172 | if logged_in? |
173 | - links.push [_('My friends'), {profile: current_user.login, controller: 'friends'}] | |
174 | - links.push [_('Invite friends'), {profile: current_user.login, controller: 'invite', action: 'friends'}] | |
173 | + links.push [_('My friends'), {profile: current_person.identifier, controller: 'friends'}] | |
174 | + links.push [_('Invite friends'), {profile: current_person.identifier, controller: 'invite', action: 'friends'}] | |
175 | 175 | end |
176 | 176 | |
177 | 177 | content_tag :li, class: 'dropdown' do |
... | ... | @@ -201,8 +201,8 @@ module ApplicationHelper |
201 | 201 | [s_('communities|More popular'), {host: host, controller: :search, action: :communities, filter: 'more_popular'}], |
202 | 202 | ] |
203 | 203 | if logged_in? |
204 | - links.push [_('My communities'), {profile: current_user.login, controller: 'memberships'}] | |
205 | - links.push [_('New community'), {profile: current_user.login, controller: 'memberships', action: 'new_community'}] | |
204 | + links.push [_('My communities'), {profile: current_person.identifier, controller: 'memberships'}] | |
205 | + links.push [_('New community'), {profile: current_person.identifier, controller: 'memberships', action: 'new_community'}] | |
206 | 206 | end |
207 | 207 | |
208 | 208 | content_tag :li, class: 'dropdown' do | ... | ... |
plugins/sniffer/views/blocks/interests.html.erb
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 | </ul> |
9 | 9 | |
10 | 10 | <div> |
11 | - <% if logged_in? and (current_user.person.is_admin?(environment) or profile.admins.include?(current_user.person)) %> | |
11 | + <% if logged_in? and (current_person.is_admin?(environment) or profile.admins.include?(current_person)) %> | |
12 | 12 | <%= _('Edit %{inputs} and %{block.interests}') % { |
13 | 13 | :inputs => link_to(_("products' inputs"), :controller => :manage_products, :action => :index), |
14 | 14 | :interests => link_to(_('declared interests'), :controller => :sniffer_plugin_myprofile, :action => :edit), | ... | ... |
plugins/solr/lib/solr_plugin/search_helper.rb
... | ... | @@ -12,9 +12,9 @@ module SolrPlugin::SearchHelper |
12 | 12 | :products => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, |
13 | 13 | :more_recent, {:label => c_('More recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}}, |
14 | 14 | :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, |
15 | - :closest, {:label => _('Closest to me'), :if => proc{ logged_in? && (profile=current_user.person).lat && profile.lng }, | |
15 | + :closest, {:label => _('Closest to me'), :if => proc{ logged_in? && (profile=current_person).lat && profile.lng }, | |
16 | 16 | :solr_opts => {:sort => "geodist() asc", |
17 | - :latitude => proc{ current_user.person.lat }, :longitude => proc{ current_user.person.lng }}}, | |
17 | + :latitude => proc{ current_person.lat }, :longitude => proc{ current_person.lng }}}, | |
18 | 18 | ], |
19 | 19 | :events => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, |
20 | 20 | :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | ... | ... |
... | ... | @@ -0,0 +1,53 @@ |
1 | +require_relative '../test_helper' | |
2 | + | |
3 | +class WebfingerTest < ActiveSupport::TestCase | |
4 | + def setup | |
5 | + Domain.create(name: 'example.com') | |
6 | + Environment.default.domains << Domain.last | |
7 | + User.create(login: 'ze', email: 'ze@localdomain.localdomain', | |
8 | + password: 'zeze', password_confirmation: 'zeze') | |
9 | + end | |
10 | + | |
11 | + should 'return correct user via webfinger url' do | |
12 | + get '.well-known/webfinger?resource=acct%3Aze%40example.com' | |
13 | + webfinger = JSON.parse(last_response.body) | |
14 | + assert_equal 200, last_response.status | |
15 | + assert_equal webfinger['subject'], 'acct:ze@example.com' | |
16 | + end | |
17 | + | |
18 | + should 'not return json when user not found' do | |
19 | + invalid_user = 'invalid_user_in_url' | |
20 | + get ".well-known/webfinger?resource=acct%3A#{invalid_user}%40example.com" | |
21 | + assert_equal 404, last_response.status | |
22 | + end | |
23 | + | |
24 | + should 'return correct article via webfinger url' do | |
25 | + a = fast_create(Article, name: 'my article', profile_id: 1) | |
26 | + get ".well-known/webfinger?resource=http://example.com/article/id/#{a.id}" | |
27 | + webfinger = JSON.parse(last_response.body) | |
28 | + assert_equal 200, last_response.status | |
29 | + assert_equal webfinger['subject'], "http://example.com/article/id/#{a.id}" | |
30 | + end | |
31 | + | |
32 | + should 'not return json when domain is invalid' do | |
33 | + invalid_domain = 'doest_not_exist.com' | |
34 | + get ".well-known/webfinger?resource=http://#{invalid_domain}/article/id/1" | |
35 | + assert_equal 404, last_response.status | |
36 | + end | |
37 | + | |
38 | + should 'not return json when entity is not found' do | |
39 | + get '.well-known/webfinger?resource=http://example.com/article/id/999999' | |
40 | + assert_equal 404, last_response.status | |
41 | + end | |
42 | + | |
43 | + should 'not return json when entity does not exist' do | |
44 | + get '.well-known/webfinger?resource=http://example.com/doest_not_exist/id/1' | |
45 | + assert_equal 404, last_response.status | |
46 | + end | |
47 | + | |
48 | + should 'not return json when request is not http' do | |
49 | + not_http_url = 'kkttc://example.com/article/id/1' | |
50 | + get ".well-known/webfinger?resource=#{not_http_url}" | |
51 | + assert_equal 404, last_response.status | |
52 | + end | |
53 | +end | ... | ... |
test/api/people_test.rb
... | ... | @@ -369,6 +369,44 @@ class PeopleTest < ActiveSupport::TestCase |
369 | 369 | assert_equal "www.blog.org", json['person']['additional_data']['Custom Blog'] |
370 | 370 | end |
371 | 371 | |
372 | + should 'return portrait icon if size is not provided and there is a profile image' do | |
373 | + img = Image.create!(uploaded_data: fixture_file_upload('/files/rails.png', 'image/png')) | |
374 | + profile = fast_create(Person, image_id: img.id) | |
375 | + | |
376 | + get "/api/v1/people/#{profile.id}/icon?#{params.to_query}" | |
377 | + assert_equal 200, last_response.status | |
378 | + json = JSON.parse(last_response.body) | |
379 | + assert_match(/^https?:\/\/.*portrait\.png$/, json['icon']) | |
380 | + end | |
381 | + | |
382 | + should 'return icon in provided size if there is a profile image' do | |
383 | + img = Image.create!(uploaded_data: fixture_file_upload('/files/rails.png', 'image/png')) | |
384 | + profile = fast_create(Person, image_id: img.id) | |
385 | + | |
386 | + get "/api/v1/people/#{profile.id}/icon?#{params.to_query}&size=big" | |
387 | + assert_equal 200, last_response.status | |
388 | + json = JSON.parse(last_response.body) | |
389 | + assert_match(/^https?:\/\/.*big\.png$/, json['icon']) | |
390 | + end | |
391 | + | |
392 | + should 'return icon from gravatar without size if there is no profile image' do | |
393 | + profile = create_user('test-user').person | |
394 | + | |
395 | + get "/api/v1/people/#{profile.id}/icon?#{params.to_query}" | |
396 | + assert_equal 200, last_response.status | |
397 | + json = JSON.parse(last_response.body) | |
398 | + assert_match(/^https:\/\/www\.gravatar\.com.*size=64/, json['icon']) | |
399 | + end | |
400 | + | |
401 | + should 'return icon from gravatar with size if there is no profile image' do | |
402 | + profile = create_user('test-user').person | |
403 | + | |
404 | + get "/api/v1/people/#{profile.id}/icon?#{params.to_query}&size=big" | |
405 | + assert_equal 200, last_response.status | |
406 | + json = JSON.parse(last_response.body) | |
407 | + assert_match(/^https:\/\/www\.gravatar\.com.*size=150/, json['icon']) | |
408 | + end | |
409 | + | |
372 | 410 | PERSON_ATTRIBUTES = %w(vote_count comments_count articles_count following_articles_count) |
373 | 411 | |
374 | 412 | PERSON_ATTRIBUTES.map do |attribute| | ... | ... |
test/functional/comment_controller_test.rb
... | ... | @@ -487,7 +487,7 @@ class CommentControllerTest < ActionController::TestCase |
487 | 487 | should 'edit comment from a page' do |
488 | 488 | login_as profile.identifier |
489 | 489 | page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') |
490 | - comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article', :author_id => profile.id) | |
490 | + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article', :author_id => profile.id, :author_type => 'Person') | |
491 | 491 | |
492 | 492 | get :edit, :id => comment.id, :profile => profile.identifier, :comment => { :body => 'Comment edited' } |
493 | 493 | assert_tag :tag => 'textarea', :attributes => {:id => 'comment_body'}, :content => /Original comment/ |
... | ... | @@ -522,7 +522,7 @@ class CommentControllerTest < ActionController::TestCase |
522 | 522 | should 'be able to update a comment' do |
523 | 523 | login_as profile.identifier |
524 | 524 | page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text', :accept_comments => false) |
525 | - comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article', :author_id => profile) | |
525 | + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article', :author_id => profile, :author_type => 'Person') | |
526 | 526 | |
527 | 527 | xhr :post, :update, :id => comment.id, :profile => profile.identifier, :comment => { :body => 'Comment edited' } |
528 | 528 | assert ActiveSupport::JSON.decode(@response.body)["ok"], "attribute ok expected to be true" | ... | ... |
test/functional/profile_controller_test.rb
... | ... | @@ -1932,4 +1932,37 @@ class ProfileControllerTest < ActionController::TestCase |
1932 | 1932 | assert_redirected_to :controller => 'account', :action => 'login' |
1933 | 1933 | end |
1934 | 1934 | |
1935 | + should 'return portrait icon if size is not provided and there is a profile image' do | |
1936 | + img = Image.create!(uploaded_data: fixture_file_upload('/files/rails.png', 'image/png')) | |
1937 | + profile = fast_create(Person, image_id: img.id) | |
1938 | + | |
1939 | + get :icon, profile: profile.identifier, size: nil | |
1940 | + assert_response :success | |
1941 | + assert_equal 'image/png', @response.header['Content-Type'] | |
1942 | + assert File.exists?(assigns(:file)) | |
1943 | + end | |
1944 | + | |
1945 | + should 'return icon in provided size if there is a profile image' do | |
1946 | + img = Image.create!(uploaded_data: fixture_file_upload('/files/rails.png', 'image/png')) | |
1947 | + profile = fast_create(Person, image_id: img.id) | |
1948 | + | |
1949 | + get :icon, profile: profile.identifier, size: :big | |
1950 | + assert_response :success | |
1951 | + assert_equal 'image/png', @response.header['Content-Type'] | |
1952 | + assert File.exists?(assigns(:file)) | |
1953 | + end | |
1954 | + | |
1955 | + should 'return icon from gravatar without size if there is no profile image' do | |
1956 | + profile = fast_create(Person) | |
1957 | + | |
1958 | + get :icon, profile: profile.identifier | |
1959 | + assert_redirected_to /^https:\/\/www\.gravatar\.com\/.*/ | |
1960 | + end | |
1961 | + | |
1962 | + should 'return icon from gravatar with size if there is no profile image' do | |
1963 | + profile = fast_create(Person) | |
1964 | + | |
1965 | + get :icon, profile: profile.identifier, size: :thumb | |
1966 | + assert_redirected_to /^https:\/\/www\.gravatar\.com\/.*/ | |
1967 | + end | |
1935 | 1968 | end | ... | ... |
test/integration/routing_test.rb
... | ... | @@ -276,4 +276,11 @@ class RoutingTest < ActionDispatch::IntegrationTest |
276 | 276 | assert_routing('/profile/~', :controller => 'profile', :profile => '~', :action => 'index') |
277 | 277 | end |
278 | 278 | |
279 | + should 'have route to profile icon without size' do | |
280 | + assert_routing('/profile/ze/icon', controller: 'profile', profile: 'ze', action: 'icon') | |
281 | + end | |
282 | + | |
283 | + should 'have route to profile icon with supported size' do | |
284 | + assert_routing('/profile/ze/icon/big', controller: 'profile', profile: 'ze', action: 'icon', size: 'big') | |
285 | + end | |
279 | 286 | end | ... | ... |
test/unit/comment_test.rb
... | ... | @@ -23,17 +23,14 @@ class CommentTest < ActiveSupport::TestCase |
23 | 23 | end |
24 | 24 | end |
25 | 25 | |
26 | - should 'record authenticated author' do | |
26 | + should 'record authenticated author polymorphically' do | |
27 | 27 | c = Comment.new |
28 | - assert_raise ActiveRecord::AssociationTypeMismatch do | |
29 | - c.author = 1 | |
30 | - end | |
31 | - assert_raise ActiveRecord::AssociationTypeMismatch do | |
32 | - c.author = Profile | |
33 | - end | |
34 | 28 | assert_nothing_raised do |
35 | 29 | c.author = Person.new |
36 | 30 | end |
31 | + assert_nothing_raised do | |
32 | + c.author = ExternalPerson.new | |
33 | + end | |
37 | 34 | end |
38 | 35 | |
39 | 36 | should 'record unauthenticated author' do | ... | ... |
... | ... | @@ -0,0 +1,137 @@ |
1 | +# encoding: UTF-8 | |
2 | +require_relative "../test_helper" | |
3 | + | |
4 | +class ExternalPersonTest < ActiveSupport::TestCase | |
5 | + fixtures :environments | |
6 | + | |
7 | + def setup | |
8 | + @external_person = ExternalPerson.create!(identifier: 'johnlock', | |
9 | + name: 'John Lock', | |
10 | + source: 'anerenvironment.org', | |
11 | + email: 'john@lock.org', | |
12 | + created_at: Date.yesterday | |
13 | + ) | |
14 | + end | |
15 | + | |
16 | + should 'have no permissions' do | |
17 | + assert_equivalent [], @external_person.role_assignments | |
18 | + refute @external_person.has_permission?(:manage_friends) | |
19 | + end | |
20 | + | |
21 | + should 'have no suggested profiles' do | |
22 | + assert_equivalent [], @external_person.suggested_communities | |
23 | + assert_equivalent [], @external_person.suggested_people | |
24 | + assert_equivalent [], @external_person.suggested_profiles | |
25 | + end | |
26 | + | |
27 | + should 'have no friendships' do | |
28 | + refute @external_person.add_friend(fast_create(Person)) | |
29 | + assert_equivalent [], @external_person.friendships | |
30 | + end | |
31 | + | |
32 | + should 'not be a member of any communities' do | |
33 | + community = fast_create(Community) | |
34 | + refute community.add_member(@external_person) | |
35 | + assert_equivalent [], @external_person.memberships | |
36 | + end | |
37 | + | |
38 | + should 'not have any favorite enterprises' do | |
39 | + assert_equivalent [], @external_person.favorite_enterprises | |
40 | + end | |
41 | + | |
42 | + should 'be a person' do | |
43 | + assert @external_person.person? | |
44 | + end | |
45 | + | |
46 | + should 'not be a community, organization or enterprise' do | |
47 | + refute @external_person.community? | |
48 | + refute @external_person.enterprise? | |
49 | + refute @external_person.organization? | |
50 | + end | |
51 | + | |
52 | + should 'never be an admin for environments' do | |
53 | + refute @external_person.is_admin? | |
54 | + env = Environment.default | |
55 | + env.add_admin @external_person | |
56 | + refute @external_person.is_admin?(env) | |
57 | + assert_equivalent [], env.admins | |
58 | + end | |
59 | + | |
60 | + should 'redirect after login based on environment settings' do | |
61 | + assert_respond_to ExternalPerson.new, :preferred_login_redirection | |
62 | + environment = fast_create(Environment, :redirection_after_login => 'site_homepage') | |
63 | + profile = fast_create(ExternalPerson, :environment_id => environment.id) | |
64 | + assert_equal 'site_homepage', profile.preferred_login_redirection | |
65 | + end | |
66 | + | |
67 | + should 'have an avatar from its original environment' do | |
68 | + assert_match(/http:\/\/#{@external_person.source}\/.*/, @external_person.avatar) | |
69 | + end | |
70 | + | |
71 | + should 'generate a custom profile icon based on its avatar' do | |
72 | + assert_match(/http:\/\/#{@external_person.source}\/.*/, @external_person.profile_custom_icon) | |
73 | + end | |
74 | + | |
75 | + should 'have an url to its profile on its original environment' do | |
76 | + assert_match(/http:\/\/#{@external_person.source}\/profile\/.*/, @external_person.url) | |
77 | + end | |
78 | + | |
79 | + should 'have a public profile url' do | |
80 | + assert_match(/http:\/\/#{@external_person.source}\/profile\/.*/, @external_person.public_profile_url) | |
81 | + end | |
82 | + | |
83 | + should 'have an admin url to its profile on its original environment' do | |
84 | + assert_match(/http:\/\/#{@external_person.source}\/myprofile\/.*/, @external_person.admin_url) | |
85 | + end | |
86 | + | |
87 | + should 'never be a friend of another person' do | |
88 | + friend = fast_create(Person) | |
89 | + friend.add_friend @external_person | |
90 | + refute @external_person.is_a_friend?(friend) | |
91 | + refute friend.is_a_friend?(@external_person) | |
92 | + end | |
93 | + | |
94 | + should 'never send a friend request to another person' do | |
95 | + friend = fast_create(Person) | |
96 | + friend.add_friend @external_person | |
97 | + refute friend.already_request_friendship?(@external_person) | |
98 | + @external_person.add_friend(friend) | |
99 | + refute @external_person.already_request_friendship?(friend) | |
100 | + end | |
101 | + | |
102 | + should 'not follow another profile' do | |
103 | + friend = fast_create(Person) | |
104 | + friend.add_friend @external_person | |
105 | + refute @external_person.follows?(friend) | |
106 | + refute friend.follows?(@external_person) | |
107 | + end | |
108 | + | |
109 | + should 'have an image' do | |
110 | + assert_not_nil @external_person.image | |
111 | + end | |
112 | + | |
113 | + should 'profile image has public filename and mimetype' do | |
114 | + assert_not_nil @external_person.image.public_filename | |
115 | + assert_not_nil @external_person.image.content_type | |
116 | + end | |
117 | + | |
118 | + should 'respond to all instance methods in Profile' do | |
119 | + methods = Profile.public_instance_methods(false) | |
120 | + methods.each do |method| | |
121 | + # We test if ExternalPerson responds to same methods as Profile, but we | |
122 | + # skip methods generated by plugins, libs and validations, which are | |
123 | + # usually only used internally | |
124 | + assert_respond_to ExternalPerson.new, method.to_sym unless method =~ /type_name|^autosave_.*|^after_.*|^before_.*|validate_.*|^attribute_.*|.*_?tags?_?.*|^custom_value.*|^custom_context.*|^xss.*|bar/ | |
125 | + end | |
126 | + end | |
127 | + | |
128 | + should 'respond to all instance methods in Person' do | |
129 | + methods = Person.public_instance_methods(false) | |
130 | + methods.each do |method| | |
131 | + # We test if ExternalPerson responds to same methods as Person, but we | |
132 | + # skip methods generated by plugins, libs and validations, which are | |
133 | + # usually only used internally | |
134 | + assert_respond_to ExternalPerson.new, method.to_sym unless method =~ /^autosave_.*|validate_.*|^before_.*|^after_.*|^assignment_.*|^(city|state)_.*/ | |
135 | + end | |
136 | + end | |
137 | +end | ... | ... |
test/unit/person_test.rb
... | ... | @@ -1831,9 +1831,9 @@ class PersonTest < ActiveSupport::TestCase |
1831 | 1831 | p1 = fast_create(Person) |
1832 | 1832 | p2 = fast_create(Person) |
1833 | 1833 | article = fast_create(Article) |
1834 | - c1 = fast_create(Comment, :source_id => article.id, :author_id => p1.id) | |
1835 | - c2 = fast_create(Comment, :source_id => article.id, :author_id => p2.id) | |
1836 | - c3 = fast_create(Comment, :source_id => article.id, :author_id => p1.id) | |
1834 | + c1 = fast_create(Comment, :source_id => article.id, :author_id => p1.id, :author_type => 'Profile') | |
1835 | + c2 = fast_create(Comment, :source_id => article.id, :author_id => p2.id, :author_type => 'Profile') | |
1836 | + c3 = fast_create(Comment, :source_id => article.id, :author_id => p1.id, :author_type => 'Profile') | |
1837 | 1837 | |
1838 | 1838 | assert_equivalent [c1,c3], p1.comments |
1839 | 1839 | end | ... | ... |
test/unit/user_test.rb
... | ... | @@ -759,6 +759,14 @@ class UserTest < ActiveSupport::TestCase |
759 | 759 | end |
760 | 760 | end |
761 | 761 | |
762 | + should 'get person or external person' do | |
763 | + user = create_user('new_user') | |
764 | + assert_kind_of Person, user.person | |
765 | + user.external_person_id = ExternalPerson.create!(identifier: 'new_user', name: 'New User', email: 'newuser@usermail.com', source: 'federated.noosfero.com', created_at: Date.today).id | |
766 | + assert_kind_of ExternalPerson, user.person | |
767 | + assert_kind_of Person, user.person_without_external | |
768 | + end | |
769 | + | |
762 | 770 | protected |
763 | 771 | def new_user(options = {}) |
764 | 772 | user = User.new({ :login => 'quire', :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options)) | ... | ... |
vendor/plugins/noosfero_caching/init.rb
... | ... | @@ -27,7 +27,7 @@ module NoosferoHttpCaching |
27 | 27 | end |
28 | 28 | |
29 | 29 | def noosfero_session_check |
30 | - headers["X-Noosfero-Auth"] = (session[:user] != nil).to_s | |
30 | + headers["X-Noosfero-Auth"] = (session[:user] != nil || session[:external] != nil).to_s | |
31 | 31 | end |
32 | 32 | |
33 | 33 | class Middleware | ... | ... |