Commit f2b0ed69f1ff0a7fadb525a62ba6f7a79f23d209

Authored by Caio Almeida
Committed by Antonio Terceiro
1 parent 2edf8709

Forum content type and refactoring image gallery implementation

(ActionItem1769)
app/controllers/my_profile/cms_controller.rb
@@ -44,7 +44,7 @@ class CmsController < MyProfileController @@ -44,7 +44,7 @@ class CmsController < MyProfileController
44 Event 44 Event
45 ] 45 ]
46 parent_id = params ? params[:parent_id] : nil 46 parent_id = params ? params[:parent_id] : nil
47 - if !parent_id or !Article.find(parent_id).blog? 47 + if !parent_id or !Article.find(parent_id).has_posts?
48 articles += [ 48 articles += [
49 RssFeed 49 RssFeed
50 ] 50 ]
@@ -56,13 +56,13 @@ class CmsController < MyProfileController @@ -56,13 +56,13 @@ class CmsController < MyProfileController
56 end 56 end
57 57
58 def special_article_types 58 def special_article_types
59 - [Folder, Blog, UploadedFile] 59 + [Folder, Blog, UploadedFile, Forum, Gallery]
60 end 60 end
61 61
62 def view 62 def view
63 @article = profile.articles.find(params[:id]) 63 @article = profile.articles.find(params[:id])
64 conditions = [] 64 conditions = []
65 - if @article.blog? 65 + if @article.has_posts?
66 conditions = ['type != ?', 'RssFeed'] 66 conditions = ['type != ?', 'RssFeed']
67 end 67 end
68 68
app/controllers/public/content_viewer_controller.rb
@@ -77,7 +77,7 @@ class ContentViewerController < ApplicationController @@ -77,7 +77,7 @@ class ContentViewerController < ApplicationController
77 remove_comment 77 remove_comment
78 end 78 end
79 79
80 - if @page.blog? 80 + if @page.has_posts?
81 posts = if params[:year] and params[:month] 81 posts = if params[:year] and params[:month]
82 filter_date = DateTime.parse("#{params[:year]}-#{params[:month]}-01") 82 filter_date = DateTime.parse("#{params[:year]}-#{params[:month]}-01")
83 @page.posts.by_range(filter_date..filter_date.at_end_of_month) 83 @page.posts.by_range(filter_date..filter_date.at_end_of_month)
@@ -88,7 +88,7 @@ class ContentViewerController < ApplicationController @@ -88,7 +88,7 @@ class ContentViewerController < ApplicationController
88 @posts = posts.paginate({ :page => params[:npage], :per_page => @page.posts_per_page }.merge(Article.display_filter(user, profile))) 88 @posts = posts.paginate({ :page => params[:npage], :per_page => @page.posts_per_page }.merge(Article.display_filter(user, profile)))
89 end 89 end
90 90
91 - if @page.folder? && @page.view_as == 'image_gallery' 91 + if @page.folder? && @page.gallery?
92 @images = @page.images 92 @images = @page.images
93 @images = @images.paginate(:per_page => per_page, :page => params[:npage]) unless params[:slideshow] 93 @images = @images.paginate(:per_page => per_page, :page => params[:npage]) unless params[:slideshow]
94 end 94 end
app/helpers/content_viewer_helper.rb
1 module ContentViewerHelper 1 module ContentViewerHelper
2 2
3 include BlogHelper 3 include BlogHelper
  4 + include ForumHelper
4 5
5 def number_of_comments(article) 6 def number_of_comments(article)
6 n = article.comments.size 7 n = article.comments.size
app/helpers/forum_helper.rb 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +module ForumHelper
  2 +
  3 + def cms_label_for_new_children
  4 + _('New discussion topic')
  5 + end
  6 +
  7 + def cms_label_for_edit
  8 + _('Configure forum')
  9 + end
  10 +
  11 + def list_forum_posts(articles)
  12 + pagination = will_paginate(articles, {
  13 + :param_name => 'npage',
  14 + :prev_label => _('« Newer posts'),
  15 + :next_label => _('Older posts »')
  16 + })
  17 + content = [content_tag('tr',
  18 + content_tag('th', _('Discussion topic')) +
  19 + content_tag('th', _('Posts')) +
  20 + content_tag('th', _('Last post'))
  21 + )
  22 + ]
  23 + artic_len = articles.length
  24 + articles.each_with_index{ |art,i|
  25 + css_add = [ 'position-'+(i+1).to_s() ]
  26 + position = (i%2 == 0) ? 'odd-post' : 'even-post'
  27 + css_add << 'first' if i == 0
  28 + css_add << 'last' if i == (artic_len-1)
  29 + css_add << 'not-published' if !art.published?
  30 + css_add << position
  31 + content << content_tag('tr',
  32 + content_tag('td', link_to(art.title, art.url)) +
  33 + content_tag('td', link_to(art.comments.count, art.url.merge(:anchor => 'comments_list'))) +
  34 + content_tag('td', last_topic_update(art)),
  35 + :class => 'forum-post ' + css_add.join(' '),
  36 + :id => "post-#{art.id}"
  37 + )
  38 + }
  39 + content_tag('table', content) + (pagination or '')
  40 + end
  41 +
  42 + def last_topic_update(article)
  43 + last_update_at, last_update_by = (article.comments.count.zero? ? [article.updated_at, article.author] : [article.comments.last.created_at, article.comments.last.author])
  44 + time_ago_as_sentence(last_update_at) + ' ' + _('ago') + ' ' + _('by') + ' ' + link_to(last_update_by.name, last_update_by.url)
  45 + end
  46 +
  47 +end
app/models/article.rb
@@ -237,6 +237,14 @@ class Article &lt; ActiveRecord::Base @@ -237,6 +237,14 @@ class Article &lt; ActiveRecord::Base
237 false 237 false
238 end 238 end
239 239
  240 + def forum?
  241 + false
  242 + end
  243 +
  244 + def has_posts?
  245 + false
  246 + end
  247 +
240 def published? 248 def published?
241 if self.published 249 if self.published
242 if self.parent && !self.parent.published? 250 if self.parent && !self.parent.published?
@@ -248,8 +256,9 @@ class Article &lt; ActiveRecord::Base @@ -248,8 +256,9 @@ class Article &lt; ActiveRecord::Base
248 end 256 end
249 end 257 end
250 258
251 - named_scope :published, :conditions => { :published => true }  
252 - named_scope :folders, :conditions => { :type => ['Folder', 'Blog'] } 259 + named_scope :published, :conditions => { :published => true }
  260 + named_scope :folders, :conditions => { :type => ['Folder', 'Blog', 'Forum', 'Gallery'] }
  261 + named_scope :galleries, :conditions => { :type => 'Gallery' }
253 named_scope :images, :conditions => { :is_image => true } 262 named_scope :images, :conditions => { :is_image => true }
254 263
255 def self.display_filter(user, profile) 264 def self.display_filter(user, profile)
@@ -350,7 +359,7 @@ class Article &lt; ActiveRecord::Base @@ -350,7 +359,7 @@ class Article &lt; ActiveRecord::Base
350 false 359 false
351 end 360 end
352 361
353 - def display_as_gallery? 362 + def gallery?
354 false 363 false
355 end 364 end
356 365
app/models/blog.rb
1 class Blog < Folder 1 class Blog < Folder
2 2
3 - has_many :posts, :class_name => 'Article', :foreign_key => 'parent_id', :source => :children, :conditions => [ 'articles.type != ?', 'RssFeed' ], :order => 'published_at DESC, id DESC'  
4 -  
5 - attr_accessor :feed_attrs  
6 -  
7 - after_create do |blog|  
8 - blog.children << RssFeed.new(:name => 'feed', :profile => blog.profile)  
9 - blog.feed = blog.feed_attrs  
10 - end  
11 -  
12 - settings_items :posts_per_page, :type => :integer, :default => 5 3 + acts_as_having_posts
13 4
14 def self.short_description 5 def self.short_description
15 _('Blog') 6 _('Blog')
@@ -35,21 +26,6 @@ class Blog &lt; Folder @@ -35,21 +26,6 @@ class Blog &lt; Folder
35 true 26 true
36 end 27 end
37 28
38 - def feed  
39 - self.children.find(:first, :conditions => {:type => 'RssFeed'})  
40 - end  
41 -  
42 - def feed=(attrs)  
43 - if attrs  
44 - if self.feed  
45 - self.feed.update_attributes(attrs)  
46 - else  
47 - self.feed_attrs = attrs  
48 - end  
49 - end  
50 - self.feed  
51 - end  
52 -  
53 has_one :external_feed, :foreign_key => 'blog_id', :dependent => :destroy 29 has_one :external_feed, :foreign_key => 'blog_id', :dependent => :destroy
54 30
55 attr_accessor :external_feed_data 31 attr_accessor :external_feed_data
@@ -78,17 +54,7 @@ class Blog &lt; Folder @@ -78,17 +54,7 @@ class Blog &lt; Folder
78 end 54 end
79 end 55 end
80 56
81 - def name=(value)  
82 - self.set_name(value)  
83 - if self.slug.blank?  
84 - self.slug = self.name.to_slug  
85 - else  
86 - self.slug = self.slug.to_slug  
87 - end  
88 - end  
89 -  
90 settings_items :visualization_format, :type => :string, :default => 'full' 57 settings_items :visualization_format, :type => :string, :default => 'full'
91 validates_inclusion_of :visualization_format, :in => [ 'full', 'short' ], :if => :visualization_format 58 validates_inclusion_of :visualization_format, :in => [ 'full', 'short' ], :if => :visualization_format
92 59
93 -  
94 end 60 end
app/models/folder.rb
@@ -2,23 +2,11 @@ class Folder &lt; Article @@ -2,23 +2,11 @@ class Folder &lt; Article
2 2
3 acts_as_having_settings :field => :setting 3 acts_as_having_settings :field => :setting
4 4
5 - settings_items :view_as, :type => :string, :default => 'folder'  
6 -  
7 xss_terminate :only => [ :body ], :with => 'white_list', :on => 'validation' 5 xss_terminate :only => [ :body ], :with => 'white_list', :on => 'validation'
8 6
9 include WhiteListFilter 7 include WhiteListFilter
10 filter_iframes :body, :whitelist => lambda { profile && profile.environment && profile.environment.trusted_sites_for_iframe } 8 filter_iframes :body, :whitelist => lambda { profile && profile.environment && profile.environment.trusted_sites_for_iframe }
11 9
12 - def self.select_views  
13 - [[_('Folder'), 'folder'], [_('Image gallery'), 'image_gallery']]  
14 - end  
15 -  
16 - def self.views  
17 - select_views.map(&:last)  
18 - end  
19 -  
20 - validates_inclusion_of :view_as, :in => self.views  
21 -  
22 def self.short_description 10 def self.short_description
23 _('Folder') 11 _('Folder')
24 end 12 end
@@ -31,33 +19,18 @@ class Folder &lt; Article @@ -31,33 +19,18 @@ class Folder &lt; Article
31 'folder' 19 'folder'
32 end 20 end
33 21
34 - 22 + include ActionView::Helpers::TagHelper
35 def to_html(options = {}) 23 def to_html(options = {})
36 - send(view_as)  
37 - end  
38 -  
39 - def folder  
40 folder = self 24 folder = self
41 lambda do 25 lambda do
42 render :file => 'content_viewer/folder', :locals => { :folder => folder } 26 render :file => 'content_viewer/folder', :locals => { :folder => folder }
43 end 27 end
44 end 28 end
45 29
46 - def image_gallery  
47 - article = self  
48 - lambda do  
49 - render :file => 'content_viewer/image_gallery', :locals => {:article => article}  
50 - end  
51 - end  
52 -  
53 def folder? 30 def folder?
54 true 31 true
55 end 32 end
56 33
57 - def display_as_gallery?  
58 - view_as == 'image_gallery'  
59 - end  
60 -  
61 def can_display_hits? 34 def can_display_hits?
62 false 35 false
63 end 36 end
@@ -74,6 +47,6 @@ class Folder &lt; Article @@ -74,6 +47,6 @@ class Folder &lt; Article
74 :foreign_key => 'parent_id', 47 :foreign_key => 'parent_id',
75 :order => 'articles.type, articles.name', 48 :order => 'articles.type, articles.name',
76 :include => :reference_article, 49 :include => :reference_article,
77 - :conditions => ["articles.type = 'UploadedFile' and articles.content_type in (?) or articles.type = 'Folder' or (articles.type = 'PublishedArticle' and reference_articles_articles.type = 'UploadedFile' and reference_articles_articles.content_type in (?))", UploadedFile.content_types, UploadedFile.content_types] 50 + :conditions => ["articles.type = 'UploadedFile' and articles.content_type in (?) or articles.type in ('Folder','Gallery') or (articles.type = 'PublishedArticle' and reference_articles_articles.type = 'UploadedFile' and reference_articles_articles.content_type in (?))", UploadedFile.content_types, UploadedFile.content_types]
78 51
79 end 52 end
app/models/forum.rb 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +class Forum < Folder
  2 +
  3 + acts_as_having_posts :order => 'updated_at DESC'
  4 +
  5 + def self.short_description
  6 + _('Forum')
  7 + end
  8 +
  9 + def self.description
  10 + _('An internet forum, also called message board, where discussions can be held.')
  11 + end
  12 +
  13 + include ActionView::Helpers::TagHelper
  14 + def to_html(options = {})
  15 + lambda do
  16 + render :file => 'content_viewer/forum_page'
  17 + end
  18 + end
  19 +
  20 + def forum?
  21 + true
  22 + end
  23 +
  24 +end
app/models/gallery.rb 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +class Gallery < Folder
  2 +
  3 + def self.short_description
  4 + _('Gallery')
  5 + end
  6 +
  7 + def self.description
  8 + _('A gallery, inside which you can put images.')
  9 + end
  10 +
  11 + include ActionView::Helpers::TagHelper
  12 + def to_html(options)
  13 + article = self
  14 + lambda do
  15 + render :file => 'content_viewer/image_gallery', :locals => {:article => article}
  16 + end
  17 + end
  18 +
  19 + def gallery?
  20 + true
  21 + end
  22 +
  23 +end
app/models/organization.rb
@@ -116,7 +116,7 @@ class Organization &lt; Profile @@ -116,7 +116,7 @@ class Organization &lt; Profile
116 def default_set_of_articles 116 def default_set_of_articles
117 [ 117 [
118 Blog.new(:name => _('Blog')), 118 Blog.new(:name => _('Blog')),
119 - Folder.new(:name => _('Gallery'), :view_as => 'image_gallery'), 119 + Gallery.new(:name => _('Gallery')),
120 ] 120 ]
121 end 121 end
122 122
app/models/person.rb
@@ -223,7 +223,7 @@ class Person &lt; Profile @@ -223,7 +223,7 @@ class Person &lt; Profile
223 def default_set_of_articles 223 def default_set_of_articles
224 [ 224 [
225 Blog.new(:name => _('Blog')), 225 Blog.new(:name => _('Blog')),
226 - Folder.new(:name => _('Gallery'), :view_as => 'image_gallery'), 226 + Gallery.new(:name => _('Gallery')),
227 ] 227 ]
228 end 228 end
229 229
app/models/profile.rb
@@ -525,7 +525,7 @@ private :generate_url, :url_options @@ -525,7 +525,7 @@ private :generate_url, :url_options
525 # associated to the profile before being saved. Example: 525 # associated to the profile before being saved. Example:
526 # 526 #
527 # def default_set_of_articles 527 # def default_set_of_articles
528 - # [Blog.new(:name => 'Blog'), Folder.new(:name => 'Gallery', :view_as => 'image_gallery')] 528 + # [Blog.new(:name => 'Blog'), Gallery.new(:name => 'Gallery')]
529 # end 529 # end
530 # 530 #
531 # By default, this method returns an empty array. 531 # By default, this method returns an empty array.
@@ -690,6 +690,16 @@ private :generate_url, :url_options @@ -690,6 +690,16 @@ private :generate_url, :url_options
690 self.blogs.count.nonzero? 690 self.blogs.count.nonzero?
691 end 691 end
692 692
  693 + has_many :forums, :source => 'articles', :class_name => 'Forum'
  694 +
  695 + def forum
  696 + self.has_forum? ? self.forums.first(:order => 'id') : nil
  697 + end
  698 +
  699 + def has_forum?
  700 + self.forums.count.nonzero?
  701 + end
  702 +
693 def admins 703 def admins
694 self.members_by_role(Profile::Roles.admin(environment.id)) 704 self.members_by_role(Profile::Roles.admin(environment.id))
695 end 705 end
@@ -703,7 +713,7 @@ private :generate_url, :url_options @@ -703,7 +713,7 @@ private :generate_url, :url_options
703 end 713 end
704 714
705 def image_galleries 715 def image_galleries
706 - folders.select { |folder| folder.display_as_gallery?} 716 + articles.galleries
707 end 717 end
708 718
709 def blocks_to_expire_cache 719 def blocks_to_expire_cache
app/models/rss_feed.rb
@@ -61,7 +61,7 @@ class RssFeed &lt; Article @@ -61,7 +61,7 @@ class RssFeed &lt; Article
61 61
62 include ActionController::UrlWriter 62 include ActionController::UrlWriter
63 def fetch_articles 63 def fetch_articles
64 - if parent && parent.blog? 64 + if parent && parent.has_posts?
65 return parent.posts.find(:all, :conditions => ['published = ?', true], :limit => self.limit, :order => 'id desc') 65 return parent.posts.find(:all, :conditions => ['published = ?', true], :limit => self.limit, :order => 'id desc')
66 end 66 end
67 67
app/models/slideshow_block.rb
@@ -11,7 +11,7 @@ class SlideshowBlock &lt; Block @@ -11,7 +11,7 @@ class SlideshowBlock &lt; Block
11 end 11 end
12 12
13 def gallery 13 def gallery
14 - gallery_id ? Folder.find(:first, :conditions => { :id => gallery_id }) : nil 14 + gallery_id ? Gallery.find(:first, :conditions => { :id => gallery_id }) : nil
15 end 15 end
16 16
17 def public_filename_for(image) 17 def public_filename_for(image)
app/models/uploaded_file.rb
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 # of the file itself is kept. (FIXME?) 4 # of the file itself is kept. (FIXME?)
5 class UploadedFile < Article 5 class UploadedFile < Article
6 6
7 - track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.display_as_gallery? } 7 + track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.gallery? }
8 8
9 include ShortFilename 9 include ShortFilename
10 10
@@ -76,7 +76,7 @@ class UploadedFile &lt; Article @@ -76,7 +76,7 @@ class UploadedFile &lt; Article
76 article = self 76 article = self
77 if image? 77 if image?
78 lambda do 78 lambda do
79 - if article.display_as_gallery? && options[:gallery_view] 79 + if article.gallery? && options[:gallery_view]
80 images = article.parent.images 80 images = article.parent.images
81 current_index = images.index(article) 81 current_index = images.index(article)
82 total_of_images = images.count 82 total_of_images = images.count
@@ -119,7 +119,7 @@ class UploadedFile &lt; Article @@ -119,7 +119,7 @@ class UploadedFile &lt; Article
119 false 119 false
120 end 120 end
121 121
122 - def display_as_gallery?  
123 - self.parent && self.parent.folder? && self.parent.display_as_gallery? 122 + def gallery?
  123 + self.parent && self.parent.folder? && self.parent.gallery?
124 end 124 end
125 end 125 end
app/views/cms/_folder.rhtml
1 <%= required_fields_message %> 1 <%= required_fields_message %>
2 2
3 <%= required f.text_field('name', :size => '64') %> 3 <%= required f.text_field('name', :size => '64') %>
4 -<%= labelled_form_field(_('Folder type'), f.select(:view_as, Folder.select_views)) %>  
5 4
6 <%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 3, :cols => 64)) %> 5 <%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 3, :cols => 64)) %>
app/views/cms/_forum.rhtml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<%= error_messages_for 'forum' %>
  2 +
  3 +<h1><%= _('My Forum') %></h1>
  4 +
  5 +<%= render :file => 'shared/tiny_mce' %>
  6 +
  7 +<%= required f.text_field(:name, :size => '64', :onchange => "updateUrlField(this, 'article_slug')") %>
  8 +
  9 +<%= labelled_form_field(_('Description:'), text_area(:article, :body, :cols => 64, :rows => 10)) %>
  10 +
  11 +<%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, [5, 10, 20, 50, 100])) %>
app/views/cms/_gallery.rhtml 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<%= required_fields_message %>
  2 +
  3 +<%= required f.text_field('name', :size => '64') %>
  4 +
  5 +<%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 3, :cols => 64)) %>
app/views/cms/view.rhtml
@@ -5,9 +5,11 @@ @@ -5,9 +5,11 @@
5 <% button_bar(:style => 'margin-bottom: 1em;') do %> 5 <% button_bar(:style => 'margin-bottom: 1em;') do %>
6 <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %> 6 <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %>
7 7
8 - <% if !@article or !@article.blog? %> 8 + <% if !@article or !@article.has_posts? %>
9 <%= button :newfolder, _('New folder'), :action => 'new', :type => 'Folder', :parent_id => parent_id %> 9 <%= button :newfolder, _('New folder'), :action => 'new', :type => 'Folder', :parent_id => parent_id %>
10 <%= button :newblog, _('New Blog'), :action => 'new', :type => 'Blog', :parent_id => parent_id %> 10 <%= button :newblog, _('New Blog'), :action => 'new', :type => 'Blog', :parent_id => parent_id %>
  11 + <%= button :newforum, _('New Forum'), :action => 'new', :type => 'Forum', :parent_id => parent_id %>
  12 + <%= button :newgallery, _('New Gallery'), :action => 'new', :type => 'Gallery', :parent_id => parent_id %>
11 <%= button('upload-file', _('Upload files'), :action => 'upload_files', :parent_id => parent_id) %> 13 <%= button('upload-file', _('Upload files'), :action => 'upload_files', :parent_id => parent_id) %>
12 <% end %> 14 <% end %>
13 <%= lightbox_button('new', label_for_new_article(@article), :action => 'new', :parent_id => parent_id) %> 15 <%= lightbox_button('new', label_for_new_article(@article), :action => 'new', :parent_id => parent_id) %>
app/views/content_viewer/forum_page.rhtml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<% add_rss_feed_to_head(@page.name, @page.feed.url) if @page.forum? && @page.feed %>
  2 +
  3 +<div>
  4 + <div class='forum-description'>
  5 + <%= @page.body %>
  6 + </div>
  7 +</div>
  8 +<hr class="pre-posts"/>
  9 +<div class="forum-posts">
  10 + <%= (@posts.compact.empty? ? content_tag('em', _('(no posts)')) : list_forum_posts(@posts)) %>
  11 +</div>
app/views/content_viewer/view_page.rhtml
1 <% 1 <%
2 - if @page.parent && @page.parent.blog? && @page.parent.feed 2 + if @page.parent && @page.parent.has_posts? && @page.parent.feed
3 add_rss_feed_to_head(@page.parent.name, @page.parent.feed.url) 3 add_rss_feed_to_head(@page.parent.name, @page.parent.feed.url)
4 end 4 end
5 %> 5 %>
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }), 15 profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }),
16 :class => 'button with-text icon-edit' %> 16 :class => 'button with-text icon-edit' %>
17 <% if !(profile.kind_of?(Enterprise) && environment.enabled?('disable_cms')) %> 17 <% if !(profile.kind_of?(Enterprise) && environment.enabled?('disable_cms')) %>
18 - <% if @page != profile.home_page && !@page.blog? %> 18 + <% if @page != profile.home_page && !@page.has_posts? %>
19 <%= link_to content_tag( 'span', _('Delete') ), 19 <%= link_to content_tag( 'span', _('Delete') ),
20 profile.admin_url.merge({ :controller => 'cms', :action => 'destroy', :id => @page }), 20 profile.admin_url.merge({ :controller => 'cms', :action => 'destroy', :id => @page }),
21 :class => 'button with-text icon-delete' %> 21 :class => 'button with-text icon-delete' %>
@@ -34,20 +34,20 @@ @@ -34,20 +34,20 @@
34 <% end %> 34 <% end %>
35 <% end %> 35 <% end %>
36 <% if !(profile.kind_of?(Enterprise) && environment.enabled?('disable_cms')) %> 36 <% if !(profile.kind_of?(Enterprise) && environment.enabled?('disable_cms')) %>
37 - <% if !@page.display_as_gallery? %> 37 + <% if !@page.gallery? %>
38 <%= lightbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %> 38 <%= lightbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %>
39 <% end %> 39 <% end %>
40 - <% if (@page.folder? && !@page.blog?) || (@page.parent && @page.parent.folder? && !@page.parent.blog?) %> 40 + <% if (@page.folder? && !@page.has_posts?) || (@page.parent && @page.parent.folder? && !@page.parent.has_posts?) %>
41 <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %> 41 <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %>
42 <% end %> 42 <% end %>
43 <% end %> 43 <% end %>
44 - <% if profile.kind_of?(Enterprise) && @page.display_as_gallery? %> 44 + <% if profile.kind_of?(Enterprise) && @page.gallery? %>
45 <%= button('upload-file', _('Upload files'), :controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent)) %> 45 <%= button('upload-file', _('Upload files'), :controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent)) %>
46 <% end %> 46 <% end %>
47 </div> 47 </div>
48 <% end %> 48 <% end %>
49 <div id="article-header"> 49 <div id="article-header">
50 - <%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.blog? && @page.feed %> 50 + <%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %>
51 <%= article_title(@page, :no_link => true) %> 51 <%= article_title(@page, :no_link => true) %>
52 </div> 52 </div>
53 </div> 53 </div>
config/initializers/dependencies.rb
@@ -4,6 +4,7 @@ require &#39;acts_as_having_settings&#39; @@ -4,6 +4,7 @@ require &#39;acts_as_having_settings&#39;
4 require 'acts_as_searchable' 4 require 'acts_as_searchable'
5 require 'acts_as_having_boxes' 5 require 'acts_as_having_boxes'
6 require 'acts_as_having_image' 6 require 'acts_as_having_image'
  7 +require 'acts_as_having_posts'
7 require 'route_if' 8 require 'route_if'
8 9
9 # third-party libraries 10 # third-party libraries
db/migrate/20101129234429_convert_folders_to_galleries.rb 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +class ConvertFoldersToGalleries < ActiveRecord::Migration
  2 + def self.up
  3 + select_all("select id, setting from articles where type = 'Folder'").each do |folder|
  4 + view_as = YAML.load(folder['setting'])[:view_as]
  5 + update("update articles set type = 'Gallery' where id = %d" % folder['id']) if view_as == 'image_gallery'
  6 + end
  7 + end
  8 +
  9 + def self.down
  10 + select_all("select id, setting from articles where type = 'Gallery'").each do |folder|
  11 + settings = YAML.load(folder['setting'])
  12 + settings[:view_as] = 'image_gallery'
  13 + assignments = ActiveRecord::Base.sanitize_sql_for_assignment(:setting => settings.to_yaml)
  14 + update("update articles set %s, type = 'Folder' where id = %d" % [assignments, folder['id']])
  15 + end
  16 + end
  17 +end
features/forum.feature 0 → 100644
@@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
  1 +Feature: forum
  2 + As a noosfero user
  3 + I want to have one or mutiple forums
  4 +
  5 + Background:
  6 + Given I am on the homepage
  7 + And the following users
  8 + | login | name |
  9 + | joaosilva | Joao Silva |
  10 + And "joaosilva" has no articles
  11 + And I am logged in as "joaosilva"
  12 +
  13 + Scenario: create a forum
  14 + Given I go to the Control panel
  15 + And I follow "Manage Content"
  16 + When I follow "New Forum"
  17 + And I fill in "Title" with "My Forum"
  18 + And I press "Save"
  19 + Then I should see "Configure forum"
  20 +
  21 + Scenario: redirect to forum after create forum from cms
  22 + Given I go to the Control panel
  23 + And I follow "Manage Content"
  24 + When I follow "New Forum"
  25 + And I fill in "Title" with "Forum from cms"
  26 + And I press "Save"
  27 + Then I should be on /joaosilva/forum-from-cms
  28 +
  29 + Scenario: create multiple forums
  30 + Given I go to the Control panel
  31 + And I follow "Manage Content"
  32 + And I follow "New Forum"
  33 + And I fill in "Title" with "Forum One"
  34 + And I press "Save"
  35 + Then I go to the Control panel
  36 + And I follow "Manage Content"
  37 + And I follow "New Forum"
  38 + And I fill in "Title" with "Forum Two"
  39 + And I press "Save"
  40 + Then I should not see "error"
  41 + And I should be on /joaosilva/forum-two
  42 +
  43 + Scenario: cancel button back to cms
  44 + Given I go to the Control panel
  45 + And I follow "Manage Content"
  46 + And I follow "New Forum"
  47 + When I follow "Cancel" within ".main-block"
  48 + Then I should be on /myprofile/joaosilva/cms
  49 +
  50 + Scenario: cancel button back to myprofile
  51 + Given I go to the Control panel
  52 + And I follow "Manage Content"
  53 + And I follow "New Forum"
  54 + When I follow "Cancel" within ".main-block"
  55 + Then I should be on /myprofile/joaosilva/cms
  56 +
  57 + Scenario: configure forum when viewing it
  58 + Given the following forums
  59 + | owner | name |
  60 + | joaosilva | Forum One |
  61 + And I go to /joaosilva/forum-one
  62 + When I follow "Configure forum"
  63 + Then I should be on edit "Forum One" by joaosilva
features/gallery_navigation.feature
@@ -6,9 +6,9 @@ Feature: gallery_navigation @@ -6,9 +6,9 @@ Feature: gallery_navigation
6 Given the following users 6 Given the following users
7 | login | 7 | login |
8 | marciopunk | 8 | marciopunk |
9 - And the following folders  
10 - | owner | name | view_as |  
11 - | marciopunk | my-gallery | image_gallery | 9 + And the following galleries
  10 + | owner | name |
  11 + | marciopunk | my-gallery |
12 And the following files 12 And the following files
13 | owner | file | mime | parent | 13 | owner | file | mime | parent |
14 | marciopunk | rails.png | image/png | my-gallery | 14 | marciopunk | rails.png | image/png | my-gallery |
features/step_definitions/noosfero_steps.rb
@@ -41,12 +41,14 @@ Given /^the following blocks$/ do |table| @@ -41,12 +41,14 @@ Given /^the following blocks$/ do |table|
41 end 41 end
42 end 42 end
43 43
44 -Given /^the following (articles|events|blogs|folders)$/ do |content, table| 44 +Given /^the following (articles|events|blogs|folders|forums|galleries)$/ do |content, table|
45 klass = { 45 klass = {
46 'articles' => TextileArticle, 46 'articles' => TextileArticle,
47 'events' => Event, 47 'events' => Event,
48 'blogs' => Blog, 48 'blogs' => Blog,
49 'folders' => Folder, 49 'folders' => Folder,
  50 + 'forums' => Forum,
  51 + 'galleries' => Gallery
50 }[content] || raise("Don't know how to build %s" % content) 52 }[content] || raise("Don't know how to build %s" % content)
51 table.hashes.map{|item| item.dup}.each do |item| 53 table.hashes.map{|item| item.dup}.each do |item|
52 owner_identifier = item.delete("owner") 54 owner_identifier = item.delete("owner")
lib/acts_as_having_posts.rb 0 → 100644
@@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
  1 +module ActsAsHavingPosts
  2 +
  3 + module ClassMethods
  4 + def acts_as_having_posts(options = {})
  5 + has_many :posts, { :class_name => 'Article', :foreign_key => 'parent_id', :source => :children, :conditions => [ 'articles.type != ?', 'RssFeed' ], :order => 'published_at DESC, id DESC' }.merge(options)
  6 +
  7 + attr_accessor :feed_attrs
  8 +
  9 + after_create do |blog|
  10 + blog.children << RssFeed.new(:name => 'feed', :profile => blog.profile)
  11 + blog.feed = blog.feed_attrs
  12 + end
  13 +
  14 + settings_items :posts_per_page, :type => :integer, :default => 5
  15 +
  16 + self.send(:include, ActsAsHavingPosts)
  17 + end
  18 + end
  19 +
  20 + def has_posts?
  21 + true
  22 + end
  23 +
  24 + def feed
  25 + self.children.find(:first, :conditions => {:type => 'RssFeed'})
  26 + end
  27 +
  28 + def feed=(attrs)
  29 + if attrs
  30 + if self.feed
  31 + self.feed.update_attributes(attrs)
  32 + else
  33 + self.feed_attrs = attrs
  34 + end
  35 + end
  36 + self.feed
  37 + end
  38 +
  39 + def name=(value)
  40 + self.set_name(value)
  41 + self.slug = self.slug.blank? ? self.name.to_slug : self.slug.to_slug
  42 + end
  43 +
  44 +end
  45 +
  46 +ActiveRecord::Base.extend(ActsAsHavingPosts::ClassMethods)
public/designs/icons/tango/style.css
@@ -73,3 +73,5 @@ @@ -73,3 +73,5 @@
73 .icon-chat { background-image: url(Tango/16x16/apps/internet-group-chat.png); background-repeat: no-repeat } 73 .icon-chat { background-image: url(Tango/16x16/apps/internet-group-chat.png); background-repeat: no-repeat }
74 .icon-scrap { background-image: url(Tango/16x16/actions/format-justify-left.png) } 74 .icon-scrap { background-image: url(Tango/16x16/actions/format-justify-left.png) }
75 .icon-reply { background-image: url(Tango/16x16/actions/mail-reply-sender.png) } 75 .icon-reply { background-image: url(Tango/16x16/actions/mail-reply-sender.png) }
  76 +.icon-newforum { background-image: url(Tango/16x16/apps/system-users.png) }
  77 +.icon-newgallery { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) }
public/designs/themes/base/style.css
@@ -1035,10 +1035,6 @@ hr.pre-posts, hr.sep-posts { @@ -1035,10 +1035,6 @@ hr.pre-posts, hr.sep-posts {
1035 color: #AAA; 1035 color: #AAA;
1036 } 1036 }
1037 1037
1038 -#article-parent {  
1039 - display: none;  
1040 -}  
1041 -  
1042 .msie .post_comment_box { 1038 .msie .post_comment_box {
1043 padding-top: 15px; 1039 padding-top: 15px;
1044 } 1040 }
public/stylesheets/application.css
@@ -5230,3 +5230,9 @@ h1#agenda-title { @@ -5230,3 +5230,9 @@ h1#agenda-title {
5230 float: none; 5230 float: none;
5231 margin-top: 10px; 5231 margin-top: 10px;
5232 } 5232 }
  5233 +
  5234 +/* Forum */
  5235 +
  5236 +.forum-posts .pagination {
  5237 + margin-top: 20px;
  5238 +}
test/factories.rb
@@ -409,4 +409,22 @@ module Noosfero::Factory @@ -409,4 +409,22 @@ module Noosfero::Factory
409 { :login => username, :email => username + '@noosfero.colivre', :crypted_password => 'test'}.merge(params) 409 { :login => username, :email => username + '@noosfero.colivre', :crypted_password => 'test'}.merge(params)
410 end 410 end
411 411
  412 + ###############################################
  413 + # Forum
  414 + ###############################################
  415 +
  416 + def defaults_for_forum(params = {})
  417 + name = "forum_#{rand(1000)}"
  418 + { :profile_id => 1, :path => name, :name => name, :slug => name.to_slug }.merge(params)
  419 + end
  420 +
  421 + ###############################################
  422 + # Gallery
  423 + ###############################################
  424 +
  425 + def defaults_for_gallery(params = {})
  426 + name = "gallery_#{rand(1000)}"
  427 + { :profile_id => 1, :path => name, :name => name, :slug => name.to_slug }.merge(params)
  428 + end
  429 +
412 end 430 end
test/functional/cms_controller_test.rb
@@ -802,6 +802,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase @@ -802,6 +802,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase
802 should 'not offer to create special article types' do 802 should 'not offer to create special article types' do
803 get :new, :profile => profile.identifier 803 get :new, :profile => profile.identifier
804 assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?type=Blog"} 804 assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?type=Blog"}
  805 + assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?type=Forum"}
805 end 806 end
806 807
807 should 'offer to edit a blog' do 808 should 'offer to edit a blog' do
@@ -918,7 +919,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase @@ -918,7 +919,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase
918 end 919 end
919 920
920 should 'create icon upload file in folder' do 921 should 'create icon upload file in folder' do
921 - f = Folder.create!(:name => 'test_folder', :profile => profile, :view_as => 'image_gallery') 922 + f = Gallery.create!(:name => 'test_folder', :profile => profile)
922 post :new, :profile => profile.identifier, 923 post :new, :profile => profile.identifier,
923 :type => UploadedFile.name, 924 :type => UploadedFile.name,
924 :parent_id => f.id, 925 :parent_id => f.id,
@@ -1155,6 +1156,8 @@ class CmsControllerTest &lt; Test::Unit::TestCase @@ -1155,6 +1156,8 @@ class CmsControllerTest &lt; Test::Unit::TestCase
1155 1156
1156 image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg')) 1157 image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
1157 image2 = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :created_at => 1.day.ago) 1158 image2 = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :created_at => 1.day.ago)
  1159 + image2.updated_at = 1.day.ago
  1160 + image2.send :update_without_callbacks
1158 1161
1159 get :media_listing, :profile => profile.identifier 1162 get :media_listing, :profile => profile.identifier
1160 1163
@@ -1296,4 +1299,115 @@ class CmsControllerTest &lt; Test::Unit::TestCase @@ -1296,4 +1299,115 @@ class CmsControllerTest &lt; Test::Unit::TestCase
1296 file_2.destroy 1299 file_2.destroy
1297 end 1300 end
1298 1301
  1302 + # Forum
  1303 +
  1304 + should 'display posts per page input with default value on edit forum' do
  1305 + n = Forum.new.posts_per_page.to_s
  1306 + get :new, :profile => profile.identifier, :type => 'Forum'
  1307 + assert_tag :tag => 'select', :attributes => { :name => 'article[posts_per_page]' }, :child => { :tag => 'option', :attributes => {:value => n, :selected => 'selected'} }
  1308 + end
  1309 +
  1310 + should 'offer to edit a forum' do
  1311 + profile.articles << Forum.new(:name => 'forum test', :profile => profile)
  1312 +
  1313 + profile.articles.reload
  1314 + assert profile.has_forum?
  1315 +
  1316 + b = profile.forum
  1317 + get :index, :profile => profile.identifier
  1318 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/edit/#{b.id}"}
  1319 + end
  1320 +
  1321 + should 'not offer to add folder to forum' do
  1322 + profile.articles << Forum.new(:name => 'forum test', :profile => profile)
  1323 +
  1324 + profile.articles.reload
  1325 + assert profile.has_forum?
  1326 +
  1327 + get :view, :profile => profile.identifier, :id => profile.forum.id
  1328 + assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?parent_id=#{profile.forum.id}&amp;type=Folder"}
  1329 + end
  1330 +
  1331 + should 'not show feed subitem for forum' do
  1332 + profile.articles << Forum.new(:name => 'Forum for test', :profile => profile)
  1333 +
  1334 + profile.articles.reload
  1335 + assert profile.has_forum?
  1336 +
  1337 + get :view, :profile => profile.identifier, :id => profile.forum.id
  1338 +
  1339 + assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/edit/#{profile.forum.feed.id}" }
  1340 + end
  1341 +
  1342 + should 'update feed options by edit forum form' do
  1343 + profile.articles << Forum.new(:name => 'Forum for test', :profile => profile)
  1344 + post :edit, :profile => profile.identifier, :id => profile.forum.id, :article => { :feed => { :limit => 7 } }
  1345 + assert_equal 7, profile.forum.feed.limit
  1346 + end
  1347 +
  1348 + should 'not offer folder to forum articles' do
  1349 + @controller.stubs(:profile).returns(fast_create(Enterprise, :name => 'test_ent', :identifier => 'test_ent'))
  1350 + forum = Forum.create!(:name => 'Forum for test', :profile => profile)
  1351 + @controller.stubs(:params).returns({ :parent_id => forum.id })
  1352 +
  1353 + assert_not_includes @controller.available_article_types, Folder
  1354 + end
  1355 +
  1356 + should 'not offer rssfeed to forum articles' do
  1357 + @controller.stubs(:profile).returns(fast_create(Enterprise, :name => 'test_ent', :identifier => 'test_ent'))
  1358 + forum = Forum.create!(:name => 'Forum for test', :profile => profile)
  1359 + @controller.stubs(:params).returns({ :parent_id => forum.id })
  1360 +
  1361 + assert_not_includes @controller.available_article_types, RssFeed
  1362 + end
  1363 +
  1364 + should 'update forum posts_per_page setting' do
  1365 + profile.articles << Forum.new(:name => 'Forum for test', :profile => profile)
  1366 + post :edit, :profile => profile.identifier, :id => profile.forum.id, :article => { :posts_per_page => 5 }
  1367 + profile.forum.reload
  1368 + assert_equal 5, profile.forum.posts_per_page
  1369 + end
  1370 +
  1371 + should "display 'New post' when create children of forum" do
  1372 + a = Forum.create!(:name => 'forum_for_test', :profile => profile)
  1373 + Article.stubs(:short_description).returns('bli')
  1374 + get :view, :profile => profile.identifier, :id => a
  1375 + assert_tag :tag => 'a', :content => 'New discussion topic'
  1376 + end
  1377 +
  1378 + should 'go to forum after create it' do
  1379 + assert_difference Forum, :count do
  1380 + post :new, :type => Forum.name, :profile => profile.identifier, :article => { :name => 'my-forum' }, :back_to => 'control_panel'
  1381 + end
  1382 + assert_redirected_to @profile.articles.find_by_name('my-forum').view_url
  1383 + end
  1384 +
  1385 + should 'back to forum after config forum' do
  1386 + profile.articles << Forum.new(:name => 'my-forum', :profile => profile)
  1387 + post :edit, :profile => profile.identifier, :id => profile.forum.id
  1388 +
  1389 + assert_redirected_to @profile.articles.find_by_name('my-forum').view_url
  1390 + end
  1391 +
  1392 + should 'back to control panel if cancel create forum' do
  1393 + get :new, :profile => profile.identifier, :type => Forum.name
  1394 + assert_tag :tag => 'a', :content => 'Cancel', :attributes => { :href => /\/myprofile\/#{profile.identifier}/ }
  1395 + end
  1396 +
  1397 + should 'back to control panel if cancel config forum' do
  1398 + profile.articles << Forum.new(:name => 'my-forum', :profile => profile)
  1399 + get :edit, :profile => profile.identifier, :id => profile.forum.id
  1400 + assert_tag :tag => 'a', :content => 'Cancel', :attributes => { :href => /\/myprofile\/#{profile.identifier}/ }
  1401 + end
  1402 +
  1403 + should 'not offer to upload files to forum' do
  1404 + profile.articles << Forum.new(:name => 'forum test', :profile => profile)
  1405 +
  1406 + profile.articles.reload
  1407 + assert profile.has_forum?
  1408 +
  1409 + get :view, :profile => profile.identifier, :id => profile.forum.id
  1410 + assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/cms/upload_files?parent_id=#{profile.forum.id}"}
  1411 + end
  1412 +
1299 end 1413 end
test/functional/content_viewer_controller_test.rb
@@ -743,14 +743,14 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase @@ -743,14 +743,14 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase
743 743
744 should "display 'Upload files' when create children of image gallery" do 744 should "display 'Upload files' when create children of image gallery" do
745 login_as(profile.identifier) 745 login_as(profile.identifier)
746 - f = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery') 746 + f = Gallery.create!(:name => 'gallery', :profile => profile)
747 get :view_page, :profile => profile.identifier, :page => f.explode_path 747 get :view_page, :profile => profile.identifier, :page => f.explode_path
748 assert_tag :tag => 'a', :content => 'Upload files', :attributes => {:href => /parent_id=#{f.id}/} 748 assert_tag :tag => 'a', :content => 'Upload files', :attributes => {:href => /parent_id=#{f.id}/}
749 end 749 end
750 750
751 should "display 'New article' when showing folder child of image gallery" do 751 should "display 'New article' when showing folder child of image gallery" do
752 login_as(profile.identifier) 752 login_as(profile.identifier)
753 - folder1 = Folder.create!(:name => 'gallery1', :profile => profile, :view_as => 'image_gallery') 753 + folder1 = Gallery.create!(:name => 'gallery1', :profile => profile)
754 folder1.children << folder2 = Folder.new(:name => 'gallery2', :profile => profile) 754 folder1.children << folder2 = Folder.new(:name => 'gallery2', :profile => profile)
755 755
756 get :view_page, :profile => profile.identifier, :page => folder2.explode_path 756 get :view_page, :profile => profile.identifier, :page => folder2.explode_path
@@ -759,7 +759,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase @@ -759,7 +759,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase
759 759
760 should "display 'Upload files' to image gallery when showing its children" do 760 should "display 'Upload files' to image gallery when showing its children" do
761 login_as(profile.identifier) 761 login_as(profile.identifier)
762 - folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery') 762 + folder = Gallery.create!(:name => 'gallery', :profile => profile)
763 file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) 763 file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
764 get :view_page, :profile => profile.identifier, :page => file.explode_path, :view => true 764 get :view_page, :profile => profile.identifier, :page => file.explode_path, :view => true
765 765
@@ -784,7 +784,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase @@ -784,7 +784,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase
784 784
785 should 'display all images from profile in the slideshow' do 785 should 'display all images from profile in the slideshow' do
786 @controller.stubs(:per_page).returns(1) 786 @controller.stubs(:per_page).returns(1)
787 - folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery') 787 + folder = Gallery.create!(:name => 'gallery', :profile => profile)
788 788
789 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg')) 789 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
790 image2 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) 790 image2 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
@@ -796,7 +796,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase @@ -796,7 +796,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase
796 796
797 should 'display default image in the slideshow if thumbnails were not processed' do 797 should 'display default image in the slideshow if thumbnails were not processed' do
798 @controller.stubs(:per_page).returns(1) 798 @controller.stubs(:per_page).returns(1)
799 - folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery') 799 + folder = Gallery.create!(:name => 'gallery', :profile => profile)
800 800
801 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg')) 801 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
802 802
@@ -807,7 +807,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase @@ -807,7 +807,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase
807 807
808 should 'display thumbnail image in the slideshow if thumbnails were processed' do 808 should 'display thumbnail image in the slideshow if thumbnails were processed' do
809 @controller.stubs(:per_page).returns(1) 809 @controller.stubs(:per_page).returns(1)
810 - folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery') 810 + folder = Gallery.create!(:name => 'gallery', :profile => profile)
811 811
812 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg')) 812 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
813 813
@@ -819,7 +819,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase @@ -819,7 +819,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase
819 819
820 should 'display default image in gallery if thumbnails were not processed' do 820 should 'display default image in gallery if thumbnails were not processed' do
821 @controller.stubs(:per_page).returns(1) 821 @controller.stubs(:per_page).returns(1)
822 - folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery') 822 + folder = Gallery.create!(:name => 'gallery', :profile => profile)
823 823
824 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg')) 824 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
825 825
@@ -830,7 +830,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase @@ -830,7 +830,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase
830 830
831 should 'display thumbnail image in gallery if thumbnails were processed' do 831 should 'display thumbnail image in gallery if thumbnails were processed' do
832 @controller.stubs(:per_page).returns(1) 832 @controller.stubs(:per_page).returns(1)
833 - folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery') 833 + folder = Gallery.create!(:name => 'gallery', :profile => profile)
834 834
835 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg')) 835 image1 = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))
836 836
@@ -875,7 +875,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase @@ -875,7 +875,7 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase
875 875
876 should 'show only first 40 chars of abstract in image gallery' do 876 should 'show only first 40 chars of abstract in image gallery' do
877 login_as(profile.identifier) 877 login_as(profile.identifier)
878 - folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery') 878 + folder = Gallery.create!(:name => 'gallery', :profile => profile)
879 file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) 879 file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
880 880
881 file.abstract = 'a long abstract bigger then 40 chars for testing' 881 file.abstract = 'a long abstract bigger then 40 chars for testing'
@@ -958,4 +958,141 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase @@ -958,4 +958,141 @@ class ContentViewerControllerTest &lt; Test::Unit::TestCase
958 assert_tag :tag => 'div', :attributes => { :class => /main-block/ }, :descendant => { :tag => 'a', :attributes => { :href => "/myprofile/testinguser/cms/edit/#{blog.id}" }, :content => 'Configure blog' } 958 assert_tag :tag => 'div', :attributes => { :class => /main-block/ }, :descendant => { :tag => 'a', :attributes => { :href => "/myprofile/testinguser/cms/edit/#{blog.id}" }, :content => 'Configure blog' }
959 end 959 end
960 960
  961 + # Forum
  962 +
  963 + should 'list unpublished forum posts to owner with a different class' do
  964 + login_as('testinguser')
  965 + forum = Forum.create!(:name => 'A forum test', :profile => profile)
  966 + forum.posts << TextileArticle.create!(:name => 'Post', :profile => profile, :parent => forum, :published => false)
  967 +
  968 + get :view_page, :profile => profile.identifier, :page => [forum.path]
  969 + assert_tag :tag => 'tr', :attributes => {:class => /not-published/}
  970 + end
  971 +
  972 + should 'not list unpublished forum posts to a not logged person' do
  973 + forum = Forum.create!(:name => 'A forum test', :profile => profile)
  974 + forum.posts << TextileArticle.create!(:name => 'Post', :profile => profile, :parent => forum, :published => false)
  975 +
  976 + get :view_page, :profile => profile.identifier, :page => [forum.path]
  977 + assert_no_tag :tag => 'a', :content => "Post"
  978 + end
  979 +
  980 + should 'display pagination links of forum' do
  981 + forum = Forum.create!(:name => 'A forum test', :profile => profile, :posts_per_page => 5)
  982 + for n in 1..10
  983 + forum.posts << TextileArticle.create!(:name => "Post #{n}", :profile => profile, :parent => forum)
  984 + end
  985 + assert_equal 10, forum.posts.size
  986 +
  987 + get :view_page, :profile => profile.identifier, :page => [forum.path]
  988 + assert_tag :tag => 'a', :attributes => { :href => "/#{profile.identifier}/#{forum.path}?npage=2", :rel => 'next' }
  989 + end
  990 +
  991 + should 'display first page of forum posts' do
  992 + forum = Forum.create!(:name => 'My forum', :profile => profile, :posts_per_page => 5)
  993 + for n in 1..10
  994 + forum.children << art = TextileArticle.create!(:name => "Post #{n}", :profile => profile, :parent => forum)
  995 + art.updated_at = (10 - n).days.ago
  996 + art.send :update_without_callbacks
  997 + end
  998 + assert_equal 10, forum.posts.size
  999 +
  1000 + get :view_page, :profile => profile.identifier, :page => [forum.path]
  1001 + for n in 1..5
  1002 + assert_no_tag :tag => 'a', :content => "Post #{n}", :parent => { :tag => 'td', :parent => { :tag => 'tr', :attributes => { :class => /forum-post/ } } }
  1003 + end
  1004 + for n in 6..10
  1005 + assert_tag :tag => 'a', :content => "Post #{n}", :parent => { :tag => 'td', :parent => { :tag => 'tr', :attributes => { :class => /forum-post/ } } }
  1006 + end
  1007 + end
  1008 +
  1009 + should 'display others pages of forum posts' do
  1010 + forum = Forum.create!(:name => 'My forum', :profile => profile, :posts_per_page => 5)
  1011 + for n in 1..10
  1012 + forum.children << art = TextileArticle.create!(:name => "Post #{n}", :profile => profile, :parent => forum)
  1013 + art.updated_at = (10 - n).days.ago
  1014 + art.send :update_without_callbacks
  1015 + end
  1016 + assert_equal 10, forum.posts.size
  1017 +
  1018 + get :view_page, :profile => profile.identifier, :page => [forum.path], :npage => 2
  1019 + for n in 1..5
  1020 + assert_tag :tag => 'a', :content => "Post #{n}", :parent => { :tag => 'td', :parent => { :tag => 'tr', :attributes => { :class => /forum-post/ } } }
  1021 + end
  1022 + for n in 6..10
  1023 + assert_no_tag :tag => 'a', :content => "Post #{n}", :parent => { :tag => 'td', :parent => { :tag => 'tr', :attributes => { :class => /forum-post/ } } }
  1024 + end
  1025 + end
  1026 +
  1027 + should 'set year and month filter from URL params for forum' do
  1028 + forum = Forum.create!(:name => "forum", :profile => profile)
  1029 + profile.articles << forum
  1030 +
  1031 + past_post = TextileArticle.create!(:name => "past post", :profile => profile, :parent => forum, :created_at => forum.created_at - 1.year)
  1032 + actual_post = TextileArticle.create!(:name => "actual post", :profile => profile, :parent => forum)
  1033 + forum.children << past_post
  1034 + forum.children << actual_post
  1035 +
  1036 + year, month = profile.forum.created_at.year.to_s, '%02d' % profile.forum.created_at.month
  1037 +
  1038 + get :view_page, :profile => profile.identifier, :page => [profile.forum.path], :year => year, :month => month
  1039 +
  1040 + assert_no_tag :tag => 'a', :content => past_post.title
  1041 + assert_tag :tag => 'a', :content => actual_post.title
  1042 + end
  1043 +
  1044 + should "display 'New discussion topic' when create children of forum" do
  1045 + login_as(profile.identifier)
  1046 + a = Forum.create!(:name => 'article folder', :profile => profile)
  1047 + Article.stubs(:short_description).returns('bli')
  1048 + get :view_page, :profile => profile.identifier, :page => [a.path]
  1049 + assert_tag :tag => 'a', :content => 'New discussion topic'
  1050 + end
  1051 +
  1052 + should "display same label for new article button of forum parent" do
  1053 + login_as(profile.identifier)
  1054 + a = Forum.create!(:name => 'article folder', :profile => profile)
  1055 + Article.stubs(:short_description).returns('bli')
  1056 + t = TextileArticle.create!(:name => 'first post', :parent => a, :profile => profile)
  1057 + get :view_page, :profile => profile.identifier, :page => [t.path]
  1058 + assert_tag :tag => 'a', :content => 'New discussion topic'
  1059 + end
  1060 +
  1061 + should 'add meta tag to rss feed on view forum' do
  1062 + login_as(profile.identifier)
  1063 + profile.articles << Forum.new(:name => 'Forum', :profile => profile)
  1064 + get :view_page, :profile => profile.identifier, :page => ['forum']
  1065 + assert_tag :tag => 'link', :attributes => { :rel => 'alternate', :type => 'application/rss+xml', :title => 'Forum', :href => "http://#{environment.default_hostname}/testinguser/forum/feed" }
  1066 + end
  1067 +
  1068 + should 'add meta tag to rss feed on view post forum' do
  1069 + login_as(profile.identifier)
  1070 + profile.articles << Forum.new(:name => 'Forum', :profile => profile)
  1071 + profile.forum.posts << TextileArticle.new(:name => 'first post', :parent => profile.forum, :profile => profile)
  1072 + get :view_page, :profile => profile.identifier, :page => ['forum', 'first-post']
  1073 + assert_tag :tag => 'link', :attributes => { :rel => 'alternate', :type => 'application/rss+xml', :title => 'Forum', :href => "http://#{environment.default_hostname}/testinguser/forum/feed" }
  1074 + end
  1075 +
  1076 + should "not display 'Upload files' when viewing forum" do
  1077 + login_as(profile.identifier)
  1078 + b = Forum.create!(:name => 'article folder', :profile => profile)
  1079 + get :view_page, :profile => profile.identifier, :page => b.explode_path
  1080 + assert_no_tag :tag => 'a', :content => 'Upload files', :attributes => {:href => /parent_id=#{b.id}/}
  1081 + end
  1082 +
  1083 + should "not display 'Upload files' when viewing post from a forum" do
  1084 + login_as(profile.identifier)
  1085 + b = Forum.create!(:name => 'article folder', :profile => profile)
  1086 + forum_post = TextileArticle.create!(:name => 'children-article', :profile => profile, :parent => b)
  1087 + get :view_page, :profile => profile.identifier, :page => forum_post.explode_path
  1088 + assert_no_tag :tag => 'a', :content => 'Upload files', :attributes => {:href => /parent_id=#{b.id}/}
  1089 + end
  1090 +
  1091 + should 'display link to edit forum for allowed' do
  1092 + forum = fast_create(Forum, :profile_id => profile.id, :path => 'forum')
  1093 + login_as(profile.identifier)
  1094 + get :view_page, :profile => profile.identifier, :page => forum.explode_path
  1095 + assert_tag :tag => 'div', :attributes => { :class => /main-block/ }, :descendant => { :tag => 'a', :attributes => { :href => "/myprofile/testinguser/cms/edit/#{forum.id}" }, :content => 'Configure forum' }
  1096 + end
  1097 +
961 end 1098 end
test/functional/profile_controller_test.rb
@@ -459,7 +459,7 @@ class ProfileControllerTest &lt; Test::Unit::TestCase @@ -459,7 +459,7 @@ class ProfileControllerTest &lt; Test::Unit::TestCase
459 end 459 end
460 460
461 should 'show number of published images in index' do 461 should 'show number of published images in index' do
462 - folder = Folder.create!(:name => 'gallery', :profile => profile, :view_as => 'image_gallery') 462 + folder = Gallery.create!(:name => 'gallery', :profile => profile)
463 published_file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) 463 published_file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
464 unpublished_file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'), :published => false) 464 unpublished_file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'), :published => false)
465 465
test/unit/article_block_test.rb
@@ -118,9 +118,7 @@ class ArticleBlockTest &lt; Test::Unit::TestCase @@ -118,9 +118,7 @@ class ArticleBlockTest &lt; Test::Unit::TestCase
118 should 'not display gallery pages navigation in content' do 118 should 'not display gallery pages navigation in content' do
119 profile = create_user('testuser').person 119 profile = create_user('testuser').person
120 block = ArticleBlock.new 120 block = ArticleBlock.new
121 - gallery = fast_create(Folder, :profile_id => profile.id)  
122 - gallery.view_as = 'image_gallery'  
123 - gallery.save! 121 + gallery = fast_create(Gallery, :profile_id => profile.id)
124 image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => gallery) 122 image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => gallery)
125 block.article = image 123 block.article = image
126 block.save! 124 block.save!
test/unit/article_test.rb
@@ -1211,4 +1211,19 @@ class ArticleTest &lt; Test::Unit::TestCase @@ -1211,4 +1211,19 @@ class ArticleTest &lt; Test::Unit::TestCase
1211 assert_equal 31, (DateTime.parse('2010-07-06')).at_end_of_month.day 1211 assert_equal 31, (DateTime.parse('2010-07-06')).at_end_of_month.day
1212 end 1212 end
1213 1213
  1214 + should 'not be a forum by default' do
  1215 + assert !fast_create(Article).forum?
  1216 + end
  1217 +
  1218 + should 'not have posts by default' do
  1219 + assert !fast_create(Article).has_posts?
  1220 + end
  1221 +
  1222 + should 'get article galleries' do
  1223 + p = fast_create(Profile)
  1224 + a = fast_create(Article, :profile_id => p.id)
  1225 + g = fast_create(Gallery, :profile_id => p.id)
  1226 + assert_equal [g], p.articles.galleries
  1227 + end
  1228 +
1214 end 1229 end
test/unit/blog_test.rb
@@ -171,4 +171,8 @@ class BlogTest &lt; ActiveSupport::TestCase @@ -171,4 +171,8 @@ class BlogTest &lt; ActiveSupport::TestCase
171 assert !blog.errors.invalid?(:visualization_format) 171 assert !blog.errors.invalid?(:visualization_format)
172 end 172 end
173 173
  174 + should 'have posts' do
  175 + assert Blog.new.has_posts?
  176 + end
  177 +
174 end 178 end
test/unit/folder_test.rb
@@ -28,31 +28,6 @@ class FolderTest &lt; ActiveSupport::TestCase @@ -28,31 +28,6 @@ class FolderTest &lt; ActiveSupport::TestCase
28 assert_equal false, a.can_display_hits? 28 assert_equal false, a.can_display_hits?
29 end 29 end
30 30
31 - should 'be viewed as image gallery' do  
32 - p = create_user('test_user').person  
33 - f = fast_create(Folder, :profile_id => p.id)  
34 - f.view_as = 'image_gallery'; f.save!  
35 - f.reload  
36 -  
37 - assert_equal 'image_gallery', f.view_as  
38 - end  
39 -  
40 - should 'not allow view as bogus' do  
41 - p = create_user('test_user').person  
42 - f = fast_create(Folder, :profile_id => p.id)  
43 - f.view_as = 'bogus'  
44 - assert !f.save  
45 - end  
46 -  
47 - should 'view as folder by default' do  
48 - p = create_user('test_user').person  
49 - f = fast_create(Folder, :profile_id => p.id)  
50 - f.expects(:folder)  
51 - f.to_html  
52 -  
53 - assert_equal 'folder', f.view_as  
54 - end  
55 -  
56 should 'have images that are only images or other folders' do 31 should 'have images that are only images or other folders' do
57 p = create_user('test_user').person 32 p = create_user('test_user').person
58 f = fast_create(Folder, :profile_id => p.id) 33 f = fast_create(Folder, :profile_id => p.id)
test/unit/forum_helper_test.rb 0 → 100644
@@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class ForumHelperTest < Test::Unit::TestCase
  4 +
  5 + include BlogHelper
  6 + include ForumHelper
  7 + include ContentViewerHelper
  8 + include ActionView::Helpers::AssetTagHelper
  9 + include ApplicationHelper
  10 +
  11 + def setup
  12 + stubs(:show_date).returns('')
  13 + @environment = Environment.default
  14 + @profile = create_user('forum_helper_test').person
  15 + @forum = fast_create(Forum, :profile_id => profile.id, :name => 'Forum test')
  16 + end
  17 +
  18 + attr :profile
  19 + attr :forum
  20 +
  21 + def _(s); s; end
  22 + def h(s); s; end
  23 +
  24 + should 'return a label for new children' do
  25 + assert_kind_of String, cms_label_for_new_children
  26 + end
  27 +
  28 + should 'return a label for edit' do
  29 + assert_kind_of String, cms_label_for_edit
  30 + end
  31 +
  32 + should 'list posts with different classes' do
  33 + forum.children << older_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => false)
  34 + forum.children << newer_post = TextileArticle.create!(:name => 'Second post', :profile => profile, :parent => forum, :published => true)
  35 + older_post.updated_at = Time.now.ago(1.month); older_post.send(:update_without_callbacks)
  36 + assert_match /forum-post position-1 first odd-post.*forum-post position-2 last not-published even-post/, list_forum_posts(forum.posts)
  37 + end
  38 +
  39 + should 'return post update if it has no comments' do
  40 + author = create_user('forum test author').person
  41 + some_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => true)
  42 + some_post.expects(:author).returns(author)
  43 + assert some_post.comments.empty?
  44 + assert_equal "#{some_post.updated_at.to_s} ago by #{author.name}", last_topic_update(some_post)
  45 + end
  46 +
  47 + should 'return last comment date if it has comments' do
  48 + some_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => true)
  49 + a1, a2 = create_user('a1').person, create_user('a2').person
  50 + some_post.comments << Comment.new(:title => 'test', :body => 'test', :author => a1)
  51 + some_post.comments << Comment.new(:title => 'test', :body => 'test', :author => a2)
  52 + c = Comment.last
  53 + assert_equal 2, some_post.comments.count
  54 + assert_equal "#{c.created_at.to_s} ago by #{a2.name}", last_topic_update(some_post)
  55 + end
  56 +
  57 + protected
  58 +
  59 + def will_paginate(arg1, arg2)
  60 + end
  61 +
  62 + def link_to(content, url)
  63 + content
  64 + end
  65 +
  66 + def tag(tag, args = {})
  67 + attrs = args.map{|k,v| "#{k}='#{v}'"}.join(' ')
  68 + "<#{tag} #{attrs} />"
  69 + end
  70 +
  71 + def content_tag(tag, content, options = {})
  72 + tag_attr = options.blank? ? "" : options.collect{ |o| "#{o[0]}=\"#{o[1]}\"" }.join(' ')
  73 + "<#{tag}#{tag_attr}>#{content}</#{tag}>"
  74 + end
  75 +
  76 + def time_ago_as_sentence(t = Time.now)
  77 + t.to_s
  78 + end
  79 +
  80 +end
test/unit/forum_test.rb 0 → 100644
@@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class ForumTest < ActiveSupport::TestCase
  4 +
  5 + should 'be an article' do
  6 + assert_kind_of Article, Forum.new
  7 + end
  8 +
  9 + should 'provide proper description' do
  10 + assert_kind_of String, Forum.description
  11 + end
  12 +
  13 + should 'provide own icon name' do
  14 + assert_not_equal Article.new.icon_name, Forum.new.icon_name
  15 + end
  16 +
  17 + should 'identify as folder' do
  18 + assert Forum.new.folder?, 'forum must identity itself as folder'
  19 + end
  20 +
  21 + should 'identify as forum' do
  22 + assert Forum.new.forum?, 'forum must identity itself as forum'
  23 + end
  24 +
  25 + should 'create rss feed automatically' do
  26 + p = create_user('testuser').person
  27 + b = create(Forum, :profile_id => p.id, :name => 'forum_feed_test')
  28 + assert_kind_of RssFeed, b.feed
  29 + end
  30 +
  31 + should 'save feed options' do
  32 + p = create_user('testuser').person
  33 + p.articles << Forum.new(:profile => p, :name => 'forum_feed_test')
  34 + p.forum.feed = { :limit => 7 }
  35 + assert_equal 7, p.forum.feed.limit
  36 + end
  37 +
  38 + should 'save feed options after create forum' do
  39 + p = create_user('testuser').person
  40 + p.articles << Forum.new(:profile => p, :name => 'forum_feed_test', :feed => { :limit => 7 })
  41 + assert_equal 7, p.forum.feed.limit
  42 + end
  43 +
  44 + should 'list 5 posts per page by default' do
  45 + forum = Forum.new
  46 + assert_equal 5, forum.posts_per_page
  47 + end
  48 +
  49 + should 'update posts per page setting' do
  50 + p = create_user('testuser').person
  51 + p.articles << Forum.new(:profile => p, :name => 'Forum test')
  52 + forum = p.forum
  53 + forum.posts_per_page = 7
  54 + assert forum.save!
  55 + assert_equal 7, p.forum.posts_per_page
  56 + end
  57 +
  58 + should 'has posts' do
  59 + p = create_user('testuser').person
  60 + forum = fast_create(Forum, :profile_id => p.id, :name => 'Forum test')
  61 + post = fast_create(TextileArticle, :name => 'First post', :profile_id => p.id, :parent_id => forum.id)
  62 + forum.children << post
  63 + assert_includes forum.posts, post
  64 + end
  65 +
  66 + should 'not includes rss feed in posts' do
  67 + p = create_user('testuser').person
  68 + forum = create(Forum, :profile_id => p.id, :name => 'Forum test')
  69 + assert_includes forum.children, forum.feed
  70 + assert_not_includes forum.posts, forum.feed
  71 + end
  72 +
  73 + should 'list posts ordered by updated at' do
  74 + p = create_user('testuser').person
  75 + forum = fast_create(Forum, :profile_id => p.id, :name => 'Forum test')
  76 + newer = create(TextileArticle, :name => 'Post 2', :parent => forum, :profile => p)
  77 + older = create(TextileArticle, :name => 'Post 1', :parent => forum, :profile => p)
  78 + older.updated_at = Time.now - 1.month
  79 + older.send :update_without_callbacks
  80 + assert_equal [newer, older], forum.posts
  81 + end
  82 +
  83 + should 'profile has more then one forum' do
  84 + p = create_user('testuser').person
  85 + fast_create(Forum, :name => 'Forum test', :profile_id => p.id)
  86 + assert_nothing_raised ActiveRecord::RecordInvalid do
  87 + Forum.create!(:name => 'Another Forum', :profile => p)
  88 + end
  89 + end
  90 +
  91 + should 'not update slug from name for existing forum' do
  92 + p = create_user('testuser').person
  93 + forum = Forum.create!(:name => 'Forum test', :profile => p)
  94 + assert_equal 'forum-test', forum.slug
  95 + forum.name = 'Changed name'
  96 + assert_not_equal 'changed-name', forum.slug
  97 + end
  98 +
  99 + should 'have posts' do
  100 + assert Forum.new.has_posts?
  101 + end
  102 +
  103 +end
test/unit/gallery_test.rb 0 → 100644
@@ -0,0 +1,138 @@ @@ -0,0 +1,138 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class GalleryTest < ActiveSupport::TestCase
  4 +
  5 + should 'be an article' do
  6 + assert_kind_of Article, Gallery.new
  7 + end
  8 +
  9 + should 'provide proper description' do
  10 + assert_kind_of String, Gallery.description
  11 + end
  12 +
  13 + should 'provide proper short description' do
  14 + assert_kind_of String, Gallery.short_description
  15 + end
  16 +
  17 + should 'provide own icon name' do
  18 + assert_not_equal Article.new.icon_name, Gallery.new.icon_name
  19 + end
  20 +
  21 + should 'identify as folder' do
  22 + assert Folder.new.folder?, 'gallery must identity itself as folder'
  23 + end
  24 +
  25 + should 'identify as gallery' do
  26 + assert Gallery.new.gallery?, 'gallery must identity itself as gallery'
  27 + end
  28 +
  29 + should 'can display hits' do
  30 + profile = create_user('testuser').person
  31 + a = fast_create(Gallery, :profile_id => profile.id)
  32 + assert_equal false, a.can_display_hits?
  33 + end
  34 +
  35 + should 'have images that are only images or other galleries' do
  36 + p = create_user('test_user').person
  37 + f = fast_create(Gallery, :profile_id => p.id)
  38 + file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :parent => f, :profile => p)
  39 + image = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => f, :profile => p)
  40 + gallery = fast_create(Gallery, :profile_id => p.id, :parent_id => f.id)
  41 +
  42 + assert_equivalent [gallery, image], f.images
  43 + end
  44 +
  45 + should 'bring galleries first in alpha order in images listing' do
  46 + p = create_user('test_user').person
  47 + f = fast_create(Gallery, :profile_id => p.id)
  48 + gallery1 = fast_create(Gallery, :name => 'b', :profile_id => p.id, :parent_id => f.id)
  49 + image = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => f, :profile => p)
  50 + gallery2 = fast_create(Gallery, :name => 'c', :profile_id => p.id, :parent_id => f.id)
  51 + gallery3 = fast_create(Gallery, :name => 'a', :profile_id => p.id, :parent_id => f.id)
  52 +
  53 + assert_equal [gallery3.id, gallery1.id, gallery2.id, image.id], f.images.map(&:id)
  54 + end
  55 +
  56 + should 'images support pagination' do
  57 + p = create_user('test_user').person
  58 + f = fast_create(Gallery, :profile_id => p.id)
  59 + gallery = fast_create(Gallery, :profile_id => p.id, :parent_id => f.id)
  60 + image = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => f, :profile => p)
  61 +
  62 + assert_equal [image], f.images.paginate(:page => 2, :per_page => 1)
  63 + end
  64 +
  65 + should 'return newest text articles as news' do
  66 + c = fast_create(Community)
  67 + gallery = fast_create(Gallery, :profile_id => c.id)
  68 + f = fast_create(Gallery, :name => 'gallery', :profile_id => c.id, :parent_id => gallery.id)
  69 + u = UploadedFile.create!(:profile => c, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => gallery)
  70 + older_t = fast_create(TinyMceArticle, :name => 'old news', :profile_id => c.id, :parent_id => gallery.id)
  71 + t = fast_create(TinyMceArticle, :name => 'news', :profile_id => c.id, :parent_id => gallery.id)
  72 + t_in_f = fast_create(TinyMceArticle, :name => 'news', :profile_id => c.id, :parent_id => f.id)
  73 +
  74 + assert_equal [t], gallery.news(1)
  75 + end
  76 +
  77 + should 'not return highlighted news when not asked' do
  78 + c = fast_create(Community)
  79 + gallery = fast_create(Gallery, :profile_id => c.id)
  80 + highlighted_t = fast_create(TinyMceArticle, :name => 'high news', :profile_id => c.id, :highlighted => true, :parent_id => gallery.id)
  81 + t = fast_create(TinyMceArticle, :name => 'news', :profile_id => c.id, :parent_id => gallery.id)
  82 +
  83 + assert_equal [t].map(&:slug), gallery.news(2).map(&:slug)
  84 + end
  85 +
  86 + should 'return highlighted news when asked' do
  87 + c = fast_create(Community)
  88 + gallery = fast_create(Gallery, :profile_id => c.id)
  89 + highlighted_t = fast_create(TinyMceArticle, :name => 'high news', :profile_id => c.id, :highlighted => true, :parent_id => gallery.id)
  90 + t = fast_create(TinyMceArticle, :name => 'news', :profile_id => c.id, :parent_id => gallery.id)
  91 +
  92 + assert_equal [highlighted_t].map(&:slug), gallery.news(2, true).map(&:slug)
  93 + end
  94 +
  95 + should 'return published images as images' do
  96 + p = create_user('test_user').person
  97 + i = UploadedFile.create!(:profile => p, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))
  98 +
  99 + c = fast_create(Community)
  100 + gallery = fast_create(Gallery, :profile_id => c.id)
  101 + pi = PublishedArticle.create!(:profile => c, :reference_article => i, :parent => gallery)
  102 +
  103 + assert_includes gallery.images(true), pi
  104 + end
  105 +
  106 + should 'not let pass javascript in the body' do
  107 + gallery = Gallery.new
  108 + gallery.body = "<script> alert(Xss!); </script>"
  109 + gallery.valid?
  110 +
  111 + assert_no_match /(<script>)/, gallery.body
  112 + end
  113 +
  114 + should 'filter fields with white_list filter' do
  115 + gallery = Gallery.new
  116 + gallery.body = "<h1> Body </h1>"
  117 + gallery.valid?
  118 +
  119 + assert_equal "<h1> Body </h1>", gallery.body
  120 + end
  121 +
  122 + should 'not sanitize html comments' do
  123 + gallery = Gallery.new
  124 + gallery.body = '<p><!-- <asdf> << aasdfa >>> --> <h1> Wellformed html code </h1>'
  125 + gallery.valid?
  126 +
  127 + assert_match /<!-- .* --> <h1> Wellformed html code <\/h1>/, gallery.body
  128 + end
  129 +
  130 + should 'escape malformed html tags' do
  131 + gallery = Gallery.new
  132 + gallery.body = "<h1<< Description >>/h1>"
  133 + gallery.valid?
  134 +
  135 + assert_no_match /[<>]/, gallery.body
  136 + end
  137 +
  138 +end
test/unit/profile_test.rb
@@ -1767,8 +1767,8 @@ class ProfileTest &lt; Test::Unit::TestCase @@ -1767,8 +1767,8 @@ class ProfileTest &lt; Test::Unit::TestCase
1767 1767
1768 should 'provide list of galleries' do 1768 should 'provide list of galleries' do
1769 p = fast_create(Profile) 1769 p = fast_create(Profile)
1770 - f1 = Folder.create(:profile => p, :name => "folder1", :view_as => 'image_gallery')  
1771 - f2 = Folder.create(:profile => p, :name => "folder2", :view_as => 'folder') 1770 + f1 = Gallery.create(:profile => p, :name => "folder1")
  1771 + f2 = Folder.create(:profile => p, :name => "folder2")
1772 1772
1773 assert_equal [f1], p.image_galleries 1773 assert_equal [f1], p.image_galleries
1774 end 1774 end
@@ -1788,6 +1788,30 @@ class ProfileTest &lt; Test::Unit::TestCase @@ -1788,6 +1788,30 @@ class ProfileTest &lt; Test::Unit::TestCase
1788 assert_nil Scrap.find_by_id(scrap.id) 1788 assert_nil Scrap.find_by_id(scrap.id)
1789 end 1789 end
1790 1790
  1791 + should 'have forum' do
  1792 + p = fast_create(Profile)
  1793 + p.articles << Forum.new(:profile => p, :name => 'forum_feed_test')
  1794 + assert p.has_forum?
  1795 + end
  1796 +
  1797 + should 'not have forum' do
  1798 + p = fast_create(Profile)
  1799 + assert !p.has_forum?
  1800 + end
  1801 +
  1802 + should 'get nil when no forum' do
  1803 + p = fast_create(Profile)
  1804 + assert_nil p.forum
  1805 + end
  1806 +
  1807 + should 'get first forum when has multiple forums' do
  1808 + p = fast_create(Profile)
  1809 + p.forums << Forum.new(:profile => p, :name => 'Forum one')
  1810 + p.forums << Forum.new(:profile => p, :name => 'Forum two')
  1811 + p.forums << Forum.new(:profile => p, :name => 'Forum three')
  1812 + assert_equal 'Forum one', p.forum.name
  1813 + assert_equal 3, p.forums.count
  1814 + end
1791 1815
1792 private 1816 private
1793 1817
test/unit/slideshow_block_test.rb
@@ -8,9 +8,7 @@ class SlideshowBlockTest &lt; ActiveSupport::TestCase @@ -8,9 +8,7 @@ class SlideshowBlockTest &lt; ActiveSupport::TestCase
8 attr_reader :profile 8 attr_reader :profile
9 9
10 should 'refer to a gallery' do 10 should 'refer to a gallery' do
11 - gallery = fast_create(Folder, :profile_id => profile.id)  
12 - gallery.view_as = 'image_gallery'  
13 - gallery.save! 11 + gallery = fast_create(Gallery, :profile_id => profile.id)
14 slideshow_block = SlideshowBlock.create!(:gallery_id => gallery.id) 12 slideshow_block = SlideshowBlock.create!(:gallery_id => gallery.id)
15 assert_equal gallery, slideshow_block.gallery 13 assert_equal gallery, slideshow_block.gallery
16 end 14 end
test/unit/uploaded_file_test.rb
@@ -243,8 +243,7 @@ class UploadedFileTest &lt; Test::Unit::TestCase @@ -243,8 +243,7 @@ class UploadedFileTest &lt; Test::Unit::TestCase
243 end 243 end
244 244
245 should 'track action when a published image is uploaded in a gallery' do 245 should 'track action when a published image is uploaded in a gallery' do
246 - p = fast_create(Folder, :profile_id => @profile.id)  
247 - p.view_as = 'image_gallery'; p.save! 246 + p = fast_create(Gallery, :profile_id => @profile.id)
248 f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => p, :profile => @profile) 247 f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => p, :profile => @profile)
249 ta = ActionTracker::Record.last(:conditions => { :verb => "upload_image" }) 248 ta = ActionTracker::Record.last(:conditions => { :verb => "upload_image" })
250 assert_kind_of String, ta.get_thumbnail_path[0] 249 assert_kind_of String, ta.get_thumbnail_path[0]
@@ -255,8 +254,7 @@ class UploadedFileTest &lt; Test::Unit::TestCase @@ -255,8 +254,7 @@ class UploadedFileTest &lt; Test::Unit::TestCase
255 254
256 should 'not track action when is not image' do 255 should 'not track action when is not image' do
257 ActionTracker::Record.delete_all 256 ActionTracker::Record.delete_all
258 - p = fast_create(Folder, :profile_id => @profile.id)  
259 - p.view_as = 'image_gallery'; p.save! 257 + p = fast_create(Gallery, :profile_id => @profile.id)
260 f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :parent => p, :profile => @profile) 258 f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :parent => p, :profile => @profile)
261 assert_nil ActionTracker::Record.last(:conditions => { :verb => "upload_image" }) 259 assert_nil ActionTracker::Record.last(:conditions => { :verb => "upload_image" })
262 end 260 end
@@ -268,8 +266,7 @@ class UploadedFileTest &lt; Test::Unit::TestCase @@ -268,8 +266,7 @@ class UploadedFileTest &lt; Test::Unit::TestCase
268 266
269 should 'not track action when is not published' do 267 should 'not track action when is not published' do
270 ActionTracker::Record.delete_all 268 ActionTracker::Record.delete_all
271 - p = fast_create(Folder, :profile_id => @profile.id)  
272 - p.view_as = 'image_gallery'; p.save! 269 + p = fast_create(Gallery, :profile_id => @profile.id)
273 f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => p, :profile => @profile, :published => false) 270 f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => p, :profile => @profile, :published => false)
274 assert_nil ActionTracker::Record.last(:conditions => { :verb => "upload_image" }) 271 assert_nil ActionTracker::Record.last(:conditions => { :verb => "upload_image" })
275 end 272 end