Commit 11dfb86bf56dd6ce8784ab13682b46a96f9efc2f

Authored by Rodrigo Souto
2 parents d442dac2 ec0f8b0e

Merge branch 'master' of gitlab.com:noosfero/noosfero

Showing 174 changed files with 2162 additions and 2196 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 174 files displayed.

Gemfile
... ... @@ -11,7 +11,6 @@ gem 'will_paginate', '~> 3.0.3'
11 11 gem 'ruby-feedparser', '~> 0.7'
12 12 gem 'daemons', '~> 1.1.5'
13 13 gem 'thin', '~> 1.3.1'
14   -gem 'hpricot', '~> 0.8.6'
15 14 gem 'nokogiri', '~> 1.5.5'
16 15 gem 'rake', :require => false
17 16 gem 'rest-client', '~> 1.6.7'
... ... @@ -41,9 +40,12 @@ group :cucumber do
41 40 gem 'selenium-webdriver', '~> 2.39.0'
42 41 end
43 42  
  43 +# Requires custom dependencies
  44 +eval(File.read('config/Gemfile'), binding) rescue nil
  45 +
44 46 # include gemfiles from enabled plugins
45 47 # plugins in baseplugins/ are not included on purpose. They should not have any
46 48 # dependencies.
47 49 Dir.glob('config/plugins/*/Gemfile').each do |gemfile|
48 50 eval File.read(gemfile)
49 51 -end
  52 +end
50 53 \ No newline at end of file
... ...
INSTALL.md
... ... @@ -21,7 +21,7 @@ Noosfero is written in Ruby with the "[Rails framework](http://www.rubyonrails.o
21 21 You need to install some packages Noosfero depends on. On Debian GNU/Linux or Debian-based systems, all of these packages are available through the Debian archive. You can install them with the following command:
22 22  
23 23 # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby1.8 \
24   - libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libhpricot-ruby \
  24 + libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby \
25 25 libwill-paginate-ruby iso-codes libfeedparser-ruby libdaemons-ruby thin \
26 26 tango-icon-theme
27 27  
... ... @@ -40,7 +40,6 @@ On other systems, they may or may not be available through your regular package
40 40 * Daemons - http://daemons.rubyforge.org
41 41 * Thin: http://code.macournoyer.com/thin
42 42 * tango-icon-theme: http://tango.freedesktop.org/Tango_Icon_Library
43   -* Hpricot: http://hpricot.com
44 43  
45 44 If you manage to install Noosfero successfully on other systems than Debian,
46 45 please feel free to contact the Noosfero development mailing with the
... ...
INSTALL.multitenancy.md
... ... @@ -26,7 +26,7 @@ The file config/database.yml must follow a structure in order to achieve multite
26 26  
27 27 Each "hosted" environment must have an entry like this:
28 28  
29   - env1_production:
  29 + env1_production: &DEFAULT
30 30 adapter: postgresql
31 31 encoding: unicode
32 32 database: noosfero
... ... @@ -61,7 +61,7 @@ The "hosted" environments define, besides the `schema_search_path`, a list of do
61 61 You must also tell the application which is the default environment.
62 62  
63 63 production:
64   - env1_production
  64 + <<: *DEFAULT
65 65  
66 66 On the example above there are only three hosted environments, but it can be more than three. The schemas `env2` and `env3` must already exist in the same database of the hosting environment. As postgres user, you can create them typing:
67 67  
... ...
app/controllers/application_controller.rb
... ... @@ -28,6 +28,7 @@ class ApplicationController &lt; ActionController::Base
28 28 unless environment.access_control_allow_methods.blank?
29 29 response.headers["Access-Control-Allow-Methods"] = environment.access_control_allow_methods
30 30 end
  31 + response.headers["Access-Control-Allow-Credentials"] = 'true'
31 32 elsif environment.restrict_to_access_control_origins
32 33 render_access_denied _('Origin not in allowed.')
33 34 end
... ...
app/helpers/application_helper.rb
... ... @@ -8,11 +8,7 @@ module ApplicationHelper
8 8  
9 9 include PermissionNameHelper
10 10  
11   - include LightboxHelper
12   -
13   - include ThickboxHelper
14   -
15   - include ColorboxHelper
  11 + include ModalHelper
16 12  
17 13 include BoxesHelper
18 14  
... ... @@ -651,8 +647,8 @@ module ApplicationHelper
651 647 ' onfocus="if(this.value==\''+s+'\'){this.value=\'\'} this.form.className=\'focus-in\'"'+
652 648 ' onblur="if(/^\s*$/.test(this.value)){this.value=\''+s+'\'} this.form.className=\'focus-out\'">'+
653 649 '</form>'
654   - else #opt == 'lightbox_link' is default
655   - lightbox_link_to '<span class="icon-menu-search"></span>'+ _('Search'), {
  650 + else
  651 + modal_link_to '<span class="icon-menu-search"></span>'+ _('Search'), {
656 652 :controller => 'search',
657 653 :action => 'popup',
658 654 :category_path => (@category ? @category.explode_path : nil)},
... ... @@ -1050,7 +1046,7 @@ module ApplicationHelper
1050 1046 {s_('contents|Most commented') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_comments'})}}
1051 1047 ]
1052 1048 if logged_in?
1053   - links.push(_('New content') => colorbox_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})}))
  1049 + links.push(_('New content') => modal_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})}))
1054 1050 end
1055 1051  
1056 1052 link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => nil}, :id => 'submenu-contents') +
... ... @@ -1398,16 +1394,16 @@ module ApplicationHelper
1398 1394 end
1399 1395  
1400 1396 def convert_macro(html, source)
1401   - doc = Hpricot(html)
  1397 + doc = Nokogiri::HTML.fragment html
1402 1398 #TODO This way is more efficient but do not support macro inside of
1403 1399 # macro. You must parse them from the inside-out in order to enable
1404 1400 # that.
1405   - doc.search('.macro').each do |macro|
  1401 + doc.css('.macro').each do |macro|
1406 1402 macro_name = macro['data-macro']
1407 1403 result = @plugins.parse_macro(macro_name, macro, source)
1408 1404 macro.inner_html = result.kind_of?(Proc) ? self.instance_exec(&result) : result
1409 1405 end
1410   - doc.html
  1406 + doc.to_html
1411 1407 end
1412 1408  
1413 1409 def default_folder_for_image_upload(profile)
... ...
app/helpers/boxes_helper.rb
... ... @@ -231,7 +231,7 @@ module BoxesHelper
231 231 end
232 232  
233 233 if block.editable?
234   - buttons << colorbox_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
  234 + buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
235 235 end
236 236  
237 237 if !block.main?
... ... @@ -241,7 +241,7 @@ module BoxesHelper
241 241 end
242 242  
243 243 if block.respond_to?(:help)
244   - buttons << thickbox_inline_popup_icon(:help, _('Help on this block'), {}, "help-on-box-#{block.id}") << content_tag('div', content_tag('h2', _('Help')) + content_tag('div', block.help, :style => 'margin-bottom: 1em;') + thickbox_close_button(_('Close')), :style => 'display: none;', :id => "help-on-box-#{block.id}")
  244 + buttons << modal_inline_icon(:help, _('Help on this block'), {}, "#help-on-box-#{block.id}") << content_tag('div', content_tag('h2', _('Help')) + content_tag('div', block.help, :style => 'margin-bottom: 1em;') + modal_close_button(_('Close')), :style => 'display: none;', :id => "help-on-box-#{block.id}")
245 245 end
246 246  
247 247 if block.embedable?
... ...
app/helpers/colorbox_helper.rb
... ... @@ -1,25 +0,0 @@
1   -module ColorboxHelper
2   -
3   - def colorbox_close_button(text, options = {})
4   - button(:close, text, '#', colorbox_options(options, :close))
5   - end
6   -
7   - def colorbox_button(type, label, url, options = {})
8   - button(type, label, url, colorbox_options(options))
9   - end
10   -
11   - def colorbox_icon_button(type, label, url, options = {})
12   - icon_button(type, label, url, colorbox_options(options))
13   - end
14   -
15   - # options must be an HTML options hash as passed to link_to etc.
16   - #
17   - # returns a new hash with colorbox class added. Keeps existing classes.
18   - def colorbox_options(options, type=nil)
19   - the_class = 'colorbox'
20   - the_class += "-#{type.to_s}" unless type.nil?
21   - the_class << " #{options[:class]}" if options.has_key?(:class)
22   - options.merge(:class => the_class)
23   - end
24   -
25   -end
app/helpers/comment_helper.rb
... ... @@ -65,7 +65,7 @@ module CommentHelper
65 65  
66 66 def link_for_edit(comment)
67 67 if comment.can_be_updated_by?(user)
68   - {:link => expirable_comment_link(comment, :edit, _('Edit'), url_for(:profile => profile.identifier, :controller => :comment, :action => :edit, :id => comment.id),:class => 'colorbox')}
  68 + {:link => expirable_comment_link(comment, :edit, _('Edit'), url_for(:profile => profile.identifier, :controller => :comment, :action => :edit, :id => comment.id),:class => 'modal')}
69 69 end
70 70 end
71 71  
... ...
app/helpers/layout_helper.rb
... ... @@ -45,8 +45,6 @@ module LayoutHelper
45 45 standard_stylesheets = [
46 46 'application',
47 47 'search',
48   - 'thickbox',
49   - 'lightbox',
50 48 'colorbox',
51 49 'selectordie',
52 50 'inputosaurus',
... ...
app/helpers/lightbox_helper.rb
... ... @@ -1,36 +0,0 @@
1   -module LightboxHelper
2   -
3   - def lightbox_link_to(text, url, options = {})
4   - link_to(text, url, lightbox_options(options))
5   - end
6   -
7   - def lightbox_close_button(text, options = {})
8   - button(:close, text, '#', lightbox_options(options, 'lbAction').merge(:rel => 'deactivate'))
9   - end
10   -
11   - def lightbox_button(type, label, url, options = {})
12   - button(type, label, url, lightbox_options(options))
13   - end
14   -
15   - def lightbox_icon_button(type, label, url, options = {})
16   - icon_button(type, label, url, lightbox_options(options))
17   - end
18   -
19   - # options must be an HTML options hash as passed to link_to etc.
20   - #
21   - # returns a new hash with lightbox class added. Keeps existing classes.
22   - def lightbox_options(options, lightbox_type = 'lbOn')
23   - the_class = lightbox_type
24   - the_class << " #{options[:class]}" if options.has_key?(:class)
25   - options.merge(:class => the_class)
26   - end
27   -
28   - def lightbox?
29   - request.xhr?
30   - end
31   -
32   - def lightbox_remote_button(type, label, url, options = {})
33   - button(type, label, url, lightbox_options(options, 'remote-lbOn'))
34   - end
35   -
36   -end
app/helpers/modal_helper.rb 0 → 100644
... ... @@ -0,0 +1,46 @@
  1 +module ModalHelper
  2 +
  3 + def modal_inline_link_to title, url, selector, options = {}
  4 + link_to title, url, modal_options(options.merge(:inline => selector))
  5 + end
  6 +
  7 + def modal_inline_icon type, title, url, selector, options = {}
  8 + icon_button type, title, url, modal_options(options.merge(:inline => selector))
  9 + end
  10 +
  11 + def modal_link_to title, url, options = {}
  12 + link_to title, url, modal_options(options)
  13 + end
  14 +
  15 + def modal_close_link text, options = {}
  16 + link_to text, '#', modal_options(options, :close)
  17 + end
  18 +
  19 + def modal_close_button(text, options = {})
  20 + button :close, text, '#', modal_options(options, :close).merge(:rel => 'deactivate')
  21 + end
  22 +
  23 + def modal_button(type, label, url, options = {})
  24 + button type, label, url, modal_options(options)
  25 + end
  26 +
  27 + def modal_icon_button(type, label, url, options = {})
  28 + icon_button type, label, url, modal_options(options)
  29 + end
  30 +
  31 + # options must be an HTML options hash as passed to link_to etc.
  32 + #
  33 + # returns a new hash with modal class added. Keeps existing classes.
  34 + def modal_options(options, type=nil)
  35 + inline_selector = options.delete :inline
  36 + options[:onclick] = "return noosfero.modal.inline('#{inline_selector}')" if inline_selector
  37 +
  38 + classes = if inline_selector then '' else 'modal-toggle' end
  39 + classes += " modal-#{type.to_s}" if type.present?
  40 + classes << " #{options[:class]}" if options.has_key? :class
  41 + options.merge!(:class => classes)
  42 +
  43 + options
  44 + end
  45 +
  46 +end
... ...
app/helpers/thickbox_helper.rb
... ... @@ -1,11 +0,0 @@
1   -module ThickboxHelper
2   - def thickbox_inline_popup_link(title, url, id, options = {})
3   - link_to(title, url_for(url) + "#TB_inline?height=300&width=500&inlineId=#{id}&modal=true", {:class => 'thickbox'}.merge(options))
4   - end
5   - def thickbox_inline_popup_icon(type, title, url, id, options = {})
6   - icon_button(type, title, url_for(url) + "#TB_inline?height=300&width=500&inlineId=#{id}&modal=true", {:class => "thickbox"}.merge(options))
7   - end
8   - def thickbox_close_button(title)
9   - button_to_function(:close, title, 'tb_remove();')
10   - end
11   -end
app/models/article.rb
1   -require 'hpricot'
2 1  
3 2 class Article < ActiveRecord::Base
4 3  
... ... @@ -707,7 +706,7 @@ class Article &lt; ActiveRecord::Base
707 706 end
708 707  
709 708 def first_paragraph
710   - paragraphs = Hpricot(to_html).search('p')
  709 + paragraphs = Nokogiri::HTML.fragment(to_html).css('p')
711 710 paragraphs.empty? ? '' : paragraphs.first.to_html
712 711 end
713 712  
... ... @@ -729,8 +728,8 @@ class Article &lt; ActiveRecord::Base
729 728  
730 729 def body_images_paths
731 730 require 'uri'
732   - Hpricot(self.body.to_s).search('img[@src]').collect do |i|
733   - (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, URI.escape(i.attributes['src'])).to_s : i.attributes['src']
  731 + Nokogiri::HTML.fragment(self.body.to_s).css('img[src]').collect do |i|
  732 + (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, URI.escape(i['src'])).to_s : i['src']
734 733 end
735 734 end
736 735  
... ... @@ -767,8 +766,8 @@ class Article &lt; ActiveRecord::Base
767 766 end
768 767  
769 768 def first_image
770   - img = Hpricot(self.lead.to_s).search('img[@src]').first || Hpricot(self.body.to_s).search('img').first
771   - img.nil? ? '' : img.attributes['src']
  769 + img = Nokogiri::HTML.fragment(self.lead.to_s).css('img[src]').first || Nokogiri::HTML.fragment(self.body.to_s).search('img').first
  770 + img.nil? ? '' : img['src']
772 771 end
773 772  
774 773 delegate :lat, :lng, :region, :region_id, :environment, :environment_id, :to => :profile, :allow_nil => true
... ...
app/models/enterprise.rb
... ... @@ -19,7 +19,8 @@ class Enterprise &lt; Organization
19 19 has_many :inputs, :through => :products
20 20 has_many :production_costs, :as => :owner
21 21  
22   - has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people'
  22 + has_many :favorite_enterprise_people
  23 + has_many :fans, through: :favorite_enterprise_people, source: :person
23 24  
24 25 def product_categories
25 26 ProductCategory.by_enterprise(self)
... ...
app/models/environment.rb
... ... @@ -273,6 +273,7 @@ class Environment &lt; ActiveRecord::Base
273 273 settings_items :help_message_to_add_enterprise, :type => String, :default => ''
274 274 settings_items :tip_message_enterprise_activation_question, :type => String, :default => ''
275 275  
  276 + settings_items :currency_iso_unit, :type => String, :default => 'USD'
276 277 settings_items :currency_unit, :type => String, :default => '$'
277 278 settings_items :currency_separator, :type => String, :default => '.'
278 279 settings_items :currency_delimiter, :type => String, :default => ','
... ...
app/models/external_feed.rb
... ... @@ -14,9 +14,9 @@ class ExternalFeed &lt; ActiveRecord::Base
14 14  
15 15 def add_item(title, link, date, content)
16 16 return if content.blank?
17   - doc = Hpricot(content)
18   - doc.search('*').each do |p|
19   - if p.instance_of? Hpricot::Elem
  17 + doc = Nokogiri::HTML.fragment content
  18 + doc.css('*').each do |p|
  19 + if p.instance_of? Nokogiri::XML::Element
20 20 p.remove_attribute 'style'
21 21 p.remove_attribute 'class'
22 22 end
... ... @@ -26,10 +26,10 @@ class ExternalFeed &lt; ActiveRecord::Base
26 26 article = TinyMceArticle.new
27 27 article.name = title
28 28 article.profile = blog.profile
29   - article.body = content
30   - article.published_at = date
31   - article.source = link
32   - article.profile = blog.profile
  29 + article.body = content
  30 + article.published_at = date
  31 + article.source = link
  32 + article.profile = blog.profile
33 33 article.parent = blog
34 34 article.author_name = self.feed_title
35 35 unless blog.children.exists?(:slug => article.slug)
... ...
app/models/favorite_enterprise_person.rb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +class FavoriteEnterprisePerson < ActiveRecord::Base
  2 +
  3 + self.table_name = :favorite_enteprises_people
  4 +
  5 + belongs_to :enterprise
  6 + belongs_to :person
  7 +
  8 +end
... ...
app/models/forum.rb
... ... @@ -54,7 +54,7 @@ class Forum &lt; Folder
54 54  
55 55 def first_paragraph
56 56 return '' if body.blank?
57   - paragraphs = Hpricot(body).search('p')
  57 + paragraphs = Nokogiri::HTML.fragment(body).css('p')
58 58 paragraphs.empty? ? '' : paragraphs.first.to_html
59 59 end
60 60  
... ...
app/models/input.rb
1 1 class Input < ActiveRecord::Base
2 2  
3   - attr_accessible :product, :product_category, :product_category_id, :amount_used, :unit_id, :price_per_unit, :relevant_to_price
  3 + attr_accessible :product, :product_id, :product_category, :product_category_id,
  4 + :amount_used, :unit_id, :price_per_unit, :relevant_to_price, :is_from_solidarity_economy
4 5  
5 6 belongs_to :product
6 7 belongs_to :product_category
... ...
app/models/person_notifier.rb
... ... @@ -22,12 +22,17 @@ class PersonNotifier
22 22 schedule_next_notification_mail
23 23 end
24 24  
  25 + def notify_from
  26 + @person.last_notification || DateTime.now - @person.notification_time.hours
  27 + end
  28 +
25 29 def notify
26 30 if @person.notification_time && @person.notification_time > 0
27   - from = @person.last_notification || DateTime.now - @person.notification_time.hours
28   - notifications = @person.tracked_notifications.find(:all, :conditions => ["created_at > ?", from])
  31 + notifications = @person.tracked_notifications.find(:all, :conditions => ["created_at > ?", notify_from])
  32 + tasks = Task.to(@person).without_spam.pending.where("created_at > ?", notify_from).order_by('created_at', 'asc')
  33 +
29 34 Noosfero.with_locale @person.environment.default_language do
30   - Mailer::content_summary(@person, notifications).deliver unless notifications.empty?
  35 + Mailer::content_summary(@person, notifications, tasks).deliver unless notifications.empty? && tasks.empty?
31 36 end
32 37 @person.settings[:last_notification] = DateTime.now
33 38 @person.save!
... ... @@ -59,8 +64,12 @@ class PersonNotifier
59 64 end
60 65  
61 66 def failure(job)
62   - person = Person.find(person_id)
63   - person.notifier.dispatch_notification_mail
  67 + begin
  68 + person = Person.find(person_id)
  69 + person.notifier.dispatch_notification_mail
  70 + rescue
  71 + Rails.logger.error "PersonNotifier::NotifyJob: Cannot recover from failure"
  72 + end
64 73 end
65 74  
66 75 end
... ... @@ -73,18 +82,24 @@ class PersonNotifier
73 82 {:theme => nil}
74 83 end
75 84  
76   - def content_summary(person, notifications)
  85 + def content_summary(person, notifications, tasks)
  86 + if person.environment
  87 + ActionMailer::Base.asset_host = person.environment.top_url
  88 + ActionMailer::Base.default_url_options[:host] = person.environment.default_hostname
  89 + end
  90 +
77 91 @current_theme = 'default'
78 92 @profile = person
79 93 @recipient = @profile.nickname || @profile.name
80 94 @notifications = notifications
  95 + @tasks = tasks
81 96 @environment = @profile.environment.name
82 97 @url = @profile.environment.top_url
83 98 mail(
84 99 content_type: "text/html",
85 100 from: "#{@profile.environment.name} <#{@profile.environment.noreply_email}>",
86 101 to: @profile.email,
87   - subject: _("[%s] Network Activity") % [@profile.environment.name]
  102 + subject: _("[%s] Notifications") % [@profile.environment.name]
88 103 )
89 104 end
90 105 end
... ...
app/models/product.rb
... ... @@ -10,7 +10,8 @@ class Product &lt; ActiveRecord::Base
10 10 :display => %w[full map]
11 11 }
12 12  
13   - attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs, :qualifiers_list
  13 + attr_accessible :name, :product_category, :profile, :profile_id, :enterprise,
  14 + :highlighted, :price, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs, :qualifiers_list
14 15  
15 16 def self.default_search_display
16 17 'full'
... ...
app/models/text_article.rb
1 1 require 'noosfero/translatable_content'
2 2  
3   -# a base class for all text article types.
  3 +# a base class for all text article types.
4 4 class TextArticle < Article
5 5  
6 6 xss_terminate :only => [ :name ], :on => 'validation'
... ... @@ -26,10 +26,10 @@ class TextArticle &lt; Article
26 26 before_save :set_relative_path
27 27  
28 28 def set_relative_path
29   - parsed = Hpricot(self.body.to_s)
30   - parsed.search('img[@src]').map { |i| change_element_path(i, 'src') }
31   - parsed.search('a[@href]').map { |i| change_element_path(i, 'href') }
32   - self.body = parsed.to_s
  29 + parsed = Nokogiri::HTML.fragment(self.body.to_s)
  30 + parsed.css('img[src]').each { |i| change_element_path(i, 'src') }
  31 + parsed.css('a[href]').each { |i| change_element_path(i, 'href') }
  32 + self.body = parsed.to_html
33 33 end
34 34  
35 35 def change_element_path(el, attribute)
... ...
app/models/user.rb
... ... @@ -54,7 +54,7 @@ class User &lt; ActiveRecord::Base
54 54  
55 55 user.person = p
56 56 end
57   - if user.environment.enabled?('skip_new_user_email_confirmation')
  57 + if user.environment.enabled?('skip_new_user_email_confirmation')
58 58 if user.environment.enabled?('admin_must_approve_new_users')
59 59 create_moderate_task
60 60 else
... ... @@ -102,6 +102,7 @@ class User &lt; ActiveRecord::Base
102 102 validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?})
103 103 validates_uniqueness_of :login, :email, :case_sensitive => false, :scope => :environment_id
104 104 before_save :encrypt_password
  105 + before_save :normalize_email, if: proc{ |u| u.email.present? }
105 106 validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?})
106 107  
107 108 validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('{fn} must be checked in order to signup.').fix_i18n
... ... @@ -114,6 +115,10 @@ class User &lt; ActiveRecord::Base
114 115 u && u.authenticated?(password) ? u : nil
115 116 end
116 117  
  118 + def register_login
  119 + self.update_attribute :last_login_at, Time.now
  120 + end
  121 +
117 122 # Activates the user in the database.
118 123 def activate
119 124 return false unless self.person
... ... @@ -332,6 +337,11 @@ class User &lt; ActiveRecord::Base
332 337 end
333 338  
334 339 protected
  340 +
  341 + def normalize_email
  342 + self.email = self.email.squish.downcase
  343 + end
  344 +
335 345 # before filter
336 346 def encrypt_password
337 347 return if password.blank?
... ... @@ -359,6 +369,6 @@ class User &lt; ActiveRecord::Base
359 369  
360 370 def delay_activation_check
361 371 return if person.is_template?
362   - Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => 72.hours.from_now})
  372 + Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => (NOOSFERO_CONF['hours_until_user_activation_check'] || 72).hours.from_now})
363 373 end
364 374 end
... ...
app/views/account/_login_form.html.erb
1 1 <%= labelled_form_for :user,
2 2 :url => { :controller => 'account', :action => (params[:enterprise_code] ? 'activate_enterprise' : 'login') } do |f| %>
3 3  
4   -<%= f.text_field :login,
5   - :id => ( lightbox? ? 'lightbox_' : '' ) + 'user_login',
6   - :onchange => 'this.value = convToValidLogin( this.value )' %>
  4 +<%= f.text_field :login, :id => 'user_login', :onchange => 'this.value = convToValidLogin( this.value )' %>
7 5  
8   -<%= f.password_field :password,
9   - :id => ( lightbox? ? 'lightbox_' : '' ) + 'user_password' %>
  6 +<%= f.password_field :password, :id => 'user_password' %>
10 7  
11 8 <% if params[:enterprise_code] %>
12 9 <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %>
... ... @@ -16,7 +13,7 @@
16 13  
17 14 <% button_bar do %>
18 15 <%= submit_button( 'login', _('Log in') )%>
19   - <%= lightbox_close_button(_('Cancel')) if lightbox? %>
  16 + <%= modal_close_button _('Cancel') if request.xhr? %>
20 17 <% end %>
21 18  
22 19 <% end %>
... ...
app/views/account/_signup_form.html.erb
... ... @@ -16,7 +16,7 @@
16 16 <input type="hidden" id="signup_time_key" name="signup_time_key" />
17 17 <script type="text/javascript">
18 18 jQuery.ajax({
19   - type: "POST",
  19 + type: "GET",
20 20 url: "<%= url_for :controller=>'account', :action=>'signup_time' %>",
21 21 dataType: 'json',
22 22 success: function(data) {
... ...
app/views/account/index_anonymous.html.erb
1 1 <h1><%= _('Identify yourself') %></h1>
2 2  
3 3 <p>
4   -<%= lightbox_link_to _('Login.'), { :controller => 'account', :action => 'login_popup' } %>
  4 +<%= modal_link_to _('Login.'), { :controller => 'account', :action => 'login_popup' } %>
5 5  
6 6 <%= _('You need to login to be able to use all the features in this environment.') %>
7 7 </p>
... ...
app/views/account/login.html.erb
... ... @@ -3,7 +3,7 @@
3 3 <h2><%= _('Login') %></h2>
4 4  
5 5 <% @user ||= User.new %>
6   -<% is_thickbox ||= false %>
  6 +<% is_popin ||= false %>
7 7  
8 8 <%= @message %>
9 9  
... ... @@ -17,8 +17,8 @@
17 17  
18 18 <% button_bar do %>
19 19 <%= submit_button( 'login', _('Log in') )%>
20   - <% if is_thickbox %>
21   - <%= thickbox_close_button(_('Cancel')) %>
  20 + <% if is_popin %>
  21 + <%= modal_close_button(_('Cancel')) %>
22 22 <% end %>
23 23 <% end %>
24 24  
... ...
app/views/account/logout_popup.html.erb
... ... @@ -2,6 +2,6 @@
2 2 <p>
3 3 <% button_bar do %>
4 4 <%= button :ok, _('Yes'), { :controller => 'account', :action => 'logout' } %>
5   - <%= lightbox_close_button _('No, I want to stay.') %>
  5 + <%= modal_close_button _('No, I want to stay.') %>
6 6 <% end %>
7 7 </p>
... ...
app/views/box_organizer/add_block.html.erb
... ... @@ -42,7 +42,7 @@
42 42  
43 43 <% button_bar do %>
44 44 <%= submit_button(:add, _("Add")) %>
45   - <%= colorbox_close_button(_('Close')) %>
  45 + <%= modal_close_button(_('Close')) %>
46 46 <% end %>
47 47  
48 48 <% end %>
... ...
app/views/box_organizer/edit.html.erb
... ... @@ -27,7 +27,7 @@
27 27  
28 28 <% button_bar do %>
29 29 <%= submit_button(:save, _('Save')) %>
30   - <%= colorbox_close_button(_('Cancel')) %>
  30 + <%= modal_close_button(_('Cancel')) %>
31 31 <% end %>
32 32  
33 33 <% end %>
... ...
app/views/box_organizer/index.html.erb
1 1 <h1><%= _('Editing sideboxes')%></h1>
2 2  
3 3 <% button_bar :class=>'design-menu' do %>
4   - <%= colorbox_button('add', _('Add a block'), { :action => 'add_block' }) %>
  4 + <%= modal_button('add', _('Add a block'), { :action => 'add_block' }) %>
5 5 <%= button(:back, _('Back to control panel'), :controller => (profile.nil? ? 'admin_panel': 'profile_editor')) %>
6 6 <% end %>
... ...
app/views/cms/edit.html.erb
... ... @@ -28,7 +28,7 @@
28 28 <% end %>
29 29  
30 30 <div style='float: right'>
31   - <%= lightbox_button :help, _('Why categorize?'), :action => 'why_categorize' %>
  31 + <%= modal_button :help, _('Why categorize?'), :action => 'why_categorize' %>
32 32 </div>
33 33  
34 34 <%= select_categories(:article, _('Categorize your article')) %>
... ...
app/views/cms/select_article_type.html.erb
... ... @@ -15,6 +15,6 @@
15 15 </ul>
16 16 <br style="clear:both" />
17 17  
18   -<%= colorbox_close_button(_('Cancel')) %>
  18 +<%= modal_close_button(_('Cancel')) %>
19 19  
20 20 </div>
... ...
app/views/cms/view.html.erb
... ... @@ -17,7 +17,7 @@
17 17 <% button_bar(:style => 'margin-bottom: 1em;') do %>
18 18 <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %>
19 19  
20   - <%= colorbox_button('new', _('New content'), :action => 'new', :parent_id => parent_id, :cms => true) %>
  20 + <%= modal_button('new', _('New content'), :action => 'new', :parent_id => parent_id, :cms => true) %>
21 21 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor', :action => "index") %>
22 22 <% end %>
23 23  
... ...
app/views/cms/why_categorize.html.erb
... ... @@ -5,5 +5,5 @@
5 5 </p>
6 6  
7 7 <% button_bar do %>
8   - <%= lightbox_close_button _('Close') %>
  8 + <%= modal_close_button _('Close') %>
9 9 <% end %>
... ...
app/views/comment/_comment_form.html.erb
... ... @@ -10,7 +10,7 @@
10 10 <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %>
11 11 <% button_bar do %>
12 12 <%= button_to_function :add, _('Confirm'), "return false", :id => "confirm-captcha" %>
13   - <%= button_to_function :cancel, _('Cancel'), "jQuery.colorbox.close()" %>
  13 + <%= button_to_function :cancel, _('Cancel'), "noosfero.modal.close()" %>
14 14 <% end %>
15 15 </div>
16 16  
... ... @@ -31,10 +31,10 @@ function check_captcha(button, confirm_action) {
31 31 return true;
32 32 <% else %>
33 33 jQuery('#recaptcha-container').show();
34   - jQuery.colorbox({ html: jQuery('#recaptcha-container').html(), maxWidth : '600px', maxHeight : '300px' });
  34 + noosfero.modal.inline('#recaptcha-container', {maxWidth :'600px', maxHeight : '300px' });
35 35 jQuery('#confirm-captcha').unbind('click');
36 36 jQuery('#confirm-captcha').bind('click', function() {
37   - jQuery.colorbox.close();
  37 + noosfero.modal.close();
38 38 button.form.recaptcha_response_field.value = jQuery('#recaptcha_response_field').val();
39 39 button.form.recaptcha_challenge_field.value = jQuery('#recaptcha_challenge_field').val();
40 40 button.form.confirm.value = 'true';
... ... @@ -88,7 +88,7 @@ function check_captcha(button, confirm_action) {
88 88 <% if !edition_mode %>
89 89 <%= button :cancel, _('Cancel'), '', :id => 'cancel-comment' %>
90 90 <% else %>
91   - <%= button :cancel, _('Cancel'), '#', :onclick => "jQuery.colorbox.close();" %>
  91 + <%= button :cancel, _('Cancel'), '#', :onclick => "noosfero.modal.close();" %>
92 92 <% end %>
93 93 <% end %>
94 94 <% end %>
... ...
app/views/content_viewer/_article_toolbar.html.erb
... ... @@ -28,14 +28,14 @@
28 28 <%= expirable_button @page, :locale, content, url %>
29 29 <% end %>
30 30  
31   - <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) unless remove_content_button(:new, @page) %>
  31 + <%= modal_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) unless remove_content_button(:new, @page) %>
32 32 <% end %>
33 33  
34 34 <% if @page.accept_uploads? && @page.allow_create?(user) %>
35 35 <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) unless remove_content_button(:upload, @page)%>
36 36 <% end %>
37 37  
38   - <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest, @page) %>
  38 + <% if !@page.allow_create?(user) && profile.organization? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest, @page) %>
39 39 <% content = content_tag( 'span', _('Suggest an article') ) %>
40 40 <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}) %>
41 41 <% options = {:id => 'suggest-article-link'} %>
... ...
app/views/content_viewer/_comment_form.html.erb
... ... @@ -7,10 +7,10 @@ function submit_comment_form(button) {
7 7 return true;
8 8 <% else %>
9 9 jQuery('#recaptcha-container').show();
10   - jQuery.colorbox({ inline : true, href : '#recaptcha-container', maxWidth : '600px', maxHeight : '300px' });
  10 + noosfero.modal.inline('#recaptcha-container', {maxWidth :'600px', maxHeight : '300px' });
11 11 jQuery('#confirm-captcha').unbind('click');
12 12 jQuery('#confirm-captcha').bind('click', function() {
13   - jQuery.colorbox.close();
  13 + noosfero.modal.close();
14 14 button.form.recaptcha_response_field.value = jQuery('#recaptcha_response_field').val();
15 15 button.form.recaptcha_challenge_field.value = jQuery('#recaptcha_challenge_field').val();
16 16 button.form.confirm.value = 'true';
... ... @@ -38,7 +38,7 @@ function submit_comment_form(button) {
38 38 <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %>
39 39 <% button_bar do %>
40 40 <%= button_to_function :add, _('Confirm'), "return false", :id => "confirm-captcha" %>
41   - <%= button_to_function :cancel, _('Cancel'), "jQuery.colorbox.close()" %>
  41 + <%= button_to_function :cancel, _('Cancel'), "noosfero.modal.close()" %>
42 42 <% end %>
43 43 </div>
44 44  
... ...
app/views/layouts/_javascript.html.erb
1 1 <%= javascript_include_tag 'jquery-2.1.1.min', 'jquery-migrate-1.2.1', 'jrails', 'rails.js',
2   -'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox',
3   -'jquery-ui-1.10.4/js/jquery-ui-1.10.4.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate',
4   -'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', 'jquery.typewatch', 'jquery.textchange',
5   -'add-and-join', 'report-abuse', 'catalog', 'manage-products', 'autogrow', 'select-or-die/_src/selectordie',
6   -'jquery-timepicker-addon/dist/jquery-ui-timepicker-addon', 'application.js', 'inputosaurus.js', :cache => 'cache/application' %>
  2 + 'jquery.cycle.all.min.js', 'jquery.colorbox-min.js',
  3 + 'jquery-ui-1.10.4/js/jquery-ui-1.10.4.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate',
  4 + 'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', 'jquery.typewatch', 'jquery.textchange',
  5 + 'jquery-timepicker-addon/dist/jquery-ui-timepicker-addon', 'inputosaurus.js', 'select-or-die/_src/selectordie',
  6 + # noosfero libraries
  7 + 'application.js', 'modal.js',
  8 + 'add-and-join', 'report-abuse', 'catalog', 'manage-products', 'autogrow',
  9 + :cache => 'cache/application' %>
7 10  
8 11 <% language = FastGettext.locale %>
9 12 <% %w{messages methods}.each do |type| %>
... ...
app/views/layouts/_user.html.erb
... ... @@ -7,11 +7,11 @@
7 7 </span>
8 8 <% else %>
9 9 <span class='not-logged-in'>
10   - <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %>
  10 + <%= _("<span class='login'>%s</span>") % modal_inline_link_to('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, '#inlineLoginBox', :id => 'link_login') %>
11 11 <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_exec(&content) }.join("") %>
12 12  
13 13 <div id='inlineLoginBox' style='display: none;'>
14   - <%= render :file => 'account/login', :locals => { :is_thickbox => true } %>
  14 + <%= render :file => 'account/login', :locals => { :is_popin => true } %>
15 15 </div>
16 16  
17 17 <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>
... ...
app/views/layouts/application-ng.html.erb
... ... @@ -18,7 +18,7 @@
18 18 <%= yield :head %>
19 19 <%=
20 20 @plugins.dispatch(:head_ending).map do |content|
21   - if content.respond_to?(:call) then instance_exec(&content).html_safe else content.html_safe end
  21 + if content.respond_to?(:call) then instance_exec(&content).to_s.html_safe else content.to_s.html_safe end
22 22 end.join("\n")
23 23 %>
24 24  
... ... @@ -32,7 +32,7 @@
32 32  
33 33 <%=
34 34 @plugins.dispatch(:body_beginning).map do |content|
35   - if content.respond_to?(:call) then instance_exec(&content).html_safe else content.html_safe end
  35 + if content.respond_to?(:call) then instance_exec(&content).to_s.html_safe else content.to_s.html_safe end
36 36 end.join("\n")
37 37 %>
38 38  
... ...
app/views/person_notifier/mailer/_comment.html.erb
... ... @@ -19,7 +19,7 @@
19 19 <span style="font-size: 12px;"><%= comment.title %></span><br/>
20 20 <% end %>
21 21 <span style="font-size: 10px;"><%= txt2html comment.body %></span><br/>
22   - <span style="font-size: 8px; color: #444444"><%= time_ago_as_sentence(comment.created_at) %></span>
  22 + <span style="font-size: 8px; color: #929292"><%= time_ago_as_sentence(comment.created_at) %></span>
23 23 <br style="clear: both;" />
24 24  
25 25 <% unless comment.replies.blank? %>
... ...
app/views/person_notifier/mailer/_create_article.html.erb
1   -<table>
2 1 <tr>
3   - <td>
  2 + <td style="width: 11%">
4 3 <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
5 4 </td>
6 5 <td>
7   - <p style="width:550px">
  6 + <p>
8 7 <span style="font-size: 14px;"><%= link_to activity.user.short_name(20), activity.user.url %></span>
9 8 <span style="font-size: 14px;"><%= _("has published on community %s") % link_to(activity.target.profile.short_name(20), activity.target.profile.url, :style => "color: #333; font-weight: bold; text-decoration: none;") if activity.target.profile.is_a?(Community) %></span>
10   - <span style="font-size: 10px; color: #444444; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  9 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
11 10 </p>
12 11 <p>
13 12 <span style="font-size: 14px;"><%= link_to(activity.params['name'], activity.params['url'], :style => "color: #333; font-weight: bold; text-decoration: none;") %></span>
... ... @@ -24,4 +23,3 @@
24 23 <%= render :partial => 'profile_comments', :locals => { :activity => activity } %>
25 24 </td>
26 25 </tr>
27   -</table>
... ...
app/views/person_notifier/mailer/_default_activity.html.erb
1   -<table>
2 1 <tr>
3   - <td>
  2 + <td style="width: 11%">
4 3 <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
5 4 </td>
6 5 <td>
7   - <p style="width:550px">
  6 + <p>
8 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
9   - <span style="font-size: 10px; color: #444444; float: right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(activity.created_at) %></span>
10 9 </p>
11 10 </td>
12 11 </tr>
... ... @@ -16,4 +15,3 @@
16 15 <%= render :partial => 'profile_comments', :locals => { :activity => activity } %>
17 16 </td>
18 17 </tr>
19   -</table>
... ...
app/views/person_notifier/mailer/_task.html.erb 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +<div style="border-bottom:1px solid #e2e2e2;padding:15px 0;width:600px">
  2 + <table style="width:100%;">
  3 + <tr>
  4 + <td style="width: 11%">
  5 + <%= profile_image(task.requestor, :minor) %>
  6 + </td>
  7 + <td>
  8 + <div>
  9 + <strong><%= link_to task.title, url_for(:controller => 'tasks', :profile => @profile.identifier, :action => 'index', :only_path => false) %></strong>
  10 + </div>
  11 + <div style="font-size: 14px">
  12 + <span style="font-size: 14px">
  13 + <%= task_information(task) %>
  14 + </span>
  15 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(task.created_at) %></span>
  16 + </div>
  17 + </td>
  18 + </tr>
  19 + </table>
  20 +</div>
... ...
app/views/person_notifier/mailer/_upload_image.html.erb
1   -<table>
2 1 <tr>
3   - <td>
  2 + <td style="width: 11%">
4 3 <%= link_to(profile_image(activity.user, :minor), activity.user.url) %>
5 4 </td>
6 5 <td>
7   - <p style="width:550px">
  6 + <p>
8 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
9   - <span style="font-size: 10px; color: #444444; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
10 9 </p>
11 10 </td>
12 11 </tr>
13   -</table>
14 12 <div title='<%= activity.target.class.short_description %>' class='profile-activity-icon icon-new icon-newgallery'></div>
15 13 <br/>
... ...
app/views/person_notifier/mailer/content_summary.html.erb
1   -<h3><%= _("%s's network activity") % @profile.name %></h3>
2   -<br/>
3   -<div>
4   -<% @notifications.each do |activity| %>
5   - <div style="border-left:none;border-right:none;border-top:1px solid #ccc;border-bottom:none;padding:10px;width:600px">
6   - <%= render :partial => activity.verb, :locals => { :activity => activity } rescue "cannot render notification for #{activity.verb}" %>
7   - </div>
8   -<% end %>
9   -</div>
  1 +<div style="background-color: #EEEEEE">
  2 + <table style="width: 100%;"><tbody><tr><td align="center">
  3 + <div style="display: table; background-color: white; margin: 26px 0;">
  4 + <div style="padding: 25px 20px 20px 20px;text-align: left;">
  5 + <%= link_to @url, :style => "text-decoration: none;" do %>
  6 + <span style="font-weight:bold;font-size: 28px;margin: 0;color: white;background-color: #AAAAAA;padding: 5px;"><%= @environment %></span>
  7 + <% end %>
  8 + <span style="font-weight:bold;color: #333;font-size:19px;margin-left: 8px;"><%= _("%s's Notifications") % @profile.name %></h3>
  9 + </div>
  10 + <div style="margin: 0 20px 20px 20px;border-top:1px solid #e2e2e2;">
  11 + <% if @tasks.present? %>
  12 + <div style="border-top: 1px solid #e2e2e2;">
  13 + <div style="border-bottom: 1px solid #CBCBCB;padding-top: 15px;font-weight: bold;text-align: right;color: #7c7c7c;float: right;min-width: 140px;">
  14 + <%= _('Tasks') %>
  15 + </div>
  16 + <%= render :partial => 'task', :collection => @tasks %>
  17 + </div>
  18 + <% end %>
  19 +
  20 + <% if @notifications.present? %>
  21 + <div style="border-top: 1px solid #e2e2e2;">
  22 + <div style="border-bottom: 1px solid #CBCBCB;padding-top: 15px;font-weight: bold;text-align: right;color: #7c7c7c;float: right;min-width: 140px;">
  23 + <%= _('Network Activity') %>
  24 + </div>
  25 + <% @notifications.each do |activity| %>
  26 + <div style="border-bottom:1px solid #e2e2e2;padding:15px 0;width:600px">
  27 + <table style="width:100%;">
  28 + <%= render :partial => activity.verb, :locals => { :activity => activity } rescue "cannot render notification for #{activity.verb}" %>
  29 + </table>
  30 + </div>
  31 + <% end %>
  32 + </div>
  33 + <% end %>
10 34  
11   -<div style="color:#444444;font-size:11px;">
12   -<p><%= _("Greetings,") %></p>
13   -<br/>
14   -<p>--</p>
15   -<p><%= _('%s team.') % @environment %></p>
16   -<p><%= url_for @url %></p>
  35 + <div style="color:#444444;font-size:11px;margin-bottom: 20px;">
  36 + <p style="margin:0"><%= _("Greetings,") %></p>
  37 + <p style="margin:0"><%= _('%s team.') % @environment %></p>
  38 + <p style="margin:0"><%= link_to @url, url_for(@url) %></p>
  39 + </div>
  40 + </div>
  41 + </td></tr></tbody></table>
17 42 </div>
18   -<br/>
... ...
app/views/profile/join.html.erb
... ... @@ -9,7 +9,7 @@
9 9 <%= hidden_field_tag(:confirmation, 1) %>
10 10 <%= submit_button(:ok, _("Yes, I want to join.") % profile.name) %>
11 11 <% if logged_in? && request.xhr? %>
12   - <%= lightbox_close_button(_("No, I don't want")) %>
  12 + <%= modal_close_button _("No, I don't want") %>
13 13 <% else %>
14 14 <%= button(:cancel, _("No, I don't want."), profile.url) %>
15 15 <% end %>
... ...
app/views/profile/leave.html.erb
... ... @@ -9,7 +9,7 @@
9 9 <%= hidden_field_tag(:back_to, @back_to) %>
10 10 <%= submit_button(:ok, _("Yes, I want to leave.") % profile.name) %>
11 11 <% if logged_in? && request.xhr? %>
12   - <%= lightbox_close_button(_("No, I don't want")) %>
  12 + <%= modal_close_button _("No, I don't want") %>
13 13 <% else %>
14 14 <%= button(:cancel, _("No, I don't want."), profile.url) %>
15 15 <% end %>
... ...
app/views/profile/report_abuse.html.erb
... ... @@ -9,7 +9,7 @@
9 9 <% end %>
10 10  
11 11 <%= submit_button(:send, _('Report profile'), :style => 'float: left; cursor: pointer;', :id => 'report-abuse-submit-button', :onclick => "jQuery('#form-submit-loading').show()") %>
12   - <%= button(:cancel, _('Cancel'), {}, :style => 'float: left; padding-top: 0px; padding-bottom: 0px;', :onclick => 'jQuery.colorbox.close(); return false;')%>
  12 + <%= button(:cancel, _('Cancel'), {}, :style => 'float: left; padding-top: 0px; padding-bottom: 0px;', :onclick => 'noosfero.modal.close(); return false;')%>
13 13 <div id="form-submit-loading" class="small-loading" style="width: 16px; height: 16px; margin-top: 3px; float: left; display: none;"></div>
14 14 <% end %>
15 15  
... ... @@ -30,7 +30,7 @@
30 30 success: function(data, status, ajax){
31 31 if ( !data.ok ) display_notice(data.error.message);
32 32 else {
33   - $.colorbox.close();
  33 + noosfero.modal.close();
34 34 display_notice(data.message);
35 35 window.location.reload();
36 36 }
... ...
app/views/profile_themes/add_css.html.erb
... ... @@ -5,7 +5,7 @@
5 5  
6 6 <% button_bar do %>
7 7 <%= submit_button(:add, _('Add')) %>
8   - <%= lightbox_close_button(_('Cancel')) %>
  8 + <%= modal_close_button _('Cancel') %>
9 9 <% end %>
10 10  
11 11 <% end %>
... ...
app/views/profile_themes/edit.html.erb
... ... @@ -16,7 +16,7 @@
16 16 <% end %>
17 17 </ul>
18 18 <% button_bar do %>
19   - <%= lightbox_button(:add, _('New CSS'), :action => 'add_css', :id => @theme.id) %>
  19 + <%= modal_button :add, _('New CSS'), :action => 'add_css', :id => @theme.id %>
20 20 <% end %>
21 21 </div>
22 22  
... ... @@ -25,10 +25,10 @@
25 25 <ul>
26 26 <% for image in @image_files %>
27 27 <li><%= image_tag("/user_themes/#{@theme.id}/images/#{image}") %></li>
28   - <% end %>
  28 + <% end %>
29 29 </ul>
30 30 <% button_bar do %>
31   - <%= lightbox_button(:add, _('Add image'), :action => 'add_image', :id => @theme.id) %>
  31 + <%= modal_button :add, _('Add image'), :action => 'add_image', :id => @theme.id %>
32 32 <% end %>
33 33 </div>
34 34  
... ...
app/views/profile_themes/index.html.erb
... ... @@ -42,7 +42,7 @@
42 42  
43 43 <% button_bar do %>
44 44 <% if environment.enabled?('user_themes') %>
45   - <%= lightbox_button(:add, _('New theme ...'), :action => 'new') %>
  45 + <%= modal_button :add, _('New theme ...'), :action => 'new' %>
46 46 <% end %>
47 47 <%= button(:back, _('Back'), :controller => 'profile_editor', :action => 'index') %>
48 48 <% end %>
... ...
app/views/shared/user_menu.html.erb
... ... @@ -20,7 +20,7 @@
20 20 </li>
21 21  
22 22 <li>
23   - <%= lightbox_link_to('<span class="icon-new"></span>' + _('New article'), '/myprofile/{login}/cms/new') %>
  23 + <%= modal_link_to '<span class="icon-new"></span>' + _('New article'), '/myprofile/{login}/cms/new' %>
24 24 </li>
25 25  
26 26 <li id='manage-enterprises-link-template' style='display: none'><a href='/myprofile/{identifier}'><span class="icon-menu-enterprise"></span><%= _('Manage %s') % '{name}' %></a></li>
... ... @@ -58,9 +58,9 @@
58 58 <% if theme_option( :menu_login ) == 'full_form' %>
59 59 <%= render :file => 'account/login_block' %>
60 60 <% else %>
61   - <%= thickbox_inline_popup_link('<span class="icon-menu-login"></span>'+ _('Login'), login_url, 'inlineLoginBox', :id => 'link_login') %>
  61 + <%= modal_inline_link_to('<span class="icon-menu-login"></span>'+ _('Login'), login_url, '#inlineLoginBox', :id => 'link_login') %>
62 62 <div id='inlineLoginBox' style='display: none;'>
63   - <%= render :file => 'account/login', :locals => { :is_thickbox => true } %>
  63 + <%= render :file => 'account/login', :locals => { :is_popin => true } %>
64 64 </div>
65 65 <% end %>
66 66 <% end %>
... ...
config/database.yml.multitenancy
1 1 # Refer to INSTALL.multitenancy for more information on Multitenancy support
2   -env1_production:
  2 +env1_production: &DEFAULT
3 3 adapter: postgresql
4 4 encoding: unicode
5 5 database: noosfero
... ... @@ -30,4 +30,4 @@ env3_production:
30 30 - env3.net
31 31  
32 32 production:
33   - env1_production
  33 + <<: *DEFAULT
... ...
config/noosfero.yml.dist
... ... @@ -9,6 +9,7 @@ development:
9 9 googlemaps_initial_zoom: 4
10 10 exception_recipients: [admin@example.com]
11 11 max_upload_size: 5MB
  12 + hours_until_user_activation_check: 72
12 13  
13 14 test:
14 15  
... ...
config/schedule.rb
... ... @@ -25,6 +25,6 @@ every 1.day do
25 25 runner "SearchTerm.calculate_scores"
26 26 end
27 27  
28   -every 90.days do
  28 +every 30.days do
29 29 runner "ProfileSuggestion.generate_all_profile_suggestions"
30 30 end
... ...
db/migrate/20140519113821_add_last_login_at_to_user.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddLastLoginAtToUser < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :users, :last_login_at, :datetime
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :users, :last_login_at
  8 + end
  9 +end
... ...
db/migrate/20150112233715_normalize_users_email.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class NormalizeUsersEmail < ActiveRecord::Migration
  2 + def up
  3 + User.find_each do |u|
  4 + u.update_column :email, u.send(:normalize_email)
  5 + end
  6 + end
  7 +
  8 + def down
  9 + say "this migration can't be reverted"
  10 + end
  11 +end
... ...
db/schema.rb
... ... @@ -733,6 +733,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150122165042) do
733 733 t.string "activation_code", :limit => 40
734 734 t.datetime "activated_at"
735 735 t.string "return_to"
  736 + t.datetime "last_login_at"
736 737 end
737 738  
738 739 create_table "validation_infos", :force => true do |t|
... ...
debian/control
... ... @@ -48,7 +48,6 @@ Depends: adduser,
48 48 ruby-feedparser,
49 49 ruby-feedparser (>= 0.7-3~),
50 50 ruby-gettext,
51   - ruby-hpricot,
52 51 ruby-memcache-client,
53 52 ruby-minitest,
54 53 ruby-nokogiri,
... ...
lib/authenticated_system.rb
... ... @@ -5,22 +5,23 @@ module AuthenticatedSystem
5 5 def logged_in?
6 6 current_user != nil
7 7 end
8   -
  8 +
9 9 # Accesses the current user from the session.
10 10 def current_user
11 11 @current_user ||= (session[:user] && User.find_by_id(session[:user])) || nil
12 12 end
13   -
  13 +
14 14 # Store the given user in the session.
15 15 def current_user=(new_user)
16 16 if new_user.nil?
17 17 session.delete(:user)
18 18 else
19 19 session[:user] = new_user.id
  20 + new_user.register_login
20 21 end
21 22 @current_user = new_user
22 23 end
23   -
  24 +
24 25 # Check if the user is authorized.
25 26 #
26 27 # Override this method in your controllers if you want to restrict access
... ... @@ -62,7 +63,7 @@ module AuthenticatedSystem
62 63 access_denied
63 64 end
64 65 end
65   -
  66 +
66 67 # Redirect as appropriate when an access request fails.
67 68 #
68 69 # The default action is to redirect to the login screen.
... ... @@ -88,15 +89,15 @@ module AuthenticatedSystem
88 89 end
89 90 end
90 91 false
91   - end
92   -
  92 + end
  93 +
93 94 # Store the URI of the current request in the session.
94 95 #
95 96 # We can return to this location by calling #redirect_back_or_default.
96 97 def store_location(location = request.url)
97 98 session[:return_to] = location
98 99 end
99   -
  100 +
100 101 # Redirect to the URI stored by the most recent store_location call or
101 102 # to the passed default.
102 103 def redirect_back_or_default(default)
... ... @@ -106,7 +107,7 @@ module AuthenticatedSystem
106 107 redirect_to(default)
107 108 end
108 109 end
109   -
  110 +
110 111 # Inclusion hook to make #current_user and #logged_in?
111 112 # available as ActionView helper methods.
112 113 def self.included(base)
... ... @@ -132,6 +133,6 @@ module AuthenticatedSystem
132 133 def get_auth_data
133 134 auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
134 135 auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
135   - return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
  136 + return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
136 137 end
137 138 end
... ...
lib/noosfero/plugin.rb
... ... @@ -24,11 +24,17 @@ class Noosfero::Plugin
24 24  
25 25 def initialize!
26 26 return if !should_load
27   - available_plugins.each do |plugin_dir|
  27 +
  28 + klasses = available_plugins.map do |plugin_dir|
28 29 plugin_name = File.basename(plugin_dir)
29   - plugin = load_plugin(plugin_name)
30   - load_plugin_extensions(plugin_dir)
31   - load_plugin_filters(plugin)
  30 + load_plugin plugin_name
  31 + end
  32 + available_plugins.each do |plugin_dir|
  33 + load_plugin_extensions plugin_dir
  34 + end
  35 + # filters must be loaded after all extensions
  36 + klasses.each do |plugin|
  37 + load_plugin_filters plugin
32 38 end
33 39 end
34 40  
... ... @@ -88,7 +94,7 @@ class Noosfero::Plugin
88 94 # This is a generic method that initialize any possible filter defined by a
89 95 # plugin to a specific controller
90 96 def load_plugin_filters(plugin)
91   - Rails.configuration.to_prepare do
  97 + ActionDispatch::Reloader.to_prepare do
92 98 filters = plugin.new.send 'application_controller_filters' rescue []
93 99 Noosfero::Plugin.add_controller_filters ApplicationController, plugin, filters
94 100  
... ... @@ -116,7 +122,7 @@ class Noosfero::Plugin
116 122 end
117 123  
118 124 def load_plugin_extensions(dir)
119   - Rails.configuration.to_prepare do
  125 + ActionDispatch::Reloader.to_prepare do
120 126 Dir[File.join(dir, 'lib', 'ext', '*.rb')].each {|file| require_dependency file }
121 127 end
122 128 end
... ...
lib/noosfero/plugin/macro.rb
... ... @@ -35,7 +35,7 @@ class Noosfero::Plugin::Macro
35 35 def attributes(macro)
36 36 macro.attributes.to_hash.
37 37 select {|key, value| key[0..10] == 'data-macro-'}.
38   - inject({}){|result, a| result.merge({a[0][11..-1] => a[1]})}.
  38 + inject({}){|result, a| result.merge({a[0][11..-1] => a[1].to_s})}.
39 39 with_indifferent_access
40 40 end
41 41  
... ...
lib/noosfero/plugin/routes.rb
1 1 plugins_root = Rails.env.test? ? 'plugins' : '{baseplugins,config/plugins}'
  2 +prefixes_by_folder = {public: 'plugin',
  3 + profile: 'profile/:profile/plugin',
  4 + myprofile: 'myprofile/:profile/plugin',
  5 + admin: 'admin/plugin'}
2 6  
3 7 Dir.glob(Rails.root.join(plugins_root, '*', 'controllers')) do |controllers_dir|
4   - prefixes_by_folder = {'public' => 'plugin',
5   - 'profile' => 'profile/:profile/plugin',
6   - 'myprofile' => 'myprofile/:profile/plugin',
7   - 'admin' => 'admin/plugin'}
  8 + plugin_name = File.basename(File.dirname(controllers_dir))
8 9  
9 10 controllers_by_folder = prefixes_by_folder.keys.inject({}) do |hash, folder|
10   - hash.merge!({folder => Dir.glob(File.join(controllers_dir, folder, '*')).map {|full_names| File.basename(full_names).gsub(/_controller.rb$/,'')}})
  11 + path = "#{controllers_dir}/#{folder}/"
  12 + hash[folder] = Dir.glob("#{path}{*.rb,#{plugin_name}_plugin/*.rb}").map do |filename|
  13 + filename.gsub(path, '').gsub(/_controller.rb$/, '')
  14 + end
  15 + hash
11 16 end
12 17  
13   - plugin_name = File.basename(File.dirname(controllers_dir))
14   -
15 18 controllers_by_folder.each do |folder, controllers|
16 19 controllers.each do |controller|
17 20 controller_name = controller.gsub("#{plugin_name}_plugin_",'')
... ...
lib/noosfero/plugin/spammable.rb
1   -Rails.configuration.to_prepare do
  1 +ActionDispatch::Reloader.to_prepare do
2 2 Spammable.module_eval do
3 3 def marked_as_spam
4 4 plugins.dispatch(:marked_as_spam, self)
... ...
lib/tasks/multitenancy.rake
1 1 namespace :multitenancy do
2 2  
3   - task :create do
  3 + task :create => :environment do
4 4 db_envs = ActiveRecord::Base.configurations.keys.select{ |k| k.match(/_development$|_production$|_test$/) }
5 5 cd Rails.root.join('config', 'environments'), :verbose => true
6   - file_envs = Dir.glob "{*_development.rb,*_prodution.rb,*_test.rb}"
  6 + file_envs = Dir.glob "{*_development.rb,*_production.rb,*_test.rb}"
7 7 (db_envs.map{ |e| e + '.rb' } - file_envs).each { |env| ln_s env.split('_').last, env }
8 8 end
9 9  
10   - task :remove do
  10 + task :remove => :environment do
11 11 db_envs = ActiveRecord::Base.configurations.keys.select{ |k| k.match(/_development$|_production$|_test$/) }
12 12 cd Rails.root.join('config', 'environments'), :verbose => true
13   - file_envs = Dir.glob "{*_development.rb,*_prodution.rb,*_test.rb}"
  13 + file_envs = Dir.glob "{*_development.rb,*_production.rb,*_test.rb}"
14 14 (file_envs - db_envs.map{ |e| e + '.rb' }).each { |env| safe_unlink env }
15 15 end
16 16  
... ...
lib/tasks/plugins_tests.rake
... ... @@ -106,7 +106,7 @@ def run_test(name, files)
106 106 files = Array(files)
107 107 plugin = filename2plugin(files.first)
108 108 if name == :cucumber || name == :selenium
109   - run_cucumber task2_profile(name, plugin), files
  109 + run_cucumber task2profile(name, plugin), files
110 110 else
111 111 run_testrb files
112 112 end
... ... @@ -134,7 +134,11 @@ end
134 134  
135 135 def run_tests(name, plugins, run=:all)
136 136 plugins = Array(plugins)
137   - glob = "plugins/{#{plugins.join(',')}}/test/#{task2folder(name)}/**/*.#{task2ext(name)}"
  137 + if name == :cucumber || name == :selenium
  138 + glob = "plugins/{#{plugins.join(',')}}/#{task2folder(name)}/**/*.#{task2ext(name)}"
  139 + else
  140 + glob = "plugins/{#{plugins.join(',')}}/test/#{task2folder(name)}/**/*.#{task2ext(name)}"
  141 + end
138 142 files = Dir.glob(glob)
139 143 if files.empty?
140 144 puts "I: no tests to run #{name}"
... ...
plugins/bsc/public/jquery.ui.spinner
... ... @@ -1 +0,0 @@
1   -Subproject commit bd879003043b4a93b78cbd4a582b6e0650900bcb
plugins/comment_classification/features/step_definitions/plugin_steps.rb
1 1 Given /^CommentClassificationPlugin is enabled$/ do
2   - step %{I am logged in as admin}
3   - step %{I am on the environment control panel}
4   - step %{I follow "Plugins"}
5   - step %{I check "Comment Classification"}
6   - step %{I press "Save changes"}
  2 + steps %Q{
  3 + Given I am logged in as admin
  4 + Given I am on the environment control panel
  5 + Given I follow "Plugins"
  6 + Given I check "Comment Classification"
  7 + Given I press "Save changes"
  8 + }
  9 +
7 10 Environment.default.enabled_plugins.should include("CommentClassificationPlugin")
8 11 end
9 12  
... ...
plugins/comment_classification/lib/ext/comment.rb
1 1 require_dependency 'comment'
2   -require 'comment_classification_plugin.rb'
3   -require 'comment_classification_plugin/label.rb'
4 2  
5 3 class Comment
6 4  
... ...
plugins/comment_group/lib/ext/article.rb
... ... @@ -9,7 +9,7 @@ class Article
9 9 def not_empty_group_comments_removed
10 10 if body && body_changed?
11 11 groups_with_comments = Comment.find(:all, :select => 'distinct group_id', :conditions => {:source_id => self.id}).map(&:group_id).compact
12   - groups = Hpricot(body.to_s).search('.macro').collect{|element| element['data-macro-group_id'].to_i}
  12 + groups = Nokogiri::HTML.fragment(body.to_s).css('.macro').collect{|element| element['data-macro-group_id'].to_i}
13 13 errors[:base] << (N_('Not empty group comment cannot be removed')) unless (groups_with_comments-groups).empty?
14 14 end
15 15 end
... ...
plugins/community_track/lib/community_track_plugin/track.rb
... ... @@ -59,7 +59,7 @@ class CommunityTrackPlugin::Track &lt; Folder
59 59  
60 60 def first_paragraph
61 61 return '' if body.blank?
62   - paragraphs = Hpricot(body).search('p')
  62 + paragraphs = Nokogiri::HTML.fragment(body).css('p')
63 63 paragraphs.empty? ? '' : paragraphs.first.to_html
64 64 end
65 65  
... ...
plugins/custom_forms/public/style.css
... ... @@ -25,7 +25,7 @@
25 25 .edit-information {
26 26 display: none;
27 27 }
28   -#colorbox .edit-information {
  28 +.modal .edit-information {
29 29 display: block;
30 30 }
31 31  
... ...
plugins/custom_forms/views/custom_forms_plugin_myprofile/_edit_select.html.erb
... ... @@ -26,7 +26,7 @@
26 26 <%= labelled_radio_button 'Multiple Select', "fields[#{counter}][kind]", 'multiple_select', field.multiple && field.list %><br />
27 27  
28 28 <% button_bar do %>
29   - <%= button :ok, c_('Ok'), '#', :class => 'colorbox-ok-button', :div_id => elem_id %>
  29 + <%= button :ok, _('Ok'), '#', :div_id => elem_id %>
30 30 <% end %>
31 31 </div>
32 32  
... ...
plugins/oauth_client/Gemfile 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +gem 'omniauth', '~> 1.2.2'
  2 +gem 'omniauth-facebook', '~> 2.0.0'
  3 +gem "omniauth-google-oauth2", '~> 0.2.6'
... ...
plugins/oauth_client/README.md 0 → 100644
... ... @@ -0,0 +1,72 @@
  1 +README - Oauth Client Plugin
  2 +================================
  3 +
  4 +OauthClient is a plugin which allow users to login/signup to noosfero with some oauth providers (for now, google, facebook and noosfero itself).
  5 +
  6 +Install
  7 +=======
  8 +
  9 +Enable Plugin
  10 +-------------
  11 +
  12 +cd <your_noosfero_dir>
  13 +./script/noosfero-plugins enable oauth_client
  14 +
  15 +Active Plugin
  16 +-------------
  17 +
  18 +As a Noosfero administrator user, go to administrator panel:
  19 +
  20 +- Click on "Enable/disable plugins" option
  21 +- Click on "Oauth Client Plugin" check-box
  22 +
  23 +Provider Settings
  24 +=================
  25 +
  26 +Goggle
  27 +------
  28 +
  29 +[Create Google+ application](https://developers.google.com/+/web/signin/javascript-flow)
  30 +
  31 +Facebook
  32 +--------
  33 +
  34 +[Create Facebook application](https://developers.facebook.com/docs/facebook-login/v2.1)
  35 +
  36 +Varnish Settings
  37 +================
  38 +If varnish has been used in your stack, you've to bypass the cache for signup page and prevent cookies to be removed when calling the oauth_client plugin callback. E.g.:
  39 +
  40 +```
  41 +if (req.url !~ "^/account/*" && req.url !~ "^/plugin/oauth_provider/*" && req.url !~ "^/plugin/oauth_client/*" && req.http.cookie !~ "_noosfero_.*") {
  42 + unset req.http.cookie;
  43 + return(lookup);
  44 +}
  45 +```
  46 +
  47 +Using Oauth Provider Plugin
  48 +===========================
  49 +The oauth_provider plugin may be used as a provider in the same noosfero installation that hosts your oauth_client plugin (this is usefull in a multi environment setup).
  50 +
  51 +However, you've to use a distinct set of thin processes to handle the authorization requests (to avoid deadlock).
  52 +
  53 +Apache settings example:
  54 +```
  55 +RewriteRule ^/oauth_provider/oauth/(authorize|token).*$ balancer://noosfero-oauth-provider%{REQUEST_URI} [P,QSA,L]
  56 +```
  57 +
  58 +
  59 +Development
  60 +===========
  61 +
  62 +Running OauthClient tests
  63 +--------------------
  64 +
  65 +$ rake test:noosfero_plugins:oauth_client
  66 +
  67 +License
  68 +=======
  69 +
  70 +Copyright (c) The Author developers.
  71 +
  72 +See Noosfero license.
... ...
plugins/oauth_client/controllers/oauth_client_plugin_admin_controller.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +class OauthClientPluginAdminController < AdminController
  2 +
  3 + def index
  4 + end
  5 +
  6 + def new
  7 + @provider = environment.oauth_providers.new
  8 + render :file => 'oauth_client_plugin_admin/edit'
  9 + end
  10 +
  11 + def remove
  12 + environment.oauth_providers.find(params[:id]).destroy
  13 + redirect_to :action => 'index'
  14 + end
  15 +
  16 + def edit
  17 + @provider = params[:id] ? environment.oauth_providers.find(params[:id]) : environment.oauth_providers.new
  18 + if request.post?
  19 + if @provider.update_attributes(params['oauth_client_plugin_provider'])
  20 + session[:notice] = _('Saved!')
  21 + else
  22 + session[:notice] = _('Error!')
  23 + end
  24 + end
  25 + end
  26 +
  27 +end
... ...
plugins/oauth_client/controllers/public/oauth_client_plugin_public_controller.rb 0 → 100644
... ... @@ -0,0 +1,46 @@
  1 +class OauthClientPluginPublicController < PublicController
  2 +
  3 + skip_before_filter :login_required
  4 +
  5 + def callback
  6 + auth = request.env["omniauth.auth"]
  7 + user = environment.users.find_by_email(auth.info.email)
  8 + user ? login(user) : signup(auth)
  9 + end
  10 +
  11 + def failure
  12 + session[:notice] = _('Failed to login')
  13 + redirect_to root_url
  14 + end
  15 +
  16 + def destroy
  17 + session[:user] = nil
  18 + redirect_to root_url
  19 + end
  20 +
  21 + protected
  22 +
  23 + def login(user)
  24 + provider = OauthClientPlugin::Provider.find(session[:provider_id])
  25 + user_provider = user.oauth_user_providers.find_by_provider_id(provider.id)
  26 + unless user_provider
  27 + user_provider = user.oauth_user_providers.create(:user => user, :provider => provider, :enabled => true)
  28 + end
  29 + if user_provider.enabled? && provider.enabled?
  30 + session[:user] = user.id
  31 + else
  32 + session[:notice] = _("Can't login with #{provider.name}")
  33 + end
  34 +
  35 + redirect_to :controller => :account, :action => :login
  36 + end
  37 +
  38 + def signup(auth)
  39 + login = auth.info.email.split('@').first
  40 + session[:oauth_data] = auth
  41 + name = auth.info.name
  42 + name ||= auth.extra && auth.extra.raw_info ? auth.extra.raw_info.name : ''
  43 + redirect_to :controller => :account, :action => :signup, :user => {:login => login, :email => auth.info.email}, :profile_data => {:name => name}
  44 + end
  45 +
  46 +end
... ...
plugins/oauth_client/db/migrate/20141010135314_create_oauth_client_plugin_provider.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class CreateOauthClientPluginProvider < ActiveRecord::Migration
  2 +
  3 + def self.up
  4 + create_table :oauth_client_plugin_providers do |t|
  5 + t.integer :environment_id
  6 + t.string :strategy
  7 + t.string :name
  8 + t.text :options
  9 + t.boolean :enabled
  10 + t.integer :image_id
  11 +
  12 + t.timestamps
  13 + end
  14 + end
  15 +
  16 + def self.down
  17 + drop_table :oauth_client_plugin_providers
  18 + end
  19 +end
... ...
plugins/oauth_client/db/migrate/20141014162710_create_oauth_client_user_providers.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class CreateOauthClientUserProviders < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :oauth_client_plugin_user_providers do |t|
  4 + t.references :user
  5 + t.references :provider
  6 + t.boolean :enabled
  7 + t.timestamps
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + drop_table :oauth_client_plugin_user_providers
  13 + end
  14 +end
... ...
plugins/oauth_client/lib/ext/environment.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +require_dependency 'environment'
  2 +
  3 +class Environment
  4 +
  5 + has_many :oauth_providers, :class_name => 'OauthClientPlugin::Provider'
  6 +
  7 +end
... ...
plugins/oauth_client/lib/ext/user.rb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +require_dependency 'user'
  2 +
  3 +class User
  4 +
  5 + has_many :oauth_user_providers, :class_name => 'OauthClientPlugin::UserProvider'
  6 + has_many :oauth_providers, :through => :oauth_user_providers, :source => :provider
  7 +
  8 + def password_required_with_oauth?
  9 + password_required_without_oauth? && oauth_providers.empty?
  10 + end
  11 +
  12 + alias_method_chain :password_required?, :oauth
  13 +
  14 + after_create :activate_oauth_user
  15 +
  16 + def activate_oauth_user
  17 + unless oauth_providers.empty?
  18 + activate
  19 + oauth_providers.each do |provider|
  20 + OauthClientPlugin::UserProvider.create!(:user => self, :provider => provider, :enabled => true)
  21 + end
  22 + end
  23 + end
  24 +
  25 + def make_activation_code_with_oauth
  26 + oauth_providers.blank? ? make_activation_code_without_oauth : nil
  27 + end
  28 +
  29 + alias_method_chain :make_activation_code, :oauth
  30 +
  31 +end
... ...
plugins/oauth_client/lib/oauth_client_plugin.rb 0 → 100644
... ... @@ -0,0 +1,95 @@
  1 +require 'omniauth/strategies/noosfero_oauth2'
  2 +
  3 +class OauthClientPlugin < Noosfero::Plugin
  4 +
  5 + def self.plugin_name
  6 + "Oauth Client Plugin"
  7 + end
  8 +
  9 + def self.plugin_description
  10 + _("Login with Oauth.")
  11 + end
  12 +
  13 + def login_extra_contents
  14 + plugin = self
  15 + proc do
  16 + render :partial => 'auth/oauth_login', :locals => {:providers => environment.oauth_providers.enabled}
  17 + end
  18 + end
  19 +
  20 + def signup_extra_contents
  21 + plugin = self
  22 +
  23 + proc do
  24 + if plugin.context.session[:oauth_data].present?
  25 + render :partial => 'account/oauth_signup'
  26 + else
  27 + ''
  28 + end
  29 + end
  30 + end
  31 +
  32 + PROVIDERS = {
  33 + :facebook => {
  34 + :name => 'Facebook'
  35 + },
  36 + :google_oauth2 => {
  37 + :name => 'Google'
  38 + },
  39 + :noosfero_oauth2 => {
  40 + :name => 'Noosfero'
  41 + }
  42 + }
  43 +
  44 + def stylesheet?
  45 + true
  46 + end
  47 +
  48 + OmniAuth.config.on_failure = OauthClientPluginPublicController.action(:failure)
  49 +
  50 + Rails.application.config.middleware.use OmniAuth::Builder do
  51 + PROVIDERS.each do |provider, options|
  52 + setup = lambda { |env|
  53 + request = Rack::Request.new(env)
  54 + strategy = env['omniauth.strategy']
  55 +
  56 + Noosfero::MultiTenancy.setup!(request.host)
  57 + domain = Domain.find_by_name(request.host)
  58 + environment = domain.environment rescue Environment.default
  59 +
  60 + provider_id = request.params['id']
  61 + provider_id ||= request.session['omniauth.params']['id'] if request.session['omniauth.params']
  62 + provider = environment.oauth_providers.find(provider_id)
  63 + strategy.options.merge!(provider.options.symbolize_keys)
  64 +
  65 + request.session[:provider_id] = provider_id
  66 + }
  67 +
  68 + provider provider, :setup => setup,
  69 + :path_prefix => '/plugin/oauth_client',
  70 + :callback_path => "/plugin/oauth_client/public/callback/#{provider}",
  71 + :client_options => { :connection_opts => { :proxy => ENV["OAUTH_HTTP_PROXY"] } }
  72 + end
  73 +
  74 + unless Rails.env.production?
  75 + provider :developer, :path_prefix => "/plugin/oauth_client", :callback_path => "/plugin/oauth_client/public/callback/developer"
  76 + end
  77 + end
  78 +
  79 + def account_controller_filters
  80 + {
  81 + :type => 'before_filter', :method_name => 'signup',
  82 + :block => proc {
  83 + auth = session[:oauth_data]
  84 +
  85 + if auth.present? && params[:user].present?
  86 + params[:user][:oauth_providers] = [OauthClientPlugin::Provider.find(session[:provider_id])]
  87 + if request.post? && auth.info.email != params[:user][:email]
  88 + raise "Wrong email for oauth signup"
  89 + end
  90 + end
  91 + }
  92 + }
  93 + end
  94 +
  95 +end
... ...
plugins/oauth_client/lib/oauth_client_plugin/provider.rb 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +class OauthClientPlugin::Provider < Noosfero::Plugin::ActiveRecord
  2 +
  3 + belongs_to :environment
  4 +
  5 + validates_presence_of :name, :strategy
  6 +
  7 + acts_as_having_image
  8 + acts_as_having_settings :field => :options
  9 +
  10 + settings_items :client_id, :type => :string
  11 + settings_items :client_secret, :type => :string
  12 + settings_items :client_options, :type => Hash
  13 +
  14 + attr_accessible :name, :environment, :strategy, :client_id, :client_secret, :enabled, :client_options, :image_builder
  15 +
  16 + scope :enabled, :conditions => {:enabled => true}
  17 +
  18 + acts_as_having_image
  19 +
  20 +end
... ...
plugins/oauth_client/lib/oauth_client_plugin/user_provider.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +class OauthClientPlugin::UserProvider < Noosfero::Plugin::ActiveRecord
  2 +
  3 + belongs_to :user, :class_name => 'User'
  4 + belongs_to :provider, :class_name => 'OauthClientPlugin::Provider'
  5 +
  6 + set_table_name :oauth_client_plugin_user_providers
  7 +
  8 + attr_accessible :user, :provider, :enabled
  9 +
  10 +end
... ...
plugins/oauth_client/lib/omniauth/strategies/noosfero_oauth2.rb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +require 'omniauth/strategies/oauth2'
  2 +
  3 +module OmniAuth
  4 + module Strategies
  5 + class NoosferoOauth2 < OmniAuth::Strategies::OAuth2
  6 + option :name, :noosfero_oauth2
  7 + option :client_options, {
  8 + :authorize_url => '/oauth_provider/oauth/authorize',
  9 + :token_url => '/oauth_provider/oauth/token'
  10 + }
  11 +
  12 + uid { raw_info["id"] }
  13 +
  14 + info do
  15 + {
  16 + :email => raw_info["email"]
  17 + }
  18 + end
  19 +
  20 + def raw_info
  21 + #FIXME access the noosfero api (coming soon)
  22 + @raw_info ||= access_token.get('/plugin/oauth_provider/public/me').parsed
  23 + end
  24 + end
  25 + end
  26 +end
... ...
plugins/oauth_client/public/style.css 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +.oauth-login .provider a {
  2 + min-width: 20px;
  3 + min-height: 20px;
  4 + background-size: 20px;
  5 + display: inline-block;
  6 + text-decoration: none;
  7 + background-repeat: no-repeat;
  8 + line-height: 20px;
  9 +}
  10 +.oauth-login .provider a img {
  11 + max-width: 40px;
  12 +}
  13 +.oauth-login .provider a:hover {
  14 + opacity: 0.7;
  15 +}
  16 +.oauth-login .provider .developer {
  17 + display: none;
  18 +}
... ...
plugins/oauth_client/test/functional/oauth_client_plugin_public_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,80 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class OauthClientPluginPublicControllerTest < ActionController::TestCase
  4 +
  5 + def setup
  6 + @auth = mock
  7 + @auth.stubs(:info).returns(mock)
  8 + request.env["omniauth.auth"] = @auth
  9 + @environment = Environment.default
  10 + @provider = OauthClientPlugin::Provider.create!(:name => 'provider', :strategy => 'provider', :enabled => true)
  11 + end
  12 + attr_reader :auth, :environment, :provider
  13 +
  14 + should 'redirect to signup when user is not found' do
  15 + auth.info.stubs(:email).returns("xyz123@noosfero.org")
  16 + auth.info.stubs(:name).returns('xyz123')
  17 + session[:provider_id] = provider.id
  18 +
  19 + get :callback
  20 + assert_match /.*\/account\/signup/, @response.redirect_url
  21 + end
  22 +
  23 + should 'redirect to login when user is found' do
  24 + user = fast_create(User, :environment_id => environment.id)
  25 + auth.info.stubs(:email).returns(user.email)
  26 + auth.info.stubs(:name).returns(user.name)
  27 + session[:provider_id] = provider.id
  28 +
  29 + get :callback
  30 + assert_redirected_to :controller => :account, :action => :login
  31 + assert_equal user.id, session[:user]
  32 + end
  33 +
  34 + should 'do not login when the provider is disabled' do
  35 + user = fast_create(User, :environment_id => environment.id)
  36 + auth.info.stubs(:email).returns(user.email)
  37 + auth.info.stubs(:name).returns(user.name)
  38 + session[:provider_id] = provider.id
  39 + provider.update_attribute(:enabled, false)
  40 +
  41 + get :callback
  42 + assert_redirected_to :controller => :account, :action => :login
  43 + assert_equal nil, session[:user]
  44 + end
  45 +
  46 + should 'do not login when the provider is disabled for a user' do
  47 + user = fast_create(User, :environment_id => environment.id)
  48 + auth.info.stubs(:email).returns(user.email)
  49 + auth.info.stubs(:name).returns(user.name)
  50 + session[:provider_id] = provider.id
  51 + user.oauth_user_providers.create(:user => user, :provider => provider, :enabled => false)
  52 +
  53 + get :callback
  54 + assert_redirected_to :controller => :account, :action => :login
  55 + assert_equal nil, session[:user]
  56 + end
  57 +
  58 + should 'save provider when an user login with it' do
  59 + user = fast_create(User, :environment_id => environment.id)
  60 + auth.info.stubs(:email).returns(user.email)
  61 + auth.info.stubs(:name).returns(user.name)
  62 + session[:provider_id] = provider.id
  63 +
  64 + get :callback
  65 + assert_equal [provider], user.oauth_providers
  66 + end
  67 +
  68 + should 'do not duplicate relations between an user and a provider when the same provider was used again in a login' do
  69 + user = fast_create(User, :environment_id => environment.id)
  70 + auth.info.stubs(:email).returns(user.email)
  71 + auth.info.stubs(:name).returns(user.name)
  72 + session[:provider_id] = provider.id
  73 +
  74 + get :callback
  75 + assert_no_difference 'user.oauth_user_providers.count' do
  76 + 3.times { get :callback }
  77 + end
  78 + end
  79 +
  80 +end
... ...
plugins/oauth_client/test/test_helper.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +require File.dirname(__FILE__) + '/../../../test/test_helper'
... ...
plugins/oauth_client/test/unit/environment_test.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class UserTest < ActiveSupport::TestCase
  4 +
  5 + should 'be able to add oauth providers in a environment' do
  6 + env = fast_create(Environment)
  7 + env.oauth_providers << OauthClientPlugin::Provider.new(:name => 'test', :strategy => 'test')
  8 + end
  9 +
  10 +end
... ...
plugins/oauth_client/test/unit/oauth_client_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,86 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class OauthClientPluginTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @plugin = OauthClientPlugin.new(self)
  7 + @params = {}
  8 + @plugin.stubs(:context).returns(self)
  9 + @environment = Environment.default
  10 + @session = {}
  11 + @request = mock
  12 + @provider = OauthClientPlugin::Provider.create!(:name => 'name', :strategy => 'strategy')
  13 + end
  14 +
  15 + attr_reader :params, :plugin, :environment, :session, :request, :provider
  16 +
  17 + should 'has extra contents for login' do
  18 + assert plugin.login_extra_contents
  19 + end
  20 +
  21 + should 'has no signup extra contents if no provider was enabled' do
  22 + assert_equal '', instance_eval(&plugin.signup_extra_contents)
  23 + end
  24 +
  25 + should 'has signup extra contents if oauth_data exists in session' do
  26 + session[:oauth_data] = {:oauth => 'test'}
  27 + expects(:render).with(:partial => 'account/oauth_signup').once
  28 + instance_eval(&plugin.signup_extra_contents)
  29 + end
  30 +
  31 + should 'define before filter for account controller' do
  32 + assert plugin.account_controller_filters
  33 + end
  34 +
  35 + should 'raise error if oauth email was changed' do
  36 + request.expects(:post?).returns(true)
  37 +
  38 + oauth_data = mock
  39 + info = mock
  40 + oauth_data.stubs(:info).returns(info)
  41 + oauth_data.stubs(:uid).returns('uid')
  42 + oauth_data.stubs(:provider).returns('provider')
  43 + info.stubs(:email).returns('test@example.com')
  44 + session[:oauth_data] = oauth_data
  45 + session[:provider_id] = provider.id
  46 +
  47 + params[:user] = {:email => 'test2@example.com'}
  48 + assert_raises RuntimeError do
  49 + instance_eval(&plugin.account_controller_filters[:block])
  50 + end
  51 + end
  52 +
  53 + should 'do not raise error if oauth email was not changed' do
  54 + request.expects(:post?).returns(true)
  55 +
  56 + oauth_data = mock
  57 + info = mock
  58 + oauth_data.stubs(:info).returns(info)
  59 + oauth_data.stubs(:uid).returns('uid')
  60 + oauth_data.stubs(:provider).returns('provider')
  61 + info.stubs(:email).returns('test@example.com')
  62 + session[:oauth_data] = oauth_data
  63 + session[:provider_id] = provider.id
  64 +
  65 + params[:user] = {:email => 'test@example.com'}
  66 + instance_eval(&plugin.account_controller_filters[:block])
  67 + end
  68 +
  69 + should 'do not raise error if oauth session is not set' do
  70 + instance_eval(&plugin.account_controller_filters[:block])
  71 + end
  72 +
  73 + should 'do not raise error if it is not a post' do
  74 + request.expects(:post?).returns(false)
  75 + params[:user] = {:email => 'test2@example.com'}
  76 +
  77 + oauth_data = mock
  78 + oauth_data.stubs(:uid).returns('uid')
  79 + oauth_data.stubs(:provider).returns('provider')
  80 + session[:provider_id] = provider.id
  81 +
  82 + session[:oauth_data] = oauth_data
  83 + instance_eval(&plugin.account_controller_filters[:block])
  84 + end
  85 +
  86 +end
... ...
plugins/oauth_client/test/unit/user_test.rb 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class UserTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @provider = OauthClientPlugin::Provider.create!(:name => 'name', :strategy => 'strategy')
  7 + end
  8 + attr_reader :provider
  9 +
  10 + should 'password is not required if there is a oauth provider' do
  11 + User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :oauth_providers => [provider])
  12 + end
  13 +
  14 + should 'password is required if there is a oauth provider' do
  15 + user = User.new(:email => 'testoauth@example.com', :login => 'testoauth')
  16 + user.save
  17 + assert user.errors[:password].present?
  18 + end
  19 +
  20 + should 'activate user when created with oauth' do
  21 + user = User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :oauth_providers => [provider])
  22 + assert user.activated?
  23 + end
  24 +
  25 + should 'not activate user when created without oauth' do
  26 + user = fast_create(User)
  27 + assert !user.activated?
  28 + end
  29 +
  30 + should 'not make activation code when created with oauth' do
  31 + user = User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :oauth_providers => [provider])
  32 + assert !user.activation_code
  33 + end
  34 +
  35 + should 'make activation code when created without oauth' do
  36 + user = User.create!(:email => 'testoauth@example.com', :login => 'testoauth', :password => 'test', :password_confirmation => 'test')
  37 + assert user.activation_code
  38 + end
  39 +
  40 +end
... ...
plugins/oauth_client/views/account/_oauth_signup.html.erb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<%= hidden_field_tag 'return_to', '/' %>
  2 +
  3 +<style>
  4 + #signup-password, #signup-password-confirmation, #signup-email {
  5 + display: none;
  6 + }
  7 +</style>
  8 +
  9 +<div id='signup-email-readonly'>
  10 + <%= labelled_form_field(_('Email'), text_field(:user, :email, :class => "disabled", :readonly => true)) %>
  11 +</div>
... ...
plugins/oauth_client/views/auth/_oauth_login.html.erb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<div class="oauth-login">
  2 + <% unless providers.empty? %>
  3 + <%= _('Login with:') %>
  4 + <% end %>
  5 + <% providers.each do |provider| %>
  6 + <span class="provider">
  7 + <%= link_to provider.image ? image_tag(provider.image.public_filename) : provider.name, "/plugin/oauth_client/#{provider.strategy}?id=#{provider.id}", :class => provider.strategy, :title => provider.name %>
  8 + </span>
  9 + <% end %>
  10 +
  11 + <span class="provider">
  12 + <% unless Rails.env.production? %>
  13 + <%= link_to _('Developer Login'), "/plugin/oauth_client/developer", :class => 'developer' %>
  14 + <% end %>
  15 + </span>
  16 +</div>
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/_noosfero_oauth2.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<%= f.fields_for :client_options, OpenStruct.new(provider.options[:client_options]) do |c| %>
  2 + <div class="client-url">
  3 + <%= labelled_form_field _('Client Url'), c.text_field(:site) %>
  4 + </div>
  5 +<% end %>
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/edit.html.erb 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 +<h1><%= _('Oauth Client Settings') %></h1>
  2 +<h3><%= _('Edit Provider') %></h3>
  3 +
  4 +<%= form_for @provider, :url => {:action => 'edit'}, :method => 'post' do |f| %>
  5 +
  6 + <div class="enabled">
  7 + <%= labelled_form_field f.check_box(:enabled) + _('Enabled'), '' %>
  8 + </div>
  9 +
  10 + <div class="name">
  11 + <%= labelled_form_field _('Name'), f.text_field(:name) %>
  12 + </div>
  13 +
  14 + <div class="strategy">
  15 + <%= labelled_form_field _('Strategy'), f.select(:strategy, OauthClientPlugin::PROVIDERS) %>
  16 + </div>
  17 +
  18 + <div class="client-id">
  19 + <%= labelled_form_field _('Client Id'), f.text_field(:client_id) %>
  20 + </div>
  21 +
  22 + <div class="client-secret">
  23 + <%= labelled_form_field _('Client Secret'), f.text_field(:client_secret) %>
  24 + </div>
  25 +
  26 + <% if File.exists?(File.join(File.dirname(__FILE__), "_#{@provider.strategy}.html.erb")) %>
  27 + <%= render :partial => "#{@provider.strategy}", :locals => {:f => f, :provider => @provider} %>
  28 + <% end %>
  29 +
  30 + <div class="image-icon">
  31 + <%= f.fields_for :image_builder, @provider.image do |i| %>
  32 + <%= file_field_or_thumbnail(_('Image:'), @provider.image, i) %><%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %>
  33 + <% end %>
  34 + </div>
  35 +
  36 + <% button_bar do %>
  37 + <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %>
  38 + <% end %>
  39 +<% end %>
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/index.html.erb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +<h1><%= _('Oauth Client Settings') %></h1>
  2 +<h3><%= _('Providers') %></h3>
  3 +<%= button :add, _('New'), {:action => 'new'} %>
  4 +<table>
  5 + <tr>
  6 + <th><%= _('Name') %></th>
  7 + <th><%= _('Strategy') %></th>
  8 + <th><%= _('Actions') %></th>
  9 + </tr>
  10 +
  11 + <% environment.oauth_providers.each do |provider| %>
  12 + <tr>
  13 + <td><%= provider.name %></td>
  14 + <td><%= provider.strategy %></td>
  15 + <td>
  16 + <%= link_to _('Edit'), {:action => 'edit', :id => provider.id} %>
  17 + <%= link_to _('Remove'), {:action => 'remove', :id => provider.id} %>
  18 + </td>
  19 + </tr>
  20 + <% end %>
  21 +</table>
  22 +<div class="actions">
  23 + <%= button(:back, _('Go back'), {:controller => 'plugins', :action => 'index'}) %>
  24 +</div>
... ...
plugins/oauth_provider/Gemfile 0 → 100644
... ... @@ -0,0 +1 @@
  1 +gem 'doorkeeper', '~> 1.4.0'
... ...
plugins/oauth_provider/README.md 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +README - Oauth Provider Plugin
  2 +================================
  3 +
  4 +OauthProvider is a plugin which allow noosfero to be used as an oauth provider
  5 +
  6 +Install
  7 +=======
  8 +
  9 +Enable Plugin
  10 +-------------
  11 +
  12 +cd <your_noosfero_dir>
  13 +./script/noosfero-plugins enable oauth_provider
  14 +
  15 +Active Plugin
  16 +-------------
  17 +
  18 +As a Noosfero administrator user, go to administrator panel:
  19 +
  20 +- Click on "Enable/disable plugins" option
  21 +- Click on "Oauth Provider Plugin" check-box
  22 +
  23 +Varnish Settings
  24 +================
  25 +If varnish has been used in your stack, you've to prevent cookies to be removed when calling authorization actions for oauth_provider. E.g.:
  26 +
  27 +```
  28 +if (req.url !~ "^/plugin/oauth_provider/*" && req.http.cookie !~ "_noosfero_.*") {
  29 + unset req.http.cookie;
  30 + return(lookup);
  31 +}
  32 +```
  33 +
  34 +Development
  35 +===========
  36 +
  37 +Running OauthProvider tests
  38 +--------------------
  39 +
  40 +$ rake test:noosfero_plugins:oauth_provider
  41 +
  42 +License
  43 +=======
  44 +
  45 +Copyright (c) The Author developers.
  46 +
  47 +See Noosfero license.
... ...