Commit d26eed6e3c6c07d144112218f179ca595eaa8a24
Exists in
theme-brasil-digital-from-staging
and in
4 other branches
Merge branch 'staging' into staging_rails4
Conflicts: app/helpers/forms_helper.rb app/views/cms/edit.html.erb lib/noosfero/api/entities.rb lib/noosfero/api/v1/comments.rb lib/noosfero/api/v1/search.rb test/unit/api/search_test.rb
Showing
44 changed files
with
445 additions
and
39 deletions
Show diff stats
app/helpers/article_helper.rb
@@ -15,6 +15,13 @@ module ArticleHelper | @@ -15,6 +15,13 @@ module ArticleHelper | ||
15 | topic_creation(@article) + | 15 | topic_creation(@article) + |
16 | content_tag('h4', _('Options')) + | 16 | content_tag('h4', _('Options')) + |
17 | content_tag('div', | 17 | content_tag('div', |
18 | + content_tag('div', | ||
19 | + check_box(:article, :archived) + | ||
20 | + content_tag('span', ' ', :class => 'access-archived-icon') + | ||
21 | + content_tag('label', _('Read Only'), :for => 'article_archived_true') + | ||
22 | + content_tag('span', _('Archive to avoid create comments, votes, actions in children articles...'), :class => 'access-note'), | ||
23 | + :class => 'access-item' | ||
24 | + ) + | ||
18 | (article.profile.has_members? ? | 25 | (article.profile.has_members? ? |
19 | content_tag( | 26 | content_tag( |
20 | 'div', | 27 | 'div', |
@@ -63,13 +70,20 @@ module ArticleHelper | @@ -63,13 +70,20 @@ module ArticleHelper | ||
63 | content_tag('div', | 70 | content_tag('div', |
64 | content_tag('div', | 71 | content_tag('div', |
65 | radio_button(:article, :published, true) + | 72 | radio_button(:article, :published, true) + |
66 | - content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true') | 73 | + content_tag('span', ' ', :class => 'access-public-icon') + |
74 | + content_tag('label', _('Public'), :for => 'article_published_true') + | ||
75 | + content_tag('span', _('Visible to other people'), :class => 'access-note'), | ||
76 | + :class => 'access-item' | ||
67 | ) + | 77 | ) + |
68 | content_tag('div', | 78 | content_tag('div', |
69 | radio_button(:article, :published, false) + | 79 | radio_button(:article, :published, false) + |
70 | - content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private") | 80 | + content_tag('span', ' ', :class => 'access-private-icon') + |
81 | + content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private") + | ||
82 | + content_tag('span', _('Limit visibility of this article'), :class => 'access-note'), | ||
83 | + :class => 'access-item' | ||
71 | ) + | 84 | ) + |
72 | - privacity_exceptions(article, tokenized_children) | 85 | + privacity_exceptions(article, tokenized_children), |
86 | + :class => 'access-itens' | ||
73 | ) | 87 | ) |
74 | end | 88 | end |
75 | 89 |
app/helpers/folder_helper.rb
@@ -59,7 +59,15 @@ module FolderHelper | @@ -59,7 +59,15 @@ module FolderHelper | ||
59 | @article = article | 59 | @article = article |
60 | 60 | ||
61 | visibility_options(article,tokenized_children) + | 61 | visibility_options(article,tokenized_children) + |
62 | + content_tag('h4', _('Options')) + | ||
62 | content_tag('div', | 63 | content_tag('div', |
64 | + content_tag('div', | ||
65 | + check_box(:article, :archived) + | ||
66 | + content_tag('span', ' ', :class => 'access-archived-icon') + | ||
67 | + content_tag('label', _('Read Only'), :for => 'article_archived_true') + | ||
68 | + content_tag('span', _('Archive to avoid votes and create new children articles'), :class => 'access-note'), | ||
69 | + :class => 'access-item' | ||
70 | + ) + | ||
63 | hidden_field_tag('article[accept_comments]', 0) | 71 | hidden_field_tag('article[accept_comments]', 0) |
64 | ) | 72 | ) |
65 | end | 73 | end |
app/models/article.rb
@@ -9,7 +9,7 @@ class Article < ActiveRecord::Base | @@ -9,7 +9,7 @@ class Article < ActiveRecord::Base | ||
9 | :highlighted, :notify_comments, :display_hits, :slug, | 9 | :highlighted, :notify_comments, :display_hits, :slug, |
10 | :external_feed_builder, :display_versions, :external_link, | 10 | :external_feed_builder, :display_versions, :external_link, |
11 | :author, :published_at, :person_followers, :show_to_followers, | 11 | :author, :published_at, :person_followers, :show_to_followers, |
12 | - :image_builder, :display_preview | 12 | + :image_builder, :display_preview, :archived |
13 | 13 | ||
14 | acts_as_having_image | 14 | acts_as_having_image |
15 | 15 | ||
@@ -156,6 +156,8 @@ class Article < ActiveRecord::Base | @@ -156,6 +156,8 @@ class Article < ActiveRecord::Base | ||
156 | validate :no_self_reference | 156 | validate :no_self_reference |
157 | validate :no_cyclical_reference, :if => 'parent_id.present?' | 157 | validate :no_cyclical_reference, :if => 'parent_id.present?' |
158 | 158 | ||
159 | + validate :parent_archived? | ||
160 | + | ||
159 | def no_self_reference | 161 | def no_self_reference |
160 | errors.add(:parent_id, _('self-reference is not allowed.')) if id && parent_id == id | 162 | errors.add(:parent_id, _('self-reference is not allowed.')) if id && parent_id == id |
161 | end | 163 | end |
@@ -490,6 +492,10 @@ class Article < ActiveRecord::Base | @@ -490,6 +492,10 @@ class Article < ActiveRecord::Base | ||
490 | end | 492 | end |
491 | end | 493 | end |
492 | 494 | ||
495 | + def archived? | ||
496 | + (self.parent && self.parent.archived) || self.archived | ||
497 | + end | ||
498 | + | ||
493 | def self.folder_types | 499 | def self.folder_types |
494 | ['Folder', 'Blog', 'Forum', 'Gallery'] | 500 | ['Folder', 'Blog', 'Forum', 'Gallery'] |
495 | end | 501 | end |
@@ -636,13 +642,21 @@ class Article < ActiveRecord::Base | @@ -636,13 +642,21 @@ class Article < ActiveRecord::Base | ||
636 | end | 642 | end |
637 | 643 | ||
638 | def hit | 644 | def hit |
639 | - self.class.connection.execute('update articles set hits = hits + 1 where id = %d' % self.id.to_i) | ||
640 | - self.hits += 1 | 645 | + if !archived? |
646 | + self.class.connection.execute('update articles set hits = hits + 1 where id = %d' % self.id.to_i) | ||
647 | + self.hits += 1 | ||
648 | + end | ||
641 | end | 649 | end |
642 | 650 | ||
643 | def self.hit(articles) | 651 | def self.hit(articles) |
644 | - Article.where(:id => articles.map(&:id)).update_all('hits = hits + 1') | ||
645 | - articles.each { |a| a.hits += 1 } | 652 | + ids = [] |
653 | + articles.each do |article| | ||
654 | + if !article.archived? | ||
655 | + ids << article.id | ||
656 | + article.hits += 1 | ||
657 | + end | ||
658 | + end | ||
659 | + Article.where(:id => ids).update_all('hits = hits + 1') if !ids.empty? | ||
646 | end | 660 | end |
647 | 661 | ||
648 | def can_display_hits? | 662 | def can_display_hits? |
@@ -856,4 +870,10 @@ class Article < ActiveRecord::Base | @@ -856,4 +870,10 @@ class Article < ActiveRecord::Base | ||
856 | sanitizer.sanitize(text) | 870 | sanitizer.sanitize(text) |
857 | end | 871 | end |
858 | 872 | ||
873 | + def parent_archived? | ||
874 | + if self.parent_id_changed? && self.parent && self.parent.archived? | ||
875 | + errors.add(:parent_folder, N_('is archived!!')) | ||
876 | + end | ||
877 | + end | ||
878 | + | ||
859 | end | 879 | end |
app/models/comment.rb
@@ -34,7 +34,9 @@ class Comment < ActiveRecord::Base | @@ -34,7 +34,9 @@ class Comment < ActiveRecord::Base | ||
34 | rec.errors.add(:name, _('{fn} can only be informed for unauthenticated authors').fix_i18n) | 34 | rec.errors.add(:name, _('{fn} can only be informed for unauthenticated authors').fix_i18n) |
35 | end | 35 | end |
36 | end | 36 | end |
37 | - | 37 | + |
38 | + validate :article_archived? | ||
39 | + | ||
38 | acts_as_having_settings | 40 | acts_as_having_settings |
39 | 41 | ||
40 | xss_terminate :only => [ :body, :title, :name ], :on => 'validation' | 42 | xss_terminate :only => [ :body, :title, :name ], :on => 'validation' |
@@ -210,4 +212,14 @@ class Comment < ActiveRecord::Base | @@ -210,4 +212,14 @@ class Comment < ActiveRecord::Base | ||
210 | user.present? && user == author | 212 | user.present? && user == author |
211 | end | 213 | end |
212 | 214 | ||
215 | + def archived? | ||
216 | + self.article.archived? if self.article.present? && self.article.respond_to?(:archived?) | ||
217 | + end | ||
218 | + | ||
219 | + protected | ||
220 | + | ||
221 | + def article_archived? | ||
222 | + errors.add(:article, N_('associated with this comment is achived!')) if archived? | ||
223 | + end | ||
224 | + | ||
213 | end | 225 | end |
app/models/folder.rb
app/models/user.rb
@@ -424,6 +424,12 @@ class User < ActiveRecord::Base | @@ -424,6 +424,12 @@ class User < ActiveRecord::Base | ||
424 | @is_password_required = false | 424 | @is_password_required = false |
425 | end | 425 | end |
426 | 426 | ||
427 | + def resend_activation_code | ||
428 | + return if self.activated? | ||
429 | + update_attribute(:activation_code, make_activation_code) | ||
430 | + self.deliver_activation_code | ||
431 | + end | ||
432 | + | ||
427 | protected | 433 | protected |
428 | 434 | ||
429 | def normalize_email | 435 | def normalize_email |
app/views/cms/edit.html.erb
1 | <%= error_messages_for 'article' %> | 1 | <%= error_messages_for 'article' %> |
2 | 2 | ||
3 | +<% if @article.archived? %> | ||
4 | + <%= render :partial => 'archived_warning', :locals => {:article => @article} %> | ||
5 | +<% end %> | ||
3 | <div class='<%= (@article.display_media_panel? ? 'with_media_panel' : 'no_media_panel') %>'> | 6 | <div class='<%= (@article.display_media_panel? ? 'with_media_panel' : 'no_media_panel') %>'> |
4 | <%= labelled_form_for 'article', :html => { :multipart => true, :class => @type } do |f| %> | 7 | <%= labelled_form_for 'article', :html => { :multipart => true, :class => @type } do |f| %> |
5 | 8 |
app/views/content_viewer/_article_toolbar.html.erb
@@ -29,7 +29,9 @@ | @@ -29,7 +29,9 @@ | ||
29 | <%= expirable_button @page, :locale, content, url %> | 29 | <%= expirable_button @page, :locale, content, url %> |
30 | <% end %> | 30 | <% end %> |
31 | 31 | ||
32 | - <%= modal_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : @page.parent))) unless remove_content_button(:new, @page) %> | 32 | + <% if !@page.archived? %> |
33 | + <%= modal_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : @page.parent))) unless remove_content_button(:new, @page) %> | ||
34 | + <% end %> | ||
33 | 35 | ||
34 | <% content = content_tag('span', label_for_clone_article(@page)) %> | 36 | <% content = content_tag('span', label_for_clone_article(@page)) %> |
35 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'new', :id => @page.id, :clone => true, :parent_id => (@page.folder? ? @page : @page.parent), :type => @page.class}) %> | 37 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'new', :id => @page.id, :clone => true, :parent_id => (@page.folder? ? @page : @page.parent), :type => @page.class}) %> |
@@ -64,6 +66,9 @@ | @@ -64,6 +66,9 @@ | ||
64 | <% end %> | 66 | <% end %> |
65 | <%= button_without_text(:feed, _('RSS feed'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %> | 67 | <%= button_without_text(:feed, _('RSS feed'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %> |
66 | <%= @plugins.dispatch(:article_header_extra_contents, @page).collect { |content| instance_exec(&content) }.join("") %> | 68 | <%= @plugins.dispatch(:article_header_extra_contents, @page).collect { |content| instance_exec(&content) }.join("") %> |
69 | + <% if @page.archived? %> | ||
70 | + <%= render :partial => 'cms/archived_warning', :locals => {:article => @page} %> | ||
71 | + <% end %> | ||
67 | <%= render :partial => 'article_title', :locals => {:no_link => true} %> | 72 | <%= render :partial => 'article_title', :locals => {:no_link => true} %> |
68 | <%= article_translations(@page) %> | 73 | <%= article_translations(@page) %> |
69 | </div> | 74 | </div> |
app/views/content_viewer/_publishing_info.html.erb
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | <div id='article-sub-header'> | 16 | <div id='article-sub-header'> |
17 | <% if @page.display_hits? %> | 17 | <% if @page.display_hits? %> |
18 | <div id="article-hits"> | 18 | <div id="article-hits"> |
19 | - <%= n_('Viewed one time', 'Viewed %{num} times', @page.hits) % { :num => @page.hits } %> | 19 | + <%= n_('Viewed one time %{desc}', 'Viewed %{num} times %{desc}', @page.hits) % { :num => @page.hits, :desc => @page.archived? ? '<b>'+_('(Not countable anymore)')+'</b>' : '' } %> |
20 | </div> | 20 | </div> |
21 | <% end %> | 21 | <% end %> |
22 | 22 |
app/views/content_viewer/view_page.html.erb
@@ -85,7 +85,7 @@ | @@ -85,7 +85,7 @@ | ||
85 | <% end %> | 85 | <% end %> |
86 | </ul> | 86 | </ul> |
87 | 87 | ||
88 | - <% if @page.accept_comments? %> | 88 | + <% if !@page.archived? || @page.accept_comments? %> |
89 | <div id='page-comment-form' class='page-comment-form'><%= render :partial => 'comment/comment_form', :locals =>{:url => {:controller => :comment, :action => :create}, :display_link => true, :cancel_triggers_hide => true}%></div> | 89 | <div id='page-comment-form' class='page-comment-form'><%= render :partial => 'comment/comment_form', :locals =>{:url => {:controller => :comment, :action => :create}, :display_link => true, :cancel_triggers_hide => true}%></div> |
90 | <% end %> | 90 | <% end %> |
91 | </div><!-- end class="comments" --> | 91 | </div><!-- end class="comments" --> |
lib/noosfero/api/entities.rb
@@ -205,7 +205,7 @@ module Noosfero | @@ -205,7 +205,7 @@ module Noosfero | ||
205 | 205 | ||
206 | class UserLogin < User | 206 | class UserLogin < User |
207 | root 'users', 'user' | 207 | root 'users', 'user' |
208 | - expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'} | 208 | + expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'}, if: lambda {|object, options| object.activated? } |
209 | end | 209 | end |
210 | 210 | ||
211 | class Task < Entity | 211 | class Task < Entity |
lib/noosfero/api/session.rb
@@ -130,6 +130,25 @@ module Noosfero | @@ -130,6 +130,25 @@ module Noosfero | ||
130 | end | 130 | end |
131 | end | 131 | end |
132 | 132 | ||
133 | + # Resend activation code. | ||
134 | + # | ||
135 | + # Parameters: | ||
136 | + # value (required) - Email or login | ||
137 | + # Example Request: | ||
138 | + # POST /resend_activation_code?value=some@mail.com | ||
139 | + post "/resend_activation_code" do | ||
140 | + requestors = fetch_requestors(params[:value]) | ||
141 | + not_found! if requestors.blank? | ||
142 | + remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR']) | ||
143 | + # test_captcha will render_api_error! and exit in case of any problem | ||
144 | + # this return is just to improve the clarity of the execution path | ||
145 | + return unless test_captcha(remote_ip, params, environment) | ||
146 | + requestors.each do |requestor| | ||
147 | + requestor.user.resend_activation_code | ||
148 | + end | ||
149 | + present requestors.map(&:user), :with => Entities::UserLogin | ||
150 | + end | ||
151 | + | ||
133 | params do | 152 | params do |
134 | requires :code, type: String, desc: _("Forgot password code") | 153 | requires :code, type: String, desc: _("Forgot password code") |
135 | end | 154 | end |
lib/noosfero/api/v1/articles.rb
@@ -131,9 +131,8 @@ module Noosfero | @@ -131,9 +131,8 @@ module Noosfero | ||
131 | failure [[403, 'Forbidden']] | 131 | failure [[403, 'Forbidden']] |
132 | named 'ArticleFollowers' | 132 | named 'ArticleFollowers' |
133 | end | 133 | end |
134 | - | ||
135 | - #FIXME refactor this method | ||
136 | get 'voted_by_me' do | 134 | get 'voted_by_me' do |
135 | + #FIXME refactor this method | ||
137 | present_articles_paginated(current_person.votes.where(:voteable_type => 'Article').collect(&:voteable)) | 136 | present_articles_paginated(current_person.votes.where(:voteable_type => 'Article').collect(&:voteable)) |
138 | end | 137 | end |
139 | 138 | ||
@@ -150,8 +149,14 @@ module Noosfero | @@ -150,8 +149,14 @@ module Noosfero | ||
150 | # FIXME verify allowed values | 149 | # FIXME verify allowed values |
151 | render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value) | 150 | render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value) |
152 | article = find_article(environment.articles, params[:id]) | 151 | article = find_article(environment.articles, params[:id]) |
153 | - vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) | ||
154 | - {:vote => vote.save} | 152 | + |
153 | + begin | ||
154 | + vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) | ||
155 | + saved = vote.save! | ||
156 | + {:vote => saved} | ||
157 | + rescue ActiveRecord::RecordInvalid => e | ||
158 | + render_api_error!(e.message, 400) | ||
159 | + end | ||
155 | end | 160 | end |
156 | 161 | ||
157 | desc 'Return the children of a article identified by id' do | 162 | desc 'Return the children of a article identified by id' do |
lib/noosfero/api/v1/comments.rb
@@ -31,7 +31,13 @@ module Noosfero | @@ -31,7 +31,13 @@ module Noosfero | ||
31 | post ":id/comments" do | 31 | post ":id/comments" do |
32 | article = find_article(environment.articles, params[:id]) | 32 | article = find_article(environment.articles, params[:id]) |
33 | options = params.select { |key,v| !['id','private_token'].include?(key) }.merge(:author => current_person, :source => article) | 33 | options = params.select { |key,v| !['id','private_token'].include?(key) }.merge(:author => current_person, :source => article) |
34 | - present Comment.create(options), :with => Entities::Comment, :current_person => current_person | 34 | + begin |
35 | + comment = Comment.create(options) | ||
36 | + comment.save! | ||
37 | + rescue ActiveRecord::RecordInvalid => e | ||
38 | + render_api_error!(e.message, 400) | ||
39 | + end | ||
40 | + present comment, :with => Entities::Comment, :current_person => current_person | ||
35 | end | 41 | end |
36 | end | 42 | end |
37 | 43 |
lib/noosfero/api/v1/search.rb
@@ -5,6 +5,7 @@ module Noosfero | @@ -5,6 +5,7 @@ module Noosfero | ||
5 | 5 | ||
6 | resource :search do | 6 | resource :search do |
7 | resource :article do | 7 | resource :article do |
8 | + paginate per_page: 20, max_per_page: 200 | ||
8 | get do | 9 | get do |
9 | # Security checks | 10 | # Security checks |
10 | sanitize_params_hash(params) | 11 | sanitize_params_hash(params) |
@@ -13,24 +14,25 @@ module Noosfero | @@ -13,24 +14,25 @@ module Noosfero | ||
13 | context = environment | 14 | context = environment |
14 | 15 | ||
15 | profile = environment.profiles.find(params[:profile_id]) if params[:profile_id] | 16 | profile = environment.profiles.find(params[:profile_id]) if params[:profile_id] |
16 | - scope = profile.nil? ? environment.articles.is_public : profile.articles.is_public | 17 | + |
18 | + scope = profile.nil? ? environment.articles.public : profile.articles.public | ||
19 | + | ||
17 | scope = scope.where(:type => params[:type]) if params[:type] && !(params[:type] == 'Article') | 20 | scope = scope.where(:type => params[:type]) if params[:type] && !(params[:type] == 'Article') |
21 | + | ||
18 | scope = scope.where(:parent_id => params[:parent_id]) if params[:parent_id].present? | 22 | scope = scope.where(:parent_id => params[:parent_id]) if params[:parent_id].present? |
23 | + | ||
19 | scope = scope.joins(:categories).where(:categories => {:id => params[:category_ids]}) if params[:category_ids].present? | 24 | scope = scope.joins(:categories).where(:categories => {:id => params[:category_ids]}) if params[:category_ids].present? |
25 | + | ||
20 | query = params[:query] || "" | 26 | query = params[:query] || "" |
21 | order = "more_recent" | 27 | order = "more_recent" |
22 | 28 | ||
23 | options = {:filter => order, :template_id => params[:template_id]} | 29 | options = {:filter => order, :template_id => params[:template_id]} |
24 | 30 | ||
25 | - paginate_options = params.select{|k,v| [:page, :per_page].include?(k.to_sym)}.symbolize_keys | ||
26 | - paginate_options.each_pair{|k,v| v=v.to_i} | ||
27 | - paginate_options[:page]=1 if !paginate_options.keys.include?(:page) | ||
28 | - | ||
29 | search_result = find_by_contents(asset, context, scope, query, paginate_options, options) | 31 | search_result = find_by_contents(asset, context, scope, query, paginate_options, options) |
30 | 32 | ||
31 | articles = search_result[:results] | 33 | articles = search_result[:results] |
32 | 34 | ||
33 | - result = present_articles(articles) | 35 | + result = present_articles_paginated(articles) |
34 | 36 | ||
35 | result | 37 | result |
36 | end | 38 | end |
lib/noosfero/vote_ext.rb
@@ -8,4 +8,15 @@ class Vote | @@ -8,4 +8,15 @@ class Vote | ||
8 | voter.present? | 8 | voter.present? |
9 | end | 9 | end |
10 | 10 | ||
11 | + validate :verify_target_archived | ||
12 | + | ||
13 | + def verify_target_archived | ||
14 | + if voteable.kind_of?(Article) || voteable.kind_of?(Comment) | ||
15 | + if voteable.archived? | ||
16 | + errors.add(:base, _("The target is achived and can't accept votes")) | ||
17 | + false | ||
18 | + end | ||
19 | + end | ||
20 | + end | ||
21 | + | ||
11 | end | 22 | end |
plugins/dialoga
plugins/gamification
plugins/pg_search/lib/ext/active_record.rb
@@ -4,7 +4,9 @@ class ActiveRecord::Base | @@ -4,7 +4,9 @@ class ActiveRecord::Base | ||
4 | def self.pg_search_plugin_search(query) | 4 | def self.pg_search_plugin_search(query) |
5 | filtered_query = query.gsub(/[\|\(\)\\\/\s\[\]'"*%&!:]/,' ').split.map{|w| w += ":*"}.join('|') | 5 | filtered_query = query.gsub(/[\|\(\)\\\/\s\[\]'"*%&!:]/,' ').split.map{|w| w += ":*"}.join('|') |
6 | if defined?(self::SEARCHABLE_FIELDS) | 6 | if defined?(self::SEARCHABLE_FIELDS) |
7 | - where("to_tsvector('simple', #{pg_search_plugin_fields}) @@ to_tsquery('#{filtered_query}')") | 7 | + select("*,ts_rank(to_tsvector('simple', #{pg_search_plugin_fields}), to_tsquery('#{filtered_query}')) as rank"). |
8 | + where("to_tsvector('simple', #{pg_search_plugin_fields}) @@ to_tsquery('#{filtered_query}')"). | ||
9 | + order("rank DESC") | ||
8 | else | 10 | else |
9 | raise "No searchable fields defined for #{self.name}" | 11 | raise "No searchable fields defined for #{self.name}" |
10 | end | 12 | end |
plugins/pg_search/test/unit/pg_search_plugin_test.rb
@@ -21,6 +21,13 @@ class PgSearchPluginTest < ActiveSupport::TestCase | @@ -21,6 +21,13 @@ class PgSearchPluginTest < ActiveSupport::TestCase | ||
21 | assert_includes search(Profile, 'admin deb'), profile2 | 21 | assert_includes search(Profile, 'admin deb'), profile2 |
22 | end | 22 | end |
23 | 23 | ||
24 | + should 'rank profiles based on the search entry' do | ||
25 | + profile1 = fast_create(Profile, :identifier => 'profile1', :name => 'debugger') | ||
26 | + profile2 = fast_create(Profile, :identifier => 'profile2', :name => 'profile admin debugger') | ||
27 | + profile3 = fast_create(Profile, :identifier => 'profile3', :name => 'admin debugger') | ||
28 | + assert_equal [profile2, profile3, profile1], search(Profile, 'profile admin deb') | ||
29 | + end | ||
30 | + | ||
24 | should 'locate profile escaping special characters' do | 31 | should 'locate profile escaping special characters' do |
25 | profile = fast_create(Profile, :name => 'John', :identifier => 'waterfall') | 32 | profile = fast_create(Profile, :name => 'John', :identifier => 'waterfall') |
26 | assert_includes search(Profile, ') ( /\/\/\/\/\ o_o oOo o_o /\/\/\/\/\ ) ((tx waterfall)'), profile | 33 | assert_includes search(Profile, ') ( /\/\/\/\/\ o_o oOo o_o /\/\/\/\/\ ) ((tx waterfall)'), profile |
plugins/vote/lib/vote_plugin_helper.rb
@@ -2,8 +2,10 @@ module VotePluginHelper | @@ -2,8 +2,10 @@ module VotePluginHelper | ||
2 | 2 | ||
3 | def vote_partial(target, like = true, load_voters=false) | 3 | def vote_partial(target, like = true, load_voters=false) |
4 | vote = like ? 1 : -1 | 4 | vote = like ? 1 : -1 |
5 | + | ||
5 | like_action = like ? 'like' : 'dislike' | 6 | like_action = like ? 'like' : 'dislike' |
6 | type = target.kind_of?(Article) ? 'article' : target.kind_of?(Comment) ? 'comment' : nil | 7 | type = target.kind_of?(Article) ? 'article' : target.kind_of?(Comment) ? 'comment' : nil |
8 | + disable_vote = target.archived? ? true : false | ||
7 | 9 | ||
8 | proc do | 10 | proc do |
9 | settings = Noosfero::Plugin::Settings.new(environment, VotePlugin) | 11 | settings = Noosfero::Plugin::Settings.new(environment, VotePlugin) |
@@ -14,7 +16,7 @@ module VotePluginHelper | @@ -14,7 +16,7 @@ module VotePluginHelper | ||
14 | active = user ? (like ? user.voted_for?(target) : user.voted_against?(target)) : false | 16 | active = user ? (like ? user.voted_for?(target) : user.voted_against?(target)) : false |
15 | count = like ? target.votes_for : target.votes_against | 17 | count = like ? target.votes_for : target.votes_against |
16 | 18 | ||
17 | - render(:partial => 'vote/vote', :locals => {:target => target, :active => active, :action => like_action, :count => count, :voters => voters, :vote => vote, :model => type }) | 19 | + render(:partial => 'vote/vote', :locals => {:target => target, :active => active, :action => like_action, :count => count, :voters => voters, :vote => vote, :model => type, :disable_vote => disable_vote }) |
18 | else | 20 | else |
19 | "" | 21 | "" |
20 | end | 22 | end |
plugins/vote/public/style.css
@@ -73,3 +73,12 @@ | @@ -73,3 +73,12 @@ | ||
73 | #article .action .vote-detail img { | 73 | #article .action .vote-detail img { |
74 | vertical-align: bottom; | 74 | vertical-align: bottom; |
75 | } | 75 | } |
76 | + | ||
77 | +.comments-action-bar span.disabled a, | ||
78 | +.comments-action-bar span.disabled a:hover, | ||
79 | +.vote-actions span.disabled a, | ||
80 | +.vote-actions span.disabled a:hover { | ||
81 | + opacity: 0.5; | ||
82 | + pointer-events: none; | ||
83 | + cursor: default; | ||
84 | +} |
plugins/vote/public/vote_actions.js
@@ -16,7 +16,9 @@ function openVotersDialog(div) { | @@ -16,7 +16,9 @@ function openVotersDialog(div) { | ||
16 | clearTimeout(openEvent); | 16 | clearTimeout(openEvent); |
17 | var url = $(div).data('reload_url'); | 17 | var url = $(div).data('reload_url'); |
18 | hideAllVoteDetail(); | 18 | hideAllVoteDetail(); |
19 | - $.post(url); | 19 | + if(url && url != '#'){ |
20 | + $.post(url); | ||
21 | + } | ||
20 | } | 22 | } |
21 | 23 | ||
22 | jQuery('body').live('click', function() { hideAllVoteDetail(); }); | 24 | jQuery('body').live('click', function() { hideAllVoteDetail(); }); |
plugins/vote/test/functional/vote_plugin_profile_controller_test.rb
@@ -32,6 +32,18 @@ class VotePluginProfileControllerTest < ActionController::TestCase | @@ -32,6 +32,18 @@ class VotePluginProfileControllerTest < ActionController::TestCase | ||
32 | assert profile.votes.empty? | 32 | assert profile.votes.empty? |
33 | end | 33 | end |
34 | 34 | ||
35 | + should 'not vote if a target is archived' do | ||
36 | + article = Article.create!(:profile => profile, :name => 'Archived article', :archived => false) | ||
37 | + comment = Comment.create!(:body => 'Comment test', :source => article, :author => profile) | ||
38 | + xhr :post, :vote, :profile => profile.identifier, :id => article.id, :model => 'article', :vote => 1 | ||
39 | + assert !profile.votes.empty? | ||
40 | + | ||
41 | + article.update_attributes(:archived => true) | ||
42 | + xhr :post, :vote, :profile => profile.identifier, :id => comment.id, :model => 'comment', :vote => 1 | ||
43 | + | ||
44 | + assert !profile.voted_for?(comment) | ||
45 | + end | ||
46 | + | ||
35 | should 'like comment' do | 47 | should 'like comment' do |
36 | xhr :post, :vote, :profile => profile.identifier, :id => comment.id, :model => 'comment', :vote => 1 | 48 | xhr :post, :vote, :profile => profile.identifier, :id => comment.id, :model => 'comment', :vote => 1 |
37 | assert profile.voted_for?(comment) | 49 | assert profile.voted_for?(comment) |
plugins/vote/views/vote/_vote.html.erb
1 | <% | 1 | <% |
2 | -url = url_for(:controller => 'vote_plugin_profile', :profile => profile.identifier, :action => :vote, :id => target.id, :model => model, :vote => vote) | ||
3 | -reload_url = url_for(:controller => 'vote_plugin_profile', :profile => profile.identifier, :action => :reload_vote, :id => target.id, :model => model, :vote => vote) | 2 | +if disable_vote |
3 | + url = reload_url = '#' | ||
4 | + class_action = 'disabled' | ||
5 | +else | ||
6 | + url = url_for(:controller => 'vote_plugin_profile', :profile => profile.identifier, :action => :vote, :id => target.id, :model => model, :vote => vote) | ||
7 | + reload_url = url_for(:controller => 'vote_plugin_profile', :profile => profile.identifier, :action => :reload_vote, :id => target.id, :model => model, :vote => vote) | ||
8 | +end | ||
4 | %> | 9 | %> |
5 | 10 | ||
6 | -<span id="vote_<%= model %>_<%= target.id %>_<%= vote %>" data-reload_url=<%= reload_url %> class="vote-action action <%= action %>-action"> | 11 | +<span id="vote_<%= model %>_<%= target.id %>_<%= vote %>" data-reload_url=<%= reload_url %> class="vote-action action <%= action %>-action <%= class_action %>"> |
7 | 12 | ||
8 | <%= link_to content_tag(:span, count, :class=>'like-action-counter') + content_tag(:span, '', :class=>"action-icon #{action}"), url, :class => "#{active ? 'like-action-active':''} #{user ? '':'disabled'} require-login-popup" %> | 13 | <%= link_to content_tag(:span, count, :class=>'like-action-counter') + content_tag(:span, '', :class=>"action-icon #{action}"), url, :class => "#{active ? 'like-action-active':''} #{user ? '':'disabled'} require-login-popup" %> |
9 | 14 |
po/noosfero.pot
@@ -5073,6 +5073,10 @@ msgid_plural "Viewed %{num} times" | @@ -5073,6 +5073,10 @@ msgid_plural "Viewed %{num} times" | ||
5073 | msgstr[0] "" | 5073 | msgstr[0] "" |
5074 | msgstr[1] "" | 5074 | msgstr[1] "" |
5075 | 5075 | ||
5076 | +#: app/views/content_viewer/_publishing_info.html.erb:19 | ||
5077 | +msgid "(Not countable anymore)" | ||
5078 | +msgstr "" | ||
5079 | + | ||
5076 | #: app/views/content_viewer/versions_diff.html.erb:5 | 5080 | #: app/views/content_viewer/versions_diff.html.erb:5 |
5077 | msgid "Changes on \"%s\"" | 5081 | msgid "Changes on \"%s\"" |
5078 | msgstr "" | 5082 | msgstr "" |
po/pt/noosfero.po
@@ -5231,11 +5231,15 @@ msgid "Reply" | @@ -5231,11 +5231,15 @@ msgid "Reply" | ||
5231 | msgstr "Responder" | 5231 | msgstr "Responder" |
5232 | 5232 | ||
5233 | #: app/views/content_viewer/_publishing_info.html.erb:19 | 5233 | #: app/views/content_viewer/_publishing_info.html.erb:19 |
5234 | -msgid "Viewed one time" | ||
5235 | -msgid_plural "Viewed %{num} times" | 5234 | +msgid "Viewed one time %{desc}" |
5235 | +msgid_plural "Viewed %{num} times %{desc}" | ||
5236 | msgstr[0] "Visualizado uma vez" | 5236 | msgstr[0] "Visualizado uma vez" |
5237 | msgstr[1] "Visualizado %{num} vezes" | 5237 | msgstr[1] "Visualizado %{num} vezes" |
5238 | 5238 | ||
5239 | +#: app/views/content_viewer/_publishing_info.html.erb:19 | ||
5240 | +msgid "(Not countable anymore)" | ||
5241 | +msgstr "(Não mais contabilizado)" | ||
5242 | + | ||
5239 | #: app/views/content_viewer/versions_diff.html.erb:5 | 5243 | #: app/views/content_viewer/versions_diff.html.erb:5 |
5240 | msgid "Changes on \"%s\"" | 5244 | msgid "Changes on \"%s\"" |
5241 | msgstr "Mudanças em \"%s\"" | 5245 | msgstr "Mudanças em \"%s\"" |
166 Bytes
273 Bytes
570 Bytes
509 Bytes
public/javascripts/article.js
@@ -200,4 +200,10 @@ jQuery(function($) { | @@ -200,4 +200,10 @@ jQuery(function($) { | ||
200 | 200 | ||
201 | $(".custom_privacy_option").click(show_hide_token_input); | 201 | $(".custom_privacy_option").click(show_hide_token_input); |
202 | 202 | ||
203 | + //Workaround to pointer-events:none CSS3 | ||
204 | + $('a.disabled').click(function(e){ | ||
205 | + e.preventDefault(); | ||
206 | + return false; | ||
207 | + }); | ||
208 | + | ||
203 | }); | 209 | }); |
public/stylesheets/cms.scss
@@ -0,0 +1,67 @@ | @@ -0,0 +1,67 @@ | ||
1 | +//Variables | ||
2 | +$icons-size: 24px; | ||
3 | +$warning-color: #e75e40; | ||
4 | +$description-color: #666; | ||
5 | +$access-types: public, private, archived; | ||
6 | + | ||
7 | +.text-warning { | ||
8 | + text-align: center; | ||
9 | + color: $warning-color; | ||
10 | + font: { | ||
11 | + size: 15px; | ||
12 | + weight: bold; | ||
13 | + } | ||
14 | + | ||
15 | + p i.icon { | ||
16 | + display: inline-block; | ||
17 | + font-size: inherit; | ||
18 | + text-rendering: auto; | ||
19 | + background: url('images/icons-app/warning-icon.png'); | ||
20 | + vertical-align: middle; | ||
21 | + margin-top: -5px; | ||
22 | + width: $icons-size; | ||
23 | + height: $icons-size; | ||
24 | + border: none; | ||
25 | + } | ||
26 | +} | ||
27 | + | ||
28 | +#edit-article-options { | ||
29 | + | ||
30 | + .access-itens .access-item { | ||
31 | + input,label { | ||
32 | + cursor: pointer; | ||
33 | + } | ||
34 | + } | ||
35 | + | ||
36 | + .access-item { | ||
37 | + margin: 15px 0; | ||
38 | + label { | ||
39 | + font: { | ||
40 | + size: 13px; | ||
41 | + weight: bold; | ||
42 | + } | ||
43 | + } | ||
44 | + } | ||
45 | + | ||
46 | + @each $access_type in $access-types { | ||
47 | + .access-#{$access_type}-icon, .access-#{$access_type}-icon { | ||
48 | + display: inline-block; | ||
49 | + margin-right: 5px; | ||
50 | + width: $icons-size; | ||
51 | + height: $icons-size; | ||
52 | + vertical-align: middle; | ||
53 | + background-image: url('images/icons-app/article-#{$access_type}-icon.png'); | ||
54 | + } | ||
55 | + } | ||
56 | + | ||
57 | + .access-note { | ||
58 | + display: block; | ||
59 | + margin: 0; | ||
60 | + color: $description-color; | ||
61 | + margin-left: 50px; | ||
62 | + font: { | ||
63 | + size: 12px; | ||
64 | + weight: normal; | ||
65 | + } | ||
66 | + } | ||
67 | +} |
test/functional/cms_controller_test.rb
@@ -694,6 +694,34 @@ class CmsControllerTest < ActionController::TestCase | @@ -694,6 +694,34 @@ class CmsControllerTest < ActionController::TestCase | ||
694 | end | 694 | end |
695 | end | 695 | end |
696 | 696 | ||
697 | + should "marks a article like archived" do | ||
698 | + article = create(Article, :profile => profile, :name => 'test', :published => true, :archived => false) | ||
699 | + | ||
700 | + post :edit, :profile => profile.identifier, :id => article.id, :article => {:archived => true} | ||
701 | + get :edit, :profile => profile.identifier, :id => article.id | ||
702 | + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'article[archived]', :id => 'article_archived', :checked => 'checked' } | ||
703 | + | ||
704 | + end | ||
705 | + | ||
706 | + should "try add children into archived folders" do | ||
707 | + folder = create(Folder, :profile => profile, :name => 'test', :published => true, :archived => false) | ||
708 | + article_child = create(Article, :profile => profile, :name => 'test child', :parent_id => folder.id, :published => true, :archived => false) | ||
709 | + | ||
710 | + get :edit, :profile => profile.identifier, :id => folder.id | ||
711 | + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'article[archived]', :id => 'article_archived' } | ||
712 | + | ||
713 | + post :edit, :profile => profile.identifier, :id => folder.id, :article => {:archived => true} | ||
714 | + | ||
715 | + get :edit, :profile => profile.identifier, :id => article_child.id | ||
716 | + assert_tag :tag => 'div', :attributes => { :class => 'text-warning'} | ||
717 | + | ||
718 | + err = assert_raises ActiveRecord::RecordInvalid do | ||
719 | + another_article_child = create(Article, :profile => profile, :name => 'other test child', :parent_id => folder.id, :published => true, :archived => false) | ||
720 | + end | ||
721 | + assert_match 'Parent folder is archived', err.message | ||
722 | + | ||
723 | + end | ||
724 | + | ||
697 | should 'be able to add image with alignment' do | 725 | should 'be able to add image with alignment' do |
698 | post :new, :type => 'TinyMceArticle', :profile => profile.identifier, :article => { :name => 'image-alignment', :body => "the text of the article with image <img src='#' align='right'/> right align..." } | 726 | post :new, :type => 'TinyMceArticle', :profile => profile.identifier, :article => { :name => 'image-alignment', :body => "the text of the article with image <img src='#' align='right'/> right align..." } |
699 | saved = TinyMceArticle.find_by_name('image-alignment') | 727 | saved = TinyMceArticle.find_by_name('image-alignment') |
test/unit/api/articles_test.rb
@@ -138,6 +138,16 @@ class ArticlesTest < ActiveSupport::TestCase | @@ -138,6 +138,16 @@ class ArticlesTest < ActiveSupport::TestCase | ||
138 | assert_equal true, json['vote'] | 138 | assert_equal true, json['vote'] |
139 | end | 139 | end |
140 | 140 | ||
141 | + should 'not perform a vote in a archived article' do | ||
142 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing", :archived => true) | ||
143 | + @params[:value] = 1 | ||
144 | + | ||
145 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | ||
146 | + json = JSON.parse(last_response.body) | ||
147 | + | ||
148 | + assert_equal 400, last_response.status | ||
149 | + end | ||
150 | + | ||
141 | expose_attributes = %w(id body abstract created_at title author profile categories image votes_for votes_against setting position hits start_date end_date tag_list parent children children_count) | 151 | expose_attributes = %w(id body abstract created_at title author profile categories image votes_for votes_against setting position hits start_date end_date tag_list parent children children_count) |
142 | 152 | ||
143 | expose_attributes.each do |attr| | 153 | expose_attributes.each do |attr| |
@@ -520,6 +530,14 @@ class ArticlesTest < ActiveSupport::TestCase | @@ -520,6 +530,14 @@ class ArticlesTest < ActiveSupport::TestCase | ||
520 | assert_equal 1, json['article']['hits'] | 530 | assert_equal 1, json['article']['hits'] |
521 | end | 531 | end |
522 | 532 | ||
533 | + should 'not update hit attribute of a specific child if a article is archived' do | ||
534 | + folder = fast_create(Folder, :profile_id => user.person.id, :archived => true) | ||
535 | + article = fast_create(Article, :parent_id => folder.id, :profile_id => user.person.id) | ||
536 | + get "/api/v1/articles/#{folder.id}/children/#{article.id}?#{params.to_query}" | ||
537 | + json = JSON.parse(last_response.body) | ||
538 | + assert_equal 0, json['article']['hits'] | ||
539 | + end | ||
540 | + | ||
523 | should 'list all events of a community in a given category' do | 541 | should 'list all events of a community in a given category' do |
524 | co = Community.create(identifier: 'my-community', name: 'name-my-community') | 542 | co = Community.create(identifier: 'my-community', name: 'name-my-community') |
525 | c1 = Category.create(environment: Environment.default, name: 'my-category') | 543 | c1 = Category.create(environment: Environment.default, name: 'my-category') |
test/unit/api/comments_test.rb
@@ -66,6 +66,15 @@ class CommentsTest < ActiveSupport::TestCase | @@ -66,6 +66,15 @@ class CommentsTest < ActiveSupport::TestCase | ||
66 | assert_equal body, json['comment']['body'] | 66 | assert_equal body, json['comment']['body'] |
67 | end | 67 | end |
68 | 68 | ||
69 | + should 'not comment an archived article' do | ||
70 | + article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing", :archived => true) | ||
71 | + body = 'My comment' | ||
72 | + params.merge!({:body => body}) | ||
73 | + | ||
74 | + post "/api/v1/articles/#{article.id}/comments?#{params.to_query}" | ||
75 | + assert_equal 400, last_response.status | ||
76 | + end | ||
77 | + | ||
69 | should 'comment creation define the source' do | 78 | should 'comment creation define the source' do |
70 | amount = Comment.count | 79 | amount = Comment.count |
71 | article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") | 80 | article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") |
test/unit/api/search_test.rb
@@ -30,8 +30,7 @@ class SearchTest < ActiveSupport::TestCase | @@ -30,8 +30,7 @@ class SearchTest < ActiveSupport::TestCase | ||
30 | assert_empty json['articles'] | 30 | assert_empty json['articles'] |
31 | end | 31 | end |
32 | 32 | ||
33 | - should 'not list articles of wrong type' do | ||
34 | - Article.delete_all | 33 | + should 'do not list articles of wrong type' do |
35 | fast_create(Article, :profile_id => person.id) | 34 | fast_create(Article, :profile_id => person.id) |
36 | get "/api/v1/search/article?type=TinyMceArticle" | 35 | get "/api/v1/search/article?type=TinyMceArticle" |
37 | json = JSON.parse(last_response.body) | 36 | json = JSON.parse(last_response.body) |
@@ -131,10 +130,8 @@ class SearchTest < ActiveSupport::TestCase | @@ -131,10 +130,8 @@ class SearchTest < ActiveSupport::TestCase | ||
131 | article2.categories<< category2 | 130 | article2.categories<< category2 |
132 | get "/api/v1/search/article?category_ids[]=#{category1.id}&category_ids[]=#{category2.id}" | 131 | get "/api/v1/search/article?category_ids[]=#{category1.id}&category_ids[]=#{category2.id}" |
133 | json = JSON.parse(last_response.body) | 132 | json = JSON.parse(last_response.body) |
134 | - ids = [article1.id, article2.id] | ||
135 | assert_equal 2, json['articles'].count | 133 | assert_equal 2, json['articles'].count |
136 | - assert_includes ids, json['articles'].first["id"] | ||
137 | - assert_includes ids, json['articles'].last["id"] | 134 | + assert_equivalent [article1.id, article2.id], json['articles'].map{|a| a['id']} |
138 | end | 135 | end |
139 | 136 | ||
140 | end | 137 | end |
test/unit/api/session_test.rb
@@ -198,4 +198,40 @@ class SessionTest < ActiveSupport::TestCase | @@ -198,4 +198,40 @@ class SessionTest < ActiveSupport::TestCase | ||
198 | assert_equal 404, last_response.status | 198 | assert_equal 404, last_response.status |
199 | end | 199 | end |
200 | 200 | ||
201 | + should 'not return private token when the registered user is inactive' do | ||
202 | + params = {:login => "newuserapi", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com" } | ||
203 | + post "/api/v1/register?#{params.to_query}" | ||
204 | + assert_equal 201, last_response.status | ||
205 | + json = JSON.parse(last_response.body) | ||
206 | + assert !User['newuserapi'].activated? | ||
207 | + assert !json['user']['activated'] | ||
208 | + assert !json['user']['private_token'].present? | ||
209 | + end | ||
210 | + | ||
211 | + should 'resend activation code for an inactive user' do | ||
212 | + user = create_user | ||
213 | + params = {:value => user.login} | ||
214 | + Delayed::Job.destroy_all | ||
215 | + assert_difference 'ActionMailer::Base.deliveries.size' do | ||
216 | + post "/api/v1/resend_activation_code?#{params.to_query}" | ||
217 | + process_delayed_job_queue | ||
218 | + end | ||
219 | + json = JSON.parse(last_response.body) | ||
220 | + assert !json['users'].first['activated'] | ||
221 | + assert_equal user.email, ActionMailer::Base.deliveries.last['to'].to_s | ||
222 | + end | ||
223 | + | ||
224 | + should 'not resend activation code for an active user' do | ||
225 | + user = create_user | ||
226 | + params = {:value => user.login} | ||
227 | + user.activate | ||
228 | + Delayed::Job.destroy_all | ||
229 | + assert_no_difference 'ActionMailer::Base.deliveries.size' do | ||
230 | + post "/api/v1/resend_activation_code?#{params.to_query}" | ||
231 | + process_delayed_job_queue | ||
232 | + end | ||
233 | + json = JSON.parse(last_response.body) | ||
234 | + assert json['users'].first['activated'] | ||
235 | + end | ||
236 | + | ||
201 | end | 237 | end |
test/unit/article_test.rb
@@ -2179,10 +2179,21 @@ class ArticleTest < ActiveSupport::TestCase | @@ -2179,10 +2179,21 @@ class ArticleTest < ActiveSupport::TestCase | ||
2179 | a3 = fast_create(Article) | 2179 | a3 = fast_create(Article) |
2180 | Article.hit([a1, a2, a3]) | 2180 | Article.hit([a1, a2, a3]) |
2181 | Article.hit([a2, a3]) | 2181 | Article.hit([a2, a3]) |
2182 | + | ||
2182 | assert_equal [1, 2, 2], [a1.hits, a2.hits, a3.hits] | 2183 | assert_equal [1, 2, 2], [a1.hits, a2.hits, a3.hits] |
2183 | assert_equal [1, 2, 2], [a1.reload.hits, a2.reload.hits, a3.reload.hits] | 2184 | assert_equal [1, 2, 2], [a1.reload.hits, a2.reload.hits, a3.reload.hits] |
2184 | end | 2185 | end |
2185 | 2186 | ||
2187 | + should 'not update hit attribute of archiveds articles' do | ||
2188 | + a1 = fast_create(Article) | ||
2189 | + a2 = fast_create(Article, :archived => true) | ||
2190 | + a3 = fast_create(Article, :archived => true) | ||
2191 | + Article.hit([a1, a2, a3]) | ||
2192 | + | ||
2193 | + assert_equal [1, 0, 0], [a1.hits, a2.hits, a3.hits] | ||
2194 | + assert_equal [1, 0, 0], [a1.reload.hits, a2.reload.hits, a3.reload.hits] | ||
2195 | + end | ||
2196 | + | ||
2186 | should 'vote in a article' do | 2197 | should 'vote in a article' do |
2187 | article = create(Article, :name => 'Test', :profile => profile, :last_changed_by => nil) | 2198 | article = create(Article, :name => 'Test', :profile => profile, :last_changed_by => nil) |
2188 | profile.vote(article, 5) | 2199 | profile.vote(article, 5) |
@@ -2241,4 +2252,25 @@ class ArticleTest < ActiveSupport::TestCase | @@ -2241,4 +2252,25 @@ class ArticleTest < ActiveSupport::TestCase | ||
2241 | assert !a.display_preview? | 2252 | assert !a.display_preview? |
2242 | end | 2253 | end |
2243 | 2254 | ||
2255 | + should 'check if a article is archived' do | ||
2256 | + folder = Folder.create!(:name => 'Parent Archived', :profile => profile) | ||
2257 | + a1 = Article.create!(:name => 'Test', :profile => profile, :parent_id => folder.id, :archived => false) | ||
2258 | + a2 = Article.create!(:name => 'Test 2', :profile => profile, :archived => true) | ||
2259 | + folder.update_attributes(:archived => true) | ||
2260 | + a1.reload | ||
2261 | + | ||
2262 | + assert a1.archived? | ||
2263 | + assert a2.archived? | ||
2264 | + end | ||
2265 | + | ||
2266 | + should 'try add a child article to a archived folder' do | ||
2267 | + folder = Folder.create!(:name => 'Parent Archived', :profile => profile, :archived => true) | ||
2268 | + | ||
2269 | + err = assert_raises ActiveRecord::RecordInvalid do | ||
2270 | + a1 = Article.create!(:name => 'Test', :profile => profile, :parent_id => folder.id, :archived => false) | ||
2271 | + end | ||
2272 | + | ||
2273 | + assert_match 'Parent folder is archived', err.message | ||
2274 | + end | ||
2275 | + | ||
2244 | end | 2276 | end |
test/unit/comment_test.rb
@@ -95,6 +95,17 @@ class CommentTest < ActiveSupport::TestCase | @@ -95,6 +95,17 @@ class CommentTest < ActiveSupport::TestCase | ||
95 | assert_equal cc + 1, ActionTracker::Record.find(activity.id).comments_count | 95 | assert_equal cc + 1, ActionTracker::Record.find(activity.id).comments_count |
96 | end | 96 | end |
97 | 97 | ||
98 | + should 'try add a comment to a archived article' do | ||
99 | + person = fast_create(Person) | ||
100 | + article = Article.create!(:name => 'Test', :profile => person, :archived => true) | ||
101 | + | ||
102 | + err = assert_raises ActiveRecord::RecordInvalid do | ||
103 | + comment = create(Comment, :source => article, :author_id => person.id) | ||
104 | + end | ||
105 | + | ||
106 | + assert_match 'Article associated with this comment is achived', err.message | ||
107 | + end | ||
108 | + | ||
98 | should 'provide author name for authenticated authors' do | 109 | should 'provide author name for authenticated authors' do |
99 | owner = create_user('testuser').person | 110 | owner = create_user('testuser').person |
100 | assert_equal 'testuser', build(Comment, :author => owner).author_name | 111 | assert_equal 'testuser', build(Comment, :author => owner).author_name |
test/unit/user_test.rb
@@ -756,6 +756,28 @@ class UserTest < ActiveSupport::TestCase | @@ -756,6 +756,28 @@ class UserTest < ActiveSupport::TestCase | ||
756 | assert_equal 'quire', user.person.name | 756 | assert_equal 'quire', user.person.name |
757 | end | 757 | end |
758 | 758 | ||
759 | + should 'deliver e-mail with activation code when resend was requested and user was not activated' do | ||
760 | + user = new_user :email => 'pending@activation.com' | ||
761 | + activation_code = user.activation_code | ||
762 | + Delayed::Job.destroy_all | ||
763 | + assert_difference 'ActionMailer::Base.deliveries.size', 1 do | ||
764 | + user.resend_activation_code | ||
765 | + process_delayed_job_queue | ||
766 | + end | ||
767 | + assert_not_equal activation_code, user.reload.activation_code | ||
768 | + assert_equal 'pending@activation.com', ActionMailer::Base.deliveries.last['to'].to_s | ||
769 | + end | ||
770 | + | ||
771 | + should 'not deliver e-mail with activation code when resend was requested and user was activated' do | ||
772 | + user = new_user :email => 'pending@activation.com' | ||
773 | + user.activate | ||
774 | + Delayed::Job.destroy_all | ||
775 | + assert_no_difference 'ActionMailer::Base.deliveries.size' do | ||
776 | + user.resend_activation_code | ||
777 | + process_delayed_job_queue | ||
778 | + end | ||
779 | + end | ||
780 | + | ||
759 | protected | 781 | protected |
760 | def new_user(options = {}) | 782 | def new_user(options = {}) |
761 | user = User.new({ :login => 'quire', :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options)) | 783 | user = User.new({ :login => 'quire', :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options)) |