Commit ea468c0ec1b11947fb88092e9b92659bbb0dd956

Authored by Victor Costa
2 parents 135c10f9 a1f85f37

Merge branch 'block-admin-mail' into production

Conflicts:
	app/models/event.rb
	app/models/profile.rb
	po/fr/noosfero.po
Showing 73 changed files with 616 additions and 428 deletions   Show diff stats
.gitlab-ci.yml 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +before_script:
  2 + - mkdir -p tmp/pids log
  3 + - bundle check || bundle install
  4 + - script/noosfero-plugins disableall
  5 + - rm -f tmp/makemo.stamp && rake makemo &>/dev/null
  6 +# database
  7 + - cp config/database.yml.gitlab-ci config/database.yml
  8 + - createdb gitlab_ci_test || true
  9 + - bundle exec rake db:schema:load &>/dev/null
  10 + - bundle exec rake db:migrate &>/dev/null
  11 +
  12 +units:
  13 + script: bundle exec rake test:units
  14 +functionals:
  15 + script: bundle exec rake test:functionals
  16 +integration:
  17 + script: bundle exec rake test:integration
  18 +cucumber:
  19 + script: bundle exec rake cucumber
  20 +selenium:
  21 + script: bundle exec rake selenium
  22 +plugins:
  23 + script: bundle exec rake test:noosfero_plugins
  24 +
... ...
.travis.yml 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +language: ruby
  2 +rvm:
  3 +# for 2.2 support we need to upgrade the pg gem
  4 + - 2.1.6
  5 +
  6 +before_install:
  7 +# dependencies
  8 + - sudo apt-get update
  9 + - sudo apt-get -y install po4a iso-codes tango-icon-theme pidgin-data default-jre
  10 + - sudo apt-get -y install libmagickwand-dev libpq-dev libreadline-dev libsqlite3-dev libxslt1-dev
  11 +# selenium support
  12 + - export DISPLAY=:99.0
  13 + - sh -e /etc/init.d/xvfb start
  14 +
  15 +before_script:
  16 + - mkdir -p tmp/pids log
  17 + - bundle check || bundle install
  18 + - script/noosfero-plugins disableall
  19 + - rake makemo
  20 +# database
  21 + - cp config/database.yml.travis config/database.yml
  22 + - psql -c 'create database myapp_test;' -U postgres
  23 + - bundle exec rake db:schema:load
  24 + - bundle exec rake db:migrate
  25 +
  26 +env:
  27 + - TASK=test:units
  28 + - TASK=test:functionals
  29 + - TASK=test:integration
  30 + - TASK=cucumber
  31 + - TASK=selenium
  32 + - TASK=test:noosfero_plugins
  33 +
  34 +script:
  35 + - bundle exec rake $TASK
  36 +
... ...
Gemfile
1 1 source "https://rubygems.org"
2   -gem 'rails', '~> 3.2.21'
  2 +gem 'rails', '~> 3.2.22'
3 3 gem 'minitest', '~> 3.2.0'
4 4 gem 'fast_gettext', '~> 0.6.8'
5 5 gem 'acts-as-taggable-on', '~> 3.4.2'
... ... @@ -40,6 +40,7 @@ group :test do
40 40 gem 'rspec', '~> 2.14.0'
41 41 gem 'rspec-rails', '~> 2.14.1'
42 42 gem 'mocha', '~> 1.1.0', :require => false
  43 + gem 'test-unit' if RUBY_VERSION >= '2.2.0'
43 44 end
44 45  
45 46 group :cucumber do
... ...
app/controllers/application_controller.rb
... ... @@ -77,8 +77,8 @@ class ApplicationController < ActionController::Base
77 77 FastGettext.available_locales = environment.available_locales
78 78 FastGettext.default_locale = environment.default_locale
79 79 FastGettext.locale = (params[:lang] || session[:lang] || environment.default_locale || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en')
80   - I18n.locale = FastGettext.locale
81   - I18n.default_locale = FastGettext.default_locale
  80 + I18n.locale = FastGettext.locale.to_s.gsub '_', '-'
  81 + I18n.default_locale = FastGettext.default_locale.to_s.gsub '_', '-'
82 82 if params[:lang]
83 83 session[:lang] = params[:lang]
84 84 end
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -6,7 +6,7 @@ class CmsController < MyProfileController
6 6  
7 7 def search_tags
8 8 arg = params[:term].downcase
9   - result = ActsAsTaggableOn::Tag.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"])
  9 + result = ActsAsTaggableOn::Tag.where('name ILIKE ?', "%#{arg}%").limit(10)
10 10 render :text => prepare_to_token_input_by_label(result).to_json, :content_type => 'application/json'
11 11 end
12 12  
... ... @@ -94,6 +94,11 @@ class CmsController < MyProfileController
94 94 record_coming
95 95 if request.post?
96 96 @article.image = nil if params[:remove_image] == 'true'
  97 + if @article.image.present? && params[:article][:image_builder] &&
  98 + params[:article][:image_builder][:label]
  99 + @article.image.label = params[:article][:image_builder][:label]
  100 + @article.image.save!
  101 + end
97 102 @article.last_changed_by = user
98 103 if @article.update_attributes(params[:article])
99 104 if !continue
... ...
app/helpers/application_helper.rb
... ... @@ -1185,7 +1185,7 @@ module ApplicationHelper
1185 1185 pending_tasks_count = link_to("<i class=\"icon-menu-tasks\"></i><span class=\"task-count\">#{count}</span>", user.tasks_url, :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
1186 1186 end
1187 1187  
1188   - (_("<span class='welcome'>Welcome,</span> %s") % link_to("<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>", user.public_profile_url, :id => "homepage-link", :title => _('Go to your homepage'))) +
  1188 + (_("<span class='welcome'>Welcome,</span> %s") % link_to("<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>", user.url, :id => "homepage-link", :title => _('Go to your homepage'))) +
1189 1189 render_environment_features(:usermenu) +
1190 1190 admin_link +
1191 1191 manage_enterprises +
... ... @@ -1234,7 +1234,7 @@ module ApplicationHelper
1234 1234  
1235 1235 def task_information(task)
1236 1236 values = {}
1237   - values.merge!({:requestor => link_to(task.requestor.name, task.requestor.public_profile_url)}) if task.requestor
  1237 + values.merge!({:requestor => link_to(task.requestor.name, task.requestor.url)}) if task.requestor
1238 1238 values.merge!({:subject => content_tag('span', task.subject, :class=>'task_target')}) if task.subject
1239 1239 values.merge!({:linked_subject => link_to(content_tag('span', task.linked_subject[:text], :class => 'task_target'), task.linked_subject[:url])}) if task.linked_subject
1240 1240 values.merge!(task.information[:variables]) if task.information[:variables]
... ...
app/helpers/comment_helper.rb
... ... @@ -16,7 +16,7 @@ module CommentHelper
16 16 content_tag('span', show_date(article.published_at), :class => 'date') +
17 17 content_tag('span', [_(", by %s") % link_to(article.author_name, article.author_url)], :class => 'author') +
18 18 content_tag('span', comments, :class => 'comments'),
19   - :class => 'created-at'
  19 + :class => 'publishing-info'
20 20 )
21 21 end
22 22 title
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -30,7 +30,7 @@ module ContentViewerHelper
30 30 date_format +
31 31 content_tag('span', _(", by %s") % (article.author ? link_to(article.author_name, article.author_url) : article.author_name), :class => 'author') +
32 32 content_tag('span', comments, :class => 'comments'),
33   - :class => 'created-at'
  33 + :class => 'publishing-info'
34 34 )
35 35 end
36 36 title
... ...
app/models/article.rb
... ... @@ -145,7 +145,7 @@ class Article &lt; ActiveRecord::Base
145 145  
146 146 scope :by_range, lambda { |range| {
147 147 :conditions => [
148   - 'published_at BETWEEN :start_date AND :end_date', { :start_date => range.first, :end_date => range.last }
  148 + 'articles.published_at BETWEEN :start_date AND :end_date', { :start_date => range.first, :end_date => range.last }
149 149 ]
150 150 }}
151 151  
... ... @@ -748,8 +748,9 @@ class Article &lt; ActiveRecord::Base
748 748 paragraphs.empty? ? '' : paragraphs.first.to_html
749 749 end
750 750  
751   - def lead
752   - abstract.blank? ? first_paragraph.html_safe : abstract.html_safe
  751 + def lead(length = nil)
  752 + content = abstract.blank? ? first_paragraph.html_safe : abstract.html_safe
  753 + length.present? ? content.truncate(length) : content
753 754 end
754 755  
755 756 def short_lead
... ...
app/models/event.rb
... ... @@ -99,47 +99,19 @@ class Event &lt; Article
99 99 start_date..(end_date||start_date)
100 100 end
101 101  
102   - # FIXME this shouldn't be needed
103   - include ActionView::Helpers::TagHelper
104   - include ActionView::Helpers::UrlHelper
105   - include DatesHelper
  102 + def first_paragraph
  103 + paragraphs = Nokogiri::HTML.fragment(self.body).css('p')
  104 + paragraphs.empty? ? '' : paragraphs.first.to_html
  105 + end
106 106  
107 107 def to_html(options = {})
  108 + event = self
  109 + format = options[:format]
108 110  
109   - result = ''
110   - html = ::Builder::XmlMarkup.new(:target => result)
111   -
112   - html.div(:class => 'event-info' ) {
113   - html.ul(:class => 'event-data' ) {
114   - html.li(:class => 'event-dates' ) {
115   - html.span _('When:')
116   - html.text! show_period(start_date, end_date)
117   - } if start_date.present? || end_date.present?
118   - html.li {
119   - html.span _('URL:')
120   - html.a(self.link || "", 'href' => self.link || "")
121   - } if self.link.present?
122   - html.li {
123   - html.span _('Address:')
124   - html.text! self.address || ""
125   - } if self.address.present?
126   - }
127   -
128   - # TODO: some good soul, please clean this ugly hack:
129   - if self.body
130   - html.div('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', :class => 'event-description')
131   - end
132   - }
133   -
134   - if self.body
135   - #if options[:format] == 'short'
136   - # result.sub!('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', display_short_format(self))
137   - #else
138   - result.sub!('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', self.body)
139   - #end
  111 + proc do
  112 + render :file => 'content_viewer/event_page', :locals => { :event => event,
  113 + :format => format }
140 114 end
141   -
142   - result
143 115 end
144 116  
145 117 def duration
... ...
app/models/image.rb
... ... @@ -23,7 +23,7 @@ class Image &lt; ActiveRecord::Base
23 23  
24 24 postgresql_attachment_fu
25 25  
26   - attr_accessible :uploaded_data
  26 + attr_accessible :uploaded_data, :label
27 27  
28 28 def current_data
29 29 File.file?(full_filename) ? File.read(full_filename) : nil
... ...
app/models/organization.rb
... ... @@ -154,6 +154,12 @@ class Organization &lt; Profile
154 154 ]
155 155 end
156 156  
  157 + def short_name chars = 40
  158 + s = self.display_name
  159 + s = super(chars) if s.blank?
  160 + s
  161 + end
  162 +
157 163 def notification_emails
158 164 emails = [contact_email].select(&:present?) + admins.map(&:email)
159 165 if emails.empty?
... ...
app/models/profile.rb
... ... @@ -3,7 +3,7 @@
3 3 # which by default is the one returned by Environment:default.
4 4 class Profile < ActiveRecord::Base
5 5  
6   - attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, :redirection_after_login, :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :custom_fields
  6 + attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, :redirection_after_login, :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :custom_fields, :administrator_mail_notification
7 7  
8 8 # use for internationalizable human type names in search facets
9 9 # reimplement on subclasses
... ... @@ -219,6 +219,7 @@ class Profile &lt; ActiveRecord::Base
219 219 settings_items :description
220 220 settings_items :fields_privacy, :type => :hash, :default => {}
221 221 settings_items :email_suggestions, :type => :boolean, :default => false
  222 + settings_items :administrator_mail_notification, :type => :boolean, :default => true
222 223  
223 224 validates_length_of :description, :maximum => 550, :allow_nil => true
224 225  
... ...
app/models/task.rb
... ... @@ -70,7 +70,9 @@ class Task &lt; ActiveRecord::Base
70 70 begin
71 71 target_msg = task.target_notification_message
72 72 if target_msg && task.target && !task.target.notification_emails.empty?
73   - TaskMailer.target_notification(task, target_msg).deliver
  73 + if target_profile_accepts_notification?(task)
  74 + TaskMailer.target_notification(task, target_msg).deliver
  75 + end
74 76 end
75 77 rescue Exception => ex
76 78 Rails.logger.info ex.to_s
... ... @@ -78,6 +80,18 @@ class Task &lt; ActiveRecord::Base
78 80 end
79 81 end
80 82  
  83 + def target_profile_accepts_notification?(task)
  84 + if target_is_profile?(task)
  85 + return task.target.administrator_mail_notification
  86 + else
  87 + true
  88 + end
  89 + end
  90 +
  91 + def target_is_profile?(task)
  92 + task.target.kind_of? Profile
  93 + end
  94 +
81 95 # this method finished the task. It calls #perform, which must be overriden
82 96 # by subclasses. At the end a message (as returned by #finish_message) is
83 97 # sent to the requestor with #notify_requestor.
... ...
app/models/user.rb
... ... @@ -334,6 +334,8 @@ class User &lt; ActiveRecord::Base
334 334  
335 335 {
336 336 'login' => self.login,
  337 + 'name' => self.person.name,
  338 + 'email' => self.email,
337 339 'avatar' => self.person.profile_custom_icon(gravatar_default),
338 340 'is_admin' => self.person.is_admin?,
339 341 'since_month' => self.person.created_at.month,
... ...
app/views/content_viewer/_article_title.html.erb 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +<% if @page.belongs_to_blog? || @page.belongs_to_forum?%>
  2 + <h1 class="title">
  3 + <% if no_link %>
  4 + <%= h(@page.title) %>
  5 + <% else %>
  6 + <%= link_to(@page.name, @page.url) %>
  7 + <% end %>
  8 + </h1>
  9 + <%= render :partial => "publishing_info" %>
  10 + <% unless @page.abstract.blank? %>
  11 + <div class="preview">
  12 + <%= @page.lead %>
  13 + </div>
  14 + <% end %>
  15 +<% else %>
  16 + <h1 class="title">
  17 + <%= h(@page.title) %>
  18 + </h1>
  19 + <%= render :partial => "publishing_info" %>
  20 +<% end %>
... ...
app/views/content_viewer/_article_toolbar.html.erb
... ... @@ -64,7 +64,7 @@
64 64 <% end %>
65 65 <%= link_to(image_tag('/images/icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %>
66 66 <%= @plugins.dispatch(:article_header_extra_contents, @page).collect { |content| instance_exec(&content) }.join("") %>
67   - <%= article_title(@page, :no_link => true) %>
  67 + <%= render :partial => 'article_title', :locals => {:no_link => true} %>
68 68 <%= article_translations(@page) %>
69 69 </div>
70 70 </div>
... ...
app/views/content_viewer/_display_compact_format.html.erb
... ... @@ -16,6 +16,6 @@
16 16 </div>
17 17 <% end %>
18 18 <div class = <%= className %> >
19   - <%= article.abstract.truncate(400) %>
  19 + <%= article.lead(400) %>
20 20 </div>
21 21 </div>
... ...
app/views/content_viewer/_publishing_info.html.erb 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +<span class="publishing-info">
  2 + <span class="date">
  3 + <%= show_date(@page.published_at) %>
  4 + </span>
  5 + <span class="author">
  6 + <%= _(", by %s") % (@page.author ? link_to(@page.author_name, @page.author_url) : @page.author_name) %>
  7 + </span>
  8 +<% unless @no_comments %>
  9 + <span class="comments">
  10 + <%= (" - %s") % link_to_comments(@page)%>
  11 + </span>
  12 +<% end %>
  13 +</span>
  14 +
  15 +<% if @page.display_hits? || @page.license.present? %>
  16 + <div id='article-sub-header'>
  17 + <% if @page.display_hits? %>
  18 + <div id="article-hits">
  19 + <%= n_('Viewed one time', 'Viewed %{num} times', @page.hits) % { :num => @page.hits } %>
  20 + </div>
  21 + <% end %>
  22 +
  23 + <% if @page.license.present? %>
  24 + <div id="article-license">
  25 + <%= _('Licensed under %s') % (@page.license.url.present? ? link_to(@page.license.name, @page.license.url, :target => '_blank') : @page.license.name) %>
  26 + </div>
  27 + <% end %>
  28 + </div>
  29 +<% end %>
... ...
app/views/content_viewer/event_page.html.erb 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +<div class="event-card">
  2 + <div class="event-image">
  3 + <% if event.image %>
  4 + <%= image_tag(event.image.public_filename(:big)) %>
  5 + <% end %>
  6 + </div>
  7 + <div class="about-event">
  8 + <% if event.start_date.present? || event.end_date.present? %>
  9 + <span class="event-date">
  10 + <%= show_period(event.start_date, event.end_date) %>
  11 + </span>
  12 + <% end %>
  13 + <% if event.link.present? %>
  14 + <span class="event-link">
  15 + <%= link_to event.link, event.link %>
  16 + </span>
  17 + <% end %>
  18 + <% if event.address.present? %>
  19 + <span class="event-address">
  20 + <span>
  21 + <%= event.address %>
  22 + </span>
  23 + </span>
  24 + <% end %>
  25 + </div>
  26 +</div>
  27 +
  28 +<div class="event-body">
  29 + <% if format == 'short' %>
  30 + <%= display_short_format event, :comments_link => false, :read_more_link => false %>
  31 + <% else %>
  32 + <% unless event.abstract.blank? %>
  33 + <div class="event-lead">
  34 + <%= event.article_lead %>
  35 + </div>
  36 + <% end %>
  37 + <div class="event-content">
  38 + <%= event.body %>
  39 + </div>
  40 + <% end %>
  41 +</div>
... ...
app/views/content_viewer/view_page.html.erb
... ... @@ -24,22 +24,6 @@
24 24 <%= render :partial => 'article_toolbar' %>
25 25 </div>
26 26  
27   -<% if @page.display_hits? || @page.license.present? %>
28   - <div id='article-sub-header'>
29   - <% if @page.display_hits? %>
30   - <div id="article-hits">
31   - <%= n_('Viewed one time', 'Viewed %{num} times', @page.hits) % { :num => @page.hits } %>
32   - </div>
33   - <% end %>
34   -
35   - <% if @page.license.present? %>
36   - <div id="article-license">
37   - <%= _('Licensed under %s') % (@page.license.url.present? ? link_to(@page.license.name, @page.license.url, :target => '_blank') : @page.license.name) %>
38   - </div>
39   - <% end %>
40   - </div>
41   -<% end %>
42   -
43 27 <% if NOOSFERO_CONF['addthis_enabled'] %>
44 28 <%= render :partial => 'addthis' %>
45 29 <% end %>
... ... @@ -47,6 +31,12 @@
47 31 <% cache(@page.cache_key(params, user, language)) do %>
48 32 <div class="<%="article-body article-body-" + @page.css_class_name %>">
49 33 <% options = @page.image? ? {:gallery_view => true} : {} %>
  34 + <% if @page.image.present? && !@page.event? %>
  35 + <div class="article-body-img">
  36 + <%= image_tag(@page.image.public_filename) %>
  37 + <p><%= @page.image.label%></p>
  38 + </div>
  39 + <% end %>
50 40 <%= article_to_html(@page, options) %>
51 41 <br style="clear:both" />
52 42 </div> <!-- end class="article-body" -->
... ...
app/views/layouts/application-ng.html.erb
... ... @@ -27,6 +27,7 @@
27 27  
28 28 <script type="text/javascript">
29 29 DEFAULT_LOADING_MESSAGE = <%="'#{ _('loading...') }'" %>;
  30 + noosfero.profile = <%= (@profile.identifier if @profile).to_json %>
30 31 </script>
31 32  
32 33 </head>
... ...
app/views/manage_products/_categories_autocomplete.html.erb
1 1 <%= text_field_tag 'product_category_id', '', :placeholder => _('type a category for the product') %>
2 2  
3 3 <%= javascript_include_tag '/javascripts/product_categories.js' %>
4   -<% javascript_tag do %>
  4 +<%= javascript_tag do %>
5 5 product_categories.autocomplete.search_url = <%= url_for(:controller => :manage_products, :action => :search_categories).to_json %>
6 6 product_categories.autocomplete.select_url = <%= url_for(:controller => :manage_products, :action => :show_category_tree).to_json %>
7 7 product_categories.autocomplete.load('#product_category_id')
... ...
app/views/profile_editor/_moderation.html.erb
1 1 <h2><%= _('Moderation options') %></h2>
2 2 <% if profile.community? %>
3 3 <div style='margin-bottom: 1em'>
  4 + <h4><%= _('Email Configuration:')%></h4>
  5 + </div>
  6 + <div style='margin-bottom: 0.5em'>
  7 + <%= check_box(:profile_data, :administrator_mail_notification, :style => 'float: left') %>
  8 + <div style='margin-left: 30px'>
  9 + <%= _('Send administrator Email for every task (Default: yes)') %>
  10 + </div>
  11 + </div>
  12 +
  13 + <div style='margin-bottom: 1em'>
4 14 <h4><%= _('Invitation moderation:')%></h4>
5 15 </div>
6 16 <div style='margin-bottom: 0.5em'>
... ...
app/views/shared/_change_image.html.erb
1   - <%= i.file_field( :uploaded_data, { :onchange => 'updateImg(this.value)' } ) %>
2   - <%= button_to_function(:cancel,_('Cancel'),"jQuery('#change-image-link').show(); jQuery('#change-image').html('')", :id => 'cancel-change-image-link', :style => 'display: none')%>
  1 +<%= i.file_field( :uploaded_data, { :onchange => 'updateImg(this.value)' } ) %>
  2 +<%= labelled_form_field(_("Image Label:"), i.text_field(:label)) %>
  3 +<%= button_to_function(:cancel,_('Cancel'),"jQuery('#change-image-link').show(); jQuery('#change-image').html('')", :id => 'cancel-change-image-link', :style => 'display: none')%>
... ...
config/database.yml.gitlab-ci 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +test: &TEST
  2 + adapter: postgresql
  3 + database: gitlab_ci_test
  4 + username: gitlab_ci_runner
  5 +development:
  6 + <<: *TEST
... ...
config/database.yml.travis 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +# From http://about.travis-ci.org/docs/user/database-setup/
  2 +test:
  3 + adapter: postgresql
  4 + database: myapp_test
  5 + username: postgres
... ...
config/environments/staging.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +# inherit from production
  2 +require_relative 'production'
  3 +
  4 +Noosfero::Application.configure do
  5 +
  6 + # expose errors
  7 + config.consider_all_requests_local = true
  8 +
  9 + # ease debug
  10 + config.assets.compress = false
  11 +
  12 +end
  13 +
... ...
config/locales/de.yml
... ... @@ -3,7 +3,7 @@
3 3 # contributors:
4 4 # - Alexander Dreher - http://github.com/alexdreher - Rails 3 update
5 5  
6   -de:
  6 +de: &de
7 7 date:
8 8 formats:
9 9 default: "%d.%m.%Y"
... ... @@ -221,3 +221,6 @@ de:
221 221  
222 222 full_messages:
223 223 format: "%{attribute} %{message}"
  224 +
  225 +de-DE:
  226 + <<: *de
... ...
config/locales/en-US.yml
... ... @@ -2,7 +2,7 @@
2 2 #
3 3 # Use this as the base for the locale file of your language.
4 4  
5   -"en-US":
  5 +"en-US": &en-US
6 6 date:
7 7 formats:
8 8 default: "%Y-%m-%d"
... ... @@ -220,4 +220,7 @@
220 220 template:
221 221 <<: *errors_template
222 222 full_messages:
223   - format: "%{attribute} %{message}"
224 223 \ No newline at end of file
  224 + format: "%{attribute} %{message}"
  225 +
  226 +en:
  227 + <<: *en-US
... ...
config/locales/en.yml 0 → 120000
... ... @@ -0,0 +1 @@
  1 +en-US.yml
0 2 \ No newline at end of file
... ...
config/locales/es.yml
... ... @@ -4,7 +4,7 @@
4 4 # - Tsutomu Kuroda - http://github.com/kuroda (t-kuroda@oiax.jp)
5 5 # Corrected by Eloy Serra Labán: http://goo.gl/i9Kts, /nQ928, /XfKaX
6 6  
7   -"es":
  7 +es: &es
8 8 date:
9 9 formats:
10 10 default: "%d/%m/%Y"
... ... @@ -223,3 +223,6 @@
223 223  
224 224 full_messages:
225 225 format: "%{attribute} %{message}"
  226 +
  227 +es_ES:
  228 + <<: *es
... ...
config/locales/fr-FR.yml 0 → 120000
... ... @@ -0,0 +1 @@
  1 +fr.yml
0 2 \ No newline at end of file
... ...
config/locales/fr.yml
... ... @@ -5,7 +5,7 @@
5 5 # - Bruno Michel - http://github.com/nono
6 6 # - Tsutomu Kuroda - http://github.com/kuroda (t-kuroda@oiax.jp)
7 7  
8   -fr:
  8 +fr: &fr
9 9 date:
10 10 formats:
11 11 default: "%d/%m/%Y"
... ... @@ -222,3 +222,7 @@ fr:
222 222 <<: *errors_template
223 223 full_messages:
224 224 format: "%{attribute} %{message}"
  225 +
  226 +fr-FR:
  227 + <<: *fr
  228 +
... ...
config/locales/hr.yml
... ... @@ -176,4 +176,4 @@
176 176 template:
177 177 <<: *errors_template
178 178 full_messages:
179   - format: "%{attribute} %{message}"
180 179 \ No newline at end of file
  180 + format: "%{attribute} %{message}"
... ...
config/locales/hy-AM.yml 0 → 120000
... ... @@ -0,0 +1 @@
  1 +hy.yml
0 2 \ No newline at end of file
... ...
config/locales/hy.yml
... ... @@ -3,7 +3,7 @@
3 3 # FIXME: This is a copy of en-US.yml. Armenian translators, please translate
4 4 # this into Armenian.
5 5  
6   -"hy":
  6 +hy: &hy
7 7 date:
8 8 formats:
9 9 default: "%Y-%m-%d"
... ... @@ -222,3 +222,6 @@
222 222 <<: *errors_template
223 223 full_messages:
224 224 format: "%{attribute} %{message}"
  225 +
  226 +hy-AM:
  227 + <<: *hy
... ...
config/locales/it.yml
... ... @@ -5,7 +5,7 @@
5 5 # - Simone Carletti (weppos@weppos.net)
6 6 # - Davide Guerri (d.guerri@caspur.it)
7 7  
8   -it:
  8 +it: &it
9 9 number:
10 10 format:
11 11 delimiter: ","
... ... @@ -234,3 +234,6 @@ it:
234 234  
235 235 full_messages:
236 236 format: "%{attribute} %{message}"
  237 +
  238 +it_IT:
  239 + <<: *it
... ...
config/locales/pt-BR.yml
1 1 # encoding: UTF-8
2 2 # pt-BR translations for Ruby on Rails
3   -"pt-BR":
  3 +
  4 +"pt-BR": &pt-BR
4 5 # formatos de data e hora
5 6 date:
6 7 formats:
... ... @@ -231,3 +232,6 @@
231 232  
232 233 full_messages:
233 234 format: "%{attribute} %{message}"
  235 +
  236 +pt:
  237 + <<: *pt-BR
... ...
config/locales/pt.yml
... ... @@ -1,233 +0,0 @@
1   -# encoding: UTF-8
2   -# pt-BR translations for Ruby on Rails
3   -"pt":
4   - # formatos de data e hora
5   - date:
6   - formats:
7   - default: "%d/%m/%Y"
8   - short: "%d de %B"
9   - long: "%d de %B de %Y"
10   -
11   - day_names:
12   - - Domingo
13   - - Segunda
14   - - Terça
15   - - Quarta
16   - - Quinta
17   - - Sexta
18   - - Sábado
19   - abbr_day_names:
20   - - Dom
21   - - Seg
22   - - Ter
23   - - Qua
24   - - Qui
25   - - Sex
26   - - Sáb
27   -
28   - month_names:
29   - - ~
30   - - Janeiro
31   - - Fevereiro
32   - - Março
33   - - Abril
34   - - Maio
35   - - Junho
36   - - Julho
37   - - Agosto
38   - - Setembro
39   - - Outubro
40   - - Novembro
41   - - Dezembro
42   - abbr_month_names:
43   - - ~
44   - - Jan
45   - - Fev
46   - - Mar
47   - - Abr
48   - - Mai
49   - - Jun
50   - - Jul
51   - - Ago
52   - - Set
53   - - Out
54   - - Nov
55   - - Dez
56   - order:
57   - - :day
58   - - :month
59   - - :year
60   -
61   - time:
62   - formats:
63   - default: "%A, %d de %B de %Y, %H:%M h"
64   - short: "%d/%m, %H:%M h"
65   - long: "%A, %d de %B de %Y, %H:%M h"
66   - am: ''
67   - pm: ''
68   -
69   - # Usado no Array.to_sentence
70   - support:
71   - array:
72   - words_connector: ", "
73   - two_words_connector: " e "
74   - last_word_connector: " e "
75   -
76   - select:
77   - prompt: "Por favor selecione"
78   -
79   - number:
80   - format:
81   - separator: ','
82   - delimiter: '.'
83   - precision: 3
84   - significant: false
85   - strip_insignificant_zeros: false
86   -
87   - currency:
88   - format:
89   - format: '%u %n'
90   - unit: 'R$'
91   - separator: ','
92   - delimiter: '.'
93   - precision: 2
94   - significant: false
95   - strip_insignificant_zeros: false
96   -
97   - percentage:
98   - format:
99   - delimiter: '.'
100   -
101   - precision:
102   - format:
103   - delimiter: '.'
104   -
105   - human:
106   - format:
107   - delimiter: '.'
108   - precision: 2
109   - significant: true
110   - strip_insignificant_zeros: true
111   - storage_units:
112   - format: "%n %u"
113   - units:
114   - byte:
115   - one: "Byte"
116   - other: "Bytes"
117   - kb: "KB"
118   - mb: "MB"
119   - gb: "GB"
120   - tb: "TB"
121   - # number_to_human()
122   - # new in rails 3: please add to other locales
123   - decimal_units:
124   - format: "%n %u"
125   - units:
126   - unit: ""
127   - thousand: "mil"
128   - million:
129   - one: milhão
130   - other: milhões
131   - billion:
132   - one: bilhão
133   - other: bilhões
134   - trillion:
135   - one: trilhão
136   - other: trilhões
137   - quadrillion:
138   - one: quatrilhão
139   - other: quatrilhões
140   -
141   - # distancia do tempo em palavras
142   - datetime:
143   - distance_in_words:
144   - half_a_minute: 'meio minuto'
145   - less_than_x_seconds:
146   - one: 'menos de 1 segundo'
147   - other: 'menos de %{count} segundos'
148   - x_seconds:
149   - one: '1 segundo'
150   - other: '%{count} segundos'
151   - less_than_x_minutes:
152   - one: 'menos de um minuto'
153   - other: 'menos de %{count} minutos'
154   - x_minutes:
155   - one: '1 minuto'
156   - other: '%{count} minutos'
157   - about_x_hours:
158   - one: 'aproximadamente 1 hora'
159   - other: 'aproximadamente %{count} horas'
160   - x_days:
161   - one: '1 dia'
162   - other: '%{count} dias'
163   - about_x_months:
164   - one: 'aproximadamente 1 mês'
165   - other: 'aproximadamente %{count} meses'
166   - x_months:
167   - one: '1 mês'
168   - other: '%{count} meses'
169   - about_x_years:
170   - one: 'aproximadamente 1 ano'
171   - other: 'aproximadamente %{count} anos'
172   - over_x_years:
173   - one: 'mais de 1 ano'
174   - other: 'mais de %{count} anos'
175   - almost_x_years:
176   - one: 'quase 1 ano'
177   - other: 'quase %{count} anos'
178   - prompts:
179   - year: "Ano"
180   - month: "Mês"
181   - day: "Dia"
182   - hour: "Hora"
183   - minute: "Minuto"
184   - second: "Segundo"
185   -
186   - helpers:
187   - select:
188   - prompt: "Por favor selecione"
189   -
190   - submit:
191   - create: 'Criar %{model}'
192   - update: 'Atualizar %{model}'
193   - submit: 'Salvar %{model}'
194   -
195   - errors:
196   - format: "%{attribute} %{message}"
197   - messages: &errors_messages
198   - inclusion: "não está incluído na lista"
199   - exclusion: "não está disponível"
200   - invalid: "não é válido"
201   - confirmation: "não está de acordo com a confirmação"
202   - accepted: "deve ser aceito"
203   - empty: "não pode ficar vazio"
204   - blank: "não pode ficar em branco"
205   - too_long: "é muito longo (máximo: %{count} caracteres)"
206   - too_short: "é muito curto (mínimo: %{count} caracteres)"
207   - wrong_length: "não possui o tamanho esperado (%{count} caracteres)"
208   - not_a_number: "não é um número"
209   - not_an_integer: "não é um número inteiro"
210   - greater_than: "deve ser maior que %{count}"
211   - greater_than_or_equal_to: "deve ser maior ou igual a %{count}"
212   - equal_to: "deve ser igual a %{count}"
213   - less_than: "deve ser menor que %{count}"
214   - less_than_or_equal_to: "deve ser menor ou igual a %{count}"
215   - odd: "deve ser ímpar"
216   - even: "deve ser par"
217   - taken: "já está em uso"
218   - record_invalid: "A validação falhou: %{errors}"
219   - template: &errors_template
220   - header:
221   - one: "Não foi possível gravar %{model}: 1 erro"
222   - other: "Não foi possível gravar %{model}: %{count} erros."
223   - body: "Por favor, verifique o(s) seguinte(s) campo(s):"
224   -
225   - activerecord:
226   - errors:
227   - messages:
228   - <<: *errors_messages
229   - template:
230   - <<: *errors_template
231   -
232   - full_messages:
233   - format: "%{attribute} %{message}"
config/locales/pt.yml 0 → 120000
... ... @@ -0,0 +1 @@
  1 +pt-BR.yml
0 2 \ No newline at end of file
... ...
config/locales/ru.yml
... ... @@ -10,7 +10,7 @@
10 10 # (http://github.com/yaroslav/russian). Следующие данные -- выдержка их него, чтобы
11 11 # была возможность минимальной локализации приложения на русский язык.
12 12  
13   -ru:
  13 +ru: &ru
14 14 date:
15 15 formats:
16 16 default: "%d.%m.%Y"
... ... @@ -300,3 +300,7 @@ ru:
300 300 words_connector: ", "
301 301 two_words_connector: " и "
302 302 last_word_connector: " и "
  303 +
  304 +ru_RU:
  305 + <<: *ru
  306 +
... ...
db/migrate/20150603182105_add_label_to_image.rb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +class AddLabelToImage < ActiveRecord::Migration
  2 + def up
  3 + add_column :images, :label, :string, :default => ""
  4 + end
  5 + def down
  6 + remove_column :images, :label
  7 + end
  8 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20150602142030) do
  14 +ActiveRecord::Schema.define(:version => 20150603182105) do
15 15  
16 16 create_table "abuse_reports", :force => true do |t|
17 17 t.integer "reporter_id"
... ... @@ -377,6 +377,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150602142030) do
377 377 t.integer "width"
378 378 t.integer "height"
379 379 t.boolean "thumbnails_processed", :default => false
  380 + t.string "label", :default => ""
380 381 end
381 382  
382 383 add_index "images", ["parent_id"], :name => "index_images_on_parent_id"
... ...
features/events.feature
... ... @@ -160,6 +160,7 @@ Feature: events
160 160 When I am on /search/events
161 161 Then I should see "Colivre.net's Events"
162 162  
  163 +
163 164 @selenium
164 165 Scenario: published events should be listed in the agenda too
165 166 Given the following community
... ...
plugins/custom_forms/po/fr/custom_forms.po
... ... @@ -7,8 +7,8 @@ msgstr &quot;&quot;
7 7 "Project-Id-Version: 1.1-166-gaf47713\n"
8 8 "Report-Msgid-Bugs-To: \n"
9 9 "POT-Creation-Date: 2015-06-01 17:26-0300\n"
10   -"PO-Revision-Date: 2015-02-23 11:38+0200\n"
11   -"Last-Translator: Michal Čihař <michal@cihar.com>\n"
  10 +"PO-Revision-Date: 2015-06-29 14:17+0200\n"
  11 +"Last-Translator: Christophe DANIEL <papaeng@gmail.com>\n"
12 12 "Language-Team: French <https://hosted.weblate.org/projects/noosfero/plugin-"
13 13 "custom-forms/fr/>\n"
14 14 "Language: fr\n"
... ... @@ -16,7 +16,7 @@ msgstr &quot;&quot;
16 16 "Content-Type: text/plain; charset=UTF-8\n"
17 17 "Content-Transfer-Encoding: 8bit\n"
18 18 "Plural-Forms: nplurals=2; plural=n > 1;\n"
19   -"X-Generator: Weblate 2.3-dev\n"
  19 +"X-Generator: Weblate 2.4-dev\n"
20 20  
21 21 #: plugins/custom_forms/lib/custom_forms_plugin/form.rb:67
22 22 msgid "Invalid string format of access."
... ... @@ -64,9 +64,8 @@ msgstr &quot;%{fn} est obligatoire&quot;
64 64  
65 65 #: plugins/custom_forms/lib/custom_forms_plugin/helper.rb:14
66 66 #: plugins/custom_forms/lib/custom_forms_plugin/helper.rb:47
67   -#, fuzzy
68 67 msgid "Logged users"
69   -msgstr "Connecté en tant que %s"
  68 +msgstr "Utilisateurs connectés"
70 69  
71 70 #: plugins/custom_forms/lib/custom_forms_plugin/helper.rb:19
72 71 #, fuzzy
... ... @@ -213,7 +212,7 @@ msgstr &quot;Une entreprise&quot;
213 212  
214 213 #: plugins/custom_forms/views/custom_forms_plugin_myprofile/_edit_select.html.erb:29
215 214 msgid "Ok"
216   -msgstr ""
  215 +msgstr "Ok"
217 216  
218 217 #: plugins/custom_forms/views/custom_forms_plugin_myprofile/custom_forms_plugin/_alternative.html.erb:10
219 218 #, fuzzy
... ...
plugins/metadata/lib/ext/product.rb
... ... @@ -7,7 +7,7 @@ class Product
7 7 url: proc{ |p, plugin| plugin.og_url_for p.url },
8 8 gr_hascurrencyvalue: proc{ |p, plugin| p.price.to_f },
9 9 gr_hascurrency: proc{ |p, plugin| p.environment.currency_unit },
10   - title: proc{ |a, plugin| "#{p.name} - #{p.profile.name}" },
  10 + title: proc{ |p, plugin| "#{p.name} - #{p.profile.name}" if p },
11 11 description: proc{ |p, plugin| ActionView::Base.full_sanitizer.sanitize p.description },
12 12  
13 13 image: proc{ |p, plugin| "#{p.environment.top_url}#{p.image.public_filename}" if p.image },
... ... @@ -17,7 +17,7 @@ class Product
17 17  
18 18 see_also: [],
19 19 site_name: proc{ |p, plugin| plugin.og_url_for p.profile.url },
20   - updated_time: proc{ |p, plugin| p.updated_at.iso8601 },
  20 + updated_time: proc{ |p, plugin| p.updated_at.iso8601 if p.updated_at },
21 21  
22 22 'locale:locale' => proc{ |p, plugin| p.environment.default_language },
23 23 'locale:alternate' => proc{ |p, plugin| p.environment.languages - [p.environment.default_language] if p.environment.languages },
... ...
plugins/metadata/test/functional/home_controller_test.rb
... ... @@ -12,7 +12,7 @@ class HomeControllerTest &lt; ActionController::TestCase
12 12 @response = ActionController::TestResponse.new
13 13  
14 14 Noosfero::Plugin.stubs(:all).returns([MetadataPlugin.name])
15   - Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([MetadataPlugin.new])
  15 + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([MetadataPlugin.new(@controller)])
16 16 end
17 17  
18 18 should 'display meta tags for social media' do
... ...
plugins/metadata/test/functional/manage_products_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +require 'test_helper'
  2 +require 'home_controller'
  3 +
  4 +# Re-raise errors caught by the controller.
  5 +class ManageProductsController; def rescue_action(e) raise e end; end
  6 +
  7 +class ManageProductsControllerTest < ActionController::TestCase
  8 +
  9 + def setup
  10 + @controller = ManageProductsController.new
  11 + @request = ActionController::TestRequest.new
  12 + @response = ActionController::TestResponse.new
  13 + @enterprise = fast_create(Enterprise, name: 'test', identifier: 'test_ent')
  14 + @user = create_user_with_permission('test_user', 'manage_products', @enterprise)
  15 + @environment = @enterprise.environment
  16 + @environment.enable('products_for_enterprises')
  17 + login_as :test_user
  18 +
  19 + Noosfero::Plugin.stubs(:all).returns([MetadataPlugin.name])
  20 + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([MetadataPlugin.new(@controller)])
  21 + end
  22 +
  23 + should "not crash on new products" do
  24 + get :new, profile: @enterprise.identifier
  25 + end
  26 +
  27 +end
... ...
plugins/remote_user/lib/remote_user_plugin.rb
... ... @@ -48,8 +48,11 @@ class RemoteUserPlugin &lt; Noosfero::Plugin
48 48 end
49 49 end
50 50 end
51   - rescue ActiveRecord::RecordInvalid => invalid
52   - session[:notice] = _('Could not create the remote_user.')
  51 + rescue ::ActiveRecord::RecordInvalid
  52 + session[:notice] = _('Could not create the remote user.')
  53 + render_404
  54 + rescue
  55 + session[:notice] = _("Could not log in.")
53 56 render_404
54 57 end
55 58 end
... ...
plugins/remote_user/test/functional/remote_user_plugin_test.rb
... ... @@ -3,7 +3,7 @@ require File.dirname(__FILE__) + &#39;/../../../../test/test_helper&#39;
3 3 # Re-raise errors caught by the controller.
4 4 class AccountController; def rescue_action(e) raise e end; end
5 5  
6   -class AccountControllerTest < ActionController::TestCase
  6 +class AccountControllerTest < ActionController::TestCase
7 7 def setup
8 8 @environment = Environment.default
9 9 @environment.enabled_plugins = ['RemoteUserPlugin']
... ... @@ -125,10 +125,18 @@ class AccountControllerTest &lt; ActionController::TestCase
125 125 get :index
126 126  
127 127 assert session[:user].blank?
128   -
  128 +
129 129 @request.env["HTTP_REMOTE_USER"] = ""
130 130 get :index
131 131  
132 132 assert session[:user].blank?
133 133 end
  134 +
  135 + should 'not create a new user if his informations is invalid' do
  136 + @request.env["HTTP_REMOTE_USER"] = "*%&invalid user name&%*"
  137 + get :index
  138 +
  139 + assert session[:user].blank?
  140 + assert_response 404
  141 + end
134 142 end
... ...
plugins/shopping_cart/lib/shopping_cart_plugin.rb
1 1 class ShoppingCartPlugin < Noosfero::Plugin
  2 + include ModalHelper
  3 + include ActionView::Helpers::UrlHelper
2 4  
3 5 class << self
4 6 def plugin_name
... ... @@ -63,4 +65,8 @@ class ShoppingCartPlugin &lt; Noosfero::Plugin
63 65  
64 66 buttons
65 67 end
  68 +
  69 + def controller
  70 + context
  71 + end
66 72 end
... ...
plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb
... ... @@ -42,7 +42,7 @@ module ShoppingCartPlugin::CartHelper
42 42 else
43 43 delivery = Product.new(:name => delivery_option || _('Delivery'), :price => settings.delivery_options[delivery_option])
44 44 end
45   - delivery.save(false)
  45 + delivery.save(validate: false)
46 46 items << [delivery.id, '']
47 47 end
48 48  
... ...
plugins/shopping_cart/test/unit/shopping_cart_plugin/cart_helper_test.rb
... ... @@ -41,5 +41,19 @@ class ShoppingCartPlugin::CartHelperTest &lt; ActiveSupport::TestCase
41 41 assert_equal "#{environment.currency_unit}13#{environment.currency_separator}70", float_to_currency_cart(value,environment)
42 42 end
43 43  
44   -end
  44 + should 'return a table of items' do
  45 + enterprise = Enterprise.new(name: "Test Enterprise", identifier: "test-enterprise")
  46 + enterprise.environment = Environment.default
  47 + enterprise.save!
  48 +
  49 + product_category = fast_create(ProductCategory, :name => 'Products')
  50 + product = fast_create(Product, :name => 'test product1', :product_category_id => product_category.id, :profile_id => enterprise.id)
  51 + setting = Noosfero::Plugin::Settings.new(enterprise, ShoppingCartPlugin)
  52 + setting.delivery = true
  53 + setting.save!
  54 +
  55 + assert_match 'table id="cart-items-table"', items_table([product], enterprise)
  56 + assert_match '<td>test product1</td>', items_table([product], enterprise)
  57 + end
45 58  
  59 +end
... ...
plugins/shopping_cart/views/cart.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <a href="cart:clean" onclick="Cart.clean(this); return false" class="cart-clean"><%=_('Clean basket')%></a>
6 6 <ul class="cart-items"></ul>
7 7 <div class="cart-total"><%=_('Total:')%> <b></b></div>
8   - <a href="/plugin/shopping_cart/buy" class="cart-buy modal"><%=_('Shopping checkout')%></a>
  8 + <%= modal_link_to _('Shopping checkout'), { controller: 'shopping_cart_plugin', action: 'buy' }, { class: "cart-buy modal" } %>
9 9 </div>
10 10 <a href="#" onclick="Cart.toggle(this); return false" class="cart-toggle">
11 11 <span class="str-show"><%=_('Show basket')%></span>
... ...
plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb
... ... @@ -24,7 +24,6 @@
24 24 <% end %>
25 25 <% delivery_option = @settings.delivery_options.first && @settings.delivery_options.first.first %>
26 26 <%= items_table(@cart[:items], @profile, delivery_option) %>
27   - <%= link_to_function '', "noosfero.modal.close();", :class => 'cart-box-close icon-cancel' %>
28 27 </div>
29 28  
30 29 <%= javascript_include_tag '../plugins/shopping_cart/buy' %>
... ...
plugins/shopping_cart/views/shopping_cart_plugin_profile/buy.html.erb
... ... @@ -17,7 +17,6 @@
17 17 </div>
18 18 <% end %>
19 19 <%= items_table(session[:cart][:items], profile) %>
20   - <%= link_to_function '', "noosfero.modal.close();", :class => 'cart-box-close icon-cancel' %>
21 20 </div>
22 21  
23 22 <script type="text/javascript">
... ...
plugins/social_share_privacy/lib/social_share_privacy_plugin.rb
... ... @@ -19,12 +19,14 @@ class SocialSharePrivacyPlugin &lt; Noosfero::Plugin
19 19 def article_extra_contents(article)
20 20 proc do
21 21 settings = Noosfero::Plugin::Settings.new(environment, SocialSharePrivacyPlugin)
  22 + modules = settings.get_setting(:networks).map { |service| "/plugins/social_share_privacy/socialshareprivacy/javascripts/modules/#{service}.js" }
22 23 locale = FastGettext.locale
23   - javascript_include_tag('plugins/social_share_privacy/socialshareprivacy/javascripts/socialshareprivacy.js') +
24   - javascript_include_tag('plugins/social_share_privacy/socialshareprivacy/javascripts/localstorage.js') +
25   - javascript_include_tag(settings.get_setting(:networks).map { |service| "plugins/social_share_privacy/socialshareprivacy/javascripts/modules/#{service}.js" }) +
26   - (locale != 'en' ? javascript_include_tag("plugins/social_share_privacy/socialshareprivacy/javascripts/locale/jquery.socialshareprivacy.min.#{locale}.js") : '') +
27   - javascript_tag("jQuery.fn.socialSharePrivacy.settings.path_prefix = '../../plugins/social_share_privacy/socialshareprivacy/'; jQuery.fn.socialSharePrivacy.settings.order = #{settings.get_setting(:networks)}; jQuery(document).ready(function () { jQuery('.social-buttons').socialSharePrivacy({info_link_target: '_blank'});});") +
  24 + javascript_include_tag('/plugins/social_share_privacy/socialshareprivacy/javascripts/socialshareprivacy.js') +
  25 + javascript_include_tag('/plugins/social_share_privacy/socialshareprivacy/javascripts/localstorage.js') +
  26 + (modules.present? ? javascript_include_tag(*modules) : '') +
  27 + javascript_include_tag("/plugins/social_share_privacy/socialshareprivacy/javascripts/modules/facebook.js") +
  28 + (locale != 'en' ? javascript_include_tag("/plugins/social_share_privacy/socialshareprivacy/javascripts/locale/jquery.socialshareprivacy.min.#{locale}.js") : '') +
  29 + javascript_tag("jQuery.fn.socialSharePrivacy.settings.path_prefix = '/plugins/social_share_privacy/socialshareprivacy/'; jQuery.fn.socialSharePrivacy.settings.order = #{settings.get_setting(:networks)}; jQuery(document).ready(function () { jQuery('.social-buttons').socialSharePrivacy({info_link_target: '_blank'});});") +
28 30 content_tag(:div, '', :class => "social-buttons")
29 31 end
30 32 end
... ...
plugins/social_share_privacy/test/functional/content_viewer_controller_test.rb
... ... @@ -23,7 +23,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
23 23  
24 24 get :view_page, :profile => @profile.identifier, :page => ['test']
25 25  
26   - assert_tag :tag => 'script', :attributes => {:src => /\/javascripts\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/socialshareprivacy\.js\??\d*/}
  26 + assert_tag :tag => 'script', :attributes => {:src => /\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/socialshareprivacy\.js\??\d*/}
27 27 assert_tag :tag => 'div', :attributes => {:class => "social-buttons"}
28 28 end
29 29  
... ... @@ -34,8 +34,8 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
34 34  
35 35 get :view_page, :profile => @profile.identifier, :page => ['test']
36 36  
37   - assert_tag :tag => 'script', :attributes => {:src => /\/javascripts\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/modules\/twitter\.js\??\d*/}
38   - assert_tag :tag => 'script', :attributes => {:src => /\/javascripts\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/modules\/gplus\.js\??\d*/}
  37 + assert_tag :tag => 'script', :attributes => {:src => /\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/modules\/twitter\.js\??\d*/}
  38 + assert_tag :tag => 'script', :attributes => {:src => /\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/modules\/gplus\.js\??\d*/}
39 39 end
40 40  
41 41 should 'add javascript with string translations if not english' do
... ... @@ -45,12 +45,12 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
45 45  
46 46 get :view_page, :profile => @profile.identifier, :page => ['test']
47 47  
48   - assert_tag :tag => 'script', :attributes => {:src => /\/javascripts\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/locale\/jquery\.socialshareprivacy\.min\.pt\.js\??\d*/}
  48 + assert_tag :tag => 'script', :attributes => {:src => /\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/locale\/jquery\.socialshareprivacy\.min\.pt\.js\??\d*/}
49 49  
50 50 FastGettext.stubs(:locale).returns('en')
51 51  
52 52 get :view_page, :profile => @profile.identifier, :page => ['test']
53 53  
54   - assert_no_tag :tag => 'script', :attributes => {:src => /\/javascripts\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/locale\/jquery\.socialshareprivacy\.min\.en\.js\??\d*/}
  54 + assert_no_tag :tag => 'script', :attributes => {:src => /\/plugins\/social_share_privacy\/socialshareprivacy\/javascripts\/locale\/jquery\.socialshareprivacy\.min\.en\.js\??\d*/}
55 55 end
56 56 end
... ...
po/fr/noosfero-doc.po
... ... @@ -7,8 +7,8 @@ msgid &quot;&quot;
7 7 msgstr ""
8 8 "Project-Id-Version: PACKAGE VERSION\n"
9 9 "POT-Creation-Date: 2013-12-10 15:48-0300\n"
10   -"PO-Revision-Date: 2015-03-23 19:30+0200\n"
11   -"Last-Translator: Jérôme Jutteau <j.jutteau@gmail.com>\n"
  10 +"PO-Revision-Date: 2015-06-29 14:38+0200\n"
  11 +"Last-Translator: Christophe DANIEL <papaeng@gmail.com>\n"
12 12 "Language-Team: French "
13 13 "<https://hosted.weblate.org/projects/noosfero/documentation/fr/>\n"
14 14 "Language: fr\n"
... ... @@ -16,7 +16,7 @@ msgstr &quot;&quot;
16 16 "Content-Type: text/plain; charset=UTF-8\n"
17 17 "Content-Transfer-Encoding: 8bit\n"
18 18 "Plural-Forms: nplurals=2; plural=n > 1;\n"
19   -"X-Generator: Weblate 2.3-dev\n"
  19 +"X-Generator: Weblate 2.4-dev\n"
20 20  
21 21 # type: Content of: <h1>
22 22 #. type: Content of: <h1>
... ... @@ -470,7 +470,7 @@ msgstr &quot;&quot;
470 470 #. type: Attribute 'alt' of: <p><img>
471 471 #: doc/noosfero/plugins/shopping_cart.en.xhtml:21
472 472 msgid "Catalog"
473   -msgstr ""
  473 +msgstr "Catalogue"
474 474  
475 475 # type: Content of: <p>
476 476 #. type: Content of: <p>
... ...
public/designs/themes/base/style.css
... ... @@ -1061,15 +1061,18 @@ hr.pre-posts, hr.sep-posts {
1061 1061 text-decoration: none;
1062 1062 }
1063 1063  
1064   -#content .main-block .created-at {
  1064 +#content .main-block .publishing-info {
1065 1065 text-align: left;
1066 1066 color: #AAA;
  1067 + font-size: 11px;
  1068 + /*padding-top: 20px;*/
  1069 + margin-bottom:15px;
1067 1070 }
1068   -#content .main-block .created-at a {
  1071 +#content .main-block .publishing-info a {
1069 1072 color: #AAA;
1070 1073 text-decoration: none;
1071 1074 }
1072   -#content .main-block .created-at a:hover {
  1075 +#content .main-block .publishing-info a:hover {
1073 1076 color: #555;
1074 1077 text-decoration: underline;
1075 1078 }
... ... @@ -1415,3 +1418,115 @@ table#recaptcha_table tr:hover td {
1415 1418 color:#333;
1416 1419 }
1417 1420  
  1421 +/************************* Article Page *****************************/
  1422 +
  1423 +#article-header .preview {
  1424 + font-size: 15px;
  1425 +}
  1426 +
  1427 +.article-body-img {
  1428 + float: left;
  1429 + margin-right: 20px;
  1430 + margin-top: 5px;
  1431 +}
  1432 +
  1433 +#content #article .article-body .article-body-img img {
  1434 + height: auto;
  1435 + width: auto;
  1436 + min-height: 120px;
  1437 + max-height: 180px;
  1438 + max-width: 250px;
  1439 + background-position: center center;
  1440 + background-repeat: no-repeat;
  1441 +}
  1442 +
  1443 +#content #article .article-body .article-body-img p {
  1444 + margin-bottom: 10px;
  1445 + font-size: 10px;
  1446 + min-height: 20px;
  1447 +}
  1448 +/* Noosfero Events */
  1449 +
  1450 +.event-card {
  1451 + float: left;
  1452 + padding-top: 25px;
  1453 + width: 494px;
  1454 + height: 116px;
  1455 + background-repeat: no-repeat;
  1456 + margin-bottom: 30px;
  1457 +}
  1458 +
  1459 +.event-image {
  1460 + position: relative;
  1461 + float: left;
  1462 + padding-right: 22px;
  1463 + max-width: 130px;
  1464 + height: 130px;
  1465 +}
  1466 +
  1467 +#content #article .article-body img{
  1468 + max-height: 100%;
  1469 +}
  1470 +
  1471 +.about-event {
  1472 + position: relative;
  1473 + float: left;
  1474 + height: 160px;
  1475 + width: 300px;
  1476 + max-width: 300px;
  1477 +}
  1478 +
  1479 +.about-event > span {
  1480 + display: block;
  1481 + max-width: inherit;
  1482 + margin-left: 20px;
  1483 + padding-left: 21px;
  1484 + line-height: 13px;
  1485 + margin-right: 11px;
  1486 +}
  1487 +
  1488 +.about-event .event-date {
  1489 + margin-top: 3px;
  1490 +}
  1491 +
  1492 +.about-event .event-address {
  1493 + margin-top: 19px;
  1494 +}
  1495 +
  1496 +.about-event .event-address span {
  1497 + display: block;
  1498 + margin-left: 0px;
  1499 + margin-top: 4.4px;
  1500 + line-height: 14px;
  1501 +}
  1502 +
  1503 +.event-date {
  1504 + background: url('/images/calendar_date_select/calendar-icon.png') no-repeat left center;
  1505 + padding: 5px;
  1506 +}
  1507 +
  1508 +.event-link {
  1509 + background: url('/images/globe-icon.png') no-repeat left center;
  1510 + margin-top: 18px;
  1511 +}
  1512 +
  1513 +.event-link a {
  1514 +}
  1515 +
  1516 +.event-address {
  1517 + background: url('/images/icone_pin.png') no-repeat left top;
  1518 +}
  1519 +
  1520 +.event-body {
  1521 + float: left;
  1522 +}
  1523 +
  1524 +.event-body .event-lead {
  1525 + font-size: 15px;
  1526 +}
  1527 +
  1528 +.event-body .event-content p {
  1529 + margin-top: 20px;
  1530 + width: 494px;
  1531 + padding-left: 2px;
  1532 +}
... ...
public/images/calendar_date_select/calendar-icon.png 0 → 100644

283 Bytes

public/images/globe-icon.png 0 → 100644

464 Bytes

public/images/icone_pin.png 0 → 100644

51.9 KB

public/javascripts/application.js
... ... @@ -14,6 +14,7 @@
14 14 *= require jquery.ba-bbq.min.js
15 15 *= require jquery.tokeninput.js
16 16 *= require jquery-timepicker-addon/dist/jquery-ui-timepicker-addon.js
  17 +*= require select-or-die/_src/selectordie
17 18 *= require inputosaurus.js
18 19 *= require reflection.js
19 20 *= require rails.js
... ... @@ -845,7 +846,7 @@ Array.min = function(array) {
845 846  
846 847 function hideAndGetUrl(link) {
847 848 document.body.style.cursor = 'wait';
848   - link.hide();
  849 + jQuery(link).hide();
849 850 url = jQuery(link).attr('href');
850 851 jQuery.get(url, function( data ) {
851 852 document.body.style.cursor = 'default';
... ...
public/javascripts/jquery.tokeninput.js
... ... @@ -345,7 +345,7 @@ $.TokenList = function (input, url_or_data, options) {
345 345 dropdown.appendTo("body");
346 346 if (!settings.permanentDropdown)
347 347 dropdown.appendTo("body");
348   - else
  348 + else
349 349 $(input).after(dropdown.show());
350 350  
351 351 if (settings.permanentDropdown || settings.showAllResults) {
... ... @@ -382,7 +382,7 @@ $.TokenList = function (input, url_or_data, options) {
382 382 if(li_data && li_data.length) {
383 383 $.each(li_data, function (index, value) {
384 384 insert_token(value);
385   - checkTokenLimit();
  385 + checkTokenLimit({init: true});
386 386 });
387 387 }
388 388  
... ... @@ -425,12 +425,12 @@ $.TokenList = function (input, url_or_data, options) {
425 425 // Private functions
426 426 //
427 427  
428   - function checkTokenLimit() {
  428 + function checkTokenLimit(options) {
429 429 if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
430 430 input_box.hide();
431 431 hide_dropdown();
432 432 return;
433   - } else {
  433 + } else if (options && !options.init) {
434 434 input_box.focus();
435 435 }
436 436 }
... ... @@ -618,7 +618,7 @@ $.TokenList = function (input, url_or_data, options) {
618 618 if (!settings.showAllResults)
619 619 dropdown.empty();
620 620 selected_dropdown_item = null;
621   - }
  621 + }
622 622 if (settings.showAllResults)
623 623 show_dropdown_hint();
624 624 }
... ... @@ -728,7 +728,7 @@ $.TokenList = function (input, url_or_data, options) {
728 728 item.addClass(settings.classes.selectedDropdownItem);
729 729 selected_dropdown_item = item.get(0);
730 730  
731   - isBefore = item[0].offsetTop <= (dropdown[0].scrollTop + dropdown[0].scrollWidth);
  731 + isBefore = item[0].offsetTop <= (dropdown[0].scrollTop + dropdown[0].scrollWidth);
732 732 isAfter = item[0].offsetTop >= dropdown[0].scrollTop;
733 733 visible = isBefore && isAfter;
734 734 if (!visible) {
... ...
public/stylesheets/application.css
... ... @@ -1054,6 +1054,11 @@ code input {
1054 1054 margin-top: 10px;
1055 1055 display: none;
1056 1056 }
  1057 +
  1058 +#change-image {
  1059 + display: table-caption;
  1060 +}
  1061 +
1057 1062 .zoomable-image {
1058 1063 position: relative;
1059 1064 display: inline-block;
... ... @@ -1520,13 +1525,13 @@ a.comment-picture {
1520 1525 text-align: right;
1521 1526 color: gray;
1522 1527 }
1523   -#content .created-at {
  1528 +#content .publishing-info {
1524 1529 color: gray;
1525 1530 font-size: 12px;
1526 1531 display: block;
1527 1532 text-align: right;
1528 1533 }
1529   -#content .blog-post .created-at {
  1534 +#content .blog-post .publishing-info {
1530 1535 text-align: left;
1531 1536 }
1532 1537 #content #article .pagination .prev_page {
... ... @@ -1598,7 +1603,7 @@ div.article-body p img {
1598 1603 .blog-post.not-published a {
1599 1604 text-decoration: none;
1600 1605 }
1601   -#content .blog-post.not-published .created-at {
  1606 +#content .blog-post.not-published .publishing-info {
1602 1607 text-align: left;
1603 1608 }
1604 1609 .blog-post.not-published .metadata {
... ...
script/gitlab-ci
... ... @@ -1,56 +0,0 @@
1   -#!/usr/bin/env ruby
2   -
3   -# These just forward the signals to the whole process group and
4   -# then immediately exit.
5   -pgid = Process.getpgid Process.pid
6   -Signal.trap(:TERM) { Process.kill(:TERM, -pgid); exit }
7   -Signal.trap(:INT) { Process.kill(:INT, -pgid); exit }
8   -
9   -def run command, options = {}
10   - command = "#{command} 2>&1 > /dev/null" if options[:output] == false
11   - #command = "time #{command}" unless options[:runtime] == false
12   - puts "== #{command}"
13   - system command
14   -end
15   -
16   -@id = (0...10).map{ ('a'..'z').to_a[rand(26)] }.join
17   -@db = "gitlab-ci-#{@id}"
18   -
19   -def config
20   - require 'yaml'
21   - db_config = {
22   - 'adapter' => 'postgresql', 'encoding' => 'unicode',
23   - 'database' => @db, 'username' => ENV['USER'],
24   - }
25   - File.write 'config/database.yml', YAML.dump('test' => db_config, 'development' => db_config)
26   -end
27   -
28   -def prepare
29   - run("createdb #{@db}") and
30   - run('mkdir -p tmp/pids log') and
31   - run('bundle check || bundle install') and
32   - run('rake db:schema:load', output: false) and
33   - run('script/noosfero-plugins disableall') and
34   - run('rake db:migrate')
35   -end
36   -
37   -def test
38   - %w[
39   - test:units
40   - test:functionals
41   - test:integration
42   - cucumber
43   - test:noosfero_plugins
44   - ].each do |task|
45   - run "rake #{task}"
46   - end
47   -end
48   -
49   -def cleanup
50   - run "dropdb #{@db}"
51   -end
52   -
53   -ret = config and prepare and test
54   -cleanup
55   -
56   -exit (if ret == true then 0 else 1 end)
script/install-dependencies/debian-wheezy.sh
... ... @@ -80,4 +80,5 @@ packages=$(grep-dctrl -n -s Build-Depends,Depends,Recommends -S -X noosfero debi
80 80 run sudo apt-get -y install $packages
81 81 sudo apt-get -y install iceweasel || sudo apt-get -y install firefox
82 82  
  83 +run rm -f Gemfile.lock
83 84 run bundle --local
... ...
test/functional/cms_controller_test.rb
... ... @@ -223,6 +223,20 @@ class CmsControllerTest &lt; ActionController::TestCase
223 223 assert_equal profile, a.last_changed_by
224 224 end
225 225  
  226 + should 'be able to set label to article image' do
  227 + login_as(profile.identifier)
  228 + post :new, :type => TextileArticle.name, :profile => profile.identifier,
  229 + :article => {
  230 + :name => 'adding-image-label',
  231 + :image_builder => {
  232 + :uploaded_data => fixture_file_upload('/files/tux.png', 'image/png'),
  233 + :label => 'test-label'
  234 + }
  235 + }
  236 + a = Article.last
  237 + assert_equal a.image.label, 'test-label'
  238 + end
  239 +
226 240 should 'edit by using the correct template to display the editor depending on the mime-type' do
227 241 a = profile.articles.build(:name => 'test document')
228 242 a.save!
... ... @@ -318,6 +332,20 @@ class CmsControllerTest &lt; ActionController::TestCase
318 332 end
319 333 end
320 334  
  335 + should 'be able to edit an image label' do
  336 + image = fast_create(Image, :content_type => 'image/png', :filename => 'event-image.png', :label => 'test_label', :size => 1014)
  337 + article = fast_create(Article, :profile_id => profile.id, :name => 'test_label_article', :body => 'test_content')
  338 + article.image = image
  339 + article.save
  340 + assert_not_nil article
  341 + assert_not_nil article.image
  342 + assert_equal 'test_label', article.image.label
  343 +
  344 + post :edit, :profile => profile.identifier, :id => article.id, :article => {:image_builder => { :label => 'test_label_modified'}}
  345 + article.reload
  346 + assert_equal 'test_label_modified', article.image.label
  347 + end
  348 +
321 349 should 'be able to upload more than one file at once' do
322 350 assert_difference 'UploadedFile.count', 2 do
323 351 post :upload_files, :profile => profile.identifier, :uploaded_files => [fixture_file_upload('/files/test.txt', 'text/plain'), fixture_file_upload('/files/rails.png', 'text/plain')]
... ... @@ -1863,8 +1891,8 @@ class CmsControllerTest &lt; ActionController::TestCase
1863 1891 end
1864 1892  
1865 1893 should 'return tags found' do
1866   - tag = mock; tag.stubs(:name).returns('linux')
1867   - ActsAsTaggableOn::Tag.stubs(:find).returns([tag])
  1894 + a = profile.articles.create(:name => 'blablabla')
  1895 + a.tags.create! name: 'linux'
1868 1896 get :search_tags, :profile => profile.identifier, :term => 'linux'
1869 1897 assert_equal '[{"label":"linux","value":"linux"}]', @response.body
1870 1898 end
... ...
test/functional/content_viewer_controller_test.rb
... ... @@ -124,6 +124,19 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
124 124 assert_tag :tag => 'div', :attributes => { :id => 'article-tags' }, :descendant => { :content => /This article's tags:/ }
125 125 end
126 126  
  127 + should "display image label on article image" do
  128 + page = TinyMceArticle.create!(
  129 + :profile => profile,
  130 + :name => 'myarticle',
  131 + :image_builder => {
  132 + :uploaded_data => fixture_file_upload('/files/tux.png', 'image/png'),
  133 + :label => 'test-label'
  134 + }
  135 + )
  136 + get :view_page, page.url
  137 + assert_match /test-label/, @response.body
  138 + end
  139 +
127 140 should "not display current article's tags" do
128 141 page = profile.articles.create!(:name => 'myarticle', :body => 'test article')
129 142  
... ...
test/unit/event_test.rb
... ... @@ -109,17 +109,20 @@ class EventTest &lt; ActiveSupport::TestCase
109 109 end
110 110  
111 111 should 'provide nice display format' do
112   - e = build(Event, :start_date => Date.new(2008,1,1), :end_date => Date.new(2008,1,1), :link => 'http://www.myevent.org', :body => 'my somewhat short description')
  112 + event = build(Event, :start_date => Date.new(2008,1,1), :end_date => Date.new(2008,1,1), :link => 'http://www.myevent.org', :body => '<p>my somewhat short description</p>')
  113 + display = instance_eval(&event.to_html)
113 114  
114   - assert_tag_in_string e.to_html, :content => Regexp.new("January 1, 2008")
115   - assert_tag_in_string e.to_html, :content => 'my somewhat short description'
116   - assert_tag_in_string e.to_html, :tag => 'a', :attributes => { :href => 'http://www.myevent.org' }, :content => 'http://www.myevent.org'
  115 + assert_tag_in_string display, :content => Regexp.new("January 1, 2008")
  116 + assert_tag_in_string display, :content => Regexp.new('my somewhat short description')
  117 + assert_tag_in_string display, :content => Regexp.new('http://www.myevent.org')
117 118 end
118 119  
119 120 should 'not crash when body is blank' do
120 121 e = Event.new
121 122 assert_nil e.body
122   - assert_no_match(/_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____/, e.to_html)
  123 + assert_nothing_raised do
  124 + instance_eval(&e.to_html)
  125 + end
123 126 end
124 127  
125 128 should 'add http:// to the link if not already present' do
... ... @@ -141,10 +144,19 @@ class EventTest &lt; ActiveSupport::TestCase
141 144 assert_equal '', a.link
142 145 end
143 146  
  147 + should 'get the first paragraph' do
  148 + profile = create_user('testuser').person
  149 + event = create(Event, :profile => profile, :name => 'test',
  150 + :body => '<p>first paragraph </p><p>second paragraph </p>',
  151 + :link => 'www.colivre.coop.br', :start_date => Date.today)
  152 +
  153 + assert_match '<p>first paragraph </p>', event.first_paragraph
  154 + end
  155 +
144 156 should 'not escape HTML in body' do
145 157 a = build(Event, :body => '<p>a paragraph of text</p>', :link => 'www.gnu.org')
146 158  
147   - assert_match '<p>a paragraph of text</p>', a.to_html
  159 + assert_match '<p>a paragraph of text</p>', instance_eval(&a.to_html)
148 160 end
149 161  
150 162 should 'filter HTML in body' do
... ... @@ -324,7 +336,7 @@ class EventTest &lt; ActiveSupport::TestCase
324 336 environment = fast_create(Environment)
325 337 environment.languages = nil
326 338 profile = fast_create(Person, :environment_id => environment.id)
327   -
  339 +
328 340 event = Event.new(:profile => profile)
329 341  
330 342 assert !event.translatable?
... ... @@ -337,11 +349,11 @@ class EventTest &lt; ActiveSupport::TestCase
337 349 event = fast_create(Event, :profile_id => profile.id)
338 350  
339 351 assert !event.translatable?
340   -
  352 +
341 353  
342 354 environment.languages = ['en','pt','fr']
343 355 environment.save
344   - event.reload
  356 + event.reload
345 357 assert event.translatable?
346 358 end
347 359  
... ...
test/unit/task_test.rb
... ... @@ -192,6 +192,32 @@ class TaskTest &lt; ActiveSupport::TestCase
192 192 task.save!
193 193 end
194 194  
  195 + should 'not send notification to target if notification is disabled in profile' do
  196 + task = Task.new
  197 + target = fast_create(Profile)
  198 + target.stubs(:notification_emails).returns(['adm@example.com'])
  199 + target.stubs(:administrator_mail_notification).returns(false)
  200 + task.target = target
  201 + task.stubs(:target_notification_message).returns('some non nil message to be sent to target')
  202 + TaskMailer.expects(:target_notification).never
  203 + task.save!
  204 + end
  205 +
  206 + should 'send notification to target if notification is enabled in profile' do
  207 + task = Task.new
  208 + target = fast_create(Profile)
  209 + target.stubs(:notification_emails).returns(['adm@example.com'])
  210 + target.stubs(:administrator_mail_notification).returns(true)
  211 + task.target = target
  212 + task.stubs(:target_notification_message).returns('some non nil message to be sent to target')
  213 +
  214 +
  215 + mailer = mock
  216 + mailer.expects(:deliver).once
  217 + TaskMailer.expects(:target_notification).returns(mailer).once
  218 + task.save!
  219 + end
  220 +
195 221 should 'be able to list pending tasks' do
196 222 Task.delete_all
197 223 t1 = Task.create!
... ...