Commit 73806727f3564512f7d9de5236ffb1931e0c83d8
Committed by
Antonio Terceiro
1 parent
56b351f7
Exists in
master
and in
29 other branches
A not logged user can ask to publish an article.
(ActionItem1732)
Showing
11 changed files
with
305 additions
and
10 deletions
Show diff stats
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -14,7 +14,8 @@ class CmsController < MyProfileController |
14 | 14 | end |
15 | 15 | end |
16 | 16 | |
17 | - protect_if :except => [:set_home_page, :edit, :destroy, :publish] do |c, user, profile| | |
17 | + before_filter :login_required, :except => [:suggest_an_article] | |
18 | + protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish] do |c, user, profile| | |
18 | 19 | user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile)) |
19 | 20 | end |
20 | 21 | |
... | ... | @@ -282,6 +283,18 @@ class CmsController < MyProfileController |
282 | 283 | end |
283 | 284 | end |
284 | 285 | |
286 | + def suggest_an_article | |
287 | + @back_to = params[:back_to] || request.referer || url_for(profile.public_profile_url) | |
288 | + @task = SuggestArticle.new(params[:task]) | |
289 | + if request.post? | |
290 | + @task.target = profile | |
291 | + if @task.save | |
292 | + session[:notice] = _('You make your suggestion successfully. Please wait the article approval.') | |
293 | + redirect_to @back_to | |
294 | + end | |
295 | + end | |
296 | + end | |
297 | + | |
285 | 298 | def media_listing |
286 | 299 | if params[:image_folder_id] |
287 | 300 | folder = profile.articles.find(params[:image_folder_id]) if !params[:image_folder_id].blank? | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -1177,4 +1177,13 @@ module ApplicationHelper |
1177 | 1177 | concat(content_tag('div', wrapper + tag('br', :style => 'clear: both;'), { :class => 'comment-balloon ' + classes.to_s }.merge(options)), block.binding) |
1178 | 1178 | end |
1179 | 1179 | |
1180 | + def display_source_info(page) | |
1181 | + if !page.source.blank? | |
1182 | + source_url = link_to(page.source_name.blank? ? page.source : page.source_name, page.source) | |
1183 | + elsif page.reference_article | |
1184 | + source_url = link_to(page.reference_article.profile.name, page.reference_article.url) | |
1185 | + end | |
1186 | + content_tag(:div, _('Source: %s') % source_url, :id => 'article-source') unless source_url.nil? | |
1187 | + end | |
1188 | + | |
1180 | 1189 | end | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +class SuggestArticle < Task | |
2 | + | |
3 | + has_captcha | |
4 | + | |
5 | + serialize :data, Hash | |
6 | + acts_as_having_settings :field => :data | |
7 | + | |
8 | + validates_presence_of :target_id, :article_name, :email, :name, :article_body | |
9 | + | |
10 | + def description | |
11 | + _('%{email} suggested to publish "%{article}" on %{community}') % { :email => email, :article => article_name, :community => target.name } | |
12 | + end | |
13 | + | |
14 | + settings_items :email, :type => String | |
15 | + settings_items :name, :type => String | |
16 | + settings_items :article_name, :type => String | |
17 | + settings_items :article_body, :type => String | |
18 | + settings_items :article_abstract, :type => String | |
19 | + settings_items :article_parent_id, :type => String | |
20 | + settings_items :source, :type => String | |
21 | + | |
22 | + def perform | |
23 | + TinyMceArticle.create!(:profile => target, :name => article_name, :body => article_body, :abstract => article_abstract, :parent_id => article_parent_id, :source => source, :source_name => name) | |
24 | + end | |
25 | + | |
26 | +end | ... | ... |
... | ... | @@ -0,0 +1,41 @@ |
1 | +<%= error_messages_for 'task' %> | |
2 | + | |
3 | +<%= required_fields_message %> | |
4 | + | |
5 | +<%= render :file => 'shared/tiny_mce' %> | |
6 | + | |
7 | +<% labelled_form_for 'task', @task do |f| %> | |
8 | + | |
9 | + <%= required labelled_form_field(_('Title'), text_field(:task, 'article_name')) %> | |
10 | + | |
11 | + <%= labelled_form_field(_('Url Source'), text_field(:task, 'source')) %> | |
12 | + | |
13 | + <%= required labelled_form_field(_('Name'), text_field(:task, 'name')) %> | |
14 | + | |
15 | + <%= required labelled_form_field(_('Email'), text_field(:task, 'email')) %> | |
16 | + | |
17 | + <br style="clear: both;"/> | |
18 | + <%= button :add, _("Lead"), '#', :id => "lead-button", :style => "margin-left: 0px;" %> | |
19 | + <em><%= _('Used when a short version your text is needed.') %></em> | |
20 | + | |
21 | + <div id="article-lead"> | |
22 | + <%= labelled_form_field(_('Lead'), text_area(:task , 'article_abstract', :style => 'width: 100%; height: 300px;')) %> | |
23 | + </div> | |
24 | + <div style="margin-top: 10px;"> | |
25 | + <%= labelled_form_field(_('Text'), text_area(:task, 'article_body', :style => 'width:100%')) %> | |
26 | + </div> | |
27 | + | |
28 | + <div id="captcha"> | |
29 | + <%= labelled_form_field(_("What is the result of '%s = ?'") % @task.captcha.task, text_field(:task, 'captcha_solution')) %> | |
30 | + <%= hidden_field :task, :captcha_secret %> | |
31 | + <br style="clear: both;"> | |
32 | + </div> | |
33 | + | |
34 | + <%= hidden_field_tag('back_to', @back_to) %> | |
35 | + <% button_bar do %> | |
36 | + <%= submit_button :save, _('Save') %> | |
37 | + <%= button :cancel, _('Cancel'), @back_to %> | |
38 | + <% end %> | |
39 | +<% end %> | |
40 | + | |
41 | +<%= javascript_include_tag 'article' %> | ... | ... |
app/views/content_viewer/view_page.rhtml
... | ... | @@ -45,6 +45,8 @@ |
45 | 45 | <%= button('upload-file', _('Upload files'), :controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent)) %> |
46 | 46 | <% end %> |
47 | 47 | </div> |
48 | + <% else %> | |
49 | + <%= link_to content_tag( 'span', _('Suggest an article') ), profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}), :class => 'button with-text icon-new' %> | |
48 | 50 | <% end %> |
49 | 51 | <div id="article-header"> |
50 | 52 | <%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %> |
... | ... | @@ -89,15 +91,7 @@ |
89 | 91 | </div> |
90 | 92 | <% end %> |
91 | 93 | |
92 | -<% if ! @page.source.nil? && ! @page.source.empty?%> | |
93 | -<div id="article-source"> | |
94 | - <%= _('Source: %s') % link_to(@page.source, @page.source) %> | |
95 | -</div> | |
96 | -<% elsif @page.reference_article %> | |
97 | -<div id="article-source"> | |
98 | - <%= _('Source: %s') % link_to(@page.reference_article.profile.name, @page.reference_article.url) %> | |
99 | -</div> | |
100 | -<% end %> | |
94 | +<%= display_source_info(@page) %> | |
101 | 95 | |
102 | 96 | <% |
103 | 97 | # AddThis Button | ... | ... |
... | ... | @@ -0,0 +1,41 @@ |
1 | +<h2><%= _('Processing task: %s') % task.description %></h2> | |
2 | + | |
3 | +<%= render :file => 'shared/tiny_mce' %> | |
4 | + | |
5 | +<% form_for('task', task, :url => { :action => 'close', :id => task.id}) do |f| %> | |
6 | + | |
7 | + <p> <%= label_tag(_("Sent by: %s") % task.name) %> </p> | |
8 | + <p><%= label_tag(_("Email: %s") % task.email) %> </p> | |
9 | + <p><%= label_tag(_("Source: %s") % task.source) %> </p> | |
10 | + | |
11 | + <%= required labelled_form_field(_('Title'), text_field_tag('task[article_name]', task.article_name)) %> | |
12 | + | |
13 | + <%= select_folder(_('Select the folder where the article must be published'), 'task', 'article_parent_id', task.target.folders) %> | |
14 | + | |
15 | + | |
16 | + <br style="clear: both;"/> | |
17 | + <%= button :add, _("Lead"), '#', :id => "lead-button", :style => "margin-left: 0px;" %> | |
18 | + <em><%= _('Used when a short version your text is needed.') %></em> | |
19 | + | |
20 | + <div id="article-lead"> | |
21 | + <%= labelled_form_field(_('Lead'), text_area_tag('task[article_abstract]', task.article_abstract, :style => 'width: 100%; height: 300px;')) %> | |
22 | + </div> | |
23 | + <div style="margin-top: 10px;"> | |
24 | + <%= labelled_form_field(_('Text'), text_area_tag('task[article_body]', task.article_body, :style => 'width:100%')) %> | |
25 | + </div> | |
26 | + | |
27 | + <div> | |
28 | + <%= labelled_radio_button _('OK'), :decision, 'finish', true, :onclick => "if(this.checked) $('rejection-field-#{task.id}').style.display='none'" %> | |
29 | + </div> | |
30 | + <div> | |
31 | + <%= labelled_radio_button _('Cancel'), :decision, 'cancel', false, :onclick => "if(this.checked) $('rejection-field-#{task.id}').style.display='block'" %> | |
32 | + </div> | |
33 | + | |
34 | + <% button_bar do %> | |
35 | + <%= submit_button(:ok, _('OK')) %> | |
36 | + <% end %> | |
37 | + | |
38 | +<% end %> | |
39 | + | |
40 | +<%= javascript_include_tag 'article' %> | |
41 | + | ... | ... |
db/migrate/20101209001631_add_source_name_to_articles.rb
0 → 100644
... | ... | @@ -0,0 +1,11 @@ |
1 | +class AddSourceNameToArticles < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + add_column :articles, :source_name, :string, :null => true | |
4 | + add_column :article_versions, :source_name, :string, :null => true | |
5 | + end | |
6 | + | |
7 | + def self.down | |
8 | + remove_column :articles, :source_name | |
9 | + remove_column :article_versions, :source_name | |
10 | + end | |
11 | +end | ... | ... |
public/stylesheets/application.css
... | ... | @@ -5237,3 +5237,17 @@ h1#agenda-title { |
5237 | 5237 | .forum-posts .pagination { |
5238 | 5238 | margin-top: 20px; |
5239 | 5239 | } |
5240 | + | |
5241 | +#captcha input { | |
5242 | + border: 1px solid #ccc; | |
5243 | + margin: 4px 0px 2px 10px !important; | |
5244 | + padding: 0px !important; | |
5245 | + width: 150px !important; | |
5246 | + font-size: 24px; | |
5247 | + float: left; | |
5248 | +} | |
5249 | + | |
5250 | +#captcha label{ | |
5251 | + float: left; | |
5252 | + font-size: 24px; | |
5253 | +} | ... | ... |
test/functional/cms_controller_test.rb
... | ... | @@ -1410,4 +1410,36 @@ class CmsControllerTest < Test::Unit::TestCase |
1410 | 1410 | assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/upload_files?parent_id=#{profile.forum.id}"} |
1411 | 1411 | end |
1412 | 1412 | |
1413 | + should 'not logged in to suggest an article' do | |
1414 | + logout | |
1415 | + get :suggest_an_article, :profile => profile.identifier, :back_to => 'action_view' | |
1416 | + | |
1417 | + assert_template 'suggest_an_article' | |
1418 | + end | |
1419 | + | |
1420 | + should 'create a task suggest task to a profile' do | |
1421 | + c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true) | |
1422 | + | |
1423 | + SuggestArticle.any_instance.stubs(:skip_captcha?).returns(true) | |
1424 | + assert_difference SuggestArticle, :count do | |
1425 | + post :suggest_an_article, :profile => c.identifier, :back_to => 'action_view', :task => {:article_name => 'some name', :article_body => 'some body', :email => 'some@localhost.com', :name => 'some name'} | |
1426 | + end | |
1427 | + end | |
1428 | + | |
1429 | + should 'suggest an article from a profile' do | |
1430 | + c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true) | |
1431 | + get :suggest_an_article, :profile => c.identifier, :back_to => c.identifier | |
1432 | + assert_response :success | |
1433 | + assert_template 'suggest_an_article' | |
1434 | + assert_tag :tag => 'input', :attributes => { :value => c.identifier, :id => 'back_to' } | |
1435 | + end | |
1436 | + | |
1437 | + should 'suggest an article accessing the url directly' do | |
1438 | + c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true) | |
1439 | + get :suggest_an_article, :profile => c.identifier | |
1440 | + assert_response :success | |
1441 | + assert_template 'suggest_an_article' | |
1442 | + assert_tag :tag => 'input', :attributes => { :value => "https://colivre.net/profile/test_comm", :id => 'back_to' } | |
1443 | + end | |
1444 | + | |
1413 | 1445 | end | ... | ... |
test/functional/tasks_controller_test.rb
... | ... | @@ -237,4 +237,29 @@ class TasksControllerTest < Test::Unit::TestCase |
237 | 237 | assert_equal Task::Status::CANCELLED, task.status |
238 | 238 | end |
239 | 239 | |
240 | + should 'create TinyMceArticle article after finish approve suggested article task' do | |
241 | + TinyMceArticle.destroy_all | |
242 | + c = fast_create(Community) | |
243 | + c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id)) | |
244 | + @controller.stubs(:profile).returns(c) | |
245 | + SuggestArticle.skip_captcha! | |
246 | + t = SuggestArticle.create!(:article_name => 'test name', :article_body => 'test body', :name => 'some name', :email => 'test@localhost.com', :target => c) | |
247 | + | |
248 | + post :close, :decision => 'finish', :id => t.id, :task => {} | |
249 | + assert_not_nil TinyMceArticle.find(:first) | |
250 | + end | |
251 | + | |
252 | + should "change the article's attributes on suggested article task approval" do | |
253 | + TinyMceArticle.destroy_all | |
254 | + c = fast_create(Community) | |
255 | + c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id)) | |
256 | + @controller.stubs(:profile).returns(c) | |
257 | + SuggestArticle.skip_captcha! | |
258 | + t = SuggestArticle.create!(:article_name => 'test name', :article_body => 'test body', :name => 'some name', :email => 'test@localhost.com', :target => c) | |
259 | + | |
260 | + post :close, :decision => 'finish', :id => t.id, :task => {:article_name => 'new name', :article_body => 'new body'} | |
261 | + assert_equal 'new name', TinyMceArticle.find(:first).name | |
262 | + assert_equal 'new body', TinyMceArticle.find(:first).body | |
263 | + end | |
264 | + | |
240 | 265 | end | ... | ... |
... | ... | @@ -0,0 +1,89 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class SuggestArticleTest < ActiveSupport::TestCase | |
4 | + | |
5 | + def setup | |
6 | + ActionMailer::Base.delivery_method = :test | |
7 | + ActionMailer::Base.perform_deliveries = true | |
8 | + ActionMailer::Base.deliveries = [] | |
9 | + @profile = create_user('test_user').person | |
10 | + end | |
11 | + attr_reader :profile | |
12 | + | |
13 | + should 'have the article_name' do | |
14 | + t = SuggestArticle.new | |
15 | + assert !t.errors.invalid?(:article_name) | |
16 | + t.valid? | |
17 | + assert t.errors.invalid?(:article_name) | |
18 | + end | |
19 | + | |
20 | + should 'have the article_body' do | |
21 | + t = SuggestArticle.new | |
22 | + assert !t.errors.invalid?(:article_body) | |
23 | + t.valid? | |
24 | + assert t.errors.invalid?(:article_body) | |
25 | + end | |
26 | + | |
27 | + should 'have the email' do | |
28 | + t = SuggestArticle.new | |
29 | + assert !t.errors.invalid?(:email) | |
30 | + t.valid? | |
31 | + assert t.errors.invalid?(:email) | |
32 | + end | |
33 | + | |
34 | + should 'have the name' do | |
35 | + t = SuggestArticle.new | |
36 | + assert !t.errors.invalid?(:name) | |
37 | + t.valid? | |
38 | + assert t.errors.invalid?(:name) | |
39 | + end | |
40 | + | |
41 | + should 'have the target_id' do | |
42 | + t = SuggestArticle.new | |
43 | + assert !t.errors.invalid?(:target_id) | |
44 | + t.valid? | |
45 | + assert t.errors.invalid?(:target_id) | |
46 | + end | |
47 | + | |
48 | + should 'have the captcha_solution be solved' do | |
49 | + t = SuggestArticle.new | |
50 | + assert !t.errors.invalid?(:captcha_solution) | |
51 | + t.valid? | |
52 | + assert t.errors.invalid?(:captcha_solution) | |
53 | + | |
54 | + t.skip_captcha! | |
55 | + assert t.skip_captcha? | |
56 | + t.valid? | |
57 | + assert !t.errors.invalid?(:captcha_solution) | |
58 | + end | |
59 | + | |
60 | + should 'have the article_abstract' do | |
61 | + t = SuggestArticle.new | |
62 | + assert t.respond_to?(:article_abstract) | |
63 | + end | |
64 | + | |
65 | + should 'have the article_parent_id' do | |
66 | + t = SuggestArticle.new | |
67 | + assert t.respond_to?(:article_parent_id) | |
68 | + end | |
69 | + | |
70 | + should 'source be defined' do | |
71 | + t = SuggestArticle.new | |
72 | + assert t.respond_to?(:source) | |
73 | + end | |
74 | + | |
75 | + should 'create an article on with perfom method' do | |
76 | + t = SuggestArticle.new | |
77 | + name = 'some name' | |
78 | + body = 'some body' | |
79 | + abstract = 'some abstract' | |
80 | + t.article_name = name | |
81 | + t.article_body = body | |
82 | + t.article_abstract = abstract | |
83 | + t.target = @profile | |
84 | + count = TinyMceArticle.count | |
85 | + t.perform | |
86 | + assert_equal count + 1, TinyMceArticle.count | |
87 | + end | |
88 | + | |
89 | +end | ... | ... |