Commit a739edce1f172e39cbd3ca8a6a1e43bae8279171

Authored by Rodrigo Souto
2 parents 48038fc5 4825fe87

Merge branch 'article-version' of https://gitlab.com/juniorsilva1001/noosfero in…

…to juniorsilva1001/noosfero-article-version

Conflicts:
	app/views/content_viewer/versioned_article.rhtml
	db/schema.rb
	public/stylesheets/application.css
app/controllers/public/content_viewer_controller.rb
  1 +require 'diffy'
  2 +
1 3 class ContentViewerController < ApplicationController
2 4  
3 5 needs_profile
... ... @@ -117,6 +119,13 @@ class ContentViewerController &lt; ApplicationController
117 119 end
118 120 end
119 121  
  122 + def versions_diff
  123 + path = params[:page].join('/')
  124 + @page = profile.articles.find_by_path(path)
  125 + @v1, @v2 = @page.versions.find_by_version(params[:v1]), @page.versions.find_by_version(params[:v2])
  126 + p params
  127 + end
  128 +
120 129 def article_versions
121 130 path = params[:page].join('/')
122 131 @page = profile.articles.find_by_path(path)
... ... @@ -184,3 +193,7 @@ class ContentViewerController &lt; ApplicationController
184 193 end
185 194  
186 195 end
  196 +
  197 +
  198 +
  199 +
... ...
app/views/content_viewer/article_versions.rhtml
  1 +<div class="article-versions">
  2 + <%= button(:back, _('Go back to post'), {:action => 'view_page'}) %>
  3 +</div>
  4 +
1 5 <%= article_title(@page, :no_link => true) %>
2 6  
3 7 <p><%= _('This is the list of all versions of this content. Select a version to see it and then revert to it.') %>.</p>
4 8  
5   -<ul class='article-versions'>
6   - <% @versions.each do |v| %>
7   - <li>
8   - <%= link_to(_("Version #{v.version}"), @page.url.merge(:version => v.version)) %>
9   - <%= @page.version == v.version ? _('(current)') : '' %>
10   - <span class='updated-by'><%= _('by %{author}') % {:author => link_to(@page.author_name(v.version), @page.author_url)} %></span>
11   - <div class='updated-on'><%= show_time(v.updated_at) %></div>
12   - </li>
13   - <% end %>
14   -</ul>
  9 +<% form_tag({:controller => 'content_viewer', :action => 'versions_diff', :profile => profile.identifier, :page => @page.path.split('/')}, :method => 'get') do %>
  10 + <ul id="article-versions">
  11 + <% @versions.each do |v| %>
  12 + <li>
  13 + <%= radio_button_tag 'v1', v.version, false, :onclick => 'versionInputClicked(this)' %>
  14 + <%= radio_button_tag 'v2', v.version, false, :onclick => 'versionInputClicked(this)' %>
  15 + <%= link_to(_("Version #{v.version}"), @page.url.merge(:version => v.version)) %>
  16 + <%= @page.version == v.version ? _('(current)') : '' %>
  17 + <span class='updated-by'><%= _('by %{author}') % {:author => link_to(@page.author_name(v.version), @page.author_url)} %></span>
  18 + <span class='updated-on'><%= show_time(v.updated_at) %></span>
  19 + </li>
  20 + <% end %>
  21 + </ul>
  22 +
  23 +<script>
  24 + function versionInputClicked(input) {
  25 + var selectedColumn = input.name;
  26 + var sisterColumn = (selectedColumn == 'v1') ? 'v2' : 'v1';
  27 + var li = input.parentNode;
  28 + var checkedBrotherLi = jQuery('#article-versions input[name=' + sisterColumn + ']:checked').parent()[0];
  29 + updateColumn(selectedColumn, li);
  30 + updateColumn(sisterColumn, checkedBrotherLi);
  31 + }
15 32  
  33 + function updateColumn(selectedColumn, startLi){
  34 + var sisterColumn = (selectedColumn == 'v1') ? 'v2' : 'v1';
  35 + var walkMethod = (selectedColumn == 'v1') ? 'prev' : 'next';
  36 + var li = startLi;
  37 + var foundCheckedBrother = false;
  38 + while(li = jQuery(li)[walkMethod]()[0]) {
  39 + li.className = '';
  40 + if (!foundCheckedBrother){
  41 + li.className = 'selected';
  42 + foundCheckedBrother = jQuery('input[name=' + sisterColumn + ']', li)[0].checked;
  43 + }
  44 + jQuery('input[name=' + selectedColumn + ']', li)[0].disabled = foundCheckedBrother;
  45 + }
  46 + }
  47 +
  48 + var penultVersion = jQuery('#article-versions input[name=v1]')[1];
  49 + var lastVersion = jQuery('#article-versions input[name=v2]')[0];
  50 + jQuery('#article-versions input').attr('disabled', false);
  51 + if (penultVersion && lastVersion) {
  52 + penultVersion.checked = lastVersion.checked = true;
  53 + lastVersion.onclick();
  54 + }
  55 +</script>
  56 + <%= submit_button(:clock, _('Show differences between selected versions')) %>
  57 +<% end %>
16 58 <%= pagination_links @versions, :param_name => 'npage' %>
  59 +
... ...
app/views/content_viewer/versioned_article.rhtml
  1 +<div class="article-versions">
  2 + <%= button(:back, _('Back to the versions'), {:action => 'article_versions'}) %>
  3 +</div>
  4 +
1 5 <div id="article" class="<%= @page.css_class_name %>">
2 6  
3 7 <div id="article-actions">
4 8 <%= button(:clock, _('All versions'), {:controller => 'content_viewer', :profile => profile.identifier, :action => 'article_versions'}, :id => 'article-versions-link') %>
5 9  
6   - <% if @page.allow_edit?(user) && !remove_content_button(:edit) %>
  10 + <% if @page.allow_edit?(user) && !remove_content_button(:undo) %>
7 11 <% content = content_tag('span', _('Revert to this version')) %>
8 12 <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id, :version => @version }) %>
9   - <%= expirable_button @page, :edit, content, url, :id => 'article-revert-version-link' %>
  13 + <%= expirable_button @page, :undo, content, url, :id => 'article-revert-version-link' %>
10 14 <% end %>
11   - </div>
12 15  
  16 + <%= button(:forward, _('Go to latest version'), {:action => 'view_page'}) %>
  17 +</div>
13 18 <div id="article-header">
14 19 <h1 class='title'><%= @versioned_article.name %></h1>
15 20 <%= _("Version %{version} - %{author} on %{date}") % {:version => @version, :author => @page.author_name(@version), :date => show_time(@versioned_article.updated_at) } %>
16 21 </div>
17 22  
  23 + <p id="no-current-version">
  24 + <%= _('This is not the latest version of this content.') %>
  25 + </p>
  26 +</div>
  27 +
18 28 <% version_license = @page.version_license(@version) %>
19 29 <%# This seemingly doubled verification exists because the article-sub-header
20   - div must appear only if at least one content inside it will appeart.
  30 + div must appear only if at least one content inside it will appear.
21 31 Although we have only one content now, we might have others in the future.
22 32 So we're keeping it like that to avoid mistakes. %>
23 33 <% if version_license.present? %>
... ...
app/views/content_viewer/versions_diff.html.erb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<div class="article-versions">
  2 +<%= button(:back, _('Back to the versions'), {:action => 'article_versions'}) %>
  3 +</div>
  4 +
  5 +<h1><%= _('Changes on "%s"') % @page.title %></h1>
  6 +
  7 +<p> <%= _('Changes from %s &rarr; %s') % [show_time(@v1.updated_at), show_time(@v2.updated_at)] %> </p>
  8 +
  9 +<% diffContent = Diffy::Diff.new(@v1.body, @v2.body, :context => 1) %>
  10 +<% if diffContent.to_s(:text).blank? %>
  11 + <p id="article-versions-no-diff">
  12 + <%= _('These versions range have no differences.')%>
  13 + </p>
  14 +<% else %>
  15 + <%= diffContent.to_s(:html) %>
  16 +<% end %>
... ...
config/routes.rb
... ... @@ -129,6 +129,9 @@ ActionController::Routing::Routes.draw do |map|
129 129 map.connect ':profile/*page/versions', :controller => 'content_viewer', :action => 'article_versions', :profile => /#{Noosfero.identifier_format}/, :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } }
130 130 map.connect '*page/versions', :controller => 'content_viewer', :action => 'article_versions'
131 131  
  132 + map.connect ':profile/*page/versions_diff', :controller => 'content_viewer', :action => 'versions_diff', :profile => /#{Noosfero.identifier_format}/, :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } }
  133 + map.connect '*page/versions_diff', :controller => 'content_viewer', :action => 'versions_diff'
  134 +
132 135 # match requests for profiles that don't have a custom domain
133 136 map.homepage ':profile/*page', :controller => 'content_viewer', :action => 'view_page', :profile => /#{Noosfero.identifier_format}/, :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } }
134 137  
... ...
db/schema.rb
... ... @@ -10,7 +10,6 @@
10 10 # It's strongly recommended to check this file into your version control system.
11 11  
12 12 ActiveRecord::Schema.define(:version => 20140314200103) do
13   -
14 13 create_table "abuse_reports", :force => true do |t|
15 14 t.integer "reporter_id"
16 15 t.integer "abuse_complaint_id"
... ... @@ -148,6 +147,7 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
148 147 add_index "articles", ["profile_id"], :name => "index_articles_on_profile_id"
149 148 add_index "articles", ["slug"], :name => "index_articles_on_slug"
150 149 add_index "articles", ["translation_of_id"], :name => "index_articles_on_translation_of_id"
  150 + add_index "articles", [nil], :name => "pg_search_plugin_article"
151 151  
152 152 create_table "articles_categories", :id => false, :force => true do |t|
153 153 t.integer "article_id"
... ... @@ -201,6 +201,8 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
201 201 t.string "abbreviation"
202 202 end
203 203  
  204 + add_index "categories", [nil], :name => "pg_search_plugin_category"
  205 +
204 206 create_table "categories_profiles", :id => false, :force => true do |t|
205 207 t.integer "profile_id"
206 208 t.integer "category_id"
... ... @@ -219,6 +221,8 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
219 221 t.datetime "updated_at"
220 222 end
221 223  
  224 + add_index "certifiers", [nil], :name => "pg_search_plugin_certifier"
  225 +
222 226 create_table "comments", :force => true do |t|
223 227 t.string "title"
224 228 t.text "body"
... ... @@ -233,9 +237,11 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
233 237 t.string "source_type"
234 238 t.string "user_agent"
235 239 t.string "referrer"
  240 + t.integer "group_id"
236 241 end
237 242  
238 243 add_index "comments", ["source_id", "spam"], :name => "index_comments_on_source_id_and_spam"
  244 + add_index "comments", [nil], :name => "pg_search_plugin_comment"
239 245  
240 246 create_table "contact_lists", :force => true do |t|
241 247 t.text "list"
... ... @@ -245,6 +251,50 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
245 251 t.datetime "updated_at"
246 252 end
247 253  
  254 + create_table "custom_forms_plugin_answers", :force => true do |t|
  255 + t.text "value"
  256 + t.integer "field_id"
  257 + t.integer "submission_id"
  258 + end
  259 +
  260 + create_table "custom_forms_plugin_fields", :force => true do |t|
  261 + t.string "name"
  262 + t.string "slug"
  263 + t.string "type"
  264 + t.string "default_value"
  265 + t.string "choices"
  266 + t.float "minimum"
  267 + t.float "maximum"
  268 + t.integer "form_id"
  269 + t.boolean "mandatory", :default => false
  270 + t.boolean "multiple"
  271 + t.boolean "list"
  272 + t.integer "position", :default => 0
  273 + end
  274 +
  275 + create_table "custom_forms_plugin_forms", :force => true do |t|
  276 + t.string "name"
  277 + t.string "slug"
  278 + t.text "description"
  279 + t.integer "profile_id"
  280 + t.datetime "begining"
  281 + t.datetime "ending"
  282 + t.boolean "report_submissions", :default => false
  283 + t.boolean "on_membership", :default => false
  284 + t.string "access"
  285 + t.datetime "created_at"
  286 + t.datetime "updated_at"
  287 + end
  288 +
  289 + create_table "custom_forms_plugin_submissions", :force => true do |t|
  290 + t.string "author_name"
  291 + t.string "author_email"
  292 + t.integer "profile_id"
  293 + t.integer "form_id"
  294 + t.datetime "created_at"
  295 + t.datetime "updated_at"
  296 + end
  297 +
248 298 create_table "delayed_jobs", :force => true do |t|
249 299 t.integer "priority", :default => 0
250 300 t.integer "attempts", :default => 0
... ... @@ -311,6 +361,10 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
311 361 t.integer "enterprise_id"
312 362 end
313 363  
  364 + create_table "foo_plugin_bars", :force => true do |t|
  365 + t.string "name"
  366 + end
  367 +
314 368 create_table "friendships", :force => true do |t|
315 369 t.integer "person_id"
316 370 t.integer "friend_id"
... ... @@ -356,6 +410,8 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
356 410 t.integer "environment_id", :null => false
357 411 end
358 412  
  413 + add_index "licenses", [nil], :name => "pg_search_plugin_license"
  414 +
359 415 create_table "mailing_sents", :force => true do |t|
360 416 t.integer "mailing_id"
361 417 t.integer "person_id"
... ... @@ -390,6 +446,7 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
390 446  
391 447 add_index "national_regions", ["name"], :name => "name_index"
392 448 add_index "national_regions", ["national_region_code"], :name => "code_index"
  449 + add_index "national_regions", [nil], :name => "pg_search_plugin_nationalregion"
393 450  
394 451 create_table "price_details", :force => true do |t|
395 452 t.decimal "price", :default => 0.0
... ... @@ -488,6 +545,7 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
488 545 add_index "profiles", ["identifier"], :name => "index_profiles_on_identifier"
489 546 add_index "profiles", ["members_count"], :name => "index_profiles_on_members_count"
490 547 add_index "profiles", ["region_id"], :name => "index_profiles_on_region_id"
  548 + add_index "profiles", [nil], :name => "pg_search_plugin_profile"
491 549  
492 550 create_table "qualifier_certifiers", :force => true do |t|
493 551 t.integer "qualifier_id"
... ... @@ -501,6 +559,8 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
501 559 t.datetime "updated_at"
502 560 end
503 561  
  562 + add_index "qualifiers", [nil], :name => "pg_search_plugin_qualifier"
  563 +
504 564 create_table "refused_join_community", :id => false, :force => true do |t|
505 565 t.integer "person_id"
506 566 t.integer "community_id"
... ... @@ -547,6 +607,8 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
547 607 t.integer "context_id"
548 608 end
549 609  
  610 + add_index "scraps", [nil], :name => "pg_search_plugin_scrap"
  611 +
550 612 create_table "sessions", :force => true do |t|
551 613 t.string "session_id", :null => false
552 614 t.text "data"
... ... @@ -606,6 +668,19 @@ ActiveRecord::Schema.define(:version =&gt; 20140314200103) do
606 668 t.string "thumbnail"
607 669 end
608 670  
  671 + create_table "tolerance_time_plugin_publications", :force => true do |t|
  672 + t.integer "target_id"
  673 + t.string "target_type"
  674 + t.datetime "created_at"
  675 + t.datetime "updated_at"
  676 + end
  677 +
  678 + create_table "tolerance_time_plugin_tolerances", :force => true do |t|
  679 + t.integer "profile_id"
  680 + t.integer "content_tolerance"
  681 + t.integer "comment_tolerance"
  682 + end
  683 +
609 684 create_table "units", :force => true do |t|
610 685 t.string "singular", :null => false
611 686 t.string "plural", :null => false
... ...
public/designs/icons/tango/style.css
1 1 /******************SMALL ICONS********************/
2 2 .icon-edit { background-image: url(Tango/16x16/apps/text-editor.png) }
  3 +.icon-undo { background-image: url(Tango/16x16/actions/edit-undo.png) }
3 4 .icon-home { background-image: url(Tango/16x16/actions/go-home.png) }
4 5 .icon-home-not { background-image: url(mod/16x16/actions/go-home-not.png) }
5 6 .icon-new,
... ...
public/stylesheets/application.css
... ... @@ -6510,11 +6510,6 @@ li.profile-activity-item.upload_image .activity-gallery-images-count-1 img {
6510 6510 text-align: center;
6511 6511 }
6512 6512  
6513   -ul.article-versions li {
6514   - font-size: 13px;
6515   - padding: 3px 0px;
6516   -}
6517   -
6518 6513 /* * * Admin manage fields * * */
6519 6514  
6520 6515 .controller-features .manage-fields-batch-actions,
... ... @@ -6526,3 +6521,90 @@ ul.article-versions li {
6526 6521 .controller-features .manage-fields-batch-actions td {
6527 6522 font-style: italic;
6528 6523 }
  6524 +
  6525 +/* * * Article versions * * */
  6526 +
  6527 +#article-versions {
  6528 + margin: 0 0 15px 0;
  6529 + padding: 0;
  6530 +}
  6531 +
  6532 +#article-versions li {
  6533 + list-style: none;
  6534 + margin: 0;
  6535 + padding: 3px 0px;
  6536 +}
  6537 +
  6538 +#article-versions input:disabled {
  6539 + opacity: 0.3;
  6540 +}
  6541 +
  6542 +#article-versions .selected {
  6543 + background: #ff9;
  6544 +}
  6545 +
  6546 +#article-versions-no-diff {
  6547 + text-align: center;
  6548 + font-style: italic;
  6549 +}
  6550 +
  6551 +#no-current-version {
  6552 + text-align: center;
  6553 + font-style: italic;
  6554 + background: #faa;
  6555 + padding: 3px;
  6556 +}
  6557 +
  6558 +.article-versions {
  6559 + margin: 5px 0px;
  6560 + text-align: right;
  6561 +}
  6562 +
  6563 +.action-content_viewer-versions_diff .diff {
  6564 + text-align: justify;
  6565 +}
  6566 +
  6567 +.diff ul {
  6568 + list-style: none;
  6569 + margin: 0;
  6570 + padding: 0;
  6571 +}
  6572 +
  6573 +.diff del, .diff ins {
  6574 + display: block;
  6575 + text-decoration: none;
  6576 +}
  6577 +
  6578 +.diff li {
  6579 + padding: 5px 10px;
  6580 + margin: 0;
  6581 + line-height: 150%;
  6582 +}
  6583 +
  6584 +.diff li.ins {
  6585 + background: #dfd;
  6586 +}
  6587 +
  6588 +.diff li.del {
  6589 + background: #fee;
  6590 +}
  6591 +
  6592 +.diff li.ins:hover {
  6593 + background: #8f8;
  6594 +}
  6595 +
  6596 +.diff li.del:hover {
  6597 + background: #f99;
  6598 +}
  6599 +
  6600 +.diff strong {
  6601 + background: rgba(255, 255, 0, 0.2);
  6602 +}
  6603 +
  6604 +.diff li.diff-comment {
  6605 + display: none;
  6606 +}
  6607 +
  6608 +.diff li.diff-block-info {
  6609 + background: none repeat scroll 0 0 gray;
  6610 +}
... ...
test/functional/content_viewer_controller_test.rb
... ... @@ -396,6 +396,17 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
396 396 assert_tag :tag => 'div', :attributes => { :class => /article-body/ }, :content => /edited article/
397 397 end
398 398  
  399 + should "display differences between article's versions" do
  400 + page = TextArticle.create!(:name => 'myarticle', :body => 'original article', :display_versions => true, :profile => profile)
  401 + page.body = 'edited article'; page.save
  402 +
  403 + get :versions_diff, :profile => profile.identifier, :page => [ 'myarticle' ], :v1 => 1, :v2 => 2;
  404 +
  405 + assert_tag :tag => 'li', :attributes => { :class => /del/ }, :content => /original article/
  406 + assert_tag :tag => 'li', :attributes => { :class => /ins/ }, :content => /edited article/
  407 + assert_response :success
  408 + end
  409 +
399 410 should 'not return an article of a different user' do
400 411 p1 = create_user('test_user').person
401 412 a = p1.articles.create!(:name => 'old-name')
... ...