Commit d755b3b712e5a0a2d580d30c5ec1668ae3d58d43
Committed by
Marcos Pereira
1 parent
e58c017a
Exists in
staging
and in
32 other branches
New feature archive articles
- Avoid create comments, associate children articles and perform votes on archived articles - Update db/schema -Signed-off-by: Michel Felipe de Oliveira Ferreira <michel.ferreira@serpro.gov.br> -Signed-off-by: Gustavo Jaruga Cruz <darksshades@gmail.com> -Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com> (cherry picked from commit 144d608f15e2864e8053d384e871699d314a9283)
Showing
28 changed files
with
295 additions
and
18 deletions
Show diff stats
app/helpers/article_helper.rb
... | ... | @@ -15,6 +15,12 @@ module ArticleHelper |
15 | 15 | topic_creation(@article) + |
16 | 16 | content_tag('h4', _('Options')) + |
17 | 17 | content_tag('div', |
18 | + content_tag( | |
19 | + 'div', | |
20 | + check_box(:article, :archived) + | |
21 | + content_tag('label', _('Do not allow new content on this article and its children'), :for => 'article_archived_true') | |
22 | + ) + | |
23 | + | |
18 | 24 | (article.profile.has_members? ? |
19 | 25 | content_tag( |
20 | 26 | 'div', |
... | ... | @@ -63,13 +69,20 @@ module ArticleHelper |
63 | 69 | content_tag('div', |
64 | 70 | content_tag('div', |
65 | 71 | radio_button(:article, :published, true) + |
66 | - content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true') | |
72 | + content_tag('span', ' ', :class => 'access-public-icon') + | |
73 | + content_tag('label', _('Public'), :for => 'article_published_true') + | |
74 | + content_tag('span', _('Visible to other people'), :class => 'access-note'), | |
75 | + :class => 'access-item' | |
67 | 76 | ) + |
68 | 77 | content_tag('div', |
69 | 78 | radio_button(:article, :published, false) + |
70 | - content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private") | |
79 | + content_tag('span', ' ', :class => 'access-private-icon') + | |
80 | + content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private") + | |
81 | + content_tag('span', _('Limit visibility of this article'), :class => 'access-note'), | |
82 | + :class => 'access-item' | |
71 | 83 | ) + |
72 | - privacity_exceptions(article, tokenized_children) | |
84 | + privacity_exceptions(article, tokenized_children), | |
85 | + :class => 'access-itens' | |
73 | 86 | ) |
74 | 87 | end |
75 | 88 | ... | ... |
app/helpers/folder_helper.rb
... | ... | @@ -59,7 +59,13 @@ module FolderHelper |
59 | 59 | @article = article |
60 | 60 | |
61 | 61 | visibility_options(article,tokenized_children) + |
62 | + content_tag('h4', _('Options')) + | |
62 | 63 | content_tag('div', |
64 | + content_tag( | |
65 | + 'div', | |
66 | + check_box(:article, :archived) + | |
67 | + content_tag('label', _('Do not allow new content on this article and its children'), :for => 'article_archived_true') | |
68 | + ) + | |
63 | 69 | hidden_field_tag('article[accept_comments]', 0) |
64 | 70 | ) |
65 | 71 | end | ... | ... |
app/models/article.rb
... | ... | @@ -8,7 +8,7 @@ class Article < ActiveRecord::Base |
8 | 8 | :accept_comments, :feed, :published, :source, :source_name, |
9 | 9 | :highlighted, :notify_comments, :display_hits, :slug, |
10 | 10 | :external_feed_builder, :display_versions, :external_link, |
11 | - :image_builder, :show_to_followers, | |
11 | + :image_builder, :show_to_followers, :archived, | |
12 | 12 | :author, :display_preview, :published_at, :person_followers |
13 | 13 | |
14 | 14 | acts_as_having_image |
... | ... | @@ -152,6 +152,8 @@ class Article < ActiveRecord::Base |
152 | 152 | validate :no_self_reference |
153 | 153 | validate :no_cyclical_reference, :if => 'parent_id.present?' |
154 | 154 | |
155 | + validate :parent_archived? | |
156 | + | |
155 | 157 | def no_self_reference |
156 | 158 | errors.add(:parent_id, _('self-reference is not allowed.')) if id && parent_id == id |
157 | 159 | end |
... | ... | @@ -499,6 +501,10 @@ class Article < ActiveRecord::Base |
499 | 501 | end |
500 | 502 | end |
501 | 503 | |
504 | + def archived? | |
505 | + (self.parent && self.parent.archived) || self.archived | |
506 | + end | |
507 | + | |
502 | 508 | def self.folder_types |
503 | 509 | ['Folder', 'Blog', 'Forum', 'Gallery'] |
504 | 510 | end |
... | ... | @@ -645,13 +651,21 @@ class Article < ActiveRecord::Base |
645 | 651 | end |
646 | 652 | |
647 | 653 | def hit |
648 | - self.class.connection.execute('update articles set hits = hits + 1 where id = %d' % self.id.to_i) | |
649 | - self.hits += 1 | |
654 | + if !archived? | |
655 | + self.class.connection.execute('update articles set hits = hits + 1 where id = %d' % self.id.to_i) | |
656 | + self.hits += 1 | |
657 | + end | |
650 | 658 | end |
651 | 659 | |
652 | 660 | def self.hit(articles) |
653 | - Article.where(:id => articles.map(&:id)).update_all('hits = hits + 1') | |
654 | - articles.each { |a| a.hits += 1 } | |
661 | + ids = [] | |
662 | + articles.each do |article| | |
663 | + if !article.archived? | |
664 | + ids << article.id | |
665 | + article.hits += 1 | |
666 | + end | |
667 | + end | |
668 | + Article.where(:id => ids).update_all('hits = hits + 1') if !ids.empty? | |
655 | 669 | end |
656 | 670 | |
657 | 671 | def can_display_hits? |
... | ... | @@ -861,4 +875,10 @@ class Article < ActiveRecord::Base |
861 | 875 | sanitizer.sanitize(text) |
862 | 876 | end |
863 | 877 | |
878 | + def parent_archived? | |
879 | + if self.parent_id_changed? && self.parent && self.parent.archived? | |
880 | + errors.add(:parent_folder, N_('is archived!!')) | |
881 | + end | |
882 | + end | |
883 | + | |
864 | 884 | end | ... | ... |
app/models/comment.rb
... | ... | @@ -36,6 +36,8 @@ class Comment < ActiveRecord::Base |
36 | 36 | end |
37 | 37 | end |
38 | 38 | |
39 | + validate :article_archived? | |
40 | + | |
39 | 41 | acts_as_having_settings |
40 | 42 | |
41 | 43 | xss_terminate :only => [ :body, :title, :name ], :on => 'validation' |
... | ... | @@ -218,4 +220,14 @@ class Comment < ActiveRecord::Base |
218 | 220 | user.present? && user == author |
219 | 221 | end |
220 | 222 | |
223 | + def archived? | |
224 | + self.source && self.source.is_a?(Article) && self.source.archived? | |
225 | + end | |
226 | + | |
227 | + protected | |
228 | + | |
229 | + def article_archived? | |
230 | + errors.add(:article, N_('associated with this comment is archived!')) if archived? | |
231 | + end | |
232 | + | |
221 | 233 | end | ... | ... |
app/views/cms/edit.html.erb
1 | 1 | <%= error_messages_for 'article' %> |
2 | 2 | |
3 | +<% if @article.archived? %> | |
4 | + <%= render :partial => 'archived_warning', :locals => {:article => @article} %> | |
5 | +<% end %> | |
3 | 6 | <div class='<%= (@article.display_media_panel? ? 'with_media_panel' : 'no_media_panel') %>'> |
4 | 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 | 29 | <%= expirable_button @page, :locale, content, url %> |
30 | 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 | 36 | <% content = content_tag('span', label_for_clone_article(@page)) %> |
35 | 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}) %> |
... | ... | @@ -66,6 +68,9 @@ |
66 | 68 | <% end %> |
67 | 69 | <%= button_without_text(:feed, _('RSS feed'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %> |
68 | 70 | <%= @plugins.dispatch(:article_header_extra_contents, @page).collect { |content| instance_exec(&content) }.join("") %> |
71 | + <% if @page.archived? %> | |
72 | + <%= render :partial => 'cms/archived_warning', :locals => {:article => @page} %> | |
73 | + <% end %> | |
69 | 74 | <%= render :partial => 'article_title', :locals => {:no_link => true} %> |
70 | 75 | <%= article_translations(@page) %> |
71 | 76 | </div> | ... | ... |
app/views/content_viewer/_publishing_info.html.erb
... | ... | @@ -34,7 +34,7 @@ |
34 | 34 | <div id='article-sub-header'> |
35 | 35 | <% if @page.display_hits? %> |
36 | 36 | <div id="article-hits"> |
37 | - <%= n_('Viewed one time', 'Viewed %{num} times', @page.hits) % { :num => @page.hits } %> | |
37 | + <%= n_('Viewed one time %{desc}', 'Viewed %{num} times %{desc}', @page.hits) % { :num => @page.hits, :desc => @page.archived? ? '<b>'+_('(Not countable anymore)')+'</b>' : '' } %> | |
38 | 38 | </div> |
39 | 39 | <% end %> |
40 | 40 | ... | ... |
app/views/content_viewer/view_page.html.erb
... | ... | @@ -85,7 +85,7 @@ |
85 | 85 | <% end %> |
86 | 86 | </ul> |
87 | 87 | |
88 | - <% if @page.accept_comments? %> | |
88 | + <% if !@page.archived? && @page.accept_comments? %> | |
89 | 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 | 90 | <% end %> |
91 | 91 | </div><!-- end class="comments" --> | ... | ... |
db/schema.rb
... | ... | @@ -167,6 +167,7 @@ ActiveRecord::Schema.define(version: 20160324132518) do |
167 | 167 | t.integer "created_by_id" |
168 | 168 | t.boolean "show_to_followers", default: true |
169 | 169 | t.integer "followers_count", default: 0 |
170 | + t.boolean "archived", default: false | |
170 | 171 | end |
171 | 172 | |
172 | 173 | add_index "articles", ["comments_count"], name: "index_articles_on_comments_count", using: :btree | ... | ... |
... | ... | @@ -0,0 +1,18 @@ |
1 | +require_dependency 'models/vote' | |
2 | + | |
3 | +class Vote | |
4 | + | |
5 | + validate :verify_target_archived | |
6 | + | |
7 | + def verify_target_archived | |
8 | + | |
9 | + if voteable.kind_of?(Article) || voteable.kind_of?(Comment) | |
10 | + if voteable.archived? | |
11 | + errors.add(:base, _("The target is achived and can't accept votes")) | |
12 | + false | |
13 | + end | |
14 | + end | |
15 | + | |
16 | + end | |
17 | + | |
18 | +end | ... | ... |
plugins/vote/lib/vote_plugin_helper.rb
... | ... | @@ -2,8 +2,10 @@ module VotePluginHelper |
2 | 2 | |
3 | 3 | def vote_partial(target, like = true, load_voters=false) |
4 | 4 | vote = like ? 1 : -1 |
5 | + | |
5 | 6 | like_action = like ? 'like' : 'dislike' |
6 | 7 | type = target.kind_of?(Article) ? 'article' : target.kind_of?(Comment) ? 'comment' : nil |
8 | + disable_vote = target.archived? ? true : false | |
7 | 9 | |
8 | 10 | proc do |
9 | 11 | settings = Noosfero::Plugin::Settings.new(environment, VotePlugin) |
... | ... | @@ -14,7 +16,7 @@ module VotePluginHelper |
14 | 16 | active = user ? (like ? user.voted_for?(target) : user.voted_against?(target)) : false |
15 | 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 | 20 | else |
19 | 21 | "" |
20 | 22 | end | ... | ... |
plugins/vote/public/style.css
... | ... | @@ -73,3 +73,12 @@ |
73 | 73 | #article .action .vote-detail img { |
74 | 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 | 16 | clearTimeout(openEvent); |
17 | 17 | var url = $(div).data('reload_url'); |
18 | 18 | hideAllVoteDetail(); |
19 | - $.post(url); | |
19 | + if(url && url != '#'){ | |
20 | + $.post(url); | |
21 | + } | |
20 | 22 | } |
21 | 23 | |
22 | 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 | 32 | assert profile.votes.empty? |
33 | 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 | 47 | should 'like comment' do |
36 | 48 | xhr :post, :vote, :profile => profile.identifier, :id => comment.id, :model => 'comment', :vote => 1 |
37 | 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 | 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 | 5073 | msgstr[0] "" |
5074 | 5074 | msgstr[1] "" |
5075 | 5075 | |
5076 | +#: app/views/content_viewer/_publishing_info.html.erb:19 | |
5077 | +msgid "(Not countable anymore)" | |
5078 | +msgstr "" | |
5079 | + | |
5076 | 5080 | #: app/views/content_viewer/versions_diff.html.erb:5 |
5077 | 5081 | msgid "Changes on \"%s\"" |
5078 | 5082 | msgstr "" | ... | ... |
po/pt/noosfero.po
... | ... | @@ -5231,11 +5231,15 @@ msgid "Reply" |
5231 | 5231 | msgstr "Responder" |
5232 | 5232 | |
5233 | 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 | 5236 | msgstr[0] "Visualizado uma vez" |
5237 | 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 | 5243 | #: app/views/content_viewer/versions_diff.html.erb:5 |
5240 | 5244 | msgid "Changes on \"%s\"" |
5241 | 5245 | msgstr "Mudanças em \"%s\"" | ... | ... |
273 Bytes
570 Bytes
509 Bytes
public/javascripts/article.js
... | ... | @@ -212,4 +212,10 @@ jQuery(function($) { |
212 | 212 | $("#article_published_true").click(show_hide_privacy_options); |
213 | 213 | $(".custom_privacy_option").click(show_hide_token_input); |
214 | 214 | |
215 | + //Workaround to pointer-events:none CSS3 | |
216 | + $('a.disabled').click(function(e){ | |
217 | + e.preventDefault(); | |
218 | + return false; | |
219 | + }); | |
220 | + | |
215 | 221 | }); | ... | ... |
public/stylesheets/cms.scss
... | ... | @@ -0,0 +1,67 @@ |
1 | +//Variables | |
2 | +$icons-size: 24px; | |
3 | +$warning-color: #e75e40; | |
4 | +$description-color: #666; | |
5 | +$access-types: public, private; | |
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 | 694 | end |
695 | 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 | 725 | should 'be able to add image with alignment' do |
698 | 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 | 727 | saved = TinyMceArticle.find_by(name: 'image-alignment') | ... | ... |
test/unit/article_test.rb
... | ... | @@ -2168,10 +2168,21 @@ class ArticleTest < ActiveSupport::TestCase |
2168 | 2168 | a3 = fast_create(Article) |
2169 | 2169 | Article.hit([a1, a2, a3]) |
2170 | 2170 | Article.hit([a2, a3]) |
2171 | + | |
2171 | 2172 | assert_equal [1, 2, 2], [a1.hits, a2.hits, a3.hits] |
2172 | 2173 | assert_equal [1, 2, 2], [a1.reload.hits, a2.reload.hits, a3.reload.hits] |
2173 | 2174 | end |
2174 | 2175 | |
2176 | + should 'not update hit attribute of archiveds articles' do | |
2177 | + a1 = fast_create(Article) | |
2178 | + a2 = fast_create(Article, :archived => true) | |
2179 | + a3 = fast_create(Article, :archived => true) | |
2180 | + Article.hit([a1, a2, a3]) | |
2181 | + | |
2182 | + assert_equal [1, 0, 0], [a1.hits, a2.hits, a3.hits] | |
2183 | + assert_equal [1, 0, 0], [a1.reload.hits, a2.reload.hits, a3.reload.hits] | |
2184 | + end | |
2185 | + | |
2175 | 2186 | should 'vote in a article' do |
2176 | 2187 | article = create(Article, :name => 'Test', :profile => profile, :last_changed_by => nil) |
2177 | 2188 | profile.vote(article, 5) |
... | ... | @@ -2288,5 +2299,25 @@ class ArticleTest < ActiveSupport::TestCase |
2288 | 2299 | assert_equal 10, article.reload.person_followers.count |
2289 | 2300 | end |
2290 | 2301 | |
2302 | + should 'check if a article is archived' do | |
2303 | + folder = Folder.create!(:name => 'Parent Archived', :profile => profile) | |
2304 | + a1 = Article.create!(:name => 'Test', :profile => profile, :parent_id => folder.id, :archived => false) | |
2305 | + a2 = Article.create!(:name => 'Test 2', :profile => profile, :archived => true) | |
2306 | + folder.update_attributes(:archived => true) | |
2307 | + a1.reload | |
2308 | + | |
2309 | + assert a1.archived? | |
2310 | + assert a2.archived? | |
2311 | + end | |
2312 | + | |
2313 | + should 'try add a child article to a archived folder' do | |
2314 | + folder = Folder.create!(:name => 'Parent Archived', :profile => profile, :archived => true) | |
2315 | + | |
2316 | + err = assert_raises ActiveRecord::RecordInvalid do | |
2317 | + a1 = Article.create!(:name => 'Test', :profile => profile, :parent_id => folder.id, :archived => false) | |
2318 | + end | |
2319 | + | |
2320 | + assert_match 'Parent folder is archived', err.message | |
2321 | + end | |
2291 | 2322 | |
2292 | 2323 | end | ... | ... |
test/unit/comment_test.rb
... | ... | @@ -95,6 +95,17 @@ class CommentTest < ActiveSupport::TestCase |
95 | 95 | assert_equal cc + 1, ActionTracker::Record.find(activity.id).comments_count |
96 | 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 archived', err.message | |
107 | + end | |
108 | + | |
98 | 109 | should 'provide author name for authenticated authors' do |
99 | 110 | owner = create_user('testuser').person |
100 | 111 | assert_equal 'testuser', build(Comment, :author => owner).author_name | ... | ... |