Commit b2833502d0184d05a577d9544379302412dc38f8

Authored by AntonioTerceiro
1 parent 7707a13c

ActionItem158: a better CMS


git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@1790 3f533792-8f58-4932-b0fe-aaf55b0a4547
app/controllers/my_profile/cms_controller.rb
@@ -19,12 +19,14 @@ class CmsController < MyProfileController @@ -19,12 +19,14 @@ class CmsController < MyProfileController
19 19
20 def view 20 def view
21 @article = profile.articles.find(params[:id]) 21 @article = profile.articles.find(params[:id])
22 - @subitems = @article.children 22 + @subitems = @article.children.reject {|item| item.folder? }
  23 + @folders = @article.children.select {|item| item.folder? }
23 end 24 end
24 25
25 def index 26 def index
26 @article = nil 27 @article = nil
27 - @subitems = profile.top_level_articles 28 + @subitems = profile.top_level_articles.reject {|item| item.folder? }
  29 + @folders = profile.top_level_articles.select {|item| item.folder?}
28 render :action => 'view' 30 render :action => 'view'
29 end 31 end
30 32
@@ -35,7 +37,7 @@ class CmsController < MyProfileController @@ -35,7 +37,7 @@ class CmsController < MyProfileController
35 if request.post? 37 if request.post?
36 @article.last_changed_by = user 38 @article.last_changed_by = user
37 if @article.update_attributes(params[:article]) 39 if @article.update_attributes(params[:article])
38 - redirect_to :action => 'view', :id => @article.id 40 + redirect_back
39 return 41 return
40 end 42 end
41 end 43 end
@@ -78,7 +80,7 @@ class CmsController < MyProfileController @@ -78,7 +80,7 @@ class CmsController < MyProfileController
78 @article.last_changed_by = user 80 @article.last_changed_by = user
79 if request.post? 81 if request.post?
80 if @article.save 82 if @article.save
81 - redirect_to :action => 'view', :id => @article.id 83 + redirect_back
82 return 84 return
83 end 85 end
84 end 86 end
@@ -102,5 +104,15 @@ class CmsController < MyProfileController @@ -102,5 +104,15 @@ class CmsController < MyProfileController
102 redirect_to :action => (@article.parent ? 'view' : 'index'), :id => @article.parent 104 redirect_to :action => (@article.parent ? 'view' : 'index'), :id => @article.parent
103 end 105 end
104 106
  107 + protected
  108 +
  109 + def redirect_back
  110 + if @article.parent
  111 + redirect_to :action => 'view', :id => @article.parent
  112 + else
  113 + redirect_to :action => 'index'
  114 + end
  115 + end
  116 +
105 end 117 end
106 118
app/models/article.rb
@@ -112,6 +112,10 @@ class Article < ActiveRecord::Base @@ -112,6 +112,10 @@ class Article < ActiveRecord::Base
112 true 112 true
113 end 113 end
114 114
  115 + def folder?
  116 + false
  117 + end
  118 +
115 def self.find_by_initial(initial) 119 def self.find_by_initial(initial)
116 self.find(:all, :order => 'articles.name', :conditions => [ 'articles.name like (?) or articles.name like (?)', initial + '%', initial.upcase + '%']) 120 self.find(:all, :order => 'articles.name', :conditions => [ 'articles.name like (?) or articles.name like (?)', initial + '%', initial.upcase + '%'])
117 end 121 end
app/models/folder.rb
@@ -20,4 +20,8 @@ class Folder < Article @@ -20,4 +20,8 @@ class Folder < Article
20 content_tag('ul', children.map { |child| content_tag('li', link_to(child.name, child.url)) }, :class => 'folder-listing') 20 content_tag('ul', children.map { |child| content_tag('li', link_to(child.name, child.url)) }, :class => 'folder-listing')
21 end 21 end
22 22
  23 + def folder?
  24 + true
  25 + end
  26 +
23 end 27 end
app/views/cms/edit.rhtml
@@ -16,6 +16,11 @@ @@ -16,6 +16,11 @@
16 %> 16 %>
17 17
18 <% button_bar do %> 18 <% button_bar do %>
19 - <%= submit_button('save', _('Save'), :cancel => (@article.parent ? { :action => 'view', :id => @article.parent.id } : { :action => 'index' } )) %> 19 + <%= submit_button :save, _('Save') %>
  20 + <% if @parent_id || @article.parent %>
  21 + <%= button :cancel, _('Cancel'), :action => 'view', :id => @parent_id || @article.parent %>
  22 + <% else %>
  23 + <%= button :cancel, _('Cancel'), :action => 'index' %>
  24 + <% end %>
20 <% end %> 25 <% end %>
21 <% end %> 26 <% end %>
app/views/cms/view.rhtml
@@ -9,68 +9,59 @@ @@ -9,68 +9,59 @@
9 <%= icon('cms') %> 9 <%= icon('cms') %>
10 <%= _('Content management') %> 10 <%= _('Content management') %>
11 </h2> 11 </h2>
12 -  
13 - <% button_bar(:style => 'margin-bottom: 1em;') do %>  
14 - <%= lightbox_button('new', _('New article'), :action => 'new') %>  
15 - <% end %>  
16 -  
17 <% end %> 12 <% end %>
18 13
19 -<%# subitem %>  
20 -<% if !@subitems.empty? && @article %>  
21 - <%= toggle_panel(_('Hide subitems'), _('Show subitems'), 'article-subitems') %> 14 +<% button_bar(:style => 'margin-bottom: 1em;') do %>
  15 + <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %>
  16 + <%= button :add, _('New folder'), :action => 'new', :type => 'Folder', :parent_id => parent_id %>
  17 + <%= lightbox_button('new', _('New article'), :action => 'new', :parent_id => parent_id) %>
22 <% end %> 18 <% end %>
23 -  
24 -<div id='article-subitems'>  
25 - <div class='file-manager-title'><%= @article ? _('Subitems') : _('Articles') %></div>  
26 - <div class='file-manager-small'>  
27 - <% unless @subitems.empty? %>  
28 - <ul>  
29 - <% @subitems.each do |item| %>  
30 - <li>  
31 - <%= file_manager_button(item.name, icon_for_article(item), :action => 'view', :id => item.id) %>  
32 - </li>  
33 - <% end %>  
34 - </ul>  
35 - <% end %>  
36 19
37 - <% if @article %>  
38 - <% button_bar(:class => 'file-manager-controls') do %>  
39 - <% if @article.allow_children? %>  
40 - <%= lightbox_button('new', _('New subitem'), :action => 'new', :parent_id => @article.id) %>  
41 - <% end %>  
42 - <%= button('up', _('Go up one level'), :action => (@article.parent ? 'view' : 'index'), :id => @article.parent) %>  
43 - <% end %>  
44 - <% end %>  
45 - </div>  
46 -</div> <!-- article-children --> 20 +<table width='100%'>
47 21
48 -<%# display the article content %>  
49 -<div id='article-contents' style='clear: left;'>  
50 - <% if @article %>  
51 - <h2>  
52 - <%= @article.name %>  
53 - <%= image_tag(icon_for_article(@article)) %>  
54 - </h2>  
55 - <% button_bar(:id => 'article-controls') do %>  
56 -  
57 - <ul>  
58 - <li>  
59 - <%= _('"%{article}", last changed by %{author}') % { :article => @article.name, :author => (@article.last_changed_by ? @article.last_changed_by.name : _('Unknown User')) } %>  
60 - </li>  
61 - <li>  
62 - <%= _('Public address of this article: %s') % link_to(url_for(@article.url), @article.url) %>  
63 - </li>  
64 - <li>  
65 - <%= _('Tags:') %> <%= @article.tag_list %>  
66 - </li>  
67 - <%= _('Categories:') %> <%= @article.categories.map { |item| item.name }.join(', ') %>  
68 - </ul> 22 + <%# folders %>
  23 + <tr>
  24 + <th colspan='2'>
  25 + <%= _('Folders') %>
  26 + </th>
  27 + </tr>
  28 + <% if @folders.empty? %>
  29 + <tr><td colspan='2' align='center'><em><%= _('None') %></em></td></tr>
  30 + <% end %>
  31 + <% for folder in @folders %>
  32 + <tr>
  33 + <td>
  34 + <%= image_tag(icon_for_article(folder)) %>
  35 + <%= link_to folder.name, :action => 'view', :id => folder.id %>
  36 + </td>
  37 + <td>
  38 + <%= link_to _('Properties'), :action => 'edit', :id => folder.id %>
  39 + <%= link_to _('View'), folder.url %>
  40 + </td>
  41 + </tr>
  42 + <% end %>
69 43
70 - <%= button('edit', _('Edit'), { :action => 'edit', :id => @article}) %>  
71 - <%= button('home', _('Use as homepage'), { :action => 'set_home_page', :id => @article }, { :method => :post }) %>  
72 - <%= button('delete', _('Delete'), { :action => 'destroy', :id => @article }, :method => :post, :confirm => _('Are you sure you wan to remove this article?')) %>  
73 - <% end %>  
74 - <%= @article.to_html %> 44 + <%# non-folder subitems %>
  45 + <tr>
  46 + <th colspan='2'>
  47 + <%= _('Articles') %>
  48 + </th>
  49 + </tr>
  50 + <% if @subitems.empty? %>
  51 + <tr><td colspan='2' align='center'><em><%= _('None') %></em></td></tr>
  52 + <% end %>
  53 + <% for item in @subitems %>
  54 + <tr>
  55 + <td>
  56 + <%= image_tag(icon_for_article(item)) %>
  57 + <%= link_to item.name, :id => item.id %>
  58 + </td>
  59 + <td>
  60 + <%= link_to _('Edit'), :action => 'edit', :id => item.id %>
  61 + <%= link_to _('View'), item.url %>
  62 + </td>
  63 + </tr>
75 <% end %> 64 <% end %>
76 -</div> 65 +
  66 +
  67 +</table>
test/functional/cms_controller_test.rb
@@ -313,6 +313,89 @@ class CmsControllerTest &lt; Test::Unit::TestCase @@ -313,6 +313,89 @@ class CmsControllerTest &lt; Test::Unit::TestCase
313 assert_tag :tag => 'input', :attributes => { :name => 'parent_id', :value => profile.home_page.id } 313 assert_tag :tag => 'input', :attributes => { :name => 'parent_id', :value => profile.home_page.id }
314 end 314 end
315 315
  316 + should 'list folders at top level' do
  317 + f1 = Folder.new(:name => 'f1'); profile.articles << f1; f1.save!
  318 + f2 = Folder.new(:name => 'f2'); profile.articles << f2; f2.save!
316 319
  320 + get :index, :profile => profile.identifier
  321 + assert_equal [f1, f2], assigns(:folders)
  322 + assert_not_includes assigns(:subitems), f1
  323 + assert_not_includes assigns(:subitems), f2
  324 + end
  325 +
  326 + should 'list folders inside another folder' do
  327 + parent = Folder.new(:name => 'parent'); profile.articles << parent; parent.save!
  328 + f1 = Folder.new(:name => 'f1', :parent => parent); profile.articles << f1; f1.save!
  329 + f2 = Folder.new(:name => 'f2', :parent => parent); profile.articles << f2; f2.save!
  330 +
  331 + get :view, :profile => profile.identifier, :id => parent.id
  332 + assert_equal [f1, f2], assigns(:folders)
  333 + assert_not_includes assigns(:subitems), f1
  334 + assert_not_includes assigns(:subitems), f2
  335 + end
  336 +
  337 + should 'offer to create new top-level folder' do
  338 + get :index, :profile => profile.identifier
  339 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?type=Folder"}
  340 + end
  341 +
  342 + should 'offer to create sub-folder' do
  343 + f = Folder.new(:name => 'f'); profile.articles << f; f.save!
  344 + get :view, :profile => profile.identifier, :id => f.id
  345 +
  346 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?parent_id=#{f.id}&amp;type=Folder" }
  347 + end
  348 +
  349 + should 'redirect back to index after creating top-level article' do
  350 + post :new, :profile => profile.identifier, :type => 'TextileArticle', :article => { :name => 'test' }
  351 + assert_redirected_to :action => 'index'
  352 + end
  353 +
  354 + should 'redirect back to folder after creating article inside it' do
  355 + f = Folder.new(:name => 'f'); profile.articles << f; f.save!
  356 + post :new, :profile => profile.identifier, :type => 'TextileArticle', :parent_id => f.id, :article => { :name => 'test' }
  357 + assert_redirected_to :action => 'view', :id => f.id
  358 + end
  359 +
  360 + should 'redirect back to index after editing top-level article' do
  361 + f = Folder.new(:name => 'f'); profile.articles << f; f.save!
  362 + post :edit, :profile => profile.identifier, :id => f.id
  363 + assert_redirected_to :action => 'index'
  364 + end
  365 +
  366 + should 'redirect back to folder after editing article inside it' do
  367 + f = Folder.new(:name => 'f'); profile.articles << f; f.save!
  368 + a = TextileArticle.create!(:parent => f, :name => 'test', :profile_id => profile.id)
  369 +
  370 + post :edit, :profile => profile.identifier, :id => a.id
  371 + assert_redirected_to :action => 'view', :id => f.id
  372 + end
  373 +
  374 + should 'point back to index when cancelling creation of top-level article' do
  375 + get :new, :profile => profile.identifier, :type => 'Folder'
  376 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms" }, :descendant => { :content => /Cancel/ }
  377 + end
  378 +
  379 + should 'point back to index when cancelling edition of top-level article' do
  380 + f = Folder.new(:name => 'f'); profile.articles << f; f.save!
  381 + get :edit, :profile => profile.identifier, :id => f.id
  382 +
  383 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms" }, :descendant => { :content => /Cancel/ }
  384 + end
  385 +
  386 + should 'point back to folder when cancelling creation of an article inside it' do
  387 + f = Folder.new(:name => 'f'); profile.articles << f; f.save!
  388 + get :new, :profile => profile.identifier, :type => 'Folder', :parent_id => f.id
  389 +
  390 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/view/#{f.id}" }, :descendant => { :content => /Cancel/ }
  391 + end
  392 +
  393 + should 'point back to folder when cancelling edition of an article inside it' do
  394 + f = Folder.new(:name => 'f'); profile.articles << f; f.save!
  395 + a = TextileArticle.create!(:name => 'test', :parent => f, :profile_id => profile.id)
  396 + get :edit, :profile => profile.identifier, :id => a.id
  397 +
  398 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/view/#{f.id}" }, :descendant => { :content => /Cancel/ }
  399 + end
317 400
318 end 401 end
test/unit/article_test.rb
@@ -229,4 +229,8 @@ class ArticleTest &lt; Test::Unit::TestCase @@ -229,4 +229,8 @@ class ArticleTest &lt; Test::Unit::TestCase
229 assert_not_includes list, a2 229 assert_not_includes list, a2
230 end 230 end
231 231
  232 + should 'identify itself as a non-folder' do
  233 + assert !Article.new.folder?, 'should identify itself as non-folder'
  234 + end
  235 +
232 end 236 end
test/unit/folder_test.rb
@@ -30,4 +30,8 @@ class FolderTest &lt; ActiveSupport::TestCase @@ -30,4 +30,8 @@ class FolderTest &lt; ActiveSupport::TestCase
30 assert_match(/<li><a href=".*\/testuser\/f\/otherarticle">otherarticle<\/a><\/li>/, f.to_html) 30 assert_match(/<li><a href=".*\/testuser\/f\/otherarticle">otherarticle<\/a><\/li>/, f.to_html)
31 end 31 end
32 32
  33 + should 'identify as folder' do
  34 + assert Folder.new.folder?, 'folder must identity itself as folder'
  35 + end
  36 +
33 end 37 end