Commit 73806727f3564512f7d9de5236ffb1931e0c83d8
Committed by
Antonio Terceiro
1 parent
56b351f7
Exists in
master
and in
22 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 | ... | ... |