Commit 089311f7d65a32404b0a37583f8dd821f1c98fc8
1 parent
ee8510cb
Exists in
export-comment-api
Initial version
Showing
7 changed files
with
131 additions
and
5 deletions
Show diff stats
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 < Grape::API | @@ -31,5 +36,16 @@ class CommentParagraphPlugin::API < 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 < ActionController::TestCase | @@ -50,4 +50,18 @@ class CommentParagraphPluginProfileControllerTest < 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 < ActiveSupport::TestCase | @@ -90,4 +90,18 @@ class APITest < 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 < ActiveSupport::TestCase | @@ -71,7 +71,7 @@ class CommentParagraphPluginTest < 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 < ActiveSupport::TestCase | @@ -81,7 +81,17 @@ class CommentParagraphPluginTest < 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 |