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,4 +21,16 @@ class CommentParagraphPluginProfileController < CommentController
21 } 21 }
22 end 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 end 36 end
plugins/comment_paragraph/lib/comment_paragraph_plugin.rb
@@ -47,12 +47,19 @@ class CommentParagraphPlugin < Noosfero::Plugin @@ -47,12 +47,19 @@ class CommentParagraphPlugin < Noosfero::Plugin
47 def article_extra_toolbar_buttons(article) 47 def article_extra_toolbar_buttons(article)
48 user = context.send :user 48 user = context.send :user
49 return [] if !article.comment_paragraph_plugin_enabled? || !article.allow_edit?(user) || article.kind_of?(CommentParagraphPlugin::Discussion) 49 return [] if !article.comment_paragraph_plugin_enabled? || !article.allow_edit?(user) || article.kind_of?(CommentParagraphPlugin::Discussion)
50 - { 50 + buttons = [
  51 + {
51 :title => article.comment_paragraph_plugin_activated? ? _('Deactivate Comments') : _('Activate Comments'), 52 :title => article.comment_paragraph_plugin_activated? ? _('Deactivate Comments') : _('Activate Comments'),
52 :url => {:controller => 'comment_paragraph_plugin_myprofile', :profile => article.profile.identifier, :action => 'toggle_activation', :id => article.id}, 53 :url => {:controller => 'comment_paragraph_plugin_myprofile', :profile => article.profile.identifier, :action => 'toggle_activation', :id => article.id},
53 :icon => :toggle_comment_paragraph 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 end 63 end
57 64
58 def self.api_mount_points 65 def self.api_mount_points
plugins/comment_paragraph/lib/comment_paragraph_plugin/api.rb
  1 +require_relative 'comments_report'
  2 +
1 # Can't be called Api as will result in: 3 # Can't be called Api as will result in:
2 # warning: toplevel constant Api referenced by CommentParagraphPlugin::Api 4 # warning: toplevel constant Api referenced by CommentParagraphPlugin::Api
3 # To fix this CommentParagraphPlugin should be a module 5 # To fix this CommentParagraphPlugin should be a module
4 class CommentParagraphPlugin::API < Grape::API 6 class CommentParagraphPlugin::API < Grape::API
  7 +
5 MAX_PER_PAGE = 20 8 MAX_PER_PAGE = 20
6 9
  10 + helpers CommentParagraphPlugin::CommentsReport
  11 +
7 resource :articles do 12 resource :articles do
8 paginate max_per_page: MAX_PER_PAGE 13 paginate max_per_page: MAX_PER_PAGE
9 get ':id/comment_paragraph_plugin/comments' do 14 get ':id/comment_paragraph_plugin/comments' do
@@ -31,5 +36,16 @@ class CommentParagraphPlugin::API &lt; Grape::API @@ -31,5 +36,16 @@ class CommentParagraphPlugin::API &lt; Grape::API
31 comments = select_filtered_collection_of(article, :comments, params) 36 comments = select_filtered_collection_of(article, :comments, params)
32 comments.group(:paragraph_uuid).count 37 comments.group(:paragraph_uuid).count
33 end 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 end 50 end
35 end 51 end
plugins/comment_paragraph/lib/comment_paragraph_plugin/comments_report.rb 0 → 100644
@@ -0,0 +1,53 @@ @@ -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,4 +50,18 @@ class CommentParagraphPluginProfileControllerTest &lt; ActionController::TestCase
50 assert_select "#comment_paragraph_uuid[value=?]", '0' 50 assert_select "#comment_paragraph_uuid[value=?]", '0'
51 end 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 end 67 end
plugins/comment_paragraph/test/unit/api_test.rb
@@ -90,4 +90,18 @@ class APITest &lt; ActiveSupport::TestCase @@ -90,4 +90,18 @@ class APITest &lt; ActiveSupport::TestCase
90 assert_equal "CommentParagraphPlugin::Discussion", json["article"]["type"] 90 assert_equal "CommentParagraphPlugin::Discussion", json["article"]["type"]
91 assert json["article"]["setting"]["comment_paragraph_plugin_activate"] 91 assert json["article"]["setting"]["comment_paragraph_plugin_activate"]
92 end 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 end 107 end
plugins/comment_paragraph/test/unit/comment_paragraph_plugin_test.rb
@@ -71,7 +71,7 @@ class CommentParagraphPluginTest &lt; ActiveSupport::TestCase @@ -71,7 +71,7 @@ class CommentParagraphPluginTest &lt; ActiveSupport::TestCase
71 article.expects(:allow_edit?).with(user).returns(true) 71 article.expects(:allow_edit?).with(user).returns(true)
72 article.expects(:comment_paragraph_plugin_activated?).at_least_once.returns(false) 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 end 75 end
76 76
77 should 'display Deactivate Comments title if comment paragraph plugin is deactivated' do 77 should 'display Deactivate Comments title if comment paragraph plugin is deactivated' do
@@ -81,7 +81,17 @@ class CommentParagraphPluginTest &lt; ActiveSupport::TestCase @@ -81,7 +81,17 @@ class CommentParagraphPluginTest &lt; ActiveSupport::TestCase
81 article.expects(:allow_edit?).with(user).returns(true) 81 article.expects(:allow_edit?).with(user).returns(true)
82 article.expects(:comment_paragraph_plugin_activated?).at_least_once.returns(true) 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 end 95 end
86 96
87 should 'not display button to toggle comment paragraph if article is a discussion' do 97 should 'not display button to toggle comment paragraph if article is a discussion' do