Commit 089311f7d65a32404b0a37583f8dd821f1c98fc8

Authored by Carlos Purificação
1 parent ee8510cb
Exists in export-comment-api

Initial version

plugins/comment_paragraph/controllers/profile/comment_paragraph_plugin_profile_controller.rb
... ... @@ -21,4 +21,16 @@ class CommentParagraphPluginProfileController < CommentController
21 21 }
22 22 end
23 23  
  24 + include CommentParagraphPlugin::CommentsReport
  25 +
  26 + def export_comments
  27 + article_id = params[:id]
  28 + article = profile.articles.find(article_id)
  29 + result = export_comments_csv(article)
  30 + filename = "comments_for_article#{article_id}_#{DateTime.now.to_i}.csv"
  31 + send_data result,
  32 + :type => 'text/csv; charset=UTF-8; header=present',
  33 + :disposition => "attachment; filename=#{filename}"
  34 + end
  35 +
24 36 end
... ...
plugins/comment_paragraph/lib/comment_paragraph_plugin.rb
... ... @@ -47,12 +47,19 @@ class CommentParagraphPlugin < Noosfero::Plugin
47 47 def article_extra_toolbar_buttons(article)
48 48 user = context.send :user
49 49 return [] if !article.comment_paragraph_plugin_enabled? || !article.allow_edit?(user) || article.kind_of?(CommentParagraphPlugin::Discussion)
50   - {
  50 + buttons = [
  51 + {
51 52 :title => article.comment_paragraph_plugin_activated? ? _('Deactivate Comments') : _('Activate Comments'),
52 53 :url => {:controller => 'comment_paragraph_plugin_myprofile', :profile => article.profile.identifier, :action => 'toggle_activation', :id => article.id},
53 54 :icon => :toggle_comment_paragraph
54   - }
55   -
  55 + }
  56 + ]
  57 + buttons << {
  58 + :title => _('Export Comments'),
  59 + :url => {:controller => 'comment_paragraph_plugin_profile', :profile => article.profile.identifier, :action => 'export_comments', :id => article.id},
  60 + :icon => :toggle_comment_paragraph
  61 + } if article.comment_paragraph_plugin_activated?
  62 + buttons
56 63 end
57 64  
58 65 def self.api_mount_points
... ...
plugins/comment_paragraph/lib/comment_paragraph_plugin/api.rb
  1 +require_relative 'comments_report'
  2 +
1 3 # Can't be called Api as will result in:
2 4 # warning: toplevel constant Api referenced by CommentParagraphPlugin::Api
3 5 # To fix this CommentParagraphPlugin should be a module
4 6 class CommentParagraphPlugin::API < Grape::API
  7 +
5 8 MAX_PER_PAGE = 20
6 9  
  10 + helpers CommentParagraphPlugin::CommentsReport
  11 +
7 12 resource :articles do
8 13 paginate max_per_page: MAX_PER_PAGE
9 14 get ':id/comment_paragraph_plugin/comments' do
... ... @@ -31,5 +36,16 @@ class CommentParagraphPlugin::API &lt; Grape::API
31 36 comments = select_filtered_collection_of(article, :comments, params)
32 37 comments.group(:paragraph_uuid).count
33 38 end
  39 +
  40 + get ":id/comment_paragraph_plugin/export" do
  41 + article = find_article(environment.articles, params[:id])
  42 + result = export_comments_csv(article)
  43 + filename = "comments_for_article#{article.id}_#{DateTime.now.to_i}.csv"
  44 + content_type 'text/csv; charset=UTF-8; header=present'
  45 + env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
  46 + header 'Content-Disposition', "attachment; filename*=UTF-8''#{CGI.escape(filename)}"
  47 + result
  48 + end
  49 +
34 50 end
35 51 end
... ...
plugins/comment_paragraph/lib/comment_paragraph_plugin/comments_report.rb 0 → 100644
... ... @@ -0,0 +1,53 @@
  1 +require 'csv'
  2 +
  3 +module CommentParagraphPlugin::CommentsReport
  4 +
  5 + #FIXME make this test
  6 + def export_comments_csv(article)
  7 + comments_map = article.comments.group_by { |comment| comment.paragraph_uuid }
  8 + @export = []
  9 + doc = Nokogiri::HTML(article.body)
  10 + paragraph_id = 1
  11 + doc.css("[data-macro-paragraph_uuid]").map do |paragraph|
  12 + uuid = paragraph.attributes['data-macro-paragraph_uuid'].value
  13 + comments_for_paragraph = comments_map[uuid]
  14 + if comments_for_paragraph
  15 + # Put comments for the paragraph
  16 + comments_for_paragraph.each do | comment |
  17 + @export << create_comment_element(comment, paragraph, paragraph_id)
  18 + end
  19 + else # There are no comments for this paragraph
  20 + @export << create_comment_element(nil, paragraph, paragraph_id)
  21 + end
  22 + paragraph_id += 1
  23 + end
  24 + # Now we need to put all other comments that are not attached to a paragraph
  25 + comments_without_paragrah = comments_map[nil] || []
  26 + comments_without_paragrah.each do | comment |
  27 + @export << create_comment_element(comment, nil, nil)
  28 + end
  29 + return _("No comments for article[%{id}]: %{path}\n\n") % {:id => article.id, :path => article.path} if @export.empty?
  30 +
  31 + column_names = @export.first.keys
  32 + CSV.generate(force_quotes: true) do |csv|
  33 + csv << column_names
  34 + @export.each { |x| csv << x.values }
  35 + end
  36 + end
  37 +
  38 + private
  39 +
  40 + def create_comment_element(comment, paragraph, paragraph_id)
  41 + {
  42 + paragraph_id: paragraph_id,
  43 + paragraph_text: paragraph.present? ? paragraph.text.strip : nil,
  44 + comment_id: comment.present? ? comment.id : '-',
  45 + comment_reply_to: comment.present? ? comment.reply_of_id : '-',
  46 + comment_title: comment.present? ? comment.title : '-',
  47 + comment_content: comment.present? ? comment.body : '-',
  48 + comment_author_name: comment.present? ? comment.author_name : '-',
  49 + comment_author_email: comment.present? ? comment.author_email : '-'
  50 + }
  51 + end
  52 +
  53 +end
... ...
plugins/comment_paragraph/test/functional/comment_paragraph_plugin_profile_controller_test.rb
... ... @@ -50,4 +50,18 @@ class CommentParagraphPluginProfileControllerTest &lt; ActionController::TestCase
50 50 assert_select "#comment_paragraph_uuid[value=?]", '0'
51 51 end
52 52  
  53 + should 'export comments as CSV' do
  54 + comment1 = fast_create(Comment, :created_at => Time.now - 1.days, :source_id => article, :author_id => profile, :title => 'a comment', :body => 'a comment', :paragraph_uuid => nil)
  55 + comment2 = fast_create(Comment, :created_at => Time.now - 2.days, :source_id => article, :author_id => profile, :title => 'b comment', :body => 'b comment', :paragraph_uuid => nil)
  56 + xhr :get, :export_comments, :profile => @profile.identifier, :id => article.id
  57 + assert_equal 'text/csv; charset=UTF-8; header=present', @response.content_type
  58 + lines = @response.body.split("\n")
  59 + assert_equal '"paragraph_id","paragraph_text","comment_id","comment_reply_to","comment_title","comment_content","comment_author_name","comment_author_email"', lines.first
  60 + assert_equal "\"\",\"\",\"#{comment2.id}\",\"\",\"b comment\",\"b comment\",\"#{comment2.author_name}\",\"#{comment2.author_email}\"", lines.second
  61 + end
  62 +
  63 + should 'not export any comments as CSV' do
  64 + xhr :get, :export_comments, :profile => @profile.identifier, :id => article.id
  65 + assert_equal "No comments for article[#{article.id}]: #{article.path}", @response.body.split("\n")[0]
  66 + end
53 67 end
... ...
plugins/comment_paragraph/test/unit/api_test.rb
... ... @@ -90,4 +90,18 @@ class APITest &lt; ActiveSupport::TestCase
90 90 assert_equal "CommentParagraphPlugin::Discussion", json["article"]["type"]
91 91 assert json["article"]["setting"]["comment_paragraph_plugin_activate"]
92 92 end
  93 +
  94 + should 'export comments' do
  95 + login_api
  96 + article = fast_create(Article, :profile_id => person.id, :name => "Some thing")
  97 + comment1 = fast_create(Comment, :created_at => Time.now - 1.days, :source_id => article, :title => 'a comment', :body => 'a comment', :paragraph_uuid => nil)
  98 + comment2 = fast_create(Comment, :created_at => Time.now - 2.days, :source_id => article, :title => 'b comment', :body => 'b comment', :paragraph_uuid => nil)
  99 + get "/api/v1/articles/#{article.id}/comment_paragraph_plugin/export?#{params.to_query}"
  100 + assert_equal 200, last_response.status
  101 + assert_equal 'text/csv; charset=UTF-8; header=present', last_response.content_type
  102 + lines = last_response.body.split("\n")
  103 + assert_equal '"paragraph_id","paragraph_text","comment_id","comment_reply_to","comment_title","comment_content","comment_author_name","comment_author_email"', lines.first
  104 + assert_equal "\"\",\"\",\"#{comment2.id}\",\"\",\"b comment\",\"b comment\",\"#{comment2.author_name}\",\"#{comment2.author_email}\"", lines.second
  105 + end
  106 +
93 107 end
... ...
plugins/comment_paragraph/test/unit/comment_paragraph_plugin_test.rb
... ... @@ -71,7 +71,7 @@ class CommentParagraphPluginTest &lt; ActiveSupport::TestCase
71 71 article.expects(:allow_edit?).with(user).returns(true)
72 72 article.expects(:comment_paragraph_plugin_activated?).at_least_once.returns(false)
73 73  
74   - assert_equal 'Activate Comments', plugin.article_extra_toolbar_buttons(article)[:title]
  74 + assert_equal 'Activate Comments', plugin.article_extra_toolbar_buttons(article).first[:title]
75 75 end
76 76  
77 77 should 'display Deactivate Comments title if comment paragraph plugin is deactivated' do
... ... @@ -81,7 +81,17 @@ class CommentParagraphPluginTest &lt; ActiveSupport::TestCase
81 81 article.expects(:allow_edit?).with(user).returns(true)
82 82 article.expects(:comment_paragraph_plugin_activated?).at_least_once.returns(true)
83 83  
84   - assert_equal 'Deactivate Comments', plugin.article_extra_toolbar_buttons(article)[:title]
  84 + assert_equal 'Deactivate Comments', plugin.article_extra_toolbar_buttons(article).first[:title]
  85 + end
  86 +
  87 + should 'display export comments button when comment paragraph plugin is activated' do
  88 + profile = fast_create(Profile)
  89 + article = fast_create(Article, :profile_id => profile.id)
  90 + article.expects(:comment_paragraph_plugin_enabled?).returns(true)
  91 + article.expects(:allow_edit?).with(user).returns(true)
  92 + article.expects(:comment_paragraph_plugin_activated?).at_least_once.returns(true)
  93 +
  94 + assert_includes plugin.article_extra_toolbar_buttons(article).map {|b| b[:title]}, 'Export Comments'
85 95 end
86 96  
87 97 should 'not display button to toggle comment paragraph if article is a discussion' do
... ...