Commit 11dfb86bf56dd6ce8784ab13682b46a96f9efc2f
Exists in
master
and in
29 other branches
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 < 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
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 |
... | ... | @@ -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 < 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 < 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 < 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 < 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 < 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 < 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 < 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/forum.rb
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 < 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 < 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 < 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 < 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 < 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 < 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 < 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
app/views/box_organizer/add_block.html.erb
app/views/box_organizer/edit.html.erb
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
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
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> | ... | ... |
... | ... | @@ -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
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
config/schedule.rb
db/schema.rb
... | ... | @@ -733,6 +733,7 @@ ActiveRecord::Schema.define(:version => 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
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
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
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 < 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
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 | ... | ... |
... | ... | @@ -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 | ||
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 | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -0,0 +1 @@ |
1 | +require File.dirname(__FILE__) + '/../../../test/test_helper' | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -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> | ... | ... |
... | ... | @@ -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
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> | ... | ... |
... | ... | @@ -0,0 +1 @@ |
1 | +gem 'doorkeeper', '~> 1.4.0' | ... | ... |
... | ... | @@ -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. | ... | ... |